diff --git a/DEPS b/DEPS
index facc4ab..ec6e880 100644
--- a/DEPS
+++ b/DEPS
@@ -203,11 +203,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': 'c7112edbe0f46d174832815f2da56b5719421f0f',
+  'skia_revision': '9f3f2c24ae4405aea8f4e35cd9e2741e97c0b862',
   # 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': '9f448651842428bb1946be77110018aa6c9ef503',
+  'v8_revision': '615ae5f5342ad5ff262494d26287ed403296141c',
   # 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.
@@ -215,7 +215,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling ANGLE
   # and whatever else without interference from each other.
-  'angle_revision': 'abe9657839a4366d23477eb2d30146dad041d23d',
+  'angle_revision': '8670d6183a8439622e5f4527e4971bafb1a9ffa7',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling SwiftShader
   # and whatever else without interference from each other.
@@ -278,7 +278,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': 'b1274ec33195253b4e25c7e12cef8b18d94344e9',
+  'devtools_frontend_revision': 'bdf70c39ad5a7c1427626768f6efcc031c028b4b',
   # 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.
@@ -330,7 +330,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': '3668d352bc5fe13af27dc178d203f67032537a7f',
+  'dawn_revision': '5d8a071433779a3da828e5e8577be8258ef957c3',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling feed
   # and whatever else without interference from each other.
@@ -1294,7 +1294,7 @@
   },
 
   'src/third_party/perfetto':
-    Var('android_git') + '/platform/external/perfetto.git' + '@' + 'a45552c0f29dc62ed601a22b258b27ed2838bc57',
+    Var('android_git') + '/platform/external/perfetto.git' + '@' + '9d937e6cbed635945701f740350e09b8f0084985',
 
   'src/third_party/perl': {
       'url': Var('chromium_git') + '/chromium/deps/perl.git' + '@' + '6f3e5028eb65d0b4c5fdd792106ac4c84eee1eb3',
@@ -1554,7 +1554,7 @@
   },
 
   'src/third_party/webrtc':
-    Var('webrtc_git') + '/src.git' + '@' + '6e7167456b5eba36c7985d6a74f1d191958d4e0f',
+    Var('webrtc_git') + '/src.git' + '@' + '091617dda85bdca0329102c432ab287760e15e37',
 
   'src/third_party/libgifcodec':
      Var('skia_git') + '/libgifcodec' + '@'+  Var('libgifcodec_revision'),
@@ -1592,7 +1592,7 @@
       'packages': [
         {
           'package': 'skia/tools/goldctl/linux-amd64',
-          'version': 'qmz8kJxTUN_Mt51qpFOU1gn2Es-tf5fUQbm_dwWR4WsC',
+          'version': 'U9IAKman_wN6alsQfNAUzIasErQFGDvx3wn9o0AQBlEC',
         },
       ],
       'dep_type': 'cipd',
@@ -1602,7 +1602,7 @@
       'packages': [
         {
           'package': 'skia/tools/goldctl/windows-amd64',
-          'version': 'VR4k806B8ASaIGHP_wz13-mO3s-X-NxvU7dSULraOMEC',
+          'version': 'HYgBDvuNpEKiDYuVIssmP2wgCGe0FS-XKCe18wxZWKwC',
         },
       ],
       'dep_type': 'cipd',
@@ -1612,7 +1612,7 @@
       'packages': [
         {
           'package': 'skia/tools/goldctl/mac-amd64',
-          'version': 'VNy9awCiFUEMvA_Yv0NaAUvTu5qcX1KK9w7RAp7kua8C',
+          'version': 'xF94ClStkjWlYHAlxYXSOCFYEGhzEgxZEwB4zirJIjUC',
         },
       ],
       'dep_type': 'cipd',
@@ -1626,7 +1626,7 @@
     Var('chromium_git') + '/v8/v8.git' + '@' +  Var('v8_revision'),
 
   'src-internal': {
-    'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@0516cae2a76956ee97f7213eb3596a356ec7e2d7',
+    'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@35dd9a4faaff15775686c54e1f408977e59d0ec3',
     'condition': 'checkout_src_internal',
   },
 
diff --git a/android_webview/browser/aw_print_manager.cc b/android_webview/browser/aw_print_manager.cc
index 12c6185..8f912a6 100644
--- a/android_webview/browser/aw_print_manager.cc
+++ b/android_webview/browser/aw_print_manager.cc
@@ -92,18 +92,20 @@
   render_frame_host->Send(reply_msg);
 }
 
-void AwPrintManager::OnDidPrintDocument(
-    content::RenderFrameHost* render_frame_host,
-    const printing::mojom::DidPrintDocumentParams& params,
-    std::unique_ptr<DelayedFrameDispatchHelper> helper) {
-  if (params.document_cookie != cookie_)
+void AwPrintManager::DidPrintDocument(
+    printing::mojom::DidPrintDocumentParamsPtr params,
+    DidPrintDocumentCallback callback) {
+  if (params->document_cookie != cookie_) {
+    std::move(callback).Run(false);
     return;
+  }
 
-  const printing::mojom::DidPrintContentParams& content = *params.content;
+  const printing::mojom::DidPrintContentParams& content = *params->content;
   if (!content.metafile_data_region.IsValid()) {
     NOTREACHED() << "invalid memory handle";
     web_contents()->Stop();
     PdfWritingDone(0);
+    std::move(callback).Run(false);
     return;
   }
 
@@ -113,12 +115,14 @@
     NOTREACHED() << "couldn't map";
     web_contents()->Stop();
     PdfWritingDone(0);
+    std::move(callback).Run(false);
     return;
   }
 
   if (number_pages_ > printing::kMaxPageCount) {
     web_contents()->Stop();
     PdfWritingDone(0);
+    std::move(callback).Run(false);
     return;
   }
 
@@ -130,18 +134,18 @@
           .get(),
       FROM_HERE, base::BindOnce(&SaveDataToFd, fd_, number_pages_, data),
       base::BindOnce(&AwPrintManager::OnDidPrintDocumentWritingDone,
-                     pdf_writing_done_callback_, std::move(helper)));
+                     pdf_writing_done_callback_, std::move(callback)));
 }
 
 // static
 void AwPrintManager::OnDidPrintDocumentWritingDone(
     const PdfWritingDoneCallback& callback,
-    std::unique_ptr<DelayedFrameDispatchHelper> helper,
+    DidPrintDocumentCallback did_print_document_cb,
     uint32_t page_count) {
   DCHECK_LE(page_count, printing::kMaxPageCount);
   if (callback)
     callback.Run(base::checked_cast<int>(page_count));
-  helper->SendCompleted();
+  std::move(did_print_document_cb).Run(true);
 }
 
 WEB_CONTENTS_USER_DATA_KEY_IMPL(AwPrintManager)
diff --git a/android_webview/browser/aw_print_manager.h b/android_webview/browser/aw_print_manager.h
index 6d59853..cbf122d 100644
--- a/android_webview/browser/aw_print_manager.h
+++ b/android_webview/browser/aw_print_manager.h
@@ -22,6 +22,8 @@
   ~AwPrintManager() override;
 
   // mojom::PrintManagerHost:
+  void DidPrintDocument(printing::mojom::DidPrintDocumentParamsPtr params,
+                        DidPrintDocumentCallback callback) override;
   void GetDefaultPrintSettings(
       GetDefaultPrintSettingsCallback callback) override;
 
@@ -41,17 +43,13 @@
   explicit AwPrintManager(content::WebContents* contents);
 
   // printing::PrintManager:
-  void OnDidPrintDocument(
-      content::RenderFrameHost* render_frame_host,
-      const printing::mojom::DidPrintDocumentParams& params,
-      std::unique_ptr<DelayedFrameDispatchHelper> helper) override;
   void OnScriptedPrint(content::RenderFrameHost* render_frame_host,
                        const printing::mojom::ScriptedPrintParams& params,
                        IPC::Message* reply_msg) override;
 
   static void OnDidPrintDocumentWritingDone(
       const PdfWritingDoneCallback& callback,
-      std::unique_ptr<DelayedFrameDispatchHelper> helper,
+      DidPrintDocumentCallback did_print_document_cb,
       uint32_t page_count);
 
   std::unique_ptr<printing::PrintSettings> settings_;
diff --git a/android_webview/tools/system_webview_shell/layout_tests/src/org/chromium/webview_shell/test/WebViewLayoutTest.java b/android_webview/tools/system_webview_shell/layout_tests/src/org/chromium/webview_shell/test/WebViewLayoutTest.java
index b3c2480..4625b42 100644
--- a/android_webview/tools/system_webview_shell/layout_tests/src/org/chromium/webview_shell/test/WebViewLayoutTest.java
+++ b/android_webview/tools/system_webview_shell/layout_tests/src/org/chromium/webview_shell/test/WebViewLayoutTest.java
@@ -110,7 +110,6 @@
 
     // This is a non-failing test because it tends to require frequent rebaselines.
     @Test
-    @DisabledTest(message = "https://crbug.com/1144241")
     @MediumTest
     public void testGlobalInterfaceNoFail() throws Exception {
         runBlinkLayoutTest("webexposed/global-interface-listing.html",
@@ -148,7 +147,6 @@
     }
 
     @Test
-    @DisabledTest(message = "https://crbug.com/1144241")
     @MediumTest
     public void testWebViewExcludedInterfaces() throws Exception {
         ensureJsTestCopied();
@@ -195,7 +193,6 @@
     }
 
     @Test
-    @DisabledTest(message = "https://crbug.com/1144241")
     @MediumTest
     public void testWebViewIncludedStableInterfaces() throws Exception {
         ensureJsTestCopied();
diff --git a/android_webview/tools/system_webview_shell/test/data/webexposed/not-webview-exposed.txt b/android_webview/tools/system_webview_shell/test/data/webexposed/not-webview-exposed.txt
index 75ef7248..706879c 100644
--- a/android_webview/tools/system_webview_shell/test/data/webexposed/not-webview-exposed.txt
+++ b/android_webview/tools/system_webview_shell/test/data/webexposed/not-webview-exposed.txt
@@ -102,6 +102,7 @@
 interface MediaDevices : EventTarget
     getter ondevicechange
     setter ondevicechange
+    method getDisplayMedia
 
 # WebAuthN API should not be exposed in WebView, crbug.com/828168
 interface AuthenticatorAssertionResponse : AuthenticatorResponse
diff --git a/ash/ash_strings.grd b/ash/ash_strings.grd
index 18bda41d..2f3e670 100644
--- a/ash/ash_strings.grd
+++ b/ash/ash_strings.grd
@@ -1198,6 +1198,9 @@
       <message name="IDS_ASH_PHONE_HUB_NOTIFICATION_HOTSPOT_FAILED_MESSAGE" desc="Message inside a PhoneHub notification when enable hotspot failed to find a connection.">
         Tap to configure
       </message>
+      <message name="IDS_ASH_PHONE_HUB_CONTINUE_BROWSING_TAB_LABEL" desc="Label inside a Phone Hub continue browsing card that describes the index of the card, title of the webpage, and webpage url.">
+        Browser tab <ph name="INDEX">$1<ex>1</ex></ph> of <ph name="TOTAL_COUNT">$2<ex>2</ex></ph>. <ph name="SITE_TITLE">$3<ex>Google</ex></ph>, <ph name="SITE_URL">$4<ex>https://google.com</ex></ph>
+      </message>
 
       <message name="IDS_ASH_STYLUS_TOOLS_CAPTURE_REGION_ACTION" desc="Title of the capture region action in the stylus tools (a pop-up panel next to the status tray). This causes a partial screenshot to be taken (the user selects an area of the screen to take a screenshot of).">
         Capture region
diff --git a/ash/ash_strings_grd/IDS_ASH_PHONE_HUB_CONTINUE_BROWSING_TAB_LABEL.png.sha1 b/ash/ash_strings_grd/IDS_ASH_PHONE_HUB_CONTINUE_BROWSING_TAB_LABEL.png.sha1
new file mode 100644
index 0000000..290932af
--- /dev/null
+++ b/ash/ash_strings_grd/IDS_ASH_PHONE_HUB_CONTINUE_BROWSING_TAB_LABEL.png.sha1
@@ -0,0 +1 @@
+22fe620f4c048b2352ad6cfe316f63daf6372489
\ No newline at end of file
diff --git a/ash/detachable_base/detachable_base_handler.cc b/ash/detachable_base/detachable_base_handler.cc
index 07ab1fb0..a4bc632 100644
--- a/ash/detachable_base/detachable_base_handler.cc
+++ b/ash/detachable_base/detachable_base_handler.cc
@@ -174,7 +174,7 @@
 
 void DetachableBaseHandler::TabletModeEventReceived(
     chromeos::PowerManagerClient::TabletMode mode,
-    const base::TimeTicks& timestamp) {
+    base::TimeTicks timestamp) {
   UpdateTabletMode(mode);
 }
 
diff --git a/ash/detachable_base/detachable_base_handler.h b/ash/detachable_base/detachable_base_handler.h
index 20b64c5b..2a3a440c 100644
--- a/ash/detachable_base/detachable_base_handler.h
+++ b/ash/detachable_base/detachable_base_handler.h
@@ -93,7 +93,7 @@
 
   // chromeos::PowerManagerClient::Observer:
   void TabletModeEventReceived(chromeos::PowerManagerClient::TabletMode mode,
-                               const base::TimeTicks& timestamp) override;
+                               base::TimeTicks timestamp) override;
 
  private:
   // Identifier for a detachable base device - HEX encoded string created from
diff --git a/ash/session/fullscreen_controller.cc b/ash/session/fullscreen_controller.cc
index b29a7f2..de933b1e 100644
--- a/ash/session/fullscreen_controller.cc
+++ b/ash/session/fullscreen_controller.cc
@@ -137,7 +137,7 @@
 
 void FullscreenController::LidEventReceived(
     chromeos::PowerManagerClient::LidState state,
-    const base::TimeTicks& timestamp) {
+    base::TimeTicks timestamp) {
   // Show alert when the lid is opened. This also covers the case when the user
   // turn off "Sleep when cover is closed".
   if (state == chromeos::PowerManagerClient::LidState::OPEN)
diff --git a/ash/session/fullscreen_controller.h b/ash/session/fullscreen_controller.h
index edb2eb9..11f5bca6 100644
--- a/ash/session/fullscreen_controller.h
+++ b/ash/session/fullscreen_controller.h
@@ -39,7 +39,7 @@
   void ScreenBrightnessChanged(
       const power_manager::BacklightBrightnessChange& change) override;
   void LidEventReceived(chromeos::PowerManagerClient::LidState state,
-                        const base::TimeTicks& timestamp) override;
+                        base::TimeTicks timestamp) override;
 
   const SessionControllerImpl* const session_controller_;
 
diff --git a/ash/system/audio/display_speaker_controller.cc b/ash/system/audio/display_speaker_controller.cc
index c62cf49f..e44f436 100644
--- a/ash/system/audio/display_speaker_controller.cc
+++ b/ash/system/audio/display_speaker_controller.cc
@@ -64,8 +64,7 @@
   CrasAudioHandler::Get()->SetActiveHDMIOutoutRediscoveringIfNecessary(false);
 }
 
-void DisplaySpeakerController::SuspendDone(
-    const base::TimeDelta& sleep_duration) {
+void DisplaySpeakerController::SuspendDone(base::TimeDelta sleep_duration) {
   // This event is triggered when the device resumes after earlier suspension,
   // we should always start or re-start HDMI re-discovering
   // grace period right after this event.
diff --git a/ash/system/audio/display_speaker_controller.h b/ash/system/audio/display_speaker_controller.h
index 0ef60332..d1843c1 100644
--- a/ash/system/audio/display_speaker_controller.h
+++ b/ash/system/audio/display_speaker_controller.h
@@ -25,7 +25,7 @@
                                uint32_t changed_metrics) override;
 
   // chromeos::PowerManagerClient::Observer:
-  void SuspendDone(const base::TimeDelta& sleep_duration) override;
+  void SuspendDone(base::TimeDelta sleep_duration) override;
 
  private:
   // Swaps the left and right channels on yoga devices based on orientation.
diff --git a/ash/system/night_light/night_light_controller_impl.cc b/ash/system/night_light/night_light_controller_impl.cc
index fd286cc..7ceae9f5 100644
--- a/ash/system/night_light/night_light_controller_impl.cc
+++ b/ash/system/night_light/night_light_controller_impl.cc
@@ -707,8 +707,7 @@
          active_user_pref_service_->GetBoolean(prefs::kNightLightEnabled);
 }
 
-void NightLightControllerImpl::SuspendDone(
-    const base::TimeDelta& sleep_duration) {
+void NightLightControllerImpl::SuspendDone(base::TimeDelta sleep_duration) {
   // Time changes while the device is suspended. We need to refresh the schedule
   // upon device resume to know what the status should be now.
   Refresh(/*did_schedule_change=*/true,
diff --git a/ash/system/night_light/night_light_controller_impl.h b/ash/system/night_light/night_light_controller_impl.h
index 0bf5168..25b905f 100644
--- a/ash/system/night_light/night_light_controller_impl.h
+++ b/ash/system/night_light/night_light_controller_impl.h
@@ -181,7 +181,7 @@
   bool GetEnabled() const override;
 
   // chromeos::PowerManagerClient::Observer:
-  void SuspendDone(const base::TimeDelta& sleep_duration) override;
+  void SuspendDone(base::TimeDelta sleep_duration) override;
   void AmbientColorChanged(const int32_t color_temperature) override;
 
   // message_center::NotificationObserver:
diff --git a/ash/system/phonehub/continue_browsing_chip.cc b/ash/system/phonehub/continue_browsing_chip.cc
index 1c00874..380f423 100644
--- a/ash/system/phonehub/continue_browsing_chip.cc
+++ b/ash/system/phonehub/continue_browsing_chip.cc
@@ -8,12 +8,15 @@
 #include "ash/resources/vector_icons/vector_icons.h"
 #include "ash/root_window_controller.h"
 #include "ash/shell.h"
+#include "ash/strings/grit/ash_strings.h"
 #include "ash/style/ash_color_provider.h"
 #include "ash/system/phonehub/phone_hub_metrics.h"
 #include "ash/system/phonehub/phone_hub_tray.h"
 #include "ash/system/status_area_widget.h"
+#include "base/strings/string_number_conversions.h"
 #include "base/strings/utf_string_conversions.h"
 #include "chromeos/components/multidevice/logging/logging.h"
+#include "ui/base/l10n/l10n_util.h"
 #include "ui/gfx/paint_vector_icon.h"
 #include "ui/views/controls/highlight_path_generator.h"
 #include "ui/views/controls/image_view.h"
@@ -36,11 +39,13 @@
 
 ContinueBrowsingChip::ContinueBrowsingChip(
     const chromeos::phonehub::BrowserTabsModel::BrowserTabMetadata& metadata,
-    int index)
+    int index,
+    size_t total_count)
     : views::Button(base::BindRepeating(&ContinueBrowsingChip::ButtonPressed,
                                         base::Unretained(this))),
       url_(metadata.url),
-      index_(index) {
+      index_(index),
+      total_count_(total_count) {
   auto* color_provider = AshColorProvider::Get();
   SetFocusBehavior(FocusBehavior::ALWAYS);
   focus_ring()->SetColor(color_provider->GetControlsLayerColor(
@@ -102,7 +107,12 @@
   title_label->SetFontList(
       title_label->font_list().DeriveWithWeight(gfx::Font::Weight::BOLD));
 
-  SetTooltipText(metadata.title);
+  const base::string16 card_label = l10n_util::GetStringFUTF16(
+      IDS_ASH_PHONE_HUB_CONTINUE_BROWSING_TAB_LABEL,
+      base::NumberToString16(index_ + 1), base::NumberToString16(total_count_),
+      metadata.title, base::UTF8ToUTF16(url_.spec()));
+  SetTooltipText(card_label);
+  SetAccessibleName(card_label);
 }
 
 void ContinueBrowsingChip::OnPaintBackground(gfx::Canvas* canvas) {
diff --git a/ash/system/phonehub/continue_browsing_chip.h b/ash/system/phonehub/continue_browsing_chip.h
index f4446fb0..f195361 100644
--- a/ash/system/phonehub/continue_browsing_chip.h
+++ b/ash/system/phonehub/continue_browsing_chip.h
@@ -18,7 +18,8 @@
  public:
   ContinueBrowsingChip(
       const chromeos::phonehub::BrowserTabsModel::BrowserTabMetadata& metadata,
-      int index);
+      int index,
+      size_t total_count);
 
   ~ContinueBrowsingChip() override;
   ContinueBrowsingChip(ContinueBrowsingChip&) = delete;
@@ -36,6 +37,9 @@
 
   // The index of the chip as it is ordered in the parent view.
   int index_;
+
+  // The total number of chips in the parent view.
+  size_t total_count_;
 };
 
 }  // namespace ash
diff --git a/ash/system/phonehub/task_continuation_view.cc b/ash/system/phonehub/task_continuation_view.cc
index c6b2d3f..b6c67bc 100644
--- a/ash/system/phonehub/task_continuation_view.cc
+++ b/ash/system/phonehub/task_continuation_view.cc
@@ -182,7 +182,8 @@
   int index = 0;
   for (const BrowserTabsModel::BrowserTabMetadata& metadata :
        browser_tabs.most_recent_tabs()) {
-    chips_view_->AddTaskChip(new ContinueBrowsingChip(metadata, index));
+    chips_view_->AddTaskChip(new ContinueBrowsingChip(
+        metadata, index, browser_tabs.most_recent_tabs().size()));
     index++;
   }
 
diff --git a/ash/system/power/power_button_controller.cc b/ash/system/power/power_button_controller.cc
index e592db51..7fc5df0 100644
--- a/ash/system/power/power_button_controller.cc
+++ b/ash/system/power/power_button_controller.cc
@@ -344,7 +344,7 @@
 
 void PowerButtonController::PowerButtonEventReceived(
     bool down,
-    const base::TimeTicks& timestamp) {
+    base::TimeTicks timestamp) {
   if (lock_state_controller_->ShutdownRequested())
     return;
 
@@ -368,7 +368,7 @@
   DismissMenu();
 }
 
-void PowerButtonController::SuspendDone(const base::TimeDelta& sleep_duration) {
+void PowerButtonController::SuspendDone(base::TimeDelta sleep_duration) {
   last_resume_time_ = tick_clock_->NowTicks();
 }
 
diff --git a/ash/system/power/power_button_controller.h b/ash/system/power/power_button_controller.h
index 2fac951..d53f66d 100644
--- a/ash/system/power/power_button_controller.h
+++ b/ash/system/power/power_button_controller.h
@@ -123,10 +123,9 @@
   // chromeos::PowerManagerClient::Observer:
   void ScreenBrightnessChanged(
       const power_manager::BacklightBrightnessChange& change) override;
-  void PowerButtonEventReceived(bool down,
-                                const base::TimeTicks& timestamp) override;
+  void PowerButtonEventReceived(bool down, base::TimeTicks timestamp) override;
   void SuspendImminent(power_manager::SuspendImminent::Reason reason) override;
-  void SuspendDone(const base::TimeDelta& sleep_duration) override;
+  void SuspendDone(base::TimeDelta sleep_duration) override;
 
   // SessionObserver:
   void OnLoginStatusChanged(LoginStatus status) override;
diff --git a/ash/system/power/power_button_display_controller.cc b/ash/system/power/power_button_display_controller.cc
index 0b739f3..3c7e6bc 100644
--- a/ash/system/power/power_button_display_controller.cc
+++ b/ash/system/power/power_button_display_controller.cc
@@ -88,8 +88,7 @@
   screen_state_last_changed_ = tick_clock_->NowTicks();
 }
 
-void PowerButtonDisplayController::SuspendDone(
-    const base::TimeDelta& sleep_duration) {
+void PowerButtonDisplayController::SuspendDone(base::TimeDelta sleep_duration) {
   // Stop forcing backlights off on resume to handle situations where the power
   // button resumed but we didn't receive the event (crbug.com/735291).
   SetBacklightsForcedOff(false);
@@ -97,13 +96,13 @@
 
 void PowerButtonDisplayController::LidEventReceived(
     chromeos::PowerManagerClient::LidState state,
-    const base::TimeTicks& timestamp) {
+    base::TimeTicks timestamp) {
   SetBacklightsForcedOff(false);
 }
 
 void PowerButtonDisplayController::TabletModeEventReceived(
     chromeos::PowerManagerClient::TabletMode mode,
-    const base::TimeTicks& timestamp) {
+    base::TimeTicks timestamp) {
   SetBacklightsForcedOff(false);
 }
 
diff --git a/ash/system/power/power_button_display_controller.h b/ash/system/power/power_button_display_controller.h
index f4f8084b..d982818 100644
--- a/ash/system/power/power_button_display_controller.h
+++ b/ash/system/power/power_button_display_controller.h
@@ -55,11 +55,11 @@
   void OnScreenStateChanged(ScreenState screen_state) override;
 
   // Overridden from chromeos::PowerManagerClient::Observer:
-  void SuspendDone(const base::TimeDelta& sleep_duration) override;
+  void SuspendDone(base::TimeDelta sleep_duration) override;
   void LidEventReceived(chromeos::PowerManagerClient::LidState state,
-                        const base::TimeTicks& timestamp) override;
+                        base::TimeTicks timestamp) override;
   void TabletModeEventReceived(chromeos::PowerManagerClient::TabletMode mode,
-                               const base::TimeTicks& timestamp) override;
+                               base::TimeTicks timestamp) override;
 
   // Overridden from ui::EventHandler:
   void OnKeyEvent(ui::KeyEvent* event) override;
diff --git a/ash/system/power/power_event_observer.cc b/ash/system/power/power_event_observer.cc
index 9211f5c..48854fd 100644
--- a/ash/system/power/power_event_observer.cc
+++ b/ash/system/power/power_event_observer.cc
@@ -271,7 +271,7 @@
   }
 }
 
-void PowerEventObserver::SuspendDone(const base::TimeDelta& sleep_duration) {
+void PowerEventObserver::SuspendDone(base::TimeDelta sleep_duration) {
   suspend_in_progress_ = false;
 
   Shell::Get()->display_configurator()->ResumeDisplays();
diff --git a/ash/system/power/power_event_observer.h b/ash/system/power/power_event_observer.h
index d91a78a..4679755 100644
--- a/ash/system/power/power_event_observer.h
+++ b/ash/system/power/power_event_observer.h
@@ -51,7 +51,7 @@
 
   // chromeos::PowerManagerClient::Observer overrides:
   void SuspendImminent(power_manager::SuspendImminent::Reason reason) override;
-  void SuspendDone(const base::TimeDelta& sleep_duration) override;
+  void SuspendDone(base::TimeDelta sleep_duration) override;
 
   // SessionObserver overrides:
   void OnLockStateChanged(bool locked) override;
diff --git a/ash/wm/tablet_mode/tablet_mode_controller.cc b/ash/wm/tablet_mode/tablet_mode_controller.cc
index 93623ac..56f83ff 100644
--- a/ash/wm/tablet_mode/tablet_mode_controller.cc
+++ b/ash/wm/tablet_mode/tablet_mode_controller.cc
@@ -657,7 +657,7 @@
 
 void TabletModeController::LidEventReceived(
     chromeos::PowerManagerClient::LidState state,
-    const base::TimeTicks& time) {
+    base::TimeTicks time) {
   VLOG(1) << "Lid event received: " << ToString(state);
   lid_is_closed_ = state != chromeos::PowerManagerClient::LidState::OPEN;
   if (lid_is_closed_) {
@@ -675,7 +675,7 @@
 
 void TabletModeController::TabletModeEventReceived(
     chromeos::PowerManagerClient::TabletMode mode,
-    const base::TimeTicks& time) {
+    base::TimeTicks time) {
   if (!tablet_mode_behavior_.use_sensor)
     return;
 
@@ -703,7 +703,7 @@
   }
 }
 
-void TabletModeController::SuspendDone(const base::TimeDelta& sleep_duration) {
+void TabletModeController::SuspendDone(base::TimeDelta sleep_duration) {
   // We do not want TabletMode usage metrics to include time spent in suspend.
   tablet_mode_usage_interval_start_time_ = base::Time::Now();
 
diff --git a/ash/wm/tablet_mode/tablet_mode_controller.h b/ash/wm/tablet_mode/tablet_mode_controller.h
index 4bf22b5..5c87daa1 100644
--- a/ash/wm/tablet_mode/tablet_mode_controller.h
+++ b/ash/wm/tablet_mode/tablet_mode_controller.h
@@ -148,11 +148,11 @@
 
   // chromeos::PowerManagerClient::Observer:
   void LidEventReceived(chromeos::PowerManagerClient::LidState state,
-                        const base::TimeTicks& time) override;
+                        base::TimeTicks time) override;
   void TabletModeEventReceived(chromeos::PowerManagerClient::TabletMode mode,
-                               const base::TimeTicks& time) override;
+                               base::TimeTicks time) override;
   void SuspendImminent(power_manager::SuspendImminent::Reason reason) override;
-  void SuspendDone(const base::TimeDelta& sleep_duration) override;
+  void SuspendDone(base::TimeDelta sleep_duration) override;
 
   // ui::InputDeviceEventObserver:
   void OnInputDeviceConfigurationChanged(uint8_t input_device_types) override;
diff --git a/base/android/java/src/org/chromium/base/library_loader/ModernLinker.java b/base/android/java/src/org/chromium/base/library_loader/ModernLinker.java
index bb1ec28..4c09ea8 100644
--- a/base/android/java/src/org/chromium/base/library_loader/ModernLinker.java
+++ b/base/android/java/src/org/chromium/base/library_loader/ModernLinker.java
@@ -48,29 +48,41 @@
             if (!ok) resetAndThrow("Cannot load without relro sharing");
             mState = State.DONE;
         } else if (provideRelro) {
-            // We are in the browser, and with a current load address that indicates that there
-            // is enough address space for shared RELRO to operate. Create the shared RELRO, and
-            // store it in the map.
+            // Running in the browser process, with a fixed load address, hence having
+            // enough address space for shared RELRO to operate. Create the shared RELRO, and
+            // store it.
             LibInfo libInfo = new LibInfo();
             libInfo.mLibFilePath = libFilePath;
-            if (!nativeLoadLibraryCreateRelros(libFilePath, loadAddress, libInfo)) {
-                Log.e(TAG, "Unable to create relro, retrying without");
+            if (!nativeLoadLibrary(
+                        libFilePath, loadAddress, libInfo, true /* spawnRelroRegion */)) {
+                Log.e(TAG, "Unable to load with ModernLinker, using the system linker instead");
                 nativeLoadLibraryNoRelros(libFilePath);
                 libInfo.mRelroFd = -1;
             }
             mLibInfo = libInfo;
+            Log.d(TAG, "Successfully spawned RELRO: mLoadAddress=%d, mLoadSize=%d",
+                    mLibInfo.mLoadAddress, mLibInfo.mLoadSize);
             // Next state is still to provide relro (even if we don't have any), as child processes
             // would wait for them.
             mState = State.DONE_PROVIDE_RELRO;
         } else {
-            // We are in a service process, again with a current load address that is suitable for
-            // shared RELRO, and we are to wait for shared RELROs. So do that, then use the LibInfo
-            // we received.
+            // Running in a child process, also with a fixed load address that is suitable for
+            // shared RELRO.
             waitForSharedRelrosLocked();
+            Log.d(TAG, "Received mLibInfo: mLoadAddress=%d, mLoadSize=%d", mLibInfo.mLoadAddress,
+                    mLibInfo.mLoadSize);
+            // Two LibInfo objects are used: |mLibInfo| that brings the RELRO FD, and a temporary
+            // LibInfo to load the library. Before replacing the library's RELRO with the one from
+            // |mLibInfo|, the two objects are compared to make sure the memory ranges and the
+            // contents match.
+            LibInfo libInfoForLoad = new LibInfo();
             assert libFilePath.equals(mLibInfo.mLibFilePath);
-            if (!nativeLoadLibraryUseRelros(libFilePath, loadAddress, mLibInfo.mRelroFd)) {
+            if (!nativeLoadLibrary(
+                        libFilePath, loadAddress, libInfoForLoad, false /* spawnRelroRegion */)) {
                 resetAndThrow(String.format("Unable to load library: %s", libFilePath));
             }
+            assert libInfoForLoad.mRelroFd == -1;
+            nativeUseRelros(mLibInfo);
 
             mLibInfo.close();
             mLibInfo = null;
@@ -107,10 +119,9 @@
         throw new UnsatisfiedLinkError(message);
     }
 
-    private static native boolean nativeLoadLibraryCreateRelros(
-            String dlopenExtPath, long loadAddress, LibInfo libInfo);
-    private static native boolean nativeLoadLibraryUseRelros(
-            String dlopenExtPath, long loadAddress, int fd);
     private static native boolean nativeLoadLibraryNoRelros(String dlopenExtPath);
+    private static native boolean nativeLoadLibrary(
+            String dlopenExtPath, long loadAddress, LibInfo libInfo, boolean spawnRelroRegion);
+    private static native boolean nativeUseRelros(LibInfo libInfo);
     private static native int nativeGetRelroSharingResult();
 }
diff --git a/base/android/linker/linker_jni.h b/base/android/linker/linker_jni.h
index 7c3abec..7a4b5491 100644
--- a/base/android/linker/linker_jni.h
+++ b/base/android/linker/linker_jni.h
@@ -40,6 +40,7 @@
 #define LOG_ERROR(FORMAT, ...)                                             \
   __android_log_print(ANDROID_LOG_ERROR, TAG, "%s: " FORMAT, __FUNCTION__, \
                       ##__VA_ARGS__)
+#define PLOG_ERROR(MESSAGE) LOG_ERROR(MESSAGE ": %s", strerror(errno))
 
 #define UNUSED __attribute__((unused))
 
@@ -171,8 +172,20 @@
     env->SetIntField(library_info_obj, relro_fd_id, relro_fd);
   }
 
-  // Use this instance to convert a RelroInfo reference into
-  // a crazy_library_info_t.
+  void GetLoadInfo(JNIEnv* env,
+                   jobject library_info_obj,
+                   size_t* load_address,
+                   size_t* load_size) {
+    if (load_address) {
+      *load_address = static_cast<size_t>(
+          env->GetLongField(library_info_obj, load_address_id));
+    }
+    if (load_size) {
+      *load_size = static_cast<size_t>(
+          env->GetLongField(library_info_obj, load_size_id));
+    }
+  }
+
   void GetRelroInfo(JNIEnv* env,
                     jobject library_info_obj,
                     size_t* relro_start,
diff --git a/base/android/linker/modern_linker_jni.cc b/base/android/linker/modern_linker_jni.cc
index 33c0dde..dc16429 100644
--- a/base/android/linker/modern_linker_jni.cc
+++ b/base/android/linker/modern_linker_jni.cc
@@ -12,6 +12,7 @@
 #include <dlfcn.h>
 #include <errno.h>
 #include <fcntl.h>
+#include <inttypes.h>
 #include <jni.h>
 #include <limits.h>
 #include <link.h>
@@ -28,16 +29,6 @@
 #include <android/dlext.h>
 #include "base/android/linker/linker_jni.h"
 
-// From //base/posix/eintr_wrapper.h, but we don't want to depend on //base.
-#define HANDLE_EINTR(x)                                     \
-  ({                                                        \
-    decltype(x) eintr_wrapper_result;                       \
-    do {                                                    \
-      eintr_wrapper_result = (x);                           \
-    } while (eintr_wrapper_result == -1 && errno == EINTR); \
-    eintr_wrapper_result;                                   \
-  })
-
 // Not defined on all platforms. As this linker is only supported on ARM32/64,
 // x86/x86_64 and MIPS, page size is always 4k.
 #if !defined(PAGE_SIZE)
@@ -68,7 +59,7 @@
 // Record of the Java VM passed to JNI_OnLoad().
 static JavaVM* s_java_vm = nullptr;
 
-// Guarded by.sLock in Linker.java.
+// Guarded by |sLock| in Linker.java.
 RelroSharingStatus s_relro_sharing_status = RelroSharingStatus::NOT_ATTEMPTED;
 
 // Helper class for anonymous memory mapping.
@@ -113,7 +104,7 @@
   void* actual_address =
       mmap(address, size, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
   if (actual_address == MAP_FAILED) {
-    LOG_INFO("mmap failed: %s", strerror(errno));
+    PLOG_ERROR("mmap");
     return {};
   }
 
@@ -144,9 +135,14 @@
         dlsym(library_handle, "ASharedMemory_create"));
     set_protection = reinterpret_cast<SetProtectionFunction>(
         dlsym(library_handle, "ASharedMemory_setProt"));
+  }
 
-    if (!create || !set_protection)
+  bool IsWorking() const {
+    if (!create || !set_protection) {
       LOG_ERROR("Cannot get the shared memory functions from libandroid");
+      return false;
+    }
+    return true;
   }
 
   ~SharedMemoryFunctions() {
@@ -163,21 +159,120 @@
   void* library_handle;
 };
 
-// Metadata about a library loaded at a given |address|.
-struct LoadedLibraryMetadata {
-  explicit LoadedLibraryMetadata(void* address)
-      : load_address(address),
-        load_size(0),
-        min_vaddr(0),
-        relro_start(0),
-        relro_size(0) {}
+// Holds address ranges of the loaded native library, its RELRO region, along
+// with the RELRO FD identifying the shared memory region. Carries the same
+// members as the Java-side LibInfo, allowing to internally import/export the
+// member values from/to the Java-side counterpart.
+//
+// Does *not* own the RELRO FD as soon as the latter gets exported to Java
+// (as a result of 'spawning' the RELRO region as shared memory.
+//
+// *Not* threadsafe.
+class NativeLibInfo {
+ public:
+  // Constructs an (almost) empty instance. To be later populated from native
+  // code. The |env| and |java_object| will be useful later for exporting the
+  // values to the Java counterpart.
+  NativeLibInfo(size_t address, JNIEnv* env, jobject java_object)
+      : load_address_(address), env_(env), java_object_(java_object) {}
 
-  const void* load_address;
+  // Constructs and imports fields from the Java LibInfo. As above, the |env|
+  // and |java_object| are used for exporting.
+  NativeLibInfo(JNIEnv* env, jobject java_object)
+      : env_(env), java_object_(java_object) {
+    s_lib_info_fields.GetLoadInfo(env, java_object, &load_address_,
+                                  &load_size_);
+    s_lib_info_fields.GetRelroInfo(env, java_object, &relro_start_,
+                                   &relro_size_, &relro_fd_);
+  }
 
-  size_t load_size;
-  size_t min_vaddr;
-  size_t relro_start;
-  size_t relro_size;
+  size_t load_address() const { return load_address_; }
+
+  // Loads the native library using android_dlopen_ext and invokes JNI_OnLoad().
+  //
+  // On a successful load exports the address range of the library to the
+  // Java-side LibInfo.
+  //
+  // Iff |spawn_relro_region| is true, also finds the RELRO region in the
+  // library (PT_GNU_RELRO), converts it to be backed by a shared memory region
+  // (here referred as "RELRO FD") and exports the RELRO information to Java
+  // (the address range and the RELRO FD).
+  //
+  // When spawned, the shared memory region is exported only after sealing as
+  // read-only and without writable memory mappings. This allows any process to
+  // provide RELRO FD before it starts processing arbitrary input. For example,
+  // an App Zygote can create a RELRO FD in a sufficiently trustworthy way to
+  // make the Browser/Privileged processes share the region with it.
+  //
+  // TODO(pasko): Add an option to use an existing memory reservation.
+  bool LoadLibrary(const String& library_path, bool spawn_relro_region);
+
+  // Finds the RELRO region in the native library identified by
+  // |this->load_address()| and replaces it with the shared memory region
+  // identified by |other_lib_info|.
+  //
+  // The external NativeLibInfo can arrive from a different process.
+  //
+  // Note on security: The RELRO region is treated as *trusted*, no untrusted
+  // user/website/network input can be processed in an isolated process before
+  // it sends the RELRO FD. This is because there is no way to check whether the
+  // process has a writable mapping of the region remaining.
+  bool CompareRelroAndReplaceItBy(const NativeLibInfo& other_lib_info);
+
+ private:
+  friend int VisitLibraryPhdrs(dl_phdr_info*, size_t, void*);
+
+  NativeLibInfo() = delete;
+
+  // Not copyable or movable.
+  NativeLibInfo(const NativeLibInfo&) = delete;
+  NativeLibInfo& operator=(const NativeLibInfo&) = delete;
+
+  // Exports the address range of the library described by |this| to the
+  // Java-side LibInfo.
+  void ExportLoadInfoToJava() const {
+    s_lib_info_fields.SetLoadInfo(env_, java_object_, load_address_,
+                                  load_size_);
+  }
+
+  // Initializes |relro_fd_| with a newly created read-only shared memory region
+  // sized as the library's RELRO and with identical data.
+  bool CreateSharedRelroFd();
+
+  // Exports the address range of the RELRO region and RELRO FD described by
+  // |this| to the Java-side LibInfo.
+  void ExportRelroInfoToJava() const {
+    s_lib_info_fields.SetRelroInfo(env_, java_object_, relro_start_,
+                                   relro_size_, relro_fd_);
+  }
+
+  void CloseRelroFd() {
+    if (relro_fd_ == kInvalidFd)
+      return;
+    close(relro_fd_);
+    relro_fd_ = kInvalidFd;
+  }
+
+  // Loads and initializes the load address ranges: |load_address_|,
+  // |load_size_|.
+  bool LoadWithDlopenExt(const String& path, void** handle);
+
+  // Assuming that RELRO-related information is populated, memory-maps the RELRO
+  // FD on top of the library's RELRO.
+  bool ReplaceRelroWithSharedOne() const;
+
+  // Returns true iff the RELRO address and size, along with the contents are
+  // equal among the two.
+  bool RelroIsIdentical(const NativeLibInfo& external_lib_info) const;
+
+  static constexpr int kInvalidFd = -1;
+  size_t load_address_ = 0;
+  size_t load_size_ = 0;
+  size_t relro_start_ = 0;
+  size_t relro_size_ = 0;
+  int relro_fd_ = kInvalidFd;
+  JNIEnv* env_;
+  jobject java_object_;
 };
 
 // android_dlopen_ext() wrapper.
@@ -194,28 +289,26 @@
 
   LOG_INFO(
       "android_dlopen_ext:"
-      " flags=0x%llx, reserved_addr=%p, reserved_size=%d",
-      static_cast<long long>(extinfo.flags), extinfo.reserved_addr,
+      " flags=0x%" PRIx64 ", reserved_addr=%p, reserved_size=%d",
+      static_cast<uint64_t>(extinfo.flags), extinfo.reserved_addr,
       static_cast<int>(extinfo.reserved_size));
 
   *status = android_dlopen_ext(filename, flag, &extinfo);
   return true;
 }
 
-// Callback for dl_iterate_phdr(). Read phdrs to identify whether or not
-// this library's load address matches the |load_address| passed in
-// |data|. If yes, fills the metadata we care about in |data|.
-//
-// A non-zero return value terminates iteration.
-int FindLoadedLibraryMetadata(dl_phdr_info* info,
-                              size_t size UNUSED,
-                              void* data) {
-  auto* metadata = reinterpret_cast<LoadedLibraryMetadata*>(data);
+// Callback for dl_iterate_phdr(). From program headers (phdr(s)) of a loaded
+// library determines its load address, and in case it is equal to
+// |lib_info.load_address()|, extracts the RELRO and size information from
+// corresponding phdr(s).
+int VisitLibraryPhdrs(dl_phdr_info* info, size_t size UNUSED, void* lib_info) {
+  auto* out_lib_info = reinterpret_cast<NativeLibInfo*>(lib_info);
+  ElfW(Addr) lookup_address =
+      static_cast<ElfW(Addr)>(out_lib_info->load_address());
 
   // Use max and min vaddr to compute the library's load size.
   auto min_vaddr = std::numeric_limits<ElfW(Addr)>::max();
   ElfW(Addr) max_vaddr = 0;
-
   ElfW(Addr) min_relro_vaddr = ~0;
   ElfW(Addr) max_relro_vaddr = 0;
 
@@ -223,47 +316,51 @@
   for (int i = 0; i < info->dlpi_phnum; ++i) {
     const ElfW(Phdr)* phdr = &info->dlpi_phdr[i];
     switch (phdr->p_type) {
-      case PT_LOAD: {
-        // See if this segment's load address matches what we passed to
-        // android_dlopen_ext as extinfo.reserved_addr.
+      case PT_LOAD:
+        // See if this segment's load address matches the value passed to
+        // android_dlopen_ext as |extinfo.reserved_addr|.
         //
         // Here and below, the virtual address in memory is computed by
         //     address == info->dlpi_addr + program_header->p_vaddr
         // that is, the p_vaddr fields is relative to the object base address.
         // See dl_iterate_phdr(3) for details.
-        void* load_addr =
-            reinterpret_cast<void*>(info->dlpi_addr + phdr->p_vaddr);
-        // Matching is based on the load address, since we have no idea
-        // where the relro segment is.
-        if (load_addr == metadata->load_address)
+        if (lookup_address == info->dlpi_addr + phdr->p_vaddr)
           is_matching = true;
 
         if (phdr->p_vaddr < min_vaddr)
           min_vaddr = phdr->p_vaddr;
         if (phdr->p_vaddr + phdr->p_memsz > max_vaddr)
           max_vaddr = phdr->p_vaddr + phdr->p_memsz;
-      } break;
+        break;
       case PT_GNU_RELRO:
         min_relro_vaddr = PAGE_START(phdr->p_vaddr);
         max_relro_vaddr = phdr->p_vaddr + phdr->p_memsz;
+
+        // As of 2020-11 in libmonochrome.so RELRO is covered by a LOAD segment.
+        // It is not clear whether this property is going to be guaranteed in
+        // the future. Include the RELRO segment as part of the 'load size'.
+        // This way a potential future change change in layout of LOAD segments
+        // would not open address space for racy mmap(MAP_FIXED).
+        if (min_relro_vaddr < min_vaddr)
+          min_vaddr = min_relro_vaddr;
+        if (max_vaddr < max_relro_vaddr)
+          max_vaddr = max_relro_vaddr;
         break;
       default:
         break;
     }
   }
 
-  // If this library matches what we seek, return its load size.
+  // Fill out size and relro information if there was a match.
   if (is_matching) {
     int page_size = sysconf(_SC_PAGESIZE);
     if (page_size != PAGE_SIZE)
       abort();
 
-    metadata->load_size = PAGE_END(max_vaddr) - PAGE_START(min_vaddr);
-    metadata->min_vaddr = min_vaddr;
-
-    metadata->relro_size =
+    out_lib_info->load_size_ = PAGE_END(max_vaddr) - PAGE_START(min_vaddr);
+    out_lib_info->relro_size_ =
         PAGE_END(max_relro_vaddr) - PAGE_START(min_relro_vaddr);
-    metadata->relro_start = info->dlpi_addr + PAGE_START(min_relro_vaddr);
+    out_lib_info->relro_start_ = info->dlpi_addr + PAGE_START(min_relro_vaddr);
 
     return true;
   }
@@ -271,6 +368,21 @@
   return false;
 }
 
+bool FindRelroAndLibraryRangesInElf(void* load_address,
+                                    NativeLibInfo* lib_info) {
+  LOG_INFO("Called for %p", load_address);
+  if (!dl_iterate_phdr) {
+    LOG_ERROR("No dl_iterate_phdr() found");
+    return false;
+  }
+  int status = dl_iterate_phdr(&VisitLibraryPhdrs, lib_info);
+  if (!status) {
+    LOG_ERROR("Failed to find library at address %p", load_address);
+    return false;
+  }
+  return true;
+}
+
 // Creates an android_dlextinfo struct so that a library is loaded inside the
 // space referenced by |mapping|.
 std::unique_ptr<android_dlextinfo> MakeAndroidDlextinfo(
@@ -284,105 +396,24 @@
   return info;
 }
 
-// Copies the current relocations into a shared-memory file, and uses this file
-// as the relocations.
-//
-// Returns true for success, and populate |fd| with the relocations's fd in this
-// case.
-bool CopyAndRemapRelocations(const LoadedLibraryMetadata& metadata, int* fd) {
-  LOG_INFO("Entering");
-  void* relro_addr = reinterpret_cast<void*>(metadata.relro_start);
-
-  SharedMemoryFunctions fns;
-  if (!fns.create)
-    return false;
-
-  int shared_mem_fd = fns.create("cr_relro", metadata.relro_size);
-  if (shared_mem_fd == -1) {
-    LOG_ERROR("Cannot create the shared memory file");
-    return false;
-  }
-
-  int rw_flags = PROT_READ | PROT_WRITE;
-  fns.set_protection(shared_mem_fd, rw_flags);
-
-  void* relro_copy_addr = mmap(nullptr, metadata.relro_size, rw_flags,
-                               MAP_SHARED, shared_mem_fd, 0);
-  if (relro_copy_addr == MAP_FAILED) {
-    LOG_ERROR("Cannot mmap() space for the copy");
-    close(shared_mem_fd);
-    return false;
-  }
-
-  memcpy(relro_copy_addr, relro_addr, metadata.relro_size);
-  int retval =
-      HANDLE_EINTR(mprotect(relro_copy_addr, metadata.relro_size, PROT_READ));
-  if (retval) {
-    LOG_ERROR("Cannot call mprotect()");
-    close(shared_mem_fd);
-    munmap(relro_copy_addr, metadata.relro_size);
-    return false;
-  }
-
-  void* new_addr =
-      mremap(relro_copy_addr, metadata.relro_size, metadata.relro_size,
-             MREMAP_MAYMOVE | MREMAP_FIXED, relro_addr);
-  if (new_addr != relro_addr) {
-    LOG_ERROR("mremap() error");
-    close(shared_mem_fd);
-    munmap(relro_copy_addr, metadata.relro_size);
-    return false;
-  }
-
-  *fd = shared_mem_fd;
-  return true;
-}
-
-// Gathers metadata about the library loaded at |addr|.
-//
-// Returns true for success.
-bool GetLoadedLibraryMetadata(LoadedLibraryMetadata* metadata) {
-  LOG_INFO("Called for %p", metadata->load_address);
-
-  if (!dl_iterate_phdr) {
-    LOG_ERROR("No dl_iterate_phdr() found");
-    return false;
-  }
-  int status = dl_iterate_phdr(&FindLoadedLibraryMetadata, metadata);
-  if (!status) {
-    LOG_ERROR("Failed to find library at address %p", metadata->load_address);
-    return false;
-  }
-
-  LOG_INFO("Relro start address = %p, size = %d",
-           reinterpret_cast<void*>(metadata->relro_start),
-           static_cast<int>(metadata->relro_size));
-
-  return true;
-}
-
-// Resizes the address space reservation to the actual required size.
-// Failure here is only a warning, as at worst this wastes virtual address
-// space, not actual memory.
-void ResizeMapping(const ScopedAnonymousMmap& mapping,
-                   const LoadedLibraryMetadata& metadata) {
+// Resizes the address space reservation to the required size.  Failure here is
+// only a warning, since at worst this wastes virtual address space, not
+// physical memory.
+void ResizeMapping(const ScopedAnonymousMmap& mapping, size_t load_size) {
   // Trim the reservation mapping to match the library's actual size. Failure
   // to resize is not a fatal error. At worst we lose a portion of virtual
   // address space that we might otherwise have recovered. Note that trimming
   // the mapping here requires that we have already released the scoped
   // mapping.
   const uintptr_t uintptr_addr = reinterpret_cast<uintptr_t>(mapping.address());
-  if (mapping.size() > metadata.load_size) {
+  if (mapping.size() <= load_size) {
+    LOG_ERROR("WARNING: library reservation was too small");
+  } else {
     // Unmap the part of the reserved address space that is beyond the end of
     // the loaded library data.
-    void* unmap = reinterpret_cast<void*>(uintptr_addr + metadata.load_size);
-    const size_t length = mapping.size() - metadata.load_size;
-    if (munmap(unmap, length) == -1) {
-      LOG_ERROR("WARNING: unmap of %d bytes at %p failed: %s",
-                static_cast<int>(length), unmap, strerror(errno));
-    }
-  } else {
-    LOG_ERROR("WARNING: library reservation was too small");
+    void* unmap = reinterpret_cast<void*>(uintptr_addr + load_size);
+    const size_t length = mapping.size() - load_size;
+    munmap(unmap, length);
   }
 }
 
@@ -406,103 +437,115 @@
   return true;
 }
 
-// Load the library at |path| at address |wanted_address| if possible, and
-// creates a file with relro at |relocations_path|.
-//
-// In case of success, returns a readonly file descriptor to the relocations,
-// otherwise returns -1.
-int LoadCreateSharedRelocations(const String& path, void* wanted_address) {
+bool NativeLibInfo::LoadWithDlopenExt(const String& path, void** handle) {
   LOG_INFO("Entering");
-  ScopedAnonymousMmap mapping = ScopedAnonymousMmap::ReserveAtAddress(
-      wanted_address, kAddressSpaceReservationSize);
-  if (!mapping.address())
-    return -1;
 
+  // Reserve a region for loading the library, as required by
+  // android_dlopen_ext.
+  auto* address = reinterpret_cast<void*>(load_address_);
+  ScopedAnonymousMmap mapping = ScopedAnonymousMmap::ReserveAtAddress(
+      address, kAddressSpaceReservationSize);
+  if (!mapping.address())
+    return false;
+
+  // Invoke android_dlopen_ext.
   std::unique_ptr<android_dlextinfo> dlextinfo = MakeAndroidDlextinfo(mapping);
-  void* handle = nullptr;
-  if (!AndroidDlopenExt(path.c_str(), RTLD_NOW, *dlextinfo, &handle)) {
+  void* local_handle = nullptr;
+  if (!AndroidDlopenExt(path.c_str(), RTLD_NOW, *dlextinfo, &local_handle)) {
     LOG_ERROR("android_dlopen_ext() error");
-    return -1;
+    return false;
   }
-  if (handle == nullptr) {
+  if (local_handle == nullptr) {
     LOG_ERROR("android_dlopen_ext: %s", dlerror());
-    return -1;
+    return false;
   }
+
+  // The library successfully loaded. Avoid further automatic unmapping.
   mapping.Release();
 
-  LoadedLibraryMetadata metadata{mapping.address()};
-  bool ok = GetLoadedLibraryMetadata(&metadata);
-  int relro_fd = -1;
-  if (ok) {
-    ResizeMapping(mapping, metadata);
-    CopyAndRemapRelocations(metadata, &relro_fd);
+  // Find RELRO and trim the unused parts of the memory mapping.
+  if (!FindRelroAndLibraryRangesInElf(address, this)) {
+    // Fail early if PT_GNU_RELRO is not found. It likely indicates a
+    // build misconfiguration.
+    LOG_ERROR("Could not find RELRO in the loaded library: %s", path.c_str());
+    abort();
+    return false;
   }
 
-  if (!CallJniOnLoad(handle))
-    return -1;
+  // Save a little virtual address space.
+  ResizeMapping(mapping, load_size_);
 
-  return relro_fd;
+  *handle = local_handle;
+  return true;
 }
 
-// Load the library at |path| at address |wanted_address| if possible, and
-// uses the relocations in |relocations_fd| if possible.
-bool LoadUseSharedRelocations(const String& path,
-                              void* wanted_address,
-                              int relocations_fd) {
+bool NativeLibInfo::CreateSharedRelroFd() {
   LOG_INFO("Entering");
-  ScopedAnonymousMmap mapping = ScopedAnonymousMmap::ReserveAtAddress(
-      wanted_address, kAddressSpaceReservationSize);
-  if (!mapping.address())
-    return false;
-
-  std::unique_ptr<android_dlextinfo> dlextinfo = MakeAndroidDlextinfo(mapping);
-  void* handle = nullptr;
-  if (!AndroidDlopenExt(path.c_str(), RTLD_NOW, *dlextinfo, &handle)) {
-    LOG_ERROR("No android_dlopen_ext function found");
-    return false;
-  }
-  if (handle == nullptr) {
-    LOG_ERROR("android_dlopen_ext: %s", dlerror());
-    return false;
-  }
-  mapping.Release();
-
-  LoadedLibraryMetadata metadata{mapping.address()};
-  bool ok = GetLoadedLibraryMetadata(&metadata);
-  if (!ok) {
-    LOG_ERROR("Cannot get library's metadata");
+  if (!relro_start_ || !relro_size_) {
+    LOG_ERROR("RELRO region is not populated");
     return false;
   }
 
-  ResizeMapping(mapping, metadata);
-  void* shared_relro_mapping_address = mmap(
-      nullptr, metadata.relro_size, PROT_READ, MAP_SHARED, relocations_fd, 0);
-  if (shared_relro_mapping_address == MAP_FAILED) {
-    LOG_ERROR("Cannot map the relocations");
+  // Create a writable shared memory region.
+  SharedMemoryFunctions functions;
+  if (!functions.IsWorking())
+    return false;
+  int shared_mem_fd = functions.create("cr_relro", relro_size_);
+  if (shared_mem_fd == -1) {
+    LOG_ERROR("Cannot create the shared memory file");
+    return false;
+  }
+  int rw_flags = PROT_READ | PROT_WRITE;
+  functions.set_protection(shared_mem_fd, rw_flags);
+
+  // Map the region as writable.
+  void* relro_copy_addr =
+      mmap(nullptr, relro_size_, rw_flags, MAP_SHARED, shared_mem_fd, 0);
+  if (relro_copy_addr == MAP_FAILED) {
+    PLOG_ERROR("failed to allocate space for copying RELRO");
+    close(shared_mem_fd);
     return false;
   }
 
-  void* current_relro_address = reinterpret_cast<void*>(metadata.relro_start);
-  int retval = memcmp(shared_relro_mapping_address, current_relro_address,
-                      metadata.relro_size);
-  if (!retval) {
-    void* new_addr = mremap(shared_relro_mapping_address, metadata.relro_size,
-                            metadata.relro_size, MREMAP_MAYMOVE | MREMAP_FIXED,
-                            current_relro_address);
-    if (new_addr != current_relro_address) {
-      LOG_ERROR("Cannot call mremap()");
-      munmap(shared_relro_mapping_address, metadata.relro_size);
-      return false;
-    }
-    s_relro_sharing_status = RelroSharingStatus::SHARED;
-  } else {
-    munmap(shared_relro_mapping_address, metadata.relro_size);
-    LOG_ERROR("Relocations are not identical, giving up.");
-    s_relro_sharing_status = RelroSharingStatus::NOT_IDENTICAL;
+  // Populate the shared memory region with the contents of RELRO.
+  void* relro_addr = reinterpret_cast<void*>(relro_start_);
+  memcpy(relro_copy_addr, relro_addr, relro_size_);
+
+  // Protect the underlying physical pages from further modifications from all
+  // processes including the forked ones.
+  //
+  // Setting protection flags on the region to read-only guarantees that the
+  // memory can no longer get mapped as writable, for any FD pointing to the
+  // region, for any process. It is necessary to also munmap(2) the existing
+  // writable memory mappings, since they are not directly affected by the
+  // change of region's protection flags.
+  munmap(relro_copy_addr, relro_size_);
+  if (functions.set_protection(shared_mem_fd, PROT_READ) == -1) {
+    LOG_ERROR("Failed to set the RELRO FD as read-only.");
+    close(shared_mem_fd);
+    return false;
   }
 
-  if (!CallJniOnLoad(handle))
+  relro_fd_ = shared_mem_fd;
+  return true;
+}
+
+bool NativeLibInfo::ReplaceRelroWithSharedOne() const {
+  LOG_INFO("Entering");
+  if (relro_fd_ == -1 || !relro_start_ || !relro_size_) {
+    LOG_ERROR("Replacement RELRO not ready");
     return false;
+  }
+
+  // Map as read-only to *atomically* replace the RELRO region provided by the
+  // dynamic linker. To avoid memory corruption it is important that the
+  // contents of both memory regions is identical.
+  void* new_addr = mmap(reinterpret_cast<void*>(relro_start_), relro_size_,
+                        PROT_READ, MAP_FIXED | MAP_SHARED, relro_fd_, 0);
+  if (new_addr == MAP_FAILED) {
+    PLOG_ERROR("mmap() over RELRO");
+    return false;
+  }
 
   return true;
 }
@@ -520,56 +563,162 @@
   return true;
 }
 
+bool NativeLibInfo::LoadLibrary(const String& library_path,
+                                bool spawn_relro_region) {
+  // Load the library.
+  void* handle = nullptr;
+  if (!LoadWithDlopenExt(library_path, &handle)) {
+    LOG_ERROR("Failed to load native library: %s", library_path.c_str());
+    return false;
+  }
+  if (!CallJniOnLoad(handle))
+    return false;
+
+  // Publish the library size and load address back to LibInfo in Java.
+  ExportLoadInfoToJava();
+
+  if (!spawn_relro_region)
+    return true;
+
+  // Spawn RELRO to a shared memory region by copying and remapping on top of
+  // itself.
+  if (!CreateSharedRelroFd()) {
+    LOG_ERROR("Failed to create shared RELRO");
+    return false;
+  }
+  if (!ReplaceRelroWithSharedOne()) {
+    LOG_ERROR("Failed to convert RELRO to shared memory");
+    CloseRelroFd();
+    return false;
+  }
+
+  LOG_INFO(
+      "Created and converted RELRO to shared memory: relro_fd=%d, "
+      "relro_start=0x%zx",
+      relro_fd_, relro_start_);
+  ExportRelroInfoToJava();
+  return true;
+}
+
+bool NativeLibInfo::RelroIsIdentical(
+    const NativeLibInfo& other_lib_info) const {
+  // Abandon sharing if contents of the incoming RELRO region does not match the
+  // current one. This can be useful for debugging, but should never happen in
+  // the field.
+  if (other_lib_info.relro_start_ != relro_start_ ||
+      other_lib_info.relro_size_ != relro_size_ ||
+      other_lib_info.load_size_ != load_size_) {
+    LOG_ERROR("Incoming RELRO size does not match RELRO of the loaded library");
+    return false;
+  }
+  void* shared_relro_address =
+      mmap(nullptr, other_lib_info.relro_size_, PROT_READ, MAP_SHARED,
+           other_lib_info.relro_fd_, 0);
+  if (shared_relro_address == MAP_FAILED) {
+    PLOG_ERROR("mmap relro_fd");
+    return false;
+  }
+  void* current_relro_address = reinterpret_cast<void*>(relro_start_);
+  int not_equal =
+      memcmp(shared_relro_address, current_relro_address, relro_size_);
+  munmap(shared_relro_address, relro_size_);
+  if (not_equal) {
+    LOG_ERROR("Relocations are not identical, giving up.");
+    return false;
+  }
+  return true;
+}
+
+bool NativeLibInfo::CompareRelroAndReplaceItBy(
+    const NativeLibInfo& other_lib_info) {
+  if (other_lib_info.relro_fd_ == -1) {
+    LOG_ERROR("No shared region to use");
+    return false;
+  }
+
+  void* library_address = reinterpret_cast<void*>(other_lib_info.load_address_);
+  if (!FindRelroAndLibraryRangesInElf(library_address, this)) {
+    LOG_ERROR("Could not find RELRO from externally provided address: 0x%p",
+              library_address);
+    return false;
+  }
+
+  if (!RelroIsIdentical(other_lib_info)) {
+    LOG_ERROR("RELRO is not identical");
+    s_relro_sharing_status = RelroSharingStatus::NOT_IDENTICAL;
+    return false;
+  }
+
+  // Make it shared.
+  //
+  // The alternative approach to invoke mprotect+mremap is probably faster than
+  // munmap+mmap here. The advantage of the latter is that it removes all
+  // formerly writable mappings, so:
+  //  * It does not rely on disallowing mprotect(PROT_WRITE)
+  //  * This way |ReplaceRelroWithSharedOne()| is reused across spawning RELRO
+  //    and receiving it
+  if (!other_lib_info.ReplaceRelroWithSharedOne()) {
+    LOG_ERROR("Failed to use relro_fd");
+    // TODO(pasko): Introduce RelroSharingStatus::OTHER for rare RELRO sharing
+    // failures like this one.
+    return false;
+  }
+
+  s_relro_sharing_status = RelroSharingStatus::SHARED;
+  return true;
+}
+
 }  // namespace
 
 JNI_GENERATOR_EXPORT jboolean
-Java_org_chromium_base_library_1loader_ModernLinker_nativeLoadLibraryCreateRelros(
+Java_org_chromium_base_library_1loader_ModernLinker_nativeLoadLibrary(
     JNIEnv* env,
     jclass clazz,
     jstring jdlopen_ext_path,
     jlong load_address,
-    jobject lib_info_obj) {
+    jobject lib_info_obj,
+    jboolean spawn_relro_region) {
   LOG_INFO("Entering");
 
-  String library_path(env, jdlopen_ext_path);
-
   if (!IsValidAddress(load_address)) {
-    LOG_ERROR("Invalid address 0x%llx", static_cast<long long>(load_address));
+    LOG_ERROR("Invalid address 0x%" PRIx64,
+              static_cast<uint64_t>(load_address));
     return false;
   }
-  void* address = reinterpret_cast<void*>(load_address);
-
-  int fd = LoadCreateSharedRelocations(library_path, address);
-  if (fd == -1)
+  String library_path(env, jdlopen_ext_path);
+  // Create an empty NativeLibInfo. It will gradually get populated as the
+  // library gets loaded, RELRO rets extracted as shared memory, etc.
+  NativeLibInfo lib_info = {static_cast<size_t>(load_address), env,
+                            lib_info_obj};
+  if (!lib_info.LoadLibrary(library_path, spawn_relro_region)) {
     return false;
-
-  // Note the shared RELRO fd in the supplied libinfo object. In this
-  // implementation the RELRO start is set to the library's load address,
-  // and the RELRO size is unused.
-  const size_t cast_addr = reinterpret_cast<size_t>(address);
-  s_lib_info_fields.SetRelroInfo(env, lib_info_obj, cast_addr, 0, fd);
-
+  }
   return true;
 }
 
 JNI_GENERATOR_EXPORT jboolean
-Java_org_chromium_base_library_1loader_ModernLinker_nativeLoadLibraryUseRelros(
+Java_org_chromium_base_library_1loader_ModernLinker_nativeUseRelros(
     JNIEnv* env,
     jclass clazz,
-    jstring jdlopen_ext_path,
-    jlong load_address,
-    jint relro_fd) {
+    jobject lib_info_obj) {
   LOG_INFO("Entering");
+  // Copy all contents from the Java-side LibInfo object.
+  NativeLibInfo incoming_lib_info(env, lib_info_obj);
 
-  String library_path(env, jdlopen_ext_path);
+  // Create an empty NativeLibInfo to extract the current information about the
+  // loaded library and later compare with the contents of the
+  // |incoming_lib_info|.
+  NativeLibInfo lib_info = {incoming_lib_info.load_address(), env,
+                            lib_info_obj};
 
-  if (!IsValidAddress(load_address)) {
-    LOG_ERROR("Invalid address 0x%llx", static_cast<long long>(load_address));
+  if (!IsValidAddress(incoming_lib_info.load_address())) {
+    LOG_ERROR("Invalid address 0x%zx", incoming_lib_info.load_address());
     return false;
   }
-  void* address = reinterpret_cast<void*>(load_address);
-
-  return LoadUseSharedRelocations(library_path, address, relro_fd);
+  if (!lib_info.CompareRelroAndReplaceItBy(incoming_lib_info)) {
+    return false;
+  }
+  return true;
 }
 
 JNI_GENERATOR_EXPORT jboolean
diff --git a/base/big_endian.h b/base/big_endian.h
index 1ef321dd..13a0b9b 100644
--- a/base/big_endian.h
+++ b/base/big_endian.h
@@ -24,7 +24,8 @@
   static_assert(std::is_integral<T>::value, "T has to be an integral type.");
   // Make an unsigned version of the output type to make shift possible
   // without UB.
-  typename std::make_unsigned<T>::type unsigned_result = uint8_t{buf[0]};
+  typename std::make_unsigned<T>::type unsigned_result =
+      static_cast<uint8_t>(buf[0]);
   for (size_t i = 1; i < sizeof(T); ++i) {
     unsigned_result <<= 8;
     // Must cast to uint8_t to avoid clobbering by sign extension.
diff --git a/base/path_service.cc b/base/path_service.cc
index 4750944..c577b31 100644
--- a/base/path_service.cc
+++ b/base/path_service.cc
@@ -303,6 +303,16 @@
 }
 
 // static
+bool PathService::IsOverriddenForTests(int key) {
+  PathData* path_data = GetPathData();
+  DCHECK(path_data);
+
+  AutoLock scoped_lock(path_data->lock);
+
+  return path_data->overrides.find(key) != path_data->overrides.end();
+}
+
+// static
 void PathService::RegisterProvider(ProviderFunc func, int key_start,
                                    int key_end) {
   PathData* path_data = GetPathData();
diff --git a/base/path_service.h b/base/path_service.h
index 7d55c8d..57e687f5 100644
--- a/base/path_service.h
+++ b/base/path_service.h
@@ -86,6 +86,9 @@
   // was an override to remove or false if none was present.
   // NOTE: This function is intended to be used by tests only!
   static bool RemoveOverride(int key);
+
+  // Returns whether an override is present for a special directory or file.
+  static bool IsOverriddenForTests(int key);
 };
 
 }  // namespace base
diff --git a/base/test/scoped_path_override.cc b/base/test/scoped_path_override.cc
index dc4a340..db918520 100644
--- a/base/test/scoped_path_override.cc
+++ b/base/test/scoped_path_override.cc
@@ -10,6 +10,7 @@
 namespace base {
 
 ScopedPathOverride::ScopedPathOverride(int key) : key_(key) {
+  SaveOriginal();
   bool result = temp_dir_.CreateUniqueTempDir();
   CHECK(result);
   result = PathService::Override(key, temp_dir_.GetPath());
@@ -18,6 +19,7 @@
 
 ScopedPathOverride::ScopedPathOverride(int key, const base::FilePath& dir)
     : key_(key) {
+  SaveOriginal();
   bool result = PathService::Override(key, dir);
   CHECK(result);
 }
@@ -27,14 +29,31 @@
                                        bool is_absolute,
                                        bool create)
     : key_(key) {
+  SaveOriginal();
   bool result =
       PathService::OverrideAndCreateIfNeeded(key, path, is_absolute, create);
   CHECK(result);
 }
 
+void ScopedPathOverride::SaveOriginal() {
+  if (PathService::IsOverriddenForTests(key_)) {
+    original_override_ = PathService::CheckedGet(key_);
+  }
+}
+
 ScopedPathOverride::~ScopedPathOverride() {
    bool result = PathService::RemoveOverride(key_);
    CHECK(result) << "The override seems to have been removed already!";
+   if (original_override_) {
+     // PathService::Override, by default, does some (blocking) checks to ensure
+     // that the path is absolute and exists. As the original override must have
+     // already gone through these checks, we can skip these checks here.
+     // This is needed for some tests which use ScopedPathOverride in scopes
+     // that disallow blocking.
+     result = PathService::OverrideAndCreateIfNeeded(
+         key_, *original_override_, /*is_absolute=*/true, /*create=*/false);
+     CHECK(result);
+   }
 }
 
 }  // namespace base
diff --git a/base/test/scoped_path_override.h b/base/test/scoped_path_override.h
index f589149..b80b9cb 100644
--- a/base/test/scoped_path_override.h
+++ b/base/test/scoped_path_override.h
@@ -7,6 +7,7 @@
 
 #include "base/files/scoped_temp_dir.h"
 #include "base/macros.h"
+#include "base/optional.h"
 
 namespace base {
 
@@ -32,8 +33,12 @@
   ~ScopedPathOverride();
 
  private:
+  // Used for saving original_override_ when an override already exists.
+  void SaveOriginal();
+
   int key_;
   ScopedTempDir temp_dir_;
+  base::Optional<FilePath> original_override_;
 
   DISALLOW_COPY_AND_ASSIGN(ScopedPathOverride);
 };
diff --git a/build/fuchsia/linux.sdk.sha1 b/build/fuchsia/linux.sdk.sha1
index 649b09dc..1be904c 100644
--- a/build/fuchsia/linux.sdk.sha1
+++ b/build/fuchsia/linux.sdk.sha1
@@ -1 +1 @@
-0.20201202.4.1
+0.20201203.0.1
diff --git a/build/fuchsia/mac.sdk.sha1 b/build/fuchsia/mac.sdk.sha1
index 649b09dc..1be904c 100644
--- a/build/fuchsia/mac.sdk.sha1
+++ b/build/fuchsia/mac.sdk.sha1
@@ -1 +1 @@
-0.20201202.4.1
+0.20201203.0.1
diff --git a/chrome/android/BUILD.gn b/chrome/android/BUILD.gn
index f036168..3a04eee0 100644
--- a/chrome/android/BUILD.gn
+++ b/chrome/android/BUILD.gn
@@ -3380,7 +3380,6 @@
     "java/src/org/chromium/chrome/browser/sharing/SharingServiceProxy.java",
     "java/src/org/chromium/chrome/browser/sharing/click_to_call/ClickToCallMessageHandler.java",
     "java/src/org/chromium/chrome/browser/sharing/shared_clipboard/SharedClipboardMessageHandler.java",
-    "java/src/org/chromium/chrome/browser/signin/ProfileDownloader.java",
     "java/src/org/chromium/chrome/browser/signin/SigninInvestigator.java",
     "java/src/org/chromium/chrome/browser/signin/SigninManagerImpl.java",
     "java/src/org/chromium/chrome/browser/signin/SigninPromoUtil.java",
diff --git a/chrome/android/chrome_java_sources.gni b/chrome/android/chrome_java_sources.gni
index 0190384..726d31e 100644
--- a/chrome/android/chrome_java_sources.gni
+++ b/chrome/android/chrome_java_sources.gni
@@ -1253,12 +1253,10 @@
   "java/src/org/chromium/chrome/browser/signin/ConfirmManagedSyncDataDialog.java",
   "java/src/org/chromium/chrome/browser/signin/ConfirmSyncDataStateMachine.java",
   "java/src/org/chromium/chrome/browser/signin/ConfirmSyncDataStateMachineDelegate.java",
-  "java/src/org/chromium/chrome/browser/signin/DisplayableProfileData.java",
   "java/src/org/chromium/chrome/browser/signin/GoogleActivityController.java",
   "java/src/org/chromium/chrome/browser/signin/IdentityServicesProvider.java",
   "java/src/org/chromium/chrome/browser/signin/PersonalizedSigninPromoView.java",
   "java/src/org/chromium/chrome/browser/signin/ProfileDataCache.java",
-  "java/src/org/chromium/chrome/browser/signin/ProfileDownloader.java",
   "java/src/org/chromium/chrome/browser/signin/SignOutDialogFragment.java",
   "java/src/org/chromium/chrome/browser/signin/SigninActivity.java",
   "java/src/org/chromium/chrome/browser/signin/SigninActivityLauncherImpl.java",
diff --git a/chrome/android/expectations/lint-baseline.xml b/chrome/android/expectations/lint-baseline.xml
index f23aa2a..595c208 100644
--- a/chrome/android/expectations/lint-baseline.xml
+++ b/chrome/android/expectations/lint-baseline.xml
@@ -81,7 +81,7 @@
     <issue
         id="VisibleForTests"
         message="This method should only be accessed from tests or within private scope"
-        errorLine1="                IconProvider.getIcon(context, R.drawable.ic_permission_location_outline),"
+        errorLine1="                IconProvider.getIcon(context, R.drawable.ic_permission_location_filled),"
         errorLine2="                             ~~~~~~~">
         <location
             file="../../chrome/android/features/keyboard_accessory/internal/java/src/org/chromium/chrome/browser/keyboard_accessory/sheet_tabs/AddressAccessorySheetCoordinator.java"
diff --git a/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/header/AssistantHeaderCoordinator.java b/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/header/AssistantHeaderCoordinator.java
index 68dff14..42963f0 100644
--- a/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/header/AssistantHeaderCoordinator.java
+++ b/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/header/AssistantHeaderCoordinator.java
@@ -19,8 +19,8 @@
 import org.chromium.chrome.browser.autofill_assistant.AutofillAssistantUiController;
 import org.chromium.chrome.browser.autofill_assistant.carousel.AssistantChipAdapter;
 import org.chromium.chrome.browser.autofill_assistant.header.AssistantHeaderViewBinder.ViewHolder;
-import org.chromium.chrome.browser.signin.DisplayableProfileData;
 import org.chromium.chrome.browser.signin.ProfileDataCache;
+import org.chromium.chrome.browser.signin.services.DisplayableProfileData;
 import org.chromium.chrome.browser.signin.services.IdentityServicesProvider;
 import org.chromium.components.signin.base.CoreAccountInfo;
 import org.chromium.components.signin.identitymanager.ConsentLevel;
diff --git a/chrome/android/features/autofill_assistant/javatests/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantChromeTabIntegrationTest.java b/chrome/android/features/autofill_assistant/javatests/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantChromeTabIntegrationTest.java
index c3ef4c4..c989b511 100644
--- a/chrome/android/features/autofill_assistant/javatests/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantChromeTabIntegrationTest.java
+++ b/chrome/android/features/autofill_assistant/javatests/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantChromeTabIntegrationTest.java
@@ -570,8 +570,8 @@
                                    .getSpec()
                                    .equals(getURL(TEST_PAGE_A)));
         waitUntilViewMatchesCondition(withId(R.id.button_init_ok), isCompletelyDisplayed());
-        onView(is(mScrimCoordinator.getViewForTesting()))
-                .check(matches(withEffectiveVisibility(Visibility.VISIBLE)));
+        waitUntilViewMatchesCondition(is(mScrimCoordinator.getViewForTesting()),
+                withEffectiveVisibility(Visibility.VISIBLE));
 
         onView(withId(org.chromium.chrome.R.id.tab_switcher_button)).perform(click());
         waitUntilViewMatchesCondition(withId(R.id.button_init_ok), not(isDisplayed()));
@@ -579,8 +579,8 @@
 
         Espresso.pressBack();
         waitUntilViewMatchesCondition(withId(R.id.button_init_ok), isCompletelyDisplayed());
-        onView(is(mScrimCoordinator.getViewForTesting()))
-                .check(matches(withEffectiveVisibility(Visibility.VISIBLE)));
+        waitUntilViewMatchesCondition(is(mScrimCoordinator.getViewForTesting()),
+                withEffectiveVisibility(Visibility.VISIBLE));
     }
 
     @Test
@@ -596,8 +596,8 @@
                                    .getSpec()
                                    .equals(getURL(TEST_PAGE_A)));
         waitUntilViewMatchesCondition(withId(R.id.button_init_ok), isCompletelyDisplayed());
-        onView(is(mScrimCoordinator.getViewForTesting()))
-                .check(matches(withEffectiveVisibility(Visibility.VISIBLE)));
+        waitUntilViewMatchesCondition(is(mScrimCoordinator.getViewForTesting()),
+                withEffectiveVisibility(Visibility.VISIBLE));
 
         // Clicking location bar hides UI and shows the keyboard.
         onView(withId(org.chromium.chrome.R.id.url_bar)).perform(click());
@@ -607,7 +607,7 @@
         // Closing keyboard brings it back.
         Espresso.pressBack();
         waitUntilViewMatchesCondition(withId(R.id.button_init_ok), isCompletelyDisplayed());
-        onView(is(mScrimCoordinator.getViewForTesting()))
-                .check(matches(withEffectiveVisibility(Visibility.VISIBLE)));
+        waitUntilViewMatchesCondition(is(mScrimCoordinator.getViewForTesting()),
+                withEffectiveVisibility(Visibility.VISIBLE));
     }
 }
diff --git a/chrome/android/features/keyboard_accessory/internal/java/src/org/chromium/chrome/browser/keyboard_accessory/sheet_tabs/AddressAccessorySheetCoordinator.java b/chrome/android/features/keyboard_accessory/internal/java/src/org/chromium/chrome/browser/keyboard_accessory/sheet_tabs/AddressAccessorySheetCoordinator.java
index f95beb3..a631b68 100644
--- a/chrome/android/features/keyboard_accessory/internal/java/src/org/chromium/chrome/browser/keyboard_accessory/sheet_tabs/AddressAccessorySheetCoordinator.java
+++ b/chrome/android/features/keyboard_accessory/internal/java/src/org/chromium/chrome/browser/keyboard_accessory/sheet_tabs/AddressAccessorySheetCoordinator.java
@@ -36,7 +36,7 @@
     public AddressAccessorySheetCoordinator(
             Context context, @Nullable RecyclerView.OnScrollListener scrollListener) {
         super(context.getString(R.string.address_accessory_sheet_title),
-                IconProvider.getIcon(context, R.drawable.ic_permission_location_outline),
+                IconProvider.getIcon(context, R.drawable.ic_permission_location_filled),
                 context.getString(R.string.address_accessory_sheet_toggle),
                 context.getString(R.string.address_accessory_sheet_opened),
                 R.layout.address_accessory_sheet, AccessoryTabType.ADDRESSES, scrollListener);
diff --git a/chrome/android/java/res/values/colors.xml b/chrome/android/java/res/values/colors.xml
index e818b7f..a02d231 100644
--- a/chrome/android/java/res/values/colors.xml
+++ b/chrome/android/java/res/values/colors.xml
@@ -69,7 +69,6 @@
     <!-- Contextual Search colors -->
     <color name="contextual_search_promo_background_color">@color/default_bg_color_elev_0</color>
     <color name="contextual_search_promo_border_color">#C2C2C2</color>
-    <color name="contextual_search_divider_line_color">@color/default_bg_color_secondary</color>
 
     <!-- Toolbar colors -->
     <color name="toolbar_text_box_background_incognito">@color/black_alpha_38</color>
diff --git a/chrome/android/java/res/values/dimens.xml b/chrome/android/java/res/values/dimens.xml
index 94a30043..b94622ee 100644
--- a/chrome/android/java/res/values/dimens.xml
+++ b/chrome/android/java/res/values/dimens.xml
@@ -79,8 +79,6 @@
     <dimen name="contextual_search_padded_button_width">
       @dimen/overlay_panel_padded_button_width
     </dimen>
-    <dimen name="contextual_search_divider_line_width">1dp</dimen>
-    <dimen name="contextual_search_divider_line_height">24dp</dimen>
     <!-- Padding at the end of the Bar. -->
     <dimen name="contextual_search_end_padding">7dp</dimen>
     <dimen name="contextual_search_bubble_y_inset">-3dp</dimen>
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/contextualsearch/ContextualSearchBarControl.java b/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/contextualsearch/ContextualSearchBarControl.java
index 87a3484..8d2f161 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/contextualsearch/ContextualSearchBarControl.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/contextualsearch/ContextualSearchBarControl.java
@@ -11,7 +11,6 @@
 
 import androidx.annotation.VisibleForTesting;
 
-import org.chromium.base.ApiCompatibilityUtils;
 import org.chromium.chrome.R;
 import org.chromium.chrome.browser.compositor.bottombar.OverlayPanelAnimation;
 import org.chromium.chrome.browser.contextualsearch.QuickActionCategory;
@@ -88,26 +87,6 @@
     private final float mTermCaptionSpacing;
 
     /**
-     * The visibility percentage for the divider line ranging from 0.f to 1.f.
-     */
-    private float mDividerLineVisibilityPercentage;
-
-    /**
-     * The width of the divider line in px.
-     */
-    private final float mDividerLineWidth;
-
-    /**
-     * The height of the divider line in px.
-     */
-    private final float mDividerLineHeight;
-
-    /**
-     * The divider line color.
-     */
-    private final int mDividerLineColor;
-
-    /**
      * The width of the end button in px.
      */
     private final float mEndButtonWidth;
@@ -130,9 +109,6 @@
     /** The animator that controls the text opacity. */
     private CompositorAnimator mTextOpacityAnimation;
 
-    /** The animator that controls the divider line visibility. */
-    private CompositorAnimator mDividerLineVisibilityAnimation;
-
     /** The animator that controls touch highlighting. */
     private CompositorAnimator mTouchHighlightAnimation;
 
@@ -162,14 +138,6 @@
         mTermCaptionSpacing = context.getResources().getDimension(
                 R.dimen.contextual_search_term_caption_spacing);
 
-        // Divider line values.
-        mDividerLineWidth = context.getResources().getDimension(
-                R.dimen.contextual_search_divider_line_width);
-        mDividerLineHeight = context.getResources().getDimension(
-                R.dimen.contextual_search_divider_line_height);
-        mDividerLineColor = ApiCompatibilityUtils.getColor(
-                context.getResources(), R.color.contextual_search_divider_line_color);
-
         // Icon attributes.
         mPaddedIconWidthPx =
                 context.getResources().getDimension(R.dimen.contextual_search_padded_button_width);
@@ -400,49 +368,6 @@
     }
 
     // ============================================================================================
-    // Divider Line
-    // ============================================================================================
-    /**
-     * @return The visibility percentage for the divider line ranging from 0.f to 1.f.
-     */
-    public float getDividerLineVisibilityPercentage() {
-        return mDividerLineVisibilityPercentage;
-    }
-
-    /**
-     * @return The width of the divider line in px.
-     */
-    public float getDividerLineWidth() {
-        return mDividerLineWidth;
-    }
-
-    /**
-     * @return The height of the divider line in px.
-     */
-    public float getDividerLineHeight() {
-        return mDividerLineHeight;
-    }
-
-    /**
-     * @return The divider line color.
-     */
-    public int getDividerLineColor() {
-        return mDividerLineColor;
-    }
-
-    /**
-     * @return The x-offset for the divider line relative to the x-position of the Bar in px.
-     */
-    public float getDividerLineXOffset() {
-        if (LocalizationUtils.isLayoutRtl()) {
-            return mEndButtonWidth;
-        } else {
-            return mContextualSearchPanel.getContentViewWidthPx() - mEndButtonWidth
-                    - getDividerLineWidth();
-        }
-    }
-
-    // ============================================================================================
     // Touch Highlight
     // ============================================================================================
 
@@ -451,16 +376,6 @@
      */
     private boolean mTouchHighlightVisible;
 
-    /**
-     * Whether the touch that triggered showing the touch highlight was on the end Bar button.
-     */
-    private boolean mWasTouchOnEndButton;
-
-    /**
-     * Whether the divider line was visible when the touch highlight started showing.
-     */
-    private boolean mWasDividerVisibleOnTouch;
-
     /** Where the touch highlight should start, in pixels. */
     private float mTouchHighlightXOffsetPx;
 
@@ -549,8 +464,6 @@
     private void showTouchHighlight(float x) {
         if (mTouchHighlightVisible) return;
 
-        mWasTouchOnEndButton = isTouchOnEndButton(x);
-
         // If the panel is expanded or maximized and the panel content cannot be promoted to a new
         // tab, then tapping anywhere besides the end buttons does nothing. In this case, the touch
         // highlight should not be shown.
@@ -577,20 +490,6 @@
         mTouchHighlightAnimation.start();
     }
 
-    /**
-     * @param xPx The x-position of the touch in px.
-     * @return Whether the touch occurred on the search Bar's end button.
-     */
-    private boolean isTouchOnEndButton(float xPx) {
-        if (getDividerLineVisibilityPercentage() == TRANSPARENT_OPACITY) return false;
-
-        // Adjust the touch position to compensate for the narrow panel.
-        xPx -= mContextualSearchPanel.getOffsetX() * mDpToPx;
-
-        if (LocalizationUtils.isLayoutRtl()) return xPx <= getDividerLineXOffset();
-        return xPx > getDividerLineXOffset();
-    }
-
     // ============================================================================================
     // Search Bar Animation
     // ============================================================================================
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/compositor/scene_layer/ContextualSearchSceneLayer.java b/chrome/android/java/src/org/chromium/chrome/browser/compositor/scene_layer/ContextualSearchSceneLayer.java
index 27057d5..12b0f42 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/compositor/scene_layer/ContextualSearchSceneLayer.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/compositor/scene_layer/ContextualSearchSceneLayer.java
@@ -122,13 +122,6 @@
         float progressBarOpacity = panel.getProgressBarOpacity();
         float progressBarCompletion = panel.getProgressBarCompletion();
 
-        float dividerLineVisibilityPercentage =
-                searchBarControl.getDividerLineVisibilityPercentage();
-        float dividerLineWidth = searchBarControl.getDividerLineWidth();
-        float dividerLineHeight = searchBarControl.getDividerLineHeight();
-        int dividerLineColor = searchBarControl.getDividerLineColor();
-        float dividerLineXOffset = searchBarControl.getDividerLineXOffset();
-
         boolean touchHighlightVisible = searchBarControl.getTouchHighlightVisible();
         float touchHighlightXOffset = searchBarControl.getTouchHighlightXOffsetPx();
         float touchHighlightWidth = searchBarControl.getTouchHighlightWidthPx();
@@ -168,10 +161,9 @@
                 quickActionIconVisible, thumbnailVisible, thumbnailUrl,
                 customImageVisibilityPercentage, barImageSize, iconColor, dragHandlebarColor,
                 closeIconOpacity, isProgressBarVisible, progressBarHeight * mDpToPx,
-                progressBarOpacity, progressBarCompletion, dividerLineVisibilityPercentage,
-                dividerLineWidth, dividerLineHeight, dividerLineColor, dividerLineXOffset,
-                touchHighlightVisible, touchHighlightXOffset, touchHighlightWidth,
-                Profile.getLastUsedRegularProfile(), roundedBarTopResourceId, separatorLineColor);
+                progressBarOpacity, progressBarCompletion, touchHighlightVisible,
+                touchHighlightXOffset, touchHighlightWidth, Profile.getLastUsedRegularProfile(),
+                roundedBarTopResourceId, separatorLineColor);
     }
 
     @CalledByNative
@@ -244,8 +236,6 @@
                 float customImageVisibilityPercentage, int barImageSize, int iconColor,
                 int dragHandlebarColor, float closeIconOpacity, boolean isProgressBarVisible,
                 float progressBarHeight, float progressBarOpacity, float progressBarCompletion,
-                float dividerLineVisibilityPercentage, float dividerLineWidth,
-                float dividerLineHeight, int dividerLineColor, float dividerLineXOffset,
                 boolean touchHighlightVisible, float touchHighlightXOffset,
                 float toucHighlightWidth, Profile profile, int barBackgroundResourceId,
                 int separatorLineColor);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/contacts_picker/ChromePickerAdapter.java b/chrome/android/java/src/org/chromium/chrome/browser/contacts_picker/ChromePickerAdapter.java
index bc42b31..5300814 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/contacts_picker/ChromePickerAdapter.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/contacts_picker/ChromePickerAdapter.java
@@ -14,8 +14,8 @@
 
 import org.chromium.chrome.R;
 import org.chromium.chrome.browser.profiles.Profile;
-import org.chromium.chrome.browser.signin.DisplayableProfileData;
 import org.chromium.chrome.browser.signin.ProfileDataCache;
+import org.chromium.chrome.browser.signin.services.DisplayableProfileData;
 import org.chromium.chrome.browser.signin.services.IdentityServicesProvider;
 import org.chromium.components.browser_ui.contacts_picker.ContactDetails;
 import org.chromium.components.browser_ui.contacts_picker.PickerAdapter;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/dagger.md b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/dagger.md
new file mode 100644
index 0000000..cd7013be
--- /dev/null
+++ b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/dagger.md
@@ -0,0 +1,125 @@
+# Dagger in Custom Tabs
+
+The Custom Tabs code (code in org.chromium.chrome.browser.customtabs, ...browserservices and ...webapps) makes use of Dagger for dependency injection.
+It was introduced with the hope that it would be more widely adopted in Chrome, but due to other ongoing refactorings it was decided not to spread it further until a cohesive end state could be understood.
+
+This document isn’t about the pros and cons of Dagger or an argument about whether it should be pushed further or ripped out, it is meant as a quick way for developers to understand what’s going on in Custom Tabs land and how to make changes.
+
+## What is Dagger?
+
+Dagger is a dependency injection framework.
+You can essentially think of it as a magic box that creates your classes and wires them together for you.
+For example:
+
+```java
+@ActivityScope
+public class Programmer {
+  private final Coffee mCoffee;
+
+  @Inject
+  public Programmer(Coffee coffee) {
+    mCoffee = coffee;
+  }
+}
+```
+
+If you ask for a `Programmer`, `Dagger` will do its best to find a `Coffee` and then create a `Programmer` for you.
+
+There are two annotations in the above example, `@ActivityScope` and `@Inject`.
+`@Inject` is the simpler one and it tells Dagger that this is the constructor it should use (Dagger won’t create objects without an `@Inject` constructor).
+`@ActivityScope` tells Dagger about the life cycle of the object - there should be one instance of this object per Android Activity.
+This is probably the one you’ll be using most of the time, but there is also `@Singleton` which can be used for singletons and a couple of others.
+
+### Modules and Components
+
+The above is all very well and good, but how does non-Dagger code interact with the magic box that is Dagger?
+We need to introduce two more concepts, *Modules* and *Components*.
+(In the “I want to…” section below I’ve linked to the Modules and Components used in Chrome if you want to see a less contrived example.)
+
+A *Module* is a way of giving objects to Dagger.
+Eg:
+
+```java
+@Module
+public class MyDaggerModule {
+  private final Coffee mCoffee;
+
+  public MyDaggerModule(Coffee coffee) {
+    mCoffee = coffee;
+  }
+
+  @Provides
+  public Coffee provideCoffee() {
+    return mCoffee;
+  }
+}
+```
+
+In non-Dagger code you would create a `MyDaggerModule` and provide it with a `Coffee` (that you created yourself).
+Armed with this, Dagger can now go and create the `Programmer`.
+
+On the other side we have *Components*, which are how you get objects out of `Dagger`.
+
+```java
+@ActivityScope
+public interface MyDaggerComponent {
+  Programmer resolveProgrammer();
+}
+```
+
+You write this interface, and then during the build process, Dagger will go and implement all of these methods for you.
+When you call `resolveProgrammer`, Dagger will create a `Programmer` if it doesn’t already have one and give it to you.
+That’s the basics of Dagger, let’s look at a few changes you may want to make and how to go about them.
+
+## I want to...
+
+### access a Dagger class from a Dagger class
+
+This is pretty simple, say you want to access `Foo` from `Bar` and both of them are constructed by Dagger.
+You add `Foo` to `Bar`’s constructor and Dagger should sort it all out for you.
+
+Dagger will complain if the life cycles don’t match up (for example, you’re trying to access a `@ActivityScope` class from a `@Singleton`), and in that case you’ll have to rethink how to do things.
+
+If there’s a circular dependency, take `Lazy<Foo>` instead of `Foo`.
+A `Lazy<T>` will be resolved the first time it is accessed.
+
+### access a non-Dagger class from a Dagger class
+
+There are quite a few non-Dagger classes already provided to Dagger, so see if the class you want is provided in any of the Modules:
+
+* [BaseCustomTabActivityModule][1] - used for anything available to BaseCustomTabActivity.
+* [ChromeActivityCommonsModule][2] - used for anything available to ChromeActivity.
+* [ChromeAppModule][3] - used for singletons.
+
+If not, add it to the appropriate Module and then take it in the constructor of the class you want to access it from.
+
+### access a Dagger class from a non-Dagger class
+
+If the class is a singleton, add a suitable *resolve* method to [ChromeAppComponent][4], you can then call `ChromeApplication.getComponent().resolveMyClass()` to get access.
+
+If the class is `@ActivityScope`, add a suitable resolve method to [BaseCustomTabActivityComponent][5], and then get the object out of Dagger in `BaseCustomTabActivity#createComponent`.
+You can then fetch the instance off `BaseCustomTabActivity`.
+
+### override a class in unit tests
+
+You shouldn't need to interact with Dagger in unit tests, since you'll be constructing the class yourself.
+Since Dagger encourages injecting a class' dependencies in the constructor, it should make it easier to create an instance for testing.
+Most likely you'll want to use fakes or mocks for the class' dependencies.
+
+### override a class in instrumentation tests
+
+You can use a [ModuleOverridesRule][6] which will allow you to override the instances of class passed in to Dagger.
+For example, see the [RunningInChromeTest][7].
+
+## Finals words
+
+Hopefully that should be enough to help you make changes to Custom Tabs code.
+If you need to do something more complicated, feel free to reach out to peconn@, either by email or by adding me on your code review.
+
+[1]: https://source.chromium.org/chromium/chromium/src/+/master:chrome/android/java/src/org/chromium/chrome/browser/customtabs/dependency_injection/BaseCustomTabActivityModule.java
+[2]: https://source.chromium.org/chromium/chromium/src/+/master:chrome/android/java/src/org/chromium/chrome/browser/dependency_injection/ChromeActivityCommonsModule.java
+[3]: https://source.chromium.org/chromium/chromium/src/+/master:chrome/android/java/src/org/chromium/chrome/browser/dependency_injection/ChromeAppModule.java
+[4]: https://source.chromium.org/chromium/chromium/src/+/master:chrome/android/java/src/org/chromium/chrome/browser/dependency_injection/ChromeAppComponent.java
+[5]: https://source.chromium.org/chromium/chromium/src/+/master:chrome/android/java/src/org/chromium/chrome/browser/customtabs/dependency_injection/BaseCustomTabActivityComponent.java
+[6]: https://source.chromium.org/chromium/chromium/src/+/master:chrome/android/javatests/src/org/chromium/chrome/browser/dependency_injection/ModuleOverridesRule.java
+[7]: https://source.chromium.org/chromium/chromium/src/+/master:chrome/android/javatests/src/org/chromium/chrome/browser/browserservices/RunningInChromeTest.java
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/signin/ProfileDataCache.java b/chrome/android/java/src/org/chromium/chrome/browser/signin/ProfileDataCache.java
index 3cc8dc542..7bb0906 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/signin/ProfileDataCache.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/signin/ProfileDataCache.java
@@ -28,7 +28,9 @@
 import org.chromium.base.ThreadUtils;
 import org.chromium.chrome.R;
 import org.chromium.chrome.browser.profiles.Profile;
+import org.chromium.chrome.browser.signin.services.DisplayableProfileData;
 import org.chromium.chrome.browser.signin.services.IdentityServicesProvider;
+import org.chromium.chrome.browser.signin.services.ProfileDownloader;
 import org.chromium.components.browser_ui.util.AvatarGenerator;
 import org.chromium.components.signin.AccountManagerFacadeProvider;
 import org.chromium.components.signin.ProfileDataSource;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/signin/SigninFragmentBase.java b/chrome/android/java/src/org/chromium/chrome/browser/signin/SigninFragmentBase.java
index 1f00e39e..cd628cfb 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/signin/SigninFragmentBase.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/signin/SigninFragmentBase.java
@@ -35,6 +35,7 @@
 import org.chromium.chrome.browser.preferences.Pref;
 import org.chromium.chrome.browser.profiles.Profile;
 import org.chromium.chrome.browser.signin.account_picker.AccountPickerCoordinator;
+import org.chromium.chrome.browser.signin.services.DisplayableProfileData;
 import org.chromium.chrome.browser.signin.services.IdentityServicesProvider;
 import org.chromium.chrome.browser.signin.ui.ConsentTextTracker;
 import org.chromium.chrome.browser.sync.SyncUserDataWiper;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/signin/SigninPromoController.java b/chrome/android/java/src/org/chromium/chrome/browser/signin/SigninPromoController.java
index b3ce91d..1afb9cd 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/signin/SigninPromoController.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/signin/SigninPromoController.java
@@ -21,6 +21,7 @@
 import org.chromium.chrome.browser.preferences.ChromePreferenceKeys;
 import org.chromium.chrome.browser.preferences.SharedPreferencesManager;
 import org.chromium.chrome.browser.signin.SigninActivity.AccessPoint;
+import org.chromium.chrome.browser.signin.services.DisplayableProfileData;
 import org.chromium.components.browser_ui.widget.impression.ImpressionTracker;
 import org.chromium.components.browser_ui.widget.impression.OneShotImpressionListener;
 import org.chromium.components.signin.metrics.SigninAccessPoint;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/signin/SigninPromoUtil.java b/chrome/android/java/src/org/chromium/chrome/browser/signin/SigninPromoUtil.java
index aa599f3..9decf4f 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/signin/SigninPromoUtil.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/signin/SigninPromoUtil.java
@@ -16,6 +16,7 @@
 import org.chromium.chrome.R;
 import org.chromium.chrome.browser.preferences.Pref;
 import org.chromium.chrome.browser.profiles.Profile;
+import org.chromium.chrome.browser.signin.services.DisplayableProfileData;
 import org.chromium.chrome.browser.signin.services.IdentityServicesProvider;
 import org.chromium.chrome.browser.signin.services.SigninPreferencesManager;
 import org.chromium.chrome.browser.version.ChromeVersionInfo;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/signin/account_picker/AccountPickerBottomSheetProperties.java b/chrome/android/java/src/org/chromium/chrome/browser/signin/account_picker/AccountPickerBottomSheetProperties.java
index 455e2180..3b050c0 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/signin/account_picker/AccountPickerBottomSheetProperties.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/signin/account_picker/AccountPickerBottomSheetProperties.java
@@ -8,7 +8,7 @@
 
 import androidx.annotation.IntDef;
 
-import org.chromium.chrome.browser.signin.DisplayableProfileData;
+import org.chromium.chrome.browser.signin.services.DisplayableProfileData;
 import org.chromium.ui.modelutil.PropertyKey;
 import org.chromium.ui.modelutil.PropertyModel;
 import org.chromium.ui.modelutil.PropertyModel.ReadableObjectPropertyKey;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/signin/account_picker/AccountPickerBottomSheetView.java b/chrome/android/java/src/org/chromium/chrome/browser/signin/account_picker/AccountPickerBottomSheetView.java
index 989d95c..21c430180 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/signin/account_picker/AccountPickerBottomSheetView.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/signin/account_picker/AccountPickerBottomSheetView.java
@@ -18,8 +18,8 @@
 import androidx.recyclerview.widget.RecyclerView;
 
 import org.chromium.chrome.R;
-import org.chromium.chrome.browser.signin.DisplayableProfileData;
 import org.chromium.chrome.browser.signin.account_picker.AccountPickerBottomSheetProperties.ViewState;
+import org.chromium.chrome.browser.signin.services.DisplayableProfileData;
 import org.chromium.components.browser_ui.bottomsheet.BottomSheetContent;
 import org.chromium.ui.widget.ButtonCompat;
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/signin/account_picker/AccountPickerBottomSheetViewBinder.java b/chrome/android/java/src/org/chromium/chrome/browser/signin/account_picker/AccountPickerBottomSheetViewBinder.java
index 08f6b2eb..f23b590 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/signin/account_picker/AccountPickerBottomSheetViewBinder.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/signin/account_picker/AccountPickerBottomSheetViewBinder.java
@@ -8,8 +8,8 @@
 import androidx.annotation.StringRes;
 
 import org.chromium.chrome.R;
-import org.chromium.chrome.browser.signin.DisplayableProfileData;
 import org.chromium.chrome.browser.signin.account_picker.AccountPickerBottomSheetProperties.ViewState;
+import org.chromium.chrome.browser.signin.services.DisplayableProfileData;
 import org.chromium.ui.modelutil.PropertyKey;
 import org.chromium.ui.modelutil.PropertyModel;
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/signin/account_picker/AccountPickerMediator.java b/chrome/android/java/src/org/chromium/chrome/browser/signin/account_picker/AccountPickerMediator.java
index adb84f4..558921c 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/signin/account_picker/AccountPickerMediator.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/signin/account_picker/AccountPickerMediator.java
@@ -12,12 +12,12 @@
 
 import org.chromium.base.Callback;
 import org.chromium.chrome.R;
-import org.chromium.chrome.browser.signin.DisplayableProfileData;
 import org.chromium.chrome.browser.signin.ProfileDataCache;
 import org.chromium.chrome.browser.signin.account_picker.AccountPickerProperties.AddAccountRowProperties;
 import org.chromium.chrome.browser.signin.account_picker.AccountPickerProperties.ExistingAccountRowProperties;
 import org.chromium.chrome.browser.signin.account_picker.AccountPickerProperties.IncognitoAccountRowProperties;
 import org.chromium.chrome.browser.signin.account_picker.AccountPickerProperties.ItemType;
+import org.chromium.chrome.browser.signin.services.DisplayableProfileData;
 import org.chromium.components.signin.AccountManagerFacade;
 import org.chromium.components.signin.AccountManagerFacadeProvider;
 import org.chromium.components.signin.AccountUtils;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/signin/account_picker/AccountPickerProperties.java b/chrome/android/java/src/org/chromium/chrome/browser/signin/account_picker/AccountPickerProperties.java
index 6168b16..24602d2 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/signin/account_picker/AccountPickerProperties.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/signin/account_picker/AccountPickerProperties.java
@@ -9,7 +9,7 @@
 import androidx.annotation.IntDef;
 
 import org.chromium.base.Callback;
-import org.chromium.chrome.browser.signin.DisplayableProfileData;
+import org.chromium.chrome.browser.signin.services.DisplayableProfileData;
 import org.chromium.ui.modelutil.PropertyKey;
 import org.chromium.ui.modelutil.PropertyModel;
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/signin/account_picker/ExistingAccountRowViewBinder.java b/chrome/android/java/src/org/chromium/chrome/browser/signin/account_picker/ExistingAccountRowViewBinder.java
index aa5447a..8ae42b1d 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/signin/account_picker/ExistingAccountRowViewBinder.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/signin/account_picker/ExistingAccountRowViewBinder.java
@@ -17,8 +17,8 @@
 
 import org.chromium.chrome.R;
 import org.chromium.chrome.browser.flags.ChromeFeatureList;
-import org.chromium.chrome.browser.signin.DisplayableProfileData;
 import org.chromium.chrome.browser.signin.account_picker.AccountPickerProperties.ExistingAccountRowProperties;
+import org.chromium.chrome.browser.signin.services.DisplayableProfileData;
 import org.chromium.ui.modelutil.PropertyKey;
 import org.chromium.ui.modelutil.PropertyModel;
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/sync/settings/SignInPreference.java b/chrome/android/java/src/org/chromium/chrome/browser/sync/settings/SignInPreference.java
index e4942246..7c646cd 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/sync/settings/SignInPreference.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/sync/settings/SignInPreference.java
@@ -18,9 +18,9 @@
 import org.chromium.chrome.browser.flags.ChromeFeatureList;
 import org.chromium.chrome.browser.preferences.Pref;
 import org.chromium.chrome.browser.profiles.Profile;
-import org.chromium.chrome.browser.signin.DisplayableProfileData;
 import org.chromium.chrome.browser.signin.ProfileDataCache;
 import org.chromium.chrome.browser.signin.SigninUtils;
+import org.chromium.chrome.browser.signin.services.DisplayableProfileData;
 import org.chromium.chrome.browser.signin.services.IdentityServicesProvider;
 import org.chromium.chrome.browser.signin.services.SigninManager.SignInAllowedObserver;
 import org.chromium.chrome.browser.sync.AndroidSyncSettings;
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/signin/ProfileDataCacheRenderTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/signin/ProfileDataCacheRenderTest.java
index a5f880a..61050ea8 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/signin/ProfileDataCacheRenderTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/signin/ProfileDataCacheRenderTest.java
@@ -39,6 +39,7 @@
 import org.chromium.base.test.util.Feature;
 import org.chromium.base.test.util.JniMocker;
 import org.chromium.chrome.browser.profiles.Profile;
+import org.chromium.chrome.browser.signin.services.DisplayableProfileData;
 import org.chromium.chrome.browser.signin.services.IdentityServicesProvider;
 import org.chromium.chrome.test.ChromeJUnit4RunnerDelegate;
 import org.chromium.chrome.test.util.ChromeRenderTestRule;
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/signin/account_picker/AccountPickerMediatorTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/signin/account_picker/AccountPickerMediatorTest.java
index 6516f671..4982171c 100644
--- a/chrome/android/junit/src/org/chromium/chrome/browser/signin/account_picker/AccountPickerMediatorTest.java
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/signin/account_picker/AccountPickerMediatorTest.java
@@ -21,9 +21,9 @@
 
 import org.chromium.base.test.BaseRobolectricTestRunner;
 import org.chromium.chrome.browser.profiles.Profile;
-import org.chromium.chrome.browser.signin.DisplayableProfileData;
 import org.chromium.chrome.browser.signin.account_picker.AccountPickerProperties.AddAccountRowProperties;
 import org.chromium.chrome.browser.signin.account_picker.AccountPickerProperties.ExistingAccountRowProperties;
+import org.chromium.chrome.browser.signin.services.DisplayableProfileData;
 import org.chromium.chrome.browser.signin.services.IdentityServicesProvider;
 import org.chromium.chrome.test.util.browser.signin.AccountManagerTestRule;
 import org.chromium.components.signin.ProfileDataSource;
diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc
index b4b6a8f..657114c 100644
--- a/chrome/browser/about_flags.cc
+++ b/chrome/browser/about_flags.cc
@@ -3347,8 +3347,7 @@
      flag_descriptions::kDesktopPWAsRunOnOsLoginName,
      flag_descriptions::kDesktopPWAsRunOnOsLoginDescription, kOsWin,
      FEATURE_VALUE_TYPE(features::kDesktopPWAsRunOnOsLogin)},
-    {"record-web-app-debug-info",
-     flag_descriptions::kRecordWebAppDebugInfoName,
+    {"record-web-app-debug-info", flag_descriptions::kRecordWebAppDebugInfoName,
      flag_descriptions::kRecordWebAppDebugInfoDescription, kOsDesktop,
      FEATURE_VALUE_TYPE(features::kRecordWebAppDebugInfo)},
     {"use-sync-sandbox", flag_descriptions::kSyncSandboxName,
@@ -5573,7 +5572,7 @@
 #endif  // !defined(OS_ANDROID)
 
     {"enable-unsafe-webgpu", flag_descriptions::kUnsafeWebGPUName,
-     flag_descriptions::kUnsafeWebGPUDescription, kOsMac | kOsWin,
+     flag_descriptions::kUnsafeWebGPUDescription, kOsMac | kOsLinux | kOsWin,
      SINGLE_VALUE_TYPE(switches::kEnableUnsafeWebGPU)},
 
     {"enable-unsafe-fast-js-calls", flag_descriptions::kUnsafeFastJSCallsName,
diff --git a/chrome/browser/android/compositor/layer/contextual_search_layer.cc b/chrome/browser/android/compositor/layer/contextual_search_layer.cc
index 228d5f2..9133b44 100644
--- a/chrome/browser/android/compositor/layer/contextual_search_layer.cc
+++ b/chrome/browser/android/compositor/layer/contextual_search_layer.cc
@@ -87,11 +87,6 @@
     float progress_bar_height,
     float progress_bar_opacity,
     float progress_bar_completion,
-    float divider_line_visibility_percentage,
-    float divider_line_width,
-    float divider_line_height,
-    int divider_line_color,
-    float divider_line_x_offset,
     bool touch_highlight_visible,
     float touch_highlight_x_offset,
     float touch_highlight_width,
@@ -282,30 +277,6 @@
       progress_bar_opacity, progress_bar_completion, search_panel_width);
 
   // ---------------------------------------------------------------------------
-  // Divider Line separator.  Deprecated -- old layout only.
-  // ---------------------------------------------------------------------------
-  if (divider_line_visibility_percentage > 0.f) {
-    if (divider_line_->parent() != layer_)
-      layer_->AddChild(divider_line_);
-
-    // The divider line animates in from the bottom.
-    float divider_line_y_offset =
-        ((search_bar_height - divider_line_height) / 2) +
-        (divider_line_height * (1.f - divider_line_visibility_percentage));
-    divider_line_->SetPosition(gfx::PointF(divider_line_x_offset,
-                                           divider_line_y_offset));
-
-    // The divider line should not draw below its final resting place.
-    // Set bounds to restrict the vertical draw position.
-    divider_line_->SetBounds(
-        gfx::Size(divider_line_width,
-                  divider_line_height * divider_line_visibility_percentage));
-    divider_line_->SetBackgroundColor(divider_line_color);
-  } else if (divider_line_->parent()) {
-    divider_line_->RemoveFromParent();
-  }
-
-  // ---------------------------------------------------------------------------
   // Touch Highlight Layer
   // ---------------------------------------------------------------------------
   if (touch_highlight_visible) {
@@ -655,7 +626,6 @@
       bar_banner_text_(cc::UIResourceLayer::Create()),
       search_caption_(cc::UIResourceLayer::Create()),
       text_layer_(cc::UIResourceLayer::Create()),
-      divider_line_(cc::SolidColorLayer::Create()),
       touch_highlight_layer_(cc::SolidColorLayer::Create()) {
   // Search Bar Banner
   bar_banner_container_->SetIsDrawable(true);
@@ -690,9 +660,6 @@
   // Quick action icon
   quick_action_icon_layer_->SetIsDrawable(true);
 
-  // Divider line
-  divider_line_->SetIsDrawable(true);
-
   // Content layer
   text_layer_->SetIsDrawable(true);
   // NOTE(mdjones): This can be called multiple times to add other text layers.
diff --git a/chrome/browser/android/compositor/layer/contextual_search_layer.h b/chrome/browser/android/compositor/layer/contextual_search_layer.h
index 7bfd9708..69397fe 100644
--- a/chrome/browser/android/compositor/layer/contextual_search_layer.h
+++ b/chrome/browser/android/compositor/layer/contextual_search_layer.h
@@ -89,11 +89,6 @@
                      float progress_bar_height,
                      float progress_bar_opacity,
                      float progress_bar_completion,
-                     float divider_line_visibility_percentage,
-                     float divider_line_width,
-                     float divider_line_height,
-                     int divider_line_color,
-                     float divider_line_x_offset,
                      bool touch_highlight_visible,
                      float touch_highlight_x_offset,
                      float touch_highlight_width,
@@ -151,7 +146,6 @@
   scoped_refptr<cc::UIResourceLayer> bar_banner_text_;
   scoped_refptr<cc::UIResourceLayer> search_caption_;
   scoped_refptr<cc::UIResourceLayer> text_layer_;
-  scoped_refptr<cc::SolidColorLayer> divider_line_;
   scoped_refptr<cc::SolidColorLayer> touch_highlight_layer_;
 };
 
diff --git a/chrome/browser/android/compositor/scene_layer/contextual_search_scene_layer.cc b/chrome/browser/android/compositor/scene_layer/contextual_search_scene_layer.cc
index e1aeb36..90503f4 100644
--- a/chrome/browser/android/compositor/scene_layer/contextual_search_scene_layer.cc
+++ b/chrome/browser/android/compositor/scene_layer/contextual_search_scene_layer.cc
@@ -127,11 +127,6 @@
     jfloat progress_bar_height,
     jfloat progress_bar_opacity,
     jfloat progress_bar_completion,
-    jfloat divider_line_visibility_percentage,
-    jfloat divider_line_width,
-    jfloat divider_line_height,
-    jint divider_line_color,
-    jfloat divider_line_x_offset,
     jboolean touch_highlight_visible,
     jfloat touch_highlight_x_offset,
     jfloat touch_highlight_width,
@@ -186,8 +181,6 @@
       custom_image_visibility_percentage, bar_image_size, icon_color,
       drag_handlebar_color, close_icon_opacity, progress_bar_visible,
       progress_bar_height, progress_bar_opacity, progress_bar_completion,
-      divider_line_visibility_percentage, divider_line_width,
-      divider_line_height, divider_line_color, divider_line_x_offset,
       touch_highlight_visible, touch_highlight_x_offset, touch_highlight_width,
       rounded_bar_top_resource_id, separator_line_color);
 
diff --git a/chrome/browser/android/compositor/scene_layer/contextual_search_scene_layer.h b/chrome/browser/android/compositor/scene_layer/contextual_search_scene_layer.h
index 39e04b91..c03acbe 100644
--- a/chrome/browser/android/compositor/scene_layer/contextual_search_scene_layer.h
+++ b/chrome/browser/android/compositor/scene_layer/contextual_search_scene_layer.h
@@ -102,11 +102,6 @@
       jfloat progress_bar_height,
       jfloat progress_bar_opacity,
       jfloat progress_bar_completion,
-      jfloat divider_line_visibility_percentage,
-      jfloat divider_line_width,
-      jfloat divider_line_height,
-      jint divider_line_color,
-      jfloat divider_line_x_offset,
       jboolean touch_highlight_visible,
       jfloat touch_highlight_x_offset,
       jfloat touch_highlight_width,
diff --git a/chrome/browser/android/cookies/cookies_fetcher_util.cc b/chrome/browser/android/cookies/cookies_fetcher_util.cc
index 800abb9..42e5097 100644
--- a/chrome/browser/android/cookies/cookies_fetcher_util.cc
+++ b/chrome/browser/android/cookies/cookies_fetcher_util.cc
@@ -23,7 +23,8 @@
 
 // Returns the cookie service at the client end of the mojo pipe.
 network::mojom::CookieManager* GetCookieServiceClient() {
-  // TODO(https://crbug.com/1060940): Update to cover all OTR profiles.
+  // Since restoring Incognito CCT session from cookies is not supported, it is
+  // safe to use the primary OTR profile here.
   return content::BrowserContext::GetDefaultStoragePartition(
              ProfileManager::GetPrimaryUserProfile()->GetPrimaryOTRProfile())
       ->GetCookieManagerForBrowserProcess();
@@ -62,7 +63,6 @@
 // no-op for the standard session. Typically associated with the #onPause of
 // Android's activty lifecycle.
 void JNI_CookiesFetcher_PersistCookies(JNIEnv* env) {
-  // TODO(https://crbug.com/1060940): Update to cover all OTR profiles.
   if (!ProfileManager::GetPrimaryUserProfile()->HasPrimaryOTRProfile()) {
     // There is no work to be done. We might consider calling
     // the Java callback if needed.
@@ -92,7 +92,6 @@
     jboolean same_party,
     jint source_scheme,
     jint source_port) {
-  // TODO(https://crbug.com/1060940): Update to cover all OTR profiles.
   if (!ProfileManager::GetPrimaryUserProfile()->HasPrimaryOTRProfile())
     return;  // Don't create it. There is nothing to do.
 
diff --git a/chrome/browser/android/preferences/cookie_controls_service_bridge.cc b/chrome/browser/android/preferences/cookie_controls_service_bridge.cc
index c748f8a9..3c7f15b 100644
--- a/chrome/browser/android/preferences/cookie_controls_service_bridge.cc
+++ b/chrome/browser/android/preferences/cookie_controls_service_bridge.cc
@@ -20,7 +20,8 @@
     : jobject_(obj) {}
 
 void CookieControlsServiceBridge::UpdateServiceIfNecessary() {
-  // TODO(https://crbug.com/1060940): Update to cover all OTR profiles.
+  // This class is only for the incognito NTP, so it is safe to always use the
+  // primary OTR profile.
   Profile* profile =
       ProfileManager::GetLastUsedProfile()->GetPrimaryOTRProfile();
   CookieControlsService* new_service =
diff --git a/chrome/browser/apps/platform_apps/app_browsertest.cc b/chrome/browser/apps/platform_apps/app_browsertest.cc
index 6d5735b..3269931 100644
--- a/chrome/browser/apps/platform_apps/app_browsertest.cc
+++ b/chrome/browser/apps/platform_apps/app_browsertest.cc
@@ -393,7 +393,14 @@
   ASSERT_FALSE(menu->HasCommandWithId(IDC_CONTENT_CONTEXT_UNDO));
 }
 
-IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest, AppWithContextMenuTextField) {
+// Flaky on Mac10.13 Tests (dbg). See https://crbug.com/1155013
+#if defined(OS_MAC)
+#define MAYBE_AppWithContextMenuTextField DISABLED_AppWithContextMenuTextField
+#else
+#define MAYBE_AppWithContextMenuTextField AppWithContextMenuTextField
+#endif
+IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest,
+                       MAYBE_AppWithContextMenuTextField) {
   LoadAndLaunchPlatformApp("context_menu", "Launched");
 
   // The context_menu app has one context menu item. This, along with a
@@ -466,7 +473,8 @@
   ASSERT_TRUE(onclicked_listener.WaitUntilSatisfied());
 }
 
-IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest, DisallowNavigation) {
+// https://crbug.com/1155013
+IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest, DISABLED_DisallowNavigation) {
   TabsAddedNotificationObserver observer(browser(), 1);
 
   ASSERT_TRUE(StartEmbeddedTestServer());
diff --git a/chrome/browser/chromeos/BUILD.gn b/chrome/browser/chromeos/BUILD.gn
index 822a7b4c..b92dc0ba 100644
--- a/chrome/browser/chromeos/BUILD.gn
+++ b/chrome/browser/chromeos/BUILD.gn
@@ -870,8 +870,6 @@
     "borealis/borealis_context.h",
     "borealis/borealis_context_manager.cc",
     "borealis/borealis_context_manager.h",
-    "borealis/borealis_context_manager_factory.cc",
-    "borealis/borealis_context_manager_factory.h",
     "borealis/borealis_context_manager_impl.cc",
     "borealis/borealis_context_manager_impl.h",
     "borealis/borealis_features.cc",
@@ -3156,6 +3154,8 @@
     "attestation/mock_enrollment_certificate_uploader.h",
     "attestation/mock_machine_certificate_uploader.cc",
     "attestation/mock_machine_certificate_uploader.h",
+    "borealis/borealis_service_fake.cc",
+    "borealis/borealis_service_fake.h",
     "cert_provisioning/mock_cert_provisioning_scheduler.cc",
     "cert_provisioning/mock_cert_provisioning_scheduler.h",
     "certificate_provider/test_certificate_provider_extension.cc",
diff --git a/chrome/browser/chromeos/app_mode/kiosk_mode_idle_app_name_notification.cc b/chrome/browser/chromeos/app_mode/kiosk_mode_idle_app_name_notification.cc
index 8ae86fb..d6365f5 100644
--- a/chrome/browser/chromeos/app_mode/kiosk_mode_idle_app_name_notification.cc
+++ b/chrome/browser/chromeos/app_mode/kiosk_mode_idle_app_name_notification.cc
@@ -96,7 +96,7 @@
 }
 
 void KioskModeIdleAppNameNotification::SuspendDone(
-    const base::TimeDelta& sleep_duration) {
+    base::TimeDelta sleep_duration) {
   // When we come back from a system resume we stop the timer and show the
   // message.
   timer_.Stop();
diff --git a/chrome/browser/chromeos/app_mode/kiosk_mode_idle_app_name_notification.h b/chrome/browser/chromeos/app_mode/kiosk_mode_idle_app_name_notification.h
index c4f4e6d..3b4343fa 100644
--- a/chrome/browser/chromeos/app_mode/kiosk_mode_idle_app_name_notification.h
+++ b/chrome/browser/chromeos/app_mode/kiosk_mode_idle_app_name_notification.h
@@ -35,7 +35,7 @@
   void OnUserActivity(const ui::Event* event) override;
 
   // PowerManagerClient::Observer overrides:
-  void SuspendDone(const base::TimeDelta& sleep_duration) override;
+  void SuspendDone(base::TimeDelta sleep_duration) override;
 
   // Begins listening for user activity and calls ResetTimer().
   void Start();
diff --git a/chrome/browser/chromeos/borealis/borealis_app_launcher.cc b/chrome/browser/chromeos/borealis/borealis_app_launcher.cc
index bbae67a..dd800b8 100644
--- a/chrome/browser/chromeos/borealis/borealis_app_launcher.cc
+++ b/chrome/browser/chromeos/borealis/borealis_app_launcher.cc
@@ -7,7 +7,6 @@
 #include "base/bind.h"
 #include "chrome/browser/chromeos/borealis/borealis_context.h"
 #include "chrome/browser/chromeos/borealis/borealis_context_manager.h"
-#include "chrome/browser/chromeos/borealis/borealis_context_manager_factory.h"
 #include "chrome/browser/chromeos/borealis/borealis_features.h"
 #include "chrome/browser/chromeos/borealis/borealis_service.h"
 #include "chrome/browser/chromeos/borealis/borealis_util.h"
@@ -86,7 +85,7 @@
     return;
   }
 
-  BorealisContextManagerFactory::GetForProfile(profile_)->StartBorealis(
+  BorealisService::GetForProfile(profile_)->ContextManager().StartBorealis(
       base::BindOnce(
           [](std::string app_id,
              BorealisAppLauncher::OnLaunchedCallback callback,
diff --git a/chrome/browser/chromeos/borealis/borealis_context_manager_factory.cc b/chrome/browser/chromeos/borealis/borealis_context_manager_factory.cc
deleted file mode 100644
index c21c7dc..0000000
--- a/chrome/browser/chromeos/borealis/borealis_context_manager_factory.cc
+++ /dev/null
@@ -1,48 +0,0 @@
-// Copyright 2020 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chrome/browser/chromeos/borealis/borealis_context_manager_factory.h"
-
-#include "chrome/browser/chromeos/borealis/borealis_context_manager_impl.h"
-#include "chrome/browser/chromeos/profiles/profile_helper.h"
-#include "chrome/browser/profiles/incognito_helpers.h"
-#include "chrome/browser/profiles/profile.h"
-#include "components/keyed_service/content/browser_context_dependency_manager.h"
-
-namespace borealis {
-
-// static
-BorealisContextManager* BorealisContextManagerFactory::GetForProfile(
-    Profile* profile) {
-  return static_cast<BorealisContextManager*>(
-      GetInstance()->GetServiceForBrowserContext(profile, true));
-}
-
-// static
-BorealisContextManagerFactory* BorealisContextManagerFactory::GetInstance() {
-  static base::NoDestructor<BorealisContextManagerFactory> factory;
-  return factory.get();
-}
-
-BorealisContextManagerFactory::BorealisContextManagerFactory()
-    : BrowserContextKeyedServiceFactory(
-          "BorealisContextManager",
-          BrowserContextDependencyManager::GetInstance()) {}
-
-BorealisContextManagerFactory::~BorealisContextManagerFactory() = default;
-
-KeyedService* BorealisContextManagerFactory::BuildServiceInstanceFor(
-    content::BrowserContext* context) const {
-  Profile* profile = Profile::FromBrowserContext(context);
-  if (chromeos::ProfileHelper::IsPrimaryProfile(profile))
-    return new BorealisContextManagerImpl(profile);
-  return nullptr;
-}
-
-content::BrowserContext* BorealisContextManagerFactory::GetBrowserContextToUse(
-    content::BrowserContext* context) const {
-  return chrome::GetBrowserContextRedirectedInIncognito(context);
-}
-
-}  // namespace borealis
diff --git a/chrome/browser/chromeos/borealis/borealis_context_manager_factory.h b/chrome/browser/chromeos/borealis/borealis_context_manager_factory.h
deleted file mode 100644
index 6124ecf..0000000
--- a/chrome/browser/chromeos/borealis/borealis_context_manager_factory.h
+++ /dev/null
@@ -1,45 +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_BOREALIS_BOREALIS_CONTEXT_MANAGER_FACTORY_H_
-#define CHROME_BROWSER_CHROMEOS_BOREALIS_BOREALIS_CONTEXT_MANAGER_FACTORY_H_
-
-#include "base/macros.h"
-#include "base/no_destructor.h"
-#include "components/keyed_service/content/browser_context_keyed_service_factory.h"
-
-namespace content {
-class BrowserContext;
-}  // namespace content
-
-class Profile;
-
-namespace borealis {
-
-class BorealisContextManager;
-
-class BorealisContextManagerFactory : public BrowserContextKeyedServiceFactory {
- public:
-  static BorealisContextManager* GetForProfile(Profile* profile);
-  static BorealisContextManagerFactory* GetInstance();
-
- private:
-  friend base::NoDestructor<BorealisContextManagerFactory>;
-
-  BorealisContextManagerFactory();
-  BorealisContextManagerFactory(const BorealisContextManagerFactory&) = delete;
-  BorealisContextManagerFactory& operator=(
-      const BorealisContextManagerFactory&) = delete;
-  ~BorealisContextManagerFactory() override;
-
-  // BrowserContextKeyedServiceFactory implementation.
-  KeyedService* BuildServiceInstanceFor(
-      content::BrowserContext* context) const override;
-  content::BrowserContext* GetBrowserContextToUse(
-      content::BrowserContext* context) const override;
-};
-
-}  // namespace borealis
-
-#endif  // CHROME_BROWSER_CHROMEOS_BOREALIS_BOREALIS_CONTEXT_MANAGER_FACTORY_H_
diff --git a/chrome/browser/chromeos/borealis/borealis_context_manager_unittest.cc b/chrome/browser/chromeos/borealis/borealis_context_manager_unittest.cc
index 813e09a..0949d80f 100644
--- a/chrome/browser/chromeos/borealis/borealis_context_manager_unittest.cc
+++ b/chrome/browser/chromeos/borealis/borealis_context_manager_unittest.cc
@@ -12,7 +12,6 @@
 #include "base/test/bind.h"
 #include "base/test/metrics/histogram_tester.h"
 #include "chrome/browser/chromeos/borealis/borealis_context_manager.h"
-#include "chrome/browser/chromeos/borealis/borealis_context_manager_factory.h"
 #include "chrome/browser/chromeos/borealis/borealis_metrics.h"
 #include "chrome/browser/chromeos/borealis/borealis_task.h"
 #include "chrome/browser/chromeos/login/users/mock_user_manager.h"
@@ -310,48 +309,5 @@
   task_environment_.RunUntilIdle();
 }
 
-class BorealisContextManagerFactoryTest : public testing::Test {
- public:
-  BorealisContextManagerFactoryTest() = default;
-  BorealisContextManagerFactoryTest(const BorealisContextManagerFactoryTest&) =
-      delete;
-  BorealisContextManagerFactoryTest& operator=(
-      const BorealisContextManagerFactoryTest&) = delete;
-  ~BorealisContextManagerFactoryTest() override = default;
-
- protected:
-  void TearDown() override { chromeos::DBusThreadManager::Shutdown(); }
-
-  content::BrowserTaskEnvironment task_environment_;
-};
-
-TEST_F(BorealisContextManagerFactoryTest, ReturnsContextManagerForMainProfile) {
-  TestingProfile profile;
-  std::unique_ptr<user_manager::ScopedUserManager> scoped_user_manager;
-  auto mock_user_manager =
-      std::make_unique<testing::NiceMock<chromeos::MockUserManager>>();
-  mock_user_manager->AddUser(
-      AccountId::FromUserEmailGaiaId(profile.GetProfileUserName(), "id"));
-  scoped_user_manager = std::make_unique<user_manager::ScopedUserManager>(
-      std::move(mock_user_manager));
-  chromeos::DBusThreadManager::Initialize();
-
-  BorealisContextManager* context_manager =
-      BorealisContextManagerFactory::GetForProfile(&profile);
-  EXPECT_TRUE(context_manager);
-}
-
-TEST_F(BorealisContextManagerFactoryTest,
-       ReturnsNullpointerForSecondaryProfile) {
-  TestingProfile::Builder profile_builder;
-  profile_builder.SetProfileName("defaultprofile");
-  std::unique_ptr<TestingProfile> profile = profile_builder.Build();
-  chromeos::DBusThreadManager::Initialize();
-
-  BorealisContextManager* context_manager =
-      BorealisContextManagerFactory::GetForProfile(profile.get());
-  EXPECT_FALSE(context_manager);
-}
-
 }  // namespace
 }  // namespace borealis
diff --git a/chrome/browser/chromeos/borealis/borealis_service.h b/chrome/browser/chromeos/borealis/borealis_service.h
index 9f28a9b..70fc8efe 100644
--- a/chrome/browser/chromeos/borealis/borealis_service.h
+++ b/chrome/browser/chromeos/borealis/borealis_service.h
@@ -12,6 +12,7 @@
 namespace borealis {
 
 class BorealisAppLauncher;
+class BorealisContextManager;
 class BorealisFeatures;
 class BorealisWindowManager;
 
@@ -24,6 +25,7 @@
   ~BorealisService() override = default;
 
   virtual BorealisAppLauncher& AppLauncher() = 0;
+  virtual BorealisContextManager& ContextManager() = 0;
   virtual BorealisFeatures& Features() = 0;
   virtual BorealisWindowManager& WindowManager() = 0;
 };
diff --git a/chrome/browser/chromeos/borealis/borealis_service_fake.cc b/chrome/browser/chromeos/borealis/borealis_service_fake.cc
new file mode 100644
index 0000000..53f9374
--- /dev/null
+++ b/chrome/browser/chromeos/borealis/borealis_service_fake.cc
@@ -0,0 +1,63 @@
+// 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/borealis/borealis_service_fake.h"
+
+#include "chrome/browser/chromeos/borealis/borealis_service_factory.h"
+
+namespace borealis {
+
+// static
+BorealisServiceFake* BorealisServiceFake::UseFakeForTesting(
+    content::BrowserContext* context) {
+  return static_cast<BorealisServiceFake*>(
+      borealis::BorealisServiceFactory::GetInstance()->SetTestingFactoryAndUse(
+          context, base::BindRepeating([](content::BrowserContext* context)
+                                           -> std::unique_ptr<KeyedService> {
+            return std::make_unique<BorealisServiceFake>();
+          })));
+}
+
+BorealisServiceFake::~BorealisServiceFake() = default;
+
+BorealisAppLauncher& BorealisServiceFake::AppLauncher() {
+  DCHECK(app_launcher_);
+  return *app_launcher_;
+}
+
+BorealisContextManager& BorealisServiceFake::ContextManager() {
+  DCHECK(context_manager_);
+  return *context_manager_;
+}
+
+BorealisFeatures& BorealisServiceFake::Features() {
+  DCHECK(features_);
+  return *features_;
+}
+
+BorealisWindowManager& BorealisServiceFake::WindowManager() {
+  DCHECK(window_manager_);
+  return *window_manager_;
+}
+
+void BorealisServiceFake::SetAppLauncherForTesting(
+    BorealisAppLauncher* app_launcher) {
+  app_launcher_ = app_launcher;
+}
+
+void BorealisServiceFake::SetContextManagerForTesting(
+    BorealisContextManager* context_manager) {
+  context_manager_ = context_manager;
+}
+
+void BorealisServiceFake::SetFeaturesForTesting(BorealisFeatures* features) {
+  features_ = features;
+}
+
+void BorealisServiceFake::SetWindowManagerForTesting(
+    BorealisWindowManager* window_manager) {
+  window_manager_ = window_manager;
+}
+
+}  // namespace borealis
diff --git a/chrome/browser/chromeos/borealis/borealis_service_fake.h b/chrome/browser/chromeos/borealis/borealis_service_fake.h
new file mode 100644
index 0000000..8b91c21
--- /dev/null
+++ b/chrome/browser/chromeos/borealis/borealis_service_fake.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_CHROMEOS_BOREALIS_BOREALIS_SERVICE_FAKE_H_
+#define CHROME_BROWSER_CHROMEOS_BOREALIS_BOREALIS_SERVICE_FAKE_H_
+
+#include "chrome/browser/chromeos/borealis/borealis_service.h"
+
+namespace content {
+class BrowserContext;
+}
+
+namespace borealis {
+
+class BorealisServiceFake : public BorealisService {
+ public:
+  // Causes the service for the given |context| to be a fake in tests. Returns a
+  // handle to the fake, which will be owned by the service factory.
+  static BorealisServiceFake* UseFakeForTesting(
+      content::BrowserContext* context);
+
+  ~BorealisServiceFake() override;
+
+  BorealisAppLauncher& AppLauncher() override;
+  BorealisContextManager& ContextManager() override;
+  BorealisFeatures& Features() override;
+  BorealisWindowManager& WindowManager() override;
+
+  void SetAppLauncherForTesting(BorealisAppLauncher* app_launcher);
+  void SetContextManagerForTesting(BorealisContextManager* context_manager);
+  void SetFeaturesForTesting(BorealisFeatures* features);
+  void SetWindowManagerForTesting(BorealisWindowManager* window_manager);
+
+ private:
+  BorealisAppLauncher* app_launcher_ = nullptr;
+  BorealisContextManager* context_manager_ = nullptr;
+  BorealisFeatures* features_ = nullptr;
+  BorealisWindowManager* window_manager_ = nullptr;
+};
+
+}  // namespace borealis
+
+#endif  // CHROME_BROWSER_CHROMEOS_BOREALIS_BOREALIS_SERVICE_FAKE_H_
diff --git a/chrome/browser/chromeos/borealis/borealis_service_impl.cc b/chrome/browser/chromeos/borealis/borealis_service_impl.cc
index f3b515e6..9e5d0fd 100644
--- a/chrome/browser/chromeos/borealis/borealis_service_impl.cc
+++ b/chrome/browser/chromeos/borealis/borealis_service_impl.cc
@@ -14,6 +14,7 @@
 BorealisServiceImpl::BorealisServiceImpl(Profile* profile)
     : profile_(profile),
       app_launcher_(profile_),
+      context_manager_(profile),
       features_(profile_),
       window_manager_(profile_) {}
 
@@ -23,6 +24,10 @@
   return app_launcher_;
 }
 
+BorealisContextManager& BorealisServiceImpl::ContextManager() {
+  return context_manager_;
+}
+
 BorealisFeatures& BorealisServiceImpl::Features() {
   return features_;
 }
diff --git a/chrome/browser/chromeos/borealis/borealis_service_impl.h b/chrome/browser/chromeos/borealis/borealis_service_impl.h
index d8713e8..5b8333f 100644
--- a/chrome/browser/chromeos/borealis/borealis_service_impl.h
+++ b/chrome/browser/chromeos/borealis/borealis_service_impl.h
@@ -8,6 +8,7 @@
 #include "chrome/browser/chromeos/borealis/borealis_service.h"
 
 #include "chrome/browser/chromeos/borealis/borealis_app_launcher.h"
+#include "chrome/browser/chromeos/borealis/borealis_context_manager_impl.h"
 #include "chrome/browser/chromeos/borealis/borealis_features.h"
 #include "chrome/browser/chromeos/borealis/borealis_window_manager.h"
 
@@ -22,12 +23,14 @@
  private:
   // BorealisService overrides.
   BorealisAppLauncher& AppLauncher() override;
+  BorealisContextManager& ContextManager() override;
   BorealisFeatures& Features() override;
   BorealisWindowManager& WindowManager() override;
 
   Profile* const profile_;
 
   BorealisAppLauncher app_launcher_;
+  BorealisContextManagerImpl context_manager_;
   BorealisFeatures features_;
   BorealisWindowManager window_manager_;
 };
diff --git a/chrome/browser/chromeos/child_accounts/event_based_status_reporting_service.cc b/chrome/browser/chromeos/child_accounts/event_based_status_reporting_service.cc
index 48af12aa..db7fa68 100644
--- a/chrome/browser/chromeos/child_accounts/event_based_status_reporting_service.cc
+++ b/chrome/browser/chromeos/child_accounts/event_based_status_reporting_service.cc
@@ -98,8 +98,7 @@
     RequestStatusReport(StatusReportEvent::kDeviceOnline);
 }
 
-void EventBasedStatusReportingService::SuspendDone(
-    const base::TimeDelta& duration) {
+void EventBasedStatusReportingService::SuspendDone(base::TimeDelta duration) {
   RequestStatusReport(StatusReportEvent::kSuspendDone);
 }
 
diff --git a/chrome/browser/chromeos/child_accounts/event_based_status_reporting_service.h b/chrome/browser/chromeos/child_accounts/event_based_status_reporting_service.h
index 3a8df742..1f5f828 100644
--- a/chrome/browser/chromeos/child_accounts/event_based_status_reporting_service.h
+++ b/chrome/browser/chromeos/child_accounts/event_based_status_reporting_service.h
@@ -72,7 +72,7 @@
   void OnConnectionChanged(network::mojom::ConnectionType type) override;
 
   // PowerManagerClient::Observer:
-  void SuspendDone(const base::TimeDelta& duration) override;
+  void SuspendDone(base::TimeDelta duration) override;
 
   // ScreenTimeController::Observer:
   void UsageTimeLimitWarning() override;
diff --git a/chrome/browser/chromeos/child_accounts/usage_time_state_notifier.cc b/chrome/browser/chromeos/child_accounts/usage_time_state_notifier.cc
index 3509dcd..5fab3cc 100644
--- a/chrome/browser/chromeos/child_accounts/usage_time_state_notifier.cc
+++ b/chrome/browser/chromeos/child_accounts/usage_time_state_notifier.cc
@@ -90,8 +90,7 @@
   ChangeUsageTimeState(UsageTimeState::INACTIVE);
 }
 
-void UsageTimeStateNotifier::SuspendDone(
-    const base::TimeDelta& sleep_duration) {
+void UsageTimeStateNotifier::SuspendDone(base::TimeDelta sleep_duration) {
   ChangeUsageTimeState(GetCurrentState());
 }
 
diff --git a/chrome/browser/chromeos/child_accounts/usage_time_state_notifier.h b/chrome/browser/chromeos/child_accounts/usage_time_state_notifier.h
index 652f05a..f475170 100644
--- a/chrome/browser/chromeos/child_accounts/usage_time_state_notifier.h
+++ b/chrome/browser/chromeos/child_accounts/usage_time_state_notifier.h
@@ -64,7 +64,7 @@
   void ScreenIdleStateChanged(
       const power_manager::ScreenIdleState& state) override;
   void SuspendImminent(power_manager::SuspendImminent::Reason reason) override;
-  void SuspendDone(const base::TimeDelta& sleep_duration) override;
+  void SuspendDone(base::TimeDelta sleep_duration) override;
 
   base::ObserverList<Observer> observers_;
 
diff --git a/chrome/browser/chromeos/crostini/crostini_manager.cc b/chrome/browser/chromeos/crostini/crostini_manager.cc
index caf0a4d..e4e6023 100644
--- a/chrome/browser/chromeos/crostini/crostini_manager.cc
+++ b/chrome/browser/chromeos/crostini/crostini_manager.cc
@@ -3429,7 +3429,7 @@
                      weak_ptr_factory_.GetWeakPtr(), token));
 }
 
-void CrostiniManager::SuspendDone(const base::TimeDelta& sleep_duration) {
+void CrostiniManager::SuspendDone(base::TimeDelta sleep_duration) {
   // https://crbug.com/968060.  Sshfs is unmounted before suspend,
   // call RestartCrostini to force remount if container is running.
   ContainerId container_id = ContainerId::GetDefault();
diff --git a/chrome/browser/chromeos/crostini/crostini_manager.h b/chrome/browser/chromeos/crostini/crostini_manager.h
index ee29b89..ccbeacd 100644
--- a/chrome/browser/chromeos/crostini/crostini_manager.h
+++ b/chrome/browser/chromeos/crostini/crostini_manager.h
@@ -568,7 +568,7 @@
 
   // chromeos::PowerManagerClient::Observer overrides:
   void SuspendImminent(power_manager::SuspendImminent::Reason reason) override;
-  void SuspendDone(const base::TimeDelta& sleep_duration) override;
+  void SuspendDone(base::TimeDelta sleep_duration) override;
 
   // Callback for |RemoveSshfsCrostiniVolume| called from |SuspendImminent| when
   // the device is allowed to suspend. Removes metadata associated with the
diff --git a/chrome/browser/chromeos/drive/drive_integration_service.cc b/chrome/browser/chromeos/drive/drive_integration_service.cc
index 0abcc5f..47d6232 100644
--- a/chrome/browser/chromeos/drive/drive_integration_service.cc
+++ b/chrome/browser/chromeos/drive/drive_integration_service.cc
@@ -1035,8 +1035,7 @@
   RemoveDriveMountPoint();
 }
 
-void DriveIntegrationService::SuspendDone(
-    const base::TimeDelta& sleep_duration) {
+void DriveIntegrationService::SuspendDone(base::TimeDelta sleep_duration) {
   if (is_enabled()) {
     AddDriveMountPoint();
   }
diff --git a/chrome/browser/chromeos/drive/drive_integration_service.h b/chrome/browser/chromeos/drive/drive_integration_service.h
index b7a826a..46ffa26 100644
--- a/chrome/browser/chromeos/drive/drive_integration_service.h
+++ b/chrome/browser/chromeos/drive/drive_integration_service.h
@@ -273,7 +273,7 @@
 
   // chromeos::PowerManagerClient::Observer overrides:
   void SuspendImminent(power_manager::SuspendImminent::Reason reason) override;
-  void SuspendDone(const base::TimeDelta& sleep_duration) override;
+  void SuspendDone(base::TimeDelta sleep_duration) override;
 
   void OnGetQuickAccessItems(
       GetQuickAccessItemsCallback callback,
diff --git a/chrome/browser/chromeos/extensions/device_local_account_external_policy_loader.cc b/chrome/browser/chromeos/extensions/device_local_account_external_policy_loader.cc
index 2c98156..11271307 100644
--- a/chrome/browser/chromeos/extensions/device_local_account_external_policy_loader.cc
+++ b/chrome/browser/chromeos/extensions/device_local_account_external_policy_loader.cc
@@ -106,7 +106,7 @@
   const policy::PolicyMap& policy_map = store_->policy_map();
   // TODO(binjin): Use two policy handlers here after
   // ExtensionManagementPolicyHandler is introduced.
-  extensions::ExtensionInstallForcelistPolicyHandler policy_handler;
+  extensions::ExtensionInstallForceListPolicyHandler policy_handler;
   if (policy_handler.CheckPolicySettings(policy_map, NULL)) {
     PrefValueMap pref_value_map;
     policy_handler.ApplyPolicySettings(policy_map, &pref_value_map);
diff --git a/chrome/browser/chromeos/extensions/file_manager/device_event_router.cc b/chrome/browser/chromeos/extensions/file_manager/device_event_router.cc
index 6a3441d..afe9917 100644
--- a/chrome/browser/chromeos/extensions/file_manager/device_event_router.cc
+++ b/chrome/browser/chromeos/extensions/file_manager/device_event_router.cc
@@ -170,7 +170,7 @@
   is_resuming_ = true;
 }
 
-void DeviceEventRouter::SuspendDone(const base::TimeDelta& sleep_duration) {
+void DeviceEventRouter::SuspendDone(base::TimeDelta sleep_duration) {
   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
   base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
       FROM_HERE,
diff --git a/chrome/browser/chromeos/extensions/file_manager/device_event_router.h b/chrome/browser/chromeos/extensions/file_manager/device_event_router.h
index c6ebbc5..3126076 100644
--- a/chrome/browser/chromeos/extensions/file_manager/device_event_router.h
+++ b/chrome/browser/chromeos/extensions/file_manager/device_event_router.h
@@ -71,7 +71,7 @@
 
   // PowerManagerClient::Observer overrides.
   void SuspendImminent(power_manager::SuspendImminent::Reason reason) override;
-  void SuspendDone(const base::TimeDelta& sleep_duration) override;
+  void SuspendDone(base::TimeDelta sleep_duration) override;
 
   bool is_resuming() const { return is_resuming_; }
   bool is_starting_up() const { return is_starting_up_; }
diff --git a/chrome/browser/chromeos/extensions/signin_screen_extensions_external_loader.cc b/chrome/browser/chromeos/extensions/signin_screen_extensions_external_loader.cc
index aef5201..ff9f7d2 100644
--- a/chrome/browser/chromeos/extensions/signin_screen_extensions_external_loader.cc
+++ b/chrome/browser/chromeos/extensions/signin_screen_extensions_external_loader.cc
@@ -30,7 +30,7 @@
 
 base::Value GetForceInstalledExtensionsFromPrefs(const PrefService* prefs) {
   const PrefService::Preference* const login_screen_extensions_pref =
-      prefs->FindPreference(extensions::pref_names::kLoginScreenExtensions);
+      prefs->FindPreference(extensions::pref_names::kInstallForceList);
   CHECK(login_screen_extensions_pref);
   if (!login_screen_extensions_pref->IsManaged() &&
       !login_screen_extensions_pref->IsDefaultValue()) {
@@ -38,7 +38,7 @@
     // (This branch could be triggered if, for example, an attacker modified the
     // Local State file trying to inject some extensions into the Login Screen.)
     LOG(WARNING) << "Ignoring untrusted value of the "
-                 << extensions::pref_names::kLoginScreenExtensions << " pref";
+                 << extensions::pref_names::kInstallForceList << " pref";
     return base::Value(base::Value::Type::DICTIONARY);
   }
   const base::Value* login_screen_extensions_pref_value =
@@ -105,7 +105,7 @@
 void SigninScreenExtensionsExternalLoader::SubscribeAndInitializeFromPrefs() {
   pref_change_registrar_.Init(profile_->GetPrefs());
   pref_change_registrar_.Add(
-      extensions::pref_names::kLoginScreenExtensions,
+      extensions::pref_names::kInstallForceList,
       base::Bind(&SigninScreenExtensionsExternalLoader::UpdateStateFromPrefs,
                  base::Unretained(this)));
 
diff --git a/chrome/browser/chromeos/login/challenge_response_auth_keys_loader.cc b/chrome/browser/chromeos/login/challenge_response_auth_keys_loader.cc
index 0b9797f..1e0ebea2 100644
--- a/chrome/browser/chromeos/login/challenge_response_auth_keys_loader.cc
+++ b/chrome/browser/chromeos/login/challenge_response_auth_keys_loader.cc
@@ -54,7 +54,7 @@
             PrefService::INITIALIZATION_STATUS_SUCCESS);
 
   const PrefService::Preference* const pref =
-      prefs->FindPreference(extensions::pref_names::kLoginScreenExtensions);
+      prefs->FindPreference(extensions::pref_names::kInstallForceList);
   if (!pref || !pref->IsManaged() ||
       pref->GetType() != base::Value::Type::DICTIONARY)
     return {};
diff --git a/chrome/browser/chromeos/login/easy_unlock/easy_unlock_service.cc b/chrome/browser/chromeos/login/easy_unlock/easy_unlock_service.cc
index 462c5a8..dafa3ce 100644
--- a/chrome/browser/chromeos/login/easy_unlock/easy_unlock_service.cc
+++ b/chrome/browser/chromeos/login/easy_unlock/easy_unlock_service.cc
@@ -97,7 +97,7 @@
     service_->PrepareForSuspend();
   }
 
-  void SuspendDone(const base::TimeDelta& sleep_duration) override {
+  void SuspendDone(base::TimeDelta sleep_duration) override {
     base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
         FROM_HERE,
         base::BindOnce(&PowerMonitor::ResetWakingUp,
diff --git a/chrome/browser/chromeos/login/lock/views_screen_locker.cc b/chrome/browser/chromeos/login/lock/views_screen_locker.cc
index e2c1a6b..794726e 100644
--- a/chrome/browser/chromeos/login/lock/views_screen_locker.cc
+++ b/chrome/browser/chromeos/login/lock/views_screen_locker.cc
@@ -176,7 +176,7 @@
   NOTREACHED();
 }
 
-void ViewsScreenLocker::SuspendDone(const base::TimeDelta& sleep_duration) {
+void ViewsScreenLocker::SuspendDone(base::TimeDelta sleep_duration) {
   for (user_manager::User* user :
        user_manager::UserManager::Get()->GetUnlockUsers()) {
     UpdatePinKeyboardState(user->GetAccountId());
diff --git a/chrome/browser/chromeos/login/lock/views_screen_locker.h b/chrome/browser/chromeos/login/lock/views_screen_locker.h
index 992ca0d..909b9fa7b 100644
--- a/chrome/browser/chromeos/login/lock/views_screen_locker.h
+++ b/chrome/browser/chromeos/login/lock/views_screen_locker.h
@@ -61,7 +61,7 @@
                                  const std::string& input_method) override;
 
   // PowerManagerClient::Observer:
-  void SuspendDone(const base::TimeDelta& sleep_duration) override;
+  void SuspendDone(base::TimeDelta sleep_duration) override;
 
   // lock_screen_apps::FocusCyclerDelegate:
   void RegisterLockScreenAppFocusHandler(
diff --git a/chrome/browser/chromeos/login/login_screen_extensions_lifetime_manager.cc b/chrome/browser/chromeos/login/login_screen_extensions_lifetime_manager.cc
index d39f30f..78431d0 100644
--- a/chrome/browser/chromeos/login/login_screen_extensions_lifetime_manager.cc
+++ b/chrome/browser/chromeos/login/login_screen_extensions_lifetime_manager.cc
@@ -37,7 +37,7 @@
             PrefService::INITIALIZATION_STATUS_SUCCESS);
 
   const PrefService::Preference* const pref =
-      prefs->FindPreference(extensions::pref_names::kLoginScreenExtensions);
+      prefs->FindPreference(extensions::pref_names::kInstallForceList);
   if (!pref || !pref->IsManaged() ||
       pref->GetType() != base::Value::Type::DICTIONARY) {
     return {};
diff --git a/chrome/browser/chromeos/login/login_screen_extensions_storage_cleaner.cc b/chrome/browser/chromeos/login/login_screen_extensions_storage_cleaner.cc
index 88241193..ec1e144 100644
--- a/chrome/browser/chromeos/login/login_screen_extensions_storage_cleaner.cc
+++ b/chrome/browser/chromeos/login/login_screen_extensions_storage_cleaner.cc
@@ -28,7 +28,7 @@
   prefs_ = ProfileHelper::GetSigninProfile()->GetPrefs();
   pref_change_registrar_.Init(prefs_);
   pref_change_registrar_.Add(
-      extensions::pref_names::kLoginScreenExtensions,
+      extensions::pref_names::kInstallForceList,
       base::BindRepeating(&LoginScreenExtensionsStorageCleaner::OnPolicyUpdated,
                           base::Unretained(this)));
   ClearPersistentDataForUninstalledExtensions();
@@ -45,7 +45,7 @@
     ClearPersistentDataForUninstalledExtensions() {
   std::vector<std::string> installed_extension_ids;
   const PrefService::Preference* const pref =
-      prefs_->FindPreference(extensions::pref_names::kLoginScreenExtensions);
+      prefs_->FindPreference(extensions::pref_names::kInstallForceList);
   if (pref && pref->IsManaged() &&
       pref->GetType() == base::Value::Type::DICTIONARY) {
     // Each `item` contains a pair of extension ID and update URL.
diff --git a/chrome/browser/chromeos/network_change_manager_client.cc b/chrome/browser/chromeos/network_change_manager_client.cc
index 77e954a5..c229460a 100644
--- a/chrome/browser/chromeos/network_change_manager_client.cc
+++ b/chrome/browser/chromeos/network_change_manager_client.cc
@@ -40,8 +40,7 @@
   PowerManagerClient::Get()->RemoveObserver(this);
 }
 
-void NetworkChangeManagerClient::SuspendDone(
-    const base::TimeDelta& sleep_duration) {
+void NetworkChangeManagerClient::SuspendDone(base::TimeDelta sleep_duration) {
   // Force invalidation of network resources on resume.
   network_change_notifier_->OnIPAddressChanged();
   if (network_change_manager_) {
diff --git a/chrome/browser/chromeos/network_change_manager_client.h b/chrome/browser/chromeos/network_change_manager_client.h
index af47c95..e2634cb 100644
--- a/chrome/browser/chromeos/network_change_manager_client.h
+++ b/chrome/browser/chromeos/network_change_manager_client.h
@@ -33,7 +33,7 @@
   ~NetworkChangeManagerClient() override;
 
   // PowerManagerClient::Observer overrides.
-  void SuspendDone(const base::TimeDelta& sleep_duration) override;
+  void SuspendDone(base::TimeDelta sleep_duration) override;
 
   // NetworkStateHandlerObserver overrides.
   void DefaultNetworkChanged(
diff --git a/chrome/browser/chromeos/policy/arc_app_install_event_log_collector.cc b/chrome/browser/chromeos/policy/arc_app_install_event_log_collector.cc
index b05ae33..15e05df 100644
--- a/chrome/browser/chromeos/policy/arc_app_install_event_log_collector.cc
+++ b/chrome/browser/chromeos/policy/arc_app_install_event_log_collector.cc
@@ -96,7 +96,7 @@
 }
 
 void ArcAppInstallEventLogCollector::SuspendDone(
-    const base::TimeDelta& sleep_duration) {
+    base::TimeDelta sleep_duration) {
   delegate_->AddForAllPackages(
       CreateSessionChangeEvent(em::AppInstallReportLogEvent::RESUME));
 }
diff --git a/chrome/browser/chromeos/policy/arc_app_install_event_log_collector.h b/chrome/browser/chromeos/policy/arc_app_install_event_log_collector.h
index 24fc1b0..957cc2b 100644
--- a/chrome/browser/chromeos/policy/arc_app_install_event_log_collector.h
+++ b/chrome/browser/chromeos/policy/arc_app_install_event_log_collector.h
@@ -68,7 +68,7 @@
 
   // chromeos::PowerManagerClient::Observer:
   void SuspendImminent(power_manager::SuspendImminent::Reason reason) override;
-  void SuspendDone(const base::TimeDelta& sleep_duration) override;
+  void SuspendDone(base::TimeDelta sleep_duration) override;
 
   // arc::ArcPolicyBridge::Observer:
   void OnCloudDpsRequested(base::Time time,
diff --git a/chrome/browser/chromeos/policy/device_local_account_extension_tracker.cc b/chrome/browser/chromeos/policy/device_local_account_extension_tracker.cc
index e15351d6..e22e078 100644
--- a/chrome/browser/chromeos/policy/device_local_account_extension_tracker.cc
+++ b/chrome/browser/chromeos/policy/device_local_account_extension_tracker.cc
@@ -57,7 +57,7 @@
 
   // TODO(binjin): Use two policy handlers here after
   // ExtensionManagementPolicyHandler is introduced.
-  extensions::ExtensionInstallForcelistPolicyHandler policy_handler;
+  extensions::ExtensionInstallForceListPolicyHandler policy_handler;
   if (!policy_handler.CheckPolicySettings(policy_map, NULL))
     return;
 
diff --git a/chrome/browser/chromeos/policy/extension_install_event_log_collector.cc b/chrome/browser/chromeos/policy/extension_install_event_log_collector.cc
index cb171a8..7b6e398 100644
--- a/chrome/browser/chromeos/policy/extension_install_event_log_collector.cc
+++ b/chrome/browser/chromeos/policy/extension_install_event_log_collector.cc
@@ -529,7 +529,7 @@
 }
 
 void ExtensionInstallEventLogCollector::SuspendDone(
-    const base::TimeDelta& sleep_duration) {
+    base::TimeDelta sleep_duration) {
   delegate_->AddForAllExtensions(
       CreateSessionChangeEvent(em::ExtensionInstallReportLogEvent::RESUME));
 }
diff --git a/chrome/browser/chromeos/policy/extension_install_event_log_collector.h b/chrome/browser/chromeos/policy/extension_install_event_log_collector.h
index b278ee05..f1524d8 100644
--- a/chrome/browser/chromeos/policy/extension_install_event_log_collector.h
+++ b/chrome/browser/chromeos/policy/extension_install_event_log_collector.h
@@ -74,7 +74,7 @@
 
   // chromeos::PowerManagerClient::Observer:
   void SuspendImminent(power_manager::SuspendImminent::Reason reason) override;
-  void SuspendDone(const base::TimeDelta& sleep_duration) override;
+  void SuspendDone(base::TimeDelta sleep_duration) override;
 
   // ExtensionRegistryObserver overrides
   void OnExtensionLoaded(content::BrowserContext* browser_context,
diff --git a/chrome/browser/chromeos/policy/install_event_log_collector_base.h b/chrome/browser/chromeos/policy/install_event_log_collector_base.h
index 1acfb514..35f0759 100644
--- a/chrome/browser/chromeos/policy/install_event_log_collector_base.h
+++ b/chrome/browser/chromeos/policy/install_event_log_collector_base.h
@@ -20,7 +20,7 @@
     : public chromeos::PowerManagerClient::Observer,
       public network::NetworkConnectionTracker::NetworkConnectionObserver {
  public:
-  InstallEventLogCollectorBase(Profile* profile);
+  explicit InstallEventLogCollectorBase(Profile* profile);
   ~InstallEventLogCollectorBase() override;
 
   // Event handlers for the login and logout events.
@@ -47,7 +47,7 @@
   // chromeos::PowerManagerClient::Observer:
   void SuspendImminent(power_manager::SuspendImminent::Reason reason) override =
       0;
-  void SuspendDone(const base::TimeDelta& sleep_duration) override = 0;
+  void SuspendDone(base::TimeDelta sleep_duration) override = 0;
 
   // network::NetworkConnectionTracker::NetworkConnectionObserver:
   void OnConnectionChanged(network::mojom::ConnectionType type) override;
diff --git a/chrome/browser/chromeos/policy/login_profile_policy_provider.cc b/chrome/browser/chromeos/policy/login_profile_policy_provider.cc
index 172cd81..bc3dd29 100644
--- a/chrome/browser/chromeos/policy/login_profile_policy_provider.cc
+++ b/chrome/browser/chromeos/policy/login_profile_policy_provider.cc
@@ -33,7 +33,7 @@
 
 const char kActionSuspend[] = "Suspend";
 const char kActionLogout[] = "Logout";
-const char kActionShutdown[]  = "Shutdown";
+const char kActionShutdown[] = "Shutdown";
 const char kActionDoNothing[] = "DoNothing";
 
 // All policies in this list should have a pref mapping test case in
@@ -67,6 +67,7 @@
     {key::kDeviceLoginScreenPrivacyScreenEnabled, key::kPrivacyScreenEnabled},
     {key::kDeviceLoginScreenWebUsbAllowDevicesForUrls,
      key::kWebUsbAllowDevicesForUrls},
+    {key::kDeviceLoginScreenExtensions, key::kExtensionInstallForcelist},
 };
 
 const DevicePolicyToUserPolicyMapEntry kRecommendedDevicePoliciesMap[] = {
@@ -153,8 +154,7 @@
     : device_policy_service_(device_policy_service),
       waiting_for_device_policy_refresh_(false) {}
 
-LoginProfilePolicyProvider::~LoginProfilePolicyProvider() {
-}
+LoginProfilePolicyProvider::~LoginProfilePolicyProvider() {}
 
 void LoginProfilePolicyProvider::Init(SchemaRegistry* registry) {
   ConfigurationPolicyProvider::Init(registry);
@@ -233,8 +233,8 @@
     if (policy_value->GetString(kLidCloseAction, &lid_close_action)) {
       std::unique_ptr<base::Value> action = GetAction(lid_close_action);
       if (action) {
-        ApplyValueAsMandatoryPolicy(
-            action.get(), key::kLidCloseAction, &user_policy_map);
+        ApplyValueAsMandatoryPolicy(action.get(), key::kLidCloseAction,
+                                    &user_policy_map);
       }
       policy_value->Remove(kLidCloseAction, NULL);
     }
diff --git a/chrome/browser/chromeos/policy/signin_profile_extensions_policy_browsertest.cc b/chrome/browser/chromeos/policy/signin_profile_extensions_policy_browsertest.cc
index 592e49b5..50a0fb4 100644
--- a/chrome/browser/chromeos/policy/signin_profile_extensions_policy_browsertest.cc
+++ b/chrome/browser/chromeos/policy/signin_profile_extensions_policy_browsertest.cc
@@ -16,7 +16,6 @@
 #include "base/threading/thread_restrictions.h"
 #include "base/version.h"
 #include "chrome/browser/chromeos/policy/signin_profile_extensions_policy_test_base.h"
-#include "chrome/browser/chromeos/profiles/profile_helper.h"
 #include "chrome/browser/extensions/crx_installer.h"
 #include "chrome/browser/extensions/extension_service.h"
 #include "chrome/browser/policy/extension_force_install_mixin.h"
@@ -283,15 +282,12 @@
 // Tests that a background page is created for the installed sign-in profile
 // app.
 IN_PROC_BROWSER_TEST_F(SigninProfileExtensionsPolicyTest, BackgroundPage) {
-  EXPECT_FALSE(
-      chromeos::ProfileHelper::SigninProfileHasLoginScreenExtensions());
   EXPECT_TRUE(extension_force_install_mixin_.ForceInstallFromCrx(
       base::PathService::CheckedGet(chrome::DIR_TEST_DATA)
           .AppendASCII(kWhitelistedAppCrxPath),
       ExtensionForceInstallMixin::WaitMode::kBackgroundPageReady));
   EXPECT_TRUE(extension_force_install_mixin_.IsExtensionBackgroundPageReady(
       kWhitelistedAppId));
-  EXPECT_TRUE(chromeos::ProfileHelper::SigninProfileHasLoginScreenExtensions());
 }
 
 // Tests installation of multiple sign-in profile apps/extensions.
diff --git a/chrome/browser/chromeos/policy/status_collector/affiliated_session_service.cc b/chrome/browser/chromeos/policy/status_collector/affiliated_session_service.cc
index 5aad921..59dc8fc 100644
--- a/chrome/browser/chromeos/policy/status_collector/affiliated_session_service.cc
+++ b/chrome/browser/chromeos/policy/status_collector/affiliated_session_service.cc
@@ -92,8 +92,7 @@
   profile_observer_.Remove(profile);
 }
 
-void AffiliatedSessionService::SuspendDone(
-    const base::TimeDelta& sleep_duration) {
+void AffiliatedSessionService::SuspendDone(base::TimeDelta sleep_duration) {
   if (sleep_duration < kMinimumSuspendDuration) {
     return;
   }
diff --git a/chrome/browser/chromeos/policy/status_collector/affiliated_session_service.h b/chrome/browser/chromeos/policy/status_collector/affiliated_session_service.h
index 42f6af8..63f6066 100644
--- a/chrome/browser/chromeos/policy/status_collector/affiliated_session_service.h
+++ b/chrome/browser/chromeos/policy/status_collector/affiliated_session_service.h
@@ -61,7 +61,7 @@
   void OnProfileWillBeDestroyed(Profile* profile) override;
 
   // chromeos::PowerManagerClient::Observer
-  void SuspendDone(const base::TimeDelta& sleep_duration) override;
+  void SuspendDone(base::TimeDelta sleep_duration) override;
 
  private:
   bool is_session_locked_;
diff --git a/chrome/browser/chromeos/power/auto_screen_brightness/adapter.cc b/chrome/browser/chromeos/power/auto_screen_brightness/adapter.cc
index 7a5a7ad1..706c26f 100644
--- a/chrome/browser/chromeos/power/auto_screen_brightness/adapter.cc
+++ b/chrome/browser/chromeos/power/auto_screen_brightness/adapter.cc
@@ -286,7 +286,7 @@
   UpdateStatus();
 }
 
-void Adapter::SuspendDone(const base::TimeDelta& /* sleep_duration */) {
+void Adapter::SuspendDone(base::TimeDelta /* sleep_duration */) {
   // We skip this notification if adapter hasn't been initialised (because its
   // |params_| may change), or, if adapter is disabled (because adapter won't
   // change brightness anyway).
@@ -298,7 +298,7 @@
 }
 
 void Adapter::LidEventReceived(chromeos::PowerManagerClient::LidState state,
-                               const base::TimeTicks& /* timestamp */) {
+                               base::TimeTicks /* timestamp */) {
   is_lid_closed_ = state == chromeos::PowerManagerClient::LidState::CLOSED;
   if (!*is_lid_closed_) {
     lid_reopen_time_ = tick_clock_->NowTicks();
diff --git a/chrome/browser/chromeos/power/auto_screen_brightness/adapter.h b/chrome/browser/chromeos/power/auto_screen_brightness/adapter.h
index fc8b582..6c771db 100644
--- a/chrome/browser/chromeos/power/auto_screen_brightness/adapter.h
+++ b/chrome/browser/chromeos/power/auto_screen_brightness/adapter.h
@@ -182,9 +182,9 @@
 
   // chromeos::PowerManagerClient::Observer overrides:
   void PowerManagerBecameAvailable(bool service_is_ready) override;
-  void SuspendDone(const base::TimeDelta& sleep_duration) override;
+  void SuspendDone(base::TimeDelta sleep_duration) override;
   void LidEventReceived(chromeos::PowerManagerClient::LidState state,
-                        const base::TimeTicks& timestamp) override;
+                        base::TimeTicks timestamp) override;
 
   Status GetStatusForTesting() const;
 
diff --git a/chrome/browser/chromeos/power/auto_screen_brightness/metrics_reporter.cc b/chrome/browser/chromeos/power/auto_screen_brightness/metrics_reporter.cc
index 375f8fb..55ed444e 100644
--- a/chrome/browser/chromeos/power/auto_screen_brightness/metrics_reporter.cc
+++ b/chrome/browser/chromeos/power/auto_screen_brightness/metrics_reporter.cc
@@ -109,7 +109,7 @@
 
 MetricsReporter::~MetricsReporter() = default;
 
-void MetricsReporter::SuspendDone(const base::TimeDelta& duration) {
+void MetricsReporter::SuspendDone(base::TimeDelta duration) {
   daily_event_->CheckInterval();
 }
 
diff --git a/chrome/browser/chromeos/power/auto_screen_brightness/metrics_reporter.h b/chrome/browser/chromeos/power/auto_screen_brightness/metrics_reporter.h
index dfd8e4e..979d291 100644
--- a/chrome/browser/chromeos/power/auto_screen_brightness/metrics_reporter.h
+++ b/chrome/browser/chromeos/power/auto_screen_brightness/metrics_reporter.h
@@ -71,7 +71,7 @@
   ~MetricsReporter() override;
 
   // PowerManagerClient::Observer:
-  void SuspendDone(const base::TimeDelta& duration) override;
+  void SuspendDone(base::TimeDelta duration) override;
 
   // Sets |device_class_|. Should only be called once after adapter is
   // initialized.
diff --git a/chrome/browser/chromeos/power/extension_event_observer.cc b/chrome/browser/chromeos/power/extension_event_observer.cc
index 2d779146..9c5c841 100644
--- a/chrome/browser/chromeos/power/extension_event_observer.cc
+++ b/chrome/browser/chromeos/power/extension_event_observer.cc
@@ -199,7 +199,7 @@
     OnSuspendImminent(true);
 }
 
-void ExtensionEventObserver::SuspendDone(const base::TimeDelta& duration) {
+void ExtensionEventObserver::SuspendDone(base::TimeDelta duration) {
   block_suspend_token_ = {};
   suspend_readiness_callback_.Cancel();
 }
diff --git a/chrome/browser/chromeos/power/extension_event_observer.h b/chrome/browser/chromeos/power/extension_event_observer.h
index c199afe..e51eefe 100644
--- a/chrome/browser/chromeos/power/extension_event_observer.h
+++ b/chrome/browser/chromeos/power/extension_event_observer.h
@@ -96,7 +96,7 @@
   // PowerManagerClient::Observer:
   void SuspendImminent(power_manager::SuspendImminent::Reason reason) override;
   void DarkSuspendImminent() override;
-  void SuspendDone(const base::TimeDelta& duration) override;
+  void SuspendDone(base::TimeDelta duration) override;
 
  private:
   friend class TestApi;
diff --git a/chrome/browser/chromeos/power/idle_action_warning_observer.cc b/chrome/browser/chromeos/power/idle_action_warning_observer.cc
index 735e0ca3..3de71bf 100644
--- a/chrome/browser/chromeos/power/idle_action_warning_observer.cc
+++ b/chrome/browser/chromeos/power/idle_action_warning_observer.cc
@@ -56,7 +56,7 @@
 }
 
 void IdleActionWarningObserver::IdleActionImminent(
-    const base::TimeDelta& time_until_idle_action) {
+    base::TimeDelta time_until_idle_action) {
   // Only display warning if idle action is to shut down or logout.
   PowerPolicyController::Action idle_action = GetIdleAction(on_battery_power_);
   if (idle_action != PowerPolicyController::ACTION_STOP_SESSION &&
diff --git a/chrome/browser/chromeos/power/idle_action_warning_observer.h b/chrome/browser/chromeos/power/idle_action_warning_observer.h
index ac6d200..63f1e72 100644
--- a/chrome/browser/chromeos/power/idle_action_warning_observer.h
+++ b/chrome/browser/chromeos/power/idle_action_warning_observer.h
@@ -23,8 +23,7 @@
   ~IdleActionWarningObserver() override;
 
   // PowerManagerClient::Observer:
-  void IdleActionImminent(
-      const base::TimeDelta& time_until_idle_action) override;
+  void IdleActionImminent(base::TimeDelta time_until_idle_action) override;
   void IdleActionDeferred() override;
   void PowerChanged(const power_manager::PowerSupplyProperties& proto) override;
 
diff --git a/chrome/browser/chromeos/power/ml/adaptive_screen_brightness_manager.cc b/chrome/browser/chromeos/power/ml/adaptive_screen_brightness_manager.cc
index 1b0e8a6..6a7c149 100644
--- a/chrome/browser/chromeos/power/ml/adaptive_screen_brightness_manager.cc
+++ b/chrome/browser/chromeos/power/ml/adaptive_screen_brightness_manager.cc
@@ -271,13 +271,13 @@
 
 void AdaptiveScreenBrightnessManager::LidEventReceived(
     const chromeos::PowerManagerClient::LidState state,
-    const base::TimeTicks& /* timestamp */) {
+    base::TimeTicks /* timestamp */) {
   lid_state_ = state;
 }
 
 void AdaptiveScreenBrightnessManager::TabletModeEventReceived(
     const chromeos::PowerManagerClient::TabletMode mode,
-    const base::TimeTicks& /* timestamp */) {
+    base::TimeTicks /* timestamp */) {
   tablet_mode_ = mode;
 }
 
diff --git a/chrome/browser/chromeos/power/ml/adaptive_screen_brightness_manager.h b/chrome/browser/chromeos/power/ml/adaptive_screen_brightness_manager.h
index 1b9b804..94a7532 100644
--- a/chrome/browser/chromeos/power/ml/adaptive_screen_brightness_manager.h
+++ b/chrome/browser/chromeos/power/ml/adaptive_screen_brightness_manager.h
@@ -74,9 +74,9 @@
       const power_manager::BacklightBrightnessChange& change) override;
   void PowerChanged(const power_manager::PowerSupplyProperties& proto) override;
   void LidEventReceived(chromeos::PowerManagerClient::LidState state,
-                        const base::TimeTicks& timestamp) override;
+                        base::TimeTicks timestamp) override;
   void TabletModeEventReceived(chromeos::PowerManagerClient::TabletMode mode,
-                               const base::TimeTicks& timestamp) override;
+                               base::TimeTicks timestamp) override;
 
   // viz::mojom::VideoDetectorObserver overrides:
   void OnVideoActivityStarted() override;
diff --git a/chrome/browser/chromeos/power/ml/idle_event_notifier.cc b/chrome/browser/chromeos/power/ml/idle_event_notifier.cc
index c68f78b..59d2075c 100644
--- a/chrome/browser/chromeos/power/ml/idle_event_notifier.cc
+++ b/chrome/browser/chromeos/power/ml/idle_event_notifier.cc
@@ -84,7 +84,7 @@
 
 void IdleEventNotifier::LidEventReceived(
     chromeos::PowerManagerClient::LidState state,
-    const base::TimeTicks& /* timestamp */) {
+    base::TimeTicks /* timestamp */) {
   // Ignore lid-close event, as we will observe suspend signal.
   if (state == chromeos::PowerManagerClient::LidState::OPEN) {
     UpdateActivityData(ActivityType::USER_OTHER);
@@ -99,8 +99,7 @@
   }
 }
 
-
-void IdleEventNotifier::SuspendDone(const base::TimeDelta& sleep_duration) {
+void IdleEventNotifier::SuspendDone(base::TimeDelta sleep_duration) {
   // SuspendDone is triggered by user opening the lid (or other user
   // activities).
   // A suspend and subsequent SuspendDone signal could occur with or without a
diff --git a/chrome/browser/chromeos/power/ml/idle_event_notifier.h b/chrome/browser/chromeos/power/ml/idle_event_notifier.h
index b2ea0f5..7df368b 100644
--- a/chrome/browser/chromeos/power/ml/idle_event_notifier.h
+++ b/chrome/browser/chromeos/power/ml/idle_event_notifier.h
@@ -99,9 +99,9 @@
 
   // chromeos::PowerManagerClient::Observer overrides:
   void LidEventReceived(chromeos::PowerManagerClient::LidState state,
-                        const base::TimeTicks& timestamp) override;
+                        base::TimeTicks timestamp) override;
   void PowerChanged(const power_manager::PowerSupplyProperties& proto) override;
-  void SuspendDone(const base::TimeDelta& sleep_duration) override;
+  void SuspendDone(base::TimeDelta sleep_duration) override;
 
   // ui::UserActivityObserver overrides:
   void OnUserActivity(const ui::Event* event) override;
diff --git a/chrome/browser/chromeos/power/ml/user_activity_manager.cc b/chrome/browser/chromeos/power/ml/user_activity_manager.cc
index 4838cee5..406dfcb5 100644
--- a/chrome/browser/chromeos/power/ml/user_activity_manager.cc
+++ b/chrome/browser/chromeos/power/ml/user_activity_manager.cc
@@ -148,7 +148,7 @@
 
 void UserActivityManager::LidEventReceived(
     chromeos::PowerManagerClient::LidState state,
-    const base::TimeTicks& /* timestamp */) {
+    base::TimeTicks /* timestamp */) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   lid_state_ = state;
 }
@@ -174,7 +174,7 @@
 
 void UserActivityManager::TabletModeEventReceived(
     chromeos::PowerManagerClient::TabletMode mode,
-    const base::TimeTicks& /* timestamp */) {
+    base::TimeTicks /* timestamp */) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   tablet_mode_ = mode;
 }
diff --git a/chrome/browser/chromeos/power/ml/user_activity_manager.h b/chrome/browser/chromeos/power/ml/user_activity_manager.h
index b628bf0..8424059f4 100644
--- a/chrome/browser/chromeos/power/ml/user_activity_manager.h
+++ b/chrome/browser/chromeos/power/ml/user_activity_manager.h
@@ -92,10 +92,10 @@
 
   // chromeos::PowerManagerClient::Observer overrides:
   void LidEventReceived(chromeos::PowerManagerClient::LidState state,
-                        const base::TimeTicks& timestamp) override;
+                        base::TimeTicks timestamp) override;
   void PowerChanged(const power_manager::PowerSupplyProperties& proto) override;
   void TabletModeEventReceived(chromeos::PowerManagerClient::TabletMode mode,
-                               const base::TimeTicks& timestamp) override;
+                               base::TimeTicks timestamp) override;
   void ScreenIdleStateChanged(
       const power_manager::ScreenIdleState& proto) override;
   void SuspendImminent(power_manager::SuspendImminent::Reason reason) override;
diff --git a/chrome/browser/chromeos/power/power_data_collector.cc b/chrome/browser/chromeos/power/power_data_collector.cc
index 77b1d92..2c7b4e4d 100644
--- a/chrome/browser/chromeos/power/power_data_collector.cc
+++ b/chrome/browser/chromeos/power/power_data_collector.cc
@@ -59,7 +59,7 @@
   AddSample(&power_supply_data_, sample);
 }
 
-void PowerDataCollector::SuspendDone(const base::TimeDelta& sleep_duration) {
+void PowerDataCollector::SuspendDone(base::TimeDelta sleep_duration) {
   SystemResumedSample sample;
   sample.time = base::Time::Now();
   sample.sleep_duration = sleep_duration;
diff --git a/chrome/browser/chromeos/power/power_data_collector.h b/chrome/browser/chromeos/power/power_data_collector.h
index 47b1bf0..0de7ade 100644
--- a/chrome/browser/chromeos/power/power_data_collector.h
+++ b/chrome/browser/chromeos/power/power_data_collector.h
@@ -81,7 +81,7 @@
 
   // PowerManagerClient::Observer implementation:
   void PowerChanged(const power_manager::PowerSupplyProperties& prop) override;
-  void SuspendDone(const base::TimeDelta& sleep_duration) override;
+  void SuspendDone(base::TimeDelta sleep_duration) override;
 
   // Only those power data samples which fall within the last
   // |kSampleTimeLimitSec| are stored in memory.
diff --git a/chrome/browser/chromeos/power/power_metrics_reporter.cc b/chrome/browser/chromeos/power/power_metrics_reporter.cc
index ecaf386..0b75527 100644
--- a/chrome/browser/chromeos/power/power_metrics_reporter.cc
+++ b/chrome/browser/chromeos/power/power_metrics_reporter.cc
@@ -136,7 +136,7 @@
   }
 }
 
-void PowerMetricsReporter::SuspendDone(const base::TimeDelta& duration) {
+void PowerMetricsReporter::SuspendDone(base::TimeDelta duration) {
   daily_event_->CheckInterval();
 }
 
diff --git a/chrome/browser/chromeos/power/power_metrics_reporter.h b/chrome/browser/chromeos/power/power_metrics_reporter.h
index eb0bf39..324eedb8 100644
--- a/chrome/browser/chromeos/power/power_metrics_reporter.h
+++ b/chrome/browser/chromeos/power/power_metrics_reporter.h
@@ -43,7 +43,7 @@
   void ScreenIdleStateChanged(
       const power_manager::ScreenIdleState& state) override;
   void SuspendImminent(power_manager::SuspendImminent::Reason reason) override;
-  void SuspendDone(const base::TimeDelta& duration) override;
+  void SuspendDone(base::TimeDelta duration) override;
 
  private:
   friend class PowerMetricsReporterTest;
diff --git a/chrome/browser/chromeos/power/smart_charging/smart_charging_manager.cc b/chrome/browser/chromeos/power/smart_charging/smart_charging_manager.cc
index 3c03a70..21fd252 100644
--- a/chrome/browser/chromeos/power/smart_charging/smart_charging_manager.cc
+++ b/chrome/browser/chromeos/power/smart_charging/smart_charging_manager.cc
@@ -326,13 +326,13 @@
 
 void SmartChargingManager::LidEventReceived(
     const chromeos::PowerManagerClient::LidState state,
-    const base::TimeTicks& /* timestamp */) {
+    base::TimeTicks /* timestamp */) {
   lid_state_ = state;
 }
 
 void SmartChargingManager::TabletModeEventReceived(
     const chromeos::PowerManagerClient::TabletMode mode,
-    const base::TimeTicks& /* timestamp */) {
+    base::TimeTicks /* timestamp */) {
   tablet_mode_ = mode;
 }
 
diff --git a/chrome/browser/chromeos/power/smart_charging/smart_charging_manager.h b/chrome/browser/chromeos/power/smart_charging/smart_charging_manager.h
index d2ca06b..7dfbb52 100644
--- a/chrome/browser/chromeos/power/smart_charging/smart_charging_manager.h
+++ b/chrome/browser/chromeos/power/smart_charging/smart_charging_manager.h
@@ -74,9 +74,9 @@
   void ShutdownRequested(power_manager::RequestShutdownReason reason) override;
   void SuspendImminent(power_manager::SuspendImminent::Reason reason) override;
   void LidEventReceived(chromeos::PowerManagerClient::LidState state,
-                        const base::TimeTicks& timestamp) override;
+                        base::TimeTicks timestamp) override;
   void TabletModeEventReceived(chromeos::PowerManagerClient::TabletMode mode,
-                               const base::TimeTicks& timestamp) override;
+                               base::TimeTicks timestamp) override;
 
   // viz::mojom::VideoDetectorObserver overrides:
   void OnVideoActivityStarted() override;
diff --git a/chrome/browser/chromeos/profiles/profile_helper.cc b/chrome/browser/chromeos/profiles/profile_helper.cc
index 89f8bfbe..8684ce8 100644
--- a/chrome/browser/chromeos/profiles/profile_helper.cc
+++ b/chrome/browser/chromeos/profiles/profile_helper.cc
@@ -35,13 +35,11 @@
 #include "chromeos/constants/chromeos_switches.h"
 #include "components/account_id/account_id.h"
 #include "components/crx_file/id_util.h"
-#include "components/prefs/pref_service.h"
 #include "components/user_manager/user.h"
 #include "components/user_manager/user_manager.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/browsing_data_remover.h"
 #include "extensions/browser/extension_system.h"
-#include "extensions/browser/pref_names.h"
 
 namespace chromeos {
 
@@ -297,18 +295,6 @@
 }
 
 // static
-bool ProfileHelper::SigninProfileHasLoginScreenExtensions() {
-  DCHECK(IsSigninProfileInitialized());
-  const Profile* profile = GetSigninProfile();
-  const PrefService* prefs = profile->GetPrefs();
-  DCHECK(prefs->GetInitializationStatus() ==
-         PrefService::INITIALIZATION_STATUS_SUCCESS);
-  const base::DictionaryValue* pref_value =
-      prefs->GetDictionary(extensions::pref_names::kLoginScreenExtensions);
-  return !pref_value->DictEmpty();
-}
-
-// static
 bool ProfileHelper::IsLockScreenAppProfile(const Profile* profile) {
   return profile && IsLockScreenAppProfilePath(profile->GetPath().BaseName());
 }
diff --git a/chrome/browser/chromeos/profiles/profile_helper.h b/chrome/browser/chromeos/profiles/profile_helper.h
index 05f77d9d..aadb96c 100644
--- a/chrome/browser/chromeos/profiles/profile_helper.h
+++ b/chrome/browser/chromeos/profiles/profile_helper.h
@@ -84,11 +84,6 @@
   // Returns true if the signin profile has been initialized.
   static bool IsSigninProfileInitialized();
 
-  // Returns true if the signin profile has force-installed extensions set by
-  // policy. This DCHECKs that the profile is created, its PrefService is
-  // initialized and the associated pref exists.
-  static bool SigninProfileHasLoginScreenExtensions();
-
   // Returns the path used for the lock screen apps profile - profile used
   // for launching platform apps that can display windows on top of the lock
   // screen.
diff --git a/chrome/browser/chromeos/smb_client/smb_service.cc b/chrome/browser/chromeos/smb_client/smb_service.cc
index 984d404f..2588d14 100644
--- a/chrome/browser/chromeos/smb_client/smb_service.cc
+++ b/chrome/browser/chromeos/smb_client/smb_service.cc
@@ -1048,7 +1048,7 @@
       power_manager_suspend_token);
 }
 
-void SmbService::SuspendDone(const base::TimeDelta& sleep_duration) {
+void SmbService::SuspendDone(base::TimeDelta sleep_duration) {
   // Don't iterate directly over the share map during the remount
   // process as shares can be removed on failure in OnSmbfsMountDone.
   std::vector<std::string> mount_ids;
diff --git a/chrome/browser/chromeos/smb_client/smb_service.h b/chrome/browser/chromeos/smb_client/smb_service.h
index acac449..e4bfaa0 100644
--- a/chrome/browser/chromeos/smb_client/smb_service.h
+++ b/chrome/browser/chromeos/smb_client/smb_service.h
@@ -128,7 +128,7 @@
 
   // chromeos::PowerManagerClient::Observer overrides
   void SuspendImminent(power_manager::SuspendImminent::Reason reason) override;
-  void SuspendDone(const base::TimeDelta& sleep_duration) override;
+  void SuspendDone(base::TimeDelta sleep_duration) override;
 
  private:
   friend class SmbServiceTest;
diff --git a/chrome/browser/chromeos/system/automatic_reboot_manager.cc b/chrome/browser/chromeos/system/automatic_reboot_manager.cc
index 3552848..4c969b5 100644
--- a/chrome/browser/chromeos/system/automatic_reboot_manager.cc
+++ b/chrome/browser/chromeos/system/automatic_reboot_manager.cc
@@ -204,8 +204,7 @@
   return initialized_.TimedWait(timeout);
 }
 
-void AutomaticRebootManager::SuspendDone(
-    const base::TimeDelta& sleep_duration) {
+void AutomaticRebootManager::SuspendDone(base::TimeDelta sleep_duration) {
   MaybeReboot(true);
 }
 
diff --git a/chrome/browser/chromeos/system/automatic_reboot_manager.h b/chrome/browser/chromeos/system/automatic_reboot_manager.h
index 1264c38..1a5fa47 100644
--- a/chrome/browser/chromeos/system/automatic_reboot_manager.h
+++ b/chrome/browser/chromeos/system/automatic_reboot_manager.h
@@ -100,7 +100,7 @@
   bool WaitForInitForTesting(const base::TimeDelta& timeout);
 
   // PowerManagerClient::Observer:
-  void SuspendDone(const base::TimeDelta& sleep_duration) override;
+  void SuspendDone(base::TimeDelta sleep_duration) override;
 
   // UpdateEngineClient::Observer:
   void UpdateStatusChanged(const update_engine::StatusResult& status) override;
diff --git a/chrome/browser/chromeos/tether/tether_service.cc b/chrome/browser/chromeos/tether/tether_service.cc
index 5c323928..fad00a9 100644
--- a/chrome/browser/chromeos/tether/tether_service.cc
+++ b/chrome/browser/chromeos/tether/tether_service.cc
@@ -260,7 +260,7 @@
   UpdateTetherTechnologyState();
 }
 
-void TetherService::SuspendDone(const base::TimeDelta& sleep_duration) {
+void TetherService::SuspendDone(base::TimeDelta sleep_duration) {
   suspended_ = false;
 
   // If there was a previous TetherComponent instance in the process of an
diff --git a/chrome/browser/chromeos/tether/tether_service.h b/chrome/browser/chromeos/tether/tether_service.h
index b628a917..5b6b48f 100644
--- a/chrome/browser/chromeos/tether/tether_service.h
+++ b/chrome/browser/chromeos/tether/tether_service.h
@@ -89,7 +89,7 @@
 
   // chromeos::PowerManagerClient::Observer:
   void SuspendImminent(power_manager::SuspendImminent::Reason reason) override;
-  void SuspendDone(const base::TimeDelta& sleep_duration) override;
+  void SuspendDone(base::TimeDelta sleep_duration) override;
 
   // chromeos::tether::TetherHostFetcher::Observer
   void OnTetherHostsUpdated() override;
diff --git a/chrome/browser/extensions/chrome_extensions_browser_client.cc b/chrome/browser/extensions/chrome_extensions_browser_client.cc
index 7c6d74ff..a232b61 100644
--- a/chrome/browser/extensions/chrome_extensions_browser_client.cc
+++ b/chrome/browser/extensions/chrome_extensions_browser_client.cc
@@ -16,7 +16,6 @@
 #include "chrome/browser/app_mode/app_mode_utils.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/chrome_content_browser_client.h"
-#include "chrome/browser/chromeos/profiles/profile_helper.h"
 #include "chrome/browser/download/download_prefs.h"
 #include "chrome/browser/extensions/activity_log/activity_log.h"
 #include "chrome/browser/extensions/api/chrome_extensions_api_client.h"
@@ -70,6 +69,7 @@
 
 #if BUILDFLAG(IS_CHROMEOS_ASH)
 #include "chrome/browser/chromeos/login/demo_mode/demo_session.h"
+#include "chrome/browser/chromeos/profiles/profile_helper.h"
 #include "chrome/browser/extensions/updater/chromeos_extension_cache_delegate.h"
 #include "chrome/browser/extensions/updater/extension_cache_impl.h"
 #include "chromeos/constants/chromeos_switches.h"
@@ -367,15 +367,8 @@
 ExtensionCache* ChromeExtensionsBrowserClient::GetExtensionCache() {
   if (!extension_cache_.get()) {
 #if BUILDFLAG(IS_CHROMEOS_ASH)
-    // TODO(crbug.com/1012892): Replace this with just BEST_EFFORT, since the
-    // sign-in profile extensions use a different caching mechanism now.
-    base::TaskPriority task_priority =
-        chromeos::ProfileHelper::IsSigninProfileInitialized() &&
-                chromeos::ProfileHelper::SigninProfileHasLoginScreenExtensions()
-            ? base::TaskPriority::USER_VISIBLE
-            : base::TaskPriority::BEST_EFFORT;
     extension_cache_.reset(new ExtensionCacheImpl(
-        std::make_unique<ChromeOSExtensionCacheDelegate>(), task_priority));
+        std::make_unique<ChromeOSExtensionCacheDelegate>()));
 #else
     extension_cache_.reset(new NullExtensionCache());
 #endif
diff --git a/chrome/browser/extensions/extension_management.cc b/chrome/browser/extensions/extension_management.cc
index fe75a42..c3656f0 100644
--- a/chrome/browser/extensions/extension_management.cc
+++ b/chrome/browser/extensions/extension_management.cc
@@ -68,8 +68,6 @@
                              pref_change_callback);
   pref_change_registrar_.Add(pref_names::kInstallForceList,
                              pref_change_callback);
-  pref_change_registrar_.Add(pref_names::kLoginScreenExtensions,
-                             pref_change_callback);
   pref_change_registrar_.Add(pref_names::kAllowedInstallSites,
                              pref_change_callback);
   pref_change_registrar_.Add(pref_names::kAllowedTypes, pref_change_callback);
@@ -371,12 +369,6 @@
   const base::DictionaryValue* forced_list_pref =
       static_cast<const base::DictionaryValue*>(LoadPreference(
           pref_names::kInstallForceList, true, base::Value::Type::DICTIONARY));
-  const base::DictionaryValue* login_screen_extensions_pref = nullptr;
-  if (is_signin_profile_) {
-    login_screen_extensions_pref = static_cast<const base::DictionaryValue*>(
-        LoadPreference(pref_names::kLoginScreenExtensions, true,
-                       base::Value::Type::DICTIONARY));
-  }
   const base::ListValue* install_sources_pref =
       static_cast<const base::ListValue*>(LoadPreference(
           pref_names::kAllowedInstallSites, true, base::Value::Type::LIST));
@@ -441,7 +433,6 @@
   }
 
   UpdateForcedExtensions(forced_list_pref);
-  UpdateForcedExtensions(login_screen_extensions_pref);
 
   if (install_sources_pref) {
     global_settings_->has_restricted_install_sources = true;
diff --git a/chrome/browser/extensions/policy_handlers.cc b/chrome/browser/extensions/policy_handlers.cc
index 45a8770..969497a 100644
--- a/chrome/browser/extensions/policy_handlers.cc
+++ b/chrome/browser/extensions/policy_handlers.cc
@@ -74,15 +74,13 @@
   prefs->SetValue(pref_path_, std::move(filtered_list));
 }
 
-// ExtensionInstallListPolicyHandler implementation ----------------------------
+// ExtensionInstallForceListPolicyHandler implementation -----------------------
 
-ExtensionInstallListPolicyHandler::ExtensionInstallListPolicyHandler(
-    const char* policy_name,
-    const char* pref_name)
-    : policy::TypeCheckingPolicyHandler(policy_name, base::Value::Type::LIST),
-      pref_name_(pref_name) {}
+ExtensionInstallForceListPolicyHandler::ExtensionInstallForceListPolicyHandler()
+    : policy::TypeCheckingPolicyHandler(policy::key::kExtensionInstallForcelist,
+                                        base::Value::Type::LIST) {}
 
-bool ExtensionInstallListPolicyHandler::CheckPolicySettings(
+bool ExtensionInstallForceListPolicyHandler::CheckPolicySettings(
     const policy::PolicyMap& policies,
     policy::PolicyErrorMap* errors) {
   const base::Value* value;
@@ -90,18 +88,18 @@
          ParseList(value, nullptr, errors);
 }
 
-void ExtensionInstallListPolicyHandler::ApplyPolicySettings(
+void ExtensionInstallForceListPolicyHandler::ApplyPolicySettings(
     const policy::PolicyMap& policies,
     PrefValueMap* prefs) {
   const base::Value* value = nullptr;
   base::DictionaryValue dict;
   if (CheckAndGetValue(policies, nullptr, &value) && value &&
       ParseList(value, &dict, nullptr)) {
-    prefs->SetValue(pref_name_, std::move(dict));
+    prefs->SetValue(pref_names::kInstallForceList, std::move(dict));
   }
 }
 
-bool ExtensionInstallListPolicyHandler::ParseList(
+bool ExtensionInstallForceListPolicyHandler::ParseList(
     const base::Value* policy_value,
     base::DictionaryValue* extension_dict,
     policy::PolicyErrorMap* errors) {
@@ -161,20 +159,6 @@
   return true;
 }
 
-// ExtensionInstallForcelistPolicyHandler implementation -----------------------
-
-ExtensionInstallForcelistPolicyHandler::ExtensionInstallForcelistPolicyHandler()
-    : ExtensionInstallListPolicyHandler(policy::key::kExtensionInstallForcelist,
-                                        pref_names::kInstallForceList) {}
-
-// ExtensionInstallLoginScreenExtensionsPolicyHandler implementation -----------
-
-ExtensionInstallLoginScreenExtensionsPolicyHandler::
-    ExtensionInstallLoginScreenExtensionsPolicyHandler()
-    : ExtensionInstallListPolicyHandler(
-          policy::key::kDeviceLoginScreenExtensions,
-          pref_names::kLoginScreenExtensions) {}
-
 // ExtensionURLPatternListPolicyHandler implementation -------------------------
 
 ExtensionURLPatternListPolicyHandler::ExtensionURLPatternListPolicyHandler(
diff --git a/chrome/browser/extensions/policy_handlers.h b/chrome/browser/extensions/policy_handlers.h
index 354311f5..9c86e81 100644
--- a/chrome/browser/extensions/policy_handlers.h
+++ b/chrome/browser/extensions/policy_handlers.h
@@ -43,53 +43,28 @@
   DISALLOW_COPY_AND_ASSIGN(ExtensionListPolicyHandler);
 };
 
-// Base class for parsing the list of extensions to force install.
-class ExtensionInstallListPolicyHandler
+// Class for parsing the list of extensions to force install.
+class ExtensionInstallForceListPolicyHandler
     : public policy::TypeCheckingPolicyHandler {
  public:
+  ExtensionInstallForceListPolicyHandler();
+  ExtensionInstallForceListPolicyHandler(
+      const ExtensionInstallForceListPolicyHandler&) = delete;
+  ExtensionInstallForceListPolicyHandler& operator=(
+      const ExtensionInstallForceListPolicyHandler&) = delete;
+  ~ExtensionInstallForceListPolicyHandler() override = default;
+
   // ConfigurationPolicyHandler methods:
   bool CheckPolicySettings(const policy::PolicyMap& policies,
                            policy::PolicyErrorMap* errors) override;
   void ApplyPolicySettings(const policy::PolicyMap& policies,
                            PrefValueMap* prefs) override;
 
- protected:
-  ExtensionInstallListPolicyHandler(const char* policy_name,
-                                    const char* pref_name);
-
-  ~ExtensionInstallListPolicyHandler() override = default;
-
  private:
   // Parses the data in |policy_value| and writes them to |extension_dict|.
   bool ParseList(const base::Value* policy_value,
                  base::DictionaryValue* extension_dict,
                  policy::PolicyErrorMap* errors);
-
-  const char* const pref_name_ = nullptr;
-
-  DISALLOW_COPY_AND_ASSIGN(ExtensionInstallListPolicyHandler);
-};
-
-// Parses the extension force install list for user sessions.
-class ExtensionInstallForcelistPolicyHandler
-    : public ExtensionInstallListPolicyHandler {
- public:
-  ExtensionInstallForcelistPolicyHandler();
-  ~ExtensionInstallForcelistPolicyHandler() override = default;
-
- private:
-  DISALLOW_COPY_AND_ASSIGN(ExtensionInstallForcelistPolicyHandler);
-};
-
-// Parses the extension force install list for the login profile.
-class ExtensionInstallLoginScreenExtensionsPolicyHandler
-    : public ExtensionInstallListPolicyHandler {
- public:
-  ExtensionInstallLoginScreenExtensionsPolicyHandler();
-  ~ExtensionInstallLoginScreenExtensionsPolicyHandler() override = default;
-
- private:
-  DISALLOW_COPY_AND_ASSIGN(ExtensionInstallLoginScreenExtensionsPolicyHandler);
 };
 
 // Implements additional checks for policies that are lists of extension
diff --git a/chrome/browser/extensions/policy_handlers_unittest.cc b/chrome/browser/extensions/policy_handlers_unittest.cc
index 7c426b8c..039e684 100644
--- a/chrome/browser/extensions/policy_handlers_unittest.cc
+++ b/chrome/browser/extensions/policy_handlers_unittest.cc
@@ -172,11 +172,11 @@
   EXPECT_EQ(expected, *value);
 }
 
-TEST(ExtensionInstallForcelistPolicyHandlerTest, CheckPolicySettings) {
+TEST(ExtensionInstallForceListPolicyHandlerTest, CheckPolicySettings) {
   base::ListValue list;
   policy::PolicyMap policy_map;
   policy::PolicyErrorMap errors;
-  ExtensionInstallForcelistPolicyHandler handler;
+  ExtensionInstallForceListPolicyHandler handler;
 
   // Start with an empty policy.
   policy_map.Set(policy::key::kExtensionInstallForcelist,
@@ -224,13 +224,13 @@
   EXPECT_EQ(2U, errors.size());
 }
 
-TEST(ExtensionInstallForcelistPolicyHandlerTest, ApplyPolicySettings) {
+TEST(ExtensionInstallForceListPolicyHandlerTest, ApplyPolicySettings) {
   base::ListValue policy;
   base::DictionaryValue expected;
   policy::PolicyMap policy_map;
   PrefValueMap prefs;
   base::Value* value = NULL;
-  ExtensionInstallForcelistPolicyHandler handler;
+  ExtensionInstallForceListPolicyHandler handler;
 
   // Start with the policy being missing. This shouldn't affect the pref.
   handler.ApplyPolicySettings(policy_map, &prefs);
diff --git a/chrome/browser/extensions/updater/extension_cache_impl.cc b/chrome/browser/extensions/updater/extension_cache_impl.cc
index f30990b..bf701869 100644
--- a/chrome/browser/extensions/updater/extension_cache_impl.cc
+++ b/chrome/browser/extensions/updater/extension_cache_impl.cc
@@ -13,6 +13,7 @@
 #include "base/sequenced_task_runner.h"
 #include "base/stl_util.h"
 #include "base/task/post_task.h"
+#include "base/task/task_traits.h"
 #include "base/task/thread_pool.h"
 #include "chrome/browser/chrome_notification_types.h"
 #include "chrome/browser/extensions/crx_installer.h"
@@ -28,14 +29,13 @@
 namespace extensions {
 
 ExtensionCacheImpl::ExtensionCacheImpl(
-    std::unique_ptr<ChromeOSExtensionCacheDelegate> delegate,
-    base::TaskPriority task_priority)
+    std::unique_ptr<ChromeOSExtensionCacheDelegate> delegate)
     : cache_(new LocalExtensionCache(
           delegate->GetCacheDir(),
           delegate->GetMaximumCacheSize(),
           delegate->GetMaximumCacheAge(),
           base::ThreadPool::CreateSequencedTaskRunner(
-              {base::MayBlock(), task_priority,
+              {base::MayBlock(), base::TaskPriority::BEST_EFFORT,
                base::TaskShutdownBehavior::SKIP_ON_SHUTDOWN}))) {
   notification_registrar_.Add(
       this, extensions::NOTIFICATION_EXTENSION_INSTALL_ERROR,
diff --git a/chrome/browser/extensions/updater/extension_cache_impl.h b/chrome/browser/extensions/updater/extension_cache_impl.h
index f52202c..67622cb5 100644
--- a/chrome/browser/extensions/updater/extension_cache_impl.h
+++ b/chrome/browser/extensions/updater/extension_cache_impl.h
@@ -14,7 +14,6 @@
 #include "base/files/file_path.h"
 #include "base/macros.h"
 #include "base/memory/weak_ptr.h"
-#include "base/task/task_traits.h"
 #include "content/public/browser/notification_observer.h"
 #include "content/public/browser/notification_registrar.h"
 #include "extensions/browser/updater/extension_cache.h"
@@ -34,8 +33,7 @@
                            public content::NotificationObserver {
  public:
   explicit ExtensionCacheImpl(
-      std::unique_ptr<ChromeOSExtensionCacheDelegate> delegate,
-      base::TaskPriority task_priority = base::TaskPriority::BEST_EFFORT);
+      std::unique_ptr<ChromeOSExtensionCacheDelegate> delegate);
   ~ExtensionCacheImpl() override;
 
   // Implementation of ExtensionCache.
diff --git a/chrome/browser/flag-metadata.json b/chrome/browser/flag-metadata.json
index 058dc615..cb1de86 100644
--- a/chrome/browser/flag-metadata.json
+++ b/chrome/browser/flag-metadata.json
@@ -910,7 +910,7 @@
   {
     "name": "disable-camera-frame-rotation-at-source",
     "owners": [ "chromeos-camera-eng@google.com" ],
-    "expiry_milestone": 88
+    "expiry_milestone": 91
   },
   {
     "name": "disable-cancel-all-touches",
diff --git a/chrome/browser/metrics/perf/profile_provider_chromeos.cc b/chrome/browser/metrics/perf/profile_provider_chromeos.cc
index 4ffd49a..c2fa2e2 100644
--- a/chrome/browser/metrics/perf/profile_provider_chromeos.cc
+++ b/chrome/browser/metrics/perf/profile_provider_chromeos.cc
@@ -137,7 +137,7 @@
   }
 }
 
-void ProfileProvider::SuspendDone(const base::TimeDelta& sleep_duration) {
+void ProfileProvider::SuspendDone(base::TimeDelta sleep_duration) {
   // A zero value for the suspend duration indicates that the suspend was
   // canceled. Do not collect anything if that's the case.
   if (sleep_duration.is_zero())
diff --git a/chrome/browser/metrics/perf/profile_provider_chromeos.h b/chrome/browser/metrics/perf/profile_provider_chromeos.h
index 73c9c1f1..d87a377 100644
--- a/chrome/browser/metrics/perf/profile_provider_chromeos.h
+++ b/chrome/browser/metrics/perf/profile_provider_chromeos.h
@@ -49,7 +49,7 @@
   // Called when a suspend finishes. This is either a successful suspend
   // followed by a resume, or a suspend that was canceled. Inherited from
   // PowerManagerClient::Observer.
-  void SuspendDone(const base::TimeDelta& sleep_duration) override;
+  void SuspendDone(base::TimeDelta sleep_duration) override;
 
   // Called when a session restore has finished.
   void OnSessionRestoreDone(int num_tabs_restored);
diff --git a/chrome/browser/nearby_sharing/power_client_chromeos.cc b/chrome/browser/nearby_sharing/power_client_chromeos.cc
index 002e9e4..e5ca06e 100644
--- a/chrome/browser/nearby_sharing/power_client_chromeos.cc
+++ b/chrome/browser/nearby_sharing/power_client_chromeos.cc
@@ -19,6 +19,6 @@
   SetSuspended(true);
 }
 
-void PowerClientChromeos::SuspendDone(const base::TimeDelta& sleep_duration) {
+void PowerClientChromeos::SuspendDone(base::TimeDelta sleep_duration) {
   SetSuspended(false);
 }
diff --git a/chrome/browser/nearby_sharing/power_client_chromeos.h b/chrome/browser/nearby_sharing/power_client_chromeos.h
index 92ea2be..d9095e33 100644
--- a/chrome/browser/nearby_sharing/power_client_chromeos.h
+++ b/chrome/browser/nearby_sharing/power_client_chromeos.h
@@ -18,7 +18,7 @@
  private:
   // chromeos::PowerManagerClient::Observer:
   void SuspendImminent(power_manager::SuspendImminent::Reason reason) override;
-  void SuspendDone(const base::TimeDelta& sleep_duration) override;
+  void SuspendDone(base::TimeDelta sleep_duration) override;
 };
 
 #endif  // CHROME_BROWSER_NEARBY_SHARING_POWER_CLIENT_CHROMEOS_H_
diff --git a/chrome/browser/password_manager/field_info_manager_factory.h b/chrome/browser/password_manager/field_info_manager_factory.h
index 7203a51..cf64ff1 100644
--- a/chrome/browser/password_manager/field_info_manager_factory.h
+++ b/chrome/browser/password_manager/field_info_manager_factory.h
@@ -21,13 +21,14 @@
   static password_manager::FieldInfoManager* GetForBrowserContext(
       content::BrowserContext* context);
 
+  FieldInfoManagerFactory(const FieldInfoManagerFactory&) = delete;
+  FieldInfoManagerFactory& operator=(const FieldInfoManagerFactory&) = delete;
+
  private:
   friend struct base::DefaultSingletonTraits<FieldInfoManagerFactory>;
 
   FieldInfoManagerFactory();
   ~FieldInfoManagerFactory() override;
-  FieldInfoManagerFactory(const FieldInfoManagerFactory&) = delete;
-  FieldInfoManagerFactory& operator=(const FieldInfoManagerFactory&) = delete;
 
   // BrowserContextKeyedServiceFactory overrides:
   KeyedService* BuildServiceInstanceFor(
diff --git a/chrome/browser/policy/configuration_policy_handler_list_factory.cc b/chrome/browser/policy/configuration_policy_handler_list_factory.cc
index 1112fe5..a094be2 100644
--- a/chrome/browser/policy/configuration_policy_handler_list_factory.cc
+++ b/chrome/browser/policy/configuration_policy_handler_list_factory.cc
@@ -1852,10 +1852,7 @@
       key::kExtensionInstallBlocklist, extensions::pref_names::kInstallDenyList,
       true));
   handlers->AddHandler(
-      std::make_unique<extensions::ExtensionInstallForcelistPolicyHandler>());
-  handlers->AddHandler(
-      std::make_unique<
-          extensions::ExtensionInstallLoginScreenExtensionsPolicyHandler>());
+      std::make_unique<extensions::ExtensionInstallForceListPolicyHandler>());
   handlers->AddHandler(
       std::make_unique<extensions::ExtensionURLPatternListPolicyHandler>(
           key::kExtensionInstallSources,
diff --git a/chrome/browser/policy/extension_force_install_mixin.cc b/chrome/browser/policy/extension_force_install_mixin.cc
index ff4c5f4..eaf76fd6 100644
--- a/chrome/browser/policy/extension_force_install_mixin.cc
+++ b/chrome/browser/policy/extension_force_install_mixin.cc
@@ -57,7 +57,6 @@
 #if BUILDFLAG(IS_CHROMEOS_ASH)
 #include "chrome/browser/chromeos/login/test/device_state_mixin.h"
 #include "chrome/browser/chromeos/policy/device_policy_cros_browser_test.h"
-#include "chrome/browser/chromeos/profiles/profile_helper.h"
 #include "components/policy/proto/chrome_device_policy.pb.h"
 #endif
 
@@ -103,19 +102,11 @@
   base::WeakPtrFactory<ForceInstallPrefObserver> weak_ptr_factory_{this};
 };
 
-std::string GetForceInstallPrefName(Profile* profile) {
-#if BUILDFLAG(IS_CHROMEOS_ASH)
-  if (chromeos::ProfileHelper::IsSigninProfile(profile))
-    return extensions::pref_names::kLoginScreenExtensions;
-#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
-  return extensions::pref_names::kInstallForceList;
-}
-
 ForceInstallPrefObserver::ForceInstallPrefObserver(
     Profile* profile,
     const extensions::ExtensionId& extension_id)
     : pref_service_(profile->GetPrefs()),
-      pref_name_(GetForceInstallPrefName(profile)),
+      pref_name_(extensions::pref_names::kInstallForceList),
       extension_id_(extension_id) {
   pref_change_registrar_.Init(pref_service_);
   pref_change_registrar_.Add(
diff --git a/chrome/browser/printing/print_view_manager_base.cc b/chrome/browser/printing/print_view_manager_base.cc
index 2414c40..94774af 100644
--- a/chrome/browser/printing/print_view_manager_base.cc
+++ b/chrome/browser/printing/print_view_manager_base.cc
@@ -460,49 +460,59 @@
     const gfx::Size& page_size,
     const gfx::Rect& content_area,
     const gfx::Point& physical_offsets,
-    std::unique_ptr<DelayedFrameDispatchHelper> helper,
+    DidPrintDocumentCallback callback,
     mojom::PrintCompositor::Status status,
     base::ReadOnlySharedMemoryRegion region) {
   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
   if (status != mojom::PrintCompositor::Status::kSuccess) {
     DLOG(ERROR) << "Compositing pdf failed with error " << status;
+    std::move(callback).Run(false);
     return;
   }
 
-  if (!print_job_->document())
+  if (!print_job_->document()) {
+    std::move(callback).Run(false);
     return;
+  }
 
   scoped_refptr<base::RefCountedSharedMemoryMapping> data =
       base::RefCountedSharedMemoryMapping::CreateFromWholeRegion(region);
-  if (!data)
+  if (!data) {
+    std::move(callback).Run(false);
     return;
+  }
 
   PrintDocument(data, page_size, content_area, physical_offsets);
-  helper->SendCompleted();
+  std::move(callback).Run(true);
 }
 
-void PrintViewManagerBase::OnDidPrintDocument(
-    content::RenderFrameHost* render_frame_host,
-    const mojom::DidPrintDocumentParams& params,
-    std::unique_ptr<DelayedFrameDispatchHelper> helper) {
-  if (!PrintJobHasDocument(params.document_cookie))
+void PrintViewManagerBase::DidPrintDocument(
+    mojom::DidPrintDocumentParamsPtr params,
+    DidPrintDocumentCallback callback) {
+  if (!PrintJobHasDocument(params->document_cookie)) {
+    std::move(callback).Run(false);
     return;
+  }
 
-  const mojom::DidPrintContentParams& content = *params.content;
+  const mojom::DidPrintContentParams& content = *params->content;
   if (!content.metafile_data_region.IsValid()) {
     NOTREACHED() << "invalid memory handle";
     web_contents()->Stop();
+    std::move(callback).Run(false);
     return;
   }
 
   auto* client = PrintCompositeClient::FromWebContents(web_contents());
+  content::RenderFrameHost* render_frame_host =
+      print_manager_host_receivers_.GetCurrentTargetFrame();
+
   if (IsOopifEnabled() && print_job_->document()->settings().is_modifiable()) {
     client->DoCompositeDocumentToPdf(
-        params.document_cookie, render_frame_host, content,
+        params->document_cookie, render_frame_host, content,
         base::BindOnce(&PrintViewManagerBase::OnComposePdfDone,
-                       weak_ptr_factory_.GetWeakPtr(), params.page_size,
-                       params.content_area, params.physical_offsets,
-                       std::move(helper)));
+                       weak_ptr_factory_.GetWeakPtr(), params->page_size,
+                       params->content_area, params->physical_offsets,
+                       std::move(callback)));
     return;
   }
   auto data = base::RefCountedSharedMemoryMapping::CreateFromWholeRegion(
@@ -510,12 +520,13 @@
   if (!data) {
     NOTREACHED() << "couldn't map";
     web_contents()->Stop();
+    std::move(callback).Run(false);
     return;
   }
 
-  PrintDocument(data, params.page_size, params.content_area,
-                params.physical_offsets);
-  helper->SendCompleted();
+  PrintDocument(data, params->page_size, params->content_area,
+                params->physical_offsets);
+  std::move(callback).Run(true);
 }
 
 void PrintViewManagerBase::GetDefaultPrintSettings(
diff --git a/chrome/browser/printing/print_view_manager_base.h b/chrome/browser/printing/print_view_manager_base.h
index e22cff2..59ef9a7f 100644
--- a/chrome/browser/printing/print_view_manager_base.h
+++ b/chrome/browser/printing/print_view_manager_base.h
@@ -77,6 +77,8 @@
 
   // mojom::PrintManagerHost:
   void DidGetPrintedPagesCount(int32_t cookie, uint32_t number_pages) override;
+  void DidPrintDocument(mojom::DidPrintDocumentParamsPtr params,
+                        DidPrintDocumentCallback callback) override;
 #if BUILDFLAG(ENABLE_TAGGED_PDF)
   void SetAccessibilityTree(
       int32_t cookie,
@@ -133,10 +135,6 @@
   void NavigationStopped() override;
 
   // printing::PrintManager:
-  void OnDidPrintDocument(
-      content::RenderFrameHost* render_frame_host,
-      const mojom::DidPrintDocumentParams& params,
-      std::unique_ptr<DelayedFrameDispatchHelper> helper) override;
   void OnScriptedPrint(content::RenderFrameHost* render_frame_host,
                        const mojom::ScriptedPrintParams& params,
                        IPC::Message* reply_msg) override;
@@ -145,7 +143,7 @@
   void OnComposePdfDone(const gfx::Size& page_size,
                         const gfx::Rect& content_area,
                         const gfx::Point& physical_offsets,
-                        std::unique_ptr<DelayedFrameDispatchHelper> helper,
+                        DidPrintDocumentCallback callback,
                         mojom::PrintCompositor::Status status,
                         base::ReadOnlySharedMemoryRegion region);
 
diff --git a/chrome/browser/profiles/android/profile_downloader_android.cc b/chrome/browser/profiles/android/profile_downloader_android.cc
index c600063..a7910ca 100644
--- a/chrome/browser/profiles/android/profile_downloader_android.cc
+++ b/chrome/browser/profiles/android/profile_downloader_android.cc
@@ -7,7 +7,6 @@
 #include "base/android/jni_android.h"
 #include "base/android/jni_string.h"
 #include "base/macros.h"
-#include "chrome/android/chrome_jni_headers/ProfileDownloader_jni.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/profiles/profile_android.h"
 #include "chrome/browser/profiles/profile_attributes_entry.h"
@@ -17,6 +16,7 @@
 #include "chrome/browser/profiles/profile_downloader_delegate.h"
 #include "chrome/browser/profiles/profile_manager.h"
 #include "chrome/browser/signin/identity_manager_factory.h"
+#include "chrome/browser/signin/services/android/jni_headers/ProfileDownloader_jni.h"
 #include "components/signin/public/identity_manager/identity_manager.h"
 #include "content/public/browser/storage_partition.h"
 #include "google_apis/gaia/gaia_auth_util.h"
diff --git a/chrome/browser/profiles/profile_attributes_entry.cc b/chrome/browser/profiles/profile_attributes_entry.cc
index 8d382354..555ee47 100644
--- a/chrome/browser/profiles/profile_attributes_entry.cc
+++ b/chrome/browser/profiles/profile_attributes_entry.cc
@@ -653,7 +653,8 @@
 }
 
 void ProfileAttributesEntry::SetHostedDomain(std::string hosted_domain) {
-  SetString(kHostedDomain, hosted_domain);
+  if (SetString(kHostedDomain, hosted_domain))
+    profile_info_cache_->NotifyProfileHostedDomainChanged(GetPath());
 }
 
 void ProfileAttributesEntry::SetAuthInfo(const std::string& gaia_id,
diff --git a/chrome/browser/profiles/profile_attributes_storage_unittest.cc b/chrome/browser/profiles/profile_attributes_storage_unittest.cc
index 43705ba9..f4487f2d 100644
--- a/chrome/browser/profiles/profile_attributes_storage_unittest.cc
+++ b/chrome/browser/profiles/profile_attributes_storage_unittest.cc
@@ -104,6 +104,8 @@
                void(const base::FilePath& profile_path));
   MOCK_METHOD1(OnProfileThemeColorsChanged,
                void(const base::FilePath& profile_path));
+  MOCK_METHOD1(OnProfileHostedDomainChanged,
+               void(const base::FilePath& profile_path));
 };
 }  // namespace
 
@@ -140,6 +142,8 @@
     EXPECT_CALL(observer_, OnProfileSigninRequiredChanged(_)).Times(0);
     EXPECT_CALL(observer_, OnProfileSupervisedUserIdChanged(_)).Times(0);
     EXPECT_CALL(observer_, OnProfileIsOmittedChanged(_)).Times(0);
+    EXPECT_CALL(observer_, OnProfileThemeColorsChanged(_)).Times(0);
+    EXPECT_CALL(observer_, OnProfileHostedDomainChanged(_)).Times(0);
   }
 
   void EnableObserver() { storage()->AddObserver(&observer_); }
@@ -298,7 +302,8 @@
   EXPECT_EQ(std::string("testing_profile_gaia0"), entry->GetGAIAId());
   EXPECT_EQ(base::ASCIIToUTF16("testing_profile_user0"), entry->GetUserName());
   EXPECT_EQ(0U, entry->GetAvatarIconIndex());
-  EXPECT_EQ(std::string(""), entry->GetSupervisedUserId());
+  EXPECT_EQ(std::string(), entry->GetSupervisedUserId());
+  EXPECT_EQ(std::string(), entry->GetHostedDomain());
 }
 
 TEST_F(ProfileAttributesStorageTest, EntryAccessors) {
@@ -333,6 +338,10 @@
   TEST_BOOL_ACCESSORS(ProfileAttributesEntry, entry, IsOmitted);
   VerifyAndResetCallExpectations();
 
+  EXPECT_CALL(observer(), OnProfileHostedDomainChanged(path)).Times(2);
+  TEST_STRING_ACCESSORS(ProfileAttributesEntry, entry, HostedDomain);
+  VerifyAndResetCallExpectations();
+
   TEST_BOOL_ACCESSORS(ProfileAttributesEntry, entry, IsEphemeral);
 
   EXPECT_CALL(observer(), OnProfileNameChanged(path, _)).Times(2);
diff --git a/chrome/browser/profiles/profile_impl.cc b/chrome/browser/profiles/profile_impl.cc
index b121e9e..767fc355 100644
--- a/chrome/browser/profiles/profile_impl.cc
+++ b/chrome/browser/profiles/profile_impl.cc
@@ -1344,7 +1344,11 @@
     std::vector<network::mojom::CorsOriginPatternPtr> allow_patterns,
     std::vector<network::mojom::CorsOriginPatternPtr> block_patterns,
     base::OnceClosure closure) {
-  auto barrier_closure = BarrierClosure(3, std::move(closure));
+  std::vector<Profile*> otr_profiles = GetAllOffTheRecordProfiles();
+  // We need two callbacks for the regular profile and shared cors origin access
+  // list, and one for each off-the-record profile.
+  auto barrier_closure =
+      BarrierClosure(2 + otr_profiles.size(), std::move(closure));
 
   // Keep profile storage partitions' NetworkContexts synchronized.
   auto profile_setter = base::MakeRefCounted<CorsOriginPatternSetter>(
@@ -1354,19 +1358,16 @@
       this, base::BindRepeating(&CorsOriginPatternSetter::SetLists,
                                 base::RetainedRef(profile_setter.get())));
 
-  // Keep incognito storage partitions' NetworkContexts synchronized.
-  if (HasPrimaryOTRProfile()) {
+  // Keep off-the-record storage partitions' NetworkContexts synchronized.
+  for (Profile* otr : otr_profiles) {
     auto off_the_record_setter = base::MakeRefCounted<CorsOriginPatternSetter>(
         source_origin, CorsOriginPatternSetter::ClonePatterns(allow_patterns),
         CorsOriginPatternSetter::ClonePatterns(block_patterns),
         barrier_closure);
     ForEachStoragePartition(
-        GetPrimaryOTRProfile(),
+        otr,
         base::BindRepeating(&CorsOriginPatternSetter::SetLists,
                             base::RetainedRef(off_the_record_setter.get())));
-  } else {
-    // Release unused closure reference.
-    barrier_closure.Run();
   }
 
   // Keep the per-profile access list up to date so that we can use this to
diff --git a/chrome/browser/profiles/profile_impl.h b/chrome/browser/profiles/profile_impl.h
index 6afd9ec..6ed3d1cc 100644
--- a/chrome/browser/profiles/profile_impl.h
+++ b/chrome/browser/profiles/profile_impl.h
@@ -94,8 +94,6 @@
       override;
   content::BackgroundFetchDelegate* GetBackgroundFetchDelegate() override;
   content::BackgroundSyncController* GetBackgroundSyncController() override;
-  // TODO(https://crbug.com/1060940): Only supports primary OTR profile. Update
-  // to support all OTR profiles.
   void SetCorsOriginAccessListForOrigin(
       const url::Origin& source_origin,
       std::vector<network::mojom::CorsOriginPatternPtr> allow_patterns,
@@ -140,9 +138,8 @@
 #if !defined(OS_ANDROID)
   ChromeZoomLevelPrefs* GetZoomLevelPrefs() override;
 #endif
-  // TODO(https://crbug.com/1060940, https://crbug.com/1065444): Only supports
-  // primary OTR profile. Either update to support all OTR profiles or remove
-  // this function.
+  // TODO(https://crbug.com/1065444): Only supports primary OTR profile. Either
+  // update to support all OTR profiles or remove this function.
   PrefService* GetOffTheRecordPrefs() override;
   PrefService* GetReadOnlyOffTheRecordPrefs() override;
   policy::SchemaRegistryService* GetPolicySchemaRegistryService() override;
diff --git a/chrome/browser/profiles/profile_info_cache.cc b/chrome/browser/profiles/profile_info_cache.cc
index c41aae4..b889aaa 100644
--- a/chrome/browser/profiles/profile_info_cache.cc
+++ b/chrome/browser/profiles/profile_info_cache.cc
@@ -231,6 +231,12 @@
     observer.OnProfileThemeColorsChanged(profile_path);
 }
 
+void ProfileInfoCache::NotifyProfileHostedDomainChanged(
+    const base::FilePath& profile_path) {
+  for (auto& observer : observer_list_)
+    observer.OnProfileHostedDomainChanged(profile_path);
+}
+
 void ProfileInfoCache::DeleteProfileFromCache(
     const base::FilePath& profile_path) {
   ProfileAttributesEntry* entry;
diff --git a/chrome/browser/profiles/profile_info_cache.h b/chrome/browser/profiles/profile_info_cache.h
index d40f537..e19ee019 100644
--- a/chrome/browser/profiles/profile_info_cache.h
+++ b/chrome/browser/profiles/profile_info_cache.h
@@ -130,6 +130,7 @@
   void NotifyProfileSupervisedUserIdChanged(const base::FilePath& profile_path);
   void NotifyProfileIsOmittedChanged(const base::FilePath& profile_path);
   void NotifyProfileThemeColorsChanged(const base::FilePath& profile_path);
+  void NotifyProfileHostedDomainChanged(const base::FilePath& profile_path);
 
  private:
   FRIEND_TEST_ALL_PREFIXES(ProfileAttributesStorageTest,
diff --git a/chrome/browser/profiles/profile_info_cache_observer.h b/chrome/browser/profiles/profile_info_cache_observer.h
index 6b6ddd9..a426344 100644
--- a/chrome/browser/profiles/profile_info_cache_observer.h
+++ b/chrome/browser/profiles/profile_info_cache_observer.h
@@ -38,6 +38,8 @@
       const base::FilePath& profile_path) {}
   virtual void OnProfileThemeColorsChanged(const base::FilePath& profile_path) {
   }
+  virtual void OnProfileHostedDomainChanged(
+      const base::FilePath& profile_path) {}
 
  protected:
   ProfileInfoCacheObserver() = default;
diff --git a/chrome/browser/resources/chromeos/bluetooth_pairing_dialog/BUILD.gn b/chrome/browser/resources/chromeos/bluetooth_pairing_dialog/BUILD.gn
index f7aa78a..e02e040 100644
--- a/chrome/browser/resources/chromeos/bluetooth_pairing_dialog/BUILD.gn
+++ b/chrome/browser/resources/chromeos/bluetooth_pairing_dialog/BUILD.gn
@@ -4,7 +4,7 @@
 
 import("//chrome/common/features.gni")
 import("//third_party/closure_compiler/compile_js.gni")
-import("//tools/grit/preprocess_grit.gni")
+import("//tools/grit/preprocess_if_expr.gni")
 import("//tools/polymer/html_to_js.gni")
 import("//ui/webui/resources/tools/generate_grd.gni")
 import("../../optimize_webui.gni")
@@ -47,7 +47,7 @@
   out_grd = "$target_gen_dir/${grd_prefix}_resources.grd"
 }
 
-preprocess_grit("preprocess_generated") {
+preprocess_if_expr("preprocess_generated") {
   deps = [ ":web_components" ]
   in_folder = target_gen_dir
   out_folder = "$target_gen_dir/$preprocess_folder"
diff --git a/chrome/browser/resources/nearby_internals/BUILD.gn b/chrome/browser/resources/nearby_internals/BUILD.gn
index 1f24052..4da8110 100644
--- a/chrome/browser/resources/nearby_internals/BUILD.gn
+++ b/chrome/browser/resources/nearby_internals/BUILD.gn
@@ -5,7 +5,7 @@
 import("//chrome/common/features.gni")
 import("//third_party/closure_compiler/compile_js.gni")
 import("//tools/grit/grit_rule.gni")
-import("//tools/grit/preprocess_grit.gni")
+import("//tools/grit/preprocess_if_expr.gni")
 import("//tools/polymer/html_to_js.gni")
 import("//ui/webui/resources/tools/generate_grd.gni")
 
@@ -29,7 +29,7 @@
   ]
 }
 
-preprocess_grit("preprocess") {
+preprocess_if_expr("preprocess") {
   in_folder = "./"
   out_folder = "$target_gen_dir/$preprocess_folder"
   out_manifest = "$target_gen_dir/$preprocess_manifest"
@@ -42,7 +42,7 @@
   ]
 }
 
-preprocess_grit("preprocess_generated") {
+preprocess_if_expr("preprocess_generated") {
   deps = [ ":web_components" ]
   in_folder = target_gen_dir
   out_folder = "$target_gen_dir/$preprocess_folder"
diff --git a/chrome/browser/resources/settings/chromeos/BUILD.gn b/chrome/browser/resources/settings/chromeos/BUILD.gn
index 3aa907d96..925b4e9 100644
--- a/chrome/browser/resources/settings/chromeos/BUILD.gn
+++ b/chrome/browser/resources/settings/chromeos/BUILD.gn
@@ -5,7 +5,7 @@
 import("//chrome/common/features.gni")
 import("//third_party/closure_compiler/compile_js.gni")
 import("//tools/grit/grit_rule.gni")
-import("//tools/grit/preprocess_grit.gni")
+import("//tools/grit/preprocess_if_expr.gni")
 import("//ui/webui/resources/tools/generate_grd.gni")
 import("//ui/webui/resources/tools/js_modulizer.gni")
 import("//ui/webui/webui_features.gni")
@@ -122,7 +122,7 @@
 # OS Settings specific mojo files, bundled in optimized builds. No need for a
 # manifest as the preprocess_mojo_v3 target generates the manifest file for the
 # grd.
-preprocess_grit("preprocess_mojo_v2") {
+preprocess_if_expr("preprocess_mojo_v2") {
   deps = [
     "//chrome/browser/ui/webui/settings/chromeos/constants:mojom_js",
     "//chrome/browser/ui/webui/settings/chromeos/search:mojo_bindings_js",
@@ -139,7 +139,7 @@
 }
 
 # OS Settings specific mojo files, bundled in optimized builds.
-preprocess_grit("preprocess_mojo_v3") {
+preprocess_if_expr("preprocess_mojo_v3") {
   deps = [
     "//chrome/browser/ui/webui/settings/chromeos/constants:mojom_js",
     "//chrome/browser/ui/webui/settings/chromeos/search:mojo_bindings_js",
@@ -157,7 +157,7 @@
 }
 
 # Mojo files generated by non-OS-settings targets, not bundled.
-preprocess_grit("preprocess_external_mojo") {
+preprocess_if_expr("preprocess_external_mojo") {
   deps = [
     "//chrome/browser/ui/webui/app_management:mojo_bindings_js",
     "//components/services/app_service/public/mojom:mojom_js",
@@ -266,7 +266,7 @@
   }
 }
 
-preprocess_grit("preprocess_v3") {
+preprocess_if_expr("preprocess_v3") {
   defines = chrome_grit_defines
   in_folder = "../"
   out_folder = "$target_gen_dir/$preprocess_folder_v3"
@@ -280,7 +280,7 @@
   ]
 }
 
-preprocess_grit("preprocess_gen_v3") {
+preprocess_if_expr("preprocess_gen_v3") {
   defines = chrome_grit_defines
   deps = [ ":polymer3_elements" ]
   in_folder = get_path_info("../", "gen_dir")
@@ -474,7 +474,7 @@
   ]
 }
 
-preprocess_grit("preprocess_v2") {
+preprocess_if_expr("preprocess_v2") {
   defines = chrome_grit_defines
   in_folder = "../"
   out_folder = "$target_gen_dir/$preprocess_folder_v2"
diff --git a/chrome/browser/resources/signin/profile_customization/profile_customization_app.js b/chrome/browser/resources/signin/profile_customization/profile_customization_app.js
index bb341c2..4e7b6fa7 100644
--- a/chrome/browser/resources/signin/profile_customization/profile_customization_app.js
+++ b/chrome/browser/resources/signin/profile_customization/profile_customization_app.js
@@ -30,7 +30,7 @@
     /** Whether the account is managed (Enterprise) */
     isManaged_: {
       type: Boolean,
-      value: () => loadTimeData.getBoolean('isManaged'),
+      value: false,
     },
 
     /** Initial local profile name, non-editable */
@@ -95,5 +95,6 @@
     this.style.setProperty(
         '--header-background-color', profileInfo.backgroundColor);
     this.pictureUrl_ = profileInfo.pictureUrl;
+    this.isManaged_ = profileInfo.isManaged;
   },
 });
diff --git a/chrome/browser/resources/signin/profile_customization/profile_customization_browser_proxy.js b/chrome/browser/resources/signin/profile_customization/profile_customization_browser_proxy.js
index 621d586..91e5e9f 100644
--- a/chrome/browser/resources/signin/profile_customization/profile_customization_browser_proxy.js
+++ b/chrome/browser/resources/signin/profile_customization/profile_customization_browser_proxy.js
@@ -15,6 +15,7 @@
  *   textColor: string,
  *   backgroundColor: string,
  *   pictureUrl: string,
+ *   isManaged: boolean,
  * }}
  */
 export let ProfileInfo;
diff --git a/chrome/browser/resources/signin/profile_picker/BUILD.gn b/chrome/browser/resources/signin/profile_picker/BUILD.gn
index 36b57cb..7b13044 100644
--- a/chrome/browser/resources/signin/profile_picker/BUILD.gn
+++ b/chrome/browser/resources/signin/profile_picker/BUILD.gn
@@ -5,7 +5,7 @@
 import("//chrome/common/features.gni")
 import("//third_party/closure_compiler/compile_js.gni")
 import("//tools/grit/grit_rule.gni")
-import("//tools/grit/preprocess_grit.gni")
+import("//tools/grit/preprocess_if_expr.gni")
 import("//tools/polymer/html_to_js.gni")
 import("//ui/webui/resources/tools/generate_grd.gni")
 import("../../optimize_webui.gni")
@@ -77,7 +77,7 @@
   }
 }
 
-preprocess_grit("preprocess") {
+preprocess_if_expr("preprocess") {
   in_folder = "./"
   out_folder = "$target_gen_dir/$preprocess_folder"
   out_manifest = "$target_gen_dir/$preprocess_manifest"
@@ -92,7 +92,7 @@
   ]
 }
 
-preprocess_grit("preprocess_generated") {
+preprocess_if_expr("preprocess_generated") {
   deps = [ ":web_components" ]
   in_folder = target_gen_dir
   out_folder = "$target_gen_dir/$preprocess_folder"
diff --git a/chrome/browser/resources/sync_file_system_internals/BUILD.gn b/chrome/browser/resources/sync_file_system_internals/BUILD.gn
index 1e747e4..4cf13d3 100644
--- a/chrome/browser/resources/sync_file_system_internals/BUILD.gn
+++ b/chrome/browser/resources/sync_file_system_internals/BUILD.gn
@@ -5,6 +5,7 @@
 import("//third_party/closure_compiler/compile_js.gni")
 
 js_type_check("closure_compile") {
+  uses_js_modules = true
   deps = [
     ":dump_database",
     ":extension_statuses",
@@ -18,43 +19,43 @@
 js_library("dump_database") {
   deps = [
     ":utils",
-    "//ui/webui/resources/js:cr",
-    "//ui/webui/resources/js:util",
+    "//ui/webui/resources/js:cr.m",
+    "//ui/webui/resources/js:util.m",
   ]
 }
 
 js_library("extension_statuses") {
   deps = [
     ":utils",
-    "//ui/webui/resources/js:cr",
-    "//ui/webui/resources/js:util",
+    "//ui/webui/resources/js:cr.m",
+    "//ui/webui/resources/js:util.m",
   ]
 }
 
 js_library("file_metadata") {
   deps = [
     ":utils",
-    "//ui/webui/resources/js:cr",
-    "//ui/webui/resources/js:icon",
-    "//ui/webui/resources/js:util",
+    "//ui/webui/resources/js:cr.m",
+    "//ui/webui/resources/js:icon.m",
+    "//ui/webui/resources/js:util.m",
   ]
 }
 
 js_library("sync_service") {
   deps = [
     ":utils",
-    "//ui/webui/resources/js:cr",
-    "//ui/webui/resources/js:util",
-    "//ui/webui/resources/js/cr:ui",
-    "//ui/webui/resources/js/cr/ui:tabs",
+    "//ui/webui/resources/js:cr.m",
+    "//ui/webui/resources/js:util.m",
+    "//ui/webui/resources/js/cr:ui.m",
+    "//ui/webui/resources/js/cr/ui:tabs.m",
   ]
 }
 
 js_library("task_log") {
   deps = [
     ":utils",
-    "//ui/webui/resources/js:cr",
-    "//ui/webui/resources/js:util",
+    "//ui/webui/resources/js:cr.m",
+    "//ui/webui/resources/js:util.m",
   ]
 }
 
diff --git a/chrome/browser/resources/sync_file_system_internals/dump_database.html b/chrome/browser/resources/sync_file_system_internals/dump_database.html
index 21511f1e..b610df38 100644
--- a/chrome/browser/resources/sync_file_system_internals/dump_database.html
+++ b/chrome/browser/resources/sync_file_system_internals/dump_database.html
@@ -1,5 +1,3 @@
-<script src="chrome://syncfs-internals/dump_database.js"></script>
-
 <button id="refresh-database-dump">Refresh</button>
 
 <div id="dump-database-placeholder"></div>
diff --git a/chrome/browser/resources/sync_file_system_internals/dump_database.js b/chrome/browser/resources/sync_file_system_internals/dump_database.js
index 3ec2267..e71a1d3 100644
--- a/chrome/browser/resources/sync_file_system_internals/dump_database.js
+++ b/chrome/browser/resources/sync_file_system_internals/dump_database.js
@@ -5,16 +5,16 @@
 /**
  * Handles DumpDatabase tab for syncfs-internals.
  */
-const DumpDatabase = (function() {
-  'use strict';
 
-  const DumpDatabase = {};
+import {sendWithPromise} from 'chrome://resources/js/cr.m.js';
+import {$} from 'chrome://resources/js/util.m.js';
+import {createElementFromText} from './utils.js';
 
   /**
    * Get the database dump.
    */
   function refreshDatabaseDump() {
-    cr.sendWithPromise('getDatabaseDump').then(DumpDatabase.onGetDatabaseDump);
+    sendWithPromise('getDatabaseDump').then(onGetDatabaseDump);
   }
 
   /**
@@ -55,7 +55,7 @@
    * Handles callback from onGetDatabaseDump.
    * @param {Array} databaseDump List of lists for the database dump.
    */
-  DumpDatabase.onGetDatabaseDump = function(databaseDump) {
+  function onGetDatabaseDump(databaseDump) {
     const placeholder = $('dump-database-placeholder');
     placeholder.innerHTML = trustedTypes.emptyHTML;
     for (let i = 0; i < databaseDump.length; ++i) {
@@ -71,7 +71,7 @@
       div.appendChild(table);
       placeholder.appendChild(div);
     }
-  };
+  }
 
   function main() {
     refreshDatabaseDump();
@@ -79,5 +79,3 @@
   }
 
   document.addEventListener('DOMContentLoaded', main);
-  return DumpDatabase;
-})();
diff --git a/chrome/browser/resources/sync_file_system_internals/extension_statuses.html b/chrome/browser/resources/sync_file_system_internals/extension_statuses.html
index 51e6871..0d802d7e 100644
--- a/chrome/browser/resources/sync_file_system_internals/extension_statuses.html
+++ b/chrome/browser/resources/sync_file_system_internals/extension_statuses.html
@@ -1,5 +1,3 @@
-<script src="chrome://syncfs-internals/extension_statuses.js"></script>
-
 <button id="refresh-extensions-statuses">Refresh</button>
 <table>
   <thead>
diff --git a/chrome/browser/resources/sync_file_system_internals/extension_statuses.js b/chrome/browser/resources/sync_file_system_internals/extension_statuses.js
index 394546a..042c38a 100644
--- a/chrome/browser/resources/sync_file_system_internals/extension_statuses.js
+++ b/chrome/browser/resources/sync_file_system_internals/extension_statuses.js
@@ -5,18 +5,17 @@
 /**
  * Handles the Extension ID -> SyncStatus tab for syncfs-internals.
  */
-const ExtensionStatuses = (function() {
-  'use strict';
 
-  const ExtensionStatuses = {};
+import {sendWithPromise} from 'chrome://resources/js/cr.m.js';
+import {$} from 'chrome://resources/js/util.m.js';
+import {createElementFromText} from './utils.js';
 
   /**
    * Get initial map of extension statuses (pending batch sync, enabled and
    * disabled).
    */
   function refreshExtensionStatuses() {
-    cr.sendWithPromise('getExtensionStatuses')
-        .then(ExtensionStatuses.onGetExtensionStatuses);
+    sendWithPromise('getExtensionStatuses').then(onGetExtensionStatuses);
   }
 
   /**
@@ -27,7 +26,7 @@
    *   status: string,
    * }>} extensionStatuses
    */
-  ExtensionStatuses.onGetExtensionStatuses = function(extensionStatuses) {
+  function onGetExtensionStatuses(extensionStatuses) {
     const itemContainer = $('extension-entries');
     itemContainer.textContent = '';
 
@@ -39,7 +38,7 @@
       tr.appendChild(createElementFromText('td', originEntry.status));
       itemContainer.appendChild(tr);
     }
-  };
+  }
 
   function main() {
     refreshExtensionStatuses();
@@ -48,5 +47,3 @@
   }
 
   document.addEventListener('DOMContentLoaded', main);
-  return ExtensionStatuses;
-})();
diff --git a/chrome/browser/resources/sync_file_system_internals/file_metadata.html b/chrome/browser/resources/sync_file_system_internals/file_metadata.html
index 59dcc10..ecb49337 100644
--- a/chrome/browser/resources/sync_file_system_internals/file_metadata.html
+++ b/chrome/browser/resources/sync_file_system_internals/file_metadata.html
@@ -1,6 +1,3 @@
-<script src="chrome://resources/js/icon.js"></script>
-<script src="chrome://syncfs-internals/file_metadata.js"></script>
-
 <select id="extensions-select"></select>
 <button id="refresh-metadata-button">Refresh</button>
 
diff --git a/chrome/browser/resources/sync_file_system_internals/file_metadata.js b/chrome/browser/resources/sync_file_system_internals/file_metadata.js
index efe43383..049b02c 100644
--- a/chrome/browser/resources/sync_file_system_internals/file_metadata.js
+++ b/chrome/browser/resources/sync_file_system_internals/file_metadata.js
@@ -5,16 +5,18 @@
 /**
  * WebUI to monitor File Metadata per Extension ID.
  */
-const FileMetadata = (function() {
-  'use strict';
 
-  const FileMetadata = {};
+import {sendWithPromise} from 'chrome://resources/js/cr.m.js';
+import {getImage} from 'chrome://resources/js/icon.m.js';
+import {$} from 'chrome://resources/js/util.m.js';
+
+import {createElementFromDictionary, createElementFromText} from './utils.js';
 
   /**
    * Gets extension data so the select drop down can be filled.
    */
   function refreshExtensions() {
-    cr.sendWithPromise('getExtensions').then(FileMetadata.onGetExtensions);
+    sendWithPromise('getExtensions').then(onGetExtensions);
   }
 
   /**
@@ -26,7 +28,7 @@
    * }>} extensionStatuses of dictionaries containing 'extensionName',
    *     'extensionID', 'status'.
    */
-  FileMetadata.onGetExtensions = function(extensionStatuses) {
+  function onGetExtensions(extensionStatuses) {
     const select = $('extensions-select');
 
     // Record existing drop down extension ID. If it's still there after the
@@ -49,7 +51,7 @@
 
     // After drop down has been loaded with options, file metadata can be loaded
     refreshFileMetadata();
-  };
+  }
 
   /**
    * @return {?string} extension ID that's currently selected in drop down box.
@@ -76,14 +78,14 @@
     }
 
     const selectedExtensionId = getSelectedExtensionId();
-    cr.sendWithPromise('getFileMetadata', selectedExtensionId)
-        .then(FileMetadata.onGetFileMetadata);
+    sendWithPromise('getFileMetadata', selectedExtensionId)
+        .then(onGetFileMetadata);
   }
 
   /**
    * Renders result of getFileMetadata as a table.
    */
-  FileMetadata.onGetFileMetadata = function(fileMetadataMap) {
+  function onGetFileMetadata(fileMetadataMap) {
     const header = $('file-metadata-header');
     // Only draw the header if it hasn't been drawn yet
     if (header.children.length === 0) {
@@ -107,7 +109,7 @@
       tr.appendChild(createElementFromDictionary('td', metadatEntry.details));
       itemContainer.appendChild(tr);
     }
-  };
+  }
 
   /**
    * @param {string} type file type string.
@@ -117,10 +119,9 @@
     const img = document.createElement('div');
     const lowerType = type.toLowerCase();
     if (lowerType == 'file') {
-      img.style.content =
-          cr.icon.getImage('chrome://theme/IDR_DEFAULT_FAVICON');
+      img.style.content = getImage('chrome://theme/IDR_DEFAULT_FAVICON');
     } else if (lowerType == 'folder') {
-      img.style.content = cr.icon.getImage('chrome://theme/IDR_FOLDER_CLOSED');
+      img.style.content = getImage('chrome://theme/IDR_FOLDER_CLOSED');
       img.className = 'folder-image';
     }
 
@@ -141,5 +142,3 @@
   }
 
   document.addEventListener('DOMContentLoaded', main);
-  return FileMetadata;
-})();
diff --git a/chrome/browser/resources/sync_file_system_internals/main.html b/chrome/browser/resources/sync_file_system_internals/main.html
index f1efad6..83b94c0 100644
--- a/chrome/browser/resources/sync_file_system_internals/main.html
+++ b/chrome/browser/resources/sync_file_system_internals/main.html
@@ -8,19 +8,12 @@
 <meta charset="utf-8">
 <title>Sync File System Internals</title>
 <link rel="stylesheet" href="chrome://resources/css/text_defaults.css">
-<link rel="stylesheet" href="main.css">
-
-<script src="chrome://resources/js/assert.js"></script>
-<script src="chrome://resources/js/util.js"></script>
-<script src="chrome://resources/js/promise_resolver.js"></script>
-<script src="chrome://resources/js/cr.js"></script>
-<script src="chrome://resources/js/cr/event_target.js"></script>
-
 <link rel="stylesheet" href="chrome://resources/css/tabs.css">
-<script src="chrome://resources/js/cr/ui.js"></script>
-<script src="chrome://resources/js/cr/ui/tabs.js"></script>
-<script src="chrome://resources/js/cr/ui/focus_outline_manager.js"></script>
-<script src="chrome://syncfs-internals/utils.js"></script>
+<link rel="stylesheet" href="main.css">
+<script type="module" src="sync_service.js"></script>
+<script type="module" src="task_log.js"></script>
+<script type="module" src="extension_statuses.js"></script>
+<script type="module" src="dump_database.js"></script>
 
 <body>
 
diff --git a/chrome/browser/resources/sync_file_system_internals/sync_service.html b/chrome/browser/resources/sync_file_system_internals/sync_service.html
index 102f4d86..e7ef906 100644
--- a/chrome/browser/resources/sync_file_system_internals/sync_service.html
+++ b/chrome/browser/resources/sync_file_system_internals/sync_service.html
@@ -1,5 +1,3 @@
-<script src="chrome://syncfs-internals/sync_service.js"></script>
-
 <table>
   <tbody>
     <tr>
diff --git a/chrome/browser/resources/sync_file_system_internals/sync_service.js b/chrome/browser/resources/sync_file_system_internals/sync_service.js
index 6fa86bac2..7f2677d 100644
--- a/chrome/browser/resources/sync_file_system_internals/sync_service.js
+++ b/chrome/browser/resources/sync_file_system_internals/sync_service.js
@@ -5,41 +5,43 @@
 /**
  * WebUI to monitor the Sync File System Service.
  */
-const SyncService = (function() {
-  'use strict';
 
-  const SyncService = {};
+import {addWebUIListener, sendWithPromise} from 'chrome://resources/js/cr.m.js';
+import {decorate} from 'chrome://resources/js/cr/ui.m.js';
+import {TabBox} from 'chrome://resources/js/cr/ui/tabs.m.js';
+import {$} from 'chrome://resources/js/util.m.js';
+
+import {createElementFromText} from './utils.js';
 
   /**
    * Request Sync Service Status.
    */
   function refreshServiceStatus() {
-    cr.sendWithPromise('getServiceStatus').then(SyncService.onGetServiceStatus);
+    sendWithPromise('getServiceStatus').then(onGetServiceStatus);
   }
 
   /**
    * Called when service status is initially retrieved or updated via events.
    * @param {string} statusString Service status enum as a string.
    */
-  SyncService.onGetServiceStatus = function(statusString) {
+  function onGetServiceStatus(statusString) {
     $('service-status').textContent = statusString;
-  };
+  }
 
   /**
    * Request Google Drive Notification Source. e.g. XMPP or polling.
    */
   function refreshNotificationSource() {
-    cr.sendWithPromise('getNotificationSource')
-        .then(SyncService.onGetNotificationSource);
+    sendWithPromise('getNotificationSource').then(onGetNotificationSource);
   }
 
   /**
    * Handles callback from getNotificationSource.
    * @param {string} sourceString Notification source as a string.
    */
-  SyncService.onGetNotificationSource = function(sourceString) {
+  function onGetNotificationSource(sourceString) {
     $('notification-source').textContent = sourceString;
-  };
+  }
 
   // Keeps track of the last log event seen so it's not reprinted.
   let lastLogEventId = -1;
@@ -48,7 +50,7 @@
    * Request debug log.
    */
   function refreshLog() {
-    cr.sendWithPromise('getLog', lastLogEventId).then(SyncService.onGetLog);
+    sendWithPromise('getLog', lastLogEventId).then(onGetLog);
   }
 
   /**
@@ -67,7 +69,7 @@
    *   time: string,
    * }>} logEntries List of dictionaries containing 'id', 'time', 'logEvent'.
    */
-  SyncService.onGetLog = function(logEntries) {
+  function onGetLog(logEntries) {
     const itemContainer = $('log-entries');
     for (let i = 0; i < logEntries.length; i++) {
       const logEntry = logEntries[i];
@@ -81,24 +83,21 @@
 
       lastLogEventId = logEntry.id;
     }
-  };
+  }
 
   /**
    * Get initial sync service values and set listeners to get updated values.
    */
   function main() {
-    cr.ui.decorate('tabbox', cr.ui.TabBox);
+    decorate('tabbox', TabBox);
     $('clear-log-button').addEventListener('click', clearLogs);
     refreshServiceStatus();
     refreshNotificationSource();
 
-    cr.addWebUIListener(
-        'service-status-changed', SyncService.onGetServiceStatus);
+    addWebUIListener('service-status-changed', onGetServiceStatus);
 
     // TODO: Look for a way to push entries to the page when necessary.
     window.setInterval(refreshLog, 1000);
   }
 
   document.addEventListener('DOMContentLoaded', main);
-  return SyncService;
-})();
diff --git a/chrome/browser/resources/sync_file_system_internals/task_log.html b/chrome/browser/resources/sync_file_system_internals/task_log.html
index 9de27fe9..bc8e15a 100644
--- a/chrome/browser/resources/sync_file_system_internals/task_log.html
+++ b/chrome/browser/resources/sync_file_system_internals/task_log.html
@@ -1,5 +1,3 @@
-<script src="chrome://syncfs-internals/task_log.js"></script>
-
 <h3>Task Log</h3>
 <table>
   <thead>
diff --git a/chrome/browser/resources/sync_file_system_internals/task_log.js b/chrome/browser/resources/sync_file_system_internals/task_log.js
index 5058a310..8db1bd8 100644
--- a/chrome/browser/resources/sync_file_system_internals/task_log.js
+++ b/chrome/browser/resources/sync_file_system_internals/task_log.js
@@ -2,15 +2,11 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-const TaskLog = (function() {
-  'use strict';
+import {addWebUIListener} from 'chrome://resources/js/cr.m.js';
+import {$} from 'chrome://resources/js/util.m.js';
+import {createElementFromText} from './utils.js';
 
   const nextTaskLogSeq = 1;
-  const TaskLog = {};
-
-  function observeTaskLog() {
-    chrome.send('observeTaskLog');
-  }
 
   /**
    * Handles per-task log event.
@@ -21,7 +17,7 @@
    *   details: !Array,
    * }} taskLog
    */
-  TaskLog.onTaskLogRecorded = function(taskLog) {
+  function onTaskLogRecorded(taskLog) {
     const details = document.createElement('td');
     details.classList.add('task-log-details');
 
@@ -49,16 +45,14 @@
     tr.appendChild(details);
 
     $('task-log-entries').appendChild(tr);
-  };
+  }
 
   /**
    * Get initial sync service values and set listeners to get updated values.
    */
   function main() {
-    cr.addWebUIListener('task-log-recorded', TaskLog.onTaskLogRecorded);
-    observeTaskLog();
+    addWebUIListener('task-log-recorded', onTaskLogRecorded);
+    chrome.send('observeTaskLog');
   }
 
   document.addEventListener('DOMContentLoaded', main);
-  return TaskLog;
-})();
diff --git a/chrome/browser/resources/sync_file_system_internals/utils.js b/chrome/browser/resources/sync_file_system_internals/utils.js
index ed5b45a..bd23d91 100644
--- a/chrome/browser/resources/sync_file_system_internals/utils.js
+++ b/chrome/browser/resources/sync_file_system_internals/utils.js
@@ -10,7 +10,7 @@
  *     element.
  * @return {!HTMLElement} The newly created HTML element.
  */
-function createElementFromText(elementName, text, opt_attributes) {
+export function createElementFromText(elementName, text, opt_attributes) {
   const element =
       /** @type {!HTMLElement} */ (document.createElement(elementName));
   element.appendChild(document.createTextNode(text));
@@ -29,7 +29,7 @@
  * element.
  * @return {!HTMLElement} The newly created HTML element.
  */
-function createElementFromDictionary(elementName, dict) {
+export function createElementFromDictionary(elementName, dict) {
   const element =
       /** @type {!HTMLElement} */ (document.createElement(elementName));
   for (const key in dict) {
diff --git a/chrome/browser/signin/dice_intercepted_session_startup_helper.cc b/chrome/browser/signin/dice_intercepted_session_startup_helper.cc
index b4e28848..1b69974 100644
--- a/chrome/browser/signin/dice_intercepted_session_startup_helper.cc
+++ b/chrome/browser/signin/dice_intercepted_session_startup_helper.cc
@@ -76,9 +76,12 @@
     accounts_in_cookie_observer_.Observe(identity_manager);
     on_cookie_update_timeout_.Reset(base::BindOnce(
         &DiceInterceptedSessionStartupHelper::MoveTab, base::Unretained(this)));
+    // Adding accounts to the cookies can be an expensive operation. In
+    // particular the ExternalCCResult fetch may time out after multiple seconds
+    // (see kExternalCCResultTimeoutSeconds and https://crbug.com/750316#c37).
     base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
         FROM_HERE, on_cookie_update_timeout_.callback(),
-        base::TimeDelta::FromSeconds(5));
+        base::TimeDelta::FromSeconds(12));
   }
 }
 
diff --git a/chrome/browser/signin/services/android/BUILD.gn b/chrome/browser/signin/services/android/BUILD.gn
index 8297994..5a8d67d 100644
--- a/chrome/browser/signin/services/android/BUILD.gn
+++ b/chrome/browser/signin/services/android/BUILD.gn
@@ -7,6 +7,7 @@
 generate_jni("jni_headers") {
   sources = [
     "java/src/org/chromium/chrome/browser/signin/services/IdentityServicesProvider.java",
+    "java/src/org/chromium/chrome/browser/signin/services/ProfileDownloader.java",
     "java/src/org/chromium/chrome/browser/signin/services/UnifiedConsentServiceBridge.java",
     "java/src/org/chromium/chrome/browser/signin/services/WebSigninBridge.java",
   ]
@@ -14,7 +15,9 @@
 
 android_library("java") {
   sources = [
+    "java/src/org/chromium/chrome/browser/signin/services/DisplayableProfileData.java",
     "java/src/org/chromium/chrome/browser/signin/services/IdentityServicesProvider.java",
+    "java/src/org/chromium/chrome/browser/signin/services/ProfileDownloader.java",
     "java/src/org/chromium/chrome/browser/signin/services/SigninManager.java",
     "java/src/org/chromium/chrome/browser/signin/services/SigninPreferencesManager.java",
     "java/src/org/chromium/chrome/browser/signin/services/UnifiedConsentServiceBridge.java",
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/signin/DisplayableProfileData.java b/chrome/browser/signin/services/android/java/src/org/chromium/chrome/browser/signin/services/DisplayableProfileData.java
similarity index 96%
rename from chrome/android/java/src/org/chromium/chrome/browser/signin/DisplayableProfileData.java
rename to chrome/browser/signin/services/android/java/src/org/chromium/chrome/browser/signin/services/DisplayableProfileData.java
index d26ffde..8997808 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/signin/DisplayableProfileData.java
+++ b/chrome/browser/signin/services/android/java/src/org/chromium/chrome/browser/signin/services/DisplayableProfileData.java
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-package org.chromium.chrome.browser.signin;
+package org.chromium.chrome.browser.signin.services;
 
 import android.graphics.drawable.Drawable;
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/signin/ProfileDownloader.java b/chrome/browser/signin/services/android/java/src/org/chromium/chrome/browser/signin/services/ProfileDownloader.java
similarity index 94%
rename from chrome/android/java/src/org/chromium/chrome/browser/signin/ProfileDownloader.java
rename to chrome/browser/signin/services/android/java/src/org/chromium/chrome/browser/signin/services/ProfileDownloader.java
index 0676544..eede782 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/signin/ProfileDownloader.java
+++ b/chrome/browser/signin/services/android/java/src/org/chromium/chrome/browser/signin/services/ProfileDownloader.java
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-package org.chromium.chrome.browser.signin;
+package org.chromium.chrome.browser.signin.services;
 
 import android.content.Context;
 import android.graphics.Bitmap;
@@ -12,7 +12,6 @@
 import org.chromium.base.annotations.CalledByNative;
 import org.chromium.base.annotations.NativeMethods;
 import org.chromium.chrome.browser.profiles.Profile;
-import org.chromium.chrome.browser.signin.services.IdentityServicesProvider;
 import org.chromium.components.signin.AccountTrackerService;
 import org.chromium.components.signin.ProfileDataSource;
 
@@ -23,14 +22,21 @@
  * The native ProfileDownloader requires its access to be in the UI thread.
  * See chrome/browser/profiles/profile_downloader.h/cc for more details.
  */
-class ProfileDownloader {
+public class ProfileDownloader {
+    private static final Object LOCK = new Object();
+
     private static ProfileDownloader sInstance;
 
     private final ObserverList<ProfileDataSource.Observer> mObservers = new ObserverList<>();
 
-    static synchronized ProfileDownloader get() {
-        if (sInstance == null) {
-            sInstance = new ProfileDownloader();
+    /**
+     * Get the instance of ProfileDownloader.
+     */
+    public static ProfileDownloader get() {
+        synchronized (LOCK) {
+            if (sInstance == null) {
+                sInstance = new ProfileDownloader();
+            }
         }
         return sInstance;
     }
diff --git a/chrome/browser/sync/test/integration/two_client_sessions_sync_test.cc b/chrome/browser/sync/test/integration/two_client_sessions_sync_test.cc
index d148831..0fbc711b 100644
--- a/chrome/browser/sync/test/integration/two_client_sessions_sync_test.cc
+++ b/chrome/browser/sync/test/integration/two_client_sessions_sync_test.cc
@@ -199,7 +199,7 @@
 }
 
 IN_PROC_BROWSER_TEST_F(TwoClientSessionsSyncTest,
-                       DISABLED_NoHistoryIfEncryptionEnabled) {
+                       NoHistoryIfEncryptionEnabled) {
   ASSERT_TRUE(SetupSync()) << "SetupSync() failed.";
 
   ASSERT_TRUE(CheckInitialState(0));
diff --git a/chrome/browser/ui/ash/assistant/assistant_browsertest.cc b/chrome/browser/ui/ash/assistant/assistant_browsertest.cc
index a2379d0..6ed21981 100644
--- a/chrome/browser/ui/ash/assistant/assistant_browsertest.cc
+++ b/chrome/browser/ui/ash/assistant/assistant_browsertest.cc
@@ -25,15 +25,6 @@
 
 constexpr int kStartBrightnessPercent = 50;
 
-// Ensures that |value_| is within the range {min_, max_}. If it isn't, this
-// will print a nice error message.
-#define EXPECT_WITHIN_RANGE(min_, value_, max_)                \
-  ({                                                           \
-    EXPECT_TRUE(min_ <= value_ && value_ <= max_)              \
-        << "Expected " << value_ << " to be within the range " \
-        << "{" << min_ << ", " << max_ << "}.";                \
-  })
-
 }  // namespace
 
 class AssistantBrowserTest : public MixinBasedInProcessBrowserTest {
diff --git a/chrome/browser/ui/ash/assistant/assistant_timers_browsertest.cc b/chrome/browser/ui/ash/assistant/assistant_timers_browsertest.cc
index 1908384..206e2f9 100644
--- a/chrome/browser/ui/ash/assistant/assistant_timers_browsertest.cc
+++ b/chrome/browser/ui/ash/assistant/assistant_timers_browsertest.cc
@@ -257,11 +257,9 @@
   // Start a timer for five minutes.
   tester()->SendTextQuery("Set a timer for 5 minutes");
   tester()->ExpectAnyOfTheseTextResponses({
-      "Alright, 5 min. Starting… now.",
-      "OK, 5 min. And we're starting… now.",
-      "OK, 5 min. Starting… now.",
-      "Sure, 5 min. And that's starting… now.",
-      "Sure, 5 min. Starting now.",
+      "Alright, 5 min.",
+      "OK, 5 min.",
+      "Sure, 5 min.",
   });
 
   // Tap status area widget (to show notifications in the Message Center).
diff --git a/chrome/browser/ui/passwords/settings/password_manager_porter.cc b/chrome/browser/ui/passwords/settings/password_manager_porter.cc
index 0f1af9d..111c050e 100644
--- a/chrome/browser/ui/passwords/settings/password_manager_porter.cc
+++ b/chrome/browser/ui/passwords/settings/password_manager_porter.cc
@@ -117,7 +117,7 @@
     : credential_provider_interface_(credential_provider_interface),
       on_export_progress_callback_(on_export_progress_callback) {}
 
-PasswordManagerPorter::~PasswordManagerPorter() {}
+PasswordManagerPorter::~PasswordManagerPorter() = default;
 
 bool PasswordManagerPorter::Store() {
   // In unittests a null WebContents means: "Abort creating the file Selector."
diff --git a/chrome/browser/ui/passwords/settings/password_manager_porter_unittest.cc b/chrome/browser/ui/passwords/settings/password_manager_porter_unittest.cc
index 664330c..a6d8f63 100644
--- a/chrome/browser/ui/passwords/settings/password_manager_porter_unittest.cc
+++ b/chrome/browser/ui/passwords/settings/password_manager_porter_unittest.cc
@@ -57,7 +57,7 @@
         forced_path_(forced_path) {}
 
  protected:
-  ~TestSelectFileDialog() override {}
+  ~TestSelectFileDialog() override = default;
 
   void SelectFileImpl(Type type,
                       const base::string16& title,
diff --git a/chrome/browser/ui/views/borealis/borealis_installer_view.cc b/chrome/browser/ui/views/borealis/borealis_installer_view.cc
index d6f5a39..b93039e 100644
--- a/chrome/browser/ui/views/borealis/borealis_installer_view.cc
+++ b/chrome/browser/ui/views/borealis/borealis_installer_view.cc
@@ -12,9 +12,9 @@
 #include "base/optional.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/utf_string_conversions.h"
-#include "chrome/browser/chromeos/borealis/borealis_context_manager_factory.h"
-#include "chrome/browser/chromeos/borealis/borealis_context_manager_impl.h"
+#include "chrome/browser/chromeos/borealis/borealis_context_manager.h"
 #include "chrome/browser/chromeos/borealis/borealis_installer_factory.h"
+#include "chrome/browser/chromeos/borealis/borealis_service.h"
 #include "chrome/browser/chromeos/borealis/borealis_util.h"
 #include "chrome/browser/ui/browser_navigator.h"
 #include "chrome/browser/ui/browser_navigator_params.h"
@@ -193,8 +193,9 @@
 
   if (state_ == State::kCompleted) {
     // Launch button has been clicked.
-    borealis::BorealisContextManagerFactory::GetForProfile(profile_)
-        ->StartBorealis(base::DoNothing());
+    borealis::BorealisService::GetForProfile(profile_)
+        ->ContextManager()
+        .StartBorealis(base::DoNothing());
     return true;
   }
 
diff --git a/chrome/browser/ui/views/borealis/borealis_installer_view_browsertest.cc b/chrome/browser/ui/views/borealis/borealis_installer_view_browsertest.cc
index e74b631..2334b675 100644
--- a/chrome/browser/ui/views/borealis/borealis_installer_view_browsertest.cc
+++ b/chrome/browser/ui/views/borealis/borealis_installer_view_browsertest.cc
@@ -7,9 +7,9 @@
 #include "base/bind.h"
 #include "chrome/browser/chromeos/borealis/borealis_context.h"
 #include "chrome/browser/chromeos/borealis/borealis_context_manager.h"
-#include "chrome/browser/chromeos/borealis/borealis_context_manager_factory.h"
 #include "chrome/browser/chromeos/borealis/borealis_installer_factory.h"
 #include "chrome/browser/chromeos/borealis/borealis_metrics.h"
+#include "chrome/browser/chromeos/borealis/borealis_service_fake.h"
 #include "chrome/browser/chromeos/borealis/borealis_task.h"
 #include "chrome/browser/chromeos/borealis/borealis_util.h"
 #include "chrome/browser/chromeos/profiles/profile_helper.h"
@@ -33,11 +33,6 @@
 
 class BorealisInstallerMock : public borealis::BorealisInstaller {
  public:
-  BorealisInstallerMock() = default;
-  ~BorealisInstallerMock() = default;
-  BorealisInstallerMock(const BorealisInstallerMock&) = delete;
-  BorealisInstallerMock& operator=(const BorealisInstallerMock&) = delete;
-
   MOCK_METHOD0(IsProcessing, bool());
   MOCK_METHOD0(Start, void());
   MOCK_METHOD0(Cancel, void());
@@ -47,12 +42,6 @@
 
 class BorealisContextManagerMock : public borealis::BorealisContextManager {
  public:
-  BorealisContextManagerMock() = default;
-  ~BorealisContextManagerMock() = default;
-  BorealisContextManagerMock(const BorealisContextManagerMock&) = delete;
-  BorealisContextManagerMock& operator=(const BorealisContextManagerMock&) =
-      delete;
-
   MOCK_METHOD(void,
               StartBorealis,
               (BorealisContextManager::ResultCallback),
@@ -74,17 +63,13 @@
                     browser()->profile(),
                     base::BindRepeating([](content::BrowserContext* context)
                                             -> std::unique_ptr<KeyedService> {
-                      return std::make_unique<BorealisInstallerMock>();
+                      return std::make_unique<
+                          testing::StrictMock<BorealisInstallerMock>>();
                     })));
-    mock_context_manager_ =
-        static_cast<::testing::StrictMock<BorealisContextManagerMock>*>(
-            borealis::BorealisContextManagerFactory::GetInstance()
-                ->SetTestingFactoryAndUse(
-                    browser()->profile(),
-                    base::BindRepeating([](content::BrowserContext* context)
-                                            -> std::unique_ptr<KeyedService> {
-                      return std::make_unique<BorealisContextManagerMock>();
-                    })));
+
+    BorealisServiceFake* fake_service =
+        BorealisServiceFake::UseFakeForTesting(browser()->profile());
+    fake_service->SetContextManagerForTesting(&mock_context_manager_);
   }
 
   void ShowUi(const std::string& name) override {
@@ -160,7 +145,7 @@
   }
 
   ::testing::StrictMock<BorealisInstallerMock>* mock_installer_;
-  ::testing::StrictMock<BorealisContextManagerMock>* mock_context_manager_;
+  ::testing::StrictMock<BorealisContextManagerMock> mock_context_manager_;
   BorealisInstallerView* view_;
   base::string16 app_name_;
 
@@ -175,6 +160,7 @@
 // Test that the dialog can be launched.
 IN_PROC_BROWSER_TEST_F(BorealisInstallerViewBrowserTest, InvokeUi_default) {
   EXPECT_CALL(*mock_installer_, RemoveObserver(_));
+  EXPECT_CALL(*mock_installer_, Cancel());
   ShowAndVerifyUi();
 }
 
@@ -185,7 +171,7 @@
   view_->OnInstallationEnded(InstallationResult::kSuccess);
   ExpectInstallationCompletedSucessfully();
 
-  EXPECT_CALL(*mock_context_manager_, StartBorealis(_));
+  EXPECT_CALL(mock_context_manager_, StartBorealis(_));
   EXPECT_CALL(*mock_installer_, RemoveObserver(_));
   view_->AcceptDialog();
 
@@ -227,7 +213,7 @@
   view_->OnInstallationEnded(InstallationResult::kSuccess);
   ExpectInstallationCompletedSucessfully();
 
-  EXPECT_CALL(*mock_context_manager_, StartBorealis(_));
+  EXPECT_CALL(mock_context_manager_, StartBorealis(_));
   EXPECT_CALL(*mock_installer_, RemoveObserver(_));
   view_->AcceptDialog();
 
diff --git a/chrome/browser/ui/webui/chromeos/login/signin_screen_handler.cc b/chrome/browser/ui/webui/chromeos/login/signin_screen_handler.cc
index bcd9e6e8..bbed7a575e 100644
--- a/chrome/browser/ui/webui/chromeos/login/signin_screen_handler.cc
+++ b/chrome/browser/ui/webui/chromeos/login/signin_screen_handler.cc
@@ -918,7 +918,7 @@
   network_state_ignored_until_proxy_auth_ = false;
 }
 
-void SigninScreenHandler::SuspendDone(const base::TimeDelta& sleep_duration) {
+void SigninScreenHandler::SuspendDone(base::TimeDelta sleep_duration) {
   for (user_manager::User* user :
        user_manager::UserManager::Get()->GetUnlockUsers()) {
     UpdatePinKeyboardState(user->GetAccountId());
diff --git a/chrome/browser/ui/webui/chromeos/login/signin_screen_handler.h b/chrome/browser/ui/webui/chromeos/login/signin_screen_handler.h
index b133e444..06141b2 100644
--- a/chrome/browser/ui/webui/chromeos/login/signin_screen_handler.h
+++ b/chrome/browser/ui/webui/chromeos/login/signin_screen_handler.h
@@ -240,7 +240,7 @@
                const content::NotificationDetails& details) override;
 
   // PowerManagerClient::Observer implementation:
-  void SuspendDone(const base::TimeDelta& sleep_duration) override;
+  void SuspendDone(base::TimeDelta sleep_duration) override;
 
   // ash::TabletModeObserver:
   void OnTabletModeStarted() override;
diff --git a/chrome/browser/ui/webui/settings/chromeos/device_power_handler.cc b/chrome/browser/ui/webui/settings/chromeos/device_power_handler.cc
index 15ffd97..81b86d4 100644
--- a/chrome/browser/ui/webui/settings/chromeos/device_power_handler.cc
+++ b/chrome/browser/ui/webui/settings/chromeos/device_power_handler.cc
@@ -202,7 +202,7 @@
 }
 
 void PowerHandler::LidEventReceived(PowerManagerClient::LidState state,
-                                    const base::TimeTicks& timestamp) {
+                                    base::TimeTicks timestamp) {
   lid_state_ = state;
   SendPowerManagementSettings(false /* force */);
 }
diff --git a/chrome/browser/ui/webui/settings/chromeos/device_power_handler.h b/chrome/browser/ui/webui/settings/chromeos/device_power_handler.h
index 71db52e..2f8b60f 100644
--- a/chrome/browser/ui/webui/settings/chromeos/device_power_handler.h
+++ b/chrome/browser/ui/webui/settings/chromeos/device_power_handler.h
@@ -85,7 +85,7 @@
   void PowerChanged(const power_manager::PowerSupplyProperties& proto) override;
   void PowerManagerRestarted() override;
   void LidEventReceived(PowerManagerClient::LidState state,
-                        const base::TimeTicks& timestamp) override;
+                        base::TimeTicks timestamp) override;
 
  private:
   enum class PowerSource { kAc, kBattery };
diff --git a/chrome/browser/ui/webui/signin/profile_customization_handler.cc b/chrome/browser/ui/webui/signin/profile_customization_handler.cc
index fdd23f9..0da1eb7 100644
--- a/chrome/browser/ui/webui/signin/profile_customization_handler.cc
+++ b/chrome/browser/ui/webui/signin/profile_customization_handler.cc
@@ -18,6 +18,7 @@
 #include "chrome/browser/profiles/profile_avatar_icon_util.h"
 #include "chrome/browser/profiles/profile_manager.h"
 #include "chrome/browser/ui/signin/profile_colors_util.h"
+#include "components/signin/public/identity_manager/account_info.h"
 #include "content/public/browser/web_contents.h"
 #include "content/public/browser/web_ui.h"
 #include "ui/base/webui/web_ui_util.h"
@@ -46,34 +47,32 @@
 }
 
 void ProfileCustomizationHandler::OnJavascriptAllowed() {
-  observed_profile_.Add(
+  observed_profile_.Observe(
       &g_browser_process->profile_manager()->GetProfileAttributesStorage());
 }
 
 void ProfileCustomizationHandler::OnJavascriptDisallowed() {
-  observed_profile_.RemoveAll();
+  observed_profile_.Reset();
 }
 
 void ProfileCustomizationHandler::OnProfileAvatarChanged(
     const base::FilePath& profile_path) {
-  if (profile_path != profile_path_)
-    return;
-  UpdateProfileInfo();
+  UpdateProfileInfo(profile_path);
 }
 
 void ProfileCustomizationHandler::OnProfileHighResAvatarLoaded(
     const base::FilePath& profile_path) {
-  if (profile_path != profile_path_)
-    return;
-  UpdateProfileInfo();
+  UpdateProfileInfo(profile_path);
 }
 
 void ProfileCustomizationHandler::OnProfileThemeColorsChanged(
     const base::FilePath& profile_path) {
-  DCHECK(IsJavascriptAllowed());
-  if (profile_path != profile_path_)
-    return;
-  UpdateProfileInfo();
+  UpdateProfileInfo(profile_path);
+}
+
+void ProfileCustomizationHandler::OnProfileHostedDomainChanged(
+    const base::FilePath& profile_path) {
+  UpdateProfileInfo(profile_path);
 }
 
 void ProfileCustomizationHandler::HandleInitialized(
@@ -97,8 +96,11 @@
     std::move(done_closure_).Run();
 }
 
-void ProfileCustomizationHandler::UpdateProfileInfo() {
+void ProfileCustomizationHandler::UpdateProfileInfo(
+    const base::FilePath& profile_path) {
   DCHECK(IsJavascriptAllowed());
+  if (profile_path != profile_path_)
+    return;
   FireWebUIListener("on-profile-info-changed", GetProfileInfoValue());
 }
 
@@ -106,6 +108,9 @@
   ProfileAttributesEntry* entry = GetProfileEntry();
   SkColor profile_color =
       entry->GetProfileThemeColors().profile_highlight_color;
+  std::string hosted_domain = entry->GetHostedDomain();
+  bool is_managed =
+      !hosted_domain.empty() && hosted_domain != kNoHostedDomainFound;
 
   base::Value dict(base::Value::Type::DICTIONARY);
   dict.SetStringKey("textColor",
@@ -119,6 +124,7 @@
       profiles::GetSizedAvatarIcon(entry->GetAvatarIcon(avatar_icon_size), true,
                                    avatar_icon_size, avatar_icon_size);
   dict.SetStringKey("pictureUrl", webui::GetBitmapDataUrl(icon.AsBitmap()));
+  dict.SetBoolKey("isManaged", is_managed);
   return dict;
 }
 
diff --git a/chrome/browser/ui/webui/signin/profile_customization_handler.h b/chrome/browser/ui/webui/signin/profile_customization_handler.h
index b9cb5d9..f505cdb 100644
--- a/chrome/browser/ui/webui/signin/profile_customization_handler.h
+++ b/chrome/browser/ui/webui/signin/profile_customization_handler.h
@@ -9,7 +9,7 @@
 
 #include "base/callback.h"
 #include "base/files/file_path.h"
-#include "base/scoped_observer.h"
+#include "base/scoped_observation.h"
 #include "chrome/browser/profiles/profile_attributes_storage.h"
 
 namespace base {
@@ -39,6 +39,8 @@
   void OnProfileHighResAvatarLoaded(
       const base::FilePath& profile_path) override;
   void OnProfileThemeColorsChanged(const base::FilePath& profile_path) override;
+  void OnProfileHostedDomainChanged(
+      const base::FilePath& profile_path) override;
 
  private:
   // Handlers for messages from javascript.
@@ -46,7 +48,9 @@
   void HandleDone(const base::ListValue* args);
 
   // Sends an updated profile info (avatar and colors) to the WebUI.
-  void UpdateProfileInfo();
+  // `profile_path` is the path of the profile being updated, this function does
+  // nothing if the profile path does not match the current profile.
+  void UpdateProfileInfo(const base::FilePath& profile_path);
 
   // Computes the profile info (avatar and colors) to be sent to the WebUI.
   base::Value GetProfileInfoValue();
@@ -55,7 +59,8 @@
   ProfileAttributesEntry* GetProfileEntry() const;
 
   base::FilePath profile_path_;
-  ScopedObserver<ProfileAttributesStorage, ProfileAttributesStorage::Observer>
+  base::ScopedObservation<ProfileAttributesStorage,
+                          ProfileAttributesStorage::Observer>
       observed_profile_{this};
 
   // Called when the "Done" button has been pressed.
diff --git a/chrome/browser/ui/webui/signin/profile_customization_ui.cc b/chrome/browser/ui/webui/signin/profile_customization_ui.cc
index f4e11e5..e6ca1bb 100644
--- a/chrome/browser/ui/webui/signin/profile_customization_ui.cc
+++ b/chrome/browser/ui/webui/signin/profile_customization_ui.cc
@@ -62,9 +62,6 @@
       .GetProfileAttributesWithPath(profile->GetPath(), &entry);
   source->AddString("profileName",
                     base::UTF16ToUTF8(entry->GetLocalProfileName()));
-  source->AddBoolean("isManaged",
-                     !entry->GetHostedDomain().empty() &&
-                         entry->GetHostedDomain() != kNoHostedDomainFound);
 
   // Resources for testing.
   source->OverrideContentSecurityPolicy(
diff --git a/chrome/browser/web_applications/external_web_app_manager.cc b/chrome/browser/web_applications/external_web_app_manager.cc
index 2c1a405..a33e4bc2 100644
--- a/chrome/browser/web_applications/external_web_app_manager.cc
+++ b/chrome/browser/web_applications/external_web_app_manager.cc
@@ -65,6 +65,7 @@
 #endif
 
 bool g_skip_startup_for_testing_ = false;
+bool g_bypass_offline_manifest_requirement_for_testing_ = false;
 const base::FilePath* g_config_dir_for_testing = nullptr;
 const std::vector<base::Value>* g_configs_for_testing = nullptr;
 const FileUtilsWrapper* g_file_utils_for_testing = nullptr;
@@ -232,6 +233,10 @@
   g_skip_startup_for_testing_ = true;
 }
 
+void ExternalWebAppManager::BypassOfflineManifestRequirementForTesting() {
+  g_bypass_offline_manifest_requirement_for_testing_ = true;
+}
+
 void ExternalWebAppManager::SetConfigDirForTesting(
     const base::FilePath* config_dir) {
   g_config_dir_for_testing = config_dir;
@@ -332,6 +337,29 @@
   for (ExternalInstallOptions& options : GetPreinstalledWebApps())
     parsed_configs.options_list.push_back(std::move(options));
 
+  // Set common install options.
+  for (ExternalInstallOptions& options : parsed_configs.options_list) {
+    ALLOW_UNUSED_LOCAL(options);
+    DCHECK_EQ(options.install_source, ExternalInstallSource::kExternalDefault);
+
+#if !BUILDFLAG(IS_CHROMEOS_ASH)
+    if (!g_bypass_offline_manifest_requirement_for_testing_) {
+      // Non-Chrome OS platforms are not permitted to fetch the web app install
+      // URLs during start up.
+      DCHECK(options.app_info_factory);
+      options.only_use_app_info_factory = true;
+    }
+
+    // Preinstalled web apps should not have OS shortcuts of any kind outside of
+    // Chrome OS.
+    options.add_to_applications_menu = false;
+    options.add_to_search = false;
+    options.add_to_management = false;
+    options.add_to_desktop = false;
+    options.add_to_quick_launch_bar = false;
+#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
+  }
+
   bool is_new_user = IsNewUser();
   std::string user_type = apps::DetermineUserType(profile_);
   size_t disabled_count = 0;
diff --git a/chrome/browser/web_applications/external_web_app_manager.h b/chrome/browser/web_applications/external_web_app_manager.h
index eee4efaa..f124c96 100644
--- a/chrome/browser/web_applications/external_web_app_manager.h
+++ b/chrome/browser/web_applications/external_web_app_manager.h
@@ -56,6 +56,7 @@
   static void RegisterProfilePrefs(user_prefs::PrefRegistrySyncable* registry);
 
   static void SkipStartupForTesting();
+  static void BypassOfflineManifestRequirementForTesting();
   static void SetConfigDirForTesting(const base::FilePath* config_dir);
   static void SetConfigsForTesting(const std::vector<base::Value>* configs);
   static void SetFileUtilsForTesting(const FileUtilsWrapper* file_utils);
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 6188a22..f6c6428 100644
--- a/chrome/browser/web_applications/external_web_app_manager_browsertest.cc
+++ b/chrome/browser/web_applications/external_web_app_manager_browsertest.cc
@@ -14,11 +14,11 @@
 #include "chrome/browser/extensions/extension_browsertest.h"
 #include "chrome/browser/ui/web_applications/test/web_app_browsertest_util.h"
 #include "chrome/browser/web_applications/components/external_app_install_features.h"
-#include "chrome/browser/web_applications/components/os_integration_manager.h"
 #include "chrome/browser/web_applications/components/web_app_helpers.h"
 #include "chrome/browser/web_applications/components/web_app_id_constants.h"
 #include "chrome/browser/web_applications/preinstalled_web_apps/preinstalled_web_apps.h"
 #include "chrome/browser/web_applications/test/test_file_utils.h"
+#include "chrome/browser/web_applications/test/test_os_integration_manager.h"
 #include "chrome/browser/web_applications/web_app_provider.h"
 #include "chrome/test/base/in_process_browser_test.h"
 #include "content/public/test/browser_test.h"
@@ -38,12 +38,15 @@
  public:
   ExternalWebAppManagerBrowserTest() {
     ExternalWebAppManager::SkipStartupForTesting();
+    WebAppProvider::SetOsIntegrationManagerFactoryForTesting(
+        [](Profile* profile) -> std::unique_ptr<OsIntegrationManager> {
+          return std::make_unique<TestOsIntegrationManager>(profile, nullptr,
+                                                            nullptr, nullptr);
+        });
   }
 
   void SetUpOnMainThread() override {
     ExtensionBrowserTest::SetUpOnMainThread();
-    os_hooks_suppress_ =
-        OsIntegrationManager::ScopedSuppressOsHooksForTesting();
   }
 
   GURL GetAppUrl() const {
@@ -125,6 +128,7 @@
 
 IN_PROC_BROWSER_TEST_F(ExternalWebAppManagerBrowserTest,
                        LaunchQueryParamsBasic) {
+  ExternalWebAppManager::BypassOfflineManifestRequirementForTesting();
   ASSERT_TRUE(embedded_test_server()->Start());
 
   GURL start_url = embedded_test_server()->GetURL("/web_apps/basic.html");
@@ -156,6 +160,7 @@
 
 IN_PROC_BROWSER_TEST_F(ExternalWebAppManagerBrowserTest,
                        LaunchQueryParamsDuplicate) {
+  ExternalWebAppManager::BypassOfflineManifestRequirementForTesting();
   ASSERT_TRUE(embedded_test_server()->Start());
 
   GURL install_url = embedded_test_server()->GetURL(
@@ -190,6 +195,7 @@
 
 IN_PROC_BROWSER_TEST_F(ExternalWebAppManagerBrowserTest,
                        LaunchQueryParamsComplex) {
+  ExternalWebAppManager::BypassOfflineManifestRequirementForTesting();
   ASSERT_TRUE(embedded_test_server()->Start());
 
   GURL install_url = embedded_test_server()->GetURL(
@@ -225,6 +231,7 @@
 }
 
 IN_PROC_BROWSER_TEST_F(ExternalWebAppManagerBrowserTest, UninstallAndReplace) {
+  ExternalWebAppManager::BypassOfflineManifestRequirementForTesting();
   ASSERT_TRUE(embedded_test_server()->Start());
   Profile* profile = browser()->profile();
 
@@ -566,6 +573,20 @@
     EXPECT_EQ(provider.registrar().GetAppLaunchUrl(expectation.app_id),
               GURL(expectation.launch_url));
   }
+
+  // Note that default web apps *DO* show app icons on Chrome OS however it
+  // is done via the |WebAppsChromeOs| publishing live our current app state to
+  // the app service rather than writing shortcut files as the case on all other
+  // desktop platforms.
+  auto* test_os_integration_manager =
+      provider.os_integration_manager().AsTestOsIntegrationManager();
+  EXPECT_EQ(test_os_integration_manager->num_create_shortcuts_calls(), 0u);
+  EXPECT_EQ(test_os_integration_manager->num_create_file_handlers_calls(), 0u);
+  EXPECT_EQ(test_os_integration_manager->num_register_run_on_os_login_calls(),
+            0u);
+  EXPECT_EQ(
+      test_os_integration_manager->num_add_app_to_quick_launch_bar_calls(), 0u);
+  EXPECT_FALSE(test_os_integration_manager->did_add_to_desktop());
 }
 #endif  // BUILDFLAG(GOOGLE_CHROME_BRANDING)
 
diff --git a/chrome/browser/web_applications/external_web_app_migration_browsertest.cc b/chrome/browser/web_applications/external_web_app_migration_browsertest.cc
index d16621a..34f6545 100644
--- a/chrome/browser/web_applications/external_web_app_migration_browsertest.cc
+++ b/chrome/browser/web_applications/external_web_app_migration_browsertest.cc
@@ -63,6 +63,7 @@
  public:
   ExternalWebAppMigrationBrowserTest() {
     ExternalWebAppManager::SkipStartupForTesting();
+    ExternalWebAppManager::BypassOfflineManifestRequirementForTesting();
     disable_scope_ =
         extensions::ExtensionService::DisableExternalUpdatesForTesting();
   }
diff --git a/chrome/browser/web_applications/preinstalled_web_apps/preinstalled_web_apps.cc b/chrome/browser/web_applications/preinstalled_web_apps/preinstalled_web_apps.cc
index 1e3016bc..586d605a 100644
--- a/chrome/browser/web_applications/preinstalled_web_apps/preinstalled_web_apps.cc
+++ b/chrome/browser/web_applications/preinstalled_web_apps/preinstalled_web_apps.cc
@@ -31,7 +31,9 @@
 std::vector<ExternalInstallOptions>* g_preinstalled_app_data_for_testing =
     nullptr;
 
-std::vector<ExternalInstallOptions> GetPreinstalledAppData() {
+}  // namespace
+
+std::vector<ExternalInstallOptions> GetPreinstalledWebApps() {
   if (g_preinstalled_app_data_for_testing)
     return *g_preinstalled_app_data_for_testing;
 
@@ -63,8 +65,6 @@
   return {};
 }
 
-}  // namespace
-
 ScopedTestingPreinstalledAppData::ScopedTestingPreinstalledAppData() {
   DCHECK_EQ(nullptr, g_preinstalled_app_data_for_testing);
   g_preinstalled_app_data_for_testing = &apps;
@@ -75,30 +75,4 @@
   g_preinstalled_app_data_for_testing = nullptr;
 }
 
-std::vector<ExternalInstallOptions> GetPreinstalledWebApps() {
-  std::vector<ExternalInstallOptions> result;
-
-  for (ExternalInstallOptions& app_data : GetPreinstalledAppData()) {
-    DCHECK_EQ(app_data.install_source, ExternalInstallSource::kExternalDefault);
-
-#if !BUILDFLAG(IS_CHROMEOS_ASH)
-    // Non-Chrome OS platforms are not permitted to fetch the web app install
-    // URLs during start up.
-    DCHECK(app_data.only_use_app_info_factory);
-    DCHECK(app_data.app_info_factory);
-#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
-
-    // Preinstalled web apps should not have OS shortcuts of any kind.
-    app_data.add_to_applications_menu = false;
-    app_data.add_to_desktop = false;
-    app_data.add_to_quick_launch_bar = false;
-    app_data.add_to_search = false;
-    app_data.add_to_management = false;
-    app_data.require_manifest = true;
-    result.push_back(std::move(app_data));
-  }
-
-  return result;
-}
-
 }  // namespace web_app
diff --git a/chrome/browser/web_applications/preinstalled_web_apps/preinstalled_web_apps.h b/chrome/browser/web_applications/preinstalled_web_apps/preinstalled_web_apps.h
index b5e3638..8703109c 100644
--- a/chrome/browser/web_applications/preinstalled_web_apps/preinstalled_web_apps.h
+++ b/chrome/browser/web_applications/preinstalled_web_apps/preinstalled_web_apps.h
@@ -11,6 +11,9 @@
 
 namespace web_app {
 
+// Returns the list of web apps that should be pre-installed on new profiles.
+std::vector<ExternalInstallOptions> GetPreinstalledWebApps();
+
 // A scoped helper to provide a testing set of preinstalled app data. This will
 // replace the default set.
 struct ScopedTestingPreinstalledAppData {
@@ -24,9 +27,6 @@
   std::vector<ExternalInstallOptions> apps;
 };
 
-// Returns the list of web apps that should be pre-installed on new profiles.
-std::vector<ExternalInstallOptions> GetPreinstalledWebApps();
-
 }  // namespace web_app
 
 #endif  // CHROME_BROWSER_WEB_APPLICATIONS_PREINSTALLED_WEB_APPS_PREINSTALLED_WEB_APPS_H_
diff --git a/chrome/browser/web_applications/test/test_os_integration_manager.cc b/chrome/browser/web_applications/test/test_os_integration_manager.cc
index 483a23d..f7a4830 100644
--- a/chrome/browser/web_applications/test/test_os_integration_manager.cc
+++ b/chrome/browser/web_applications/test/test_os_integration_manager.cc
@@ -51,8 +51,10 @@
   OsHooksResults os_hooks_results{false};
   last_options_ = options;
 
-  if (options.os_hooks[OsHookType::kFileHandlers])
+  if (options.os_hooks[OsHookType::kFileHandlers]) {
+    ++num_create_file_handlers_calls_;
     os_hooks_results[OsHookType::kFileHandlers] = true;
+  }
 
   did_add_to_desktop_ = options.add_to_desktop;
 
diff --git a/chrome/browser/web_applications/test/test_os_integration_manager.h b/chrome/browser/web_applications/test/test_os_integration_manager.h
index 634553f..bada6d8 100644
--- a/chrome/browser/web_applications/test/test_os_integration_manager.h
+++ b/chrome/browser/web_applications/test/test_os_integration_manager.h
@@ -44,6 +44,10 @@
     return num_create_shortcuts_calls_;
   }
 
+  size_t num_create_file_handlers_calls() const {
+    return num_create_file_handlers_calls_;
+  }
+
   size_t num_register_run_on_os_login_calls() const {
     return num_register_run_on_os_login_calls_;
   }
@@ -76,6 +80,7 @@
 
  private:
   size_t num_create_shortcuts_calls_ = 0;
+  size_t num_create_file_handlers_calls_ = 0;
   size_t num_register_run_on_os_login_calls_ = 0;
   size_t num_add_app_to_quick_launch_bar_calls_ = 0;
   base::Optional<bool> did_add_to_desktop_;
diff --git a/chrome/browser/web_applications/web_app_provider.cc b/chrome/browser/web_applications/web_app_provider.cc
index 87103c3..14f7deb 100644
--- a/chrome/browser/web_applications/web_app_provider.cc
+++ b/chrome/browser/web_applications/web_app_provider.cc
@@ -41,6 +41,13 @@
 
 namespace web_app {
 
+namespace {
+
+WebAppProvider::OsIntegrationManagerFactory
+    g_os_integration_manager_factory_for_testing = nullptr;
+
+}  // namespace
+
 // static
 WebAppProvider* WebAppProvider::Get(Profile* profile) {
   return WebAppProviderFactory::GetForProfile(profile);
@@ -55,6 +62,12 @@
   return WebAppProvider::Get(profile);
 }
 
+// static
+void WebAppProvider::SetOsIntegrationManagerFactoryForTesting(
+    OsIntegrationManagerFactory factory) {
+  g_os_integration_manager_factory_for_testing = factory;
+}
+
 WebAppProvider::WebAppProvider(Profile* profile) : profile_(profile) {
   DCHECK(AreWebAppsEnabled(profile_));
   // WebApp System must have only one instance in original profile.
@@ -207,15 +220,20 @@
   install_finalizer_ = std::make_unique<WebAppInstallFinalizer>(
       profile, icon_manager.get(), std::move(legacy_finalizer));
 
-  auto file_handler_manager =
-      std::make_unique<WebAppFileHandlerManager>(profile);
-  auto protocol_handler_manager =
-      std::make_unique<ProtocolHandlerManager>(profile);
-  auto shortcut_manager = std::make_unique<WebAppShortcutManager>(
-      profile, icon_manager.get(), file_handler_manager.get());
-  os_integration_manager_ = std::make_unique<OsIntegrationManager>(
-      profile, std::move(shortcut_manager), std::move(file_handler_manager),
-      std::move(protocol_handler_manager));
+  if (g_os_integration_manager_factory_for_testing) {
+    os_integration_manager_ =
+        g_os_integration_manager_factory_for_testing(profile);
+  } else {
+    auto file_handler_manager =
+        std::make_unique<WebAppFileHandlerManager>(profile);
+    auto protocol_handler_manager =
+        std::make_unique<ProtocolHandlerManager>(profile);
+    auto shortcut_manager = std::make_unique<WebAppShortcutManager>(
+        profile, icon_manager.get(), file_handler_manager.get());
+    os_integration_manager_ = std::make_unique<OsIntegrationManager>(
+        profile, std::move(shortcut_manager), std::move(file_handler_manager),
+        std::move(protocol_handler_manager));
+  }
 
   migration_manager_ = std::make_unique<WebAppMigrationManager>(
       profile, database_factory_.get(), icon_manager.get(),
diff --git a/chrome/browser/web_applications/web_app_provider.h b/chrome/browser/web_applications/web_app_provider.h
index 0170c79..0cf11d73 100644
--- a/chrome/browser/web_applications/web_app_provider.h
+++ b/chrome/browser/web_applications/web_app_provider.h
@@ -60,6 +60,11 @@
   static WebAppProvider* Get(Profile* profile);
   static WebAppProvider* GetForWebContents(content::WebContents* web_contents);
 
+  using OsIntegrationManagerFactory =
+      std::unique_ptr<OsIntegrationManager> (*)(Profile*);
+  static void SetOsIntegrationManagerFactoryForTesting(
+      OsIntegrationManagerFactory factory);
+
   explicit WebAppProvider(Profile* profile);
   WebAppProvider(const WebAppProvider&) = delete;
   WebAppProvider& operator=(const WebAppProvider&) = delete;
diff --git a/chrome/build/linux.pgo.txt b/chrome/build/linux.pgo.txt
index 963ca12..eabf76e 100644
--- a/chrome/build/linux.pgo.txt
+++ b/chrome/build/linux.pgo.txt
@@ -1 +1 @@
-chrome-linux-master-1606953494-bd74c7c56f61c746e2347181ab9ffd8bac2372a6.profdata
+chrome-linux-master-1606975184-aefe3d214a47b5e57d9dcedd54737f7057f97fb8.profdata
diff --git a/chrome/build/mac.pgo.txt b/chrome/build/mac.pgo.txt
index e0244b62e..996e611 100644
--- a/chrome/build/mac.pgo.txt
+++ b/chrome/build/mac.pgo.txt
@@ -1 +1 @@
-chrome-mac-master-1606953494-1095cc05af875eadbe87fc6109d3867a4076cbf5.profdata
+chrome-mac-master-1606975184-196f68b969b73bc3452eae4d054586312080107c.profdata
diff --git a/chrome/build/win64.pgo.txt b/chrome/build/win64.pgo.txt
index 75dd4e8..5258336 100644
--- a/chrome/build/win64.pgo.txt
+++ b/chrome/build/win64.pgo.txt
@@ -1 +1 @@
-chrome-win64-master-1606942778-d5d5cc9b57e062a2c1a80c892b64ebbae55abc2c.profdata
+chrome-win64-master-1606964048-45fff1aeb7e9c3fd35f310aad8ee0c61f812a3a1.profdata
diff --git a/chrome/common/extensions/api/_manifest_features.json b/chrome/common/extensions/api/_manifest_features.json
index f796253..10b8550 100644
--- a/chrome/common/extensions/api/_manifest_features.json
+++ b/chrome/common/extensions/api/_manifest_features.json
@@ -167,7 +167,7 @@
   "minimum_chrome_version": {
     "channel": "stable",
     "extension_types": [
-      "extension", "legacy_packaged_app", "hosted_app", "platform_app"
+      "extension", "legacy_packaged_app", "hosted_app", "platform_app", "theme"
     ]
   },
   "natively_connectable": {
diff --git a/chrome/common/extensions/manifest_tests/extension_manifests_initvalue_unittest.cc b/chrome/common/extensions/manifest_tests/extension_manifests_initvalue_unittest.cc
index 22d2343a..b1fca91 100644
--- a/chrome/common/extensions/manifest_tests/extension_manifests_initvalue_unittest.cc
+++ b/chrome/common/extensions/manifest_tests/extension_manifests_initvalue_unittest.cc
@@ -156,6 +156,9 @@
     // Test a hosted app with a requirements section.
     Testcase("init_valid_app_requirements.json"),
 
+    // Test a theme with a minimum_chrome_version.
+    Testcase("init_valid_theme_minimum_chrome.json"),
+
     // Verify empty permission settings are considered valid.
     Testcase("init_valid_permissions_empty.json"),
 
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn
index 26fab11c..94497cea 100644
--- a/chrome/test/BUILD.gn
+++ b/chrome/test/BUILD.gn
@@ -2853,7 +2853,7 @@
         }
         deps += [ "//printing:test_support" ]
       }
-      if (enable_assistant_integration_tests) {
+      if (enable_cros_libassistant) {
         sources += [
           "../browser/ui/ash/assistant/assistant_browsertest.cc",
           "../browser/ui/ash/assistant/assistant_test_mixin.cc",
diff --git a/chrome/test/data/extensions/manifest_tests/init_valid_theme_minimum_chrome.json b/chrome/test/data/extensions/manifest_tests/init_valid_theme_minimum_chrome.json
new file mode 100644
index 0000000..75c74f4
--- /dev/null
+++ b/chrome/test/data/extensions/manifest_tests/init_valid_theme_minimum_chrome.json
@@ -0,0 +1,11 @@
+{
+  "name": "Minimum Version Theme",
+  "manifest_version": 2,
+  "version": "1",
+  "theme": {
+    "colors": {
+      "frame": [100, 100, 100]
+    }
+  },
+  "minimum_chrome_version": "1.0.0.1"
+}
diff --git a/chrome/test/data/policy/policy_test_cases.json b/chrome/test/data/policy/policy_test_cases.json
index 1438916..b3e2ba7 100644
--- a/chrome/test/data/policy/policy_test_cases.json
+++ b/chrome/test/data/policy/policy_test_cases.json
@@ -5907,7 +5907,7 @@
           ]
         },
         "prefs": {
-          "extensions.install.login_screen_extensions": {
+          "extensions.install.forcelist": {
             "value": {
               "abcdefghijklmnopabcdefghijklmnop": {
                 "external_update_url": "https://clients2.google.com/service/update2/crx"
diff --git a/chrome/test/data/webui/signin/profile_customization_test.js b/chrome/test/data/webui/signin/profile_customization_test.js
index 5b97f5ae..49eedd5 100644
--- a/chrome/test/data/webui/signin/profile_customization_test.js
+++ b/chrome/test/data/webui/signin/profile_customization_test.js
@@ -27,7 +27,6 @@
 
   setup(function() {
     loadTimeData.overrideValues({
-      isManaged: false,
       profileName: 'TestName',
     });
     browserProxy = new TestProfileCustomizationBrowserProxy();
@@ -35,6 +34,7 @@
       textColor: 'rgb(255, 0, 0)',
       backgroundColor: 'rgb(0, 255, 0)',
       pictureUrl: AVATAR_URL_1,
+      isManaged: false,
     });
     ProfileCustomizationBrowserProxyImpl.instance_ = browserProxy;
     document.body.innerHTML = '';
@@ -100,15 +100,20 @@
     assertEquals('rgb(255, 0, 0)', getComputedStyle(header).color);
     assertEquals('rgb(0, 255, 0)', getComputedStyle(header).backgroundColor);
     checkImageUrl('#avatar', AVATAR_URL_1);
+    assertFalse(isChildVisible(app, '#badge'));
     // Update the info.
     const color1 = 'rgb(1, 2, 3)';
     const color2 = 'rgb(4, 5, 6)';
-    webUIListenerCallback(
-        'on-profile-info-changed',
-        {textColor: color1, backgroundColor: color2, pictureUrl: AVATAR_URL_2});
+    webUIListenerCallback('on-profile-info-changed', {
+      textColor: color1,
+      backgroundColor: color2,
+      pictureUrl: AVATAR_URL_2,
+      isManaged: true,
+    });
     assertEquals(color1, getComputedStyle(header).color);
     assertEquals(color2, getComputedStyle(header).backgroundColor);
     checkImageUrl('#avatar', AVATAR_URL_2);
+    assertTrue(isChildVisible(app, '#badge'));
   });
 
   test('ThemeSelector', function() {
diff --git a/chrome/test/data/webui/signin/test_profile_customization_browser_proxy.js b/chrome/test/data/webui/signin/test_profile_customization_browser_proxy.js
index 3659a5e4..8d87555 100644
--- a/chrome/test/data/webui/signin/test_profile_customization_browser_proxy.js
+++ b/chrome/test/data/webui/signin/test_profile_customization_browser_proxy.js
@@ -15,6 +15,7 @@
       textColor: '',
       backgroundColor: '',
       pictureUrl: '',
+      isManaged: false,
     };
   }
 
diff --git a/chrome/test/views/accessibility_checker.cc b/chrome/test/views/accessibility_checker.cc
index d5b1d55..486e3f5 100644
--- a/chrome/test/views/accessibility_checker.cc
+++ b/chrome/test/views/accessibility_checker.cc
@@ -78,6 +78,8 @@
           "\n- Focusable View has no accessible name or placeholder, and the "
           "name attribute does not use kAttributeExplicitlyEmpty.";
     }
+    if (node_data.HasState(State::kIgnored))
+      violations += "\n- Focusable View should not be ignored.";
     if (node_data.HasState(State::kInvisible))
       violations += "\n- Focusable View should not be invisible.";
   }
diff --git a/chromeos/assistant/assistant.gni b/chromeos/assistant/assistant.gni
index c28a144..447b34e 100644
--- a/chromeos/assistant/assistant.gni
+++ b/chromeos/assistant/assistant.gni
@@ -12,6 +12,8 @@
 }
 
 declare_args() {
+  # TODO(b/170170824): This flag is dead and should be removed when it is no
+  # longer set in the ChromeOS build.
   # Enable Assistant integration tests using LibAssistant and a fake S3 server.
   # This requires libassistant.so to support grpc communication with the S3
   # server, which increases the library size, which is why we introduced this
diff --git a/chromeos/components/camera_app_ui/resources/js/models/barcode.js b/chromeos/components/camera_app_ui/resources/js/models/barcode.js
index 96983f1..5d2eeba 100644
--- a/chromeos/components/camera_app_ui/resources/js/models/barcode.js
+++ b/chromeos/components/camera_app_ui/resources/js/models/barcode.js
@@ -9,8 +9,8 @@
 // eslint-disable-next-line no-unused-vars
 import {BarcodeWorkerInterface} from './barcode_worker_interface.js';
 
-// TODO(b/172879638): Get some performance data and tune the scan interval.
-const SCAN_INTERVAL = 1000;
+// The delay interval bewteen consecutive barcode detections.
+const SCAN_INTERVAL = 200;
 
 // If any dimension of the video exceeds this size, the image would be cropped
 // and/or scaled before scanning to speed up the detection.
diff --git a/chromeos/components/camera_app_ui/resources/js/util.js b/chromeos/components/camera_app_ui/resources/js/util.js
index cdc7008..379875c5 100644
--- a/chromeos/components/camera_app_ui/resources/js/util.js
+++ b/chromeos/components/camera_app_ui/resources/js/util.js
@@ -56,7 +56,7 @@
  *     cancelled.
  */
 function waitAnimationCompleted(element) {
-  return new Promise((resolve, reject) => {
+  return new Promise((resolve) => {
     let animationCount = 0;
     const onStart = (event) =>
         void (event.target === element && animationCount++);
@@ -150,8 +150,8 @@
 
 /**
  * Sets up i18n messages on DOM subtree by i18n attributes.
- * @param {!Node} rootElement Root of DOM subtree to be set up
- *     with.
+ * @param {!Element|!DocumentFragment} rootElement Root of DOM subtree to be set
+ *     up with.
  */
 export function setupI18nElements(rootElement) {
   const getElements = (attr) => rootElement.querySelectorAll('[' + attr + ']');
@@ -319,13 +319,14 @@
 /**
  * Instantiates template with the target selector.
  * @param {string} selector
- * @return {!Node}
+ * @return {!DocumentFragment}
  */
 export function instantiateTemplate(selector) {
   const tpl = dom.get(selector, HTMLTemplateElement);
-  const node = document.importNode(tpl.content, true);
-  setupI18nElements(node);
-  return node;
+  const doc = assertInstanceof(
+      document.importNode(tpl.content, true), DocumentFragment);
+  setupI18nElements(doc);
+  return doc;
 }
 
 /**
diff --git a/chromeos/components/camera_app_ui/resources/js/views/camera/preview.js b/chromeos/components/camera_app_ui/resources/js/views/camera/preview.js
index 00c988d4..b7ef0c3 100644
--- a/chromeos/components/camera_app_ui/resources/js/views/camera/preview.js
+++ b/chromeos/components/camera_app_ui/resources/js/views/camera/preview.js
@@ -121,8 +121,8 @@
    * @return {!Promise} Promise for the operation.
    */
   async setSource_(stream) {
-    const node = util.instantiateTemplate('#preview-video-template');
-    const video = dom.getFrom(node, 'video', HTMLVideoElement);
+    const tpl = util.instantiateTemplate('#preview-video-template');
+    const video = dom.getFrom(tpl, 'video', HTMLVideoElement);
     await new Promise((resolve) => {
       const handler = () => {
         video.removeEventListener('canplay', handler);
@@ -132,7 +132,7 @@
       video.srcObject = stream;
     });
     await video.play();
-    this.video_.parentElement.replaceChild(node, this.video_);
+    this.video_.parentElement.replaceChild(tpl, this.video_);
     this.video_.removeAttribute('srcObject');
     this.video_.load();
     this.video_ = video;
diff --git a/chromeos/components/camera_app_ui/resources/js/views/settings.js b/chromeos/components/camera_app_ui/resources/js/views/settings.js
index 7d91039..5b9b515 100644
--- a/chromeos/components/camera_app_ui/resources/js/views/settings.js
+++ b/chromeos/components/camera_app_ui/resources/js/views/settings.js
@@ -653,7 +653,7 @@
       }
       input.disabled = state.get(state.State.CAMERA_CONFIGURING) ||
           state.get(state.State.TAKING);
-      input.addEventListener('change', (event) => {
+      input.addEventListener('change', () => {
         if (input.checked) {
           captionText.textContent = optTextTempl(r, resolutions);
           onChange(r);
diff --git a/chromeos/components/local_search_service/index.cc b/chromeos/components/local_search_service/index.cc
index d13a22f4..6fd1631 100644
--- a/chromeos/components/local_search_service/index.cc
+++ b/chromeos/components/local_search_service/index.cc
@@ -4,12 +4,40 @@
 
 #include "chromeos/components/local_search_service/index.h"
 
+#include "base/metrics/histogram_functions.h"
 #include "base/optional.h"
 
 namespace chromeos {
 namespace local_search_service {
 
-Index::Index(IndexId index_id, Backend backend) {}
+namespace {
+
+void LogIndexIdAndBackendType(const std::string& histogram_prefix,
+                              Backend backend) {
+  base::UmaHistogramEnumeration(histogram_prefix + ".Backend", backend);
+}
+
+std::string IndexIdBasedHistogramPrefix(IndexId index_id) {
+  const std::string prefix = "LocalSearchService.";
+  switch (index_id) {
+    case IndexId::kCrosSettings:
+      return prefix + "CrosSettings";
+    case IndexId::kHelpApp:
+      return prefix + "HelpApp";
+  }
+}
+
+void OnSearchPerformedDone() {
+  // TODO(thanhdng): add a histogram to log this.
+}
+
+}  // namespace
+
+Index::Index(IndexId index_id, Backend backend) : index_id_(index_id) {
+  histogram_prefix_ = IndexIdBasedHistogramPrefix(index_id);
+  DCHECK(!histogram_prefix_.empty());
+  LogIndexIdAndBackendType(histogram_prefix_, backend);
+}
 
 Index::~Index() = default;
 
@@ -17,5 +45,34 @@
   receivers_.Add(this, std::move(receiver));
 }
 
+void Index::SetReporterRemote(
+    mojo::PendingRemote<mojom::SearchMetricsReporter> reporter_remote) {
+  DCHECK(!reporter_remote_.is_bound());
+  reporter_remote_.Bind(std::move(reporter_remote));
+}
+
+void Index::MaybeLogSearchResultsStats(ResponseStatus status,
+                                       size_t num_results,
+                                       base::TimeDelta latency) {
+  if (reporter_remote_.is_bound())
+    reporter_remote_->OnSearchPerformed(index_id_,
+                                        base::BindOnce(&OnSearchPerformedDone));
+
+  base::UmaHistogramEnumeration(histogram_prefix_ + ".ResponseStatus", status);
+  if (status == ResponseStatus::kSuccess) {
+    // Only logs number of results and latency if search is a success.
+    base::UmaHistogramCounts100(histogram_prefix_ + ".NumberResults",
+                                num_results);
+    base::UmaHistogramTimes(histogram_prefix_ + ".SearchLatency", latency);
+  }
+}
+
+void Index::MaybeLogIndexSize(uint64_t index_size) {
+  if (index_size != 0u) {
+    base::UmaHistogramCounts10000(histogram_prefix_ + ".NumberDocuments",
+                                  index_size);
+  }
+}
+
 }  // namespace local_search_service
 }  // namespace chromeos
diff --git a/chromeos/components/local_search_service/index.h b/chromeos/components/local_search_service/index.h
index c4acb69e..0f8d91b 100644
--- a/chromeos/components/local_search_service/index.h
+++ b/chromeos/components/local_search_service/index.h
@@ -9,6 +9,7 @@
 
 #include "base/strings/string16.h"
 #include "chromeos/components/local_search_service/public/mojom/index.mojom.h"
+#include "chromeos/components/local_search_service/public/mojom/local_search_service.mojom.h"
 #include "mojo/public/cpp/bindings/pending_receiver.h"
 #include "mojo/public/cpp/bindings/receiver_set.h"
 
@@ -22,7 +23,25 @@
 
   void BindReceiver(mojo::PendingReceiver<mojom::Index> receiver);
 
+  // Call once to set the SearchMetricsReporter remote.
+  void SetReporterRemote(
+      mojo::PendingRemote<mojom::SearchMetricsReporter> reporter_remote);
+
+ protected:
+  // Logs daily search metrics if |reporter_remote_| is bound. Also logs
+  // other UMA metrics (number results and search latency).
+  void MaybeLogSearchResultsStats(ResponseStatus status,
+                                  size_t num_results,
+                                  base::TimeDelta latency);
+
+  // Logs number of documents in the index.
+  void MaybeLogIndexSize(uint64_t index_size);
+
+  IndexId index_id_;
+
  private:
+  std::string histogram_prefix_;
+  mojo::Remote<mojom::SearchMetricsReporter> reporter_remote_;
   mojo::ReceiverSet<mojom::Index> receivers_;
 };
 
diff --git a/chromeos/components/local_search_service/index_sync.cc b/chromeos/components/local_search_service/index_sync.cc
index d6cd06a2..b914138 100644
--- a/chromeos/components/local_search_service/index_sync.cc
+++ b/chromeos/components/local_search_service/index_sync.cc
@@ -49,9 +49,9 @@
 
 IndexSync::~IndexSync() = default;
 
-void IndexSync::MaybeLogSearchResultsStats(ResponseStatus status,
-                                           size_t num_results,
-                                           base::TimeDelta latency) {
+void IndexSync::MaybeLogSearchResultsStatsSync(ResponseStatus status,
+                                               size_t num_results,
+                                               base::TimeDelta latency) {
   if (reporter_)
     reporter_->OnSearchPerformed();
 
@@ -64,7 +64,7 @@
   }
 }
 
-void IndexSync::MaybeLogIndexSize() {
+void IndexSync::MaybeLogIndexSizeSync() {
   const uint64_t index_size = GetSizeSync();
   if (index_size != 0u) {
     base::UmaHistogramCounts10000(histogram_prefix_ + ".NumberDocuments",
diff --git a/chromeos/components/local_search_service/index_sync.h b/chromeos/components/local_search_service/index_sync.h
index ebe2d51..85934a9 100644
--- a/chromeos/components/local_search_service/index_sync.h
+++ b/chromeos/components/local_search_service/index_sync.h
@@ -61,14 +61,14 @@
   // UMA metrics (number results and search latency).
   // Each implementation of this class should call this method at the end of
   // Find.
-  void MaybeLogSearchResultsStats(ResponseStatus status,
-                                  size_t num_results,
-                                  base::TimeDelta latency);
+  void MaybeLogSearchResultsStatsSync(ResponseStatus status,
+                                      size_t num_results,
+                                      base::TimeDelta latency);
 
   // Logs number of documents in the index if the index is not empty.
   // Each implementation of this class should call this method at the end of
   // Find.
-  void MaybeLogIndexSize();
+  void MaybeLogIndexSizeSync();
 
   void SetSearchParams(const SearchParams& search_params);
   SearchParams GetSearchParamsForTesting();
diff --git a/chromeos/components/local_search_service/inverted_index_search.cc b/chromeos/components/local_search_service/inverted_index_search.cc
index e316719..71093472 100644
--- a/chromeos/components/local_search_service/inverted_index_search.cc
+++ b/chromeos/components/local_search_service/inverted_index_search.cc
@@ -145,12 +145,12 @@
   results->clear();
   if (query.empty()) {
     const ResponseStatus status = ResponseStatus::kEmptyQuery;
-    MaybeLogSearchResultsStats(status, 0u, base::TimeDelta());
+    MaybeLogSearchResultsStatsSync(status, 0u, base::TimeDelta());
     return status;
   }
   if (GetSizeSync() == 0u) {
     const ResponseStatus status = ResponseStatus::kEmptyIndex;
-    MaybeLogSearchResultsStats(status, 0u, base::TimeDelta());
+    MaybeLogSearchResultsStatsSync(status, 0u, base::TimeDelta());
     return status;
   }
 
@@ -163,7 +163,7 @@
 
   const base::TimeTicks end = base::TimeTicks::Now();
   const ResponseStatus status = ResponseStatus::kSuccess;
-  MaybeLogSearchResultsStats(status, results->size(), end - start);
+  MaybeLogSearchResultsStatsSync(status, results->size(), end - start);
   return status;
 }
 
@@ -208,12 +208,17 @@
                                uint32_t max_results,
                                FindCallback callback) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  const base::TimeTicks start = base::TimeTicks::Now();
   if (query.empty()) {
-    std::move(callback).Run(ResponseStatus::kEmptyQuery, base::nullopt);
+    const ResponseStatus status = ResponseStatus::kEmptyQuery;
+    MaybeLogSearchResultsStats(status, 0u, base::TimeDelta());
+    std::move(callback).Run(status, base::nullopt);
     return;
   }
   if (inverted_index_->NumberDocuments() == 0u) {
-    std::move(callback).Run(ResponseStatus::kEmptyIndex, base::nullopt);
+    const ResponseStatus status = ResponseStatus::kEmptyIndex;
+    MaybeLogSearchResultsStats(status, 0u, base::TimeDelta());
+    std::move(callback).Run(status, base::nullopt);
     return;
   }
 
@@ -224,7 +229,11 @@
 
   if (results.size() > max_results && max_results > 0u)
     results.resize(max_results);
-  std::move(callback).Run(ResponseStatus::kSuccess, results);
+
+  const ResponseStatus status = ResponseStatus::kSuccess;
+  const base::TimeTicks end = base::TimeTicks::Now();
+  MaybeLogSearchResultsStats(status, results.size(), end - start);
+  std::move(callback).Run(status, results);
 }
 
 void InvertedIndexSearch::ClearIndex(ClearIndexCallback callback) {
diff --git a/chromeos/components/local_search_service/linear_map_search.cc b/chromeos/components/local_search_service/linear_map_search.cc
index 1bedc6a..defc6606 100644
--- a/chromeos/components/local_search_service/linear_map_search.cc
+++ b/chromeos/components/local_search_service/linear_map_search.cc
@@ -99,7 +99,7 @@
     UpdateData(id, item.contents, &data_);
   }
 
-  MaybeLogIndexSize();
+  MaybeLogIndexSizeSync();
 }
 
 uint32_t LinearMapSearch::DeleteSync(const std::vector<std::string>& ids) {
@@ -109,7 +109,7 @@
     num_deleted += data_.erase(id);
   }
 
-  MaybeLogIndexSize();
+  MaybeLogIndexSizeSync();
   return num_deleted;
 }
 
@@ -126,13 +126,13 @@
 
   if (query.empty()) {
     const ResponseStatus status = ResponseStatus::kEmptyQuery;
-    MaybeLogSearchResultsStats(status, 0u, base::TimeDelta());
+    MaybeLogSearchResultsStatsSync(status, 0u, base::TimeDelta());
     return status;
   }
 
   if (data_.empty()) {
     const ResponseStatus status = ResponseStatus::kEmptyIndex;
-    MaybeLogSearchResultsStats(status, 0u, base::TimeDelta());
+    MaybeLogSearchResultsStatsSync(status, 0u, base::TimeDelta());
     return status;
   }
 
@@ -140,7 +140,7 @@
 
   const base::TimeTicks end = base::TimeTicks::Now();
   const ResponseStatus status = ResponseStatus::kSuccess;
-  MaybeLogSearchResultsStats(status, results->size(), end - start);
+  MaybeLogSearchResultsStatsSync(status, results->size(), end - start);
   return status;
 }
 
@@ -150,13 +150,13 @@
 
 void LinearMapSearch::AddOrUpdate(const std::vector<Data>& data,
                                   AddOrUpdateCallback callback) {
-  // TODO(thanhdng): Add logging to this function once we have the metrics
-  // reporter available.
   for (const auto& item : data) {
     const auto& id = item.id;
     DCHECK(!id.empty());
     UpdateData(id, item.contents, &data_);
   }
+
+  MaybeLogIndexSize(data_.size());
   std::move(callback).Run();
 }
 
@@ -168,6 +168,7 @@
     num_deleted += data_.erase(id);
   }
 
+  MaybeLogIndexSize(data_.size());
   std::move(callback).Run(num_deleted);
 }
 
@@ -185,24 +186,35 @@
     }
   }
 
+  MaybeLogIndexSize(data_.size());
   std::move(callback).Run(num_deleted);
 }
 
 void LinearMapSearch::Find(const base::string16& query,
                            uint32_t max_results,
                            FindCallback callback) {
+  const base::TimeTicks start = base::TimeTicks::Now();
   if (query.empty()) {
-    std::move(callback).Run(ResponseStatus::kEmptyQuery, base::nullopt);
+    const ResponseStatus status = ResponseStatus::kEmptyQuery;
+    MaybeLogSearchResultsStats(status, 0u, base::TimeDelta());
+    std::move(callback).Run(status, base::nullopt);
     return;
   }
 
   if (data_.empty()) {
-    std::move(callback).Run(ResponseStatus::kEmptyIndex, base::nullopt);
+    const ResponseStatus status = ResponseStatus::kEmptyIndex;
+    MaybeLogSearchResultsStats(status, 0u, base::TimeDelta());
+    std::move(callback).Run(status, base::nullopt);
     return;
   }
 
   std::vector<Result> results = GetSearchResults(query, max_results);
-  std::move(callback).Run(ResponseStatus::kSuccess, std::move(results));
+
+  const ResponseStatus status = ResponseStatus::kSuccess;
+  const base::TimeTicks end = base::TimeTicks::Now();
+  MaybeLogSearchResultsStats(status, results.size(), end - start);
+
+  std::move(callback).Run(status, std::move(results));
 }
 
 void LinearMapSearch::ClearIndex(ClearIndexCallback callback) {
diff --git a/chromeos/components/local_search_service/local_search_service.cc b/chromeos/components/local_search_service/local_search_service.cc
index 1669eb5..a3c1b42ddd 100644
--- a/chromeos/components/local_search_service/local_search_service.cc
+++ b/chromeos/components/local_search_service/local_search_service.cc
@@ -47,9 +47,9 @@
     return;
   }
 
-  if (reporter_remote)
-    reporter_remote_set_.Add(std::move(reporter_remote));
   it->second->BindReceiver(std::move(index_receiver));
+  if (reporter_remote)
+    it->second->SetReporterRemote(std::move(reporter_remote));
   std::move(callback).Run(base::nullopt);
 }
 
diff --git a/chromeos/components/local_search_service/local_search_service.h b/chromeos/components/local_search_service/local_search_service.h
index 74af4a96..9692746 100644
--- a/chromeos/components/local_search_service/local_search_service.h
+++ b/chromeos/components/local_search_service/local_search_service.h
@@ -31,7 +31,6 @@
 
  private:
   mojo::Receiver<mojom::LocalSearchService> receiver_;
-  mojo::RemoteSet<mojom::SearchMetricsReporter> reporter_remote_set_;
   std::map<IndexId, std::unique_ptr<Index>> indices_;
 };
 
diff --git a/chromeos/components/phonehub/feature_status_provider_impl.cc b/chromeos/components/phonehub/feature_status_provider_impl.cc
index 26e636f..ce0f53e 100644
--- a/chromeos/components/phonehub/feature_status_provider_impl.cc
+++ b/chromeos/components/phonehub/feature_status_provider_impl.cc
@@ -315,8 +315,7 @@
   UpdateStatus();
 }
 
-void FeatureStatusProviderImpl::SuspendDone(
-    const base::TimeDelta& sleep_duration) {
+void FeatureStatusProviderImpl::SuspendDone(base::TimeDelta sleep_duration) {
   PA_LOG(INFO) << "Device has stopped suspending";
   is_suspended_ = false;
   UpdateStatus();
diff --git a/chromeos/components/phonehub/feature_status_provider_impl.h b/chromeos/components/phonehub/feature_status_provider_impl.h
index 1925d6d..a639a4d 100644
--- a/chromeos/components/phonehub/feature_status_provider_impl.h
+++ b/chromeos/components/phonehub/feature_status_provider_impl.h
@@ -77,7 +77,7 @@
 
   // chromeos::PowerManagerClient::Observer:
   void SuspendImminent(power_manager::SuspendImminent::Reason reason) override;
-  void SuspendDone(const base::TimeDelta& sleep_duration) override;
+  void SuspendDone(base::TimeDelta sleep_duration) override;
 
   void RecordFeatureStatusOnLogin();
 
diff --git a/chromeos/components/power/dark_resume_controller.cc b/chromeos/components/power/dark_resume_controller.cc
index f53fea8b..11a0e30 100644
--- a/chromeos/components/power/dark_resume_controller.cc
+++ b/chromeos/components/power/dark_resume_controller.cc
@@ -54,7 +54,7 @@
           weak_ptr_factory_.GetWeakPtr()));
 }
 
-void DarkResumeController::SuspendDone(const base::TimeDelta& sleep_duration) {
+void DarkResumeController::SuspendDone(base::TimeDelta sleep_duration) {
   DVLOG(1) << __func__;
   // Clear any dark resume state when the device resumes.
   ClearDarkResumeState();
diff --git a/chromeos/components/power/dark_resume_controller.h b/chromeos/components/power/dark_resume_controller.h
index d3ff0c3..4f57a88 100644
--- a/chromeos/components/power/dark_resume_controller.h
+++ b/chromeos/components/power/dark_resume_controller.h
@@ -61,7 +61,7 @@
   // chromeos::PowerManagerClient::Observer overrides.
   void PowerManagerInitialized() override;
   void DarkSuspendImminent() override;
-  void SuspendDone(const base::TimeDelta& sleep_duration) override;
+  void SuspendDone(base::TimeDelta sleep_duration) override;
 
   // mojom::WakeLockObserver overrides.
   void OnWakeLockDeactivated(device::mojom::WakeLockType type) override;
diff --git a/chromeos/components/proximity_auth/unlock_manager_impl.cc b/chromeos/components/proximity_auth/unlock_manager_impl.cc
index bc57ca9..39b2cd6 100644
--- a/chromeos/components/proximity_auth/unlock_manager_impl.cc
+++ b/chromeos/components/proximity_auth/unlock_manager_impl.cc
@@ -441,7 +441,7 @@
   bluetooth_suspension_recovery_timer_->Stop();
 }
 
-void UnlockManagerImpl::SuspendDone(const base::TimeDelta& sleep_duration) {
+void UnlockManagerImpl::SuspendDone(base::TimeDelta sleep_duration) {
   bluetooth_suspension_recovery_timer_->Start(
       FROM_HERE, kBluetoothAdapterResumeMaxDuration,
       base::BindOnce(
diff --git a/chromeos/components/proximity_auth/unlock_manager_impl.h b/chromeos/components/proximity_auth/unlock_manager_impl.h
index 1c74312..2dc3853 100644
--- a/chromeos/components/proximity_auth/unlock_manager_impl.h
+++ b/chromeos/components/proximity_auth/unlock_manager_impl.h
@@ -97,7 +97,7 @@
 
   // chromeos::PowerManagerClient::Observer:
   void SuspendImminent(power_manager::SuspendImminent::Reason reason) override;
-  void SuspendDone(const base::TimeDelta& sleep_duration) override;
+  void SuspendDone(base::TimeDelta sleep_duration) override;
 
   // RemoteDeviceLifeCycle::Observer:
   void OnLifeCycleStateChanged(RemoteDeviceLifeCycle::State old_state,
diff --git a/chromeos/dbus/arc/arc_data_snapshotd_client.cc b/chromeos/dbus/arc/arc_data_snapshotd_client.cc
index 1b7f978..796aac1 100644
--- a/chromeos/dbus/arc/arc_data_snapshotd_client.cc
+++ b/chromeos/dbus/arc/arc_data_snapshotd_client.cc
@@ -19,9 +19,40 @@
 
 namespace {
 
-void OnVoidDBusMethod(VoidDBusMethodCallback callback,
-                      dbus::Response* response) {
-  std::move(callback).Run(response != nullptr);
+void OnBoolMethodCallback(VoidDBusMethodCallback callback,
+                          dbus::Response* response) {
+  if (!response) {
+    std::move(callback).Run(false /* success */);
+    return;
+  }
+  dbus::MessageReader reader(response);
+  bool success;
+  if (!reader.PopBool(&success)) {
+    std::move(callback).Run(false /* success */);
+    return;
+  }
+  std::move(callback).Run(success);
+}
+
+void OnLoadSnapshotMethodCallback(
+    ArcDataSnapshotdClient::LoadSnapshotMethodCallback callback,
+    dbus::Response* response) {
+  if (!response) {
+    std::move(callback).Run(false /* success */, false /* last */);
+    return;
+  }
+  dbus::MessageReader reader(response);
+  bool success;
+  if (!reader.PopBool(&success)) {
+    std::move(callback).Run(false /* success */, false /* last */);
+    return;
+  }
+  bool last;
+  if (!reader.PopBool(&last)) {
+    std::move(callback).Run(success, false /* last */);
+    return;
+  }
+  std::move(callback).Run(success, last);
 }
 
 class ArcDataSnapshotdClientImpl : public ArcDataSnapshotdClient {
@@ -39,8 +70,55 @@
         arc::data_snapshotd::kArcDataSnapshotdServiceInterface,
         arc::data_snapshotd::kGenerateKeyPairMethod);
     dbus::MessageWriter writer(&method_call);
-    proxy_->CallMethod(&method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
-                       base::BindOnce(&OnVoidDBusMethod, std::move(callback)));
+    proxy_->CallMethod(
+        &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
+        base::BindOnce(&OnBoolMethodCallback, std::move(callback)));
+  }
+
+  void ClearSnapshot(bool last, VoidDBusMethodCallback callback) override {
+    dbus::MethodCall method_call(
+        arc::data_snapshotd::kArcDataSnapshotdServiceInterface,
+        arc::data_snapshotd::kClearSnapshotMethod);
+    dbus::MessageWriter writer(&method_call);
+    writer.AppendBool(last);
+    proxy_->CallMethod(
+        &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
+        base::BindOnce(&OnBoolMethodCallback, std::move(callback)));
+  }
+
+  void TakeSnapshot(const std::string& account_id,
+                    VoidDBusMethodCallback callback) override {
+    dbus::MethodCall method_call(
+        arc::data_snapshotd::kArcDataSnapshotdServiceInterface,
+        arc::data_snapshotd::kTakeSnapshotMethod);
+    dbus::MessageWriter writer(&method_call);
+    writer.AppendString(account_id);
+    proxy_->CallMethod(
+        &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
+        base::BindOnce(&OnBoolMethodCallback, std::move(callback)));
+  }
+
+  void LoadSnapshot(const std::string& account_id,
+                    base::OnceCallback<void(bool, bool)> callback) override {
+    dbus::MethodCall method_call(
+        arc::data_snapshotd::kArcDataSnapshotdServiceInterface,
+        arc::data_snapshotd::kLoadSnapshotMethod);
+    dbus::MessageWriter writer(&method_call);
+    writer.AppendString(account_id);
+    proxy_->CallMethod(
+        &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
+        base::BindOnce(&OnLoadSnapshotMethodCallback, std::move(callback)));
+  }
+
+  void Update(int percent, VoidDBusMethodCallback callback) override {
+    dbus::MethodCall method_call(
+        arc::data_snapshotd::kArcDataSnapshotdServiceInterface,
+        arc::data_snapshotd::kUpdateMethod);
+    dbus::MessageWriter writer(&method_call);
+    writer.AppendInt32(percent);
+    proxy_->CallMethod(
+        &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
+        base::BindOnce(&OnBoolMethodCallback, std::move(callback)));
   }
 
   void WaitForServiceToBeAvailable(
diff --git a/chromeos/dbus/arc/arc_data_snapshotd_client.h b/chromeos/dbus/arc/arc_data_snapshotd_client.h
index 6eb0944..dbac03b 100644
--- a/chromeos/dbus/arc/arc_data_snapshotd_client.h
+++ b/chromeos/dbus/arc/arc_data_snapshotd_client.h
@@ -5,6 +5,9 @@
 #ifndef CHROMEOS_DBUS_ARC_ARC_DATA_SNAPSHOTD_CLIENT_H_
 #define CHROMEOS_DBUS_ARC_ARC_DATA_SNAPSHOTD_CLIENT_H_
 
+#include <string>
+
+#include "base/callback_forward.h"
 #include "base/component_export.h"
 #include "chromeos/dbus/dbus_client.h"
 #include "chromeos/dbus/dbus_method_call_status.h"
@@ -22,6 +25,8 @@
   ArcDataSnapshotdClient(const ArcDataSnapshotdClient&) = delete;
   ArcDataSnapshotdClient& operator=(const ArcDataSnapshotdClient&) = delete;
 
+  using LoadSnapshotMethodCallback = base::OnceCallback<void(bool, bool)>;
+
   // Factory function, creates a new instance and returns ownership.
   // For normal usage, access the singleton via DBusThreadManager::Get().
   static std::unique_ptr<ArcDataSnapshotdClient> Create();
@@ -30,6 +35,23 @@
   // Should be called before the user session started.
   virtual void GenerateKeyPair(VoidDBusMethodCallback callback) = 0;
 
+  // Remove a snapshot. If |last|, remove the last generated snapshot,
+  // otherwise the previous one.
+  virtual void ClearSnapshot(bool last, VoidDBusMethodCallback callback) = 0;
+
+  // Take the ARC data/ snapshot of the current session.
+  // MGS is a current active session with |account_id|.
+  virtual void TakeSnapshot(const std::string& account_id,
+                            VoidDBusMethodCallback callback) = 0;
+
+  // Load the ARC data/ snapshot to the current active MGS with |account_id|.
+  virtual void LoadSnapshot(const std::string& account_id,
+                            LoadSnapshotMethodCallback callback) = 0;
+
+  // Update a progress bar on a UI screen.
+  // |percent| is a percentage of installed required ARC apps [0..100].
+  virtual void Update(int percent, VoidDBusMethodCallback callback) = 0;
+
   // Registers |callback| to run when the arc-data-snapshotd becomes available.
   // If the service is already available, or if connecting to the name-owner-
   // changed signal fails, |callback| will be run once asynchronously.
diff --git a/chromeos/dbus/arc/fake_arc_data_snapshotd_client.cc b/chromeos/dbus/arc/fake_arc_data_snapshotd_client.cc
index 5e52128..0ce6c46 100644
--- a/chromeos/dbus/arc/fake_arc_data_snapshotd_client.cc
+++ b/chromeos/dbus/arc/fake_arc_data_snapshotd_client.cc
@@ -21,6 +21,32 @@
       FROM_HERE, base::BindOnce(std::move(callback), true));
 }
 
+void FakeArcDataSnapshotdClient::ClearSnapshot(
+    bool last,
+    VoidDBusMethodCallback callback) {
+  base::ThreadTaskRunnerHandle::Get()->PostTask(
+      FROM_HERE, base::BindOnce(std::move(callback), true));
+}
+
+void FakeArcDataSnapshotdClient::TakeSnapshot(const std::string& account_id,
+                                              VoidDBusMethodCallback callback) {
+  base::ThreadTaskRunnerHandle::Get()->PostTask(
+      FROM_HERE, base::BindOnce(std::move(callback), true));
+}
+
+void FakeArcDataSnapshotdClient::LoadSnapshot(
+    const std::string& account_id,
+    LoadSnapshotMethodCallback callback) {
+  base::ThreadTaskRunnerHandle::Get()->PostTask(
+      FROM_HERE, base::BindOnce(std::move(callback), true, true));
+}
+
+void FakeArcDataSnapshotdClient::Update(int percent,
+                                        VoidDBusMethodCallback callback) {
+  base::ThreadTaskRunnerHandle::Get()->PostTask(
+      FROM_HERE, base::BindOnce(std::move(callback), true));
+}
+
 void FakeArcDataSnapshotdClient::WaitForServiceToBeAvailable(
     dbus::ObjectProxy::WaitForServiceToBeAvailableCallback callback) {
   base::ThreadTaskRunnerHandle::Get()->PostTask(
diff --git a/chromeos/dbus/arc/fake_arc_data_snapshotd_client.h b/chromeos/dbus/arc/fake_arc_data_snapshotd_client.h
index 5d1fa97..f189b1c 100644
--- a/chromeos/dbus/arc/fake_arc_data_snapshotd_client.h
+++ b/chromeos/dbus/arc/fake_arc_data_snapshotd_client.h
@@ -5,6 +5,8 @@
 #ifndef CHROMEOS_DBUS_ARC_FAKE_ARC_DATA_SNAPSHOTD_CLIENT_H_
 #define CHROMEOS_DBUS_ARC_FAKE_ARC_DATA_SNAPSHOTD_CLIENT_H_
 
+#include <string>
+
 #include "chromeos/dbus/arc/arc_data_snapshotd_client.h"
 
 namespace chromeos {
@@ -26,6 +28,16 @@
   // ArcDataSnapshotdClient override:
   void GenerateKeyPair(VoidDBusMethodCallback callback) override;
 
+  void ClearSnapshot(bool last, VoidDBusMethodCallback callback) override;
+
+  void TakeSnapshot(const std::string& account_id,
+                    VoidDBusMethodCallback callback) override;
+
+  void LoadSnapshot(const std::string& account_id,
+                    LoadSnapshotMethodCallback callback) override;
+
+  void Update(int percent, VoidDBusMethodCallback callback) override;
+
   void WaitForServiceToBeAvailable(
       dbus::ObjectProxy::WaitForServiceToBeAvailableCallback callback) override;
 
diff --git a/chromeos/dbus/power/power_manager_client.h b/chromeos/dbus/power/power_manager_client.h
index 70225cf..c2db49a 100644
--- a/chromeos/dbus/power/power_manager_client.h
+++ b/chromeos/dbus/power/power_manager_client.h
@@ -128,7 +128,7 @@
     // Called when a suspend attempt (previously announced via
     // SuspendImminent()) has completed. The system may not have actually
     // suspended (if e.g. the user canceled the suspend attempt).
-    virtual void SuspendDone(const base::TimeDelta& sleep_duration) {}
+    virtual void SuspendDone(base::TimeDelta sleep_duration) {}
 
     // Called when the system is about to resuspend from a dark resume.  Like
     // SuspendImminent(), the suspend will be deferred until all observers have
@@ -146,22 +146,20 @@
 
     // Called when the power button is pressed or released.
     virtual void PowerButtonEventReceived(bool down,
-                                          const base::TimeTicks& timestamp) {}
+                                          base::TimeTicks timestamp) {}
 
     // Called when the device's lid is opened or closed. LidState::NOT_PRESENT
     // is never passed.
-    virtual void LidEventReceived(LidState state,
-                                  const base::TimeTicks& timestamp) {}
+    virtual void LidEventReceived(LidState state, base::TimeTicks timestamp) {}
 
     // Called when the device's tablet mode switch is on or off.
     // TabletMode::UNSUPPORTED is never passed.
     virtual void TabletModeEventReceived(TabletMode mode,
-                                         const base::TimeTicks& timestamp) {}
+                                         base::TimeTicks timestamp) {}
 
     // Called when the idle action will be performed after
     // |time_until_idle_action|.
-    virtual void IdleActionImminent(
-        const base::TimeDelta& time_until_idle_action) {}
+    virtual void IdleActionImminent(base::TimeDelta time_until_idle_action) {}
 
     // Called after IdleActionImminent() when the inactivity timer is reset
     // before the idle action has been performed.
diff --git a/chromeos/dbus/power/power_manager_client_unittest.cc b/chromeos/dbus/power/power_manager_client_unittest.cc
index 2ab77da..232a90ee 100644
--- a/chromeos/dbus/power/power_manager_client_unittest.cc
+++ b/chromeos/dbus/power/power_manager_client_unittest.cc
@@ -129,7 +129,7 @@
     if (run_unblock_suspend_immediately_)
       CHECK(UnblockSuspend());
   }
-  void SuspendDone(const base::TimeDelta& sleep_duration) override {
+  void SuspendDone(base::TimeDelta sleep_duration) override {
     num_suspend_done_++;
   }
   void DarkSuspendImminent() override {
diff --git a/chromeos/disks/suspend_unmount_manager.cc b/chromeos/disks/suspend_unmount_manager.cc
index cb3b5bb..88357c9d 100644
--- a/chromeos/disks/suspend_unmount_manager.cc
+++ b/chromeos/disks/suspend_unmount_manager.cc
@@ -55,7 +55,7 @@
   }
 }
 
-void SuspendUnmountManager::SuspendDone(const base::TimeDelta& sleep_duration) {
+void SuspendUnmountManager::SuspendDone(base::TimeDelta sleep_duration) {
   // SuspendDone can be called before OnUnmountComplete when suspend is
   // cancelled, or it takes long time to unmount volumes.
   unmounting_paths_.clear();
diff --git a/chromeos/disks/suspend_unmount_manager.h b/chromeos/disks/suspend_unmount_manager.h
index 155cb7a..f721361 100644
--- a/chromeos/disks/suspend_unmount_manager.h
+++ b/chromeos/disks/suspend_unmount_manager.h
@@ -33,7 +33,7 @@
 
   // PowerManagerClient::Observer
   void SuspendImminent(power_manager::SuspendImminent::Reason reason) override;
-  void SuspendDone(const base::TimeDelta& sleep_duration) override;
+  void SuspendDone(base::TimeDelta sleep_duration) override;
 
   // Callback passed to DiskMountManager holds weak pointers of this.
   DiskMountManager* const disk_mount_manager_;
diff --git a/chromeos/ime/gen_input_methods.py b/chromeos/ime/gen_input_methods.py
index dec940c1..94e781a 100755
--- a/chromeos/ime/gen_input_methods.py
+++ b/chromeos/ime/gen_input_methods.py
@@ -5,10 +5,10 @@
 
 """Generate a C++ header from input_methods.txt.
 
-This program generates a C++ header file containing the information on
-available input methods.  It parses input_methods.txt, and then generates a
-static array definition from the information extracted. The input and output
-file names are specified on the command line.
+This program generates a C++ header file containing the information on login XKB
+layout IDs. It parses input_methods.txt, and then generates a static array
+definition from the information extracted. The input and output file names are
+specified on the command line.
 
 Run it like:
   gen_input_methods.py input_methods.txt input_methods.h
@@ -23,18 +23,15 @@
 namespace input_method {
 
 struct InputMethodsInfo {
-  const char* input_method_id;
-  const char* language_code;
   const char* xkb_layout_id;
-  const char* indicator;
   bool is_login_keyboard;
 };
 const InputMethodsInfo kInputMethods[] = {
-  {"xkb:us::eng", "en-US", "us", "US", true},
-  {"xkb:us:dvorak:eng", "en-US", "us(dvorak)", "DV", true},
-  {"xkb:be::fra", "fr", "be", "BE", true},
-  {"xkb:br::por", "pt-BR", "br", "BR", true},
-  {"xkb:ru::rus", "ru", "ru", "RU", false},
+  {"us", true},
+  {"us(dvorak)", true},
+  {"be", true},
+  {"br", true},
+  {"ru", false},
 };
 
 }  // namespace input_method
@@ -56,17 +53,12 @@
 namespace input_method {
 
 struct InputMethodsInfo {
-  const char* input_method_id;
-  const char* language_code;
   const char* xkb_layout_id;
-  const char* indicator;
   bool is_login_keyboard;
 };
 const InputMethodsInfo kInputMethods[] = {
 """
-ENGINE_FORMAT = ('  {"%(input_method_id)s", "%(language_code)s", ' +
-                 '"%(xkb_layout_id)s", "%(indicator)s", ' +
-                 '%(is_login_keyboard)s},\n')
+ENGINE_FORMAT = ('  {"%(xkb_layout_id)s", %(is_login_keyboard)s},\n')
 OUTPUT_FOOTER = """
 };
 
@@ -105,10 +97,7 @@
     columns = line.split()
     assert len(columns) == 4 or len(columns) == 5, "Invalid format: " + line
     engine = {}
-    engine['input_method_id'] = columns[0]
     engine['xkb_layout_id'] = columns[1]
-    engine['language_code'] = columns[2]
-    engine['indicator'] = columns[3]
     is_login_keyboard = "false"
     if len(columns) == 5:
       assert columns[4] == "login", "Invalid attribute: " + columns[4]
diff --git a/chromeos/ime/input_methods.txt b/chromeos/ime/input_methods.txt
index 81801f95..098cd34 100644
--- a/chromeos/ime/input_methods.txt
+++ b/chromeos/ime/input_methods.txt
@@ -1,34 +1,27 @@
-# The list of keyboard layouts that we support. The keyboard layout metadata is
-# also defined here.
+# WARNING: This is a deprecated config file. This file no longer contains
+# canonical configs for input methods or keyboard layouts on CrOS. The only
+# piece of info deduced from this file and used by CrOS is an allowlist of XKB
+# layout IDs for login and lock screens. See below for details.
 #
 # Each non-comment line contains the following tab-or-space-separated columns.
-#
-# 1) The input method ID used by Chrome. (ex. "xkb:ca::fra") You should *NEVER*
-#    change the ID since the ID might be written in user's ~/Preferences. For
-#    example, three-letter ISO 639-2/B codes are used for IDs start with "xkb:"
-#    for histrical reason, but we should not replace them with two-letter 639-1
-#    codes that are currently in use in the 3rd column.
+# 1) Deprecated. Data in this column are no longer read by Chrome-on-CrOS.
 # 2) The keyboard layout ID used by XKB. (ex. "us", "us(dvorak)", "ca",
-#    "handwriting-vk,jp"). See also: /usr/share/X11/xkb/symbols.
-# 3) The language code (ex. "fr"). Only one format, ISO 639-1 compliant two-
-#    letter language code which can be recognized by ICU, is allowed. Do not use
-#    three-letter ones (ISO 639-2/T and 639-2/B) here. For "en", "pt", and "zh",
-#    two-letter upper-case country code should be added (ex. "en-US", "zh-TW").
-#    See http://en.wikipedia.org/wiki/List_of_ISO_639-1_codes for details.
-#    We can specify multiple language code with comma separator.
-# 4) The indicator string (ex. INTL for xkb:us:intl:eng). This string will be
-#    shown in system tray or indicator window.
-# 5) The additional attibution.
-#    login: Specified keyboard layout will be used on login screen or lock
-#    screen.
+#    "handwriting-vk,jp"). See also: /usr/share/X11/xkb/symbols. Whether data
+#    in this column are read by Chrome-on-CrOS depends on data in column 5.
+# 3) Deprecated. Data in this column are no longer read by Chrome-on-CrOS.
+# 4) Deprecated. Data in this column are no longer read by Chrome-on-CrOS.
+# 5) Fixed string "login": Corresponding XKB layout ID in column 2 is read by
+#    Chrome-on-CrOS into an allowlist for login and lock screens.
+#    Empty: Corresponding XKB layout ID in column 2 is ignored.
 #
-# Notes:
-#   If you add an XKB layout which depends on AltGr or X11's Mod3Mask
-#   (e.g. Germany Neo2 XKB layout), you should also update kAltGrLayoutIds or
-#   kMod3LayoutIds in
-#   chrome/browser/chromeos/input_method/input_method_manager_impl.cc
-#   Otherwise, Mod3Mask might be removed unexpectedly by the rewriter, and
-#   sticky keys will not work.
+# Nowadays canonical input method configs on CrOS are defined in:
+# chrome/browser/resources/chromeos/input_method/google_xkb_manifest.json
+# For open-source Chromium OS: see other *_manifest.json in the same folder.
+#
+# Deprecated data aren't removed yet. This file is shipped in CrOS images, thus
+# possibly still read (and likely interpreted incorrectly) by other systems.
+# TODO(crbug.com/1134526): Investigate external systems that still read this
+# file for proper migration plans, then ultimately retire this legacy file.
 #
 
 # U.S. English
@@ -47,9 +40,6 @@
 xkb:us::fil             us               fil                  US   login
 xkb:us::msa             us               ms                   US   login
 
-# U.S. English entiries have to be above the Dutch entry so that xkb:us:intl:eng
-# will be selected as the default keyboard when the UI language is set to Dutch.
-
 # Dutch
 xkb:be::nld  be nl BE login
 # We don't support xkb:nl::nld. See b/4430951.
@@ -69,15 +59,13 @@
 xkb:ch::ger     ch      de,de-CH CH  login
 
 # Japanese
-# |kMozcJaInputMethodIds| in ibus_ui_controller.cc should also be updated when
-# a new Mozc Japanese IME for another keyboard layout is added.
 xkb:jp::jpn  jp ja JA login
 
 # Russian
 xkb:ru::rus          ru           ru RU
 xkb:ru:phonetic:rus  ru(phonetic) ru RU
 
-# Keyboard layouts.
+# Others
 xkb:br::por           br             pt-BR,pt  BR login
 xkb:bg::bul           bg             bg        BG
 xkb:bg:phonetic:bul   bg(phonetic)   bg        BG
@@ -122,6 +110,3 @@
 xkb:ie::ga            ie             ga        GA login
 xkb:mt::mlt           mt             mt        MT login
 xkb:mk::mkd           mk             mk        MK
-
-# TODO(yusukes): Support xkb:latam:deadtilde:spa and/or xkb:latam:nodeadkeys:spa
-# if necessary.
diff --git a/chromeos/services/assistant/chromium_api_delegate.cc b/chromeos/services/assistant/chromium_api_delegate.cc
index 5ebc935..f8e1c37 100644
--- a/chromeos/services/assistant/chromium_api_delegate.cc
+++ b/chromeos/services/assistant/chromium_api_delegate.cc
@@ -6,6 +6,7 @@
 
 #include <utility>
 
+#include "base/notreached.h"
 #include "base/single_thread_task_runner.h"
 #include "services/network/public/cpp/shared_url_loader_factory.h"
 
@@ -24,5 +25,9 @@
   return &http_connection_factory_;
 }
 
+void ChromiumApiDelegate::OverrideDoNotDisturb(bool do_not_disturb_enabled) {
+  NOTIMPLEMENTED();
+}
+
 }  // namespace assistant
 }  // namespace chromeos
diff --git a/chromeos/services/assistant/chromium_api_delegate.h b/chromeos/services/assistant/chromium_api_delegate.h
index e31a438..008bca8 100644
--- a/chromeos/services/assistant/chromium_api_delegate.h
+++ b/chromeos/services/assistant/chromium_api_delegate.h
@@ -29,6 +29,7 @@
   ~ChromiumApiDelegate() override;
   // assistant_client::FuchsiaApiDelegate overrides:
   assistant_client::HttpConnectionFactory* GetHttpConnectionFactory() override;
+  void OverrideDoNotDisturb(bool do_not_disturb_enabled) override;
 
  private:
   ChromiumHttpConnectionFactory http_connection_factory_;
diff --git a/chromeos/services/assistant/chromium_http_connection.cc b/chromeos/services/assistant/chromium_http_connection.cc
index 2f002fd5..bd9dde0 100644
--- a/chromeos/services/assistant/chromium_http_connection.cc
+++ b/chromeos/services/assistant/chromium_http_connection.cc
@@ -152,6 +152,15 @@
     case Method::HEAD:
       resource_request->method = "HEAD";
       break;
+    case Method::PATCH:
+      resource_request->method = "PATCH";
+      break;
+    case Method::PUT:
+      resource_request->method = "PUT";
+      break;
+    case Method::DELETE:
+      resource_request->method = "DELETE";
+      break;
   }
   resource_request->credentials_mode = network::mojom::CredentialsMode::kOmit;
 
diff --git a/chromeos/services/assistant/platform/audio_input_impl.cc b/chromeos/services/assistant/platform/audio_input_impl.cc
index ae008cb..02ba3d7 100644
--- a/chromeos/services/assistant/platform/audio_input_impl.cc
+++ b/chromeos/services/assistant/platform/audio_input_impl.cc
@@ -333,7 +333,7 @@
 
 void AudioInputImpl::LidEventReceived(
     chromeos::PowerManagerClient::LidState state,
-    const base::TimeTicks& timestamp) {
+    base::TimeTicks timestamp) {
   // Lid switch event still gets fired during system suspend, which enables
   // us to stop DSP recording correctly when user closes lid after the device
   // goes to sleep.
diff --git a/chromeos/services/assistant/platform/audio_input_impl.h b/chromeos/services/assistant/platform/audio_input_impl.h
index 60a20e6a..de13a2f 100644
--- a/chromeos/services/assistant/platform/audio_input_impl.h
+++ b/chromeos/services/assistant/platform/audio_input_impl.h
@@ -72,7 +72,7 @@
 
   // chromeos::PowerManagerClient::Observer overrides:
   void LidEventReceived(chromeos::PowerManagerClient::LidState state,
-                        const base::TimeTicks& timestamp) override;
+                        base::TimeTicks timestamp) override;
 
   // Called when the mic state associated with the interaction is changed.
   void SetMicState(bool mic_open);
diff --git a/chromeos/services/assistant/service.cc b/chromeos/services/assistant/service.cc
index 52993fb..f0f8684 100644
--- a/chromeos/services/assistant/service.cc
+++ b/chromeos/services/assistant/service.cc
@@ -287,7 +287,7 @@
   UpdateAssistantManagerState();
 }
 
-void Service::SuspendDone(const base::TimeDelta& sleep_duration) {
+void Service::SuspendDone(base::TimeDelta sleep_duration) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   // |token_refresh_timer_| may become stale during sleeping, so we immediately
   // request a new token to make sure it is fresh.
diff --git a/chromeos/services/assistant/service.h b/chromeos/services/assistant/service.h
index 1186aff..5a450e7 100644
--- a/chromeos/services/assistant/service.h
+++ b/chromeos/services/assistant/service.h
@@ -98,7 +98,7 @@
 
   // chromeos::PowerManagerClient::Observer overrides:
   void PowerChanged(const power_manager::PowerSupplyProperties& prop) override;
-  void SuspendDone(const base::TimeDelta& sleep_duration) override;
+  void SuspendDone(base::TimeDelta sleep_duration) override;
 
   // ash::SessionActivationObserver overrides:
   void OnSessionActivated(bool activated) override;
diff --git a/chromeos/services/assistant/utils.cc b/chromeos/services/assistant/utils.cc
index 82bbf877..ffa338b 100644
--- a/chromeos/services/assistant/utils.cc
+++ b/chromeos/services/assistant/utils.cc
@@ -40,6 +40,22 @@
     base::StringAppendF(user_agent, " ARC/%s", arc_version.c_str());
 }
 
+// Returns if we are running a test or release image.
+bool IsTestImage() {
+  // If we're not running on real hardware, we're considered a test build.
+  // This check is needed because the release track is only set for real
+  // hardware.
+  if (!base::SysInfo::IsRunningOnChromeOS())
+    return true;
+
+  constexpr char kChromeOSReleaseTrack[] = "CHROMEOS_RELEASE_TRACK";
+  constexpr char kTestImageRelease[] = "testimage-channel";
+
+  std::string track;
+  bool found = base::SysInfo::GetLsbReleaseValue(kChromeOSReleaseTrack, &track);
+  return found && (track.find(kTestImageRelease) != std::string::npos);
+}
+
 }  // namespace
 
 // Get the root path for assistant files.
@@ -148,10 +164,11 @@
                          GetBaseAssistantDir().AsUTF8Unsafe());
   }
 
-  if (features::IsLibAssistantBetaBackendEnabled() ||
-      features::IsAssistantDebuggingEnabled()) {
+  // Inform Libassistant if we're running a test image, because Libassistant has
+  // a consistency check to ensure |libassistant_debug.so| is not used in
+  // production.
+  if (IsTestImage())
     config.SetStringPath("internal.backend_type", "BETA_DOGFOOD");
-  }
 
   // Use http unless we're using the fake s3 server, which requires grpc.
   if (s3_server_uri_override)
diff --git a/components/arc/enterprise/arc_data_snapshotd_bridge.cc b/components/arc/enterprise/arc_data_snapshotd_bridge.cc
index 795d28f..64588539e 100644
--- a/components/arc/enterprise/arc_data_snapshotd_bridge.cc
+++ b/components/arc/enterprise/arc_data_snapshotd_bridge.cc
@@ -109,9 +109,9 @@
     return;
   }
   VLOG(1) << "ClearSnapshot via D-Bus";
-  NOTIMPLEMENTED();
-
-  std::move(callback).Run(true /* success */);
+  chromeos::DBusThreadManager::Get()
+      ->GetArcDataSnapshotdClient()
+      ->ClearSnapshot(last, std::move(callback));
 }
 
 void ArcDataSnapshotdBridge::TakeSnapshot(
@@ -123,9 +123,8 @@
     return;
   }
   VLOG(1) << "TakeSnapshot via D-Bus";
-  NOTIMPLEMENTED();
-
-  std::move(callback).Run(true /* success */);
+  chromeos::DBusThreadManager::Get()->GetArcDataSnapshotdClient()->TakeSnapshot(
+      account_id, std::move(callback));
 }
 
 void ArcDataSnapshotdBridge::LoadSnapshot(
@@ -137,9 +136,20 @@
     return;
   }
   VLOG(1) << "LoadSnapshot via D-Bus";
-  NOTIMPLEMENTED();
+  chromeos::DBusThreadManager::Get()->GetArcDataSnapshotdClient()->LoadSnapshot(
+      account_id, std::move(callback));
+}
 
-  std::move(callback).Run(true /* success */, true /* last */);
+void ArcDataSnapshotdBridge::Update(int percent,
+                                    base::OnceCallback<void(bool)> callback) {
+  if (!is_available_) {
+    LOG(ERROR) << "Update call when D-Bus service is not available.";
+    std::move(callback).Run(false /* success */);
+    return;
+  }
+  VLOG(1) << "Update via D-Bus";
+  chromeos::DBusThreadManager::Get()->GetArcDataSnapshotdClient()->Update(
+      percent, std::move(callback));
 }
 
 }  // namespace data_snapshotd
diff --git a/components/arc/enterprise/arc_data_snapshotd_bridge.h b/components/arc/enterprise/arc_data_snapshotd_bridge.h
index a54a19cc..38d9ac9 100644
--- a/components/arc/enterprise/arc_data_snapshotd_bridge.h
+++ b/components/arc/enterprise/arc_data_snapshotd_bridge.h
@@ -5,6 +5,8 @@
 #ifndef COMPONENTS_ARC_ENTERPRISE_ARC_DATA_SNAPSHOTD_BRIDGE_H_
 #define COMPONENTS_ARC_ENTERPRISE_ARC_DATA_SNAPSHOTD_BRIDGE_H_
 
+#include <string>
+
 #include "base/callback.h"
 #include "base/memory/weak_ptr.h"
 #include "base/time/time.h"
@@ -28,11 +30,21 @@
 
   // Delegates the key pair generation to arc-data-snapshotd daemon.
   void GenerateKeyPair(base::OnceCallback<void(bool)> callback);
+  // Delegates the removal of snapshot to arc-data-snapshotd daemon. If |last|,
+  // removes the last generated snapshot.
   void ClearSnapshot(bool last, base::OnceCallback<void(bool)> callback);
+  // Delegates the taking of ARC data snapshot to arc-data-snapshotd daemon.
+  // |account_id| is the current account_id of MGS.
   void TakeSnapshot(const std::string& account_id,
                     base::OnceCallback<void(bool)> callback);
+  // Delegates the loading of ARC data snapshot to current MGS to
+  // arc-data-snapshotd daemon. |account_id| is the current account_id of MGS.
   void LoadSnapshot(const std::string& account_id,
                     base::OnceCallback<void(bool, bool)> callback);
+  // Delegates the updating of a progress bar on a UI screen to
+  // arc-data-snapshotd daemon. |percent| is a percentage of installed required
+  // ARC apps [0..100].
+  void Update(int percent, base::OnceCallback<void(bool)> callback);
 
   bool is_available_for_testing() { return is_available_; }
 
diff --git a/components/arc/enterprise/arc_data_snapshotd_bridge_unittest.cc b/components/arc/enterprise/arc_data_snapshotd_bridge_unittest.cc
index 002889f..8c98e46 100644
--- a/components/arc/enterprise/arc_data_snapshotd_bridge_unittest.cc
+++ b/components/arc/enterprise/arc_data_snapshotd_bridge_unittest.cc
@@ -21,6 +21,8 @@
 
 namespace {
 
+constexpr char kFakeAccountId[] = "fake_account_id@localhost";
+
 void RunGenerateKeyPair(ArcDataSnapshotdBridge* bridge, bool expected_result) {
   base::RunLoop run_loop;
   bridge->GenerateKeyPair(
@@ -31,6 +33,61 @@
   run_loop.Run();
 }
 
+void RunClearSnapshot(ArcDataSnapshotdBridge* bridge, bool expected_result) {
+  base::RunLoop run_loop;
+  bridge->ClearSnapshot(
+      false /* last */,
+      base::BindLambdaForTesting([expected_result, &run_loop](bool success) {
+        EXPECT_EQ(expected_result, success);
+        run_loop.Quit();
+      }));
+  run_loop.Run();
+}
+
+void RunTakeSnapshot(ArcDataSnapshotdBridge* bridge, bool expected_result) {
+  base::RunLoop run_loop;
+  bridge->TakeSnapshot(
+      kFakeAccountId,
+      base::BindLambdaForTesting([expected_result, &run_loop](bool success) {
+        EXPECT_EQ(expected_result, success);
+        run_loop.Quit();
+      }));
+  run_loop.Run();
+}
+
+void RunLoadSnapshot(ArcDataSnapshotdBridge* bridge, bool expected_result) {
+  base::RunLoop run_loop;
+  bridge->LoadSnapshot(kFakeAccountId,
+                       base::BindLambdaForTesting([expected_result, &run_loop](
+                                                      bool success, bool last) {
+                         EXPECT_EQ(expected_result, success);
+                         // If LoadSnapshot fails, last = false.
+                         // If succeeds, last = true for tests.
+                         EXPECT_EQ(expected_result, last);
+                         run_loop.Quit();
+                       }));
+  run_loop.Run();
+}
+
+void RunUpdate(ArcDataSnapshotdBridge* bridge, bool expected_result) {
+  base::RunLoop run_loop;
+  bridge->Update(
+      50 /* percent */,
+      base::BindLambdaForTesting([expected_result, &run_loop](bool success) {
+        EXPECT_EQ(expected_result, success);
+        run_loop.Quit();
+      }));
+  run_loop.Run();
+}
+
+void RunAll(ArcDataSnapshotdBridge* bridge, bool expected_result) {
+  RunGenerateKeyPair(bridge, expected_result);
+  RunClearSnapshot(bridge, expected_result);
+  RunTakeSnapshot(bridge, expected_result);
+  RunLoadSnapshot(bridge, expected_result);
+  RunUpdate(bridge, expected_result);
+}
+
 // Tests ArcDataSnapshotdBridge class instance.
 class ArcDataSnapshotdBridgeTest : public testing::Test {
  protected:
@@ -65,12 +122,12 @@
   dbus_client()->set_available(true /* is_available */);
   ArcDataSnapshotdBridge bridge{base::DoNothing()};
   EXPECT_FALSE(bridge.is_available_for_testing());
-  RunGenerateKeyPair(&bridge, false /* expected_result */);
+  RunAll(&bridge, false /* expected_result */);
 
   task_environment_.RunUntilIdle();
 
   EXPECT_TRUE(bridge.is_available_for_testing());
-  RunGenerateKeyPair(&bridge, true /* expected_result */);
+  RunAll(&bridge, true /* expected_result */);
 }
 
 // Test basic scenario: D-Bus service is not available.
@@ -81,7 +138,7 @@
   task_environment_.RunUntilIdle();
 
   EXPECT_FALSE(bridge.is_available_for_testing());
-  RunGenerateKeyPair(&bridge, false /* expected_result */);
+  RunAll(&bridge, false /* expected_result */);
 }
 
 // Test that service is available from the max attempt.
@@ -104,7 +161,7 @@
   dbus_client()->set_available(true /* is_available */);
   FastForwardAttempt();
   EXPECT_TRUE(bridge.is_available_for_testing());
-  RunGenerateKeyPair(&bridge, true /* expected_result */);
+  RunAll(&bridge, true /* expected_result */);
 }
 
 // Test that service is available from the max + 1 attempt and is not picked up.
@@ -127,7 +184,7 @@
   dbus_client()->set_available(true /* is_available */);
   FastForwardAttempt();
   EXPECT_FALSE(bridge.is_available_for_testing());
-  RunGenerateKeyPair(&bridge, false /* expected_result */);
+  RunAll(&bridge, false /* expected_result */);
 }
 
 }  // namespace
diff --git a/components/arc/power/arc_power_bridge.cc b/components/arc/power/arc_power_bridge.cc
index f5e915a..c7d96365 100644
--- a/components/arc/power/arc_power_bridge.cc
+++ b/components/arc/power/arc_power_bridge.cc
@@ -214,7 +214,7 @@
   chromeos::PowerManagerClient::Get()->UnblockSuspend(token);
 }
 
-void ArcPowerBridge::SuspendDone(const base::TimeDelta& sleep_duration) {
+void ArcPowerBridge::SuspendDone(base::TimeDelta sleep_duration) {
   if (arc::IsArcVmEnabled()) {
     vm_tools::concierge::ResumeVmRequest request;
     request.set_name(kArcVmName);
diff --git a/components/arc/power/arc_power_bridge.h b/components/arc/power/arc_power_bridge.h
index da1b335..d16b1b9 100644
--- a/components/arc/power/arc_power_bridge.h
+++ b/components/arc/power/arc_power_bridge.h
@@ -72,7 +72,7 @@
 
   // chromeos::PowerManagerClient::Observer overrides.
   void SuspendImminent(power_manager::SuspendImminent::Reason reason) override;
-  void SuspendDone(const base::TimeDelta& sleep_duration) override;
+  void SuspendDone(base::TimeDelta sleep_duration) override;
   void ScreenBrightnessChanged(
       const power_manager::BacklightBrightnessChange& change) override;
   void PowerChanged(const power_manager::PowerSupplyProperties& proto) override;
diff --git a/components/arc/video_accelerator/gpu_arc_video_encode_accelerator.cc b/components/arc/video_accelerator/gpu_arc_video_encode_accelerator.cc
index 0fab25d9..f93c017 100644
--- a/components/arc/video_accelerator/gpu_arc_video_encode_accelerator.cc
+++ b/components/arc/video_accelerator/gpu_arc_video_encode_accelerator.cc
@@ -27,6 +27,14 @@
 namespace arc {
 
 namespace {
+
+// Maximum number of concurrent ARC video clients.
+// Currently we have no way to know the resources are not enough to create more
+// VEAs. Currently this value is selected as 40 instances are enough to pass
+// the CTS tests.
+// TODO(b/168422427): Decrease this to 8 once media_codecs_c2.xml is updated.
+constexpr size_t kMaxConcurrentClients = 40;
+
 base::Optional<media::VideoFrameLayout> CreateVideoFrameLayout(
     media::VideoPixelFormat format,
     const gfx::Size& coded_size,
@@ -63,6 +71,9 @@
 }
 }  // namespace
 
+// static
+size_t GpuArcVideoEncodeAccelerator::client_count_ = 0;
+
 GpuArcVideoEncodeAccelerator::GpuArcVideoEncodeAccelerator(
     const gpu::GpuPreferences& gpu_preferences,
     const gpu::GpuDriverBugWorkarounds& gpu_workarounds)
@@ -72,7 +83,13 @@
           media::VideoEncodeAccelerator::Config::StorageType::kShmem),
       bitstream_buffer_serial_(0) {}
 
-GpuArcVideoEncodeAccelerator::~GpuArcVideoEncodeAccelerator() = default;
+GpuArcVideoEncodeAccelerator::~GpuArcVideoEncodeAccelerator() {
+  // Normally |client_count_| should always be > 0 if vea_ is set, but if it
+  // isn't and we underflow then we won't be able to create any new decoder
+  // forever. (b/173700103). So let's use an extra check to avoid this...
+  if (accelerator_ && client_count_ > 0)
+    client_count_--;
+}
 
 // VideoEncodeAccelerator::Client implementation.
 void GpuArcVideoEncodeAccelerator::RequireBitstreamBuffers(
@@ -140,6 +157,13 @@
     DLOG(ERROR) << "storage type must be specified";
     return mojom::VideoEncodeAccelerator::Result::kInvalidArgumentError;
   }
+
+  if (client_count_ >= kMaxConcurrentClients) {
+    VLOGF(1) << "Reject to Initialize() due to too many clients: "
+             << client_count_;
+    return mojom::VideoEncodeAccelerator::Result::kInsufficientResourcesError;
+  }
+
   input_pixel_format_ = config.input_format;
   input_storage_type_ = *config.storage_type;
   visible_size_ = config.input_visible_size;
@@ -149,8 +173,11 @@
     DLOG(ERROR) << "Failed to create a VideoEncodeAccelerator.";
     return mojom::VideoEncodeAccelerator::Result::kPlatformFailureError;
   }
+
   client_.Bind(std::move(client));
 
+  client_count_++;
+  VLOGF(2) << "Number of concurrent clients: " << client_count_;
   return mojom::VideoEncodeAccelerator::Result::kSuccess;
 }
 
diff --git a/components/arc/video_accelerator/gpu_arc_video_encode_accelerator.h b/components/arc/video_accelerator/gpu_arc_video_encode_accelerator.h
index 47bf8f2..5d72141 100644
--- a/components/arc/video_accelerator/gpu_arc_video_encode_accelerator.h
+++ b/components/arc/video_accelerator/gpu_arc_video_encode_accelerator.h
@@ -88,6 +88,12 @@
                           bool force_keyframe,
                           EncodeCallback callback);
 
+  // Global counter that keeps track of the number of active clients (i.e., how
+  // many VEAs in use by this class).
+  // Since this class only works on the same thread, it's safe to access
+  // |client_count_| without lock.
+  static size_t client_count_;
+
   gpu::GpuPreferences gpu_preferences_;
   gpu::GpuDriverBugWorkarounds gpu_workarounds_;
   std::unique_ptr<media::VideoEncodeAccelerator> accelerator_;
diff --git a/components/autofill/core/browser/form_parsing/form_field.cc b/components/autofill/core/browser/form_parsing/form_field.cc
index baa116f1..16b45ac 100644
--- a/components/autofill/core/browser/form_parsing/form_field.cc
+++ b/components/autofill/core/browser/form_parsing/form_field.cc
@@ -174,10 +174,9 @@
                            AutofillField** match,
                            const RegExLogging& logging) {
   if (base::FeatureList::IsEnabled(
-          features::kAutofillUsePageLanguageToSelectFieldParsingPatterns) ||
+          features::kAutofillParsingPatternsLanguageDependent) ||
       base::FeatureList::IsEnabled(
-          features::
-              kAutofillApplyNegativePatternsForFieldTypeDetectionHeuristics)) {
+          features::kAutofillParsingPatternsNegativeMatching)) {
     return ParseField(scanner, patterns, match, logging);
   } else {
     return ParseField(scanner, pattern, match, logging);
@@ -221,8 +220,7 @@
 
     // TODO(crbug.com/1132831): Remove feature check once launched.
     if (base::FeatureList::IsEnabled(
-            features::
-                kAutofillApplyNegativePatternsForFieldTypeDetectionHeuristics)) {
+            features::kAutofillParsingPatternsNegativeMatching)) {
       if (!pattern.negative_pattern.empty() &&
           FormField::Match(field, base::UTF8ToUTF16(pattern.negative_pattern),
                            pattern.match_field_attributes,
@@ -263,10 +261,9 @@
     const RegExLogging& logging,
     MatchFieldBitmasks match_field_bitmasks) {
   if (base::FeatureList::IsEnabled(
-          features::kAutofillUsePageLanguageToSelectFieldParsingPatterns) ||
+          features::kAutofillParsingPatternsLanguageDependent) ||
       base::FeatureList::IsEnabled(
-          features::
-              kAutofillApplyNegativePatternsForFieldTypeDetectionHeuristics)) {
+          features::kAutofillParsingPatternsNegativeMatching)) {
     // TODO(crbug/1142936): This hack is to allow
     // AddressField::ParseNameAndLabelSeparately().
     if (match_field_bitmasks.restrict_attributes != ~0 ||
diff --git a/components/autofill/core/browser/pattern_provider/pattern_configuration_parser.cc b/components/autofill/core/browser/pattern_provider/pattern_configuration_parser.cc
index 28fbe66..b7818c26 100644
--- a/components/autofill/core/browser/pattern_provider/pattern_configuration_parser.cc
+++ b/components/autofill/core/browser/pattern_provider/pattern_configuration_parser.cc
@@ -82,7 +82,8 @@
 // are equal or both unspecified (i.e. set to 0) this prioritizes the remote
 // configuration over the local one.
 void OnJsonParsed(data_decoder::DataDecoder::ValueOrError result) {
-  if (!base::FeatureList::IsEnabled(features::kAutofillUseRemotePatterns)) {
+  if (!base::FeatureList::IsEnabled(
+          features::kAutofillParsingPatternsFromRemote)) {
     DVLOG(1) << "Remote patterns are disabled.";
     return;
   }
diff --git a/components/autofill/core/browser/pattern_provider/pattern_provider.cc b/components/autofill/core/browser/pattern_provider/pattern_provider.cc
index f7d56f5..f1e0d90 100644
--- a/components/autofill/core/browser/pattern_provider/pattern_provider.cc
+++ b/components/autofill/core/browser/pattern_provider/pattern_provider.cc
@@ -100,7 +100,7 @@
 
   // TODO(crbug.com/1134496): Remove feature check once launched.
   if (base::FeatureList::IsEnabled(
-          features::kAutofillUsePageLanguageToSelectFieldParsingPatterns)) {
+          features::kAutofillParsingPatternsLanguageDependent)) {
     auto outer_it = patterns_.find(pattern_name);
     if (outer_it != patterns_.end()) {
       const std::map<LanguageCode, std::vector<MatchingPattern>>&
@@ -114,10 +114,8 @@
       }
     }
     return GetAllPatternsByType(pattern_name);
-  } else if (
-      base::FeatureList::IsEnabled(
-          features::
-              kAutofillApplyNegativePatternsForFieldTypeDetectionHeuristics)) {
+  } else if (base::FeatureList::IsEnabled(
+                 features::kAutofillParsingPatternsNegativeMatching)) {
     return GetAllPatternsByType(pattern_name);
   } else {
     return {};
diff --git a/components/autofill/core/browser/pattern_provider/pattern_provider_unittest.cc b/components/autofill/core/browser/pattern_provider/pattern_provider_unittest.cc
index 9152d3c..c3faf37 100644
--- a/components/autofill/core/browser/pattern_provider/pattern_provider_unittest.cc
+++ b/components/autofill/core/browser/pattern_provider/pattern_provider_unittest.cc
@@ -119,7 +119,7 @@
 TEST(AutofillPatternProviderTest, Single_Match) {
   base::test::ScopedFeatureList scoped_feature_list;
   scoped_feature_list.InitAndEnableFeature(
-      features::kAutofillUsePageLanguageToSelectFieldParsingPatterns);
+      features::kAutofillParsingPatternsLanguageDependent);
 
   UnitTestPatternProvider p;
   EXPECT_THAT(p.GetMatchPatterns("COMPANY_NAME", kLanguageEn),
@@ -166,10 +166,9 @@
     base::test::ScopedFeatureList feature;
     feature.InitWithFeatures(
         // enabled
-        {features::kAutofillUsePageLanguageToSelectFieldParsingPatterns},
+        {features::kAutofillParsingPatternsLanguageDependent},
         // disabled
-        {features::
-             kAutofillApplyNegativePatternsForFieldTypeDetectionHeuristics});
+        {features::kAutofillParsingPatternsNegativeMatching});
     UnitTestPatternProvider p;
     EXPECT_EQ(p.GetMatchPatterns(COMPANY_NAME, LanguageCode("")),
               p.GetAllPatternsByType(COMPANY_NAME));
@@ -181,10 +180,9 @@
     base::test::ScopedFeatureList feature;
     feature.InitWithFeatures(
         // enabled
-        {features::
-             kAutofillApplyNegativePatternsForFieldTypeDetectionHeuristics},
+        {features::kAutofillParsingPatternsNegativeMatching},
         // disabled
-        {features::kAutofillUsePageLanguageToSelectFieldParsingPatterns});
+        {features::kAutofillParsingPatternsLanguageDependent});
     UnitTestPatternProvider p;
     EXPECT_EQ(p.GetMatchPatterns(COMPANY_NAME, LanguageCode("")),
               p.GetAllPatternsByType(COMPANY_NAME));
@@ -198,10 +196,9 @@
     base::test::ScopedFeatureList feature;
     feature.InitWithFeatures(
         // enabled
-        {features::kAutofillUsePageLanguageToSelectFieldParsingPatterns},
+        {features::kAutofillParsingPatternsLanguageDependent},
         // disabled
-        {features::
-             kAutofillApplyNegativePatternsForFieldTypeDetectionHeuristics});
+        {features::kAutofillParsingPatternsNegativeMatching});
     UnitTestPatternProvider p;
     EXPECT_EQ(p.GetMatchPatterns(COMPANY_NAME, kLanguageEn),
               std::vector<MatchingPattern>{GetCompanyPatternEn()});
@@ -214,10 +211,9 @@
     base::test::ScopedFeatureList feature;
     feature.InitWithFeatures(
         // enabled
-        {features::
-             kAutofillApplyNegativePatternsForFieldTypeDetectionHeuristics},
+        {features::kAutofillParsingPatternsNegativeMatching},
         // disabled
-        {features::kAutofillUsePageLanguageToSelectFieldParsingPatterns});
+        {features::kAutofillParsingPatternsLanguageDependent});
     UnitTestPatternProvider p;
     EXPECT_EQ(p.GetMatchPatterns(COMPANY_NAME, kLanguageEn),
               std::vector<MatchingPattern>(
@@ -232,8 +228,8 @@
   base::test::ScopedFeatureList feature;
   feature.InitWithFeatures(
       // enabled
-      {features::kAutofillUsePageLanguageToSelectFieldParsingPatterns,
-       features::kAutofillApplyNegativePatternsForFieldTypeDetectionHeuristics},
+      {features::kAutofillParsingPatternsLanguageDependent,
+       features::kAutofillParsingPatternsNegativeMatching},
       // disabled
       {});
   std::vector<MatchingPattern> de_input_patterns;
diff --git a/components/autofill/core/common/autofill_features.cc b/components/autofill/core/common/autofill_features.cc
index 534e61c..77ad1aa0 100644
--- a/components/autofill/core/common/autofill_features.cc
+++ b/components/autofill/core/common/autofill_features.cc
@@ -49,13 +49,6 @@
 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{
@@ -181,6 +174,18 @@
 const base::Feature kAutofillOffNoServerData{"AutofillOffNoServerData",
                                              base::FEATURE_DISABLED_BY_DEFAULT};
 
+// Controls whether negative patterns are used to parse the field type.
+// TODO(crbug.com/1132831): Remove once launched.
+const base::Feature kAutofillParsingPatternsNegativeMatching{
+    "AutofillParsingPatternsNegativeMatching",
+    base::FEATURE_DISABLED_BY_DEFAULT};
+
+// Controls whether page language is used to match patterns.
+// TODO(crbug.com/1134496): Remove once launched.
+const base::Feature kAutofillParsingPatternsLanguageDependent{
+    "AutofillParsingPatternsLanguageDependent",
+    base::FEATURE_DISABLED_BY_DEFAULT};
+
 // If feature is enabled, Autofill will be disabled for mixed forms (forms on
 // HTTPS sites that submit over HTTP).
 const base::Feature kAutofillPreventMixedFormsFilling{
@@ -280,16 +285,10 @@
 const base::Feature kAutofillUseNewSectioningMethod{
     "AutofillUseNewSectioningMethod", base::FEATURE_DISABLED_BY_DEFAULT};
 
-// Controls whether page language is used to match patterns.
-// TODO(crbug.com/1134496): Remove once launched.
-const base::Feature kAutofillUsePageLanguageToSelectFieldParsingPatterns{
-    "AutofillUsePageLanguageToSelectFieldParsingPatterns",
-    base::FEATURE_DISABLED_BY_DEFAULT};
-
 // When enabled, Autofill will load remote patterns via the component updater.
 // TODO(crbug/1121990): Remove once launched.
-extern const base::Feature kAutofillUseRemotePatterns{
-    "AutofillUseRemotePatterns", base::FEATURE_DISABLED_BY_DEFAULT};
+extern const base::Feature kAutofillParsingPatternsFromRemote{
+    "AutofillParsingPatternsFromRemote", base::FEATURE_DISABLED_BY_DEFAULT};
 
 #if defined(OS_ANDROID)
 // Controls whether the Autofill manual fallback for Addresses and Payments is
diff --git a/components/autofill/core/common/autofill_features.h b/components/autofill/core/common/autofill_features.h
index 010fbda5..b96b5c0 100644
--- a/components/autofill/core/common/autofill_features.h
+++ b/components/autofill/core/common/autofill_features.h
@@ -26,8 +26,6 @@
 extern const base::Feature kAutofillAllowDuplicateFormSubmissions;
 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;
@@ -52,6 +50,9 @@
 extern const base::Feature kAutofillPruneSuggestions;
 extern const base::Feature kAutofillMetadataUploads;
 extern const base::Feature kAutofillOffNoServerData;
+extern const base::Feature kAutofillParsingPatternsFromRemote;
+extern const base::Feature kAutofillParsingPatternsNegativeMatching;
+extern const base::Feature kAutofillParsingPatternsLanguageDependent;
 extern const base::Feature kAutofillPreventMixedFormsFilling;
 extern const base::Feature kAutofillProbableFormSubmissionInBrowser;
 extern const base::Feature kAutofillProfileClientValidation;
@@ -70,8 +71,6 @@
 extern const base::Feature kAutofillUseAlternativeStateNameMap;
 extern const base::Feature kAutofillUseImprovedLabelDisambiguation;
 extern const base::Feature kAutofillUseNewSectioningMethod;
-extern const base::Feature kAutofillUsePageLanguageToSelectFieldParsingPatterns;
-extern const base::Feature kAutofillUseRemotePatterns;
 
 #if defined(OS_ANDROID)
 extern const base::Feature kAutofillManualFallbackAndroid;
diff --git a/components/autofill_assistant/browser/controller.cc b/components/autofill_assistant/browser/controller.cc
index cd96730..ada7439 100644
--- a/components/autofill_assistant/browser/controller.cc
+++ b/components/autofill_assistant/browser/controller.cc
@@ -1793,6 +1793,18 @@
   expect_navigation_ = true;
 }
 
+void Controller::OnNavigationShutdownOrError(const GURL& url,
+                                             Metrics::DropOutReason reason) {
+  if (google_util::IsGoogleDomainUrl(
+          url, google_util::ALLOW_SUBDOMAIN,
+          google_util::DISALLOW_NON_STANDARD_PORTS)) {
+    client_->Shutdown(reason);
+  } else {
+    OnScriptError(l10n_util::GetStringUTF8(IDS_AUTOFILL_ASSISTANT_GIVE_UP),
+                  reason);
+  }
+}
+
 void Controller::DidStartNavigation(
     content::NavigationHandle* navigation_handle) {
   if (!navigation_handle->IsInMainFrame() ||
@@ -1850,8 +1862,8 @@
       web_contents()->GetLastCommittedURL().is_valid() &&
       !navigation_handle->WasServerRedirect() &&
       !navigation_handle->IsRendererInitiated()) {
-    OnScriptError(l10n_util::GetStringUTF8(IDS_AUTOFILL_ASSISTANT_GIVE_UP),
-                  Metrics::DropOutReason::NAVIGATION);
+    OnNavigationShutdownOrError(navigation_handle->GetURL(),
+                                Metrics::DropOutReason::NAVIGATION);
     return;
   }
 
@@ -1860,8 +1872,9 @@
   if (state_ == AutofillAssistantState::RUNNING &&
       !navigation_handle->WasServerRedirect() &&
       !navigation_handle->IsRendererInitiated()) {
-    OnScriptError(l10n_util::GetStringUTF8(IDS_AUTOFILL_ASSISTANT_GIVE_UP),
-                  Metrics::DropOutReason::NAVIGATION_WHILE_RUNNING);
+    OnNavigationShutdownOrError(
+        navigation_handle->GetURL(),
+        Metrics::DropOutReason::NAVIGATION_WHILE_RUNNING);
     return;
   }
 
@@ -1889,24 +1902,17 @@
 
   // When in BROWSE state, stop autofill assistant if the user navigates away
   // from the original assisted domain. Subdomains of the original domain are
-  // supported.
+  // supported. If the new URL is on a Google property, destroy the UI
+  // immediately, without showing an error.
   if (state_ == AutofillAssistantState::BROWSE) {
     if (!url_utils::IsInDomainOrSubDomain(GetCurrentURL(), script_url_) &&
         !url_utils::IsInDomainOrSubDomain(GetCurrentURL(),
                                           browse_domains_allowlist_)) {
-      OnScriptError(l10n_util::GetStringUTF8(IDS_AUTOFILL_ASSISTANT_GIVE_UP),
-                    Metrics::DropOutReason::DOMAIN_CHANGE_DURING_BROWSE_MODE);
+      OnNavigationShutdownOrError(
+          web_contents()->GetLastCommittedURL(),
+          Metrics::DropOutReason::DOMAIN_CHANGE_DURING_BROWSE_MODE);
     }
   }
-  // When in STOPPED state, entered by an unexpected DidStartNavigation or
-  // domain change while in BROWSE state (above), and the new URL is on a
-  // Google property, destroy the UI immediately.
-  if (state_ == AutofillAssistantState::STOPPED &&
-      google_util::IsGoogleDomainUrl(
-          web_contents()->GetLastCommittedURL(), google_util::ALLOW_SUBDOMAIN,
-          google_util::DISALLOW_NON_STANDARD_PORTS)) {
-    client_->DestroyUI();
-  }
 
   if (start_after_navigation_) {
     std::move(start_after_navigation_).Run();
diff --git a/components/autofill_assistant/browser/controller.h b/components/autofill_assistant/browser/controller.h
index 98ba3ff..a4b8d7f 100644
--- a/components/autofill_assistant/browser/controller.h
+++ b/components/autofill_assistant/browser/controller.h
@@ -180,6 +180,8 @@
       base::OnceCallback<void(UserData*, UserData::FieldChange*)>) override;
   void OnScriptError(const std::string& error_message,
                      Metrics::DropOutReason reason);
+  void OnNavigationShutdownOrError(const GURL& url,
+                                   Metrics::DropOutReason reason);
 
   // Overrides autofill_assistant::UiDelegate:
   AutofillAssistantState GetState() const override;
diff --git a/components/autofill_assistant/browser/controller_unittest.cc b/components/autofill_assistant/browser/controller_unittest.cc
index 48bc7dd..390ade9 100644
--- a/components/autofill_assistant/browser/controller_unittest.cc
+++ b/components/autofill_assistant/browser/controller_unittest.cc
@@ -1893,7 +1893,7 @@
                                    AutofillAssistantState::STOPPED));
 }
 
-TEST_F(ControllerTest, NavigationToGooglePropertyDestroysUI) {
+TEST_F(ControllerTest, NavigationToGooglePropertyShutsDownDestroyingUI) {
   SupportsScriptResponseProto script_response;
   AddRunnableScript(&script_response, "autostart")
       ->mutable_presentation()
@@ -1911,23 +1911,20 @@
   Start();
   EXPECT_EQ(AutofillAssistantState::PROMPT, controller_->GetState());
 
-  EXPECT_CALL(mock_client_, RecordDropOut(Metrics::DropOutReason::NAVIGATION));
-  EXPECT_CALL(mock_client_, DestroyUI);
+  EXPECT_CALL(mock_client_, Shutdown(Metrics::DropOutReason::NAVIGATION));
   GURL google("https://google.com/search");
   SetLastCommittedUrl(google);
   content::NavigationSimulator::NavigateAndCommitFromBrowser(web_contents(),
                                                              google);
 
-  EXPECT_EQ(AutofillAssistantState::STOPPED, controller_->GetState());
-
   // Full history of state transitions.
   EXPECT_THAT(states_, ElementsAre(AutofillAssistantState::STARTING,
                                    AutofillAssistantState::RUNNING,
-                                   AutofillAssistantState::PROMPT,
-                                   AutofillAssistantState::STOPPED));
+                                   AutofillAssistantState::PROMPT));
 }
 
-TEST_F(ControllerTest, DomainChangeToGooglePropertyDuringBrowseDestroysUI) {
+TEST_F(ControllerTest,
+       DomainChangeToGooglePropertyDuringBrowseShutsDownDestroyingUI) {
   SupportsScriptResponseProto script_response;
   AddRunnableScript(&script_response, "runnable")
       ->mutable_presentation()
@@ -1948,20 +1945,16 @@
 
   EXPECT_CALL(
       mock_client_,
-      RecordDropOut(Metrics::DropOutReason::DOMAIN_CHANGE_DURING_BROWSE_MODE));
-  EXPECT_CALL(mock_client_, DestroyUI);
+      Shutdown(Metrics::DropOutReason::DOMAIN_CHANGE_DURING_BROWSE_MODE));
   GURL google("https://google.com/search");
   SetLastCommittedUrl(google);
   content::NavigationSimulator::NavigateAndCommitFromBrowser(web_contents(),
                                                              google);
 
-  EXPECT_EQ(AutofillAssistantState::STOPPED, controller_->GetState());
-
   // Full history of state transitions.
   EXPECT_THAT(states_, ElementsAre(AutofillAssistantState::STARTING,
                                    AutofillAssistantState::RUNNING,
-                                   AutofillAssistantState::BROWSE,
-                                   AutofillAssistantState::STOPPED));
+                                   AutofillAssistantState::BROWSE));
 }
 
 TEST_F(ControllerTest, UserDataFormEmpty) {
diff --git a/components/browser_ui/styles/android/BUILD.gn b/components/browser_ui/styles/android/BUILD.gn
index 32c2930..acf34dc 100644
--- a/components/browser_ui/styles/android/BUILD.gn
+++ b/components/browser_ui/styles/android/BUILD.gn
@@ -160,7 +160,6 @@
     "java/res/drawable/ic_offline_pin_24dp_on_dark_bg.xml",
     "java/res/drawable/ic_offline_pin_24dp_on_light_bg.xml",
     "java/res/drawable/ic_permission_location_filled.xml",
-    "java/res/drawable/ic_permission_location_outline.xml",
     "java/res/drawable/ic_play_circle_filled_24dp_on_dark_bg.xml",
     "java/res/drawable/ic_play_circle_filled_24dp_on_light_bg.xml",
     "java/res/drawable/ic_security_grey.xml",
diff --git a/components/browser_ui/styles/android/java/res/drawable/ic_permission_location_outline.xml b/components/browser_ui/styles/android/java/res/drawable/ic_permission_location_outline.xml
deleted file mode 100644
index 5e09f76..0000000
--- a/components/browser_ui/styles/android/java/res/drawable/ic_permission_location_outline.xml
+++ /dev/null
@@ -1,5 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--Copyright 2019 The Chromium Authors. All rights reserved. Use of this source code is governed by a BSD-style license that can be found in the LICENSE file.-->
-<vector xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" tools:targetApi="21" android:width="24dp" android:height="24dp" android:viewportWidth="24.0" android:viewportHeight="24.0">
-    <path android:pathData="M12 2c3.87 0 7 3.13 7 7 0 5.25-7 13-7 13S5 14.25 5 9c0-3.87 3.13-7 7-7zm0 2C9.24 4 7 6.24 7 9c0 2.85 2.92 7.21 5 9.88 2.12-2.69 5-7 5-9.88 0-2.76-2.24-5-5-5zm0 2.5c1.38 0 2.5 1.12 2.5 2.5s-1.12 2.5-2.5 2.5S9.5 10.38 9.5 9s1.12-2.5 2.5-2.5z" android:strokeWidth="1" android:fillColor="#000000"/>
-</vector>
diff --git a/components/offline_items_collection/DIR_METADATA b/components/offline_items_collection/DIR_METADATA
new file mode 100644
index 0000000..30fe702ce
--- /dev/null
+++ b/components/offline_items_collection/DIR_METADATA
@@ -0,0 +1,5 @@
+monorail {
+  component: "UI>Browser>Downloads"
+}
+
+team_email: "chrome-downloads@chromium.org"
diff --git a/components/offline_items_collection/OWNERS b/components/offline_items_collection/OWNERS
index 0f3c3ca..56f4567 100644
--- a/components/offline_items_collection/OWNERS
+++ b/components/offline_items_collection/OWNERS
@@ -3,6 +3,3 @@
 fgorski@chromium.org
 qinmin@chromium.org
 shaktisahu@chromium.org
-
-# TEAM: chrome-downloads@chromium.org
-# COMPONENT: UI>Browser>Downloads
diff --git a/components/offline_pages/DIR_METADATA b/components/offline_pages/DIR_METADATA
new file mode 100644
index 0000000..a629a88
--- /dev/null
+++ b/components/offline_pages/DIR_METADATA
@@ -0,0 +1,5 @@
+monorail {
+  component: "UI>Browser>Offline"
+}
+
+team_email: "offline-dev@chromium.org"
diff --git a/components/offline_pages/OWNERS b/components/offline_pages/OWNERS
index 7f43edb..20755ed 100644
--- a/components/offline_pages/OWNERS
+++ b/components/offline_pages/OWNERS
@@ -7,6 +7,3 @@
 jianli@chromium.org
 petewil@chromium.org
 sclittle@chromium.org
-
-# TEAM: offline-dev@chromium.org
-# COMPONENT: UI>Browser>Offline
diff --git a/components/on_load_script_injector/DIR_METADATA b/components/on_load_script_injector/DIR_METADATA
new file mode 100644
index 0000000..6d8f079
--- /dev/null
+++ b/components/on_load_script_injector/DIR_METADATA
@@ -0,0 +1,7 @@
+monorail {
+  component: "Fuchsia"
+}
+
+team_email: "cr-fuchsia@chromium.org"
+
+os: FUCHSIA
diff --git a/components/on_load_script_injector/OWNERS b/components/on_load_script_injector/OWNERS
index b817b00..7c2278d 100644
--- a/components/on_load_script_injector/OWNERS
+++ b/components/on_load_script_injector/OWNERS
@@ -1,7 +1,4 @@
 file://build/fuchsia/OWNERS
-# COMPONENT: Fuchsia
-# OS: Fuchsia
-# TEAM: cr-fuchsia@chromium.org
 
 per-file *.mojom=set noparent
 per-file *.mojom=file://ipc/SECURITY_OWNERS
diff --git a/components/onc/DIR_METADATA b/components/onc/DIR_METADATA
new file mode 100644
index 0000000..5c6791b3
--- /dev/null
+++ b/components/onc/DIR_METADATA
@@ -0,0 +1,3 @@
+monorail {
+  component: "OS>Systems>Network"
+}
diff --git a/components/onc/OWNERS b/components/onc/OWNERS
index 09e9f939..ae9ccd5 100644
--- a/components/onc/OWNERS
+++ b/components/onc/OWNERS
@@ -2,5 +2,3 @@
 gauravsh@chromium.org
 gspencer@chromium.org
 stevenjb@chromium.org
-
-# COMPONENT: OS>Systems>Network
diff --git a/components/open_from_clipboard/DIR_METADATA b/components/open_from_clipboard/DIR_METADATA
new file mode 100644
index 0000000..9ee06a1
--- /dev/null
+++ b/components/open_from_clipboard/DIR_METADATA
@@ -0,0 +1,5 @@
+monorail {
+  component: "UI>Browser>Omnibox>ZeroSuggest"
+}
+
+team_email: "ios-directory-owners@chromium.org"
diff --git a/components/open_from_clipboard/OWNERS b/components/open_from_clipboard/OWNERS
index 730ca68..3ebff38d 100644
--- a/components/open_from_clipboard/OWNERS
+++ b/components/open_from_clipboard/OWNERS
@@ -1,3 +1 @@
 olivierrobin@chromium.org
-# COMPONENT: UI>Browser>Omnibox>ZeroSuggest
-# TEAM: ios-directory-owners@chromium.org
diff --git a/components/optimization_guide/DIR_METADATA b/components/optimization_guide/DIR_METADATA
new file mode 100644
index 0000000..f21921424
--- /dev/null
+++ b/components/optimization_guide/DIR_METADATA
@@ -0,0 +1,3 @@
+monorail {
+  component: "Internals>OptimizationGuide"
+}
diff --git a/components/optimization_guide/OWNERS b/components/optimization_guide/OWNERS
index 39af85a..6602eb7 100644
--- a/components/optimization_guide/OWNERS
+++ b/components/optimization_guide/OWNERS
@@ -1,5 +1,3 @@
 sophiechang@chromium.org
 mcrouse@chromium.org
 tbansal@chromium.org
-
-# COMPONENT: Internals>OptimizationGuide
diff --git a/components/os_crypt/DIR_METADATA b/components/os_crypt/DIR_METADATA
new file mode 100644
index 0000000..f382c002
--- /dev/null
+++ b/components/os_crypt/DIR_METADATA
@@ -0,0 +1,3 @@
+monorail {
+  component: "Internals>LocalDataEncryption"
+}
diff --git a/components/os_crypt/OWNERS b/components/os_crypt/OWNERS
index b7713b6..6de8c4e 100644
--- a/components/os_crypt/OWNERS
+++ b/components/os_crypt/OWNERS
@@ -1,4 +1,2 @@
 cfroussios@chromium.org
 thestig@chromium.org
-
-# COMPONENT: Internals>LocalDataEncryption
diff --git a/components/ownership/DIR_METADATA b/components/ownership/DIR_METADATA
new file mode 100644
index 0000000..14b5edb
--- /dev/null
+++ b/components/ownership/DIR_METADATA
@@ -0,0 +1,3 @@
+monorail {
+  component: "Internals"
+}
diff --git a/components/ownership/OWNERS b/components/ownership/OWNERS
index 6f8d32d..2dcc458 100644
--- a/components/ownership/OWNERS
+++ b/components/ownership/OWNERS
@@ -1,2 +1 @@
 alemate@chromium.org
-# COMPONENT: Internals
diff --git a/components/password_manager/core/browser/android_affiliation/affiliation_fetch_throttler_delegate.h b/components/password_manager/core/browser/android_affiliation/affiliation_fetch_throttler_delegate.h
index 36d00c92..d0c5b14 100644
--- a/components/password_manager/core/browser/android_affiliation/affiliation_fetch_throttler_delegate.h
+++ b/components/password_manager/core/browser/android_affiliation/affiliation_fetch_throttler_delegate.h
@@ -21,7 +21,7 @@
   virtual bool OnCanSendNetworkRequest() = 0;
 
  protected:
-  virtual ~AffiliationFetchThrottlerDelegate() {}
+  virtual ~AffiliationFetchThrottlerDelegate() = default;
 };
 
 }  // namespace password_manager
diff --git a/components/password_manager/core/browser/android_affiliation/affiliation_fetcher_delegate.h b/components/password_manager/core/browser/android_affiliation/affiliation_fetcher_delegate.h
index 42902df4..4c3faef 100644
--- a/components/password_manager/core/browser/android_affiliation/affiliation_fetcher_delegate.h
+++ b/components/password_manager/core/browser/android_affiliation/affiliation_fetcher_delegate.h
@@ -50,7 +50,7 @@
   virtual void OnMalformedResponse(AffiliationFetcherInterface* fetcher) = 0;
 
  protected:
-  virtual ~AffiliationFetcherDelegate() {}
+  virtual ~AffiliationFetcherDelegate() = default;
 };
 
 }  // namespace password_manager
diff --git a/components/password_manager/core/browser/android_affiliation/affiliation_utils.cc b/components/password_manager/core/browser/android_affiliation/affiliation_utils.cc
index 2b21b94..cdc5735 100644
--- a/components/password_manager/core/browser/android_affiliation/affiliation_utils.cc
+++ b/components/password_manager/core/browser/android_affiliation/affiliation_utils.cc
@@ -198,8 +198,7 @@
 
 // FacetURI -------------------------------------------------------------------
 
-FacetURI::FacetURI() : is_valid_(false) {
-}
+FacetURI::FacetURI() = default;
 
 // static
 FacetURI FacetURI::FromPotentiallyInvalidSpec(const std::string& spec) {
diff --git a/components/password_manager/core/browser/android_affiliation/affiliation_utils.h b/components/password_manager/core/browser/android_affiliation/affiliation_utils.h
index 83a8533..0d0b764 100644
--- a/components/password_manager/core/browser/android_affiliation/affiliation_utils.h
+++ b/components/password_manager/core/browser/android_affiliation/affiliation_utils.h
@@ -136,7 +136,7 @@
   FacetURI(const std::string& canonical_spec, bool is_valid);
 
   // Whether |canonical_spec_| contains a valid facet URI in canonical form.
-  bool is_valid_;
+  bool is_valid_ = false;
 
   // The text of the encapsulated canonical URI, valid if and only if
   // |is_valid_| is true.
diff --git a/components/password_manager/core/browser/android_affiliation/facet_manager_host.h b/components/password_manager/core/browser/android_affiliation/facet_manager_host.h
index 21c12e3..8213aec 100644
--- a/components/password_manager/core/browser/android_affiliation/facet_manager_host.h
+++ b/components/password_manager/core/browser/android_affiliation/facet_manager_host.h
@@ -14,7 +14,7 @@
 // provided by the AffiliationBackend.
 class FacetManagerHost {
  public:
-  virtual ~FacetManagerHost() {}
+  virtual ~FacetManagerHost() = default;
 
   // Reads the equivalence class containing |facet_uri| from the database and
   // returns true if found; returns false otherwise.
diff --git a/components/password_manager/core/browser/compromised_credentials_table_unittest.cc b/components/password_manager/core/browser/compromised_credentials_table_unittest.cc
index 4d78678f3..deff04f 100644
--- a/components/password_manager/core/browser/compromised_credentials_table_unittest.cc
+++ b/components/password_manager/core/browser/compromised_credentials_table_unittest.cc
@@ -308,6 +308,9 @@
                           compromised_credentials3, compromised_credentials4));
 
   EXPECT_TRUE(db()->RemoveRowsByUrlAndTime(
+      // Can't use the generic `std::not_equal_to<>` here, because BindRepeating
+      // does not support functors with an overloaded call operator.
+      // NOLINTNEXTLINE(modernize-use-transparent-functors)
       base::BindRepeating(std::not_equal_to<GURL>(),
                           GURL(compromised_credentials1.signon_realm)),
       base::Time(), base::Time::Max()));
diff --git a/components/password_manager/core/browser/credential_manager_pending_prevent_silent_access_task.h b/components/password_manager/core/browser/credential_manager_pending_prevent_silent_access_task.h
index d248209..8697c4a 100644
--- a/components/password_manager/core/browser/credential_manager_pending_prevent_silent_access_task.h
+++ b/components/password_manager/core/browser/credential_manager_pending_prevent_silent_access_task.h
@@ -14,7 +14,7 @@
 // Handles mediation completion and retrieves embedder-dependent services.
 class CredentialManagerPendingPreventSilentAccessTaskDelegate {
  public:
-  virtual ~CredentialManagerPendingPreventSilentAccessTaskDelegate() {}
+  virtual ~CredentialManagerPendingPreventSilentAccessTaskDelegate() = default;
 
   // Retrieves the profile PasswordStore.
   virtual PasswordStore* GetProfilePasswordStore() = 0;
diff --git a/components/password_manager/core/browser/credential_manager_pending_request_task.cc b/components/password_manager/core/browser/credential_manager_pending_request_task.cc
index dc9a51e..fd8ecd9 100644
--- a/components/password_manager/core/browser/credential_manager_pending_request_task.cc
+++ b/components/password_manager/core/browser/credential_manager_pending_request_task.cc
@@ -41,6 +41,27 @@
   return form1.date_created > form2.date_created;
 }
 
+// Inserts `form` into `set` if no equally comparing element exists yet, or
+// replaces an existing `old_form` if `pred(old_form, form)` evaluates to true.
+// Returns whether `set` contains `form` following this operation.
+template <typename Comp, typename Predicate>
+bool InsertOrReplaceIf(base::flat_set<std::unique_ptr<PasswordForm>, Comp>& set,
+                       std::unique_ptr<PasswordForm> form,
+                       Predicate pred) {
+  auto lower = set.lower_bound(form);
+  if (lower == set.end() || set.key_comp()(form, *lower)) {
+    set.insert(lower, std::move(form));
+    return true;
+  }
+
+  if (pred(*lower, form)) {
+    *lower = std::move(form);
+    return true;
+  }
+
+  return false;
+}
+
 // Creates a base::flat_set of std::unique_ptr<PasswordForm> that uses
 // |key_getter| to compute the key used when comparing forms.
 template <typename KeyGetter>
@@ -72,14 +93,15 @@
       // |forms| contains credentials from both the profile and account stores.
       // Therefore, it could potentially contains duplicate federated
       // credentials. In case of duplicates, favor the account store version.
-      auto result =
-          federated_forms_with_unique_username.insert(std::move(form));
-      if (!result.second && form->IsUsingAccountStore())
-        *result.first = std::move(form);
+      InsertOrReplaceIf(federated_forms_with_unique_username, std::move(form),
+                        [](const auto& old_form, const auto& new_form) {
+                          return new_form->IsUsingAccountStore();
+                        });
     } else {
-      auto result = credentials.insert(std::move(form));
-      if (!result.second && IsBetterMatch(*form, **result.first))
-        *result.first = std::move(form);
+      InsertOrReplaceIf(credentials, std::move(form),
+                        [](const auto& old_form, const auto& new_form) {
+                          return IsBetterMatch(*new_form, *old_form);
+                        });
     }
   }
   // |credentials| contains credentials from both profile and account stores.
@@ -96,9 +118,10 @@
       });
 
   for (auto& form : std::move(credentials).extract()) {
-    auto result = credentials_with_unique_passwords.insert(std::move(form));
-    if (!result.second && form->IsUsingAccountStore())
-      *result.first = std::move(form);
+    InsertOrReplaceIf(credentials_with_unique_passwords, std::move(form),
+                      [](const auto& old_form, const auto& new_form) {
+                        return new_form->IsUsingAccountStore();
+                      });
   }
   *forms = std::move(credentials_with_unique_passwords).extract();
 
diff --git a/components/password_manager/core/browser/field_info_manager.h b/components/password_manager/core/browser/field_info_manager.h
index 4ad8819..5f79134 100644
--- a/components/password_manager/core/browser/field_info_manager.h
+++ b/components/password_manager/core/browser/field_info_manager.h
@@ -37,7 +37,8 @@
                              public KeyedService,
                              public PasswordStoreConsumer {
  public:
-  FieldInfoManagerImpl(scoped_refptr<password_manager::PasswordStore> store);
+  explicit FieldInfoManagerImpl(
+      scoped_refptr<password_manager::PasswordStore> store);
   ~FieldInfoManagerImpl() override;
 
   // FieldInfoManager:
diff --git a/components/password_manager/core/browser/generation/password_requirements_spec_fetcher_impl.cc b/components/password_manager/core/browser/generation/password_requirements_spec_fetcher_impl.cc
index bf18dee..099649dc 100644
--- a/components/password_manager/core/browser/generation/password_requirements_spec_fetcher_impl.cc
+++ b/components/password_manager/core/browser/generation/password_requirements_spec_fetcher_impl.cc
@@ -265,6 +265,8 @@
 
     if (!found_entry) {
       VLOG(1) << "Found no entry for " << host;
+      // `found_entry` guards against moving out of `callback_function` twice.
+      // NOLINTNEXTLINE(bugprone-use-after-move)
       TriggerCallback(std::move(callback_function), ResultCode::kFoundNoSpec,
                       PasswordRequirementsSpec());
     }
diff --git a/components/password_manager/core/browser/hash_password_manager_unittest.cc b/components/password_manager/core/browser/hash_password_manager_unittest.cc
index 371d530..4223697 100644
--- a/components/password_manager/core/browser/hash_password_manager_unittest.cc
+++ b/components/password_manager/core/browser/hash_password_manager_unittest.cc
@@ -68,7 +68,7 @@
   // Verify |SavePasswordHash(const PasswordHashData&)| behavior.
   base::string16 new_password(base::UTF8ToUTF16("new_password"));
   PasswordHashData new_password_data(username, new_password,
-                                     /*is_gaia_password=*/true);
+                                     /*force_update=*/true);
   EXPECT_TRUE(hash_password_manager.SavePasswordHash(new_password_data));
   EXPECT_NE(current_password_hash_data->hash,
             hash_password_manager
diff --git a/components/password_manager/core/browser/leak_detection/leak_detection_request_utils.cc b/components/password_manager/core/browser/leak_detection/leak_detection_request_utils.cc
index dbbd4cc..a6328a3 100644
--- a/components/password_manager/core/browser/leak_detection/leak_detection_request_utils.cc
+++ b/components/password_manager/core/browser/leak_detection/leak_detection_request_utils.cc
@@ -167,7 +167,7 @@
     signin::AccessTokenFetcher::TokenCallback callback) {
   return identity_manager->CreateAccessTokenFetcherForAccount(
       GetAccountForRequest(identity_manager),
-      /*consumer_name=*/"leak_detection_service", {kAPIScope},
+      /*oauth_consumer_name=*/"leak_detection_service", {kAPIScope},
       std::move(callback), signin::AccessTokenFetcher::Mode::kImmediate);
 }
 
diff --git a/components/password_manager/core/browser/login_database_unittest.cc b/components/password_manager/core/browser/login_database_unittest.cc
index 915f58e5..8eb4a51 100644
--- a/components/password_manager/core/browser/login_database_unittest.cc
+++ b/components/password_manager/core/browser/login_database_unittest.cc
@@ -378,7 +378,7 @@
 
   // We update, and check to make sure it matches the
   // old form, and there is only one record.
-  EXPECT_EQ(UpdateChangeForForm(form5, /*passwordchanged=*/true),
+  EXPECT_EQ(UpdateChangeForForm(form5, /*password_changed=*/true),
             db().UpdateLogin(form5));
   // matches
   EXPECT_TRUE(db().GetLogins(PasswordStore::FormDigest(form5), &result));
@@ -1275,7 +1275,7 @@
   // Simulate the user changing their password.
   complete_form.password_value = ASCIIToUTF16("new_password");
   complete_form.date_synced = base::Time::Now();
-  EXPECT_EQ(UpdateChangeForForm(complete_form, /*passwordchanged=*/true),
+  EXPECT_EQ(UpdateChangeForForm(complete_form, /*password_changed=*/true),
             db().UpdateLogin(complete_form));
 
   // When we retrieve the forms from the store, |in_store| should be set.
@@ -1358,7 +1358,7 @@
   form.moving_blocked_for_list.push_back(GaiaIdHash::FromGaiaId("gaia_id"));
 
   PasswordStoreChangeList changes = db().UpdateLogin(form);
-  EXPECT_EQ(UpdateChangeForForm(form, /*passwordchanged=*/true), changes);
+  EXPECT_EQ(UpdateChangeForForm(form, /*password_changed=*/true), changes);
   ASSERT_EQ(1U, changes.size());
   EXPECT_EQ(1, changes[0].primary_key());
 
@@ -1396,7 +1396,7 @@
   form.moving_blocked_for_list.push_back(GaiaIdHash::FromGaiaId("gaia_id"));
 
   PasswordStoreChangeList changes = db().UpdateLogin(form);
-  EXPECT_EQ(UpdateChangeForForm(form, /*passwordchanged=*/false), changes);
+  EXPECT_EQ(UpdateChangeForForm(form, /*password_changed=*/false), changes);
   ASSERT_EQ(1U, changes.size());
   EXPECT_EQ(1, changes[0].primary_key());
 
diff --git a/components/password_manager/core/browser/password_autofill_manager_unittest.cc b/components/password_manager/core/browser/password_autofill_manager_unittest.cc
index 565234f0..cf4dec3 100644
--- a/components/password_manager/core/browser/password_autofill_manager_unittest.cc
+++ b/components/password_manager/core/browser/password_autofill_manager_unittest.cc
@@ -454,7 +454,9 @@
         .WillOnce(testing::SaveArg<0>(&open_args));
     password_autofill_manager_->OnShowPasswordSuggestions(
         base::i18n::RIGHT_TO_LEFT, base::string16(),
-        is_suggestion_on_password_field ? autofill::IS_PASSWORD_FIELD : 0,
+        is_suggestion_on_password_field
+            ? autofill::IS_PASSWORD_FIELD
+            : autofill::ShowPasswordSuggestionsOptions(),
         gfx::RectF());
     ASSERT_GE(open_args.suggestions.size(), 2u);
     EXPECT_THAT(
@@ -823,8 +825,8 @@
   // Only the unlock button was available. After being clicked, it's in a
   // loading state which the DeleteFillData() call will end.
   Suggestion unlock_suggestion(
-      /*label=*/"Unlock passwords and fill", /*value=*/"", /*icon=*/"",
-      /*fronend_id=*/
+      /*value=*/"Unlock passwords and fill", /*label=*/"", /*icon=*/"",
+      /*frontend_id=*/
       autofill::POPUP_ITEM_ID_PASSWORD_ACCOUNT_STORAGE_OPT_IN);
   unlock_suggestion.is_loading = Suggestion::IsLoading(true);
   EXPECT_CALL(autofill_client, GetPopupSuggestions)
@@ -906,7 +908,8 @@
   EXPECT_CALL(autofill_client, ShowAutofillPopup)
       .WillOnce(testing::SaveArg<0>(&open_args));
   password_autofill_manager_->OnShowPasswordSuggestions(
-      base::i18n::RIGHT_TO_LEFT, base::string16(), 0, element_bounds);
+      base::i18n::RIGHT_TO_LEFT, base::string16(),
+      autofill::ShowPasswordSuggestionsOptions(), element_bounds);
   EXPECT_THAT(
       open_args.suggestions,
       SuggestionVectorValuesAre(testing::UnorderedElementsAre(
@@ -922,7 +925,8 @@
   EXPECT_CALL(autofill_client, ShowAutofillPopup)
       .WillOnce(testing::SaveArg<0>(&open_args));
   password_autofill_manager_->OnShowPasswordSuggestions(
-      base::i18n::RIGHT_TO_LEFT, base::ASCIIToUTF16("John"), 0, element_bounds);
+      base::i18n::RIGHT_TO_LEFT, base::ASCIIToUTF16("John"),
+      autofill::ShowPasswordSuggestionsOptions(), element_bounds);
   EXPECT_THAT(open_args.suggestions,
               SuggestionVectorValuesAre(
                   ElementsAre(additional.username, GetManagePasswordsTitle())));
@@ -961,7 +965,8 @@
   EXPECT_CALL(autofill_client, ShowAutofillPopup)
       .WillOnce(testing::SaveArg<0>(&open_args));
   password_autofill_manager_->OnShowPasswordSuggestions(
-      base::i18n::RIGHT_TO_LEFT, base::string16(), 0, gfx::RectF());
+      base::i18n::RIGHT_TO_LEFT, base::string16(),
+      autofill::ShowPasswordSuggestionsOptions(), gfx::RectF());
   EXPECT_THAT(open_args.suggestions,
               SuggestionVectorLabelsAre(testing::Contains(
                   base::ASCIIToUTF16("android://com.example2.android/"))));
@@ -1029,7 +1034,8 @@
   EXPECT_CALL(autofill_client, ShowAutofillPopup)
       .WillOnce(testing::SaveArg<0>(&open_args));
   password_autofill_manager_->OnShowPasswordSuggestions(
-      base::i18n::RIGHT_TO_LEFT, base::ASCIIToUTF16("foo"), 0, element_bounds);
+      base::i18n::RIGHT_TO_LEFT, base::ASCIIToUTF16("foo"),
+      autofill::ShowPasswordSuggestionsOptions(), element_bounds);
   EXPECT_THAT(open_args.suggestions,
               SuggestionVectorValuesAre(testing::UnorderedElementsAre(
                   username, additional.username, GetManagePasswordsTitle())));
@@ -1064,7 +1070,8 @@
 
   EXPECT_CALL(autofill_client, ShowAutofillPopup).Times(0);
   password_autofill_manager_->OnShowPasswordSuggestions(
-      base::i18n::RIGHT_TO_LEFT, base::ASCIIToUTF16("oo"), 0, element_bounds);
+      base::i18n::RIGHT_TO_LEFT, base::ASCIIToUTF16("oo"),
+      autofill::ShowPasswordSuggestionsOptions(), element_bounds);
 }
 
 // Verify that typing "foo@exam" into the username field will match username
@@ -1098,8 +1105,8 @@
   EXPECT_CALL(autofill_client, ShowAutofillPopup)
       .WillOnce(testing::SaveArg<0>(&open_args));
   password_autofill_manager_->OnShowPasswordSuggestions(
-      base::i18n::RIGHT_TO_LEFT, base::ASCIIToUTF16("foo@exam"), 0,
-      element_bounds);
+      base::i18n::RIGHT_TO_LEFT, base::ASCIIToUTF16("foo@exam"),
+      autofill::ShowPasswordSuggestionsOptions(), element_bounds);
   EXPECT_THAT(open_args.suggestions,
               SuggestionVectorValuesAre(
                   ElementsAre(additional.username, GetManagePasswordsTitle())));
@@ -1138,8 +1145,8 @@
   EXPECT_CALL(autofill_client, ShowAutofillPopup)
       .WillOnce(testing::SaveArg<0>(&open_args));
   password_autofill_manager_->OnShowPasswordSuggestions(
-      base::i18n::RIGHT_TO_LEFT, base::ASCIIToUTF16("foo"), false,
-      element_bounds);
+      base::i18n::RIGHT_TO_LEFT, base::ASCIIToUTF16("foo"),
+      autofill::ShowPasswordSuggestionsOptions(), element_bounds);
   EXPECT_THAT(open_args.suggestions,
               SuggestionVectorValuesAre(ElementsAre(
                   username, additional.username, GetManagePasswordsTitle())));
@@ -1162,7 +1169,7 @@
   gfx::RectF element_bounds;
   password_autofill_manager_->OnShowPasswordSuggestions(
       base::i18n::RIGHT_TO_LEFT, base::string16(),
-      /*autoselect_first_suggestion=*/false, element_bounds);
+      autofill::ShowPasswordSuggestionsOptions(), element_bounds);
 
   // Check that preview of the empty username works.
   EXPECT_CALL(*client.mock_driver(),
@@ -1260,7 +1267,8 @@
   EXPECT_CALL(autofill_client, ShowAutofillPopup)
       .WillOnce(testing::SaveArg<0>(&open_args));
   password_autofill_manager_->OnShowPasswordSuggestions(
-      base::i18n::RIGHT_TO_LEFT, test_username_, 0, element_bounds);
+      base::i18n::RIGHT_TO_LEFT, test_username_,
+      autofill::ShowPasswordSuggestionsOptions(), element_bounds);
   EXPECT_THAT(open_args.suggestions,
               SuggestionVectorValuesAre(
                   ElementsAre(test_username_, GetManagePasswordsTitle())));
@@ -1421,7 +1429,8 @@
   EXPECT_CALL(autofill_client, ShowAutofillPopup)
       .WillOnce(testing::SaveArg<0>(&open_args));
   password_autofill_manager_->OnShowPasswordSuggestions(
-      base::i18n::RIGHT_TO_LEFT, base::string16(), false, element_bounds);
+      base::i18n::RIGHT_TO_LEFT, base::string16(),
+      autofill::ShowPasswordSuggestionsOptions(), element_bounds);
   ASSERT_THAT(open_args.suggestions.size(),
               testing::Ge(1u));  // No footer on Android.
   EXPECT_THAT(open_args.suggestions[0].store_indicator_icon, "google");
diff --git a/components/password_manager/core/browser/password_generation_manager.h b/components/password_manager/core/browser/password_generation_manager.h
index 1bd4758..f588bf5 100644
--- a/components/password_manager/core/browser/password_generation_manager.h
+++ b/components/password_manager/core/browser/password_generation_manager.h
@@ -21,7 +21,7 @@
 
 class PasswordGenerationManager {
  public:
-  PasswordGenerationManager(PasswordManagerClient* client);
+  explicit PasswordGenerationManager(PasswordManagerClient* client);
   ~PasswordGenerationManager();
   PasswordGenerationManager(const PasswordGenerationManager& rhs) = delete;
   PasswordGenerationManager& operator=(const PasswordGenerationManager&) =
diff --git a/components/password_manager/core/browser/password_manager_client.h b/components/password_manager/core/browser/password_manager_client.h
index 189fd2cd..2586670 100644
--- a/components/password_manager/core/browser/password_manager_client.h
+++ b/components/password_manager/core/browser/password_manager_client.h
@@ -93,8 +93,8 @@
   using CredentialsCallback = base::OnceCallback<void(const PasswordForm*)>;
   using ReauthSucceeded = base::StrongAlias<class ReauthSucceededTag, bool>;
 
-  PasswordManagerClient() {}
-  virtual ~PasswordManagerClient() {}
+  PasswordManagerClient() = default;
+  virtual ~PasswordManagerClient() = default;
 
   // Is saving new data for password autofill and filling of saved data enabled
   // for the current profile and page? For example, saving is disabled in
diff --git a/components/password_manager/core/browser/password_manager_test_utils.h b/components/password_manager/core/browser/password_manager_test_utils.h
index 2f8081b..028c28b 100644
--- a/components/password_manager/core/browser/password_manager_test_utils.h
+++ b/components/password_manager/core/browser/password_manager_test_utils.h
@@ -125,13 +125,13 @@
     : public ::testing::MatcherInterface<base::Optional<PasswordHashData>> {
  public:
   explicit PasswordHashDataMatcher(base::Optional<PasswordHashData> expected);
-  virtual ~PasswordHashDataMatcher() {}
+  ~PasswordHashDataMatcher() override = default;
 
   // ::testing::MatcherInterface overrides
-  virtual bool MatchAndExplain(base::Optional<PasswordHashData> hash_data,
-                               ::testing::MatchResultListener* listener) const;
-  virtual void DescribeTo(::std::ostream* os) const;
-  virtual void DescribeNegationTo(::std::ostream* os) const;
+  bool MatchAndExplain(base::Optional<PasswordHashData> hash_data,
+                       ::testing::MatchResultListener* listener) const override;
+  void DescribeTo(::std::ostream* os) const override;
+  void DescribeNegationTo(::std::ostream* os) const override;
 
  private:
   const base::Optional<PasswordHashData> expected_;
diff --git a/components/password_manager/core/browser/password_manager_unittest.cc b/components/password_manager/core/browser/password_manager_unittest.cc
index d9f41de..81a781f 100644
--- a/components/password_manager/core/browser/password_manager_unittest.cc
+++ b/components/password_manager/core/browser/password_manager_unittest.cc
@@ -341,13 +341,13 @@
     bool enable_passwords_account_storage = GetParam();
     if (enable_passwords_account_storage) {
       feature_list_.InitWithFeatures(
-          /*enable_features=*/{features::kPasswordReuseDetectionEnabled,
-                               features::kEnablePasswordsAccountStorage},
-          /*disable_features=*/{});
+          /*enabled_features=*/{features::kPasswordReuseDetectionEnabled,
+                                features::kEnablePasswordsAccountStorage},
+          /*disabled_features=*/{});
     } else {
       feature_list_.InitWithFeatures(
-          /*enable_features=*/{features::kPasswordReuseDetectionEnabled},
-          /*disable_features=*/{features::kEnablePasswordsAccountStorage});
+          /*enabled_features=*/{features::kPasswordReuseDetectionEnabled},
+          /*disabled_features=*/{features::kEnablePasswordsAccountStorage});
     }
   }
   ~PasswordManagerTest() override = default;
diff --git a/components/password_manager/core/browser/password_reuse_detector_unittest.cc b/components/password_manager/core/browser/password_reuse_detector_unittest.cc
index b7caf40..1e7958c 100644
--- a/components/password_manager/core/browser/password_reuse_detector_unittest.cc
+++ b/components/password_manager/core/browser/password_reuse_detector_unittest.cc
@@ -89,7 +89,7 @@
   for (const auto& password : passwords) {
     PasswordHashData password_hash("username_" + password,
                                    ASCIIToUTF16(password),
-                                   /*is_gaia_password=*/true);
+                                   /*force_update=*/true);
     result.push_back(password_hash);
   }
   return result;
@@ -101,7 +101,7 @@
   for (const auto& password : passwords) {
     PasswordHashData password_hash("enterpriseUsername_" + password,
                                    ASCIIToUTF16(password),
-                                   /*is_gaia_password=*/false);
+                                   /*force_update=*/false);
     result.push_back(password_hash);
   }
   return result;
diff --git a/components/password_manager/core/browser/password_save_manager_impl.h b/components/password_manager/core/browser/password_save_manager_impl.h
index 7368eab..b3ece36 100644
--- a/components/password_manager/core/browser/password_save_manager_impl.h
+++ b/components/password_manager/core/browser/password_save_manager_impl.h
@@ -21,7 +21,7 @@
 
 class PasswordSaveManagerImpl : public PasswordSaveManager {
  public:
-  PasswordSaveManagerImpl(std::unique_ptr<FormSaver> form_saver);
+  explicit PasswordSaveManagerImpl(std::unique_ptr<FormSaver> form_saver);
   ~PasswordSaveManagerImpl() override;
 
   // Returns a MultiStorePasswordSaveManager if the password account storage
diff --git a/components/password_manager/core/browser/password_store_change.h b/components/password_manager/core/browser/password_store_change.h
index dd2db7ed..8070a7f3a 100644
--- a/components/password_manager/core/browser/password_store_change.h
+++ b/components/password_manager/core/browser/password_store_change.h
@@ -37,7 +37,7 @@
   PasswordStoreChange(PasswordStoreChange&& other) = default;
   PasswordStoreChange& operator=(const PasswordStoreChange& change) = default;
   PasswordStoreChange& operator=(PasswordStoreChange&& change) = default;
-  virtual ~PasswordStoreChange() {}
+  ~PasswordStoreChange() = default;
 
   Type type() const { return type_; }
   const PasswordForm& form() const { return form_; }
diff --git a/components/password_manager/core/browser/password_store_unittest.cc b/components/password_manager/core/browser/password_store_unittest.cc
index 724ea9b..4125f49 100644
--- a/components/password_manager/core/browser/password_store_unittest.cc
+++ b/components/password_manager/core/browser/password_store_unittest.cc
@@ -1666,6 +1666,9 @@
   testing::Mock::VerifyAndClearExpectations(&consumer);
 
   store->RemoveCompromisedCredentialsByUrlAndTime(
+      // Can't use the generic `std::not_equal_to<>` here, because BindRepeating
+      // does not support functors with an overloaded call operator.
+      // NOLINTNEXTLINE(modernize-use-transparent-functors)
       base::BindRepeating(std::not_equal_to<GURL>(),
                           GURL(compromised_credentials3.signon_realm)),
       base::Time::FromTimeT(150), base::Time::FromTimeT(350),
diff --git a/components/password_manager/core/browser/statistics_table.cc b/components/password_manager/core/browser/statistics_table.cc
index b291001..24089a8 100644
--- a/components/password_manager/core/browser/statistics_table.cc
+++ b/components/password_manager/core/browser/statistics_table.cc
@@ -48,8 +48,7 @@
          lhs.update_time == rhs.update_time;
 }
 
-StatisticsTable::StatisticsTable() : db_(nullptr) {
-}
+StatisticsTable::StatisticsTable() = default;
 
 StatisticsTable::~StatisticsTable() = default;
 
diff --git a/components/password_manager/core/browser/statistics_table.h b/components/password_manager/core/browser/statistics_table.h
index 9295dec..58ae104 100644
--- a/components/password_manager/core/browser/statistics_table.h
+++ b/components/password_manager/core/browser/statistics_table.h
@@ -79,7 +79,7 @@
   int GetNumAccounts();
 
  private:
-  sql::Database* db_;
+  sql::Database* db_ = nullptr;
 
   DISALLOW_COPY_AND_ASSIGN(StatisticsTable);
 };
diff --git a/components/password_manager/core/browser/statistics_table_unittest.cc b/components/password_manager/core/browser/statistics_table_unittest.cc
index dc4228bd..5919549 100644
--- a/components/password_manager/core/browser/statistics_table_unittest.cc
+++ b/components/password_manager/core/browser/statistics_table_unittest.cc
@@ -150,6 +150,9 @@
   // Remove the entries with the timestamp 2 that are NOT matching
   // |kTestDomain3|.
   EXPECT_TRUE(db()->RemoveStatsByOriginAndTime(
+      // Can't use the generic `std::not_equal_to<>` here, because BindRepeating
+      // does not support functors with an overloaded call operator.
+      // NOLINTNEXTLINE(modernize-use-transparent-functors)
       base::BindRepeating(std::not_equal_to<GURL>(), stats3.origin_domain),
       base::Time::FromTimeT(2), base::Time()));
   EXPECT_THAT(db()->GetAllRows(), ElementsAre(stats3));
diff --git a/components/password_manager/core/browser/sync/password_sync_bridge_unittest.cc b/components/password_manager/core/browser/sync/password_sync_bridge_unittest.cc
index 31a6f3b..32d77f7 100644
--- a/components/password_manager/core/browser/sync/password_sync_bridge_unittest.cc
+++ b/components/password_manager/core/browser/sync/password_sync_bridge_unittest.cc
@@ -367,12 +367,15 @@
   ON_CALL(mock_processor(), IsTrackingMetadata()).WillByDefault(Return(true));
 
   PasswordStoreChangeList changes;
-  changes.push_back(PasswordStoreChange(
-      PasswordStoreChange::ADD, MakePasswordForm(kSignonRealm1), /*id=*/1));
-  changes.push_back(PasswordStoreChange(
-      PasswordStoreChange::UPDATE, MakePasswordForm(kSignonRealm2), /*id=*/2));
-  changes.push_back(PasswordStoreChange(
-      PasswordStoreChange::REMOVE, MakePasswordForm(kSignonRealm3), /*id=*/3));
+  changes.push_back(PasswordStoreChange(PasswordStoreChange::ADD,
+                                        MakePasswordForm(kSignonRealm1),
+                                        /*primary_key=*/1));
+  changes.push_back(PasswordStoreChange(PasswordStoreChange::UPDATE,
+                                        MakePasswordForm(kSignonRealm2),
+                                        /*primary_key=*/2));
+  changes.push_back(PasswordStoreChange(PasswordStoreChange::REMOVE,
+                                        MakePasswordForm(kSignonRealm3),
+                                        /*primary_key=*/3));
   PasswordStoreSync::MetadataStore* store =
       mock_password_store_sync()->GetMetadataStore();
   EXPECT_CALL(mock_processor(),
@@ -392,12 +395,15 @@
   ON_CALL(mock_processor(), IsTrackingMetadata()).WillByDefault(Return(false));
 
   PasswordStoreChangeList changes;
-  changes.push_back(PasswordStoreChange(
-      PasswordStoreChange::ADD, MakePasswordForm(kSignonRealm1), /*id=*/1));
-  changes.push_back(PasswordStoreChange(
-      PasswordStoreChange::UPDATE, MakePasswordForm(kSignonRealm2), /*id=*/2));
-  changes.push_back(PasswordStoreChange(
-      PasswordStoreChange::REMOVE, MakePasswordForm(kSignonRealm3), /*id=*/3));
+  changes.push_back(PasswordStoreChange(PasswordStoreChange::ADD,
+                                        MakePasswordForm(kSignonRealm1),
+                                        /*primary_key=*/1));
+  changes.push_back(PasswordStoreChange(PasswordStoreChange::UPDATE,
+                                        MakePasswordForm(kSignonRealm2),
+                                        /*primary_key=*/2));
+  changes.push_back(PasswordStoreChange(PasswordStoreChange::REMOVE,
+                                        MakePasswordForm(kSignonRealm3),
+                                        /*primary_key=*/3));
 
   EXPECT_CALL(mock_processor(), Put).Times(0);
   EXPECT_CALL(mock_processor(), Delete).Times(0);
diff --git a/components/password_manager/core/browser/sync_credentials_filter_unittest.cc b/components/password_manager/core/browser/sync_credentials_filter_unittest.cc
index bbbb0c68..18fddf5 100644
--- a/components/password_manager/core/browser/sync_credentials_filter_unittest.cc
+++ b/components/password_manager/core/browser/sync_credentials_filter_unittest.cc
@@ -108,13 +108,13 @@
   CredentialsFilterTest() : pending_(SimpleGaiaForm("user@gmail.com")) {
     if (GetParam()) {
       feature_list_.InitWithFeatures(
-          /*enable_features=*/{features::kPasswordReuseDetectionEnabled,
-                               features::kEnablePasswordsAccountStorage},
-          /*disable_features=*/{});
+          /*enabled_features=*/{features::kPasswordReuseDetectionEnabled,
+                                features::kEnablePasswordsAccountStorage},
+          /*disabled_features=*/{});
     } else {
       feature_list_.InitWithFeatures(
-          /*enable_features=*/{features::kPasswordReuseDetectionEnabled},
-          /*disable_features=*/{features::kEnablePasswordsAccountStorage});
+          /*enabled_features=*/{features::kPasswordReuseDetectionEnabled},
+          /*disabled_features=*/{features::kEnablePasswordsAccountStorage});
     }
 
     client_ = std::make_unique<FakePasswordManagerClient>(identity_manager());
diff --git a/components/password_manager/core/browser/ui/credential_provider_interface.h b/components/password_manager/core/browser/ui/credential_provider_interface.h
index cb4b71d..7fc52ac 100644
--- a/components/password_manager/core/browser/ui/credential_provider_interface.h
+++ b/components/password_manager/core/browser/ui/credential_provider_interface.h
@@ -21,7 +21,7 @@
   virtual std::vector<std::unique_ptr<PasswordForm>> GetAllPasswords() = 0;
 
  protected:
-  virtual ~CredentialProviderInterface() {}
+  virtual ~CredentialProviderInterface() = default;
 };
 
 }  // namespace password_manager
diff --git a/components/password_manager/core/browser/ui/credential_utils.h b/components/password_manager/core/browser/ui/credential_utils.h
index b9d1cc53..cad7648 100644
--- a/components/password_manager/core/browser/ui/credential_utils.h
+++ b/components/password_manager/core/browser/ui/credential_utils.h
@@ -21,11 +21,11 @@
 // Simple struct that stores a canonicalized credential. Allows implicit
 // constructon from PasswordForm and LeakCheckCredentail for convenience.
 struct CanonicalizedCredential {
-  CanonicalizedCredential(const PasswordForm& form)
+  CanonicalizedCredential(const PasswordForm& form)  // NOLINT
       : canonicalized_username(CanonicalizeUsername(form.username_value)),
         password(form.password_value) {}
 
-  CanonicalizedCredential(const LeakCheckCredential& credential)
+  CanonicalizedCredential(const LeakCheckCredential& credential)  // NOLINT
       : canonicalized_username(CanonicalizeUsername(credential.username())),
         password(credential.password()) {}
 
diff --git a/components/password_manager/core/browser/ui/export_flow.h b/components/password_manager/core/browser/ui/export_flow.h
index b445cfc..2681968 100644
--- a/components/password_manager/core/browser/ui/export_flow.h
+++ b/components/password_manager/core/browser/ui/export_flow.h
@@ -25,7 +25,7 @@
   virtual password_manager::ExportProgressStatus GetExportProgressStatus() = 0;
 
  protected:
-  virtual ~ExportFlow() {}
+  virtual ~ExportFlow() = default;
 };
 
 }  // namespace password_manager
diff --git a/components/password_manager/core/browser/ui/import_flow.h b/components/password_manager/core/browser/ui/import_flow.h
index 3408517..a481028 100644
--- a/components/password_manager/core/browser/ui/import_flow.h
+++ b/components/password_manager/core/browser/ui/import_flow.h
@@ -14,7 +14,7 @@
   virtual void Load() = 0;
 
  protected:
-  virtual ~ImportFlow() {}
+  virtual ~ImportFlow() = default;
 };
 
 }  // namespace password_manager
diff --git a/components/password_manager/core/common/credential_manager_types.cc b/components/password_manager/core/common/credential_manager_types.cc
index dd7f47b..75bb3bb 100644
--- a/components/password_manager/core/common/credential_manager_types.cc
+++ b/components/password_manager/core/common/credential_manager_types.cc
@@ -27,8 +27,7 @@
   return os << CredentialTypeToString(value);
 }
 
-CredentialInfo::CredentialInfo() : type(CredentialType::CREDENTIAL_TYPE_EMPTY) {
-}
+CredentialInfo::CredentialInfo() = default;
 
 CredentialInfo::CredentialInfo(CredentialType type,
                                base::Optional<base::string16> id,
diff --git a/components/password_manager/core/common/credential_manager_types.h b/components/password_manager/core/common/credential_manager_types.h
index 3887e35d..3c45a8d7 100644
--- a/components/password_manager/core/common/credential_manager_types.h
+++ b/components/password_manager/core/common/credential_manager_types.h
@@ -56,7 +56,7 @@
 
   bool operator==(const CredentialInfo& rhs) const;
 
-  CredentialType type;
+  CredentialType type = CredentialType::CREDENTIAL_TYPE_EMPTY;
 
   // An identifier (username, email address, etc). Corresponds to
   // WebCredential's id property.
diff --git a/components/performance_manager/BUILD.gn b/components/performance_manager/BUILD.gn
index e13839a..083e79d 100644
--- a/components/performance_manager/BUILD.gn
+++ b/components/performance_manager/BUILD.gn
@@ -33,6 +33,8 @@
     "execution_context_priority/boosting_vote_aggregator.cc",
     "execution_context_priority/boosting_vote_aggregator.h",
     "execution_context_priority/execution_context_priority.cc",
+    "execution_context_priority/execution_context_priority_decorator.cc",
+    "execution_context_priority/execution_context_priority_decorator.h",
     "execution_context_priority/frame_visibility_voter.cc",
     "execution_context_priority/frame_visibility_voter.h",
     "execution_context_priority/max_vote_aggregator.cc",
diff --git a/components/performance_manager/embedder/graph_features_helper.h b/components/performance_manager/embedder/graph_features_helper.h
index 785626f..679aab3 100644
--- a/components/performance_manager/embedder/graph_features_helper.h
+++ b/components/performance_manager/embedder/graph_features_helper.h
@@ -24,6 +24,7 @@
       // (1) Add a corresponding EnableFeatureFoo() member function.
       // (2) Add the feature to EnableDefault() if necessary.
       // (3) Add the feature to the implementation of ConfigureGraph().
+      bool execution_context_priority_decorator : 1;
       bool execution_context_registry : 1;
       bool frame_node_impl_describer : 1;
       bool frame_visibility_decorator : 1;
@@ -42,6 +43,12 @@
   constexpr GraphFeaturesHelper(const GraphFeaturesHelper& other) = default;
   GraphFeaturesHelper& operator=(const GraphFeaturesHelper& other) = default;
 
+  constexpr GraphFeaturesHelper& EnableExecutionContextPriorityDecorator() {
+    EnableExecutionContextRegistry();
+    flags_.execution_context_priority_decorator = true;
+    return *this;
+  }
+
   constexpr GraphFeaturesHelper& EnableExecutionContextRegistry() {
     flags_.execution_context_registry = true;
     return *this;
diff --git a/components/performance_manager/execution_context_priority/execution_context_priority_decorator.cc b/components/performance_manager/execution_context_priority/execution_context_priority_decorator.cc
new file mode 100644
index 0000000..52c7d98
--- /dev/null
+++ b/components/performance_manager/execution_context_priority/execution_context_priority_decorator.cc
@@ -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.
+
+#include "components/performance_manager/execution_context_priority/execution_context_priority_decorator.h"
+
+namespace performance_manager {
+namespace execution_context_priority {
+
+ExecutionContextPriorityDecorator::ExecutionContextPriorityDecorator() {
+  // The following schema describes the structure of the voting tree. Arrows are
+  // voting channels.
+  //
+  // Note: |ad_frame_voter_| is currently the only downvoter but there could
+  // possibly be more should the need arise. Their votes would be aggregated
+  // using some sort of MinVoteAggregator.
+  //
+  //            |root_vote_observer_|
+  //                     ^
+  //                     |
+  //         |override_vote_aggregator_|
+  //            ^                  ^
+  //            | (override)       | (default)
+  //            |                  |
+  //        Downvoter         |max_vote_aggregator_|
+  //                              ^    ^        ^
+  //                             /     |         \
+  //                            /      |          \
+  //                         Voter1, Voter2, ..., VoterN
+  //
+  // Set up the voting tree from top to bottom.
+  override_vote_aggregator_.SetUpstreamVotingChannel(
+      root_vote_observer_.GetVotingChannel());
+  max_vote_aggregator_.SetUpstreamVotingChannel(
+      override_vote_aggregator_.GetDefaultVotingChannel());
+
+  // Set up downvoter.
+  ad_frame_voter_.SetVotingChannel(
+      override_vote_aggregator_.GetOverrideVotingChannel());
+
+  // Set up voters.
+  frame_visibility_voter_.SetVotingChannel(
+      max_vote_aggregator_.GetVotingChannel());
+}
+ExecutionContextPriorityDecorator::~ExecutionContextPriorityDecorator() =
+    default;
+
+void ExecutionContextPriorityDecorator::OnPassedToGraph(Graph* graph) {
+  // Subscribe voters to the graph.
+  graph->AddFrameNodeObserver(&ad_frame_voter_);
+  graph->AddFrameNodeObserver(&frame_visibility_voter_);
+}
+
+void ExecutionContextPriorityDecorator::OnTakenFromGraph(Graph* graph) {
+  // Unsubscribe voters from the graph.
+  graph->RemoveFrameNodeObserver(&frame_visibility_voter_);
+  graph->RemoveFrameNodeObserver(&ad_frame_voter_);
+}
+
+}  // namespace execution_context_priority
+}  // namespace performance_manager
diff --git a/components/performance_manager/execution_context_priority/execution_context_priority_decorator.h b/components/performance_manager/execution_context_priority/execution_context_priority_decorator.h
new file mode 100644
index 0000000..e4208ae
--- /dev/null
+++ b/components/performance_manager/execution_context_priority/execution_context_priority_decorator.h
@@ -0,0 +1,60 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef COMPONENTS_PERFORMANCE_MANAGER_EXECUTION_CONTEXT_PRIORITY_EXECUTION_CONTEXT_PRIORITY_DECORATOR_H_
+#define COMPONENTS_PERFORMANCE_MANAGER_EXECUTION_CONTEXT_PRIORITY_EXECUTION_CONTEXT_PRIORITY_DECORATOR_H_
+
+#include "components/performance_manager/execution_context_priority/ad_frame_voter.h"
+#include "components/performance_manager/execution_context_priority/frame_visibility_voter.h"
+#include "components/performance_manager/execution_context_priority/max_vote_aggregator.h"
+#include "components/performance_manager/execution_context_priority/override_vote_aggregator.h"
+#include "components/performance_manager/execution_context_priority/root_vote_observer.h"
+#include "components/performance_manager/public/graph/graph.h"
+
+namespace performance_manager {
+namespace execution_context_priority {
+
+// The ExecutionContextPriorityDecorator's responsibility is to own the voting
+// system that assigns the priority of every frame and worker in the graph.
+//
+// See the README.md for more details on the voting system.
+class ExecutionContextPriorityDecorator final : public GraphOwned {
+ public:
+  ExecutionContextPriorityDecorator();
+  ~ExecutionContextPriorityDecorator() override;
+
+  ExecutionContextPriorityDecorator(const ExecutionContextPriorityDecorator&) =
+      delete;
+  ExecutionContextPriorityDecorator& operator=(
+      const ExecutionContextPriorityDecorator&) = delete;
+
+ private:
+  void OnPassedToGraph(Graph* graph) override;
+  void OnTakenFromGraph(Graph* graph) override;
+
+  // Takes in the aggregated votes and applies them to the execution contexts in
+  // the graph.
+  RootVoteObserver root_vote_observer_;
+
+  // Used to cast a negative vote that overrides the vote from
+  // |max_vote_aggregator_|.
+  OverrideVoteAggregator override_vote_aggregator_;
+
+  // Aggregates all the votes from the voters.
+  MaxVoteAggregator max_vote_aggregator_;
+
+  // Note: Voters should be added below this line so that they are destroyed
+  //       before the aggregators.
+
+  // Casts a downvote for ad frames.
+  AdFrameVoter ad_frame_voter_;
+
+  // Casts a USER_VISIBLE vote when a frame is visible.
+  FrameVisibilityVoter frame_visibility_voter_;
+};
+
+}  // namespace execution_context_priority
+}  // namespace performance_manager
+
+#endif  // COMPONENTS_PERFORMANCE_MANAGER_EXECUTION_CONTEXT_PRIORITY_EXECUTION_CONTEXT_PRIORITY_DECORATOR_H_
diff --git a/components/performance_manager/graph_features_helper.cc b/components/performance_manager/graph_features_helper.cc
index 37691c2..d0dd4f32 100644
--- a/components/performance_manager/graph_features_helper.cc
+++ b/components/performance_manager/graph_features_helper.cc
@@ -10,6 +10,7 @@
 #include "components/performance_manager/decorators/frame_visibility_decorator.h"
 #include "components/performance_manager/decorators/page_load_tracker_decorator.h"
 #include "components/performance_manager/execution_context/execution_context_registry_impl.h"
+#include "components/performance_manager/execution_context_priority/execution_context_priority_decorator.h"
 #include "components/performance_manager/graph/frame_node_impl_describer.h"
 #include "components/performance_manager/graph/page_node_impl_describer.h"
 #include "components/performance_manager/graph/process_node_impl_describer.h"
@@ -59,10 +60,14 @@
     Install<SiteDataRecorder>(graph);
 #endif
 
-  // This class has a dependency on ExecutionContextRegistry, so must be
+  // These classes have a dependency on ExecutionContextRegistry, so must be
   // installed after it.
+  if (flags_.execution_context_priority_decorator) {
+    Install<execution_context_priority::ExecutionContextPriorityDecorator>(
+        graph);
+  }
   if (flags_.v8_context_tracker)
     Install<v8_memory::V8ContextTracker>(graph);
 }
 
-}  // namespace performance_manager
\ No newline at end of file
+}  // namespace performance_manager
diff --git a/components/printing/browser/print_manager.cc b/components/printing/browser/print_manager.cc
index 9e9c8c11..84f3e05 100644
--- a/components/printing/browser/print_manager.cc
+++ b/components/printing/browser/print_manager.cc
@@ -22,53 +22,8 @@
                        IPC::Message* reply_msg) {
     manager->OnScriptedPrint(render_frame_host, scripted_params, reply_msg);
   }
-
-  void OnDidPrintDocument(const mojom::DidPrintDocumentParams& params,
-                          IPC::Message* reply_msg) {
-    // If DidPrintDocument message was received then need to transition from
-    // a variable allocated on stack (which has efficient memory management
-    // when dealing with any other incoming message) to a persistent variable
-    // on the heap that can be referenced by the asynchronous processing which
-    // occurs beyond the scope of PrintViewManagerBase::OnMessageReceived().
-    manager->OnDidPrintDocument(
-        render_frame_host, params,
-        std::make_unique<DelayedFrameDispatchHelper>(
-            manager->web_contents(), render_frame_host, reply_msg));
-  }
 };
 
-PrintManager::DelayedFrameDispatchHelper::DelayedFrameDispatchHelper(
-    content::WebContents* contents,
-    content::RenderFrameHost* render_frame_host,
-    IPC::Message* reply_msg)
-    : content::WebContentsObserver(contents),
-      render_frame_host_(render_frame_host),
-      reply_msg_(reply_msg) {}
-
-PrintManager::DelayedFrameDispatchHelper::~DelayedFrameDispatchHelper() {
-  if (reply_msg_) {
-    PrintHostMsg_DidPrintDocument::WriteReplyParams(reply_msg_, false);
-    render_frame_host_->Send(reply_msg_);
-  }
-}
-
-void PrintManager::DelayedFrameDispatchHelper::SendCompleted() {
-  if (!reply_msg_)
-    return;
-
-  PrintHostMsg_DidPrintDocument::WriteReplyParams(reply_msg_, true);
-  render_frame_host_->Send(reply_msg_);
-
-  // This wraps up the one allowed reply for the message.
-  reply_msg_ = nullptr;
-}
-
-void PrintManager::DelayedFrameDispatchHelper::RenderFrameDeleted(
-    content::RenderFrameHost* render_frame_host) {
-  if (render_frame_host == render_frame_host_)
-    reply_msg_ = nullptr;
-}
-
 PrintManager::PrintManager(content::WebContents* contents)
     : content::WebContentsObserver(contents),
       print_manager_host_receivers_(contents, this) {}
@@ -83,8 +38,6 @@
   IPC_BEGIN_MESSAGE_MAP(PrintManager, message)
     IPC_MESSAGE_FORWARD_DELAY_REPLY(PrintHostMsg_ScriptedPrint, &helper,
                                     FrameDispatchHelper::OnScriptedPrint)
-    IPC_MESSAGE_FORWARD_DELAY_REPLY(PrintHostMsg_DidPrintDocument, &helper,
-                                    FrameDispatchHelper::OnDidPrintDocument);
     IPC_MESSAGE_UNHANDLED(handled = false)
   IPC_END_MESSAGE_MAP()
   return handled;
@@ -122,6 +75,11 @@
 
 void PrintManager::DidShowPrintDialog() {}
 
+void PrintManager::DidPrintDocument(mojom::DidPrintDocumentParamsPtr params,
+                                    DidPrintDocumentCallback callback) {
+  std::move(callback).Run(false);
+}
+
 void PrintManager::ShowInvalidPrinterSettingsError() {}
 
 void PrintManager::PrintingFailed(int32_t cookie) {
diff --git a/components/printing/browser/print_manager.h b/components/printing/browser/print_manager.h
index dc3dbb5..72765e53 100644
--- a/components/printing/browser/print_manager.h
+++ b/components/printing/browser/print_manager.h
@@ -47,6 +47,8 @@
   // printing::mojom::PrintManagerHost:
   void DidGetPrintedPagesCount(int32_t cookie, uint32_t number_pages) override;
   void DidGetDocumentCookie(int32_t cookie) override;
+  void DidPrintDocument(mojom::DidPrintDocumentParamsPtr params,
+                        DidPrintDocumentCallback callback) override;
 #if BUILDFLAG(ENABLE_TAGGED_PDF)
   void SetAccessibilityTree(
       int32_t cookie,
@@ -78,38 +80,7 @@
   // IPC handling support
   struct FrameDispatchHelper;
 
-  // IPC message PrintHostMsg_DidPrintDocument can require handling in other
-  // processes beyond the rendering process running OnMessageReceived(),
-  // requiring that the renderer needs to wait.
-  class DelayedFrameDispatchHelper : public content::WebContentsObserver {
-   public:
-    DelayedFrameDispatchHelper(content::WebContents* contents,
-                               content::RenderFrameHost* render_frame_host,
-                               IPC::Message* reply_msg);
-    DelayedFrameDispatchHelper(const DelayedFrameDispatchHelper&) = delete;
-    ~DelayedFrameDispatchHelper() override;
-    DelayedFrameDispatchHelper& operator=(const DelayedFrameDispatchHelper&) =
-        delete;
-
-    // content::WebContentsObserver
-    void RenderFrameDeleted(
-        content::RenderFrameHost* render_frame_host) override;
-
-    // SendCompleted() can be called at most once, since it provides the success
-    // reply for a message. A failure reply for the message is automatically
-    // sent if this is never called.
-    void SendCompleted();
-
-   private:
-    content::RenderFrameHost* const render_frame_host_;
-    IPC::Message* reply_msg_;
-  };
-
   // IPC handlers
-  virtual void OnDidPrintDocument(
-      content::RenderFrameHost* render_frame_host,
-      const mojom::DidPrintDocumentParams& params,
-      std::unique_ptr<DelayedFrameDispatchHelper> helper) = 0;
   virtual void OnScriptedPrint(content::RenderFrameHost* render_frame_host,
                                const mojom::ScriptedPrintParams& params,
                                IPC::Message* reply_msg) = 0;
diff --git a/components/printing/common/print.mojom b/components/printing/common/print.mojom
index bcd40171..2c19fe7 100644
--- a/components/printing/common/print.mojom
+++ b/components/printing/common/print.mojom
@@ -302,6 +302,12 @@
   // Tells the browser that the print dialog has been shown.
   DidShowPrintDialog();
 
+  // Sends back to the browser the rendered document that was requested by a
+  // PrintRequestedPages() or from scripted printing. Waits until the document
+  // is ready before replying.
+  [Sync]
+  DidPrintDocument(DidPrintDocumentParams params) => (bool completed);
+
   // Tells the browser that there are invalid printer settings.
   ShowInvalidPrinterSettingsError();
 
diff --git a/components/printing/common/print_messages.h b/components/printing/common/print_messages.h
index cb8f067b..80c98a5 100644
--- a/components/printing/common/print_messages.h
+++ b/components/printing/common/print_messages.h
@@ -267,15 +267,6 @@
 
 // Messages sent from the renderer to the browser.
 
-// Sends back to the browser the rendered document that was requested by a
-// PrintMsg_PrintPages message or from scripted printing. The memory handle in
-// this message is already valid in the browser process. Waits until the
-// document is complete ready before replying.
-IPC_SYNC_MESSAGE_ROUTED1_1(PrintHostMsg_DidPrintDocument,
-                           printing::mojom::DidPrintDocumentParams
-                           /* page content */,
-                           bool /* completed */)
-
 // It's the renderer that controls the printing process when it is generated
 // by javascript. This step is about showing UI to the user to select the
 // final print settings. The output parameter is the same as
diff --git a/components/printing/renderer/print_render_frame_helper.cc b/components/printing/renderer/print_render_frame_helper.cc
index a48331f..07c5205 100644
--- a/components/printing/renderer/print_render_frame_helper.cc
+++ b/components/printing/renderer/print_render_frame_helper.cc
@@ -2010,13 +2010,14 @@
     snapshotter->Snapshot(ui::AXMode::kPDF, 0, &metafile.accessibility_tree());
   }
 
-  mojom::DidPrintDocumentParams page_params;
-  page_params.content = mojom::DidPrintContentParams::New();
+  mojom::DidPrintDocumentParamsPtr page_params =
+      mojom::DidPrintDocumentParams::New();
+  page_params->content = mojom::DidPrintContentParams::New();
   gfx::Size* page_size_in_dpi;
   gfx::Rect* content_area_in_dpi;
 #if defined(OS_APPLE) || defined(OS_WIN)
-  page_size_in_dpi = &page_params.page_size;
-  content_area_in_dpi = &page_params.content_area;
+  page_size_in_dpi = &page_params->page_size;
+  content_area_in_dpi = &page_params->content_area;
 #else
   page_size_in_dpi = nullptr;
   content_area_in_dpi = nullptr;
@@ -2036,17 +2037,16 @@
   metafile.FinishDocument();
 
   if (!CopyMetafileDataToReadOnlySharedMem(metafile,
-                                           page_params.content.get())) {
+                                           page_params->content.get())) {
     return false;
   }
 
-  page_params.document_cookie = print_params.document_cookie;
+  page_params->document_cookie = print_params.document_cookie;
 #if defined(OS_WIN)
-  page_params.physical_offsets = printer_printable_area_.origin();
+  page_params->physical_offsets = printer_printable_area_.origin();
 #endif
   bool completed = false;
-  Send(
-      new PrintHostMsg_DidPrintDocument(routing_id(), page_params, &completed));
+  GetPrintManagerHost()->DidPrintDocument(std::move(page_params), &completed);
   return completed;
 }
 
diff --git a/components/printing/test/mock_printer.cc b/components/printing/test/mock_printer.cc
index 6327a03..ebab2e6 100644
--- a/components/printing/test/mock_printer.cc
+++ b/components/printing/test/mock_printer.cc
@@ -204,18 +204,17 @@
   pages_.clear();
 }
 
-void MockPrinter::PrintPage(
-    const printing::mojom::DidPrintDocumentParams& params) {
+void MockPrinter::PrintPage(printing::mojom::DidPrintDocumentParamsPtr params) {
   // Verify the input parameter and update the printer status so that the
   // RenderViewTest class can verify the this function finishes without errors.
   EXPECT_EQ(PRINTER_PRINTING, printer_status_);
-  EXPECT_EQ(document_cookie_, params.document_cookie);
+  EXPECT_EQ(document_cookie_, params->document_cookie);
 
 #if defined(OS_WIN) || defined(OS_APPLE)
   // Load the data sent from a RenderView object and create a PageData object.
-  ASSERT_TRUE(params.content->metafile_data_region.IsValid());
+  ASSERT_TRUE(params->content->metafile_data_region.IsValid());
   base::ReadOnlySharedMemoryMapping mapping =
-      params.content->metafile_data_region.Map();
+      params->content->metafile_data_region.Map();
   ASSERT_TRUE(mapping.IsValid());
   EXPECT_GT(mapping.size(), 0U);
 
diff --git a/components/printing/test/mock_printer.h b/components/printing/test/mock_printer.h
index dd1d9e8..d2f6f0f 100644
--- a/components/printing/test/mock_printer.h
+++ b/components/printing/test/mock_printer.h
@@ -89,7 +89,7 @@
                       int margins_type,
                       const gfx::Size& page_size,
                       int scale_factor);
-  void PrintPage(const printing::mojom::DidPrintDocumentParams& params);
+  void PrintPage(printing::mojom::DidPrintDocumentParamsPtr params);
 
   // Functions that retrieve the output pages.
   Status GetPrinterStatus() const { return printer_status_; }
diff --git a/components/printing/test/print_mock_render_thread.cc b/components/printing/test/print_mock_render_thread.cc
index e6c8058..79575b9 100644
--- a/components/printing/test/print_mock_render_thread.cc
+++ b/components/printing/test/print_mock_render_thread.cc
@@ -51,8 +51,6 @@
   IPC_BEGIN_MESSAGE_MAP(PrintMockRenderThread, msg)
 #if BUILDFLAG(ENABLE_PRINTING)
     IPC_MESSAGE_HANDLER_DELAY_REPLY(PrintHostMsg_ScriptedPrint, OnScriptedPrint)
-    IPC_MESSAGE_HANDLER_DELAY_REPLY(PrintHostMsg_DidPrintDocument,
-                                    OnDidPrintDocument)
 #if BUILDFLAG(ENABLE_PRINT_PREVIEW)
     IPC_MESSAGE_HANDLER(PrintHostMsg_DidStartPreview, OnDidStartPreview)
     IPC_MESSAGE_HANDLER(PrintHostMsg_DidPreviewPage, OnDidPreviewPage)
@@ -79,14 +77,6 @@
   Send(reply_msg);
 }
 
-void PrintMockRenderThread::OnDidPrintDocument(
-    const printing::mojom::DidPrintDocumentParams& params,
-    IPC::Message* reply_msg) {
-  printer_->PrintPage(params);
-  PrintHostMsg_DidPrintDocument::WriteReplyParams(reply_msg, true);
-  Send(reply_msg);
-}
-
 #if BUILDFLAG(ENABLE_PRINT_PREVIEW)
 void PrintMockRenderThread::OnDidStartPreview(
     const printing::mojom::DidStartPreviewParams& params,
diff --git a/components/printing/test/print_mock_render_thread.h b/components/printing/test/print_mock_render_thread.h
index f9561fe..c28a74f 100644
--- a/components/printing/test/print_mock_render_thread.h
+++ b/components/printing/test/print_mock_render_thread.h
@@ -67,9 +67,6 @@
   // PrintRenderFrameHelper expects final print settings from the user.
   void OnScriptedPrint(const printing::mojom::ScriptedPrintParams& params,
                        IPC::Message* reply_msg);
-
-  void OnDidPrintDocument(const printing::mojom::DidPrintDocumentParams& params,
-                          IPC::Message* reply_msg);
 #if BUILDFLAG(ENABLE_PRINT_PREVIEW)
   void OnDidStartPreview(const printing::mojom::DidStartPreviewParams& params,
                          const printing::mojom::PreviewIds& ids);
diff --git a/components/printing/test/print_render_frame_helper_browsertest.cc b/components/printing/test/print_render_frame_helper_browsertest.cc
index e3b4b9d..29be45e 100644
--- a/components/printing/test/print_render_frame_helper_browsertest.cc
+++ b/components/printing/test/print_render_frame_helper_browsertest.cc
@@ -230,6 +230,13 @@
     printer_->SetPrintedPagesCount(cookie, number_pages);
   }
   void DidGetDocumentCookie(int32_t cookie) override {}
+  void DidPrintDocument(mojom::DidPrintDocumentParamsPtr params,
+                        DidPrintDocumentCallback callback) override {
+    base::RunLoop().RunUntilIdle();
+    printer_->PrintPage(std::move(params));
+    std::move(callback).Run(true);
+    is_printed_ = true;
+  }
   void GetDefaultPrintSettings(
       GetDefaultPrintSettingsCallback callback) override {
     printing::mojom::PrintParamsPtr params =
@@ -325,6 +332,7 @@
 
   void DidShowPrintDialog() override {}
 
+  bool IsPrinted() { return is_printed_; }
   void SetExpectedPagesCount(uint32_t number_pages) {
     number_pages_ = number_pages;
   }
@@ -354,6 +362,7 @@
   }
 
   uint32_t number_pages_ = 0;
+  bool is_printed_ = false;
   MockPrinter* printer_;
   base::OnceClosure quit_closure_;
   mojo::AssociatedReceiver<mojom::PrintManagerHost> receiver_{this};
@@ -435,12 +444,11 @@
 #endif  // BUILDFLAG(ENABLE_PRINT_PREVIEW)
 
   // Verifies whether the pages printed or not.
-  void VerifyPagesPrinted(bool expect_printed) {
-    const IPC::Message* print_msg =
-        render_thread_->sink().GetUniqueMessageMatching(
-            PrintHostMsg_DidPrintDocument::ID);
-    bool did_print = !!print_msg;
-    ASSERT_EQ(expect_printed, did_print);
+  void VerifyPagesPrinted(bool expect_printed,
+                          content::RenderFrame* render_frame = nullptr) {
+    if (!render_frame)
+      render_frame = content::RenderFrame::FromWebFrame(GetMainFrame());
+    ASSERT_EQ(expect_printed, print_manager(render_frame)->IsPrinted());
   }
 
   void OnPrintPages() {
@@ -547,9 +555,10 @@
   }
 
   PrintMockRenderThread* print_render_thread() { return print_render_thread_; }
-  TestPrintManagerHost* print_manager() {
-    auto it = frame_to_print_manager_map_.find(
-        content::RenderFrame::FromWebFrame(GetMainFrame()));
+  TestPrintManagerHost* print_manager(content::RenderFrame* frame = nullptr) {
+    if (!frame)
+      frame = content::RenderFrame::FromWebFrame(GetMainFrame());
+    auto it = frame_to_print_manager_map_.find(frame);
     return it->second.get();
   }
 #if BUILDFLAG(ENABLE_PRINT_PREVIEW)
@@ -693,9 +702,11 @@
       "</body>";
 
   LoadHTML(kCloseOnBeforeHtml);
+  content::RenderFrame* sub_render_frame = content::RenderFrame::FromWebFrame(
+      GetMainFrame()->FindFrameByName("sub")->ToWebLocalFrame());
   OnPrintPagesInFrame("sub");
   EXPECT_EQ(nullptr, GetMainFrame()->FindFrameByName("sub"));
-  VerifyPagesPrinted(false);
+  VerifyPagesPrinted(false, sub_render_frame);
 
   ClearPrintManagerHost();
 
@@ -707,9 +718,11 @@
       "</body>";
 
   LoadHTML(kCloseOnAfterHtml);
+  sub_render_frame = content::RenderFrame::FromWebFrame(
+      GetMainFrame()->FindFrameByName("sub")->ToWebLocalFrame());
   OnPrintPagesInFrame("sub");
   EXPECT_EQ(nullptr, GetMainFrame()->FindFrameByName("sub"));
-  VerifyPagesPrinted(true);
+  VerifyPagesPrinted(true, sub_render_frame);
 }
 
 #if defined(OS_APPLE)
diff --git a/components/signin/internal/identity_manager/gaia_cookie_manager_service.cc b/components/signin/internal/identity_manager/gaia_cookie_manager_service.cc
index 7a3934f..3621a01 100644
--- a/components/signin/internal/identity_manager/gaia_cookie_manager_service.cc
+++ b/components/signin/internal/identity_manager/gaia_cookie_manager_service.cc
@@ -47,6 +47,10 @@
 // The maximum number of retries for a fetcher used in this class.
 constexpr int kMaxFetcherRetries = 8;
 
+// Timeout for the ExternalCCResult fetch. See https://crbug.com/750316#c37 for
+// details on the exact duration.
+constexpr int kExternalCCResultTimeoutSeconds = 7;
+
 // In case of an error while fetching using the GaiaAuthFetcher or
 // SimpleURLLoader, retry with exponential backoff. Try up to 7 times within 15
 // minutes.
@@ -248,10 +252,10 @@
   helper_->gaia_auth_fetcher_->StartGetCheckConnectionInfo();
 
   // Some fetches may timeout.  Start a timer to decide when the result fetcher
-  // has waited long enough. See https://crbug.com/750316#c36 for details on
-  // exact timeout duration.
-  timer_.Start(FROM_HERE, base::TimeDelta::FromSeconds(7), this,
-               &GaiaCookieManagerService::ExternalCcResultFetcher::Timeout);
+  // has waited long enough.
+  timer_.Start(
+      FROM_HERE, base::TimeDelta::FromSeconds(kExternalCCResultTimeoutSeconds),
+      this, &GaiaCookieManagerService::ExternalCcResultFetcher::Timeout);
 }
 
 bool GaiaCookieManagerService::ExternalCcResultFetcher::IsRunning() {
diff --git a/components/sync/DIR_METADATA b/components/sync/DIR_METADATA
new file mode 100644
index 0000000..1a6d7ee6
--- /dev/null
+++ b/components/sync/DIR_METADATA
@@ -0,0 +1,3 @@
+monorail {
+  component: "Services>Sync"
+}
diff --git a/components/sync/OWNERS b/components/sync/OWNERS
index 17d71aa..6577ed5 100644
--- a/components/sync/OWNERS
+++ b/components/sync/OWNERS
@@ -6,5 +6,3 @@
 treib@chromium.org
 tschumann@chromium.org
 victorvianna@google.com
-
-# COMPONENT: Services>Sync
diff --git a/components/sync/driver/data_type_manager_impl.cc b/components/sync/driver/data_type_manager_impl.cc
index 2a2e2a4b..62aec7a 100644
--- a/components/sync/driver/data_type_manager_impl.cc
+++ b/components/sync/driver/data_type_manager_impl.cc
@@ -47,10 +47,10 @@
 
 }  // namespace
 
-DataTypeManagerImpl::AssociationTypesInfo::AssociationTypesInfo() {}
+DataTypeManagerImpl::AssociationTypesInfo::AssociationTypesInfo() = default;
 DataTypeManagerImpl::AssociationTypesInfo::AssociationTypesInfo(
     const AssociationTypesInfo& other) = default;
-DataTypeManagerImpl::AssociationTypesInfo::~AssociationTypesInfo() {}
+DataTypeManagerImpl::AssociationTypesInfo::~AssociationTypesInfo() = default;
 
 DataTypeManagerImpl::DataTypeManagerImpl(
     ModelTypeSet initial_types,
@@ -67,8 +67,7 @@
       debug_info_listener_(debug_info_listener),
       model_load_manager_(controllers, this),
       observer_(observer),
-      encryption_handler_(encryption_handler),
-      download_started_(false) {
+      encryption_handler_(encryption_handler) {
   DCHECK(configurer_);
   DCHECK(observer_);
 
@@ -324,7 +323,6 @@
   download_types_queue_ = PrioritizeTypes(last_enabled_types_);
   association_types_info_.reset();
 
-  download_started_ = false;
   model_load_manager_.Initialize(
       /*desired_types=*/last_enabled_types_,
       /*preferred_types=*/last_requested_types_, last_requested_context_);
@@ -333,8 +331,6 @@
 void DataTypeManagerImpl::OnAllDataTypesReadyForConfigure() {
   // TODO(crbug.com/1102837): Should we handle |needs_reconfigure_| here,
   // before even starting the downloads?
-  DCHECK(!download_started_);
-  download_started_ = true;
   // TODO(pavely): By now some of datatypes in |download_types_queue_| could
   // have failed loading and should be excluded from configuration. I need to
   // adjust |download_types_queue_| for such types.
@@ -488,14 +484,12 @@
   DCHECK(download_types_queue_.front() == downloaded_types);
   download_types_queue_.pop();
 
-  // Those types that were already downloaded (non first sync/error types)
-  // are already done. Just finalize the newly downloaded types if necessary.
   if (association_types_info_) {
     // A non-empty |association_types_info_| means there were actually types
-    // downloading. Finalize those.
+    // downloading. Record stats for those.
     association_types_info_->first_sync_types = succeeded_configuration_types;
     association_types_info_->download_ready_time = base::Time::Now();
-    StartNextAssociation(association_types_info_->types);
+    RecordConfigurationStats(association_types_info_->types);
   }
   DCHECK(!association_types_info_);
 
@@ -537,8 +531,10 @@
   association_types_info_->high_priority_types_before =
       high_priority_types_before;
 
-  // Finalize the types that are already downloaded.
-  StartNextAssociation(ready_types);
+  // Record stats for the types that are already downloaded. The remaining types
+  // will be handled once their download finishes (which happens as part of
+  // ConfigureDataTypes).
+  RecordConfigurationStats(ready_types);
 }
 
 ModelTypeSet DataTypeManagerImpl::PrepareConfigureParams(
@@ -641,22 +637,21 @@
   return Difference(active_types, types_to_download);
 }
 
-void DataTypeManagerImpl::StartNextAssociation(
-    ModelTypeSet types_to_associate) {
+void DataTypeManagerImpl::RecordConfigurationStats(ModelTypeSet types) {
   DCHECK(association_types_info_);
   DCHECK(state_ == CONFIGURING);
 
-  for (ModelType type : types_to_associate) {
+  for (ModelType type : types) {
     if (ProtocolTypes().Has(type)) {
-      RecordConfigurationStats(type);
+      RecordConfigurationStatsImpl(type);
     }
   }
 
   // If any pending types weren't covered here, then we're not done yet.
-  if (types_to_associate != association_types_info_->types) {
-    DCHECK_EQ(association_types_info_->ready_types, types_to_associate);
+  if (types != association_types_info_->types) {
+    DCHECK_EQ(association_types_info_->ready_types, types);
     // The remaining types are still downloading; this method will get called
-    // again (with UNREADY_AT_CONFIG) once the download finishes.
+    // again (with the full set of types) once the download finishes.
     DCHECK(association_types_info_->download_ready_time.is_null());
     return;
   }
@@ -685,7 +680,7 @@
   }
 }
 
-void DataTypeManagerImpl::RecordConfigurationStats(ModelType type) {
+void DataTypeManagerImpl::RecordConfigurationStatsImpl(ModelType type) {
   DCHECK(association_types_info_);
 
   if (!debug_info_listener_.IsInitialized())
diff --git a/components/sync/driver/data_type_manager_impl.h b/components/sync/driver/data_type_manager_impl.h
index b6c81ad1..d72eece 100644
--- a/components/sync/driver/data_type_manager_impl.h
+++ b/components/sync/driver/data_type_manager_impl.h
@@ -80,8 +80,6 @@
   };
   using DataTypeConfigStateMap = std::map<ModelType, DataTypeConfigState>;
 
-  void RecordConfigurationStats(ModelType type);
-
   // Return model types in |state_map| that match |state|.
   static ModelTypeSet GetDataTypesInState(
       DataTypeConfigState state,
@@ -142,11 +140,9 @@
   // Will kick off configuration of any new ready types.
   void StartNextDownload(ModelTypeSet high_priority_types_before);
 
-  // Finalize a set of data types that have finished downloading.
-  // TODO(crbug.com/1102837): Simplify and rename this. "Association" doesn't
-  // exist anymore; all this does is record configuration stats and eventually
-  // update |state_|.
-  void StartNextAssociation(ModelTypeSet types_to_associate);
+  void RecordConfigurationStats(ModelTypeSet types);
+
+  void RecordConfigurationStatsImpl(ModelType type);
 
   void StopImpl(ShutdownReason reason);
 
@@ -238,11 +234,6 @@
   // Timing stats of data type configuration.
   std::map<ModelType, DataTypeConfigurationStats> configuration_stats_;
 
-  // Configuration process is started when ModelLoadManager notifies
-  // DataTypeManager that all types are ready for configure.
-  // This flag ensures that this process is started only once.
-  bool download_started_;
-
   base::WeakPtrFactory<DataTypeManagerImpl> weak_ptr_factory_{this};
 
   DISALLOW_COPY_AND_ASSIGN(DataTypeManagerImpl);
diff --git a/components/sync/driver/profile_sync_service.cc b/components/sync/driver/profile_sync_service.cc
index fd92d8f..4ada388 100644
--- a/components/sync/driver/profile_sync_service.cc
+++ b/components/sync/driver/profile_sync_service.cc
@@ -1045,13 +1045,18 @@
       // the next browser startup.
       StopAndClear();
 #if !BUILDFLAG(IS_CHROMEOS_ASH)
-      // On every platform except ChromeOS, sign out the user after a dashboard
-      // clear.
-      if (!IsLocalSyncEnabled()) {
+      // On every platform except ChromeOS, revoke the Sync consent in
+      // IdentityManager after a dashboard clear.
+      if (!IsLocalSyncEnabled() &&
+          identity_manager_->HasPrimaryAccount(signin::ConsentLevel::kSync)) {
         auto* account_mutator = identity_manager_->GetPrimaryAccountMutator();
-
         // GetPrimaryAccountMutator() returns nullptr on ChromeOS only.
         DCHECK(account_mutator);
+
+        // Note that this method is misnamed: It will not actually remove the
+        // primary account, it will just clear the Sync consent bit (i.e. the
+        // account will change from ConsentLevel::kSync to
+        // ConsentLevel::kNotRequired)
         account_mutator->ClearPrimaryAccount(
             signin::PrimaryAccountMutator::ClearAccountsAction::kDefault,
             signin_metrics::SERVER_FORCED_DISABLE,
diff --git a/components/sync_bookmarks/DIR_METADATA b/components/sync_bookmarks/DIR_METADATA
new file mode 100644
index 0000000..36470dc1
--- /dev/null
+++ b/components/sync_bookmarks/DIR_METADATA
@@ -0,0 +1,5 @@
+monorail {
+  component: "Services>Sync"
+}
+
+team_email: "chromium-reviews@chromium.org"
diff --git a/components/sync_bookmarks/OWNERS b/components/sync_bookmarks/OWNERS
index 2453e93..261ab18 100644
--- a/components/sync_bookmarks/OWNERS
+++ b/components/sync_bookmarks/OWNERS
@@ -1,4 +1 @@
 file://components/sync/OWNERS
-
-# COMPONENT: Services>Sync
-# TEAM: chromium-reviews@chromium.org
diff --git a/components/sync_device_info/DIR_METADATA b/components/sync_device_info/DIR_METADATA
new file mode 100644
index 0000000..1a6d7ee6
--- /dev/null
+++ b/components/sync_device_info/DIR_METADATA
@@ -0,0 +1,3 @@
+monorail {
+  component: "Services>Sync"
+}
diff --git a/components/sync_device_info/OWNERS b/components/sync_device_info/OWNERS
index ef97383..261ab18 100644
--- a/components/sync_device_info/OWNERS
+++ b/components/sync_device_info/OWNERS
@@ -1,3 +1 @@
 file://components/sync/OWNERS
-
-# COMPONENT: Services>Sync
diff --git a/components/sync_preferences/DIR_METADATA b/components/sync_preferences/DIR_METADATA
new file mode 100644
index 0000000..8c96537a
--- /dev/null
+++ b/components/sync_preferences/DIR_METADATA
@@ -0,0 +1,5 @@
+monorail {
+  component: "UI>Browser>Preferences"
+}
+
+team_email: "chromium-reviews@chromium.org"
diff --git a/components/sync_preferences/OWNERS b/components/sync_preferences/OWNERS
index 8b22624..5267bb4 100644
--- a/components/sync_preferences/OWNERS
+++ b/components/sync_preferences/OWNERS
@@ -1,6 +1,3 @@
 file://components/sync/OWNERS
 battre@chromium.org
 gab@chromium.org
-
-# COMPONENT: UI>Browser>Preferences
-# TEAM: chromium-reviews@chromium.org
diff --git a/components/sync_sessions/DIR_METADATA b/components/sync_sessions/DIR_METADATA
new file mode 100644
index 0000000..1a6d7ee6
--- /dev/null
+++ b/components/sync_sessions/DIR_METADATA
@@ -0,0 +1,3 @@
+monorail {
+  component: "Services>Sync"
+}
diff --git a/components/sync_sessions/OWNERS b/components/sync_sessions/OWNERS
index ef97383..261ab18 100644
--- a/components/sync_sessions/OWNERS
+++ b/components/sync_sessions/OWNERS
@@ -1,3 +1 @@
 file://components/sync/OWNERS
-
-# COMPONENT: Services>Sync
diff --git a/components/sync_ui_strings_grdp/DIR_METADATA b/components/sync_ui_strings_grdp/DIR_METADATA
new file mode 100644
index 0000000..1a6d7ee6
--- /dev/null
+++ b/components/sync_ui_strings_grdp/DIR_METADATA
@@ -0,0 +1,3 @@
+monorail {
+  component: "Services>Sync"
+}
diff --git a/components/sync_ui_strings_grdp/OWNERS b/components/sync_ui_strings_grdp/OWNERS
index ef97383..261ab18 100644
--- a/components/sync_ui_strings_grdp/OWNERS
+++ b/components/sync_ui_strings_grdp/OWNERS
@@ -1,3 +1 @@
 file://components/sync/OWNERS
-
-# COMPONENT: Services>Sync
diff --git a/components/sync_user_events/DIR_METADATA b/components/sync_user_events/DIR_METADATA
new file mode 100644
index 0000000..1a6d7ee6
--- /dev/null
+++ b/components/sync_user_events/DIR_METADATA
@@ -0,0 +1,3 @@
+monorail {
+  component: "Services>Sync"
+}
diff --git a/components/sync_user_events/OWNERS b/components/sync_user_events/OWNERS
index ef97383..261ab18 100644
--- a/components/sync_user_events/OWNERS
+++ b/components/sync_user_events/OWNERS
@@ -1,3 +1 @@
 file://components/sync/OWNERS
-
-# COMPONENT: Services>Sync
diff --git a/content/browser/back_forward_cache_browsertest.cc b/content/browser/back_forward_cache_browsertest.cc
index 17c9f28..5c9336e 100644
--- a/content/browser/back_forward_cache_browsertest.cc
+++ b/content/browser/back_forward_cache_browsertest.cc
@@ -3739,10 +3739,35 @@
 
  protected:
   void SetUpCommandLine(base::CommandLine* command_line) override {
-    EnableFeatureAndSetParams(blink::features::kLoadingTasksUnfreezable, "",
-                              "");
+    EnableFeatureAndSetParams(blink::features::kLoadingTasksUnfreezable,
+                              "max_buffered_bytes",
+                              base::NumberToString(kMaxBufferedBytes));
     BackForwardCacheBrowserTest::SetUpCommandLine(command_line);
   }
+
+  // Navigates to a page at |page_url| with an img element with src set to
+  // "image.png".
+  RenderFrameHostImpl* NavigateToPageWithImage(const GURL& page_url) {
+    EXPECT_TRUE(NavigateToURL(shell(), page_url));
+    RenderFrameHostImpl* rfh = current_frame_host();
+    // Wait for the document to load DOM to ensure that kLoading is not
+    // one of the reasons why the document wasn't cached.
+    WaitForDOMContentLoaded(rfh);
+
+    EXPECT_TRUE(ExecJs(rfh, R"(
+      var image = document.createElement("img");
+      image.src = "image.png";
+      document.body.appendChild(image);
+
+      var image_load_status = new Promise((resolve, reject) => {
+        image.onload = () => { resolve("loaded"); }
+        image.onerror = () => { resolve("error"); }
+      });
+    )"));
+    return rfh;
+  }
+
+  const int kMaxBufferedBytes = 7000;
 };
 
 // When loading task is unfreezable with the feature flag
@@ -3824,6 +3849,158 @@
                 FROM_HERE);
 }
 
+IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTestWithUnfreezableLoading,
+                       ImageStillLoading_ResponseStartedWhileFrozen) {
+  net::test_server::ControllableHttpResponse image_response(
+      embedded_test_server(), "/image.png");
+  ASSERT_TRUE(embedded_test_server()->Start());
+
+  // 1) Navigate to a page with an image with src == "image.png".
+  RenderFrameHostImpl* rfh_1 = NavigateToPageWithImage(
+      embedded_test_server()->GetURL("a.com", "/title1.html"));
+  image_response.WaitForRequest();
+
+  // 2) Navigate away.
+  EXPECT_TRUE(NavigateToURL(
+      shell(), embedded_test_server()->GetURL("b.com", "/title2.html")));
+  // The page was still loading when we navigated away, but it's still eligible
+  // for back-forward cache.
+  EXPECT_TRUE(rfh_1->IsInBackForwardCache());
+
+  // Start sending the image body while in the back-forward cache.
+  image_response.Send(net::HTTP_OK, "image/png");
+  image_response.Send("image_body");
+  image_response.Done();
+
+  // 3) Go back to the first page. We should restore the page from the
+  // back-forward cache.
+  web_contents()->GetController().GoBack();
+  EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
+  ExpectOutcome(BackForwardCacheMetrics::HistoryNavigationOutcome::kRestored,
+                FROM_HERE);
+
+  // Wait until the deferred body is processed. Since it's not a valid image
+  // value, we'll get the "error" event.
+  EXPECT_EQ("error", EvalJs(rfh_1, "image_load_status"));
+}
+
+IN_PROC_BROWSER_TEST_F(
+    BackForwardCacheBrowserTestWithUnfreezableLoading,
+    ImageStillLoading_ResponseStartedWhileFrozen_ExceedsBytesLimit) {
+  net::test_server::ControllableHttpResponse image_response(
+      embedded_test_server(), "/image.png");
+  ASSERT_TRUE(embedded_test_server()->Start());
+
+  // 1) Navigate to a page with an image with src == "image.png".
+  RenderFrameHostImpl* rfh_1 = NavigateToPageWithImage(
+      embedded_test_server()->GetURL("a.com", "/title1.html"));
+
+  // Wait for the image request, but don't send anything yet.
+  image_response.WaitForRequest();
+
+  // 2) Navigate away.
+  EXPECT_TRUE(NavigateToURL(
+      shell(), embedded_test_server()->GetURL("b.com", "/title2.html")));
+  // The page was still loading when we navigated away, but it's still eligible
+  // for back-forward cache.
+  EXPECT_TRUE(rfh_1->IsInBackForwardCache());
+
+  RenderFrameDeletedObserver delete_observer(rfh_1);
+  // Start sending the image response while in the back-forward cache.
+  image_response.Send(net::HTTP_OK, "image/png");
+  std::string body(kMaxBufferedBytes + 1, '*');
+  image_response.Send(body);
+  image_response.Done();
+  delete_observer.WaitUntilDeleted();
+
+  // 3) Go back to the first page. We should not restore the page from the
+  // back-forward cache.
+  web_contents()->GetController().GoBack();
+  EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
+  ExpectOutcome(BackForwardCacheMetrics::HistoryNavigationOutcome::kNotRestored,
+                FROM_HERE);
+}
+
+IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTestWithUnfreezableLoading,
+                       ImageStillLoading_ResponseStartedBeforeFreezing) {
+  net::test_server::ControllableHttpResponse image_response(
+      embedded_test_server(), "/image.png");
+  ASSERT_TRUE(embedded_test_server()->Start());
+
+  // 1) Navigate to a page with an image with src == "image.png".
+  RenderFrameHostImpl* rfh_1 = NavigateToPageWithImage(
+      embedded_test_server()->GetURL("a.com", "/title1.html"));
+
+  // Start sending response before the page gets in the back-forward cache.
+  image_response.WaitForRequest();
+  image_response.Send(net::HTTP_OK, "image/png");
+  image_response.Send(" ");
+  // Run some script to ensure the renderer processed its pending tasks.
+  EXPECT_TRUE(ExecJs(rfh_1, "var foo = 42;"));
+
+  // 2) Navigate away.
+  EXPECT_TRUE(NavigateToURL(
+      shell(), embedded_test_server()->GetURL("b.com", "/title2.html")));
+  // The page was still loading when we navigated away, but it's still eligible
+  // for back-forward cache.
+  EXPECT_TRUE(rfh_1->IsInBackForwardCache());
+
+  // Send body while in the back-forward cache.
+  image_response.Send("image_body");
+  image_response.Done();
+
+  // 3) Go back to the first page. We should restore the page from the
+  // back-forward cache.
+  web_contents()->GetController().GoBack();
+  EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
+  ExpectOutcome(BackForwardCacheMetrics::HistoryNavigationOutcome::kRestored,
+                FROM_HERE);
+
+  // Wait until the deferred body is processed. Since it's not a valid image
+  // value, we'll get the "error" event.
+  EXPECT_EQ("error", EvalJs(rfh_1, "image_load_status"));
+}
+
+IN_PROC_BROWSER_TEST_F(
+    BackForwardCacheBrowserTestWithUnfreezableLoading,
+    ImageStillLoading_ResponseStartedBeforeFreezing_ExceedsBytesLimit) {
+  net::test_server::ControllableHttpResponse image_response(
+      embedded_test_server(), "/image.png");
+  ASSERT_TRUE(embedded_test_server()->Start());
+
+  // 1) Navigate to a page with an image with src == "image.png".
+  RenderFrameHostImpl* rfh_1 = NavigateToPageWithImage(
+      embedded_test_server()->GetURL("a.com", "/title1.html"));
+
+  // Start sending response before the page gets in the back-forward cache.
+  image_response.WaitForRequest();
+  image_response.Send(net::HTTP_OK, "image/png");
+  image_response.Send(" ");
+  // Run some script to ensure the renderer processed its pending tasks.
+  EXPECT_TRUE(ExecJs(rfh_1, "var foo = 42;"));
+
+  // 2) Navigate away.
+  EXPECT_TRUE(NavigateToURL(
+      shell(), embedded_test_server()->GetURL("b.com", "/title2.html")));
+  // The page was still loading when we navigated away, but it's still eligible
+  // for back-forward cache.
+  EXPECT_TRUE(rfh_1->IsInBackForwardCache());
+
+  // Send the image response body while in the back-forward cache.
+  RenderFrameDeletedObserver delete_observer(rfh_1);
+  std::string body(kMaxBufferedBytes + 1, '*');
+  image_response.Send(body);
+  image_response.Done();
+  delete_observer.WaitUntilDeleted();
+
+  // 3) Go back to the first page. We should not restore the page from the
+  // back-forward cache.
+  web_contents()->GetController().GoBack();
+  EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
+  ExpectOutcome(BackForwardCacheMetrics::HistoryNavigationOutcome::kNotRestored,
+                FROM_HERE);
+}
+
 // Disabled on Android, since we have problems starting up the websocket test
 // server in the host
 #if defined(OS_ANDROID)
diff --git a/content/browser/renderer_host/navigation_controller_impl.h b/content/browser/renderer_host/navigation_controller_impl.h
index 6f7964c..a322ba66 100644
--- a/content/browser/renderer_host/navigation_controller_impl.h
+++ b/content/browser/renderer_host/navigation_controller_impl.h
@@ -340,8 +340,13 @@
   FRIEND_TEST_ALL_PREFIXES(TimeSmoother, SingleDuplicate);
   FRIEND_TEST_ALL_PREFIXES(TimeSmoother, ManyDuplicates);
   FRIEND_TEST_ALL_PREFIXES(TimeSmoother, ClockBackwardsJump);
-  FRIEND_TEST_ALL_PREFIXES(NavigationControllerTest,
+  FRIEND_TEST_ALL_PREFIXES(NavigationControllerBrowserTest, PostThenReload);
+  FRIEND_TEST_ALL_PREFIXES(NavigationControllerBrowserTest,
                            PostThenReplaceStateThenReload);
+  FRIEND_TEST_ALL_PREFIXES(NavigationControllerBrowserTest,
+                           PostThenPushStateThenReload);
+  FRIEND_TEST_ALL_PREFIXES(NavigationControllerBrowserTest,
+                           PostThenFragmentNavigationThenReload);
 
   // Defines possible actions that are returned by
   // DetermineActionForHistoryNavigation().
diff --git a/content/browser/renderer_host/navigation_controller_impl_browsertest.cc b/content/browser/renderer_host/navigation_controller_impl_browsertest.cc
index ca97193..273091f 100644
--- a/content/browser/renderer_host/navigation_controller_impl_browsertest.cc
+++ b/content/browser/renderer_host/navigation_controller_impl_browsertest.cc
@@ -142,6 +142,29 @@
     return static_cast<WebContentsImpl*>(shell()->web_contents());
   }
 
+  // Creates a form and submits it to |form_submit_url|. Returns the POST ID of
+  // the submitted form POST data.
+  int64_t CreateAndSubmitForm(const GURL& form_submit_url) {
+    NavigationControllerImpl& controller =
+        static_cast<NavigationControllerImpl&>(contents()->GetController());
+    TestNavigationObserver form_nav_observer(contents());
+    EXPECT_TRUE(ExecJs(contents(),
+                       JsReplace("var form = document.createElement('form');"
+                                 "form.method = 'POST';"
+                                 "form.action = $1;"
+                                 "document.body.appendChild(form);"
+                                 "form.submit();",
+                                 form_submit_url)));
+    form_nav_observer.Wait();
+    EXPECT_EQ(form_submit_url, contents()->GetLastCommittedURL());
+    const int64_t form_post_id =
+        controller.GetLastCommittedEntry()->GetPostID();
+    EXPECT_NE(-1, form_post_id);
+    EXPECT_TRUE(controller.GetLastCommittedEntry()->GetHasPostData());
+    EXPECT_EQ("POST", contents()->GetMainFrame()->last_http_method());
+    return form_post_id;
+  }
+
  private:
   base::test::ScopedFeatureList feature_list_for_render_document_;
 };
@@ -411,6 +434,20 @@
   // What the base URL ends up being is really implementation defined, as
   // using an invalid base URL is already undefined behavior.
   EXPECT_EQ(base_url, entry->GetBaseURLForDataURL());
+
+  {
+    // Make a same-document navigation via history.pushState.
+    TestNavigationObserver same_tab_observer(shell()->web_contents(), 1);
+    EXPECT_TRUE(
+        ExecuteScript(shell(), "history.pushState('', 'test', '#foo')"));
+    same_tab_observer.Wait();
+  }
+
+  // Verify that the same-document navigation succeeds.
+  EXPECT_EQ(2, controller.GetEntryCount());
+  entry = controller.GetLastCommittedEntry();
+  EXPECT_EQ(base_url, entry->GetBaseURLForDataURL());
+  EXPECT_EQ(history_url, contents()->GetMainFrame()->GetLastCommittedURL());
 }
 #endif  // defined(OS_ANDROID)
 
@@ -8729,6 +8766,282 @@
             kill_waiter.Wait());
 }
 
+// Load the same page twice, once as a GET and once as a POST.
+// We should update the post state on the NavigationEntry.
+IN_PROC_BROWSER_TEST_P(NavigationControllerBrowserTest,
+                       LoadURL_SamePage_DifferentMethod) {
+  NavigationControllerImpl& controller =
+      static_cast<NavigationControllerImpl&>(contents()->GetController());
+  GURL start_url(embedded_test_server()->GetURL("/title1.html"));
+  EXPECT_TRUE(NavigateToURL(shell(), start_url));
+
+  // Create a form in the page then submit it to create a POST request.
+  GURL form_submit_url(embedded_test_server()->GetURL("/title2.html"));
+  CreateAndSubmitForm(form_submit_url);
+
+  // Navigate to the page with a "GET" request. This will reload the page with a
+  // different method, and the last committed entry should have the POST-related
+  // data cleared.
+  EXPECT_TRUE(NavigateToURL(shell(), form_submit_url));
+  NavigationEntryImpl* entry = controller.GetLastCommittedEntry();
+  EXPECT_EQ(form_submit_url, entry->GetURL());
+  EXPECT_FALSE(entry->GetHasPostData());
+  EXPECT_EQ(entry->GetPostID(), -1);
+  EXPECT_EQ("GET", contents()->GetMainFrame()->last_http_method());
+}
+
+// Similar to LoadURL_SamePage_DifferentMethod but does a renderer-initiated
+// navigation instead.
+IN_PROC_BROWSER_TEST_P(NavigationControllerBrowserTest,
+                       LoadURL_SamePage_DifferentMethod_RendererInitiated) {
+  NavigationControllerImpl& controller =
+      static_cast<NavigationControllerImpl&>(contents()->GetController());
+  GURL start_url(embedded_test_server()->GetURL("/title1.html"));
+  EXPECT_TRUE(NavigateToURL(shell(), start_url));
+
+  // Create a form in the page then submit it to create a POST request.
+  GURL form_submit_url(embedded_test_server()->GetURL("/title2.html"));
+  CreateAndSubmitForm(form_submit_url);
+
+  // Navigate to the page with a "GET" request. This will reload the page with a
+  // different method, and the last committed entry should have the POST-related
+  // data cleared.
+  EXPECT_TRUE(NavigateToURLFromRenderer(shell(), form_submit_url));
+  NavigationEntryImpl* entry = controller.GetLastCommittedEntry();
+  EXPECT_EQ(form_submit_url, entry->GetURL());
+  EXPECT_FALSE(entry->GetHasPostData());
+  EXPECT_EQ(entry->GetPostID(), -1);
+  EXPECT_EQ("GET", contents()->GetMainFrame()->last_http_method());
+}
+
+IN_PROC_BROWSER_TEST_P(NavigationControllerBrowserTest,
+                       FormSubmitServerRedirect) {
+  NavigationControllerImpl& controller =
+      static_cast<NavigationControllerImpl&>(contents()->GetController());
+  GURL start_url(embedded_test_server()->GetURL("/title1.html"));
+  EXPECT_TRUE(NavigateToURL(shell(), start_url));
+
+  GURL url2(embedded_test_server()->GetURL("/title2.html"));
+  GURL redirect_to_url2_url(
+      embedded_test_server()->GetURL("/server-redirect?" + url2.spec()));
+
+  // Create a form in the page then submit it to create a POST request, but the
+  // request got server-redirected and lost the POST data.
+  TestNavigationObserver form_nav_observer(contents());
+  EXPECT_TRUE(
+      ExecJs(contents(), JsReplace("var form = document.createElement('form');"
+                                   "form.method = 'POST';"
+                                   "form.action = $1;"
+                                   "document.body.appendChild(form);"
+                                   "form.submit();",
+                                   redirect_to_url2_url)));
+  form_nav_observer.Wait();
+  NavigationEntryImpl* entry = controller.GetLastCommittedEntry();
+  EXPECT_EQ(url2, entry->GetURL());
+  EXPECT_FALSE(entry->GetHasPostData());
+  EXPECT_EQ(-1, entry->GetPostID());
+  EXPECT_EQ("GET", contents()->GetMainFrame()->last_http_method());
+}
+
+IN_PROC_BROWSER_TEST_P(NavigationControllerBrowserTest,
+                       FormSubmitClientRedirect) {
+  NavigationControllerImpl& controller =
+      static_cast<NavigationControllerImpl&>(contents()->GetController());
+  GURL start_url(embedded_test_server()->GetURL("/title1.html"));
+  EXPECT_TRUE(NavigateToURL(shell(), start_url));
+
+  GURL url2(embedded_test_server()->GetURL(
+      "/navigation_controller/simple_page_1.html"));
+  GURL redirect_to_url2_url(embedded_test_server()->GetURL(
+      "/navigation_controller/client_redirect.html"));
+
+  // Create a form in the page then submit it to create a POST request, but we
+  // lost the POST data after client-redirect.
+  TestNavigationObserver form_nav_observer(contents());
+  EXPECT_TRUE(
+      ExecJs(contents(), JsReplace("var form = document.createElement('form');"
+                                   "form.method = 'POST';"
+                                   "form.action = $1;"
+                                   "document.body.appendChild(form);"
+                                   "form.submit();",
+                                   redirect_to_url2_url)));
+  form_nav_observer.Wait();
+  NavigationEntryImpl* entry = controller.GetLastCommittedEntry();
+  EXPECT_EQ(url2, entry->GetURL());
+  EXPECT_FALSE(entry->GetHasPostData());
+  EXPECT_EQ(-1, entry->GetPostID());
+  EXPECT_EQ("GET", contents()->GetMainFrame()->last_http_method());
+}
+
+// Counts the occurrences of form repost warning dialogs.
+class CountRepostFormWarningWebContentsDelegate : public WebContentsDelegate {
+ public:
+  CountRepostFormWarningWebContentsDelegate() = default;
+
+  int repost_form_warning_count() { return repost_form_warning_count_; }
+
+  void ShowRepostFormWarningDialog(WebContents* source) override {
+    repost_form_warning_count_++;
+  }
+
+ private:
+  // The number of times ShowRepostFormWarningDialog() was called.
+  int repost_form_warning_count_ = 0;
+};
+
+IN_PROC_BROWSER_TEST_P(NavigationControllerBrowserTest, PostThenReload) {
+  NavigationControllerImpl& controller =
+      static_cast<NavigationControllerImpl&>(contents()->GetController());
+  std::unique_ptr<CountRepostFormWarningWebContentsDelegate> delegate(
+      new CountRepostFormWarningWebContentsDelegate());
+  contents()->SetDelegate(delegate.get());
+  GURL start_url(embedded_test_server()->GetURL("/title1.html"));
+  EXPECT_TRUE(NavigateToURL(shell(), start_url));
+
+  // Create a form in the page then submit it to create a POST request.
+  GURL form_submit_url(embedded_test_server()->GetURL("/title2.html"));
+  const int64_t form_post_id = CreateAndSubmitForm(form_submit_url);
+  EXPECT_EQ(0, delegate->repost_form_warning_count());
+
+  // Reload. We should show a repost warning dialog.
+  {
+    NavigationControllerImpl::ScopedShowRepostDialogForTesting show_repost;
+    controller.Reload(ReloadType::NORMAL, true /* check_for_repost */);
+    EXPECT_TRUE(WaitForLoadStop(contents()));
+    EXPECT_EQ(form_submit_url, contents()->GetLastCommittedURL());
+    EXPECT_TRUE(controller.GetLastCommittedEntry()->GetHasPostData());
+    EXPECT_EQ(form_post_id, controller.GetLastCommittedEntry()->GetPostID());
+  }
+  EXPECT_EQ(1, delegate->repost_form_warning_count());
+}
+
+IN_PROC_BROWSER_TEST_P(NavigationControllerBrowserTest,
+                       PostThenReplaceStateThenReload) {
+  NavigationControllerImpl& controller =
+      static_cast<NavigationControllerImpl&>(contents()->GetController());
+  std::unique_ptr<CountRepostFormWarningWebContentsDelegate> delegate(
+      new CountRepostFormWarningWebContentsDelegate());
+  contents()->SetDelegate(delegate.get());
+  GURL start_url(embedded_test_server()->GetURL("/title1.html"));
+  EXPECT_TRUE(NavigateToURL(shell(), start_url));
+
+  // Create a form in the page then submit it to create a POST request.
+  GURL form_submit_url(embedded_test_server()->GetURL("/title2.html"));
+  CreateAndSubmitForm(form_submit_url);
+  const int kExpectedRepostFormWarningCount = 0;
+  EXPECT_EQ(kExpectedRepostFormWarningCount,
+            delegate->repost_form_warning_count());
+
+  // history.replaceState() is called, which clears the POST data.
+  GURL replace_url(embedded_test_server()->GetURL("/title2.html#foo"));
+  {
+    EXPECT_TRUE(
+        ExecJs(contents(), "history.replaceState({}, '', 'title2.html#foo')"));
+    EXPECT_TRUE(WaitForLoadStop(contents()));
+    EXPECT_EQ(replace_url, contents()->GetLastCommittedURL());
+    EXPECT_FALSE(controller.GetLastCommittedEntry()->GetHasPostData());
+    EXPECT_EQ(-1, controller.GetLastCommittedEntry()->GetPostID());
+  }
+  EXPECT_EQ(kExpectedRepostFormWarningCount,
+            delegate->repost_form_warning_count());
+
+  // Now reload. replaceState overrides the POST, so we should not show a repost
+  // warning dialog.
+  {
+    NavigationControllerImpl::ScopedShowRepostDialogForTesting show_repost;
+    controller.Reload(ReloadType::NORMAL, true /* check_for_repost */);
+    EXPECT_TRUE(WaitForLoadStop(contents()));
+    EXPECT_EQ(replace_url, contents()->GetLastCommittedURL());
+    EXPECT_FALSE(controller.GetLastCommittedEntry()->GetHasPostData());
+    EXPECT_EQ(-1, controller.GetLastCommittedEntry()->GetPostID());
+  }
+  EXPECT_EQ(kExpectedRepostFormWarningCount,
+            delegate->repost_form_warning_count());
+}
+
+IN_PROC_BROWSER_TEST_P(NavigationControllerBrowserTest,
+                       PostThenPushStateThenReload) {
+  NavigationControllerImpl& controller =
+      static_cast<NavigationControllerImpl&>(contents()->GetController());
+  std::unique_ptr<CountRepostFormWarningWebContentsDelegate> delegate(
+      new CountRepostFormWarningWebContentsDelegate());
+  contents()->SetDelegate(delegate.get());
+  GURL start_url(embedded_test_server()->GetURL("/title1.html"));
+  EXPECT_TRUE(NavigateToURL(shell(), start_url));
+
+  // Create a form in the page then submit it to create a POST request.
+  GURL form_submit_url(embedded_test_server()->GetURL("/title2.html"));
+  CreateAndSubmitForm(form_submit_url);
+  const int kExpectedRepostFormWarningCount = 0;
+  EXPECT_EQ(kExpectedRepostFormWarningCount,
+            delegate->repost_form_warning_count());
+
+  // history.pushState() is called, which clears the POST data.
+  GURL push_url(embedded_test_server()->GetURL("/title2.html#foo"));
+  {
+    EXPECT_TRUE(
+        ExecJs(contents(), "history.pushState({}, '', 'title2.html#foo')"));
+    EXPECT_TRUE(WaitForLoadStop(contents()));
+    EXPECT_EQ(push_url, contents()->GetLastCommittedURL());
+    EXPECT_FALSE(controller.GetLastCommittedEntry()->GetHasPostData());
+    EXPECT_EQ(-1, controller.GetLastCommittedEntry()->GetPostID());
+  }
+  EXPECT_EQ(kExpectedRepostFormWarningCount,
+            delegate->repost_form_warning_count());
+
+  // Now reload. pushState overrides the POST, so we should not show a
+  // repost warning dialog.
+  {
+    NavigationControllerImpl::ScopedShowRepostDialogForTesting show_repost;
+    controller.Reload(ReloadType::NORMAL, true /* check_for_repost */);
+    EXPECT_TRUE(WaitForLoadStop(contents()));
+    EXPECT_EQ(push_url, contents()->GetLastCommittedURL());
+    EXPECT_FALSE(controller.GetLastCommittedEntry()->GetHasPostData());
+    EXPECT_EQ(-1, controller.GetLastCommittedEntry()->GetPostID());
+  }
+  EXPECT_EQ(kExpectedRepostFormWarningCount,
+            delegate->repost_form_warning_count());
+}
+
+IN_PROC_BROWSER_TEST_P(NavigationControllerBrowserTest,
+                       PostThenFragmentNavigationThenReload) {
+  NavigationControllerImpl& controller =
+      static_cast<NavigationControllerImpl&>(contents()->GetController());
+  std::unique_ptr<CountRepostFormWarningWebContentsDelegate> delegate(
+      new CountRepostFormWarningWebContentsDelegate());
+  contents()->SetDelegate(delegate.get());
+  GURL start_url(embedded_test_server()->GetURL("/title1.html"));
+  EXPECT_TRUE(NavigateToURL(shell(), start_url));
+
+  // Create a form in the page then submit it to create a POST request.
+  GURL form_submit_url(embedded_test_server()->GetURL("/title2.html"));
+  const int64_t form_post_id = CreateAndSubmitForm(form_submit_url);
+  EXPECT_EQ(0, delegate->repost_form_warning_count());
+
+  // Do a fragment navigation. This should preserve the POST data.
+  GURL fragment_url(embedded_test_server()->GetURL("/title2.html#foo"));
+  {
+    EXPECT_TRUE(ExecJs(contents(), "location.href = '#foo'"));
+    EXPECT_TRUE(WaitForLoadStop(contents()));
+    EXPECT_EQ(fragment_url, contents()->GetLastCommittedURL());
+    EXPECT_TRUE(controller.GetLastCommittedEntry()->GetHasPostData());
+    EXPECT_EQ(form_post_id, controller.GetLastCommittedEntry()->GetPostID());
+  }
+  EXPECT_EQ(0, delegate->repost_form_warning_count());
+
+  // Now reload. Fragment navigation keeps the previous POST data, so we should
+  // show a repost warning dialog.
+  {
+    NavigationControllerImpl::ScopedShowRepostDialogForTesting show_repost;
+    controller.Reload(ReloadType::NORMAL, true /* check_for_repost */);
+    EXPECT_TRUE(WaitForLoadStop(contents()));
+    EXPECT_EQ(fragment_url, contents()->GetLastCommittedURL());
+    EXPECT_TRUE(controller.GetLastCommittedEntry()->GetHasPostData());
+    EXPECT_EQ(form_post_id, controller.GetLastCommittedEntry()->GetPostID());
+  }
+  EXPECT_EQ(1, delegate->repost_form_warning_count());
+}
+
 // Verify that a session history navigation which results in a different
 // SiteInstance from the original commit is correctly handled - classified
 // as new navigation with replacement, resulting in no new navigation
diff --git a/content/browser/renderer_host/navigation_controller_impl_unittest.cc b/content/browser/renderer_host/navigation_controller_impl_unittest.cc
index 3e37f8e..fc237ed 100644
--- a/content/browser/renderer_host/navigation_controller_impl_unittest.cc
+++ b/content/browser/renderer_host/navigation_controller_impl_unittest.cc
@@ -224,29 +224,19 @@
 
 class TestWebContentsDelegate : public WebContentsDelegate {
  public:
-  TestWebContentsDelegate()
-      : navigation_state_change_count_(0), repost_form_warning_count_(0) {}
+  TestWebContentsDelegate() = default;
 
   int navigation_state_change_count() { return navigation_state_change_count_; }
 
-  int repost_form_warning_count() { return repost_form_warning_count_; }
-
   // Keep track of whether the tab has notified us of a navigation state change.
   void NavigationStateChanged(WebContents* source,
                               InvalidateTypes changed_flags) override {
     navigation_state_change_count_++;
   }
 
-  void ShowRepostFormWarningDialog(WebContents* source) override {
-    repost_form_warning_count_++;
-  }
-
  private:
   // The number of times NavigationStateChanged has been called.
-  int navigation_state_change_count_;
-
-  // The number of times ShowRepostFormWarningDialog() was called.
-  int repost_form_warning_count_;
+  int navigation_state_change_count_ = 0;
 };
 
 // Observer that records the LoadCommittedDetails from the most recent commit.
@@ -4111,45 +4101,6 @@
   EXPECT_EQ(url4, controller.GetVisibleEntry()->GetURL());
 }
 
-TEST_F(NavigationControllerTest, PostThenReplaceStateThenReload) {
-  std::unique_ptr<TestWebContentsDelegate> delegate(
-      new TestWebContentsDelegate());
-  EXPECT_FALSE(contents()->GetDelegate());
-  contents()->SetDelegate(delegate.get());
-
-  // Submit a form.
-  auto simulator = NavigationSimulatorImpl::CreateRendererInitiated(
-      GURL("http://foo"), main_test_rfh());
-  simulator->SetIsFormSubmission(true);
-  simulator->SetIsPostWithId(123);
-  simulator->Commit();
-
-  // Now reload. We should show repost warning dialog.
-  {
-    NavigationControllerImpl::ScopedShowRepostDialogForTesting show_repost;
-    controller_impl().Reload(ReloadType::NORMAL, true);
-  }
-  const int expected_repost_form_warning_count = 1;
-  EXPECT_EQ(expected_repost_form_warning_count,
-            delegate->repost_form_warning_count());
-
-  // history.replaceState() is called.
-  GURL replace_url("http://foo#foo");
-  simulator = NavigationSimulatorImpl::CreateRendererInitiated(
-      GURL("http://foo#foo"), main_test_rfh());
-  simulator->set_did_create_new_entry(false);
-  simulator->Commit();
-
-  // Now reload. replaceState overrides the POST, so we should not show a
-  // repost warning dialog.
-  {
-    NavigationControllerImpl::ScopedShowRepostDialogForTesting show_repost;
-    controller_impl().Reload(ReloadType::NORMAL, true);
-  }
-  EXPECT_EQ(expected_repost_form_warning_count,
-            delegate->repost_form_warning_count());
-}
-
 // Tests that if a stale navigation comes back from the renderer, it is properly
 // resurrected.
 TEST_F(NavigationControllerTest, StaleNavigationsResurrected) {
diff --git a/content/browser/renderer_host/navigation_request.cc b/content/browser/renderer_host/navigation_request.cc
index c425557..c0b31bf 100644
--- a/content/browser/renderer_host/navigation_request.cc
+++ b/content/browser/renderer_host/navigation_request.cc
@@ -900,6 +900,7 @@
     blink::mojom::ReferrerPtr referrer,
     const ui::PageTransition& transition,
     bool should_replace_current_entry,
+    const std::string& method,
     const NavigationGesture& gesture,
     const std::vector<GURL>& redirects,
     const blink::PageState& page_state,
@@ -919,7 +920,7 @@
           GURL() /* base_url_for_data_url*/,
           GURL() /* history_url_for_data_url */,
           blink::PreviewsTypes::PREVIEWS_UNSPECIFIED, base::TimeTicks::Now(),
-          "GET" /* method */, nullptr /* post_data */,
+          method /* method */, nullptr /* post_data */,
           network::mojom::SourceLocation::New(),
           false /* started_from_context_menu */,
           gesture == NavigationGestureUser, false /* has_text_fragment_token */,
@@ -934,7 +935,7 @@
           std::vector<network::mojom::URLResponseHeadPtr>(),
           std::vector<net::RedirectInfo>(),
           std::string() /* redirect_response */, url /* original_url */,
-          "GET" /* original_method */, false /* can_load_local_resources */,
+          method /* original_method */, false /* can_load_local_resources */,
           page_state, 0 /* nav_entry_id*/,
           base::flat_map<std::string, bool>() /* subframe_unique_names */,
           false /* intended_as_new_entry */,
diff --git a/content/browser/renderer_host/navigation_request.h b/content/browser/renderer_host/navigation_request.h
index 13a1f41..730174f 100644
--- a/content/browser/renderer_host/navigation_request.h
+++ b/content/browser/renderer_host/navigation_request.h
@@ -212,6 +212,7 @@
       blink::mojom::ReferrerPtr referrer,
       const ui::PageTransition& transition,
       bool should_replace_current_entry,
+      const std::string& method,
       const NavigationGesture& gesture,
       const std::vector<GURL>& redirects,
       const blink::PageState& page_state,
diff --git a/content/browser/renderer_host/render_frame_host_impl.cc b/content/browser/renderer_host/render_frame_host_impl.cc
index d256ae1..cb5b9b4 100644
--- a/content/browser/renderer_host/render_frame_host_impl.cc
+++ b/content/browser/renderer_host/render_frame_host_impl.cc
@@ -2622,6 +2622,15 @@
   if (!params.url_is_unreachable)
     last_successful_url_ = params.url;
 
+  // Set the last committed HTTP method. Note that we're setting this here
+  // instead of in DidCommitNewDocument because same-document navigations
+  // triggered by the History API (history.replaceState/pushState) will reset
+  // the method to "GET" (while fragment navigations won't).
+  // TODO(arthursonzogni): Stop relying on DidCommitProvisionalLoadParams. Use
+  // the NavigationRequest instead. The browser process doesn't need to rely on
+  // the renderer process.
+  last_http_method_ = params.method;
+
   if (did_create_new_document)
     DidCommitNewDocument(params, navigation_request);
 
@@ -3026,7 +3035,7 @@
   is_loading_ = true;
 
   DidCommitNavigationInternal(std::move(owned_request), std::move(params),
-                              /*is_same_document_navigation=*/false);
+                              /*same_document_params=*/nullptr);
 
   // The page is already loaded since it came from the cache, so fire the stop
   // loading event.
@@ -3058,7 +3067,8 @@
 }
 
 void RenderFrameHostImpl::DidCommitSameDocumentNavigation(
-    mojom::DidCommitProvisionalLoadParamsPtr params) {
+    mojom::DidCommitProvisionalLoadParamsPtr params,
+    mojom::DidCommitSameDocumentNavigationParamsPtr same_document_params) {
   ScopedActiveURL scoped_active_url(params->url,
                                     frame_tree()->root()->current_origin());
   ScopedCommitStateResetter commit_state_resetter(this);
@@ -3091,7 +3101,7 @@
   if (!DidCommitNavigationInternal(
           is_browser_initiated ? std::move(same_document_navigation_request_)
                                : nullptr,
-          std::move(params), true /* is_same_document_navigation*/)) {
+          std::move(params), std::move(same_document_params))) {
     return;
   }
 
@@ -8049,7 +8059,9 @@
     const NavigationGesture& gesture,
     const std::vector<GURL>& redirects,
     const blink::PageState& page_state,
-    bool is_same_document) {
+    bool is_same_document,
+    bool is_same_document_history_api_navigation) {
+  DCHECK(!is_same_document_history_api_navigation || is_same_document);
   std::unique_ptr<CrossOriginEmbedderPolicyReporter> coep_reporter;
   // We don't switch the COEP reporter on same-document navigations, so create
   // one only for cross-document navigations.
@@ -8067,10 +8079,18 @@
     // history navigations.
     web_bundle_navigation_info = web_bundle_handle_->navigation_info()->Clone();
   }
+  std::string method = "GET";
+  if (is_same_document && !is_same_document_history_api_navigation) {
+    // Preserve the HTTP method used by the last navigation if this is a
+    // same-document navigation that is not triggered by the history API
+    // (history.replaceState/pushState). See spec:
+    // https://html.spec.whatwg.org/multipage/history.html#url-and-history-update-steps
+    method = last_http_method_;
+  }
   return NavigationRequest::CreateForCommit(
       frame_tree_node_, this, is_same_document, url, origin,
-      std::move(referrer), transition, should_replace_current_entry, gesture,
-      redirects, page_state, std::move(coep_reporter),
+      std::move(referrer), transition, should_replace_current_entry, method,
+      gesture, redirects, page_state, std::move(coep_reporter),
       std::move(web_bundle_navigation_info));
 }
 
@@ -8432,7 +8452,8 @@
 bool RenderFrameHostImpl::DidCommitNavigationInternal(
     std::unique_ptr<NavigationRequest> navigation_request,
     mojom::DidCommitProvisionalLoadParamsPtr params,
-    bool is_same_document_navigation) {
+    mojom::DidCommitSameDocumentNavigationParamsPtr same_document_params) {
+  const bool is_same_document_navigation = !!same_document_params;
   // Sanity-check the page transition for frame type.
   DCHECK_EQ(ui::PageTransitionIsMainFrame(params->transition), !GetParent());
   if (navigation_request &&
@@ -8519,7 +8540,9 @@
         params->url, params->origin, params->referrer.Clone(),
         params->transition, params->should_replace_current_entry,
         params->gesture, params->redirects, params->page_state,
-        is_same_document_navigation);
+        is_same_document_navigation,
+        same_document_params &&
+            same_document_params->is_history_api_navigation);
   }
 
   DCHECK(navigation_request);
@@ -8672,11 +8695,6 @@
   // the renderer process.
   last_http_status_code_ = params.http_status_code;
 
-  // TODO(arthursonzogni): Stop relying on DidCommitProvisionalLoadParams. Use
-  // the NavigationRequest instead. The browser process doesn't need to rely on
-  // the renderer process.
-  last_http_method_ = params.method;
-
   renderer_reported_scheduler_tracked_features_ = 0;
   browser_reported_scheduler_tracked_features_ = 0;
 
@@ -9025,7 +9043,7 @@
   }
 
   if (!DidCommitNavigationInternal(std::move(request), std::move(params),
-                                   false /* is_same_document_navigation */)) {
+                                   nullptr /* same_document_params */)) {
     return;
   }
 
diff --git a/content/browser/renderer_host/render_frame_host_impl.h b/content/browser/renderer_host/render_frame_host_impl.h
index 53f6546..685e7e7 100644
--- a/content/browser/renderer_host/render_frame_host_impl.h
+++ b/content/browser/renderer_host/render_frame_host_impl.h
@@ -2073,7 +2073,9 @@
       mojom::DidCommitProvisionalLoadInterfaceParamsPtr interface_params);
 
   void DidCommitSameDocumentNavigation(
-      mojom::DidCommitProvisionalLoadParamsPtr params) override;
+      mojom::DidCommitProvisionalLoadParamsPtr params,
+      mojom::DidCommitSameDocumentNavigationParamsPtr same_document_params)
+      override;
   void BeginNavigation(
       mojom::CommonNavigationParamsPtr common_params,
       mojom::BeginNavigationParamsPtr begin_params,
@@ -2284,7 +2286,8 @@
       const NavigationGesture& gesture,
       const std::vector<GURL>& redirects,
       const blink::PageState& page_state,
-      bool is_same_document);
+      bool is_same_document,
+      bool is_same_document_history_api_navigation);
 
   // Helper to process the beforeunload completion callback. |proceed| indicates
   // whether the navigation or tab close should be allowed to proceed.  If
@@ -2410,7 +2413,7 @@
   bool DidCommitNavigationInternal(
       std::unique_ptr<NavigationRequest> navigation_request,
       mojom::DidCommitProvisionalLoadParamsPtr params,
-      bool is_same_document_navigation);
+      mojom::DidCommitSameDocumentNavigationParamsPtr same_document_params);
 
   // Called when we received the confirmation a new document committed in the
   // renderer. It was created from the |navigation|.
diff --git a/content/common/frame.mojom b/content/common/frame.mojom
index 6867426..8c41fa6 100644
--- a/content/common/frame.mojom
+++ b/content/common/frame.mojom
@@ -464,7 +464,8 @@
   // Sent by the renderer to indicate that a same document navigation
   // committed in the renderer process.
   DidCommitSameDocumentNavigation(
-      DidCommitProvisionalLoadParams params);
+      DidCommitProvisionalLoadParams params,
+      DidCommitSameDocumentNavigationParams same_document_params);
 
   // Sent by the renderer to request a navigation.
   // |blob_url_token| should be non-null when this is a navigation to a blob:
diff --git a/content/common/navigation_client.mojom b/content/common/navigation_client.mojom
index 9f542680..8a65aaa 100644
--- a/content/common/navigation_client.mojom
+++ b/content/common/navigation_client.mojom
@@ -166,6 +166,18 @@
   mojo_base.mojom.UnguessableToken? embedding_token;
 };
 
+// Similar to DidCommitProvisionalLoadParams, but only used for
+// FrameHost.DidCommitSameDocumentNavigation. Eventually, all parameters in
+// DidCommitProvisionalLoadParams will either get removed or moved to
+// DidCommitSameDocumentNavigationParams.
+// See https://crbug.com/1133115, https://crbug.com/1131832
+struct DidCommitSameDocumentNavigationParams {
+  // Will be true if the navigation is the result of history.pushState or
+  // history.replaceState.
+  // TODO(crbug.com/1131832): Port SameDocumentNavigationSource enum to mojo
+  // and use that instead of bool here.
+  bool is_history_api_navigation = false;
+};
 
 interface NavigationClient {
   // Tells the renderer that a navigation is ready to commit.
diff --git a/content/common/net/ip_address_space_util.cc b/content/common/net/ip_address_space_util.cc
index 0284080..dc209a3 100644
--- a/content/common/net/ip_address_space_util.cc
+++ b/content/common/net/ip_address_space_util.cc
@@ -61,4 +61,14 @@
       response_head->remote_endpoint.address());
 }
 
+IPAddressSpace CalculateResourceAddressSpace(const GURL& url,
+                                             const net::IPAddress& address) {
+  if (url.SchemeIsFile()) {
+    // See: https://wicg.github.io/cors-rfc1918/#file-url.
+    return IPAddressSpace::kLocal;
+  }
+
+  return network::IPAddressToIPAddressSpace(address);
+}
+
 }  // namespace content
diff --git a/content/common/net/ip_address_space_util.h b/content/common/net/ip_address_space_util.h
index e21f8be..93358e9 100644
--- a/content/common/net/ip_address_space_util.h
+++ b/content/common/net/ip_address_space_util.h
@@ -11,6 +11,12 @@
 
 class GURL;
 
+namespace net {
+
+class IPAddress;
+
+}  // namespace net
+
 namespace content {
 
 // Given a request URL and response information, this function calculates the
@@ -37,6 +43,17 @@
     const GURL& url,
     const network::mojom::URLResponseHead* response_head);
 
+// Given a response URL and the IP address the requested resource was fetched
+// from, this function calculates the IPAddressSpace of the requested resource.
+//
+// As opposed to CalculateClientAddressSpace(), this function is used to
+// determine the address space of the *target* of a fetch, for comparison with
+// that of the client of the fetch.
+//
+// See: https://wicg.github.io/cors-rfc1918/#integration-fetch
+network::mojom::IPAddressSpace CONTENT_EXPORT
+CalculateResourceAddressSpace(const GURL& url, const net::IPAddress& address);
+
 }  // namespace content
 
 #endif  // CONTENT_COMMON_NET_IP_ADDRESS_SPACE_UTIL_H_
diff --git a/content/common/net/ip_address_space_util_unittest.cc b/content/common/net/ip_address_space_util_unittest.cc
index ea0f5aa..6271e0f 100644
--- a/content/common/net/ip_address_space_util_unittest.cc
+++ b/content/common/net/ip_address_space_util_unittest.cc
@@ -24,6 +24,10 @@
 using network::mojom::ParsedHeaders;
 using network::mojom::URLResponseHead;
 
+IPAddress PublicIPv4Address() {
+  return IPAddress(64, 233, 160, 0);
+}
+
 IPAddress PrivateIPv4Address() {
   return IPAddress(192, 168, 1, 1);
 }
@@ -105,5 +109,25 @@
       CalculateClientAddressSpace(GURL("http://foo.test"), &response_head));
 }
 
+TEST(IPAddressSpaceTest, CalculateResourceAddressSpaceFileURL) {
+  EXPECT_EQ(IPAddressSpace::kLocal,
+            CalculateResourceAddressSpace(GURL("file:///foo"), IPAddress()));
+}
+
+TEST(IPAddressSpaceTest, CalculateResourceAddressSpaceIPAddress) {
+  EXPECT_EQ(IPAddressSpace::kLocal,
+            CalculateResourceAddressSpace(GURL("http:///foo.test"),
+                                          IPAddress::IPv4Localhost()));
+  EXPECT_EQ(IPAddressSpace::kPrivate,
+            CalculateResourceAddressSpace(GURL("http:///foo.test"),
+                                          PrivateIPv4Address()));
+  EXPECT_EQ(IPAddressSpace::kPublic,
+            CalculateResourceAddressSpace(GURL("http:///foo.test"),
+                                          PublicIPv4Address()));
+  EXPECT_EQ(
+      IPAddressSpace::kUnknown,
+      CalculateResourceAddressSpace(GURL("http:///foo.test"), IPAddress()));
+}
+
 }  // namespace
 }  // namespace content
diff --git a/content/public/test/render_view_test.cc b/content/public/test/render_view_test.cc
index f6b7bf03..2efc7e3 100644
--- a/content/public/test/render_view_test.cc
+++ b/content/public/test/render_view_test.cc
@@ -826,7 +826,7 @@
   view->GetMainRenderFrame()->DidFinishSameDocumentNavigation(
       is_new_navigation ? blink::kWebStandardCommit
                         : blink::kWebHistoryInertCommit,
-      false /* content_initiated */);
+      false /* content_initiated */, false /* is_history_api_navigation */);
 }
 
 void RenderViewTest::SetUseZoomForDSFEnabled(bool enabled) {
diff --git a/content/renderer/loader/url_loader_client_impl.cc b/content/renderer/loader/url_loader_client_impl.cc
index f8778c2..afdfc4f 100644
--- a/content/renderer/loader/url_loader_client_impl.cc
+++ b/content/renderer/loader/url_loader_client_impl.cc
@@ -23,6 +23,8 @@
 namespace content {
 namespace {
 
+constexpr size_t kDefaultMaxBufferedBodyBytes = 100 * 1000;
+
 // Determines whether it is safe to redirect from |from_url| to |to_url|.
 bool IsRedirectSafe(const GURL& from_url, const GURL& to_url) {
   return IsSafeRedirectTarget(from_url, to_url) &&
@@ -155,7 +157,11 @@
         writable_(std::move(writable)),
         writable_watcher_(FROM_HERE,
                           mojo::SimpleWatcher::ArmingPolicy::MANUAL,
-                          std::move(task_runner)) {
+                          std::move(task_runner)),
+        max_bytes_drained_(base::GetFieldTrialParamByFeatureAsInt(
+            blink::features::kLoadingTasksUnfreezable,
+            "max_buffered_bytes",
+            kDefaultMaxBufferedBodyBytes)) {
     pipe_drainer_ =
         std::make_unique<mojo::DataPipeDrainer>(this, std::move(readable));
     writable_watcher_.Watch(
@@ -176,6 +182,13 @@
     SCOPED_CRASH_KEY_STRING256(
         OnDataAvailable, last_loaded_url,
         owner_->last_loaded_url().possibly_invalid_spec());
+    total_bytes_drained_ += num_bytes;
+
+    if (total_bytes_drained_ > max_bytes_drained_ &&
+        owner_->IsDeferredWithBackForwardCache()) {
+      owner_->EvictFromBackForwardCache();
+      return;
+    }
     buffered_body_.emplace(static_cast<const char*>(data),
                            static_cast<const char*>(data) + num_bytes);
     WriteBufferedBody(MOJO_RESULT_OK);
@@ -250,6 +263,8 @@
   // memory as soon as we finish sending a chunk completely.
   base::queue<std::vector<char>> buffered_body_;
   uint32_t offset_in_current_chunk_ = 0;
+  size_t total_bytes_drained_ = 0;
+  const size_t max_bytes_drained_;
   bool draining_ = true;
 };
 
@@ -369,6 +384,9 @@
                                              std::move(response_head));
   }
 }
+void URLLoaderClientImpl::EvictFromBackForwardCache() {
+  resource_dispatcher_->EvictFromBackForwardCache(request_id_);
+}
 
 void URLLoaderClientImpl::OnReceiveRedirect(
     const net::RedirectInfo& redirect_info,
@@ -376,7 +394,7 @@
   DCHECK(!has_received_response_head_);
   if (deferred_state_ ==
       blink::WebURLLoader::DeferType::kDeferredWithBackForwardCache) {
-    resource_dispatcher_->EvictFromBackForwardCache(request_id_);
+    EvictFromBackForwardCache();
     // Close the connections and dispatch and OnComplete message.
     url_loader_.reset();
     url_loader_client_receiver_.reset();
@@ -453,13 +471,17 @@
                                                      std::move(body));
     return;
   }
-  if (!base::FeatureList::IsEnabled(
-          blink::features::kLoadingTasksUnfreezable)) {
+
+  if (deferred_state_ !=
+      blink::WebURLLoader::DeferType::kDeferredWithBackForwardCache) {
     // Defer the message, storing the original body pipe.
     StoreAndDispatch(
         std::make_unique<DeferredOnStartLoadingResponseBody>(std::move(body)));
     return;
   }
+
+  DCHECK(
+      base::FeatureList::IsEnabled(blink::features::kLoadingTasksUnfreezable));
   // We want to run loading tasks while deferred (but without dispatching the
   // messages). Drain the original pipe containing the response body into a
   // new pipe so that we won't block the network service if we're deferred for
diff --git a/content/renderer/loader/url_loader_client_impl.h b/content/renderer/loader/url_loader_client_impl.h
index aa2af3b7..169b477e 100644
--- a/content/renderer/loader/url_loader_client_impl.h
+++ b/content/renderer/loader/url_loader_client_impl.h
@@ -74,6 +74,12 @@
       mojo::ScopedDataPipeConsumerHandle body) override;
   void OnComplete(const network::URLLoaderCompletionStatus& status) override;
 
+  void EvictFromBackForwardCache();
+  bool IsDeferredWithBackForwardCache() {
+    return deferred_state_ ==
+           blink::WebURLLoader::DeferType::kDeferredWithBackForwardCache;
+  }
+
   const GURL& last_loaded_url() const { return last_loaded_url_; }
 
  private:
diff --git a/content/renderer/loader/url_loader_client_impl_unittest.cc b/content/renderer/loader/url_loader_client_impl_unittest.cc
index 4c50081..c8a7e7e 100644
--- a/content/renderer/loader/url_loader_client_impl_unittest.cc
+++ b/content/renderer/loader/url_loader_client_impl_unittest.cc
@@ -54,7 +54,7 @@
                                 public ::testing::WithParamInterface<bool> {
  protected:
   URLLoaderClientImplTest() : dispatcher_(new ResourceDispatcher()) {
-    if (BufferingEnabled()) {
+    if (DeferWithBackForwardCacheEnabled()) {
       scoped_feature_list_.InitAndEnableFeature(
           blink::features::kLoadingTasksUnfreezable);
     }
@@ -75,7 +75,7 @@
     EXPECT_TRUE(url_loader_client_);
   }
 
-  bool BufferingEnabled() { return GetParam(); }
+  bool DeferWithBackForwardCacheEnabled() { return GetParam(); }
 
   void TearDown() override { url_loader_client_.reset(); }
 
@@ -327,9 +327,12 @@
   EXPECT_EQ("hello", GetRequestPeerContextBody(&request_peer_context_));
 }
 
-TEST_P(URLLoaderClientImplTest, StoppedDeferringBeforeClosing) {
-  // Call OnReceiveResponse, OnStartLoadingResponseBody, OnComplete while
-  // deferred.
+TEST_P(URLLoaderClientImplTest,
+       DeferredAndDeferredWithBackForwardCacheTransitions) {
+  if (!DeferWithBackForwardCacheEnabled())
+    return;
+  // Call OnReceiveResponse and OnStartLoadingResponseBody while
+  // deferred (not for back-forward cache).
   dispatcher_->SetDefersLoading(request_id_,
                                 blink::WebURLLoader::DeferType::kDeferred);
   url_loader_client_->OnReceiveResponse(network::mojom::URLResponseHead::New());
@@ -338,6 +341,79 @@
   ASSERT_EQ(MOJO_RESULT_OK,
             mojo::CreateDataPipe(nullptr, &producer_handle, &consumer_handle));
   url_loader_client_->OnStartLoadingResponseBody(std::move(consumer_handle));
+  base::RunLoop().RunUntilIdle();
+  EXPECT_FALSE(request_peer_context_.received_response);
+  EXPECT_FALSE(request_peer_context_.complete);
+  EXPECT_EQ("", GetRequestPeerContextBody(&request_peer_context_));
+
+  // Write data to the response body pipe.
+  std::string msg1 = "he";
+  uint32_t size = msg1.size();
+  ASSERT_EQ(MOJO_RESULT_OK, producer_handle->WriteData(
+                                msg1.data(), &size, MOJO_WRITE_DATA_FLAG_NONE));
+  EXPECT_EQ(msg1.size(), size);
+  base::RunLoop().RunUntilIdle();
+  EXPECT_EQ("", GetRequestPeerContextBody(&request_peer_context_));
+
+  // Defer for back-forward cache.
+  dispatcher_->SetDefersLoading(
+      request_id_,
+      blink::WebURLLoader::DeferType::kDeferredWithBackForwardCache);
+  std::string msg2 = "ll";
+  size = msg2.size();
+  ASSERT_EQ(MOJO_RESULT_OK, producer_handle->WriteData(
+                                msg2.data(), &size, MOJO_WRITE_DATA_FLAG_NONE));
+  EXPECT_EQ(msg2.size(), size);
+  base::RunLoop().RunUntilIdle();
+  EXPECT_EQ("", GetRequestPeerContextBody(&request_peer_context_));
+
+  // Defer not for back-forward cache again.
+  dispatcher_->SetDefersLoading(
+      request_id_,
+      blink::WebURLLoader::DeferType::kDeferredWithBackForwardCache);
+  std::string msg3 = "o";
+  size = msg3.size();
+  ASSERT_EQ(MOJO_RESULT_OK, producer_handle->WriteData(
+                                msg3.data(), &size, MOJO_WRITE_DATA_FLAG_NONE));
+  EXPECT_EQ(msg3.size(), size);
+  base::RunLoop().RunUntilIdle();
+  EXPECT_EQ("", GetRequestPeerContextBody(&request_peer_context_));
+
+  // Stop deferring.
+  dispatcher_->SetDefersLoading(request_id_,
+                                blink::WebURLLoader::DeferType::kNotDeferred);
+  base::RunLoop().RunUntilIdle();
+  EXPECT_TRUE(request_peer_context_.received_response);
+  EXPECT_FALSE(request_peer_context_.complete);
+  EXPECT_EQ("hello", GetRequestPeerContextBody(&request_peer_context_));
+
+  // Write more data to the pipe while not deferred.
+  std::string msg4 = "world";
+  size = msg4.size();
+  ASSERT_EQ(MOJO_RESULT_OK, producer_handle->WriteData(
+                                msg4.data(), &size, MOJO_WRITE_DATA_FLAG_NONE));
+  EXPECT_EQ(msg4.size(), size);
+  base::RunLoop().RunUntilIdle();
+  EXPECT_TRUE(request_peer_context_.received_response);
+  EXPECT_FALSE(request_peer_context_.complete);
+  EXPECT_EQ("helloworld", GetRequestPeerContextBody(&request_peer_context_));
+}
+
+TEST_P(URLLoaderClientImplTest,
+       DeferredWithBackForwardCacheStoppedDeferringBeforeClosing) {
+  if (!DeferWithBackForwardCacheEnabled())
+    return;
+  // Call OnReceiveResponse, OnStartLoadingResponseBody, OnComplete while
+  // deferred.
+  dispatcher_->SetDefersLoading(
+      request_id_,
+      blink::WebURLLoader::DeferType::kDeferredWithBackForwardCache);
+  url_loader_client_->OnReceiveResponse(network::mojom::URLResponseHead::New());
+  mojo::ScopedDataPipeProducerHandle producer_handle;
+  mojo::ScopedDataPipeConsumerHandle consumer_handle;
+  ASSERT_EQ(MOJO_RESULT_OK,
+            mojo::CreateDataPipe(nullptr, &producer_handle, &consumer_handle));
+  url_loader_client_->OnStartLoadingResponseBody(std::move(consumer_handle));
   network::URLLoaderCompletionStatus status;
   url_loader_client_->OnComplete(status);
   base::RunLoop().RunUntilIdle();
@@ -364,7 +440,7 @@
   EXPECT_TRUE(request_peer_context_.received_response);
   // When the body is buffered, we'll wait until the pipe is closed before
   // sending the OnComplete message.
-  EXPECT_NE(BufferingEnabled(), request_peer_context_.complete);
+  EXPECT_FALSE(request_peer_context_.complete);
   EXPECT_EQ("hello", GetRequestPeerContextBody(&request_peer_context_));
 
   // Write more data to the pipe while not deferred.
@@ -375,7 +451,7 @@
   EXPECT_EQ(msg2.size(), size);
   base::RunLoop().RunUntilIdle();
   EXPECT_TRUE(request_peer_context_.received_response);
-  EXPECT_NE(BufferingEnabled(), request_peer_context_.complete);
+  EXPECT_FALSE(request_peer_context_.complete);
   EXPECT_EQ("helloworld", GetRequestPeerContextBody(&request_peer_context_));
 
   // Close the response body pipe.
@@ -428,11 +504,14 @@
   EXPECT_EQ("hello", GetRequestPeerContextBody(&request_peer_context_));
 }
 
-TEST_P(URLLoaderClientImplTest, DeferredWithLongResponseBody) {
+TEST_P(URLLoaderClientImplTest, DeferredWithBackForwardCacheLongResponseBody) {
+  if (!DeferWithBackForwardCacheEnabled())
+    return;
   // Call OnReceiveResponse, OnStartLoadingResponseBody, OnComplete while
   // deferred.
-  dispatcher_->SetDefersLoading(request_id_,
-                                blink::WebURLLoader::DeferType::kDeferred);
+  dispatcher_->SetDefersLoading(
+      request_id_,
+      blink::WebURLLoader::DeferType::kDeferredWithBackForwardCache);
   url_loader_client_->OnReceiveResponse(network::mojom::URLResponseHead::New());
   mojo::ScopedDataPipeProducerHandle producer_handle;
   mojo::ScopedDataPipeConsumerHandle consumer_handle;
@@ -456,15 +535,10 @@
     MojoResult result = producer_handle->WriteData(
         body.c_str() + start_position, &bytes_sent, MOJO_WRITE_DATA_FLAG_NONE);
     if (result == MOJO_RESULT_SHOULD_WAIT) {
-      if (BufferingEnabled()) {
         // When we buffer the body the pipe gets drained asynchronously, so it's
         // possible to keep writing to the pipe if we wait.
         base::RunLoop().RunUntilIdle();
         continue;
-      } else
-        // When we don't buffer the body, however, nothing is draining the pipe
-        // so we can't write more even if we wait.
-        break;
     }
     EXPECT_EQ(MOJO_RESULT_OK, result);
     EXPECT_GE(bytes_remaining, bytes_sent);
@@ -473,7 +547,7 @@
   // Ensure we've written all that we can write. When buffering is disabled, we
   // can only write |body_size| - |bytes_remaining| bytes.
   const uint32_t bytes_written = body_size - bytes_remaining;
-  DCHECK_EQ(BufferingEnabled(), body_size == bytes_written);
+  EXPECT_EQ(body_size, bytes_written);
   producer_handle.reset();
 
   // Stop deferring.
@@ -483,7 +557,7 @@
   EXPECT_TRUE(request_peer_context_.received_response);
   // When the body is buffered, BodyBuffer shouldn't be finished writing to the
   // new response body pipe at this point (because nobody is reading it).
-  EXPECT_NE(BufferingEnabled(), request_peer_context_.complete);
+  EXPECT_FALSE(request_peer_context_.complete);
 
   // Calling GetRequestPeerContextBody to read data from the new response body
   // pipe will make BodyBuffer write the rest of the body to the pipe.
@@ -494,8 +568,7 @@
   }
   // Ensure that we've read everything we've written.
   EXPECT_EQ(bytes_written, bytes_read);
-  EXPECT_EQ(body.substr(0, bytes_written),
-            GetRequestPeerContextBody(&request_peer_context_));
+  EXPECT_EQ(body, GetRequestPeerContextBody(&request_peer_context_));
   EXPECT_TRUE(request_peer_context_.complete);
 }
 
diff --git a/content/renderer/loader/web_url_loader_impl.cc b/content/renderer/loader/web_url_loader_impl.cc
index 32354af..1e3f2e7 100644
--- a/content/renderer/loader/web_url_loader_impl.cc
+++ b/content/renderer/loader/web_url_loader_impl.cc
@@ -32,6 +32,7 @@
 #include "components/variations/net/variations_url_loader_throttle.h"
 #include "content/child/child_thread_impl.h"
 #include "content/common/frame.mojom.h"
+#include "content/common/net/ip_address_space_util.h"
 #include "content/public/common/content_constants.h"
 #include "content/public/common/content_features.h"
 #include "content/public/common/navigation_policy.h"
@@ -54,7 +55,6 @@
 #include "net/ssl/ssl_connection_status_flags.h"
 #include "net/ssl/ssl_info.h"
 #include "services/network/public/cpp/http_raw_request_response_info.h"
-#include "services/network/public/cpp/ip_address_space_util.h"
 #include "services/network/public/cpp/resource_request.h"
 #include "services/network/public/mojom/ip_address_space.mojom-shared.h"
 #include "services/network/public/mojom/trust_tokens.mojom-shared.h"
@@ -633,8 +633,8 @@
   uint32_t loader_options = network::mojom::kURLLoadOptionNone;
   if (!no_mime_sniffing) {
     loader_options |= network::mojom::kURLLoadOptionSniffMimeType;
-    throttles.push_back(
-        std::make_unique<blink::MimeSniffingThrottle>(freezable_task_runner_));
+    throttles.push_back(std::make_unique<blink::MimeSniffingThrottle>(
+        unfreezable_task_runner_));
   }
 
   if (sync_load_response) {
@@ -659,8 +659,11 @@
 
   TRACE_EVENT_WITH_FLOW0("loading", "WebURLLoaderImpl::Context::Start", this,
                          TRACE_EVENT_FLAG_FLOW_OUT);
+  // If we use freezable_task_runner_, we won't call
+  // URLLoaderClientImpl::OnStartLoadingResponseBody until after bfcache
+  // restore. Is this OK?
   request_id_ = resource_dispatcher_->StartAsync(
-      std::move(request), requestor_id, freezable_task_runner_,
+      std::move(request), requestor_id, unfreezable_task_runner_,
       GetTrafficAnnotationTag(resource_type), loader_options, std::move(peer),
       url_loader_factory_, std::move(throttles),
       std::move(resource_load_info_notifier_wrapper));
@@ -896,21 +899,13 @@
           : blink::WebString());
 
   response->SetRemoteIPEndpoint(head.remote_endpoint);
-
   // This computation can only be done once SetUrlListViaServiceWorker() has
   // been called on |response|, so that ResponseUrl() returns the correct
   // answer.
   //
   // Implements: https://wicg.github.io/cors-rfc1918/#integration-html
-  //
-  // TODO(crbug.com/955213): Just copy the address space in |head| once it is
-  // made available.
-  if (response->ResponseUrl().ProtocolIs("file")) {
-    response->SetAddressSpace(network::mojom::IPAddressSpace::kLocal);
-  } else {
-    response->SetAddressSpace(
-        network::IPAddressToIPAddressSpace(head.remote_endpoint.address()));
-  }
+  response->SetAddressSpace(CalculateResourceAddressSpace(
+      response->ResponseUrl(), head.remote_endpoint.address()));
 
   blink::WebVector<blink::WebString> cors_exposed_header_names(
       head.cors_exposed_header_names.size());
diff --git a/content/renderer/render_frame_impl.cc b/content/renderer/render_frame_impl.cc
index 940181e..de76a54 100644
--- a/content/renderer/render_frame_impl.cc
+++ b/content/renderer/render_frame_impl.cc
@@ -4230,13 +4230,13 @@
       GetTransitionType(frame_->GetDocumentLoader(), IsMainFrame());
 
   DidCommitNavigationInternal(
-      commit_type, false /* was_within_same_document */, transition,
-      sandbox_flags, feature_policy_header, document_policy_header,
+      commit_type, transition, sandbox_flags, feature_policy_header,
+      document_policy_header,
       should_reset_browser_interface_broker
           ? mojom::DidCommitProvisionalLoadInterfaceParams::New(
                 std::move(browser_interface_broker_receiver))
           : nullptr,
-      GetWebFrame()->GetEmbeddingToken());
+      nullptr /* same_document_params */, GetWebFrame()->GetEmbeddingToken());
 
   // If we end up reusing this WebRequest (for example, due to a #ref click),
   // we don't want the transition type to persist.  Just clear it.
@@ -4372,7 +4372,8 @@
 
 void RenderFrameImpl::DidFinishSameDocumentNavigation(
     blink::WebHistoryCommitType commit_type,
-    bool content_initiated) {
+    bool content_initiated,
+    bool is_history_api_navigation) {
   TRACE_EVENT1("navigation,rail",
                "RenderFrameImpl::didFinishSameDocumentNavigation", "id",
                routing_id_);
@@ -4385,14 +4386,16 @@
 
   ui::PageTransition transition =
       GetTransitionType(frame_->GetDocumentLoader(), IsMainFrame());
+  auto same_document_params =
+      mojom::DidCommitSameDocumentNavigationParams::New();
+  same_document_params->is_history_api_navigation = is_history_api_navigation;
   DidCommitNavigationInternal(
-      commit_type,
-      true,  // was_within_same_document
-      transition, network::mojom::WebSandboxFlags(),
+      commit_type, transition, network::mojom::WebSandboxFlags(),
       blink::ParsedFeaturePolicy(),         // feature_policy_header
       blink::DocumentPolicyFeatureState(),  // document_policy_header
       nullptr,                              // interface_params
-      base::nullopt                         // embedding_token
+      std::move(same_document_params),
+      base::nullopt  // embedding_token
   );
 
   // If we end up reusing this WebRequest (for example, due to a #ref click),
@@ -5186,14 +5189,14 @@
 
 void RenderFrameImpl::DidCommitNavigationInternal(
     blink::WebHistoryCommitType commit_type,
-    bool was_within_same_document,
     ui::PageTransition transition,
     network::mojom::WebSandboxFlags sandbox_flags,
     const blink::ParsedFeaturePolicy& feature_policy_header,
     const blink::DocumentPolicyFeatureState& document_policy_header,
     mojom::DidCommitProvisionalLoadInterfaceParamsPtr interface_params,
+    mojom::DidCommitSameDocumentNavigationParamsPtr same_document_params,
     const base::Optional<base::UnguessableToken>& embedding_token) {
-  DCHECK(!(was_within_same_document && interface_params));
+  DCHECK(!(same_document_params && interface_params));
   UpdateStateForCommit(commit_type, transition);
 
   if (render_view_->renderer_wide_named_frame_lookup())
@@ -5208,8 +5211,9 @@
       commit_type, transition, sandbox_flags, feature_policy_header,
       document_policy_header, embedding_token);
 
-  if (was_within_same_document) {
-    GetFrameHost()->DidCommitSameDocumentNavigation(std::move(params));
+  if (same_document_params) {
+    GetFrameHost()->DidCommitSameDocumentNavigation(
+        std::move(params), std::move(same_document_params));
   } else {
     NavigationState* navigation_state =
         NavigationState::FromDocumentLoader(frame_->GetDocumentLoader());
diff --git a/content/renderer/render_frame_impl.h b/content/renderer/render_frame_impl.h
index 27510ec..0798db2 100644
--- a/content/renderer/render_frame_impl.h
+++ b/content/renderer/render_frame_impl.h
@@ -624,7 +624,8 @@
   void DidHandleOnloadEvents() override;
   void DidFinishLoad() override;
   void DidFinishSameDocumentNavigation(blink::WebHistoryCommitType commit_type,
-                                       bool content_initiated) override;
+                                       bool content_initiated,
+                                       bool is_history_api_navigation) override;
   void DidUpdateCurrentHistoryItem() override;
   base::UnguessableToken GetDevToolsFrameToken() override;
   void AbortClientNavigation() override;
@@ -1086,12 +1087,12 @@
   // a commit message to the browser process.
   void DidCommitNavigationInternal(
       blink::WebHistoryCommitType commit_type,
-      bool was_within_same_document,
       ui::PageTransition transition,
       network::mojom::WebSandboxFlags sandbox_flags,
       const blink::ParsedFeaturePolicy& feature_policy_header,
       const blink::DocumentPolicyFeatureState& document_policy_header,
       mojom::DidCommitProvisionalLoadInterfaceParamsPtr interface_params,
+      mojom::DidCommitSameDocumentNavigationParamsPtr same_document_params,
       const base::Optional<base::UnguessableToken>& embedding_token);
 
   blink::WebComputedAXTree* GetOrCreateWebComputedAXTree() override;
diff --git a/content/test/test_render_frame.cc b/content/test/test_render_frame.cc
index b0d41c155..cfa424a 100644
--- a/content/test/test_render_frame.cc
+++ b/content/test/test_render_frame.cc
@@ -150,7 +150,9 @@
   }
 
   void DidCommitSameDocumentNavigation(
-      mojom::DidCommitProvisionalLoadParamsPtr params) override {
+      mojom::DidCommitProvisionalLoadParamsPtr params,
+      mojom::DidCommitSameDocumentNavigationParamsPtr same_doc_params)
+      override {
     last_commit_params_ = std::move(params);
   }
 
diff --git a/content/test/test_render_frame_host.cc b/content/test/test_render_frame_host.cc
index a2cbc4d..a8dd845 100644
--- a/content/test/test_render_frame_host.cc
+++ b/content/test/test_render_frame_host.cc
@@ -274,7 +274,10 @@
     bool was_within_same_document) {
   last_commit_was_error_page_ = params->url_is_unreachable;
   if (was_within_same_document) {
-    DidCommitSameDocumentNavigation(std::move(params));
+    auto same_doc_params = mojom::DidCommitSameDocumentNavigationParams::New();
+    same_doc_params->is_history_api_navigation = false;
+    DidCommitSameDocumentNavigation(std::move(params),
+                                    std::move(same_doc_params));
   } else {
     DidCommitProvisionalLoad(std::move(params), std::move(interface_params));
   }
diff --git a/docs/vscode.md b/docs/vscode.md
index 523473f..d51e75a 100644
--- a/docs/vscode.md
+++ b/docs/vscode.md
@@ -75,24 +75,6 @@
 }
 ```
 
-#### Rendering of underscore on Linux
-
-As mentioned in [#35901](https://github.com/Microsoft/vscode/issues/35901), VS
-Code will not show underscore (`_`) properly on Linux by default. You can work
-around this issue by forcing another font such as the default `monospace` or
-changing the font size in your settings:
-
-```json
-{
-  // If you want to use the default "monospace" font:
-  //"terminal.integrated.fontFamily": "monospace"
-  // If you would rather just increase the size of the font:
-  //"terminal.integrated.fontSize": 15
-  // If you would rather decrease the size of the font:
-  //"terminal.integrated.fontSize": 13
-}
-```
-
 ### Useful Extensions
 
 Up to now, you have a basic version of VS Code without much language support.
diff --git a/extensions/browser/extension_prefs.cc b/extensions/browser/extension_prefs.cc
index 7ccabed..bd26e97 100644
--- a/extensions/browser/extension_prefs.cc
+++ b/extensions/browser/extension_prefs.cc
@@ -2308,7 +2308,6 @@
   registry->RegisterListPref(pref_names::kInstallAllowList);
   registry->RegisterListPref(pref_names::kInstallDenyList);
   registry->RegisterDictionaryPref(pref_names::kInstallForceList);
-  registry->RegisterDictionaryPref(pref_names::kLoginScreenExtensions);
   registry->RegisterListPref(pref_names::kAllowedTypes);
   registry->RegisterBooleanPref(pref_names::kStorageGarbageCollect, false);
   registry->RegisterListPref(pref_names::kAllowedInstallSites);
diff --git a/extensions/browser/pref_names.cc b/extensions/browser/pref_names.cc
index 30e8453..f516115c1 100644
--- a/extensions/browser/pref_names.cc
+++ b/extensions/browser/pref_names.cc
@@ -38,8 +38,6 @@
 const char kInstallAllowList[] = "extensions.install.allowlist";
 const char kInstallDenyList[] = "extensions.install.denylist";
 const char kInstallForceList[] = "extensions.install.forcelist";
-const char kLoginScreenExtensions[] =
-    "extensions.install.login_screen_extensions";
 const char kLastChromeVersion[] = "extensions.last_chrome_version";
 const char kNativeMessagingBlocklist[] = "native_messaging.blacklist";
 const char kNativeMessagingAllowlist[] = "native_messaging.whitelist";
diff --git a/extensions/browser/pref_names.h b/extensions/browser/pref_names.h
index 7356be8..bd92e38 100644
--- a/extensions/browser/pref_names.h
+++ b/extensions/browser/pref_names.h
@@ -73,13 +73,6 @@
 // accessed through extensions::ExternalPolicyProvider.
 extern const char kInstallForceList[];
 
-// A list containing apps or extensions that Chrome will silently install on the
-// login screen on Chrome OS at startup time. It is a list of strings, each
-// string contains an app ID and an update URL, delimited by a semicolon. This
-// preference is set by an admin policy, and meant to be only accessed through
-// extensions::ExternalPolicyProvider.
-extern const char kLoginScreenExtensions[];
-
 // String pref for what version chrome was last time the extension prefs were
 // loaded.
 extern const char kLastChromeVersion[];
diff --git a/extensions/shell/browser/shell_desktop_controller_aura.cc b/extensions/shell/browser/shell_desktop_controller_aura.cc
index 490f6421..48090e6 100644
--- a/extensions/shell/browser/shell_desktop_controller_aura.cc
+++ b/extensions/shell/browser/shell_desktop_controller_aura.cc
@@ -212,7 +212,7 @@
 #if BUILDFLAG(IS_CHROMEOS_ASH)
 void ShellDesktopControllerAura::PowerButtonEventReceived(
     bool down,
-    const base::TimeTicks& timestamp) {
+    base::TimeTicks timestamp) {
   if (down) {
     chromeos::PowerManagerClient::Get()->RequestShutdown(
         power_manager::REQUEST_SHUTDOWN_FOR_USER, "AppShell power button");
diff --git a/extensions/shell/browser/shell_desktop_controller_aura.h b/extensions/shell/browser/shell_desktop_controller_aura.h
index 85778a97..f9bd47b 100644
--- a/extensions/shell/browser/shell_desktop_controller_aura.h
+++ b/extensions/shell/browser/shell_desktop_controller_aura.h
@@ -88,8 +88,7 @@
 
 #if BUILDFLAG(IS_CHROMEOS_ASH)
   // chromeos::PowerManagerClient::Observer:
-  void PowerButtonEventReceived(bool down,
-                                const base::TimeTicks& timestamp) override;
+  void PowerButtonEventReceived(bool down, base::TimeTicks timestamp) override;
 
   // display::DisplayConfigurator::Observer:
   void OnDisplayModeChanged(
diff --git a/headless/lib/browser/headless_print_manager.cc b/headless/lib/browser/headless_print_manager.cc
index 67ffbad..be9c9ac4 100644
--- a/headless/lib/browser/headless_print_manager.cc
+++ b/headless/lib/browser/headless_print_manager.cc
@@ -259,22 +259,23 @@
   ReleaseJob(PRINTING_FAILED);
 }
 
-void HeadlessPrintManager::OnDidPrintDocument(
-    content::RenderFrameHost* render_frame_host,
-    const printing::mojom::DidPrintDocumentParams& params,
-    std::unique_ptr<DelayedFrameDispatchHelper> helper) {
-  auto& content = *params.content;
+void HeadlessPrintManager::DidPrintDocument(
+    printing::mojom::DidPrintDocumentParamsPtr params,
+    DidPrintDocumentCallback callback) {
+  auto& content = *params->content;
   if (!content.metafile_data_region.IsValid()) {
     ReleaseJob(INVALID_MEMORY_HANDLE);
+    std::move(callback).Run(false);
     return;
   }
   base::ReadOnlySharedMemoryMapping map = content.metafile_data_region.Map();
   if (!map.IsValid()) {
     ReleaseJob(METAFILE_MAP_ERROR);
+    std::move(callback).Run(false);
     return;
   }
   data_ = std::string(static_cast<const char*>(map.memory()), map.size());
-  helper->SendCompleted();
+  std::move(callback).Run(true);
   ReleaseJob(PRINT_SUCCESS);
 }
 
diff --git a/headless/lib/browser/headless_print_manager.h b/headless/lib/browser/headless_print_manager.h
index ce2236d..fd5f373 100644
--- a/headless/lib/browser/headless_print_manager.h
+++ b/headless/lib/browser/headless_print_manager.h
@@ -95,15 +95,13 @@
                          content::RenderFrameHost* render_frame_host) override;
 
   // printing::PrintManager:
-  void OnDidPrintDocument(
-      content::RenderFrameHost* render_frame_host,
-      const printing::mojom::DidPrintDocumentParams& params,
-      std::unique_ptr<DelayedFrameDispatchHelper> helper) override;
   void OnScriptedPrint(content::RenderFrameHost* render_frame_host,
                        const printing::mojom::ScriptedPrintParams& params,
                        IPC::Message* reply_msg) override;
 
   // printing::mojom::PrintManagerHost:
+  void DidPrintDocument(printing::mojom::DidPrintDocumentParamsPtr params,
+                        DidPrintDocumentCallback callback) override;
   void GetDefaultPrintSettings(
       GetDefaultPrintSettingsCallback callback) override;
   void ShowInvalidPrinterSettingsError() override;
diff --git a/ios/chrome/browser/ui/browser_view/BUILD.gn b/ios/chrome/browser/ui/browser_view/BUILD.gn
index d5874727..84b92cf 100644
--- a/ios/chrome/browser/ui/browser_view/BUILD.gn
+++ b/ios/chrome/browser/ui/browser_view/BUILD.gn
@@ -102,6 +102,9 @@
     "//ios/chrome/browser/ui/gestures",
     "//ios/chrome/browser/ui/history",
     "//ios/chrome/browser/ui/image_util:web",
+    "//ios/chrome/browser/ui/incognito_reauth:incognito_reauth_commands",
+    "//ios/chrome/browser/ui/incognito_reauth:incognito_reauth_scene_agent",
+    "//ios/chrome/browser/ui/incognito_reauth:incognito_reauth_ui",
     "//ios/chrome/browser/ui/infobars",
     "//ios/chrome/browser/ui/infobars:feature_flags",
     "//ios/chrome/browser/ui/infobars:public",
@@ -239,6 +242,7 @@
     "//ios/chrome/browser/ui/browser_container:ui",
     "//ios/chrome/browser/ui/commands",
     "//ios/chrome/browser/ui/fullscreen:feature_flags",
+    "//ios/chrome/browser/ui/incognito_reauth:incognito_reauth_scene_agent",
     "//ios/chrome/browser/ui/main:scene_state_header",
     "//ios/chrome/browser/ui/toolbar/public",
     "//ios/chrome/browser/ui/toolbar/test",
@@ -248,6 +252,7 @@
     "//ios/chrome/browser/web_state_list",
     "//ios/chrome/browser/web_state_list:test_support",
     "//ios/chrome/browser/web_state_list/web_usage_enabler",
+    "//ios/chrome/common/ui/reauthentication:reauthentication",
     "//ios/chrome/test:block_cleanup_test",
     "//ios/chrome/test:test_support",
     "//ios/net",
diff --git a/ios/chrome/browser/ui/browser_view/browser_coordinator.mm b/ios/chrome/browser/ui/browser_view/browser_coordinator.mm
index 1435317c..15c957d2 100644
--- a/ios/chrome/browser/ui/browser_view/browser_coordinator.mm
+++ b/ios/chrome/browser/ui/browser_view/browser_coordinator.mm
@@ -45,7 +45,10 @@
 #import "ios/chrome/browser/ui/download/pass_kit_coordinator.h"
 #import "ios/chrome/browser/ui/find_bar/find_bar_controller_ios.h"
 #import "ios/chrome/browser/ui/find_bar/find_bar_coordinator.h"
+#import "ios/chrome/browser/ui/incognito_reauth/incognito_reauth_mediator.h"
+#import "ios/chrome/browser/ui/incognito_reauth/incognito_reauth_scene_agent.h"
 #import "ios/chrome/browser/ui/infobars/infobar_feature.h"
+#import "ios/chrome/browser/ui/main/scene_state_browser_agent.h"
 #import "ios/chrome/browser/ui/open_in/open_in_mediator.h"
 #import "ios/chrome/browser/ui/overlays/overlay_container_coordinator.h"
 #import "ios/chrome/browser/ui/page_info/page_info_coordinator.h"
@@ -104,6 +107,9 @@
 // Mediator between OpenIn TabHelper and OpenIn UI.
 @property(nonatomic, strong) OpenInMediator* openInMediator;
 
+// Mediator for incognito reauth.
+@property(nonatomic, strong) IncognitoReauthMediator* incognitoAuthMediator;
+
 // =================================================
 // Child Coordinators, listed in alphabetical order.
 // =================================================
@@ -226,6 +232,7 @@
   [self startBrowserContainer];
   [self createViewController];
   [self startChildCoordinators];
+  [self startMediators];
   [self installDelegatesForAllWebStates];
   [self installDelegatesForBrowser];
   [self addWebStateListObserver];
@@ -470,6 +477,27 @@
   self.defaultBrowserPromoCoordinator = nil;
 }
 
+// Starts mediators owned by this coordinator.
+- (void)startMediators {
+  if (self.browser->GetBrowserState()->IsOffTheRecord()) {
+    IncognitoReauthSceneAgent* reauthAgent = nil;
+    for (id agent in SceneStateBrowserAgent::FromBrowser(self.browser)
+             ->GetSceneState()
+             .connectedAgents) {
+      if ([agent isKindOfClass:[IncognitoReauthSceneAgent class]]) {
+        reauthAgent = agent;
+      }
+    }
+
+    self.incognitoAuthMediator =
+        [[IncognitoReauthMediator alloc] initWithConsumer:self.viewController
+                                              reauthAgent:reauthAgent];
+  }
+
+  self.viewController.reauthHandler =
+      HandlerForProtocol(self.dispatcher, IncognitoReauthCommands);
+}
+
 #pragma mark - ActivityServiceCommands
 
 - (void)sharePage {
diff --git a/ios/chrome/browser/ui/browser_view/browser_coordinator_unittest.mm b/ios/chrome/browser/ui/browser_view/browser_coordinator_unittest.mm
index 8fefd6921..6c4eb92a 100644
--- a/ios/chrome/browser/ui/browser_view/browser_coordinator_unittest.mm
+++ b/ios/chrome/browser/ui/browser_view/browser_coordinator_unittest.mm
@@ -12,10 +12,12 @@
 #import "ios/chrome/browser/ui/commands/browser_coordinator_commands.h"
 #import "ios/chrome/browser/ui/commands/command_dispatcher.h"
 #import "ios/chrome/browser/ui/fullscreen/fullscreen_features.h"
+#import "ios/chrome/browser/ui/incognito_reauth/incognito_reauth_scene_agent.h"
 #import "ios/chrome/browser/ui/main/scene_state.h"
 #import "ios/chrome/browser/ui/main/scene_state_browser_agent.h"
 #import "ios/chrome/browser/url_loading/url_loading_notifier_browser_agent.h"
 #import "ios/chrome/browser/web/web_navigation_browser_agent.h"
+#import "ios/chrome/common/ui/reauthentication/reauthentication_module.h"
 #include "ios/web/public/test/web_task_environment.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "testing/gtest_mac.h"
@@ -37,6 +39,14 @@
     UrlLoadingNotifierBrowserAgent::CreateForBrowser(browser_.get());
     SceneStateBrowserAgent::CreateForBrowser(browser_.get(), scene_state_);
     WebNavigationBrowserAgent::CreateForBrowser(browser_.get());
+
+    IncognitoReauthSceneAgent* reauthAgent = [[IncognitoReauthSceneAgent alloc]
+        initWithReauthModule:[[ReauthenticationModule alloc] init]];
+    [scene_state_ addAgent:reauthAgent];
+
+    CommandDispatcher* dispatcher = browser_->GetCommandDispatcher();
+    [dispatcher startDispatchingToTarget:reauthAgent
+                             forProtocol:@protocol(IncognitoReauthCommands)];
   }
 
   BrowserCoordinator* GetBrowserCoordinator() {
diff --git a/ios/chrome/browser/ui/browser_view/browser_view_controller.h b/ios/chrome/browser/ui/browser_view/browser_view_controller.h
index ba951c2..7cd27562 100644
--- a/ios/chrome/browser/ui/browser_view/browser_view_controller.h
+++ b/ios/chrome/browser/ui/browser_view/browser_view_controller.h
@@ -10,6 +10,7 @@
 #import "base/ios/block_types.h"
 #import "ios/chrome/browser/ui/find_bar/find_bar_coordinator.h"
 #import "ios/chrome/browser/ui/gestures/view_revealing_vertical_pan_handler.h"
+#import "ios/chrome/browser/ui/incognito_reauth/incognito_reauth_consumer.h"
 #import "ios/chrome/browser/ui/page_info/requirements/page_info_presentation.h"
 #import "ios/chrome/browser/ui/settings/sync/utils/sync_presenter.h"
 #import "ios/chrome/browser/ui/thumb_strip/thumb_strip_attacher.h"
@@ -23,12 +24,14 @@
 @class BrowserViewControllerDependencyFactory;
 @class CommandDispatcher;
 @class ToolbarAccessoryPresenter;
+@protocol IncognitoReauthCommands;
 
 // The top-level view controller for the browser UI. Manages other controllers
 // which implement the interface.
 @interface BrowserViewController
-    : UIViewController <LogoAnimationControllerOwnerOwner,
-                        FindBarPresentationDelegate,
+    : UIViewController <FindBarPresentationDelegate,
+                        IncognitoReauthConsumer,
+                        LogoAnimationControllerOwnerOwner,
                         PageInfoPresentation,
                         SyncPresenter,
                         ThumbStripAttacher,
@@ -56,6 +59,9 @@
 // Command dispatcher.
 @property(nonatomic, weak) CommandDispatcher* commandDispatcher;
 
+// Handler for reauth commands.
+@property(nonatomic, weak) id<IncognitoReauthCommands> reauthHandler;
+
 // Returns whether or not text to speech is playing.
 @property(nonatomic, assign, readonly, getter=isPlayingTTS) BOOL playingTTS;
 
diff --git a/ios/chrome/browser/ui/browser_view/browser_view_controller.mm b/ios/chrome/browser/ui/browser_view/browser_view_controller.mm
index 642e22f..bc08ab9 100644
--- a/ios/chrome/browser/ui/browser_view/browser_view_controller.mm
+++ b/ios/chrome/browser/ui/browser_view/browser_view_controller.mm
@@ -94,6 +94,8 @@
 #import "ios/chrome/browser/ui/gestures/view_revealing_animatee.h"
 #import "ios/chrome/browser/ui/image_util/image_copier.h"
 #import "ios/chrome/browser/ui/image_util/image_saver.h"
+#import "ios/chrome/browser/ui/incognito_reauth/incognito_reauth_commands.h"
+#import "ios/chrome/browser/ui/incognito_reauth/incognito_reauth_view.h"
 #import "ios/chrome/browser/ui/infobars/infobar_container_coordinator.h"
 #import "ios/chrome/browser/ui/infobars/infobar_feature.h"
 #import "ios/chrome/browser/ui/infobars/infobar_positioner.h"
@@ -500,6 +502,9 @@
 @property(nonatomic, assign) BOOL viewVisible;
 // Whether the controller should broadcast its UI.
 @property(nonatomic, assign, getter=isBroadcasting) BOOL broadcasting;
+// A view to obscure incognito content when the user isn't authorized to
+// see it.
+@property(nonatomic, strong) IncognitoReauthView* blockingView;
 // Whether the controller is currently dismissing a presented view controller.
 @property(nonatomic, assign, getter=isDismissingModal) BOOL dismissingModal;
 // Whether web usage is enabled for the WebStates in |self.browser|.
@@ -4697,6 +4702,33 @@
   return self.contentArea;
 }
 
+#pragma mark - IncognitoReauthConsumer
+
+- (void)setItemsRequireAuthentication:(BOOL)require {
+  if (require) {
+    if (!self.blockingView) {
+      self.blockingView = [[IncognitoReauthView alloc] init];
+      self.blockingView.translatesAutoresizingMaskIntoConstraints = NO;
+      self.blockingView.layer.zPosition = FLT_MAX;
+
+      [self.blockingView.authenticateButton
+                 addTarget:self.reauthHandler
+                    action:@selector(authenticateIncognitoContent)
+          forControlEvents:UIControlEventTouchUpInside];
+
+      [self.blockingView.tabSwitcherButton
+                 addTarget:self.dispatcher
+                    action:@selector(displayRegularTabSwitcherInGridLayout)
+          forControlEvents:UIControlEventTouchUpInside];
+    }
+
+    [self.view addSubview:self.blockingView];
+    AddSameConstraints(self.view, self.blockingView);
+  } else {
+    [self.blockingView removeFromSuperview];
+  }
+}
+
 #pragma mark - UIGestureRecognizerDelegate
 
 // Always return yes, as this tap should work with various recognizers,
diff --git a/ios/chrome/browser/ui/commands/application_commands.h b/ios/chrome/browser/ui/commands/application_commands.h
index 5dd5e162..0248911 100644
--- a/ios/chrome/browser/ui/commands/application_commands.h
+++ b/ios/chrome/browser/ui/commands/application_commands.h
@@ -112,6 +112,10 @@
 // TabSwitcher UI, specifically in its grid layout.
 - (void)displayTabSwitcherInGridLayout;
 
+// Same as displayTabSwitcherInGridLayout, but also force tab switcher to
+// regular tabs page.
+- (void)displayRegularTabSwitcherInGridLayout;
+
 // TODO(crbug.com/779791) : Do not pass baseViewController through dispatcher.
 // Shows the Autofill Settings UI, presenting from |baseViewController|.
 - (void)showAutofillSettingsFromViewController:
diff --git a/ios/chrome/browser/ui/incognito_reauth/incognito_reauth_mediator.mm b/ios/chrome/browser/ui/incognito_reauth/incognito_reauth_mediator.mm
index 67045fd..3497bf2 100644
--- a/ios/chrome/browser/ui/incognito_reauth/incognito_reauth_mediator.mm
+++ b/ios/chrome/browser/ui/incognito_reauth/incognito_reauth_mediator.mm
@@ -37,6 +37,10 @@
   return self;
 }
 
+- (void)dealloc {
+  [_reauthAgent removeObserver:self];
+}
+
 #pragma mark - IncognitoReauthObserver
 
 - (void)reauthAgent:(IncognitoReauthSceneAgent*)agent
diff --git a/ios/chrome/browser/ui/incognito_reauth/incognito_reauth_view.mm b/ios/chrome/browser/ui/incognito_reauth/incognito_reauth_view.mm
index 81b9ed8..61efcea 100644
--- a/ios/chrome/browser/ui/incognito_reauth/incognito_reauth_view.mm
+++ b/ios/chrome/browser/ui/incognito_reauth/incognito_reauth_view.mm
@@ -57,6 +57,9 @@
 
 + (NSString*)authenticationActionLabel {
   LAContext* ctx = [[LAContext alloc] init];
+  // Call canEvaluatePolicy:error: once to populate biometrics type
+  [ctx canEvaluatePolicy:LAPolicyDeviceOwnerAuthenticationWithBiometrics
+                   error:nil];
   switch (ctx.biometryType) {
     case LABiometryTypeFaceID:
       return @"Face ID";
diff --git a/ios/chrome/browser/ui/main/BUILD.gn b/ios/chrome/browser/ui/main/BUILD.gn
index f839799a2..406ec0f 100644
--- a/ios/chrome/browser/ui/main/BUILD.gn
+++ b/ios/chrome/browser/ui/main/BUILD.gn
@@ -187,6 +187,7 @@
     "//ios/chrome/browser/ui/commands",
     "//ios/chrome/browser/ui/coordinators:chrome_coordinators",
     "//ios/chrome/browser/ui/download",
+    "//ios/chrome/browser/ui/incognito_reauth:incognito_reauth_scene_agent",
     "//ios/chrome/browser/ui/page_info:coordinator",
     "//ios/chrome/browser/ui/print",
     "//ios/chrome/browser/ui/qr_scanner:coordinator",
diff --git a/ios/chrome/browser/ui/main/browser_view_wrangler.mm b/ios/chrome/browser/ui/main/browser_view_wrangler.mm
index 2dd93e83..d859111 100644
--- a/ios/chrome/browser/ui/main/browser_view_wrangler.mm
+++ b/ios/chrome/browser/ui/main/browser_view_wrangler.mm
@@ -24,6 +24,7 @@
 #import "ios/chrome/browser/ui/commands/application_commands.h"
 #import "ios/chrome/browser/ui/commands/browsing_data_commands.h"
 #import "ios/chrome/browser/ui/commands/command_dispatcher.h"
+#import "ios/chrome/browser/ui/incognito_reauth/incognito_reauth_scene_agent.h"
 #import "ios/chrome/browser/ui/main/scene_state.h"
 #import "ios/chrome/browser/ui/main/scene_state_browser_agent.h"
 #import "ios/chrome/browser/ui/util/multi_window_support.h"
@@ -432,9 +433,20 @@
 }
 
 - (void)dispatchToEndpointsForBrowser:(Browser*)browser {
-  [browser->GetCommandDispatcher()
-      startDispatchingToTarget:_applicationCommandEndpoint
-                   forProtocol:@protocol(ApplicationCommands)];
+  IncognitoReauthSceneAgent* reauthAgent = nil;
+  for (id agent in _sceneState.connectedAgents) {
+    if ([agent isKindOfClass:[IncognitoReauthSceneAgent class]]) {
+      reauthAgent = agent;
+    }
+  }
+
+  CommandDispatcher* dispatcher = browser->GetCommandDispatcher();
+  [dispatcher startDispatchingToTarget:reauthAgent
+                           forProtocol:@protocol(IncognitoReauthCommands)];
+
+  [dispatcher startDispatchingToTarget:_applicationCommandEndpoint
+                           forProtocol:@protocol(ApplicationCommands)];
+
   // -startDispatchingToTarget:forProtocol: doesn't pick up protocols the
   // passed protocol conforms to, so ApplicationSettingsCommands is explicitly
   // dispatched to the endpoint as well. Since this is potentially
@@ -442,12 +454,10 @@
   DCHECK(!_applicationCommandEndpoint ||
          [_applicationCommandEndpoint
              conformsToProtocol:@protocol(ApplicationSettingsCommands)]);
-  [browser->GetCommandDispatcher()
-      startDispatchingToTarget:_applicationCommandEndpoint
-                   forProtocol:@protocol(ApplicationSettingsCommands)];
-  [browser->GetCommandDispatcher()
-      startDispatchingToTarget:_browsingDataCommandEndpoint
-                   forProtocol:@protocol(BrowsingDataCommands)];
+  [dispatcher startDispatchingToTarget:_applicationCommandEndpoint
+                           forProtocol:@protocol(ApplicationSettingsCommands)];
+  [dispatcher startDispatchingToTarget:_browsingDataCommandEndpoint
+                           forProtocol:@protocol(BrowsingDataCommands)];
 }
 
 @end
diff --git a/ios/chrome/browser/ui/main/scene_controller.mm b/ios/chrome/browser/ui/main/scene_controller.mm
index 95a5ad94..beda9352 100644
--- a/ios/chrome/browser/ui/main/scene_controller.mm
+++ b/ios/chrome/browser/ui/main/scene_controller.mm
@@ -1057,7 +1057,15 @@
   [self.mainCoordinator prepareToShowTabGrid];
 }
 
+- (void)displayRegularTabSwitcherInGridLayout {
+  [self displayTabSwitcherForcingRegularTabs:YES];
+}
+
 - (void)displayTabSwitcherInGridLayout {
+  [self displayTabSwitcherForcingRegularTabs:NO];
+}
+
+- (void)displayTabSwitcherForcingRegularTabs:(BOOL)forcing {
   if (!IsThumbStripEnabled()) {
     // When the thumb strip feature is enabled, |self.tabSwitcherIsActive| could
     // be YES if the tab switcher button is tapped while the thumb strip is
@@ -1068,6 +1076,11 @@
   }
   if (!self.isProcessingVoiceSearchCommand) {
     [self.currentInterface.bvc userEnteredTabSwitcher];
+
+    if (forcing && self.currentInterface.incognito) {
+      [self setCurrentInterfaceForMode:ApplicationMode::NORMAL];
+    }
+
     [self showTabSwitcher];
     self.isProcessingTabSwitcherCommand = YES;
     dispatch_after(dispatch_time(DISPATCH_TIME_NOW,
@@ -2361,7 +2374,7 @@
 // Shows the tab switcher UI.
 - (void)showTabSwitcher {
   DCHECK(self.mainCoordinator);
-  [self.mainCoordinator setActivePage:[self activePage]];
+  [self.mainCoordinator setActivePage:self.activePage];
   self.tabSwitcherIsActive = YES;
   self.mainCoordinator.delegate = self;
 
diff --git a/ios/chrome/browser/ui/tab_switcher/tab_strip/BUILD.gn b/ios/chrome/browser/ui/tab_switcher/tab_strip/BUILD.gn
index c6b176b..8bab8a6 100644
--- a/ios/chrome/browser/ui/tab_switcher/tab_strip/BUILD.gn
+++ b/ios/chrome/browser/ui/tab_switcher/tab_strip/BUILD.gn
@@ -39,6 +39,7 @@
     "//ios/chrome/browser",
     "//ios/chrome/browser/browser_state",
     "//ios/chrome/browser/tabs",
+    "//ios/chrome/browser/ui/image_util",
     "//ios/chrome/browser/ui/tab_switcher",
     "//ios/chrome/browser/web:tab_id_tab_helper",
     "//ios/chrome/browser/web_state_list",
diff --git a/ios/chrome/browser/ui/tab_switcher/tab_strip/tab_strip_cell.mm b/ios/chrome/browser/ui/tab_switcher/tab_strip/tab_strip_cell.mm
index 730996e9..5c2433a 100644
--- a/ios/chrome/browser/ui/tab_switcher/tab_strip/tab_strip_cell.mm
+++ b/ios/chrome/browser/ui/tab_switcher/tab_strip/tab_strip_cell.mm
@@ -4,6 +4,7 @@
 
 #import "ios/chrome/browser/ui/tab_switcher/tab_strip/tab_strip_cell.h"
 
+#import "ios/chrome/browser/ui/image_util/image_util.h"
 #import "ios/chrome/common/ui/colors/semantic_color_names.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
@@ -21,13 +22,7 @@
 
 - (instancetype)initWithFrame:(CGRect)frame {
   if ((self = [super initWithFrame:frame])) {
-    NSString* imageName = @"tabstrip_background_tab";
-    UIImage* image = [UIImage imageNamed:imageName];
-    UIEdgeInsets insets =
-        UIEdgeInsetsMake(0, kTabBackgroundLeftCapInset, image.size.height + 1.0,
-                         image.size.width - kTabBackgroundLeftCapInset + 1.0);
-    self.backgroundView = [[UIImageView alloc]
-        initWithImage:[image resizableImageWithCapInsets:insets]];
+    [self setupBackgroundViews];
 
     UIImage* favicon = [[UIImage imageNamed:@"default_world_favicon"]
         imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate];
@@ -83,6 +78,43 @@
   [super prepareForReuse];
   self.titleLabel.text = nil;
   self.itemIdentifier = nil;
+  self.selected = NO;
+}
+
+- (void)setupBackgroundViews {
+  self.backgroundView = [self resizeableBackgroundImageForStateSelected:NO];
+  self.selectedBackgroundView =
+      [self resizeableBackgroundImageForStateSelected:YES];
+}
+
+#pragma mark - UIView
+
+- (void)traitCollectionDidChange:(UITraitCollection*)previousTraitCollection {
+  [super traitCollectionDidChange:previousTraitCollection];
+  [self setupBackgroundViews];
+}
+
+#pragma mark - Private
+
+// Updates this tab's style based on the value of |selected| and the current
+// incognito style.
+- (UIView*)resizeableBackgroundImageForStateSelected:(BOOL)selected {
+  // Style the background image first.
+  NSString* state = (selected ? @"foreground" : @"background");
+  NSString* imageName = [NSString stringWithFormat:@"tabstrip_%@_tab", state];
+
+  // As of iOS 13 Beta 4, resizable images are flaky for dark mode.
+  // Radar filled: b/137942721.
+  UIImage* resolvedImage = [UIImage imageNamed:imageName
+                                      inBundle:nil
+                 compatibleWithTraitCollection:self.traitCollection];
+  UIEdgeInsets insets = UIEdgeInsetsMake(
+      0, kTabBackgroundLeftCapInset, resolvedImage.size.height + 1.0,
+      resolvedImage.size.width - kTabBackgroundLeftCapInset + 1.0);
+  UIImage* backgroundImage =
+      StretchableImageFromUIImage(resolvedImage, kTabBackgroundLeftCapInset, 0);
+  return [[UIImageView alloc]
+      initWithImage:[backgroundImage resizableImageWithCapInsets:insets]];
 }
 
 // Selector registered to the close button.
diff --git a/ios/chrome/browser/ui/tab_switcher/tab_strip/tab_strip_consumer.h b/ios/chrome/browser/ui/tab_switcher/tab_strip/tab_strip_consumer.h
index f7cbcef..8058faf 100644
--- a/ios/chrome/browser/ui/tab_switcher/tab_strip/tab_strip_consumer.h
+++ b/ios/chrome/browser/ui/tab_switcher/tab_strip/tab_strip_consumer.h
@@ -23,6 +23,9 @@
 // The consumer should ignore this call if |itemID| has not yet been inserted.
 - (void)replaceItemID:(NSString*)itemID withItem:(TabSwitcherItem*)item;
 
+// Tells the consumer to update the selected item ID to be |selectedItemID|.
+- (void)selectItemWithID:(NSString*)selectedItemID;
+
 @end
 
 #endif  // IOS_CHROME_BROWSER_UI_TAB_SWITCHER_TAB_STRIP_TAB_STRIP_CONSUMER_H_
diff --git a/ios/chrome/browser/ui/tab_switcher/tab_strip/tab_strip_mediator.mm b/ios/chrome/browser/ui/tab_switcher/tab_strip/tab_strip_mediator.mm
index 531de47..c69a594 100644
--- a/ios/chrome/browser/ui/tab_switcher/tab_strip/tab_strip_mediator.mm
+++ b/ios/chrome/browser/ui/tab_switcher/tab_strip/tab_strip_mediator.mm
@@ -161,6 +161,25 @@
   [self populateConsumerItems];
 }
 
+- (void)webStateList:(WebStateList*)webStateList
+    didChangeActiveWebState:(web::WebState*)newWebState
+                oldWebState:(web::WebState*)oldWebState
+                    atIndex:(int)atIndex
+                     reason:(ActiveWebStateChangeReason)reason {
+  DCHECK_EQ(_webStateList, webStateList);
+  if (webStateList->IsBatchInProgress())
+    return;
+  // If the selected index changes as a result of the last webstate being
+  // detached, atIndex will be -1.
+  if (atIndex == -1) {
+    [self.consumer selectItemWithID:nil];
+    return;
+  }
+
+  TabIdTabHelper* tabHelper = TabIdTabHelper::FromWebState(newWebState);
+  [self.consumer selectItemWithID:tabHelper->tab_id()];
+}
+
 #pragma mark - TabFaviconDataSource
 
 - (void)faviconForIdentifier:(NSString*)identifier
@@ -207,6 +226,7 @@
       base::checked_cast<int>(self.webStateList->count()), std::move(webState),
       (WebStateList::INSERT_FORCE_INDEX | WebStateList::INSERT_ACTIVATE),
       WebStateOpener());
+  [self.consumer selectItemWithID:GetActiveTabId(self.webStateList)];
 }
 
 - (void)selectTab:(int)index {
diff --git a/ios/chrome/browser/ui/tab_switcher/tab_strip/tab_strip_view_controller.mm b/ios/chrome/browser/ui/tab_switcher/tab_strip/tab_strip_view_controller.mm
index d63c236..d0ccb1b 100644
--- a/ios/chrome/browser/ui/tab_switcher/tab_strip/tab_strip_view_controller.mm
+++ b/ios/chrome/browser/ui/tab_switcher/tab_strip/tab_strip_view_controller.mm
@@ -126,6 +126,10 @@
   self.items = [items mutableCopy];
   self.selectedItemID = selectedItemID;
   [self.collectionView reloadData];
+  [self.collectionView
+      selectItemAtIndexPath:CreateIndexPath(self.selectedIndex)
+                   animated:YES
+             scrollPosition:UICollectionViewScrollPositionNone];
 }
 
 - (void)replaceItemID:(NSString*)itemID withItem:(TabSwitcherItem*)item {
@@ -143,6 +147,20 @@
     [self configureCell:cell withItem:item];
 }
 
+- (void)selectItemWithID:(NSString*)selectedItemID {
+  if (self.selectedItemID == selectedItemID)
+    return;
+
+  [self.collectionView
+      deselectItemAtIndexPath:CreateIndexPath(self.selectedIndex)
+                     animated:YES];
+  self.selectedItemID = selectedItemID;
+  [self.collectionView
+      selectItemAtIndexPath:CreateIndexPath(self.selectedIndex)
+                   animated:YES
+             scrollPosition:UICollectionViewScrollPositionNone];
+}
+
 #pragma mark - Private
 
 // Configures |cell|'s title synchronously, and favicon asynchronously with
@@ -179,6 +197,12 @@
   [self.delegate addNewItem];
 }
 
+#pragma mark - Private properties
+
+- (NSUInteger)selectedIndex {
+  return [self indexOfItemWithID:self.selectedItemID];
+}
+
 #pragma mark - UICollectionViewDelegate
 
 - (void)collectionView:(UICollectionView*)collectionView
diff --git a/ios/chrome/browser/ui/table_view/cells/table_view_cells_constants.mm b/ios/chrome/browser/ui/table_view/cells/table_view_cells_constants.mm
index 594508d..b239beca 100644
--- a/ios/chrome/browser/ui/table_view/cells/table_view_cells_constants.mm
+++ b/ios/chrome/browser/ui/table_view/cells/table_view_cells_constants.mm
@@ -21,8 +21,8 @@
 const CGFloat kUseDefaultFontSize = 0.0;
 const CGFloat kTableViewLabelVerticalTopSpacing = 13.0;
 const CGFloat kTableViewAccessoryWidth = 40;
-const CGFloat kTableViewIconImageSize = 28;
-const CGFloat kTableViewImagePadding = 12;
+const CGFloat kTableViewIconImageSize = 30;
+const CGFloat kTableViewImagePadding = 14;
 
 NSString* const kMaskedPassword = @"••••••••";
 NSString* const kTableViewCellInfoButtonViewId =
diff --git a/ios/google_internal/frameworks/chrome_internal_dynamic_framework.arm64.zip.sha1 b/ios/google_internal/frameworks/chrome_internal_dynamic_framework.arm64.zip.sha1
index 241147c1..77f863a 100644
--- a/ios/google_internal/frameworks/chrome_internal_dynamic_framework.arm64.zip.sha1
+++ b/ios/google_internal/frameworks/chrome_internal_dynamic_framework.arm64.zip.sha1
@@ -1 +1 @@
-b8f924676128a3e1ef3d1556c5f106f385a182bd
\ No newline at end of file
+324a16db812e7879d250a3514b1b4f744ff091a6
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/chrome_internal_dynamic_framework.x64.zip.sha1 b/ios/google_internal/frameworks/chrome_internal_dynamic_framework.x64.zip.sha1
index 3984207..656ea71 100644
--- a/ios/google_internal/frameworks/chrome_internal_dynamic_framework.x64.zip.sha1
+++ b/ios/google_internal/frameworks/chrome_internal_dynamic_framework.x64.zip.sha1
@@ -1 +1 @@
-4017b02cc4f85ebca9c18525395badced645fb0f
\ No newline at end of file
+da316f13de971feba199e67c04ec286b5f540efd
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.arm64.zip.sha1 b/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.arm64.zip.sha1
index a111947d..43269a1 100644
--- a/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.arm64.zip.sha1
+++ b/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.arm64.zip.sha1
@@ -1 +1 @@
-e7c3c41be6a4f863fb130f4cfbfe0615d8580837
\ No newline at end of file
+3fc65b170cd78ecb71476702ea616029ae29a579
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.x64.zip.sha1 b/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.x64.zip.sha1
index 187b32f7..c29c7bd 100644
--- a/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.x64.zip.sha1
+++ b/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.x64.zip.sha1
@@ -1 +1 @@
-a7ef8acd7a7b179a505c6b6005e8244799cf468b
\ No newline at end of file
+583af3b9184883631bc86b8a08f7d68dd593a496
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/remoting_dogfood_internal_dynamic_framework.arm64.zip.sha1 b/ios/google_internal/frameworks/remoting_dogfood_internal_dynamic_framework.arm64.zip.sha1
index bf43673..90cd644 100644
--- a/ios/google_internal/frameworks/remoting_dogfood_internal_dynamic_framework.arm64.zip.sha1
+++ b/ios/google_internal/frameworks/remoting_dogfood_internal_dynamic_framework.arm64.zip.sha1
@@ -1 +1 @@
-076cc16e9bfe129204ec7855a09f154b7c5c3ea1
\ No newline at end of file
+5bf91f7a6db7a5b3a621efaecaf32857a608e44d
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/remoting_dogfood_internal_dynamic_framework.x64.zip.sha1 b/ios/google_internal/frameworks/remoting_dogfood_internal_dynamic_framework.x64.zip.sha1
index 8ba26bd..51c52020 100644
--- a/ios/google_internal/frameworks/remoting_dogfood_internal_dynamic_framework.x64.zip.sha1
+++ b/ios/google_internal/frameworks/remoting_dogfood_internal_dynamic_framework.x64.zip.sha1
@@ -1 +1 @@
-d7537259f9a374528001f4a14487fa4a661353d9
\ No newline at end of file
+905e9bc24b4da815ea1a39784920c36e058cfd4a
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/remoting_internal_dynamic_framework.arm64.zip.sha1 b/ios/google_internal/frameworks/remoting_internal_dynamic_framework.arm64.zip.sha1
index 21487da..fada12c 100644
--- a/ios/google_internal/frameworks/remoting_internal_dynamic_framework.arm64.zip.sha1
+++ b/ios/google_internal/frameworks/remoting_internal_dynamic_framework.arm64.zip.sha1
@@ -1 +1 @@
-9b3e6e6175695771482b6af97c1505f04b07b62f
\ No newline at end of file
+6f87cfac459edaadd4991cc00cf72696c38e6089
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/remoting_internal_dynamic_framework.x64.zip.sha1 b/ios/google_internal/frameworks/remoting_internal_dynamic_framework.x64.zip.sha1
index b381dd51..fe2d71e6 100644
--- a/ios/google_internal/frameworks/remoting_internal_dynamic_framework.x64.zip.sha1
+++ b/ios/google_internal/frameworks/remoting_internal_dynamic_framework.x64.zip.sha1
@@ -1 +1 @@
-8f1ee339a6b708d65906ccb87db7f6a744f61451
\ No newline at end of file
+36af3cc1f2655871d5f44a076ed41b72afbac9bd
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.arm64.zip.sha1 b/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.arm64.zip.sha1
index bab7c0a..9a33718 100644
--- a/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.arm64.zip.sha1
+++ b/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.arm64.zip.sha1
@@ -1 +1 @@
-3042efc4cf2909b87d61e2f706e1fd276ab39504
\ No newline at end of file
+a37fc59391bc432a2d56c23484996cb1ac156eee
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.x64.zip.sha1 b/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.x64.zip.sha1
index fae1892a..c12aaa1 100644
--- a/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.x64.zip.sha1
+++ b/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.x64.zip.sha1
@@ -1 +1 @@
-26d76dee09ba529168ee57dc935fe747c44bfe15
\ No newline at end of file
+5d3f0a379bf5c4c956e22131b8e16ffe54520e1f
\ No newline at end of file
diff --git a/media/capture/video/chromeos/camera_hal_dispatcher_impl.cc b/media/capture/video/chromeos/camera_hal_dispatcher_impl.cc
index 81beec4..c49ba54 100644
--- a/media/capture/video/chromeos/camera_hal_dispatcher_impl.cc
+++ b/media/capture/video/chromeos/camera_hal_dispatcher_impl.cc
@@ -100,6 +100,20 @@
 
 CameraClientObserver::~CameraClientObserver() = default;
 
+FailedCameraHalServerCallbacks::FailedCameraHalServerCallbacks()
+    : callbacks_(this) {}
+FailedCameraHalServerCallbacks::~FailedCameraHalServerCallbacks() = default;
+
+mojo::PendingRemote<cros::mojom::CameraHalServerCallbacks>
+FailedCameraHalServerCallbacks::GetRemote() {
+  return callbacks_.BindNewPipeAndPassRemote();
+}
+
+void FailedCameraHalServerCallbacks::CameraDeviceActivityChange(
+    int32_t camera_id,
+    bool opened,
+    cros::mojom::CameraClientType type) {}
+
 // static
 CameraHalDispatcherImpl* CameraHalDispatcherImpl::GetInstance() {
   return base::Singleton<CameraHalDispatcherImpl>::get();
@@ -229,11 +243,8 @@
 void CameraHalDispatcherImpl::RegisterServer(
     mojo::PendingRemote<cros::mojom::CameraHalServer> camera_hal_server) {
   DCHECK(proxy_task_runner_->BelongsToCurrentThread());
-  // TODO(b/170075468): Reject this call once Chrome OS uses
-  // RegisterServerWithToken.
-  auto temporary_token = base::UnguessableToken::Create();
-  RegisterServerWithToken(std::move(camera_hal_server), temporary_token,
-                          base::DoNothing());
+  LOG(ERROR) << "CameraHalDispatcher::RegisterServer is deprecated. "
+                "CameraHalServer will not be registered.";
 }
 
 void CameraHalDispatcherImpl::RegisterServerWithToken(
@@ -241,10 +252,17 @@
     const base::UnguessableToken& token,
     RegisterServerWithTokenCallback callback) {
   DCHECK(proxy_task_runner_->BelongsToCurrentThread());
-  // TODO(b/170075468): Authenticate the token.
 
   if (camera_hal_server_) {
     LOG(ERROR) << "Camera HAL server is already registered";
+    std::move(callback).Run(-EALREADY,
+                            failed_camera_hal_server_callbacks_.GetRemote());
+    return;
+  }
+  if (!token_manager_.AuthenticateServer(token)) {
+    LOG(ERROR) << "Failed to authenticate server";
+    std::move(callback).Run(-EPERM,
+                            failed_camera_hal_server_callbacks_.GetRemote());
     return;
   }
   camera_hal_server_.Bind(std::move(camera_hal_server));
@@ -643,4 +661,8 @@
   camera_hal_server_->SetTracingEnabled(false);
 }
 
+TokenManager* CameraHalDispatcherImpl::GetTokenManagerForTesting() {
+  return &token_manager_;
+}
+
 }  // namespace media
diff --git a/media/capture/video/chromeos/camera_hal_dispatcher_impl.h b/media/capture/video/chromeos/camera_hal_dispatcher_impl.h
index df5a5d4..11b9cd88 100644
--- a/media/capture/video/chromeos/camera_hal_dispatcher_impl.h
+++ b/media/capture/video/chromeos/camera_hal_dispatcher_impl.h
@@ -66,6 +66,32 @@
                                     bool is_active) = 0;
 };
 
+// A class to provide a no-op remote to CameraHalServer that failed
+// registration. When CameraHalServer calls
+// CameraHalDispatcher::RegisterServerWithToken to register itself, a
+// PendingRemote<CameraHalServerCallbacks> is returned. Returning an unbound
+// pending remote would crash CameraHalServer immediately, and thus disallows
+// it from handling authentication failures.
+// TODO(b/170075468): Modify RegisterServerWithToken to return an optional
+// CameraHalServerCallbacks instead.
+class FailedCameraHalServerCallbacks
+    : public cros::mojom::CameraHalServerCallbacks {
+ private:
+  friend class CameraHalDispatcherImpl;
+
+  FailedCameraHalServerCallbacks();
+  ~FailedCameraHalServerCallbacks() final;
+
+  mojo::PendingRemote<cros::mojom::CameraHalServerCallbacks> GetRemote();
+
+  // CameraHalServerCallbacks implementations.
+  void CameraDeviceActivityChange(int32_t camera_id,
+                                  bool opened,
+                                  cros::mojom::CameraClientType type) final;
+
+  mojo::Receiver<cros::mojom::CameraHalServerCallbacks> callbacks_;
+};
+
 // The CameraHalDispatcherImpl hosts and waits on the unix domain socket
 // /var/run/camera3.sock.  CameraHalServer and CameraHalClients connect to the
 // unix domain socket to create the initial Mojo connections with the
@@ -186,6 +212,8 @@
   void OnTraceLogEnabledOnProxyThread();
   void OnTraceLogDisabledOnProxyThread();
 
+  TokenManager* GetTokenManagerForTesting();
+
   base::ScopedFD proxy_fd_;
   base::ScopedFD cancel_pipe_;
 
@@ -200,6 +228,7 @@
 
   mojo::Receiver<cros::mojom::CameraHalServerCallbacks>
       camera_hal_server_callbacks_;
+  FailedCameraHalServerCallbacks failed_camera_hal_server_callbacks_;
 
   std::set<std::unique_ptr<CameraClientObserver>, base::UniquePtrComparator>
       client_observers_;
diff --git a/media/capture/video/chromeos/camera_hal_dispatcher_impl_unittest.cc b/media/capture/video/chromeos/camera_hal_dispatcher_impl_unittest.cc
index 94cab60..0c78af2 100644
--- a/media/capture/video/chromeos/camera_hal_dispatcher_impl_unittest.cc
+++ b/media/capture/video/chromeos/camera_hal_dispatcher_impl_unittest.cc
@@ -8,6 +8,7 @@
 #include <utility>
 
 #include "base/bind.h"
+#include "base/posix/safe_strerror.h"
 #include "base/run_loop.h"
 #include "base/single_thread_task_runner.h"
 #include "base/test/task_environment.h"
@@ -107,10 +108,13 @@
 
   static void RegisterServer(
       CameraHalDispatcherImpl* dispatcher,
-      mojo::PendingRemote<cros::mojom::CameraHalServer> server) {
-    // TODO(b/170075468): Migrate to RegisterServerWithToken once the migration
-    // is done.
-    dispatcher->RegisterServer(std::move(server));
+      mojo::PendingRemote<cros::mojom::CameraHalServer> server,
+      cros::mojom::CameraHalDispatcher::RegisterServerWithTokenCallback
+          callback) {
+    auto token = base::UnguessableToken::Create();
+    dispatcher->GetTokenManagerForTesting()->AssignServerTokenForTesting(token);
+    dispatcher->RegisterServerWithToken(std::move(server), std::move(token),
+                                        std::move(callback));
   }
 
   static void RegisterClient(
@@ -121,6 +125,16 @@
     dispatcher->RegisterClient(std::move(client));
   }
 
+  void OnRegisteredServer(
+      int32_t result,
+      mojo::PendingRemote<cros::mojom::CameraHalServerCallbacks> callbacks) {
+    if (result != 0) {
+      ADD_FAILURE() << "Failed to register server: "
+                    << base::safe_strerror(-result);
+      QuitRunLoop();
+    }
+  }
+
  protected:
   // We can't use std::unique_ptr here because the constructor and destructor of
   // CameraHalDispatcherImpl are private.
@@ -149,8 +163,11 @@
   auto server = mock_server->GetPendingRemote();
   GetProxyTaskRunner()->PostTask(
       FROM_HERE,
-      base::BindOnce(&CameraHalDispatcherImplTest::RegisterServer,
-                     base::Unretained(dispatcher_), std::move(server)));
+      base::BindOnce(
+          &CameraHalDispatcherImplTest::RegisterServer,
+          base::Unretained(dispatcher_), std::move(server),
+          base::BindOnce(&CameraHalDispatcherImplTest::OnRegisteredServer,
+                         base::Unretained(this))));
   auto client = mock_client->GetPendingRemote();
   GetProxyTaskRunner()->PostTask(
       FROM_HERE,
@@ -174,8 +191,11 @@
   server = mock_server->GetPendingRemote();
   GetProxyTaskRunner()->PostTask(
       FROM_HERE,
-      base::BindOnce(&CameraHalDispatcherImplTest::RegisterServer,
-                     base::Unretained(dispatcher_), std::move(server)));
+      base::BindOnce(
+          &CameraHalDispatcherImplTest::RegisterServer,
+          base::Unretained(dispatcher_), std::move(server),
+          base::BindOnce(&CameraHalDispatcherImplTest::OnRegisteredServer,
+                         base::Unretained(this))));
 
   // Wait until the clients gets the newly established Mojo channel.
   DoLoop();
@@ -198,8 +218,11 @@
   auto server = mock_server->GetPendingRemote();
   GetProxyTaskRunner()->PostTask(
       FROM_HERE,
-      base::BindOnce(&CameraHalDispatcherImplTest::RegisterServer,
-                     base::Unretained(dispatcher_), std::move(server)));
+      base::BindOnce(
+          &CameraHalDispatcherImplTest::RegisterServer,
+          base::Unretained(dispatcher_), std::move(server),
+          base::BindOnce(&CameraHalDispatcherImplTest::OnRegisteredServer,
+                         base::Unretained(this))));
   auto client = mock_client->GetPendingRemote();
   GetProxyTaskRunner()->PostTask(
       FROM_HERE,
diff --git a/media/capture/video/chromeos/token_manager.cc b/media/capture/video/chromeos/token_manager.cc
index fc933e0..3b14e62 100644
--- a/media/capture/video/chromeos/token_manager.cc
+++ b/media/capture/video/chromeos/token_manager.cc
@@ -115,6 +115,11 @@
   }
 }
 
+bool TokenManager::AuthenticateServer(const base::UnguessableToken& token) {
+  DCHECK(!server_token_.is_empty());
+  return server_token_ == token;
+}
+
 bool TokenManager::AuthenticateClient(cros::mojom::CameraClientType type,
                                       const base::UnguessableToken& token) {
   base::AutoLock l(client_token_map_lock_);
@@ -127,4 +132,9 @@
   return token_set.find(token) != token_set.end();
 }
 
+void TokenManager::AssignServerTokenForTesting(
+    const base::UnguessableToken& token) {
+  server_token_ = token;
+}
+
 }  // namespace media
diff --git a/media/capture/video/chromeos/token_manager.h b/media/capture/video/chromeos/token_manager.h
index 3531a0b..fba250b 100644
--- a/media/capture/video/chromeos/token_manager.h
+++ b/media/capture/video/chromeos/token_manager.h
@@ -9,11 +9,12 @@
 #include "base/containers/flat_set.h"
 #include "base/thread_annotations.h"
 #include "base/unguessable_token.h"
+#include "media/capture/capture_export.h"
 #include "media/capture/video/chromeos/mojom/cros_camera_service.mojom.h"
 
 namespace media {
 
-class TokenManager {
+class CAPTURE_EXPORT TokenManager {
  public:
   TokenManager();
   ~TokenManager();
@@ -28,10 +29,15 @@
   void RegisterPluginVmToken(const base::UnguessableToken& token);
   void UnregisterPluginVmToken(const base::UnguessableToken& token);
 
+  bool AuthenticateServer(const base::UnguessableToken& token);
   bool AuthenticateClient(cros::mojom::CameraClientType type,
                           const base::UnguessableToken& token);
 
  private:
+  friend class CameraHalDispatcherImplTest;
+
+  void AssignServerTokenForTesting(const base::UnguessableToken& token);
+
   base::UnguessableToken server_token_;
 
   base::Lock client_token_map_lock_;
diff --git a/media/capture/video/chromeos/video_capture_device_chromeos_halv3.cc b/media/capture/video/chromeos/video_capture_device_chromeos_halv3.cc
index 07f2996..6b9999e 100644
--- a/media/capture/video/chromeos/video_capture_device_chromeos_halv3.cc
+++ b/media/capture/video/chromeos/video_capture_device_chromeos_halv3.cc
@@ -87,7 +87,7 @@
                                   device_, token));
   }
 
-  void SuspendDone(const base::TimeDelta& sleep_duration) final {
+  void SuspendDone(base::TimeDelta sleep_duration) final {
     device_task_runner_->PostTask(
         FROM_HERE,
         base::BindOnce(&VideoCaptureDeviceChromeOSHalv3::OpenDevice, device_));
diff --git a/services/network/public/cpp/ip_address_space_util_unittest.cc b/services/network/public/cpp/ip_address_space_util_unittest.cc
index 03638b8..6891669f 100644
--- a/services/network/public/cpp/ip_address_space_util_unittest.cc
+++ b/services/network/public/cpp/ip_address_space_util_unittest.cc
@@ -14,6 +14,10 @@
 using net::IPAddress;
 using net::IPAddressBytes;
 
+IPAddress PublicIPv4Address() {
+  return IPAddress(64, 233, 160, 0);
+}
+
 IPAddress PrivateIPv4Address() {
   return IPAddress(192, 168, 1, 1);
 }
@@ -21,7 +25,7 @@
 TEST(IPAddressSpaceTest, IPAddressToIPAddressSpacev4) {
   EXPECT_EQ(IPAddressToIPAddressSpace(IPAddress()), IPAddressSpace::kUnknown);
 
-  EXPECT_EQ(IPAddressToIPAddressSpace(IPAddress(64, 233, 160, 0)),
+  EXPECT_EQ(IPAddressToIPAddressSpace(PublicIPv4Address()),
             IPAddressSpace::kPublic);
 
   EXPECT_EQ(IPAddressToIPAddressSpace(PrivateIPv4Address()),
diff --git a/testing/buildbot/chromium.android.fyi.json b/testing/buildbot/chromium.android.fyi.json
index de97e5d5..6364d72 100644
--- a/testing/buildbot/chromium.android.fyi.json
+++ b/testing/buildbot/chromium.android.fyi.json
@@ -3706,7 +3706,7 @@
             {
               "cipd_package": "chromium/testing/weblayer-x86",
               "location": "weblayer_instrumentation_test_M87",
-              "revision": "version:87.0.4280.66"
+              "revision": "version:87.0.4280.86"
             },
             {
               "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
@@ -3783,7 +3783,7 @@
             {
               "cipd_package": "chromium/testing/weblayer-x86",
               "location": "weblayer_instrumentation_test_M87",
-              "revision": "version:87.0.4280.66"
+              "revision": "version:87.0.4280.86"
             },
             {
               "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
@@ -4389,7 +4389,7 @@
             {
               "cipd_package": "chromium/testing/weblayer-x86",
               "location": "weblayer_instrumentation_test_M87",
-              "revision": "version:87.0.4280.66"
+              "revision": "version:87.0.4280.86"
             },
             {
               "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
@@ -4466,7 +4466,7 @@
             {
               "cipd_package": "chromium/testing/weblayer-x86",
               "location": "weblayer_instrumentation_test_M87",
-              "revision": "version:87.0.4280.66"
+              "revision": "version:87.0.4280.86"
             },
             {
               "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
@@ -5072,7 +5072,7 @@
             {
               "cipd_package": "chromium/testing/weblayer-x86",
               "location": "weblayer_instrumentation_test_M87",
-              "revision": "version:87.0.4280.66"
+              "revision": "version:87.0.4280.86"
             },
             {
               "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
@@ -5149,7 +5149,7 @@
             {
               "cipd_package": "chromium/testing/weblayer-x86",
               "location": "weblayer_instrumentation_test_M87",
-              "revision": "version:87.0.4280.66"
+              "revision": "version:87.0.4280.86"
             },
             {
               "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
diff --git a/testing/buildbot/variants.pyl b/testing/buildbot/variants.pyl
index febbff6..442ed96 100644
--- a/testing/buildbot/variants.pyl
+++ b/testing/buildbot/variants.pyl
@@ -348,7 +348,7 @@
         {
           'cipd_package': 'chromium/testing/weblayer-x86',
           'location': 'weblayer_instrumentation_test_M87',
-          'revision': 'version:87.0.4280.66',
+          'revision': 'version:87.0.4280.86',
         }
       ],
     },
@@ -440,7 +440,7 @@
         {
           'cipd_package': 'chromium/testing/weblayer-x86',
           'location': 'weblayer_instrumentation_test_M87',
-          'revision': 'version:87.0.4280.66',
+          'revision': 'version:87.0.4280.86',
         }
       ],
     },
@@ -491,4 +491,4 @@
       ],
     },
   },
-}
+}
\ No newline at end of file
diff --git a/testing/variations/fieldtrial_testing_config.json b/testing/variations/fieldtrial_testing_config.json
index bc0cabf..d750261 100644
--- a/testing/variations/fieldtrial_testing_config.json
+++ b/testing/variations/fieldtrial_testing_config.json
@@ -3575,6 +3575,21 @@
             ]
         }
     ],
+    "IOSRestoreGaiaCookies": [
+        {
+            "platforms": [
+                "ios"
+            ],
+            "experiments": [
+                {
+                    "name": "Enabled",
+                    "enable_features": [
+                        "RestoreGAIACookiesIfDeleted"
+                    ]
+                }
+            ]
+        }
+    ],
     "Identifiability": [
         {
             "platforms": [
@@ -6449,6 +6464,21 @@
             ]
         }
     ],
+    "ShareByDefaultInCCT": [
+        {
+            "platforms": [
+                "android"
+            ],
+            "experiments": [
+                {
+                    "name": "Enabled",
+                    "enable_features": [
+                        "ShareByDefaultInCCT"
+                    ]
+                }
+            ]
+        }
+    ],
     "SharedClipboard": [
         {
             "platforms": [
diff --git a/third_party/blink/public/mojom/web_feature/web_feature.mojom b/third_party/blink/public/mojom/web_feature/web_feature.mojom
index 6d2a90b..f20a8e5 100644
--- a/third_party/blink/public/mojom/web_feature/web_feature.mojom
+++ b/third_party/blink/public/mojom/web_feature/web_feature.mojom
@@ -3062,6 +3062,10 @@
   kChangeTypeUsingConfig = 3734,
   kV8SourceBuffer_AppendEncodedChunks_Method = 3735,
   kOversrollBehaviorOnViewportBreaks = 3736,
+  kSameOriginJsonTypeForScript = 3737,
+  kCrossOriginJsonTypeForScript = 3738,
+  kSameOriginStrictNosniffWouldBlock = 3739,
+  kCrossOriginStrictNosniffWouldBlock = 3740,
 
   // Add new features immediately above this line. Don't change assigned
   // numbers of any item, and don't reuse removed slots.
diff --git a/third_party/blink/public/web/web_local_frame_client.h b/third_party/blink/public/web/web_local_frame_client.h
index 83f70a1..a298cc7 100644
--- a/third_party/blink/public/web/web_local_frame_client.h
+++ b/third_party/blink/public/web/web_local_frame_client.h
@@ -399,7 +399,9 @@
   // For example, the navigation may have just resulted in scrolling to a
   // named anchor or a PopState event may have been dispatched.
   virtual void DidFinishSameDocumentNavigation(WebHistoryCommitType,
-                                               bool content_initiated) {}
+                                               bool content_initiated,
+                                               bool is_history_api_navigation) {
+  }
 
   // Called upon update to scroll position, document state, and other
   // non-navigational events related to the data held by WebHistoryItem.
diff --git a/third_party/blink/renderer/core/editing/editing_utilities.cc b/third_party/blink/renderer/core/editing/editing_utilities.cc
index 1eafb74..c63090c0 100644
--- a/third_party/blink/renderer/core/editing/editing_utilities.cc
+++ b/third_party/blink/renderer/core/editing/editing_utilities.cc
@@ -166,6 +166,11 @@
   return node && (!node->hasChildren() || EditingIgnoresContent(*node));
 }
 
+bool IsAtomicNodeInFlatTree(const Node* node) {
+  return node && (!FlatTreeTraversal::HasChildren(*node) ||
+                  EditingIgnoresContent(*node));
+}
+
 template <typename Traversal>
 static int16_t ComparePositions(const Node* container_a,
                                 int offset_a,
diff --git a/third_party/blink/renderer/core/editing/editing_utilities.h b/third_party/blink/renderer/core/editing/editing_utilities.h
index afb12dfb..dc4f76c 100644
--- a/third_party/blink/renderer/core/editing/editing_utilities.h
+++ b/third_party/blink/renderer/core/editing/editing_utilities.h
@@ -156,6 +156,7 @@
 }
 
 bool IsAtomicNode(const Node*);
+bool IsAtomicNodeInFlatTree(const Node*);
 CORE_EXPORT bool IsEnclosingBlock(const Node*);
 CORE_EXPORT bool IsTabHTMLSpanElement(const Node*);
 bool IsTabHTMLSpanElementTextNode(const Node*);
diff --git a/third_party/blink/renderer/core/editing/frame_selection.cc b/third_party/blink/renderer/core/editing/frame_selection.cc
index 81722f0..f813916f 100644
--- a/third_party/blink/renderer/core/editing/frame_selection.cc
+++ b/third_party/blink/renderer/core/editing/frame_selection.cc
@@ -1288,6 +1288,11 @@
   return layout_selection_->ComputeSelectionStatus(cursor);
 }
 
+SelectionState FrameSelection::ComputeLayoutSelectionStateForCursor(
+    const NGInlineCursorPosition& position) const {
+  return layout_selection_->ComputeSelectionStateForCursor(position);
+}
+
 bool FrameSelection::IsDirectional() const {
   return is_directional_;
 }
diff --git a/third_party/blink/renderer/core/editing/frame_selection.h b/third_party/blink/renderer/core/editing/frame_selection.h
index 0eb5d11..5ca1f29 100644
--- a/third_party/blink/renderer/core/editing/frame_selection.h
+++ b/third_party/blink/renderer/core/editing/frame_selection.h
@@ -51,6 +51,7 @@
 class GranularityStrategy;
 class GraphicsContext;
 class NGInlineCursor;
+class NGInlineCursorPosition;
 class Range;
 class SelectionEditor;
 class LayoutSelection;
@@ -285,6 +286,8 @@
       const LayoutText& text) const;
   LayoutSelectionStatus ComputeLayoutSelectionStatus(
       const NGInlineCursor& cursor) const;
+  SelectionState ComputeLayoutSelectionStateForCursor(
+      const NGInlineCursorPosition& position) const;
 
   void Trace(Visitor*) const override;
 
diff --git a/third_party/blink/renderer/core/editing/layout_selection.cc b/third_party/blink/renderer/core/editing/layout_selection.cc
index 416baaf4..737ca3a 100644
--- a/third_party/blink/renderer/core/editing/layout_selection.cc
+++ b/third_party/blink/renderer/core/editing/layout_selection.cc
@@ -582,10 +582,10 @@
   return layout_text.GetSelectionState();
 }
 
-static SelectionState GetSelectionStateFor(const NGInlineCursor& cursor) {
-  DCHECK(cursor.Current().GetLayoutObject());
-  return GetSelectionStateFor(
-      To<LayoutText>(*cursor.Current().GetLayoutObject()));
+static SelectionState GetSelectionStateFor(
+    const NGInlineCursorPosition& position) {
+  DCHECK(position.GetLayoutObject());
+  return GetSelectionStateFor(To<LayoutText>(*position.GetLayoutObject()));
 }
 
 bool LayoutSelection::IsSelected(const LayoutObject& layout_object) {
@@ -665,7 +665,7 @@
   const NGTextOffset offset = cursor.Current().TextOffset();
   const unsigned start_offset = offset.start;
   const unsigned end_offset = offset.end;
-  switch (GetSelectionStateFor(cursor)) {
+  switch (GetSelectionStateFor(cursor.Current())) {
     case SelectionState::kStart: {
       const unsigned start_in_block = paint_range_->start_offset.value();
       const bool is_continuous = start_in_block <= end_offset;
@@ -709,6 +709,61 @@
   }
 }
 
+SelectionState LayoutSelection::ComputeSelectionStateForCursor(
+    const NGInlineCursorPosition& position) const {
+  if (!position)
+    return SelectionState::kNone;
+
+  DCHECK(position.IsText());
+
+  // Selection on ellipsis is not supported.
+  if (position.IsEllipsis())
+    return SelectionState::kNone;
+
+  const NGTextOffset offset = position.TextOffset();
+  const unsigned start_offset = offset.start;
+  const unsigned end_offset = offset.end;
+  // Determine the state of the overall selection, relative to the LayoutObject
+  // associated with the current cursor position. This state will allow us know
+  // which offset comparisons are valid, and determine if the selection
+  // endpoints fall within the current cursor position.
+  switch (GetSelectionStateFor(position)) {
+    case SelectionState::kStart: {
+      const unsigned start_in_block = paint_range_->start_offset.value();
+      return start_offset <= start_in_block && start_in_block <= end_offset
+                 ? SelectionState::kStart
+                 : SelectionState::kNone;
+    }
+    case SelectionState::kEnd: {
+      const unsigned end_in_block = paint_range_->end_offset.value();
+      return start_offset <= end_in_block && end_in_block <= end_offset
+                 ? SelectionState::kEnd
+                 : SelectionState::kNone;
+    }
+    case SelectionState::kStartAndEnd: {
+      const unsigned start_in_block = paint_range_->start_offset.value();
+      const unsigned end_in_block = paint_range_->end_offset.value();
+      const bool is_start_in_current_cursor =
+          start_offset <= start_in_block && start_in_block <= end_offset;
+      const bool is_end_in_current_cursor =
+          start_offset <= end_in_block && end_in_block <= end_offset;
+      if (is_start_in_current_cursor && is_end_in_current_cursor)
+        return SelectionState::kStartAndEnd;
+      else if (is_start_in_current_cursor)
+        return SelectionState::kStart;
+      else if (is_end_in_current_cursor)
+        return SelectionState::kEnd;
+      else
+        return SelectionState::kInside;
+    }
+    case SelectionState::kInside: {
+      return SelectionState::kInside;
+    }
+    default:
+      return SelectionState::kNone;
+  }
+}
+
 static NewPaintRangeAndSelectedNodes CalcSelectionRangeAndSetSelectionState(
     const FrameSelection& frame_selection) {
   const SelectionInDOMTree& selection_in_dom =
diff --git a/third_party/blink/renderer/core/editing/layout_selection.h b/third_party/blink/renderer/core/editing/layout_selection.h
index 1cd02ed..ee941a0 100644
--- a/third_party/blink/renderer/core/editing/layout_selection.h
+++ b/third_party/blink/renderer/core/editing/layout_selection.h
@@ -33,10 +33,12 @@
 class LayoutObject;
 class LayoutText;
 class NGInlineCursor;
+class NGInlineCursorPosition;
 class FrameSelection;
 struct LayoutSelectionStatus;
 struct LayoutTextSelectionStatus;
 class SelectionPaintRange;
+enum class SelectionState;
 
 class LayoutSelection final : public GarbageCollected<LayoutSelection> {
  public:
@@ -50,6 +52,15 @@
 
   LayoutTextSelectionStatus ComputeSelectionStatus(const LayoutText&) const;
   LayoutSelectionStatus ComputeSelectionStatus(const NGInlineCursor&) const;
+
+  // Compute the layout selection state relative to the current item of the
+  // given NGInlineCursor. E.g. a state of kStart means that the selection
+  // starts within the position (and ends elsewhere), where kStartAndEnd means
+  // the selection both starts and ends within the position. This information is
+  // used at paint time to determine the edges of the layout selection.
+  SelectionState ComputeSelectionStateForCursor(
+      const NGInlineCursorPosition&) const;
+
   static bool IsSelected(const LayoutObject&);
 
   void ContextDestroyed();
diff --git a/third_party/blink/renderer/core/editing/layout_selection_test.cc b/third_party/blink/renderer/core/editing/layout_selection_test.cc
index c2c784c..6a044580 100644
--- a/third_party/blink/renderer/core/editing/layout_selection_test.cc
+++ b/third_party/blink/renderer/core/editing/layout_selection_test.cc
@@ -982,6 +982,14 @@
     return Selection().ComputeLayoutSelectionStatus(cursor);
   }
 
+  SelectionState ComputeLayoutSelectionStateForCursor(
+      const LayoutObject& layout_object) const {
+    DCHECK(layout_object.IsText());
+    NGInlineCursor cursor;
+    cursor.MoveTo(layout_object);
+    return Selection().ComputeLayoutSelectionStateForCursor(cursor.Current());
+  }
+
   void SetSelectionAndUpdateLayoutSelection(const std::string& selection_text) {
     const SelectionInDOMTree& selection =
         SetSelectionTextToBody(selection_text);
@@ -1033,6 +1041,7 @@
       GetDocument().body()->firstChild()->firstChild()->GetLayoutObject();
   EXPECT_EQ(LayoutSelectionStatus(1u, 3u, SelectSoftLineBreak::kSelected),
             ComputeLayoutSelectionStatus(*foo));
+  EXPECT_EQ(SelectionState::kStart, ComputeLayoutSelectionStateForCursor(*foo));
   LayoutObject* const bar = GetDocument()
                                 .body()
                                 ->firstChild()
@@ -1041,6 +1050,101 @@
                                 ->GetLayoutObject();
   EXPECT_EQ(LayoutSelectionStatus(0u, 2u, SelectSoftLineBreak::kNotSelected),
             ComputeLayoutSelectionStatus(*bar));
+  EXPECT_EQ(SelectionState::kEnd, ComputeLayoutSelectionStateForCursor(*bar));
+}
+
+TEST_F(NGLayoutSelectionTest, StartAndEndState) {
+  SetSelectionAndUpdateLayoutSelection("<div>f^oo|</div><div>bar</div>");
+  LayoutObject* const foo =
+      GetDocument().body()->firstChild()->firstChild()->GetLayoutObject();
+  EXPECT_EQ(LayoutSelectionStatus(1u, 3u, SelectSoftLineBreak::kNotSelected),
+            ComputeLayoutSelectionStatus(*foo));
+  EXPECT_EQ(SelectionState::kStartAndEnd,
+            ComputeLayoutSelectionStateForCursor(*foo));
+  LayoutObject* const bar = GetDocument()
+                                .body()
+                                ->firstChild()
+                                ->nextSibling()
+                                ->firstChild()
+                                ->GetLayoutObject();
+  EXPECT_EQ(LayoutSelectionStatus(0u, 0u, SelectSoftLineBreak::kNotSelected),
+            ComputeLayoutSelectionStatus(*bar));
+  EXPECT_EQ(SelectionState::kNone, ComputeLayoutSelectionStateForCursor(*bar));
+}
+
+TEST_F(NGLayoutSelectionTest, StartAndEndMultilineState) {
+  SetSelectionAndUpdateLayoutSelection(
+      "<div style='white-space:pre'>f^oo\nbar\nba|z</div>");
+  LayoutObject* const div_text =
+      GetDocument().body()->firstChild()->firstChild()->GetLayoutObject();
+
+  NGInlineCursor cursor(*(div_text->ContainingNGBlockFlow()));
+  cursor.MoveTo(*div_text);
+  EXPECT_EQ(LayoutSelectionStatus(1u, 3u, SelectSoftLineBreak::kNotSelected),
+            Selection().ComputeLayoutSelectionStatus(cursor));
+  EXPECT_EQ(SelectionState::kStart,
+            Selection().ComputeLayoutSelectionStateForCursor(cursor.Current()));
+
+  // Move to 'bar' text.
+  cursor.MoveToNext();
+  cursor.MoveToNext();
+  cursor.MoveToNext();
+  EXPECT_EQ(LayoutSelectionStatus(4u, 7u, SelectSoftLineBreak::kNotSelected),
+            Selection().ComputeLayoutSelectionStatus(cursor));
+  EXPECT_EQ(SelectionState::kInside,
+            Selection().ComputeLayoutSelectionStateForCursor(cursor.Current()));
+
+  // Move to 'baz' text.
+  cursor.MoveToNext();
+  cursor.MoveToNext();
+  cursor.MoveToNext();
+  EXPECT_EQ(LayoutSelectionStatus(8u, 10u, SelectSoftLineBreak::kNotSelected),
+            Selection().ComputeLayoutSelectionStatus(cursor));
+  EXPECT_EQ(SelectionState::kEnd,
+            Selection().ComputeLayoutSelectionStateForCursor(cursor.Current()));
+}
+
+TEST_F(NGLayoutSelectionTest, BeforeStartAndAfterEndMultilineState) {
+  SetSelectionAndUpdateLayoutSelection(
+      "<div style='white-space:pre'>foo\nba^r</div><div "
+      "style='white-space:pre'>ba|z\nquu</div>");
+  LayoutObject* const div_text =
+      GetDocument().body()->firstChild()->firstChild()->GetLayoutObject();
+  NGInlineCursor cursor(*(div_text->ContainingNGBlockFlow()));
+  cursor.MoveTo(*div_text);
+  EXPECT_EQ(LayoutSelectionStatus(3u, 3u, SelectSoftLineBreak::kNotSelected),
+            Selection().ComputeLayoutSelectionStatus(cursor));
+  EXPECT_EQ(SelectionState::kNone,
+            Selection().ComputeLayoutSelectionStateForCursor(cursor.Current()));
+
+  // Move to 'bar' text.
+  cursor.MoveToNext();
+  cursor.MoveToNext();
+  cursor.MoveToNext();
+  EXPECT_EQ(LayoutSelectionStatus(6u, 7u, SelectSoftLineBreak::kSelected),
+            Selection().ComputeLayoutSelectionStatus(cursor));
+  EXPECT_EQ(SelectionState::kStart,
+            Selection().ComputeLayoutSelectionStateForCursor(cursor.Current()));
+
+  LayoutObject* const second_div_text =
+      GetDocument().body()->lastChild()->firstChild()->GetLayoutObject();
+  NGInlineCursor second_cursor(*(second_div_text->ContainingNGBlockFlow()));
+  second_cursor.MoveTo(*second_div_text);
+  EXPECT_EQ(LayoutSelectionStatus(0u, 2u, SelectSoftLineBreak::kNotSelected),
+            Selection().ComputeLayoutSelectionStatus(second_cursor));
+  EXPECT_EQ(SelectionState::kEnd,
+            Selection().ComputeLayoutSelectionStateForCursor(
+                second_cursor.Current()));
+
+  // Move to 'quu' text.
+  second_cursor.MoveToNext();
+  second_cursor.MoveToNext();
+  second_cursor.MoveToNext();
+  EXPECT_EQ(LayoutSelectionStatus(4u, 4u, SelectSoftLineBreak::kNotSelected),
+            Selection().ComputeLayoutSelectionStatus(second_cursor));
+  EXPECT_EQ(SelectionState::kNone,
+            Selection().ComputeLayoutSelectionStateForCursor(
+                second_cursor.Current()));
 }
 
 // TODO(editing-dev): Once LayoutNG supports editing, we should change this
@@ -1135,6 +1239,8 @@
   CHECK(layout_br->IsBR());
   EXPECT_EQ(LayoutSelectionStatus(3u, 4u, SelectSoftLineBreak::kNotSelected),
             ComputeLayoutSelectionStatus(*layout_br));
+  EXPECT_EQ(SelectionState::kStartAndEnd,
+            ComputeLayoutSelectionStateForCursor(*layout_br));
 }
 
 // https://crbug.com/907186
@@ -1145,6 +1251,8 @@
       GetDocument().QuerySelector("wbr")->GetLayoutObject();
   EXPECT_EQ(LayoutSelectionStatus(3u, 4u, SelectSoftLineBreak::kSelected),
             ComputeLayoutSelectionStatus(*layout_wbr));
+  EXPECT_EQ(SelectionState::kInside,
+            ComputeLayoutSelectionStateForCursor(*layout_wbr));
 }
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/editing/selection_adjuster.cc b/third_party/blink/renderer/core/editing/selection_adjuster.cc
index e60b026f8..3e523062 100644
--- a/third_party/blink/renderer/core/editing/selection_adjuster.cc
+++ b/third_party/blink/renderer/core/editing/selection_adjuster.cc
@@ -224,7 +224,7 @@
             .DeepEquivalent();
       case TextGranularity::kLine: {
         const VisiblePositionTemplate<Strategy> end =
-            EndOfLine(CreateVisiblePosition(passed_end));
+            CreateVisiblePosition(EndOfLine(passed_end));
         if (!IsEndOfParagraph(end))
           return end.DeepEquivalent();
         // If the end of this line is at the end of a paragraph, include the
@@ -235,7 +235,7 @@
         return next.DeepEquivalent();
       }
       case TextGranularity::kLineBoundary:
-        return EndOfLine(CreateVisiblePosition(passed_end)).DeepEquivalent();
+        return EndOfLine(passed_end).GetPosition();
       case TextGranularity::kParagraph: {
         const VisiblePositionTemplate<Strategy> visible_paragraph_end =
             EndOfParagraph(CreateVisiblePosition(passed_end));
diff --git a/third_party/blink/renderer/core/editing/selection_modifier.cc b/third_party/blink/renderer/core/editing/selection_modifier.cc
index b2e93ce..20fba9f 100644
--- a/third_party/blink/renderer/core/editing/selection_modifier.cc
+++ b/third_party/blink/renderer/core/editing/selection_modifier.cc
@@ -33,6 +33,7 @@
 #include "third_party/blink/renderer/core/editing/ephemeral_range.h"
 #include "third_party/blink/renderer/core/editing/inline_box_position.h"
 #include "third_party/blink/renderer/core/editing/local_caret_rect.h"
+#include "third_party/blink/renderer/core/editing/ng_flat_tree_shorthands.h"
 #include "third_party/blink/renderer/core/editing/selection_template.h"
 #include "third_party/blink/renderer/core/editing/visible_position.h"
 #include "third_party/blink/renderer/core/editing/visible_units.h"
@@ -54,15 +55,16 @@
 // enters an infinite loop. Work around it by hard-limiting the iteration.
 const unsigned kMaxIterationForPageGranularityMovement = 1024;
 
-VisiblePosition LeftBoundaryOfLine(const VisiblePosition& c,
-                                   TextDirection direction) {
+VisiblePositionInFlatTree LeftBoundaryOfLine(const VisiblePositionInFlatTree& c,
+                                             TextDirection direction) {
   DCHECK(c.IsValid()) << c;
   return direction == TextDirection::kLtr ? LogicalStartOfLine(c)
                                           : LogicalEndOfLine(c);
 }
 
-VisiblePosition RightBoundaryOfLine(const VisiblePosition& c,
-                                    TextDirection direction) {
+VisiblePositionInFlatTree RightBoundaryOfLine(
+    const VisiblePositionInFlatTree& c,
+    TextDirection direction) {
   DCHECK(c.IsValid()) << c;
   return direction == TextDirection::kLtr ? LogicalEndOfLine(c)
                                           : LogicalStartOfLine(c);
@@ -70,14 +72,25 @@
 
 }  // namespace
 
+static bool InSameParagraph(const VisiblePositionInFlatTree& a,
+                            const VisiblePositionInFlatTree& b,
+                            EditingBoundaryCrossingRule boundary_crossing_rule =
+                                kCannotCrossEditingBoundary) {
+  DCHECK(a.IsValid()) << a;
+  DCHECK(b.IsValid()) << b;
+  return a.IsNotNull() &&
+         StartOfParagraph(a, boundary_crossing_rule).DeepEquivalent() ==
+             StartOfParagraph(b, boundary_crossing_rule).DeepEquivalent();
+}
+
 // static
-VisiblePosition SelectionModifier::PreviousParagraphPosition(
-    const VisiblePosition& passed_position,
+VisiblePositionInFlatTree SelectionModifier::PreviousParagraphPosition(
+    const VisiblePositionInFlatTree& passed_position,
     LayoutUnit x_point) {
-  VisiblePosition position = passed_position;
+  VisiblePositionInFlatTree position = passed_position;
   do {
     DCHECK(position.IsValid()) << position;
-    const VisiblePosition& new_position = CreateVisiblePosition(
+    const VisiblePositionInFlatTree& new_position = CreateVisiblePosition(
         PreviousLinePosition(position.ToPositionWithAffinity(), x_point));
     if (new_position.IsNull() ||
         new_position.DeepEquivalent() == position.DeepEquivalent())
@@ -88,13 +101,13 @@
 }
 
 // static
-VisiblePosition SelectionModifier::NextParagraphPosition(
-    const VisiblePosition& passed_position,
+VisiblePositionInFlatTree SelectionModifier::NextParagraphPosition(
+    const VisiblePositionInFlatTree& passed_position,
     LayoutUnit x_point) {
-  VisiblePosition position = passed_position;
+  VisiblePositionInFlatTree position = passed_position;
   do {
     DCHECK(position.IsValid()) << position;
-    const VisiblePosition& new_position = CreateVisiblePosition(
+    const VisiblePositionInFlatTree& new_position = CreateVisiblePosition(
         NextLinePosition(position.ToPositionWithAffinity(), x_point));
     if (new_position.IsNull() ||
         new_position.DeepEquivalent() == position.DeepEquivalent())
@@ -118,7 +131,7 @@
     const SelectionInDOMTree& selection,
     LayoutUnit x_pos_for_vertical_arrow_navigation)
     : frame_(&frame),
-      current_selection_(selection),
+      current_selection_(ConvertToSelectionInFlatTree(selection)),
       x_pos_for_vertical_arrow_navigation_(
           x_pos_for_vertical_arrow_navigation) {}
 
@@ -127,20 +140,21 @@
     : SelectionModifier(frame, selection, NoXPosForVerticalArrowNavigation()) {}
 
 VisibleSelection SelectionModifier::Selection() const {
-  return CreateVisibleSelection(current_selection_);
+  return CreateVisibleSelection(
+      ConvertToSelectionInDOMTree(current_selection_));
 }
 
-static VisiblePosition ComputeVisibleExtent(
-    const VisibleSelection& visible_selection) {
+static VisiblePositionInFlatTree ComputeVisibleExtent(
+    const VisibleSelectionInFlatTree& visible_selection) {
   return CreateVisiblePosition(visible_selection.Extent(),
                                visible_selection.Affinity());
 }
 
 TextDirection SelectionModifier::DirectionOfEnclosingBlock() const {
-  const Position& selection_extent = selection_.Extent();
+  const PositionInFlatTree& selection_extent = selection_.Extent();
 
-  // TODO(editing-dev): Check for Position::IsNotNull is an easy fix for few
-  // editing/ web tests, that didn't expect that (e.g.
+  // TODO(editing-dev): Check for PositionInFlatTree::IsNotNull is an easy fix
+  // for few editing/ web tests, that didn't expect that (e.g.
   // editing/selection/extend-byline-withfloat.html).
   // That should be fixed in a more appropriate manner.
   // We should either have SelectionModifier aborted earlier for null selection,
@@ -153,10 +167,11 @@
 namespace {
 
 base::Optional<TextDirection> DirectionAt(
-    const PositionWithAffinity& position) {
+    const PositionInFlatTreeWithAffinity& position) {
   if (position.IsNull())
     return base::nullopt;
-  const PositionWithAffinity adjusted = ComputeInlineAdjustedPosition(position);
+  const PositionInFlatTreeWithAffinity adjusted =
+      ComputeInlineAdjustedPosition(position);
   if (adjusted.IsNull())
     return base::nullopt;
 
@@ -176,10 +191,11 @@
 
 // TODO(xiaochengh): Deduplicate code with |DirectionAt()|.
 base::Optional<TextDirection> LineDirectionAt(
-    const PositionWithAffinity& position) {
+    const PositionInFlatTreeWithAffinity& position) {
   if (position.IsNull())
     return base::nullopt;
-  const PositionWithAffinity adjusted = ComputeInlineAdjustedPosition(position);
+  const PositionInFlatTreeWithAffinity adjusted =
+      ComputeInlineAdjustedPosition(position);
   if (adjusted.IsNull())
     return base::nullopt;
 
@@ -199,7 +215,7 @@
   return base::nullopt;
 }
 
-TextDirection DirectionOf(const VisibleSelection& visible_selection) {
+TextDirection DirectionOf(const VisibleSelectionInFlatTree& visible_selection) {
   base::Optional<TextDirection> maybe_start_direction =
       DirectionAt(visible_selection.VisibleStart().ToPositionWithAffinity());
   base::Optional<TextDirection> maybe_end_direction =
@@ -222,7 +238,7 @@
       .value_or(DirectionOfEnclosingBlockOf(selection_.Extent()));
 }
 
-static bool IsBaseStart(const VisibleSelection& visible_selection,
+static bool IsBaseStart(const VisibleSelectionInFlatTree& visible_selection,
                         SelectionModifyDirection direction) {
   switch (direction) {
     case SelectionModifyDirection::kRight:
@@ -238,25 +254,27 @@
   return true;
 }
 
-// This function returns |VisibleSelection| from start and end position of
-// current_selection_'s |VisibleSelection| with |direction| and ordering of base
-// and extent to handle base/extent don't match to start/end, e.g. granularity
-// != character, and start/end adjustment in |visibleSelection::validate()| for
-// range selection.
-VisibleSelection SelectionModifier::PrepareToModifySelection(
+// This function returns |VisibleSelectionInFlatTree| from start and end
+// position of current_selection_'s |VisibleSelectionInFlatTree| with
+// |direction| and ordering of base and extent to handle base/extent don't match
+// to start/end, e.g. granularity
+// != character, and start/end adjustment in
+// |VisibleSelectionInFlatTree::validate()| for range selection.
+VisibleSelectionInFlatTree SelectionModifier::PrepareToModifySelection(
     SelectionModifyAlteration alter,
     SelectionModifyDirection direction) const {
-  const VisibleSelection& visible_selection =
+  const VisibleSelectionInFlatTree& visible_selection =
       CreateVisibleSelection(current_selection_);
   if (alter != SelectionModifyAlteration::kExtend)
     return visible_selection;
   if (visible_selection.IsNone())
     return visible_selection;
 
-  const EphemeralRange& range = visible_selection.AsSelection().ComputeRange();
+  const EphemeralRangeInFlatTree& range =
+      visible_selection.AsSelection().ComputeRange();
   if (range.IsCollapsed())
     return visible_selection;
-  SelectionInDOMTree::Builder builder;
+  SelectionInFlatTree::Builder builder;
   // Make base and extent match start and end so we extend the user-visible
   // selection. This only matters for cases where base and extend point to
   // different positions than start and end (e.g. after a double-click to
@@ -271,63 +289,65 @@
   return CreateVisibleSelection(builder.Build());
 }
 
-VisiblePosition SelectionModifier::PositionForPlatform(
+VisiblePositionInFlatTree SelectionModifier::PositionForPlatform(
     bool is_get_start) const {
   Settings* settings = GetFrame().GetSettings();
   if (settings && settings->GetEditingBehaviorType() ==
                       mojom::blink::EditingBehavior::kEditingMacBehavior)
     return is_get_start ? selection_.VisibleStart() : selection_.VisibleEnd();
   // Linux and Windows always extend selections from the extent endpoint.
-  // FIXME: VisibleSelection should be fixed to ensure as an invariant that
-  // base/extent always point to the same nodes as start/end, but which points
-  // to which depends on the value of isBaseFirst. Then this can be changed
-  // to just return selection_.extent().
+  // FIXME: VisibleSelectionInFlatTree should be fixed to ensure as an invariant
+  // that base/extent always point to the same nodes as start/end, but which
+  // points to which depends on the value of isBaseFirst. Then this can be
+  // changed to just return selection_.extent().
   return selection_.IsBaseFirst() ? selection_.VisibleEnd()
                                   : selection_.VisibleStart();
 }
 
-VisiblePosition SelectionModifier::StartForPlatform() const {
+VisiblePositionInFlatTree SelectionModifier::StartForPlatform() const {
   return PositionForPlatform(true);
 }
 
-VisiblePosition SelectionModifier::EndForPlatform() const {
+VisiblePositionInFlatTree SelectionModifier::EndForPlatform() const {
   return PositionForPlatform(false);
 }
 
-Position SelectionModifier::NextWordPositionForPlatform(
-    const Position& original_position) {
+PositionInFlatTree SelectionModifier::NextWordPositionForPlatform(
+    const PositionInFlatTree& original_position) {
   const PlatformWordBehavior platform_word_behavior =
       GetFrame().GetEditor().Behavior().ShouldSkipSpaceWhenMovingRight()
           ? PlatformWordBehavior::kWordSkipSpaces
           : PlatformWordBehavior::kWordDontSkipSpaces;
   // Next word position can't be upstream.
-  const Position position_after_current_word =
+  const PositionInFlatTree position_after_current_word =
       NextWordPosition(original_position, platform_word_behavior).GetPosition();
 
   return position_after_current_word;
 }
 
-static VisiblePosition AdjustForwardPositionForUserSelectAll(
-    const VisiblePosition& position) {
+static VisiblePositionInFlatTree AdjustForwardPositionForUserSelectAll(
+    const VisiblePositionInFlatTree& position) {
   Node* const root_user_select_all = EditingStrategy::RootUserSelectAllForNode(
       position.DeepEquivalent().AnchorNode());
   if (!root_user_select_all)
     return position;
   return CreateVisiblePosition(MostForwardCaretPosition(
-      Position::AfterNode(*root_user_select_all), kCanCrossEditingBoundary));
+      PositionInFlatTree::AfterNode(*root_user_select_all),
+      kCanCrossEditingBoundary));
 }
 
-static VisiblePosition AdjustBackwardPositionForUserSelectAll(
-    const VisiblePosition& position) {
+static VisiblePositionInFlatTree AdjustBackwardPositionForUserSelectAll(
+    const VisiblePositionInFlatTree& position) {
   Node* const root_user_select_all = EditingStrategy::RootUserSelectAllForNode(
       position.DeepEquivalent().AnchorNode());
   if (!root_user_select_all)
     return position;
   return CreateVisiblePosition(MostBackwardCaretPosition(
-      Position::BeforeNode(*root_user_select_all), kCanCrossEditingBoundary));
+      PositionInFlatTree::BeforeNode(*root_user_select_all),
+      kCanCrossEditingBoundary));
 }
 
-VisiblePosition SelectionModifier::ModifyExtendingRightInternal(
+VisiblePositionInFlatTree SelectionModifier::ModifyExtendingRightInternal(
     TextGranularity granularity) {
   // The difference between modifyExtendingRight and modifyExtendingForward is:
   // modifyExtendingForward always extends forward logically.
@@ -364,18 +384,19 @@
       return ModifyExtendingForwardInternal(granularity);
   }
   NOTREACHED() << static_cast<int>(granularity);
-  return VisiblePosition();
+  return VisiblePositionInFlatTree();
 }
 
-VisiblePosition SelectionModifier::ModifyExtendingRight(
+VisiblePositionInFlatTree SelectionModifier::ModifyExtendingRight(
     TextGranularity granularity) {
-  const VisiblePosition& pos = ModifyExtendingRightInternal(granularity);
+  const VisiblePositionInFlatTree& pos =
+      ModifyExtendingRightInternal(granularity);
   if (DirectionOfEnclosingBlock() == TextDirection::kLtr)
     return AdjustForwardPositionForUserSelectAll(pos);
   return AdjustBackwardPositionForUserSelectAll(pos);
 }
 
-VisiblePosition SelectionModifier::ModifyExtendingForwardInternal(
+VisiblePositionInFlatTree SelectionModifier::ModifyExtendingForwardInternal(
     TextGranularity granularity) {
   switch (granularity) {
     case TextGranularity::kCharacter:
@@ -390,7 +411,7 @@
               ComputeVisibleExtent(selection_).DeepEquivalent()),
           TextAffinity::kUpstreamIfPossible);
     case TextGranularity::kLine: {
-      const VisiblePosition& pos = ComputeVisibleExtent(selection_);
+      const VisiblePositionInFlatTree& pos = ComputeVisibleExtent(selection_);
       DCHECK(pos.IsValid()) << pos;
       return CreateVisiblePosition(NextLinePosition(
           pos.ToPositionWithAffinity(),
@@ -407,7 +428,7 @@
     case TextGranularity::kParagraphBoundary:
       return EndOfParagraph(EndForPlatform());
     case TextGranularity::kDocumentBoundary: {
-      const VisiblePosition& pos = EndForPlatform();
+      const VisiblePositionInFlatTree& pos = EndForPlatform();
       if (IsEditablePosition(pos.DeepEquivalent())) {
         DCHECK(pos.IsValid()) << pos;
         return CreateVisiblePosition(
@@ -417,18 +438,19 @@
     }
   }
   NOTREACHED() << static_cast<int>(granularity);
-  return VisiblePosition();
+  return VisiblePositionInFlatTree();
 }
 
-VisiblePosition SelectionModifier::ModifyExtendingForward(
+VisiblePositionInFlatTree SelectionModifier::ModifyExtendingForward(
     TextGranularity granularity) {
-  const VisiblePosition pos = ModifyExtendingForwardInternal(granularity);
+  const VisiblePositionInFlatTree pos =
+      ModifyExtendingForwardInternal(granularity);
   if (DirectionOfEnclosingBlock() == TextDirection::kLtr)
     return AdjustForwardPositionForUserSelectAll(pos);
   return AdjustBackwardPositionForUserSelectAll(pos);
 }
 
-VisiblePosition SelectionModifier::ModifyMovingRight(
+VisiblePositionInFlatTree SelectionModifier::ModifyMovingRight(
     TextGranularity granularity) {
   switch (granularity) {
     case TextGranularity::kCharacter:
@@ -457,10 +479,10 @@
                                  DirectionOfEnclosingBlock());
   }
   NOTREACHED() << static_cast<int>(granularity);
-  return VisiblePosition();
+  return VisiblePositionInFlatTree();
 }
 
-VisiblePosition SelectionModifier::ModifyMovingForward(
+VisiblePositionInFlatTree SelectionModifier::ModifyMovingForward(
     TextGranularity granularity) {
   // TODO(editing-dev): Stay in editable content for the less common
   // granularities.
@@ -482,7 +504,7 @@
       // down-arrowing from a range selection that ends at the start of a line
       // needs to leave the selection at that line start (no need to call
       // nextLinePosition!)
-      const VisiblePosition& pos = EndForPlatform();
+      const VisiblePositionInFlatTree& pos = EndForPlatform();
       if (selection_.IsRange() && IsStartOfLine(pos))
         return pos;
       DCHECK(pos.IsValid()) << pos;
@@ -501,7 +523,7 @@
     case TextGranularity::kParagraphBoundary:
       return EndOfParagraph(EndForPlatform());
     case TextGranularity::kDocumentBoundary: {
-      const VisiblePosition& pos = EndForPlatform();
+      const VisiblePositionInFlatTree& pos = EndForPlatform();
       if (IsEditablePosition(pos.DeepEquivalent())) {
         DCHECK(pos.IsValid()) << pos;
         return CreateVisiblePosition(
@@ -511,10 +533,10 @@
     }
   }
   NOTREACHED() << static_cast<int>(granularity);
-  return VisiblePosition();
+  return VisiblePositionInFlatTree();
 }
 
-VisiblePosition SelectionModifier::ModifyExtendingLeftInternal(
+VisiblePositionInFlatTree SelectionModifier::ModifyExtendingLeftInternal(
     TextGranularity granularity) {
   // The difference between modifyExtendingLeft and modifyExtendingBackward is:
   // modifyExtendingBackward always extends backward logically.
@@ -550,23 +572,24 @@
       return ModifyExtendingBackwardInternal(granularity);
   }
   NOTREACHED() << static_cast<int>(granularity);
-  return VisiblePosition();
+  return VisiblePositionInFlatTree();
 }
 
-VisiblePosition SelectionModifier::ModifyExtendingLeft(
+VisiblePositionInFlatTree SelectionModifier::ModifyExtendingLeft(
     TextGranularity granularity) {
-  const VisiblePosition& pos = ModifyExtendingLeftInternal(granularity);
+  const VisiblePositionInFlatTree& pos =
+      ModifyExtendingLeftInternal(granularity);
   if (DirectionOfEnclosingBlock() == TextDirection::kLtr)
     return AdjustBackwardPositionForUserSelectAll(pos);
   return AdjustForwardPositionForUserSelectAll(pos);
 }
 
-VisiblePosition SelectionModifier::ModifyExtendingBackwardInternal(
+VisiblePositionInFlatTree SelectionModifier::ModifyExtendingBackwardInternal(
     TextGranularity granularity) {
   // Extending a selection backward by word or character from just after a table
   // selects the table.  This "makes sense" from the user perspective, esp. when
-  // deleting. It was done here instead of in VisiblePosition because we want
-  // VPs to iterate over everything.
+  // deleting. It was done here instead of in VisiblePositionInFlatTree because
+  // we want VPs to iterate over everything.
   switch (granularity) {
     case TextGranularity::kCharacter:
       return PreviousPositionOf(ComputeVisibleExtent(selection_),
@@ -578,7 +601,7 @@
       return CreateVisiblePosition(PreviousSentencePosition(
           ComputeVisibleExtent(selection_).DeepEquivalent()));
     case TextGranularity::kLine: {
-      const VisiblePosition& pos = ComputeVisibleExtent(selection_);
+      const VisiblePositionInFlatTree& pos = ComputeVisibleExtent(selection_);
       DCHECK(pos.IsValid()) << pos;
       return CreateVisiblePosition(PreviousLinePosition(
           pos.ToPositionWithAffinity(),
@@ -596,7 +619,7 @@
     case TextGranularity::kParagraphBoundary:
       return StartOfParagraph(StartForPlatform());
     case TextGranularity::kDocumentBoundary: {
-      const VisiblePosition pos = StartForPlatform();
+      const VisiblePositionInFlatTree pos = StartForPlatform();
       if (IsEditablePosition(pos.DeepEquivalent())) {
         DCHECK(pos.IsValid()) << pos;
         return CreateVisiblePosition(
@@ -606,18 +629,19 @@
     }
   }
   NOTREACHED() << static_cast<int>(granularity);
-  return VisiblePosition();
+  return VisiblePositionInFlatTree();
 }
 
-VisiblePosition SelectionModifier::ModifyExtendingBackward(
+VisiblePositionInFlatTree SelectionModifier::ModifyExtendingBackward(
     TextGranularity granularity) {
-  const VisiblePosition pos = ModifyExtendingBackwardInternal(granularity);
+  const VisiblePositionInFlatTree pos =
+      ModifyExtendingBackwardInternal(granularity);
   if (DirectionOfEnclosingBlock() == TextDirection::kLtr)
     return AdjustBackwardPositionForUserSelectAll(pos);
   return AdjustForwardPositionForUserSelectAll(pos);
 }
 
-VisiblePosition SelectionModifier::ModifyMovingLeft(
+VisiblePositionInFlatTree SelectionModifier::ModifyMovingLeft(
     TextGranularity granularity) {
   switch (granularity) {
     case TextGranularity::kCharacter:
@@ -646,12 +670,12 @@
                                 DirectionOfEnclosingBlock());
   }
   NOTREACHED() << static_cast<int>(granularity);
-  return VisiblePosition();
+  return VisiblePositionInFlatTree();
 }
 
-VisiblePosition SelectionModifier::ModifyMovingBackward(
+VisiblePositionInFlatTree SelectionModifier::ModifyMovingBackward(
     TextGranularity granularity) {
-  VisiblePosition pos;
+  VisiblePositionInFlatTree pos;
   switch (granularity) {
     case TextGranularity::kCharacter:
       if (selection_.IsRange()) {
@@ -670,7 +694,7 @@
           ComputeVisibleExtent(selection_).DeepEquivalent()));
       break;
     case TextGranularity::kLine: {
-      const VisiblePosition& start = StartForPlatform();
+      const VisiblePositionInFlatTree& start = StartForPlatform();
       DCHECK(start.IsValid()) << start;
       pos = CreateVisiblePosition(PreviousLinePosition(
           start.ToPositionWithAffinity(),
@@ -712,7 +736,7 @@
          granularity == TextGranularity::kDocumentBoundary;
 }
 
-VisiblePosition SelectionModifier::ComputeModifyPosition(
+VisiblePositionInFlatTree SelectionModifier::ComputeModifyPosition(
     SelectionModifyAlteration alter,
     SelectionModifyDirection direction,
     TextGranularity granularity) {
@@ -735,7 +759,7 @@
       return ModifyMovingBackward(granularity);
   }
   NOTREACHED() << static_cast<int>(direction);
-  return VisiblePosition();
+  return VisiblePositionInFlatTree();
 }
 
 bool SelectionModifier::Modify(SelectionModifyAlteration alter,
@@ -750,8 +774,8 @@
     return false;
 
   bool was_range = selection_.IsRange();
-  VisiblePosition original_start_position = selection_.VisibleStart();
-  VisiblePosition position =
+  VisiblePositionInFlatTree original_start_position = selection_.VisibleStart();
+  VisiblePositionInFlatTree position =
       ComputeModifyPosition(alter, direction, granularity);
   if (position.IsNull())
     return false;
@@ -772,10 +796,9 @@
 
   switch (alter) {
     case SelectionModifyAlteration::kMove:
-      current_selection_ =
-          SelectionInDOMTree::Builder()
-              .Collapse(position.ToPositionWithAffinity())
-              .Build();
+      current_selection_ = SelectionInFlatTree::Builder()
+                               .Collapse(position.ToPositionWithAffinity())
+                               .Build();
       break;
     case SelectionModifyAlteration::kExtend:
 
@@ -792,10 +815,11 @@
         // starting with the caret in the middle of a word and then
         // word-selecting forward, leaving the caret in the same place where it
         // was, instead of directly selecting to the end of the word.
-        const VisibleSelection& new_selection = CreateVisibleSelection(
-            SelectionInDOMTree::Builder(selection_.AsSelection())
-                .Extend(position.DeepEquivalent())
-                .Build());
+        const VisibleSelectionInFlatTree& new_selection =
+            CreateVisibleSelection(
+                SelectionInFlatTree::Builder(selection_.AsSelection())
+                    .Extend(position.DeepEquivalent())
+                    .Build());
         if (selection_.IsBaseFirst() != new_selection.IsBaseFirst())
           position = selection_.VisibleBase();
       }
@@ -808,7 +832,7 @@
                .Behavior()
                .ShouldAlwaysGrowSelectionWhenExtendingToBoundary() ||
           selection_.IsCaret() || !IsBoundary(granularity)) {
-        current_selection_ = SelectionInDOMTree::Builder()
+        current_selection_ = SelectionInFlatTree::Builder()
                                  .Collapse(selection_.Base())
                                  .Extend(position.DeepEquivalent())
                                  .Build();
@@ -820,7 +844,7 @@
             (text_direction == TextDirection::kRtl &&
              direction == SelectionModifyDirection::kLeft)) {
           current_selection_ =
-              SelectionInDOMTree::Builder()
+              SelectionInFlatTree::Builder()
                   .Collapse(selection_.IsBaseFirst()
                                 ? selection_.Base()
                                 : position.DeepEquivalent())
@@ -829,7 +853,7 @@
                   .Build();
         } else {
           current_selection_ =
-              SelectionInDOMTree::Builder()
+              SelectionInFlatTree::Builder()
                   .Collapse(selection_.IsBaseFirst() ? position.DeepEquivalent()
                                                      : selection_.Base())
                   .Extend(selection_.IsBaseFirst() ? selection_.Extent()
@@ -848,7 +872,7 @@
 }
 
 // TODO(yosin): Maybe baseline would be better?
-static bool AbsoluteCaretY(const PositionWithAffinity& c, int& y) {
+static bool AbsoluteCaretY(const PositionInFlatTreeWithAffinity& c, int& y) {
   IntRect rect = AbsoluteCaretBoundsOf(c);
   if (rect.IsEmpty())
     return false;
@@ -872,7 +896,7 @@
                  ? SelectionModifyDirection::kBackward
                  : SelectionModifyDirection::kForward);
 
-  VisiblePosition pos;
+  VisiblePositionInFlatTree pos;
   LayoutUnit x_pos;
   switch (alter) {
     case SelectionModifyAlteration::kMove:
@@ -901,10 +925,10 @@
     start_y = -start_y;
   int last_y = start_y;
 
-  VisiblePosition result;
-  VisiblePosition next;
+  VisiblePositionInFlatTree result;
+  VisiblePositionInFlatTree next;
   unsigned iteration_count = 0;
-  for (VisiblePosition p = pos;
+  for (VisiblePositionInFlatTree p = pos;
        iteration_count < kMaxIterationForPageGranularityMovement; p = next) {
     ++iteration_count;
 
@@ -938,7 +962,7 @@
   switch (alter) {
     case SelectionModifyAlteration::kMove:
       current_selection_ =
-          SelectionInDOMTree::Builder()
+          SelectionInFlatTree::Builder()
               .Collapse(result.ToPositionWithAffinity())
               .SetAffinity(direction == SelectionModifyVerticalDirection::kUp
                                ? TextAffinity::kUpstream
@@ -946,7 +970,7 @@
               .Build();
       break;
     case SelectionModifyAlteration::kExtend: {
-      current_selection_ = SelectionInDOMTree::Builder()
+      current_selection_ = SelectionInFlatTree::Builder()
                                .Collapse(selection_.Base())
                                .Extend(result.DeepEquivalent())
                                .Build();
@@ -960,7 +984,7 @@
 // Abs x/y position of the caret ignoring transforms.
 // TODO(yosin) navigation with transforms should be smarter.
 static LayoutUnit LineDirectionPointForBlockDirectionNavigationOf(
-    const VisiblePosition& visible_position) {
+    const VisiblePositionInFlatTree& visible_position) {
   if (visible_position.IsNull())
     return LayoutUnit();
 
@@ -983,7 +1007,7 @@
 }
 
 LayoutUnit SelectionModifier::LineDirectionPointForBlockDirectionNavigation(
-    const Position& pos) {
+    const PositionInFlatTree& pos) {
   LayoutUnit x;
 
   if (selection_.IsNone())
@@ -991,11 +1015,11 @@
 
   if (x_pos_for_vertical_arrow_navigation_ ==
       NoXPosForVerticalArrowNavigation()) {
-    VisiblePosition visible_position =
+    VisiblePositionInFlatTree visible_position =
         CreateVisiblePosition(pos, selection_.Affinity());
-    // VisiblePosition creation can fail here if a node containing the selection
-    // becomes visibility:hidden after the selection is created and before this
-    // function is called.
+    // VisiblePositionInFlatTree creation can fail here if a node containing the
+    // selection becomes visibility:hidden after the selection is created and
+    // before this function is called.
     x = LineDirectionPointForBlockDirectionNavigationOf(visible_position);
     x_pos_for_vertical_arrow_navigation_ = x;
   } else {
diff --git a/third_party/blink/renderer/core/editing/selection_modifier.h b/third_party/blink/renderer/core/editing/selection_modifier.h
index db0e55f..d83545c 100644
--- a/third_party/blink/renderer/core/editing/selection_modifier.h
+++ b/third_party/blink/renderer/core/editing/selection_modifier.h
@@ -77,51 +77,55 @@
   const LocalFrame& GetFrame() const { return *frame_; }
 
   static bool ShouldAlwaysUseDirectionalSelection(const LocalFrame&);
-  VisibleSelection PrepareToModifySelection(SelectionModifyAlteration,
-                                            SelectionModifyDirection) const;
+  VisibleSelectionInFlatTree PrepareToModifySelection(
+      SelectionModifyAlteration,
+      SelectionModifyDirection) const;
   TextDirection DirectionOfEnclosingBlock() const;
   TextDirection LineDirectionOfExtent() const;
-  VisiblePosition PositionForPlatform(bool is_get_start) const;
-  VisiblePosition StartForPlatform() const;
-  VisiblePosition EndForPlatform() const;
-  LayoutUnit LineDirectionPointForBlockDirectionNavigation(const Position&);
-  VisiblePosition ComputeModifyPosition(SelectionModifyAlteration,
-                                        SelectionModifyDirection,
-                                        TextGranularity);
-  VisiblePosition ModifyExtendingRight(TextGranularity);
-  VisiblePosition ModifyExtendingRightInternal(TextGranularity);
-  VisiblePosition ModifyExtendingForward(TextGranularity);
-  VisiblePosition ModifyExtendingForwardInternal(TextGranularity);
-  VisiblePosition ModifyMovingRight(TextGranularity);
-  VisiblePosition ModifyMovingForward(TextGranularity);
-  VisiblePosition ModifyExtendingLeft(TextGranularity);
-  VisiblePosition ModifyExtendingLeftInternal(TextGranularity);
-  VisiblePosition ModifyExtendingBackward(TextGranularity);
-  VisiblePosition ModifyExtendingBackwardInternal(TextGranularity);
-  VisiblePosition ModifyMovingLeft(TextGranularity);
-  VisiblePosition ModifyMovingBackward(TextGranularity);
-  Position NextWordPositionForPlatform(const Position&);
+  VisiblePositionInFlatTree PositionForPlatform(bool is_get_start) const;
+  VisiblePositionInFlatTree StartForPlatform() const;
+  VisiblePositionInFlatTree EndForPlatform() const;
+  LayoutUnit LineDirectionPointForBlockDirectionNavigation(
+      const PositionInFlatTree&);
+  VisiblePositionInFlatTree ComputeModifyPosition(SelectionModifyAlteration,
+                                                  SelectionModifyDirection,
+                                                  TextGranularity);
+  VisiblePositionInFlatTree ModifyExtendingRight(TextGranularity);
+  VisiblePositionInFlatTree ModifyExtendingRightInternal(TextGranularity);
+  VisiblePositionInFlatTree ModifyExtendingForward(TextGranularity);
+  VisiblePositionInFlatTree ModifyExtendingForwardInternal(TextGranularity);
+  VisiblePositionInFlatTree ModifyMovingRight(TextGranularity);
+  VisiblePositionInFlatTree ModifyMovingForward(TextGranularity);
+  VisiblePositionInFlatTree ModifyExtendingLeft(TextGranularity);
+  VisiblePositionInFlatTree ModifyExtendingLeftInternal(TextGranularity);
+  VisiblePositionInFlatTree ModifyExtendingBackward(TextGranularity);
+  VisiblePositionInFlatTree ModifyExtendingBackwardInternal(TextGranularity);
+  VisiblePositionInFlatTree ModifyMovingLeft(TextGranularity);
+  VisiblePositionInFlatTree ModifyMovingBackward(TextGranularity);
+  PositionInFlatTree NextWordPositionForPlatform(const PositionInFlatTree&);
 
-  static PositionWithAffinity PreviousLinePosition(
-      const PositionWithAffinity&,
+  static PositionInFlatTreeWithAffinity PreviousLinePosition(
+      const PositionInFlatTreeWithAffinity&,
       LayoutUnit line_direction_point);
-  static PositionWithAffinity NextLinePosition(const PositionWithAffinity&,
-                                               LayoutUnit line_direction_point);
-  static VisiblePosition PreviousParagraphPosition(
-      const VisiblePosition&,
+  static PositionInFlatTreeWithAffinity NextLinePosition(
+      const PositionInFlatTreeWithAffinity&,
       LayoutUnit line_direction_point);
-  static VisiblePosition NextParagraphPosition(const VisiblePosition&,
-                                               LayoutUnit line_direction_point);
+  static VisiblePositionInFlatTree PreviousParagraphPosition(
+      const VisiblePositionInFlatTree&,
+      LayoutUnit line_direction_point);
+  static VisiblePositionInFlatTree NextParagraphPosition(
+      const VisiblePositionInFlatTree&,
+      LayoutUnit line_direction_point);
 
   const LocalFrame* frame_;
   // TODO(editing-dev): We should get rid of |selection_| once we change
   // all member functions not to use |selection_|.
   // |selection_| is used as implicit parameter or a cache instead of pass it.
-  VisibleSelection selection_;
+  VisibleSelectionInFlatTree selection_;
   // TODO(editing-dev): We should introduce |GetSelection()| to return
   // |result_| to replace |Selection().AsSelection()|.
   // |current_selection_| holds initial value and result of |Modify()|.
-  SelectionInDOMTree current_selection_;
+  SelectionInFlatTree current_selection_;
   LayoutUnit x_pos_for_vertical_arrow_navigation_;
   bool selection_is_directional_ = false;
 
diff --git a/third_party/blink/renderer/core/editing/selection_modifier_line.cc b/third_party/blink/renderer/core/editing/selection_modifier_line.cc
index 1623cdf9..bc9cd35 100644
--- a/third_party/blink/renderer/core/editing/selection_modifier_line.cc
+++ b/third_party/blink/renderer/core/editing/selection_modifier_line.cc
@@ -51,7 +51,7 @@
  public:
   AbstractLineBox() = default;
 
-  static AbstractLineBox CreateFor(const PositionWithAffinity&);
+  static AbstractLineBox CreateFor(const PositionInFlatTreeWithAffinity&);
 
   bool IsNull() const { return type_ == Type::kNull; }
 
@@ -121,7 +121,7 @@
                           line_direction_point - absolute_block_point.top);
   }
 
-  PositionWithAffinity PositionForPoint(
+  PositionInFlatTreeWithAffinity PositionForPoint(
       const PhysicalOffset& point_in_container,
       bool only_editable_leaves) const {
     if (IsOldLayout()) {
@@ -130,11 +130,14 @@
               GetBlock().FlipForWritingMode(point_in_container),
               only_editable_leaves);
       if (!closest_leaf_child)
-        return PositionWithAffinity();
+        return PositionInFlatTreeWithAffinity();
       const Node* node = closest_leaf_child->GetNode();
-      if (node && EditingIgnoresContent(*node))
-        return PositionWithAffinity(Position::InParentBeforeNode(*node));
-      return closest_leaf_child->PositionForPoint(point_in_container);
+      if (node && EditingIgnoresContent(*node)) {
+        return PositionInFlatTreeWithAffinity(
+            PositionInFlatTree::InParentBeforeNode(*node));
+      }
+      return ToPositionInFlatTreeWithAffinity(
+          closest_leaf_child->PositionForPoint(point_in_container));
     }
     return PositionForPoint(cursor_, point_in_container, only_editable_leaves);
   }
@@ -186,9 +189,10 @@
            HasEditableStyle(*layout_object->GetNode());
   }
 
-  static PositionWithAffinity PositionForPoint(const NGInlineCursor& line,
-                                               const PhysicalOffset& point,
-                                               bool only_editable_leaves) {
+  static PositionInFlatTreeWithAffinity PositionForPoint(
+      const NGInlineCursor& line,
+      const PhysicalOffset& point,
+      bool only_editable_leaves) {
     DCHECK(line.Current().IsLineBox());
     const PhysicalSize unit_square(LayoutUnit(1), LayoutUnit(1));
     const LogicalOffset logical_point =
@@ -232,13 +236,16 @@
       }
     }
     if (!closest_leaf_child)
-      return PositionWithAffinity();
+      return PositionInFlatTreeWithAffinity();
     const Node* const node = closest_leaf_child.Current().GetNode();
     if (!node)
-      return PositionWithAffinity();
-    if (EditingIgnoresContent(*node))
-      return PositionWithAffinity(Position::BeforeNode(*node));
-    return closest_leaf_child.PositionForPointInChild(point);
+      return PositionInFlatTreeWithAffinity();
+    if (EditingIgnoresContent(*node)) {
+      return PositionInFlatTreeWithAffinity(
+          PositionInFlatTree::BeforeNode(*node));
+    }
+    return ToPositionInFlatTreeWithAffinity(
+        closest_leaf_child.PositionForPointInChild(point));
   }
 
   enum class Type { kNull, kOldLayout, kLayoutNG };
@@ -250,13 +257,14 @@
 
 // static
 AbstractLineBox AbstractLineBox::CreateFor(
-    const PositionWithAffinity& position) {
+    const PositionInFlatTreeWithAffinity& position) {
   if (position.IsNull() ||
       !position.GetPosition().AnchorNode()->GetLayoutObject()) {
     return AbstractLineBox();
   }
 
-  const PositionWithAffinity adjusted = ComputeInlineAdjustedPosition(position);
+  const PositionWithAffinity adjusted =
+      ToPositionInDOMTreeWithAffinity(ComputeInlineAdjustedPosition(position));
   if (adjusted.IsNull())
     return AbstractLineBox();
 
@@ -276,25 +284,27 @@
 }
 
 Node* PreviousNodeConsideringAtomicNodes(const Node& start) {
-  if (start.previousSibling()) {
-    Node* node = start.previousSibling();
-    while (!IsAtomicNode(node) && node->lastChild())
-      node = node->lastChild();
+  if (Node* previous_sibling = FlatTreeTraversal::PreviousSibling(start)) {
+    Node* node = previous_sibling;
+    while (!IsAtomicNodeInFlatTree(node)) {
+      if (Node* last_child = FlatTreeTraversal::LastChild(*node))
+        node = last_child;
+    }
     return node;
   }
-  return start.parentNode();
+  return FlatTreeTraversal::Parent(start);
 }
 
 Node* NextNodeConsideringAtomicNodes(const Node& start) {
-  if (!IsAtomicNode(&start) && start.hasChildren())
-    return start.firstChild();
-  if (start.nextSibling())
-    return start.nextSibling();
+  if (!IsAtomicNodeInFlatTree(&start) && FlatTreeTraversal::HasChildren(start))
+    return FlatTreeTraversal::FirstChild(start);
+  if (Node* next_sibling = FlatTreeTraversal::NextSibling(start))
+    return next_sibling;
   const Node* node = &start;
-  while (node && !node->nextSibling())
-    node = node->parentNode();
+  while (node && !FlatTreeTraversal::NextSibling(*node))
+    node = FlatTreeTraversal::Parent(*node);
   if (node)
-    return node->nextSibling();
+    return FlatTreeTraversal::NextSibling(*node);
   return nullptr;
 }
 
@@ -303,7 +313,7 @@
 Node* PreviousAtomicLeafNode(const Node& start) {
   Node* node = PreviousNodeConsideringAtomicNodes(start);
   while (node) {
-    if (IsAtomicNode(node))
+    if (IsAtomicNodeInFlatTree(node))
       return node;
     node = PreviousNodeConsideringAtomicNodes(*node);
   }
@@ -315,7 +325,7 @@
 Node* NextAtomicLeafNode(const Node& start) {
   Node* node = NextNodeConsideringAtomicNodes(start);
   while (node) {
-    if (IsAtomicNode(node))
+    if (IsAtomicNodeInFlatTree(node))
       return node;
     node = NextNodeConsideringAtomicNodes(*node);
   }
@@ -344,16 +354,18 @@
   return nullptr;
 }
 
-bool InSameLine(const Node& node, const PositionWithAffinity& position) {
+bool InSameLine(const Node& node,
+                const PositionInFlatTreeWithAffinity& position) {
   if (!node.GetLayoutObject())
     return true;
-  return InSameLine(CreateVisiblePosition(FirstPositionInOrBeforeNode(node))
+  return InSameLine(CreateVisiblePosition(
+                        PositionInFlatTree::FirstPositionInOrBeforeNode(node))
                         .ToPositionWithAffinity(),
                     position);
 }
 
 Node* FindNodeInPreviousLine(const Node& start_node,
-                             const PositionWithAffinity& position) {
+                             const PositionInFlatTreeWithAffinity& position) {
   for (Node* runner = PreviousLeafWithSameEditability(start_node); runner;
        runner = PreviousLeafWithSameEditability(*runner)) {
     if (!InSameLine(*runner, position))
@@ -363,9 +375,9 @@
 }
 
 // FIXME: consolidate with code in previousLinePosition.
-Position PreviousRootInlineBoxCandidatePosition(
+PositionInFlatTree PreviousRootInlineBoxCandidatePosition(
     Node* node,
-    const PositionWithAffinity& position) {
+    const PositionInFlatTreeWithAffinity& position) {
   ContainerNode* highest_root = HighestEditableRoot(position.GetPosition());
   Node* const previous_node = FindNodeInPreviousLine(*node, position);
   for (Node* runner = previous_node; runner && !runner->IsShadowRoot();
@@ -373,19 +385,19 @@
     if (HighestEditableRootOfNode(*runner) != highest_root)
       break;
 
-    const Position& candidate =
-        IsA<HTMLBRElement>(*runner)
-            ? Position::BeforeNode(*runner)
-            : Position::EditingPositionOf(runner, CaretMaxOffset(runner));
+    const PositionInFlatTree& candidate =
+        IsA<HTMLBRElement>(*runner) ? PositionInFlatTree::BeforeNode(*runner)
+                                    : PositionInFlatTree::EditingPositionOf(
+                                          runner, CaretMaxOffset(runner));
     if (IsVisuallyEquivalentCandidate(candidate))
       return candidate;
   }
-  return Position();
+  return PositionInFlatTree();
 }
 
-Position NextRootInlineBoxCandidatePosition(
+PositionInFlatTree NextRootInlineBoxCandidatePosition(
     Node* node,
-    const PositionWithAffinity& position) {
+    const PositionInFlatTreeWithAffinity& position) {
   ContainerNode* highest_root = HighestEditableRoot(position.GetPosition());
   // TODO(xiaochengh): We probably also need to pass in the starting editability
   // to |PreviousLeafWithSameEditability|.
@@ -401,31 +413,31 @@
     if (HighestEditableRootOfNode(*runner) != highest_root)
       break;
 
-    const Position& candidate =
-        Position::EditingPositionOf(runner, CaretMinOffset(runner));
+    const PositionInFlatTree& candidate =
+        PositionInFlatTree::EditingPositionOf(runner, CaretMinOffset(runner));
     if (IsVisuallyEquivalentCandidate(candidate))
       return candidate;
   }
-  return Position();
+  return PositionInFlatTree();
 }
 
 }  // namespace
 
 // static
-PositionWithAffinity SelectionModifier::PreviousLinePosition(
-    const PositionWithAffinity& position,
+PositionInFlatTreeWithAffinity SelectionModifier::PreviousLinePosition(
+    const PositionInFlatTreeWithAffinity& position,
     LayoutUnit line_direction_point) {
   // TODO(xiaochengh): Make all variables |const|.
 
-  Position p = position.GetPosition();
+  PositionInFlatTree p = position.GetPosition();
   Node* node = p.AnchorNode();
 
   if (!node)
-    return PositionWithAffinity();
+    return PositionInFlatTreeWithAffinity();
 
   LayoutObject* layout_object = node->GetLayoutObject();
   if (!layout_object)
-    return PositionWithAffinity();
+    return PositionInFlatTreeWithAffinity();
 
   AbstractLineBox line = AbstractLineBox::CreateFor(position);
   if (!line.IsNull()) {
@@ -435,14 +447,15 @@
   }
 
   if (line.IsNull()) {
-    Position candidate = PreviousRootInlineBoxCandidatePosition(node, position);
+    PositionInFlatTree candidate =
+        PreviousRootInlineBoxCandidatePosition(node, position);
     if (candidate.IsNotNull()) {
       line = AbstractLineBox::CreateFor(
           CreateVisiblePosition(candidate).ToPositionWithAffinity());
       if (line.IsNull()) {
         // TODO(editing-dev): Investigate if this is correct for null
         // |CreateVisiblePosition(candidate)|.
-        return PositionWithAffinity(candidate);
+        return PositionInFlatTreeWithAffinity(candidate);
       }
     }
   }
@@ -473,25 +486,26 @@
                               ? RootEditableElement(*node)
                               : node->GetDocument().documentElement();
   if (!root_element)
-    return PositionWithAffinity();
-  return PositionWithAffinity(Position::FirstPositionInNode(*root_element));
+    return PositionInFlatTreeWithAffinity();
+  return PositionInFlatTreeWithAffinity(
+      PositionInFlatTree::FirstPositionInNode(*root_element));
 }
 
 // static
-PositionWithAffinity SelectionModifier::NextLinePosition(
-    const PositionWithAffinity& position,
+PositionInFlatTreeWithAffinity SelectionModifier::NextLinePosition(
+    const PositionInFlatTreeWithAffinity& position,
     LayoutUnit line_direction_point) {
   // TODO(xiaochengh): Make all variables |const|.
 
-  Position p = position.GetPosition();
+  PositionInFlatTree p = position.GetPosition();
   Node* node = p.AnchorNode();
 
   if (!node)
-    return PositionWithAffinity();
+    return PositionInFlatTreeWithAffinity();
 
   LayoutObject* layout_object = node->GetLayoutObject();
   if (!layout_object)
-    return PositionWithAffinity();
+    return PositionInFlatTreeWithAffinity();
 
   AbstractLineBox line = AbstractLineBox::CreateFor(position);
   if (!line.IsNull()) {
@@ -502,10 +516,10 @@
 
   if (line.IsNull()) {
     // FIXME: We need do the same in previousLinePosition.
-    Node* child = NodeTraversal::ChildAt(*node, p.ComputeEditingOffset());
+    Node* child = FlatTreeTraversal::ChildAt(*node, p.ComputeEditingOffset());
     Node* search_start_node =
-        child ? child : &NodeTraversal::LastWithinOrSelf(*node);
-    Position candidate =
+        child ? child : &FlatTreeTraversal::LastWithinOrSelf(*node);
+    PositionInFlatTree candidate =
         NextRootInlineBoxCandidatePosition(search_start_node, position);
     if (candidate.IsNotNull()) {
       line = AbstractLineBox::CreateFor(
@@ -513,7 +527,7 @@
       if (line.IsNull()) {
         // TODO(editing-dev): Investigate if this is correct for null
         // |CreateVisiblePosition(candidate)|.
-        return PositionWithAffinity(candidate);
+        return PositionInFlatTreeWithAffinity(candidate);
       }
     }
   }
@@ -544,8 +558,9 @@
                               ? RootEditableElement(*node)
                               : node->GetDocument().documentElement();
   if (!root_element)
-    return PositionWithAffinity();
-  return PositionWithAffinity(Position::LastPositionInNode(*root_element));
+    return PositionInFlatTreeWithAffinity();
+  return PositionInFlatTreeWithAffinity(
+      PositionInFlatTree::LastPositionInNode(*root_element));
 }
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/editing/selection_modifier_test.cc b/third_party/blink/renderer/core/editing/selection_modifier_test.cc
index 166d141..9481466 100644
--- a/third_party/blink/renderer/core/editing/selection_modifier_test.cc
+++ b/third_party/blink/renderer/core/editing/selection_modifier_test.cc
@@ -4,6 +4,8 @@
 
 #include "third_party/blink/renderer/core/editing/selection_modifier.h"
 
+#include "third_party/blink/renderer/core/editing/editing_behavior.h"
+#include "third_party/blink/renderer/core/editing/editor.h"
 #include "third_party/blink/renderer/core/editing/testing/editing_test_base.h"
 #include "third_party/blink/renderer/core/editing/visible_position.h"
 #include "third_party/blink/renderer/platform/testing/runtime_enabled_features_test_helpers.h"
@@ -128,4 +130,153 @@
                                TextGranularity::kSentenceBoundary));
 }
 
+TEST_F(SelectionModifierTest, MoveCaretWithShadow) {
+  const char* body_content =
+      "a a"
+      "<div id='host'>"
+      "<span slot='e'>e e</span>"
+      "<span slot='c'>c c</span>"
+      "</div>"
+      "f f";
+  const char* shadow_content =
+      "b b"
+      "<slot name='c'></slot>"
+      "d d"
+      "<slot name='e'></slot>";
+  LoadAhem();
+  InsertStyleElement("body {font-family: Ahem}");
+  SetBodyContent(body_content);
+  Element* host = GetDocument().getElementById("host");
+  ShadowRoot& shadow_root =
+      host->AttachShadowRootInternal(ShadowRootType::kOpen);
+  shadow_root.setInnerHTML(shadow_content);
+  UpdateAllLifecyclePhasesForTest();
+
+  Element* body = GetDocument().body();
+  Node* a = body->childNodes()->item(0);
+  Node* b = shadow_root.childNodes()->item(0);
+  Node* c = host->QuerySelector("[slot=c]")->firstChild();
+  Node* d = shadow_root.childNodes()->item(2);
+  Node* e = host->QuerySelector("[slot=e]")->firstChild();
+  Node* f = body->childNodes()->item(2);
+
+  auto makeSelection = [&](Position position) {
+    return SelectionInDOMTree::Builder().Collapse(position).Build();
+  };
+  SelectionModifyAlteration move = SelectionModifyAlteration::kMove;
+  SelectionModifyDirection direction;
+  TextGranularity granularity;
+
+  {
+    // Test moving forward, character by character.
+    direction = SelectionModifyDirection::kForward;
+    granularity = TextGranularity::kCharacter;
+    SelectionModifier modifier(GetFrame(), makeSelection(Position(body, 0)));
+    EXPECT_EQ(Position(a, 0), modifier.Selection().Base());
+    for (Node* node : {a, b, c, d, e, f}) {
+      if (node == b || node == f) {
+        modifier.Modify(move, direction, granularity);
+        EXPECT_EQ(Position(node, 0), modifier.Selection().Base());
+      }
+      modifier.Modify(move, direction, granularity);
+      EXPECT_EQ(Position(node, 1), modifier.Selection().Base());
+      modifier.Modify(move, direction, granularity);
+      EXPECT_EQ(Position(node, 2), modifier.Selection().Base());
+      modifier.Modify(move, direction, granularity);
+      EXPECT_EQ(Position(node, 3), modifier.Selection().Base());
+    }
+  }
+  {
+    // Test moving backward, character by character.
+    direction = SelectionModifyDirection::kBackward;
+    granularity = TextGranularity::kCharacter;
+    SelectionModifier modifier(GetFrame(), makeSelection(Position(body, 3)));
+    for (Node* node : {f, e, d, c, b, a}) {
+      EXPECT_EQ(Position(node, 3), modifier.Selection().Base());
+      modifier.Modify(move, direction, granularity);
+      EXPECT_EQ(Position(node, 2), modifier.Selection().Base());
+      modifier.Modify(move, direction, granularity);
+      EXPECT_EQ(Position(node, 1), modifier.Selection().Base());
+      modifier.Modify(move, direction, granularity);
+      if (node == f || node == b) {
+        EXPECT_EQ(Position(node, 0), modifier.Selection().Base());
+        modifier.Modify(move, direction, granularity);
+      }
+    }
+    EXPECT_EQ(Position(a, 0), modifier.Selection().Base());
+  }
+  {
+    // Test moving forward, word by word.
+    direction = SelectionModifyDirection::kForward;
+    granularity = TextGranularity::kWord;
+    bool skip_space =
+        GetFrame().GetEditor().Behavior().ShouldSkipSpaceWhenMovingRight();
+    SelectionModifier modifier(GetFrame(), makeSelection(Position(body, 0)));
+    EXPECT_EQ(Position(a, 0), modifier.Selection().Base());
+    for (Node* node : {a, b, c, d, e, f}) {
+      if (node == b || node == f) {
+        modifier.Modify(move, direction, granularity);
+        EXPECT_EQ(Position(node, 0), modifier.Selection().Base());
+      }
+      modifier.Modify(move, direction, granularity);
+      EXPECT_EQ(Position(node, skip_space ? 2 : 1),
+                modifier.Selection().Base());
+      if (node == a || node == e || node == f) {
+        modifier.Modify(move, direction, granularity);
+        EXPECT_EQ(Position(node, 3), modifier.Selection().Base());
+      }
+    }
+  }
+  {
+    // Test moving backward, word by word.
+    direction = SelectionModifyDirection::kBackward;
+    granularity = TextGranularity::kWord;
+    SelectionModifier modifier(GetFrame(), makeSelection(Position(body, 3)));
+    for (Node* node : {f, e, d, c, b, a}) {
+      if (node == f || node == e || node == a) {
+        EXPECT_EQ(Position(node, 3), modifier.Selection().Base());
+        modifier.Modify(move, direction, granularity);
+      }
+      EXPECT_EQ(Position(node, 2), modifier.Selection().Base());
+      modifier.Modify(move, direction, granularity);
+      if (node == f || node == b) {
+        EXPECT_EQ(Position(node, 0), modifier.Selection().Base());
+        modifier.Modify(move, direction, granularity);
+      }
+    }
+    EXPECT_EQ(Position(a, 0), modifier.Selection().Base());
+  }
+
+  // Place the contents into different lines
+  InsertStyleElement("span {display: block}");
+  UpdateAllLifecyclePhasesForTest();
+
+  {
+    // Test moving forward, line by line.
+    direction = SelectionModifyDirection::kForward;
+    granularity = TextGranularity::kLine;
+    for (int i = 0; i <= 3; ++i) {
+      SelectionModifier modifier(GetFrame(), makeSelection(Position(a, i)));
+      for (Node* node : {a, b, c, d, e, f}) {
+        EXPECT_EQ(Position(node, i), modifier.Selection().Base());
+        modifier.Modify(move, direction, granularity);
+      }
+      EXPECT_EQ(Position(f, 3), modifier.Selection().Base());
+    }
+  }
+  {
+    // Test moving backward, line by line.
+    direction = SelectionModifyDirection::kBackward;
+    granularity = TextGranularity::kLine;
+    for (int i = 0; i <= 3; ++i) {
+      SelectionModifier modifier(GetFrame(), makeSelection(Position(f, i)));
+      for (Node* node : {f, e, d, c, b, a}) {
+        EXPECT_EQ(Position(node, i), modifier.Selection().Base());
+        modifier.Modify(move, direction, granularity);
+      }
+      EXPECT_EQ(Position(a, 0), modifier.Selection().Base());
+    }
+  }
+}
+
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/editing/visible_units.cc b/third_party/blink/renderer/core/editing/visible_units.cc
index 82e1cb5a..7378d23 100644
--- a/third_party/blink/renderer/core/editing/visible_units.cc
+++ b/third_party/blink/renderer/core/editing/visible_units.cc
@@ -409,20 +409,20 @@
 
 // ---------
 
-Position StartOfEditableContent(const Position& position) {
+PositionInFlatTree StartOfEditableContent(const PositionInFlatTree& position) {
   ContainerNode* highest_root = HighestEditableRoot(position);
   if (!highest_root)
-    return Position();
+    return PositionInFlatTree();
 
-  return Position::FirstPositionInNode(*highest_root);
+  return PositionInFlatTree::FirstPositionInNode(*highest_root);
 }
 
-Position EndOfEditableContent(const Position& position) {
+PositionInFlatTree EndOfEditableContent(const PositionInFlatTree& position) {
   ContainerNode* highest_root = HighestEditableRoot(position);
   if (!highest_root)
-    return Position();
+    return PositionInFlatTree();
 
-  return Position::LastPositionInNode(*highest_root);
+  return PositionInFlatTree::LastPositionInNode(*highest_root);
 }
 
 bool IsEndOfEditableOrNonEditableContent(const VisiblePosition& position) {
diff --git a/third_party/blink/renderer/core/editing/visible_units.h b/third_party/blink/renderer/core/editing/visible_units.h
index d52ca13..969c4a2 100644
--- a/third_party/blink/renderer/core/editing/visible_units.h
+++ b/third_party/blink/renderer/core/editing/visible_units.h
@@ -130,9 +130,14 @@
 CORE_EXPORT PositionInFlatTree
 EndOfWordPosition(const PositionInFlatTree&, WordSide = kNextWordIfOnBoundary);
 CORE_EXPORT PositionWithAffinity PreviousWordPosition(const Position&);
+CORE_EXPORT PositionInFlatTreeWithAffinity
+PreviousWordPosition(const PositionInFlatTree&);
 CORE_EXPORT PositionWithAffinity NextWordPosition(
     const Position&,
     PlatformWordBehavior = PlatformWordBehavior::kWordDontSkipSpaces);
+CORE_EXPORT PositionInFlatTreeWithAffinity NextWordPosition(
+    const PositionInFlatTree&,
+    PlatformWordBehavior = PlatformWordBehavior::kWordDontSkipSpaces);
 
 // sentences
 CORE_EXPORT Position StartOfSentencePosition(const Position&);
@@ -144,8 +149,8 @@
 CORE_EXPORT VisiblePosition EndOfSentence(const VisiblePosition&);
 CORE_EXPORT VisiblePositionInFlatTree
 EndOfSentence(const VisiblePositionInFlatTree&);
-Position PreviousSentencePosition(const Position&);
-Position NextSentencePosition(const Position&);
+PositionInFlatTree PreviousSentencePosition(const PositionInFlatTree&);
+PositionInFlatTree NextSentencePosition(const PositionInFlatTree&);
 EphemeralRange ExpandEndToSentenceBoundary(const EphemeralRange&);
 EphemeralRange ExpandRangeToSentenceBoundary(const EphemeralRange&);
 
@@ -158,11 +163,6 @@
 CORE_EXPORT PositionWithAffinity StartOfLine(const PositionWithAffinity&);
 CORE_EXPORT PositionInFlatTreeWithAffinity
 StartOfLine(const PositionInFlatTreeWithAffinity&);
-// TODO(yosin) Return values of |VisiblePosition| version of |endOfLine()| with
-// shadow tree isn't defined well. We should not use it for shadow tree.
-CORE_EXPORT VisiblePosition EndOfLine(const VisiblePosition&);
-CORE_EXPORT VisiblePositionInFlatTree
-EndOfLine(const VisiblePositionInFlatTree&);
 CORE_EXPORT PositionWithAffinity EndOfLine(const PositionWithAffinity&);
 CORE_EXPORT PositionInFlatTreeWithAffinity
 EndOfLine(const PositionInFlatTreeWithAffinity&);
@@ -232,8 +232,8 @@
 bool IsEndOfDocument(const VisiblePosition&);
 
 // editable content
-Position StartOfEditableContent(const Position&);
-Position EndOfEditableContent(const Position&);
+PositionInFlatTree StartOfEditableContent(const PositionInFlatTree&);
+PositionInFlatTree EndOfEditableContent(const PositionInFlatTree&);
 CORE_EXPORT bool IsEndOfEditableOrNonEditableContent(const VisiblePosition&);
 CORE_EXPORT bool IsEndOfEditableOrNonEditableContent(
     const VisiblePositionInFlatTree&);
diff --git a/third_party/blink/renderer/core/editing/visible_units_line.cc b/third_party/blink/renderer/core/editing/visible_units_line.cc
index bfe74da..d98a26b1 100644
--- a/third_party/blink/renderer/core/editing/visible_units_line.cc
+++ b/third_party/blink/renderer/core/editing/visible_units_line.cc
@@ -291,8 +291,11 @@
     const PositionWithAffinityTemplate<Strategy> candidate_position =
         PositionWithAffinityTemplate<Strategy>(
             candidate, TextAffinity::kUpstreamIfPossible);
-    if (InSameLine(current_position, candidate_position))
-      return candidate_position;
+    if (InSameLine(current_position, candidate_position)) {
+      return PositionWithAffinityTemplate<Strategy>(
+          CreateVisiblePosition(candidate).DeepEquivalent(),
+          TextAffinity::kUpstreamIfPossible);
+    }
     const PositionWithAffinityTemplate<Strategy>& adjusted_position =
         PreviousPositionOf(CreateVisiblePosition(current_position))
             .ToPositionWithAffinity();
@@ -403,20 +406,6 @@
   return EndOfLineAlgorithm<EditingInFlatTreeStrategy>(position);
 }
 
-// TODO(yosin) Rename this function to reflect the fact it ignores bidi levels.
-VisiblePosition EndOfLine(const VisiblePosition& current_position) {
-  DCHECK(current_position.IsValid()) << current_position;
-  return CreateVisiblePosition(
-      EndOfLine(current_position.ToPositionWithAffinity()));
-}
-
-VisiblePositionInFlatTree EndOfLine(
-    const VisiblePositionInFlatTree& current_position) {
-  DCHECK(current_position.IsValid()) << current_position;
-  return CreateVisiblePosition(
-      EndOfLine(current_position.ToPositionWithAffinity()));
-}
-
 template <typename Strategy>
 static bool InSameLogicalLine(
     const PositionWithAffinityTemplate<Strategy>& position1,
@@ -550,9 +539,14 @@
 }
 
 template <typename Strategy>
-static bool IsEndOfLineAlgorithm(const VisiblePositionTemplate<Strategy>& p) {
-  DCHECK(p.IsValid()) << p;
-  return p.IsNotNull() && p.DeepEquivalent() == EndOfLine(p).DeepEquivalent();
+static bool IsEndOfLineAlgorithm(
+    const VisiblePositionTemplate<Strategy>& visible_position) {
+  DCHECK(visible_position.IsValid()) << visible_position;
+  if (visible_position.IsNull())
+    return false;
+  const auto& end_of_line =
+      EndOfLine(visible_position.ToPositionWithAffinity());
+  return visible_position.DeepEquivalent() == end_of_line.GetPosition();
 }
 
 bool IsEndOfLine(const VisiblePosition& p) {
diff --git a/third_party/blink/renderer/core/editing/visible_units_line_test.cc b/third_party/blink/renderer/core/editing/visible_units_line_test.cc
index d379b60..7ec941e 100644
--- a/third_party/blink/renderer/core/editing/visible_units_line_test.cc
+++ b/third_party/blink/renderer/core/editing/visible_units_line_test.cc
@@ -16,6 +16,15 @@
 
 namespace blink {
 
+static VisiblePosition EndOfLine(const VisiblePosition& position) {
+  return CreateVisiblePosition(EndOfLine(position.ToPositionWithAffinity()));
+}
+
+static VisiblePositionInFlatTree EndOfLine(
+    const VisiblePositionInFlatTree& position) {
+  return CreateVisiblePosition(EndOfLine(position.ToPositionWithAffinity()));
+}
+
 class VisibleUnitsLineTest : public EditingTestBase {
  protected:
   static PositionWithAffinity PositionWithAffinityInDOMTree(
diff --git a/third_party/blink/renderer/core/frame/local_frame.cc b/third_party/blink/renderer/core/frame/local_frame.cc
index 24c738b8..2af284f 100644
--- a/third_party/blink/renderer/core/frame/local_frame.cc
+++ b/third_party/blink/renderer/core/frame/local_frame.cc
@@ -2386,8 +2386,10 @@
 }
 
 WebURLLoader::DeferType LocalFrame::GetLoadDeferType() {
-  if (GetPage()->GetPageScheduler()->IsInBackForwardCache())
+  if (GetPage()->GetPageScheduler()->IsInBackForwardCache() &&
+      base::FeatureList::IsEnabled(features::kLoadingTasksUnfreezable)) {
     return WebURLLoader::DeferType::kDeferredWithBackForwardCache;
+  }
   if (paused_ || frozen_)
     return WebURLLoader::DeferType::kDeferred;
   return WebURLLoader::DeferType::kNotDeferred;
@@ -2411,10 +2413,7 @@
     DomWindow()->SetIsInBackForwardCache(true);
   }
 
-  WebURLLoader::DeferType defer =
-      GetPage()->GetPageScheduler()->IsInBackForwardCache()
-          ? WebURLLoader::DeferType::kDeferredWithBackForwardCache
-          : WebURLLoader::DeferType::kDeferred;
+  WebURLLoader::DeferType defer = GetLoadDeferType();
   GetDocument()->Fetcher()->SetDefersLoading(defer);
   Loader().SetDefersLoading(defer);
 }
diff --git a/third_party/blink/renderer/core/frame/local_frame_client.h b/third_party/blink/renderer/core/frame/local_frame_client.h
index 828d564..40cb1dab2 100644
--- a/third_party/blink/renderer/core/frame/local_frame_client.h
+++ b/third_party/blink/renderer/core/frame/local_frame_client.h
@@ -132,7 +132,9 @@
   virtual void DispatchDidHandleOnloadEvents() = 0;
   virtual void DidFinishSameDocumentNavigation(HistoryItem*,
                                                WebHistoryCommitType,
-                                               bool content_initiated) {}
+                                               bool content_initiated,
+                                               bool is_history_api_navigation) {
+  }
   virtual void DispatchDidReceiveTitle(const String&) = 0;
   virtual void DispatchDidCommitLoad(
       HistoryItem* item,
diff --git a/third_party/blink/renderer/core/frame/local_frame_client_impl.cc b/third_party/blink/renderer/core/frame/local_frame_client_impl.cc
index 486485c6..2541f527 100644
--- a/third_party/blink/renderer/core/frame/local_frame_client_impl.cc
+++ b/third_party/blink/renderer/core/frame/local_frame_client_impl.cc
@@ -525,13 +525,14 @@
 void LocalFrameClientImpl::DidFinishSameDocumentNavigation(
     HistoryItem* item,
     WebHistoryCommitType commit_type,
-    bool content_initiated) {
+    bool content_initiated,
+    bool is_history_api_navigation) {
   bool should_create_history_entry = commit_type == kWebStandardCommit;
   // TODO(dglazkov): Does this need to be called for subframes?
   web_frame_->ViewImpl()->DidCommitLoad(should_create_history_entry, true);
   if (web_frame_->Client()) {
-    web_frame_->Client()->DidFinishSameDocumentNavigation(commit_type,
-                                                          content_initiated);
+    web_frame_->Client()->DidFinishSameDocumentNavigation(
+        commit_type, content_initiated, is_history_api_navigation);
   }
 }
 
diff --git a/third_party/blink/renderer/core/frame/local_frame_client_impl.h b/third_party/blink/renderer/core/frame/local_frame_client_impl.h
index c53f964..02f98349 100644
--- a/third_party/blink/renderer/core/frame/local_frame_client_impl.h
+++ b/third_party/blink/renderer/core/frame/local_frame_client_impl.h
@@ -93,7 +93,8 @@
   void DispatchDidHandleOnloadEvents() override;
   void DidFinishSameDocumentNavigation(HistoryItem*,
                                        WebHistoryCommitType,
-                                       bool content_initiated) override;
+                                       bool content_initiated,
+                                       bool is_history_api_navigation) override;
   void DispatchDidReceiveTitle(const String&) override;
   void DispatchDidCommitLoad(
       HistoryItem*,
diff --git a/third_party/blink/renderer/core/frame/web_frame_test.cc b/third_party/blink/renderer/core/frame/web_frame_test.cc
index 66e040e4..e73d1fe0 100644
--- a/third_party/blink/renderer/core/frame/web_frame_test.cc
+++ b/third_party/blink/renderer/core/frame/web_frame_test.cc
@@ -7595,8 +7595,10 @@
   ~TestDidNavigateCommitTypeWebFrameClient() override = default;
 
   // frame_test_helpers::TestWebFrameClient:
-  void DidFinishSameDocumentNavigation(WebHistoryCommitType type,
-                                       bool content_initiated) override {
+  void DidFinishSameDocumentNavigation(
+      WebHistoryCommitType type,
+      bool content_initiated,
+      bool is_history_api_navigation) override {
     last_commit_type_ = type;
   }
 
diff --git a/third_party/blink/renderer/core/geometry/dom_quad.cc b/third_party/blink/renderer/core/geometry/dom_quad.cc
index ea4bf8a..1cf4aa4 100644
--- a/third_party/blink/renderer/core/geometry/dom_quad.cc
+++ b/third_party/blink/renderer/core/geometry/dom_quad.cc
@@ -83,7 +83,7 @@
       other->hasP1() ? other->p1() : DOMPointInit::Create(),
       other->hasP2() ? other->p2() : DOMPointInit::Create(),
       other->hasP3() ? other->p3() : DOMPointInit::Create(),
-      other->hasP3() ? other->p4() : DOMPointInit::Create());
+      other->hasP4() ? other->p4() : DOMPointInit::Create());
 }
 
 DOMRect* DOMQuad::getBounds() {
diff --git a/third_party/blink/renderer/core/inspector/inspector_highlight.cc b/third_party/blink/renderer/core/inspector/inspector_highlight.cc
index 31be97c1..c0b23f4 100644
--- a/third_party/blink/renderer/core/inspector/inspector_highlight.cc
+++ b/third_party/blink/renderer/core/inspector/inspector_highlight.cc
@@ -28,6 +28,7 @@
 #include "third_party/blink/renderer/core/layout/layout_inline.h"
 #include "third_party/blink/renderer/core/layout/layout_object.h"
 #include "third_party/blink/renderer/core/layout/layout_view.h"
+#include "third_party/blink/renderer/core/layout/ng/ng_box_fragment.h"
 #include "third_party/blink/renderer/core/layout/ng/ng_physical_box_fragment.h"
 #include "third_party/blink/renderer/core/layout/shapes/shape_outside_info.h"
 #include "third_party/blink/renderer/core/page/chrome_client.h"
@@ -880,15 +881,17 @@
          layout_flex->StyleRef().ResolvedIsColumnFlexDirection();
 }
 
-Vector<Vector<PhysicalRect>> GetFlexLinesAndItems(LayoutBox* layout_box,
-                                                  bool is_horizontal,
-                                                  bool is_reverse) {
-  Vector<Vector<PhysicalRect>> flex_lines;
+Vector<Vector<std::pair<PhysicalRect, float>>> GetFlexLinesAndItems(
+    LayoutBox* layout_box,
+    bool is_horizontal,
+    bool is_reverse) {
+  Vector<Vector<std::pair<PhysicalRect, float>>> flex_lines;
 
   // Flex containers can't get fragmented yet, but this may change in the
   // future.
   for (const auto& fragment : layout_box->PhysicalFragments()) {
     LayoutUnit progression;
+
     for (const auto& child : fragment.Children()) {
       const NGPhysicalFragment* child_fragment = child.get();
       if (!child_fragment || child_fragment->IsOutOfFlowPositioned())
@@ -899,6 +902,14 @@
 
       const LayoutObject* object = child_fragment->GetLayoutObject();
       const auto* box = To<LayoutBox>(object);
+
+      LayoutUnit baseline =
+          NGBoxFragment(box->StyleRef().GetWritingDirection(),
+                        *To<NGPhysicalBoxFragment>(child_fragment))
+              .BaselineOrSynthesize();
+      float adjusted_baseline = AdjustForAbsoluteZoom::AdjustFloat(
+          baseline + box->MarginTop(), box->StyleRef());
+
       PhysicalRect item_rect =
           PhysicalRect(fragment_offset.left - box->MarginLeft(),
                        fragment_offset.top - box->MarginTop(),
@@ -914,7 +925,7 @@
         flex_lines.emplace_back();
       }
 
-      flex_lines.back().push_back(item_rect);
+      flex_lines.back().push_back(std::make_pair(item_rect, adjusted_baseline));
 
       progression = is_reverse ? item_start : item_end;
     }
@@ -950,23 +961,30 @@
   container_builder.AppendPath(QuadToPath(content_quad), scale);
 
   // Gather all flex items, sorted by flex line.
-  Vector<Vector<PhysicalRect>> flex_lines =
+  Vector<Vector<std::pair<PhysicalRect, float>>> flex_lines =
       GetFlexLinesAndItems(layout_box, is_horizontal, is_reverse);
 
-  // Send the offset information for each item to the frontend.
+  // We send a list of flex lines, each containing a list of flex items, with
+  // their baselines, to the frontend.
   std::unique_ptr<protocol::ListValue> lines_info =
       protocol::ListValue::create();
   for (auto line : flex_lines) {
     std::unique_ptr<protocol::ListValue> items_info =
         protocol::ListValue::create();
-    for (auto item_rect : line) {
+    for (auto item_data : line) {
+      std::unique_ptr<protocol::DictionaryValue> item_info =
+          protocol::DictionaryValue::create();
+
       FloatQuad item_margin_quad =
-          layout_object->LocalRectToAbsoluteQuad(item_rect);
+          layout_object->LocalRectToAbsoluteQuad(item_data.first);
       FrameQuadToViewport(containing_view, item_margin_quad);
       PathBuilder item_builder;
       item_builder.AppendPath(QuadToPath(item_margin_quad), scale);
 
-      items_info->pushValue(item_builder.Release());
+      item_info->setValue("itemBorder", item_builder.Release());
+      item_info->setDouble("baseline", item_data.second);
+
+      items_info->pushValue(std::move(item_info));
     }
     lines_info->pushValue(std::move(items_info));
   }
diff --git a/third_party/blink/renderer/core/loader/document_loader.cc b/third_party/blink/renderer/core/loader/document_loader.cc
index bc9f595..32205ae 100644
--- a/third_party/blink/renderer/core/loader/document_loader.cc
+++ b/third_party/blink/renderer/core/loader/document_loader.cc
@@ -483,7 +483,11 @@
   original_url_ = new_url;
   url_ = new_url;
   replaces_current_history_item_ = type != WebFrameLoadType::kStandard;
-  if (same_document_navigation_source == kSameDocumentNavigationHistoryApi) {
+  bool is_history_api_navigation =
+      (same_document_navigation_source == kSameDocumentNavigationHistoryApi);
+  if (is_history_api_navigation) {
+    // See spec:
+    // https://html.spec.whatwg.org/multipage/history.html#url-and-history-update-steps
     http_method_ = http_names::kGET;
     http_body_ = nullptr;
   }
@@ -502,13 +506,12 @@
             same_document_navigation_source);
   }
 
-  SetHistoryItemStateForCommit(
-      history_item_.Get(), type,
-      same_document_navigation_source == kSameDocumentNavigationHistoryApi
-          ? HistoryNavigationType::kHistoryApi
-          : HistoryNavigationType::kFragment);
+  SetHistoryItemStateForCommit(history_item_.Get(), type,
+                               is_history_api_navigation
+                                   ? HistoryNavigationType::kHistoryApi
+                                   : HistoryNavigationType::kFragment);
   history_item_->SetDocumentState(frame_->GetDocument()->GetDocumentState());
-  if (same_document_navigation_source == kSameDocumentNavigationHistoryApi) {
+  if (is_history_api_navigation) {
     history_item_->SetStateObject(std::move(data));
     history_item_->SetScrollRestorationType(scroll_restoration_type);
   }
@@ -518,7 +521,8 @@
       FrameScheduler::NavigationType::kSameDocument);
 
   GetLocalFrameClient().DidFinishSameDocumentNavigation(
-      history_item_.Get(), commit_type, is_content_initiated);
+      history_item_.Get(), commit_type, is_content_initiated,
+      is_history_api_navigation);
   probe::DidNavigateWithinDocument(frame_);
   if (!was_loading) {
     GetLocalFrameClient().DidStopLoading();
diff --git a/third_party/blink/renderer/modules/media_controls/resources/mediaControls.css b/third_party/blink/renderer/modules/media_controls/resources/mediaControls.css
index 1e36d10..0d088be 100644
--- a/third_party/blink/renderer/modules/media_controls/resources/mediaControls.css
+++ b/third_party/blink/renderer/modules/media_controls/resources/mediaControls.css
@@ -868,7 +868,7 @@
   overflow-y: auto;
   white-space: nowrap;
   font-size: 12px;
-  background: #FFFFFF;
+  background: -internal-light-dark(#ffffff, #3B3B3B);
   box-shadow: 0 1px 9px 0 rgba(0,0,0,0.40);
   border-radius: 2px;
   transition: transform .3s ease-out, opacity .2s linear;
diff --git a/third_party/blink/renderer/platform/loader/allowed_by_nosniff.cc b/third_party/blink/renderer/platform/loader/allowed_by_nosniff.cc
index 180d4f32..1d45872 100644
--- a/third_party/blink/renderer/platform/loader/allowed_by_nosniff.cc
+++ b/third_party/blink/renderer/platform/loader/allowed_by_nosniff.cc
@@ -56,6 +56,16 @@
     WebFeature::kSameOriginTextXml,
 };
 
+const WebFeature kJsonFeatures[2] = {
+    WebFeature::kCrossOriginJsonTypeForScript,
+    WebFeature::kSameOriginJsonTypeForScript,
+};
+
+const WebFeature kUnknownFeatures[2] = {
+    WebFeature::kCrossOriginStrictNosniffWouldBlock,
+    WebFeature::kSameOriginStrictNosniffWouldBlock,
+};
+
 // Helper function to decide what to do with with a given mime type. This takes
 // - a mime type
 // - inputs that affect the decision (is_same_origin, mime_type_check_mode).
@@ -121,6 +131,11 @@
     counter = kTextPlainFeatures[same_origin];
   } else if (mime_type.StartsWithIgnoringCase("text/xml")) {
     counter = kTextXmlFeatures[same_origin];
+  } else if (mime_type.StartsWithIgnoringCase("text/json") ||
+             mime_type.StartsWithIgnoringCase("application/json")) {
+    counter = kJsonFeatures[same_origin];
+  } else {
+    counter = kUnknownFeatures[same_origin];
   }
 
   return true;
diff --git a/third_party/blink/renderer/platform/loader/allowed_by_nosniff_test.cc b/third_party/blink/renderer/platform/loader/allowed_by_nosniff_test.cc
index 4f47d21..f4db817 100644
--- a/third_party/blink/renderer/platform/loader/allowed_by_nosniff_test.cc
+++ b/third_party/blink/renderer/platform/loader/allowed_by_nosniff_test.cc
@@ -152,6 +152,16 @@
       {bla, blubb, "text/plain", kOpaque, WebFeature::kCrossOriginTextPlain},
       {bla, bla, "text/plain", kBasic, WebFeature::kSameOriginTextScript},
       {bla, bla, "text/plain", kBasic, WebFeature::kSameOriginTextPlain},
+      {bla, bla, "text/json", kBasic, WebFeature::kSameOriginTextScript},
+
+      // JSON
+      {bla, bla, "text/json", kBasic, WebFeature::kSameOriginJsonTypeForScript},
+      {bla, bla, "application/json", kBasic,
+       WebFeature::kSameOriginJsonTypeForScript},
+      {bla, blubb, "text/json", kOpaque,
+       WebFeature::kCrossOriginJsonTypeForScript},
+      {bla, blubb, "application/json", kOpaque,
+       WebFeature::kCrossOriginJsonTypeForScript},
 
       // Test mime type and subtype handling.
       {bla, bla, "text/xml", kBasic, WebFeature::kSameOriginTextScript},
@@ -166,6 +176,12 @@
       {blubb, blubb, "application/xml", kCors,
        WebFeature::kCrossOriginApplicationXml},
       {bla, bla, "text/html", kBasic, WebFeature::kSameOriginTextHtml},
+
+      // Unknown
+      {bla, bla, "not/script", kBasic,
+       WebFeature::kSameOriginStrictNosniffWouldBlock},
+      {bla, blubb, "not/script", kOpaque,
+       WebFeature::kCrossOriginStrictNosniffWouldBlock},
   };
 
   for (auto& testcase : data) {
diff --git a/third_party/blink/renderer/platform/loader/fetch/resource_loader.cc b/third_party/blink/renderer/platform/loader/fetch/resource_loader.cc
index b2e0941..8e779ee 100644
--- a/third_party/blink/renderer/platform/loader/fetch/resource_loader.cc
+++ b/third_party/blink/renderer/platform/loader/fetch/resource_loader.cc
@@ -632,7 +632,7 @@
   if (response_body_loader_) {
     if (defers != WebURLLoader::DeferType::kNotDeferred &&
         !response_body_loader_->IsSuspended()) {
-      response_body_loader_->Suspend();
+      response_body_loader_->Suspend(defers);
       if (defers == WebURLLoader::DeferType::kDeferredWithBackForwardCache) {
         response_body_loader_->EvictFromBackForwardCacheIfDrained();
       }
@@ -1080,7 +1080,7 @@
   DataPipeBytesConsumer::CompletionNotifier* completion_notifier = nullptr;
   DidStartLoadingResponseBodyInternal(
       *MakeGarbageCollected<DataPipeBytesConsumer>(
-          GetLoadingTaskRunner(), std::move(body), &completion_notifier));
+          task_runner_for_body_loader_, std::move(body), &completion_notifier));
   data_pipe_completion_notifier_ = completion_notifier;
 }
 
diff --git a/third_party/blink/renderer/platform/loader/fetch/response_body_loader.cc b/third_party/blink/renderer/platform/loader/fetch/response_body_loader.cc
index 7b046f7..f78c804a 100644
--- a/third_party/blink/renderer/platform/loader/fetch/response_body_loader.cc
+++ b/third_party/blink/renderer/platform/loader/fetch/response_body_loader.cc
@@ -17,6 +17,8 @@
 
 constexpr size_t ResponseBodyLoader::kMaxNumConsumedBytesInTask;
 
+constexpr size_t kDefaultMaxBufferedBodyBytes = 100 * 1000;
+
 class ResponseBodyLoader::DelegatingBytesConsumer final
     : public BytesConsumer,
       public BytesConsumer::Client {
@@ -281,14 +283,25 @@
 class ResponseBodyLoader::Buffer final
     : public GarbageCollected<ResponseBodyLoader::Buffer> {
  public:
-  explicit Buffer(ResponseBodyLoader* owner) : owner_(owner) {}
+  explicit Buffer(ResponseBodyLoader* owner)
+      : owner_(owner),
+        max_bytes_to_read_(base::GetFieldTrialParamByFeatureAsInt(
+            blink::features::kLoadingTasksUnfreezable,
+            "max_buffered_bytes",
+            kDefaultMaxBufferedBodyBytes)) {}
 
   bool IsEmpty() const { return buffered_data_.IsEmpty(); }
 
-  void AddChunk(const char* buffer, size_t available) {
+  // Tries to add |buffer| to |buffered_data_|. Will return false if this
+  // exceeds |max_bytes_to_read_| bytes.
+  bool AddChunk(const char* buffer, size_t available) {
+    total_bytes_read_ += available;
+    if (total_bytes_read_ > max_bytes_to_read_)
+      return false;
     Vector<char> new_chunk;
     new_chunk.Append(buffer, available);
     buffered_data_.emplace_back(std::move(new_chunk));
+    return true;
   }
 
   // Dispatches the frontmost chunk in |buffered_data_|. Returns the size of
@@ -323,6 +336,8 @@
   // we can free memory as soon as we finish sending a chunk completely.
   Deque<Vector<char>> buffered_data_;
   size_t offset_in_current_chunk_ = 0;
+  size_t total_bytes_read_ = 0;
+  const size_t max_bytes_to_read_;
 };
 
 ResponseBodyLoader::ResponseBodyLoader(
@@ -331,12 +346,9 @@
     scoped_refptr<base::SingleThreadTaskRunner> task_runner)
     : bytes_consumer_(bytes_consumer),
       client_(client),
-      task_runner_(std::move(task_runner)),
-      buffer_data_while_suspended_(
-          base::FeatureList::IsEnabled(features::kLoadingTasksUnfreezable)) {
+      task_runner_(std::move(task_runner)) {
   bytes_consumer_->SetClient(this);
-  if (buffer_data_while_suspended_)
-    body_buffer_ = MakeGarbageCollected<Buffer>(this);
+  body_buffer_ = MakeGarbageCollected<Buffer>(this);
 }
 
 mojo::ScopedDataPipeConsumerHandle ResponseBodyLoader::DrainAsDataPipe(
@@ -385,7 +397,7 @@
   if (aborted_)
     return;
 
-  if (suspended_) {
+  if (IsSuspended()) {
     finish_signal_is_pending_ = true;
     return;
   }
@@ -398,7 +410,7 @@
   if (aborted_)
     return;
 
-  if (suspended_) {
+  if (IsSuspended()) {
     fail_signal_is_pending_ = true;
     return;
   }
@@ -411,7 +423,7 @@
   if (aborted_)
     return;
 
-  if (suspended_) {
+  if (IsSuspended()) {
     cancel_signal_is_pending_ = true;
     return;
   }
@@ -448,12 +460,23 @@
   }
 }
 
-void ResponseBodyLoader::Suspend() {
+void ResponseBodyLoader::Suspend(WebURLLoader::DeferType suspended_state) {
   if (aborted_)
     return;
 
-  DCHECK(!suspended_);
-  suspended_ = true;
+  bool was_suspended = (suspended_state_ == WebURLLoader::DeferType::kDeferred);
+
+  suspended_state_ = suspended_state;
+  if (IsSuspendedForBackForwardCache()) {
+    DCHECK(base::FeatureList::IsEnabled(features::kLoadingTasksUnfreezable));
+    // If we're already suspended (but not for back-forward cache), we might've
+    // ignored some OnStateChange calls.
+    if (was_suspended) {
+      task_runner_->PostTask(FROM_HERE,
+                             base::BindOnce(&ResponseBodyLoader::OnStateChange,
+                                            WrapPersistent(this)));
+    }
+  }
 }
 
 void ResponseBodyLoader::EvictFromBackForwardCacheIfDrained() {
@@ -466,8 +489,8 @@
   if (aborted_)
     return;
 
-  DCHECK(suspended_);
-  suspended_ = false;
+  DCHECK(IsSuspended());
+  suspended_state_ = WebURLLoader::DeferType::kNotDeferred;
 
   if (finish_signal_is_pending_) {
     task_runner_->PostTask(
@@ -495,8 +518,7 @@
   TRACE_EVENT0("blink", "ResponseBodyLoader::OnStateChange");
 
   size_t num_bytes_consumed = 0;
-
-  while (!aborted_ && (!suspended_ || buffer_data_while_suspended_)) {
+  while (!aborted_ && (!IsSuspended() || IsSuspendedForBackForwardCache())) {
     if (kMaxNumConsumedBytesInTask == num_bytes_consumed) {
       // We've already consumed many bytes in this task. Defer the remaining
       // to the next task.
@@ -506,8 +528,7 @@
       return;
     }
 
-    if (!suspended_ && body_buffer_ && !body_buffer_->IsEmpty()) {
-      DCHECK(buffer_data_while_suspended_);
+    if (!IsSuspended() && body_buffer_ && !body_buffer_->IsEmpty()) {
       // We need to empty |body_buffer_| first before reading more from
       // |bytes_consumer_|.
       num_bytes_consumed += body_buffer_->DispatchChunk(
@@ -523,19 +544,25 @@
     if (result == BytesConsumer::Result::kOk) {
       TRACE_EVENT1("blink", "ResponseBodyLoader::OnStateChange", "available",
                    available);
-      in_two_phase_read_ = true;
 
+      base::AutoReset<bool> auto_reset_for_in_two_phase_read(
+          &in_two_phase_read_, true);
       available =
           std::min(available, kMaxNumConsumedBytesInTask - num_bytes_consumed);
-      if (suspended_) {
-        DCHECK(buffer_data_while_suspended_);
-        // When suspended, save the read data into |body_buffer_| instead.
-        body_buffer_->AddChunk(buffer, available);
+      if (IsSuspendedForBackForwardCache()) {
+        // Save the read data into |body_buffer_| instead.
+        if (!body_buffer_->AddChunk(buffer, available)) {
+          // We've read too much data while suspended for back-forward cache.
+          // Evict the page from the back-forward cache.
+          result = bytes_consumer_->EndRead(available);
+          EvictFromBackForwardCache();
+          return;
+        }
       } else {
+        DCHECK(!IsSuspended());
         DidReceiveData(base::make_span(buffer, available));
       }
       result = bytes_consumer_->EndRead(available);
-      in_two_phase_read_ = false;
       num_bytes_consumed += available;
 
       if (aborted_) {
@@ -544,7 +571,8 @@
       }
     }
     DCHECK_NE(result, BytesConsumer::Result::kShouldWait);
-    if (suspended_ && result != BytesConsumer::Result::kOk) {
+    if (IsSuspendedForBackForwardCache() &&
+        result != BytesConsumer::Result::kOk) {
       // Don't dispatch finish/failure messages when suspended. We'll dispatch
       // them later when we call OnStateChange again after resuming.
       return;
diff --git a/third_party/blink/renderer/platform/loader/fetch/response_body_loader.h b/third_party/blink/renderer/platform/loader/fetch/response_body_loader.h
index 66ccb4a..3374e5f 100644
--- a/third_party/blink/renderer/platform/loader/fetch/response_body_loader.h
+++ b/third_party/blink/renderer/platform/loader/fetch/response_body_loader.h
@@ -8,6 +8,7 @@
 #include "base/containers/span.h"
 #include "base/memory/scoped_refptr.h"
 #include "mojo/public/cpp/system/data_pipe.h"
+#include "third_party/blink/public/platform/web_url_loader.h"
 #include "third_party/blink/renderer/platform/heap/garbage_collected.h"
 #include "third_party/blink/renderer/platform/heap/member.h"
 #include "third_party/blink/renderer/platform/loader/fetch/bytes_consumer.h"
@@ -89,14 +90,20 @@
   // drained data pipe. This function cannot be called when suspended.
   void Abort();
 
-  // Suspendes loading.
-  void Suspend();
+  // Suspends loading.
+  void Suspend(WebURLLoader::DeferType suspended_state);
 
   // Resumes loading.
   void Resume();
 
   bool IsAborted() const { return aborted_; }
-  bool IsSuspended() const { return suspended_; }
+  bool IsSuspended() const {
+    return suspended_state_ != WebURLLoader::DeferType::kNotDeferred;
+  }
+  bool IsSuspendedForBackForwardCache() const {
+    return suspended_state_ ==
+           WebURLLoader::DeferType::kDeferredWithBackForwardCache;
+  }
   bool IsDrained() const { return drained_; }
 
   void EvictFromBackForwardCacheIfDrained();
@@ -124,22 +131,22 @@
   // BytesConsumer::Client implementation.
   void OnStateChange() override;
   String DebugName() const override { return "ResponseBodyLoader"; }
-  // When |buffer_data_while_suspended_| is true, we'll save the response body
-  // read when suspended.
+  // When |buffer_data_while_suspended_for_bfcache_| is true, we'll save the
+  // response body read when suspended.
   Member<Buffer> body_buffer_;
   Member<BytesConsumer> bytes_consumer_;
   Member<DelegatingBytesConsumer> delegating_bytes_consumer_;
   const Member<ResponseBodyLoaderClient> client_;
   const scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
+  WebURLLoader::DeferType suspended_state_ =
+      WebURLLoader::DeferType::kNotDeferred;
   bool started_ = false;
   bool aborted_ = false;
-  bool suspended_ = false;
   bool drained_ = false;
   bool finish_signal_is_pending_ = false;
   bool fail_signal_is_pending_ = false;
   bool cancel_signal_is_pending_ = false;
   bool in_two_phase_read_ = false;
-  const bool buffer_data_while_suspended_;
 };
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/platform/loader/fetch/response_body_loader_test.cc b/third_party/blink/renderer/platform/loader/fetch/response_body_loader_test.cc
index b096934..49809843 100644
--- a/third_party/blink/renderer/platform/loader/fetch/response_body_loader_test.cc
+++ b/third_party/blink/renderer/platform/loader/fetch/response_body_loader_test.cc
@@ -55,7 +55,7 @@
           loader_->Abort();
           break;
         case Option::kSuspendOnDidReceiveData:
-          loader_->Suspend();
+          loader_->Suspend(WebURLLoader::DeferType::kDeferred);
           break;
       }
     }
@@ -439,20 +439,22 @@
       public ::testing::WithParamInterface<bool> {
  protected:
   ResponseBodyLoaderLoadingTasksUnfreezableTest() {
-    if (BufferDataWhileSuspended()) {
+    if (DeferWithBackForwardCacheEnabled()) {
       scoped_feature_list_.InitAndEnableFeature(
           features::kLoadingTasksUnfreezable);
     }
   }
 
-  bool BufferDataWhileSuspended() { return GetParam(); }
+  bool DeferWithBackForwardCacheEnabled() { return GetParam(); }
 
  private:
   base::test::ScopedFeatureList scoped_feature_list_;
 };
 
 TEST_P(ResponseBodyLoaderLoadingTasksUnfreezableTest,
-       ReadDataFromConsumerWhileSuspended) {
+       SuspendedThenSuspendedForBackForwardCacheThenResume) {
+  if (!DeferWithBackForwardCacheEnabled())
+    return;
   auto task_runner = base::MakeRefCounted<scheduler::FakeTaskRunner>();
   auto* consumer = MakeGarbageCollected<ReplayingBytesConsumer>(task_runner);
   auto* client = MakeGarbageCollected<TestClient>();
@@ -465,23 +467,32 @@
   EXPECT_FALSE(client->LoadingIsFinished());
   EXPECT_FALSE(client->LoadingIsFailed());
 
-  // Suspend, then add some data to |consumer|.
-  body_loader->Suspend();
+  // Suspend (not for back-forward cache), then add some data to |consumer|.
+  body_loader->Suspend(WebURLLoader::DeferType::kDeferred);
   consumer->Add(Command(Command::kData, "llo"));
-  consumer->Add(Command(Command::kWait));
-  consumer->Add(Command(Command::kData, "wo"));
-
-  // If kLoadingTasksUnfreezable is enabled, ResponseBodyLoader will buffer data
-  // when deferred, and won't notify the client until it's resumed.
   EXPECT_FALSE(consumer->IsCommandsEmpty());
+  // Simulate the "readable again" signal.
   consumer->TriggerOnStateChange();
-  if (BufferDataWhileSuspended()) {
-    while (!consumer->IsCommandsEmpty()) {
-      task_runner->RunUntilIdle();
-    }
-  } else {
-    EXPECT_FALSE(consumer->IsCommandsEmpty());
-  }
+  task_runner->RunUntilIdle();
+
+  // When suspended not for back-forward cache, ResponseBodyLoader won't consume
+  // the data.
+  EXPECT_FALSE(consumer->IsCommandsEmpty());
+  EXPECT_EQ("he", client->GetData());
+  EXPECT_FALSE(client->LoadingIsFinished());
+  EXPECT_FALSE(client->LoadingIsFailed());
+
+  // Suspend for back-forward cache, then add some more data to |consumer|.
+  body_loader->Suspend(WebURLLoader::DeferType::kDeferredWithBackForwardCache);
+  consumer->Add(Command(Command::kData, "w"));
+  consumer->Add(Command(Command::kWait));
+  consumer->Add(Command(Command::kData, "o"));
+
+  // ResponseBodyLoader will buffer data when deferred for back-forward cache,
+  // but won't notify the client until it's resumed.
+  EXPECT_FALSE(consumer->IsCommandsEmpty());
+  task_runner->RunUntilIdle();
+  EXPECT_TRUE(consumer->IsCommandsEmpty());
 
   EXPECT_EQ("he", client->GetData());
   EXPECT_FALSE(client->LoadingIsFinished());
@@ -500,7 +511,126 @@
 }
 
 TEST_P(ResponseBodyLoaderLoadingTasksUnfreezableTest,
-       ReadDataFromConsumerWhileSuspendedLong) {
+       FinishedWhileSuspendedThenSuspendedForBackForwardCacheThenResume) {
+  if (!DeferWithBackForwardCacheEnabled())
+    return;
+  auto task_runner = base::MakeRefCounted<scheduler::FakeTaskRunner>();
+  auto* consumer = MakeGarbageCollected<ReplayingBytesConsumer>(task_runner);
+  auto* client = MakeGarbageCollected<TestClient>();
+  auto* body_loader =
+      MakeGarbageCollected<ResponseBodyLoader>(*consumer, *client, task_runner);
+  consumer->Add(Command(Command::kData, "he"));
+  body_loader->Start();
+  task_runner->RunUntilIdle();
+  EXPECT_EQ("he", client->GetData());
+  EXPECT_FALSE(client->LoadingIsFinished());
+  EXPECT_FALSE(client->LoadingIsFailed());
+
+  // Suspend (not for back-forward cache), then add some data to |consumer| with
+  // the finish signal at the end.
+  body_loader->Suspend(WebURLLoader::DeferType::kDeferred);
+  consumer->Add(Command(Command::kData, "llo"));
+  consumer->Add(Command(Command::kDone));
+  // Simulate the "readable again" signal.
+  consumer->TriggerOnStateChange();
+  EXPECT_FALSE(consumer->IsCommandsEmpty());
+  task_runner->RunUntilIdle();
+
+  // When suspended not for back-forward cache, ResponseBodyLoader won't consume
+  // the data, including the finish signal.
+  EXPECT_FALSE(consumer->IsCommandsEmpty());
+  EXPECT_EQ("he", client->GetData());
+  EXPECT_FALSE(client->LoadingIsFinished());
+  EXPECT_FALSE(client->LoadingIsFailed());
+
+  // Suspend for back-forward cache.
+  body_loader->Suspend(WebURLLoader::DeferType::kDeferredWithBackForwardCache);
+  // ResponseBodyLoader will buffer data when deferred for back-forward cache,
+  // but won't notify the client until it's resumed.
+  EXPECT_FALSE(consumer->IsCommandsEmpty());
+  task_runner->RunUntilIdle();
+  EXPECT_TRUE(consumer->IsCommandsEmpty());
+
+  EXPECT_EQ("he", client->GetData());
+  EXPECT_FALSE(client->LoadingIsFinished());
+  EXPECT_FALSE(client->LoadingIsFailed());
+
+  // The data received while suspended will be processed after resuming,
+  // including the finish signal.
+  body_loader->Resume();
+  task_runner->RunUntilIdle();
+  EXPECT_EQ("hello", client->GetData());
+  EXPECT_TRUE(client->LoadingIsFinished());
+  EXPECT_FALSE(client->LoadingIsFailed());
+}
+
+TEST_P(ResponseBodyLoaderLoadingTasksUnfreezableTest,
+       SuspendedForBackForwardCacheThenSuspendedThenResume) {
+  if (!DeferWithBackForwardCacheEnabled())
+    return;
+  auto task_runner = base::MakeRefCounted<scheduler::FakeTaskRunner>();
+  auto* consumer = MakeGarbageCollected<ReplayingBytesConsumer>(task_runner);
+  auto* client = MakeGarbageCollected<TestClient>();
+  auto* body_loader =
+      MakeGarbageCollected<ResponseBodyLoader>(*consumer, *client, task_runner);
+  consumer->Add(Command(Command::kData, "he"));
+  body_loader->Start();
+  task_runner->RunUntilIdle();
+
+  EXPECT_EQ("he", client->GetData());
+  EXPECT_FALSE(client->LoadingIsFinished());
+  EXPECT_FALSE(client->LoadingIsFailed());
+
+  // Suspend for back-forward cache, then add some more data to |consumer|.
+  body_loader->Suspend(WebURLLoader::DeferType::kDeferredWithBackForwardCache);
+  consumer->Add(Command(Command::kData, "llo"));
+  EXPECT_FALSE(consumer->IsCommandsEmpty());
+  // Simulate the "readable again" signal.
+  consumer->TriggerOnStateChange();
+
+  // ResponseBodyLoader will buffer data  when deferred for back-forward cache,
+  // but won't notify the client until it's resumed.
+  while (!consumer->IsCommandsEmpty()) {
+    task_runner->RunUntilIdle();
+  }
+
+  EXPECT_EQ("he", client->GetData());
+  EXPECT_FALSE(client->LoadingIsFinished());
+  EXPECT_FALSE(client->LoadingIsFailed());
+
+  // Suspend (not for back-forward cache), then add some data to |consumer|.
+  body_loader->Suspend(WebURLLoader::DeferType::kDeferred);
+  consumer->Add(Command(Command::kData, "w"));
+  consumer->Add(Command(Command::kWait));
+  consumer->Add(Command(Command::kData, "o"));
+
+  // When suspended not for back-forward cache, ResponseBodyLoader won't consume
+  // the data, even with OnStateChange triggered.
+  for (int i = 0; i < 3; ++i) {
+    consumer->TriggerOnStateChange();
+    task_runner->RunUntilIdle();
+  }
+  EXPECT_FALSE(consumer->IsCommandsEmpty());
+  EXPECT_EQ("he", client->GetData());
+  EXPECT_FALSE(client->LoadingIsFinished());
+  EXPECT_FALSE(client->LoadingIsFailed());
+
+  // The data received while suspended will be processed after resuming, before
+  // processing newer data.
+  body_loader->Resume();
+  consumer->Add(Command(Command::kData, "rld"));
+  consumer->Add(Command(Command::kDone));
+
+  task_runner->RunUntilIdle();
+  EXPECT_EQ("helloworld", client->GetData());
+  EXPECT_TRUE(client->LoadingIsFinished());
+  EXPECT_FALSE(client->LoadingIsFailed());
+}
+
+TEST_P(ResponseBodyLoaderLoadingTasksUnfreezableTest,
+       ReadDataFromConsumerWhileSuspendedForBackForwardCacheLong) {
+  if (!DeferWithBackForwardCacheEnabled())
+    return;
   auto task_runner = base::MakeRefCounted<scheduler::FakeTaskRunner>();
   auto* consumer = MakeGarbageCollected<ReplayingBytesConsumer>(task_runner);
   auto* client = MakeGarbageCollected<TestClient>();
@@ -513,20 +643,17 @@
   EXPECT_FALSE(client->LoadingIsFailed());
 
   // Suspend, then add a long response body to |consumer|.
-  body_loader->Suspend();
+  body_loader->Suspend(WebURLLoader::DeferType::kDeferredWithBackForwardCache);
   std::string body(70000, '*');
   consumer->Add(Command(Command::kDataAndDone, body.c_str()));
 
-  // If kLoadingTasksUnfreezable is enabled, ResponseBodyLoader will buffer data
-  // when deferred, and won't notify the client until it's resumed.
+  // ResponseBodyLoader will buffer data when deferred, and won't notify the
+  // client until it's resumed.
   EXPECT_FALSE(consumer->IsCommandsEmpty());
+  // Simulate the "readable" signal.
   consumer->TriggerOnStateChange();
-  if (BufferDataWhileSuspended()) {
-    while (!consumer->IsCommandsEmpty()) {
-      task_runner->RunUntilIdle();
-    }
-  } else {
-    EXPECT_FALSE(consumer->IsCommandsEmpty());
+  while (!consumer->IsCommandsEmpty()) {
+    task_runner->RunUntilIdle();
   }
 
   EXPECT_EQ("", client->GetData());
diff --git a/third_party/blink/web_tests/TestExpectations b/third_party/blink/web_tests/TestExpectations
index c02bd99..bfda15e 100644
--- a/third_party/blink/web_tests/TestExpectations
+++ b/third_party/blink/web_tests/TestExpectations
@@ -828,6 +828,7 @@
 crbug.com/626703 external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/flexbox/flexbox-justify-content-vert-006.xhtml [ Failure ]
 crbug.com/626703 external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/flexbox/flexbox-justify-content-wmvert-001.xhtml [ Failure ]
 crbug.com/626703 external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/flexbox/flexbox-safe-overflow-position-001.html [ Failure ]
+crbug.com/1155036 [ Debug ] external/wpt/css/css-flexbox/contain-size-layout-abspos-flex-container-crash.html [ Crash Pass ]
 
 # [css-lists]
 crbug.com/1123457 external/wpt/css/css-lists/counter-list-item-2.html [ Failure ]
diff --git a/third_party/blink/web_tests/http/tests/devtools/elements/highlight/highlight-css-flex-alignment-expected.txt b/third_party/blink/web_tests/http/tests/devtools/elements/highlight/highlight-css-flex-alignment-expected.txt
index 02d9398..707fd3efc 100644
--- a/third_party/blink/web_tests/http/tests/devtools/elements/highlight/highlight-css-flex-alignment-expected.txt
+++ b/third_party/blink/web_tests/http/tests/devtools/elements/highlight/highlight-css-flex-alignment-expected.txt
@@ -115,21 +115,24 @@
       ],
       "lines": [
         [
-          [
-            "M",
-            0,
-            0,
-            "L",
-            0,
-            0,
-            "L",
-            0,
-            0,
-            "L",
-            0,
-            0,
-            "Z"
-          ]
+          {
+            "itemBorder": [
+              "M",
+              0,
+              0,
+              "L",
+              0,
+              0,
+              "L",
+              0,
+              0,
+              "L",
+              0,
+              0,
+              "Z"
+            ],
+            "baseline": 0
+          }
         ]
       ],
       "isHorizontalFlow": true,
@@ -286,21 +289,24 @@
       ],
       "lines": [
         [
-          [
-            "M",
-            0,
-            200,
-            "L",
-            0,
-            200,
-            "L",
-            0,
-            200,
-            "L",
-            0,
-            200,
-            "Z"
-          ]
+          {
+            "itemBorder": [
+              "M",
+              0,
+              200,
+              "L",
+              0,
+              200,
+              "L",
+              0,
+              200,
+              "L",
+              0,
+              200,
+              "Z"
+            ],
+            "baseline": 0
+          }
         ]
       ],
       "isHorizontalFlow": true,
@@ -457,21 +463,24 @@
       ],
       "lines": [
         [
-          [
-            "M",
-            0,
-            250,
-            "L",
-            0,
-            250,
-            "L",
-            0,
-            250,
-            "L",
-            0,
-            250,
-            "Z"
-          ]
+          {
+            "itemBorder": [
+              "M",
+              0,
+              250,
+              "L",
+              0,
+              250,
+              "L",
+              0,
+              250,
+              "L",
+              0,
+              250,
+              "Z"
+            ],
+            "baseline": 0
+          }
         ]
       ],
       "isHorizontalFlow": true,
@@ -628,21 +637,24 @@
       ],
       "lines": [
         [
-          [
-            "M",
-            0,
-            300,
-            "L",
-            0,
-            300,
-            "L",
-            0,
-            400,
-            "L",
-            0,
-            400,
-            "Z"
-          ]
+          {
+            "itemBorder": [
+              "M",
+              0,
+              300,
+              "L",
+              0,
+              300,
+              "L",
+              0,
+              400,
+              "L",
+              0,
+              400,
+              "Z"
+            ],
+            "baseline": 100
+          }
         ]
       ],
       "isHorizontalFlow": true,
@@ -799,21 +811,24 @@
       ],
       "lines": [
         [
-          [
-            "M",
-            0,
-            400,
-            "L",
-            0,
-            400,
-            "L",
-            0,
-            500,
-            "L",
-            0,
-            500,
-            "Z"
-          ]
+          {
+            "itemBorder": [
+              "M",
+              0,
+              400,
+              "L",
+              0,
+              400,
+              "L",
+              0,
+              500,
+              "L",
+              0,
+              500,
+              "Z"
+            ],
+            "baseline": 100
+          }
         ]
       ],
       "isHorizontalFlow": true,
diff --git a/third_party/blink/web_tests/http/tests/devtools/elements/highlight/highlight-css-flex-expected.txt b/third_party/blink/web_tests/http/tests/devtools/elements/highlight/highlight-css-flex-expected.txt
index 7193a00..a107bb5 100644
--- a/third_party/blink/web_tests/http/tests/devtools/elements/highlight/highlight-css-flex-expected.txt
+++ b/third_party/blink/web_tests/http/tests/devtools/elements/highlight/highlight-css-flex-expected.txt
@@ -114,51 +114,60 @@
       ],
       "lines": [
         [
-          [
-            "M",
-            8,
-            8,
-            "L",
-            174.671875,
-            8,
-            "L",
-            174.671875,
-            108,
-            "L",
-            8,
-            108,
-            "Z"
-          ],
-          [
-            "M",
-            174.671875,
-            8,
-            "L",
-            341.34375,
-            8,
-            "L",
-            341.34375,
-            108,
-            "L",
-            174.671875,
-            108,
-            "Z"
-          ],
-          [
-            "M",
-            341.34375,
-            8,
-            "L",
-            508.015625,
-            8,
-            "L",
-            508.015625,
-            108,
-            "L",
-            341.34375,
-            108,
-            "Z"
-          ]
+          {
+            "itemBorder": [
+              "M",
+              8,
+              8,
+              "L",
+              174.671875,
+              8,
+              "L",
+              174.671875,
+              108,
+              "L",
+              8,
+              108,
+              "Z"
+            ],
+            "baseline": 90
+          },
+          {
+            "itemBorder": [
+              "M",
+              174.671875,
+              8,
+              "L",
+              341.34375,
+              8,
+              "L",
+              341.34375,
+              108,
+              "L",
+              174.671875,
+              108,
+              "Z"
+            ],
+            "baseline": 90
+          },
+          {
+            "itemBorder": [
+              "M",
+              341.34375,
+              8,
+              "L",
+              508.015625,
+              8,
+              "L",
+              508.015625,
+              108,
+              "L",
+              341.34375,
+              108,
+              "Z"
+            ],
+            "baseline": 90
+          }
         ]
       ],
       "isHorizontalFlow": true,
diff --git a/third_party/blink/web_tests/http/tests/devtools/elements/highlight/highlight-css-flex-multiline-expected.txt b/third_party/blink/web_tests/http/tests/devtools/elements/highlight/highlight-css-flex-multiline-expected.txt
index 5f32fb1..2e793b7 100644
--- a/third_party/blink/web_tests/http/tests/devtools/elements/highlight/highlight-css-flex-multiline-expected.txt
+++ b/third_party/blink/web_tests/http/tests/devtools/elements/highlight/highlight-css-flex-multiline-expected.txt
@@ -114,98 +114,116 @@
       ],
       "lines": [
         [
-          [
-            "M",
-            100,
-            100,
-            "L",
-            200,
-            100,
-            "L",
-            200,
-            200,
-            "L",
-            100,
-            200,
-            "Z"
-          ],
-          [
-            "M",
-            250,
-            100,
-            "L",
-            350,
-            100,
-            "L",
-            350,
-            200,
-            "L",
-            250,
-            200,
-            "Z"
-          ],
-          [
-            "M",
-            400,
-            100,
-            "L",
-            500,
-            100,
-            "L",
-            500,
-            200,
-            "L",
-            400,
-            200,
-            "Z"
-          ]
+          {
+            "itemBorder": [
+              "M",
+              100,
+              100,
+              "L",
+              200,
+              100,
+              "L",
+              200,
+              200,
+              "L",
+              100,
+              200,
+              "Z"
+            ],
+            "baseline": 100
+          },
+          {
+            "itemBorder": [
+              "M",
+              250,
+              100,
+              "L",
+              350,
+              100,
+              "L",
+              350,
+              200,
+              "L",
+              250,
+              200,
+              "Z"
+            ],
+            "baseline": 100
+          },
+          {
+            "itemBorder": [
+              "M",
+              400,
+              100,
+              "L",
+              500,
+              100,
+              "L",
+              500,
+              200,
+              "L",
+              400,
+              200,
+              "Z"
+            ],
+            "baseline": 100
+          }
         ],
         [
-          [
-            "M",
-            100,
-            400,
-            "L",
-            200,
-            400,
-            "L",
-            200,
-            500,
-            "L",
-            100,
-            500,
-            "Z"
-          ],
-          [
-            "M",
-            250,
-            400,
-            "L",
-            350,
-            400,
-            "L",
-            350,
-            500,
-            "L",
-            250,
-            500,
-            "Z"
-          ],
-          [
-            "M",
-            400,
-            400,
-            "L",
-            500,
-            400,
-            "L",
-            500,
-            500,
-            "L",
-            400,
-            500,
-            "Z"
-          ]
+          {
+            "itemBorder": [
+              "M",
+              100,
+              400,
+              "L",
+              200,
+              400,
+              "L",
+              200,
+              500,
+              "L",
+              100,
+              500,
+              "Z"
+            ],
+            "baseline": 100
+          },
+          {
+            "itemBorder": [
+              "M",
+              250,
+              400,
+              "L",
+              350,
+              400,
+              "L",
+              350,
+              500,
+              "L",
+              250,
+              500,
+              "Z"
+            ],
+            "baseline": 100
+          },
+          {
+            "itemBorder": [
+              "M",
+              400,
+              400,
+              "L",
+              500,
+              400,
+              "L",
+              500,
+              500,
+              "L",
+              400,
+              500,
+              "Z"
+            ],
+            "baseline": 100
+          }
         ]
       ],
       "isHorizontalFlow": true,
diff --git a/third_party/blink/web_tests/http/tests/devtools/elements/highlight/highlight-css-flex-reverse-expected.txt b/third_party/blink/web_tests/http/tests/devtools/elements/highlight/highlight-css-flex-reverse-expected.txt
index f1ec94c..691a845 100644
--- a/third_party/blink/web_tests/http/tests/devtools/elements/highlight/highlight-css-flex-reverse-expected.txt
+++ b/third_party/blink/web_tests/http/tests/devtools/elements/highlight/highlight-css-flex-reverse-expected.txt
@@ -115,51 +115,60 @@
       ],
       "lines": [
         [
-          [
-            "M",
-            78,
-            8,
-            "L",
-            98,
-            8,
-            "L",
-            98,
-            28,
-            "L",
-            78,
-            28,
-            "Z"
-          ],
-          [
-            "M",
-            48,
-            88,
-            "L",
-            68,
-            88,
-            "L",
-            68,
-            108,
-            "L",
-            48,
-            108,
-            "Z"
-          ],
-          [
-            "M",
-            18,
-            8,
-            "L",
-            38,
-            8,
-            "L",
-            38,
-            28,
-            "L",
-            18,
-            28,
-            "Z"
-          ]
+          {
+            "itemBorder": [
+              "M",
+              78,
+              8,
+              "L",
+              98,
+              8,
+              "L",
+              98,
+              28,
+              "L",
+              78,
+              28,
+              "Z"
+            ],
+            "baseline": 20
+          },
+          {
+            "itemBorder": [
+              "M",
+              48,
+              88,
+              "L",
+              68,
+              88,
+              "L",
+              68,
+              108,
+              "L",
+              48,
+              108,
+              "Z"
+            ],
+            "baseline": 20
+          },
+          {
+            "itemBorder": [
+              "M",
+              18,
+              8,
+              "L",
+              38,
+              8,
+              "L",
+              38,
+              28,
+              "L",
+              18,
+              28,
+              "Z"
+            ],
+            "baseline": 20
+          }
         ]
       ],
       "isHorizontalFlow": true,
@@ -316,51 +325,60 @@
       ],
       "lines": [
         [
-          [
-            "M",
-            8,
-            178,
-            "L",
-            28,
-            178,
-            "L",
-            28,
-            198,
-            "L",
-            8,
-            198,
-            "Z"
-          ],
-          [
-            "M",
-            88,
-            148,
-            "L",
-            108,
-            148,
-            "L",
-            108,
-            168,
-            "L",
-            88,
-            168,
-            "Z"
-          ],
-          [
-            "M",
-            8,
-            118,
-            "L",
-            28,
-            118,
-            "L",
-            28,
-            138,
-            "L",
-            8,
-            138,
-            "Z"
-          ]
+          {
+            "itemBorder": [
+              "M",
+              8,
+              178,
+              "L",
+              28,
+              178,
+              "L",
+              28,
+              198,
+              "L",
+              8,
+              198,
+              "Z"
+            ],
+            "baseline": 20
+          },
+          {
+            "itemBorder": [
+              "M",
+              88,
+              148,
+              "L",
+              108,
+              148,
+              "L",
+              108,
+              168,
+              "L",
+              88,
+              168,
+              "Z"
+            ],
+            "baseline": 20
+          },
+          {
+            "itemBorder": [
+              "M",
+              8,
+              118,
+              "L",
+              28,
+              118,
+              "L",
+              28,
+              138,
+              "L",
+              8,
+              138,
+              "Z"
+            ],
+            "baseline": 20
+          }
         ]
       ],
       "isHorizontalFlow": false,
diff --git a/third_party/blink/web_tests/platform/linux/virtual/dark-color-scheme/fast/forms/color-scheme/media/video-overlay-menu-expected.png b/third_party/blink/web_tests/platform/linux/virtual/dark-color-scheme/fast/forms/color-scheme/media/video-overlay-menu-expected.png
index 528ddf8..f8b20c1 100644
--- a/third_party/blink/web_tests/platform/linux/virtual/dark-color-scheme/fast/forms/color-scheme/media/video-overlay-menu-expected.png
+++ b/third_party/blink/web_tests/platform/linux/virtual/dark-color-scheme/fast/forms/color-scheme/media/video-overlay-menu-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac-arm11.0/virtual/dark-color-scheme/fast/forms/color-scheme/media/video-overlay-menu-expected.png b/third_party/blink/web_tests/platform/mac-mac-arm11.0/virtual/dark-color-scheme/fast/forms/color-scheme/media/video-overlay-menu-expected.png
new file mode 100644
index 0000000..823f964
--- /dev/null
+++ b/third_party/blink/web_tests/platform/mac-mac-arm11.0/virtual/dark-color-scheme/fast/forms/color-scheme/media/video-overlay-menu-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.12/virtual/dark-color-scheme/fast/forms/color-scheme/media/video-overlay-menu-expected.png b/third_party/blink/web_tests/platform/mac-mac10.12/virtual/dark-color-scheme/fast/forms/color-scheme/media/video-overlay-menu-expected.png
index 67f8faac..b2b018e 100644
--- a/third_party/blink/web_tests/platform/mac-mac10.12/virtual/dark-color-scheme/fast/forms/color-scheme/media/video-overlay-menu-expected.png
+++ b/third_party/blink/web_tests/platform/mac-mac10.12/virtual/dark-color-scheme/fast/forms/color-scheme/media/video-overlay-menu-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.13/virtual/dark-color-scheme/fast/forms/color-scheme/media/video-overlay-menu-expected.png b/third_party/blink/web_tests/platform/mac-mac10.13/virtual/dark-color-scheme/fast/forms/color-scheme/media/video-overlay-menu-expected.png
index db0b34ff..76fd87a 100644
--- a/third_party/blink/web_tests/platform/mac-mac10.13/virtual/dark-color-scheme/fast/forms/color-scheme/media/video-overlay-menu-expected.png
+++ b/third_party/blink/web_tests/platform/mac-mac10.13/virtual/dark-color-scheme/fast/forms/color-scheme/media/video-overlay-menu-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.14/virtual/dark-color-scheme/fast/forms/color-scheme/media/video-overlay-menu-expected.png b/third_party/blink/web_tests/platform/mac-mac10.14/virtual/dark-color-scheme/fast/forms/color-scheme/media/video-overlay-menu-expected.png
index db0b34ff..76fd87a 100644
--- a/third_party/blink/web_tests/platform/mac-mac10.14/virtual/dark-color-scheme/fast/forms/color-scheme/media/video-overlay-menu-expected.png
+++ b/third_party/blink/web_tests/platform/mac-mac10.14/virtual/dark-color-scheme/fast/forms/color-scheme/media/video-overlay-menu-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.15/virtual/dark-color-scheme/fast/forms/color-scheme/media/video-overlay-menu-expected.png b/third_party/blink/web_tests/platform/mac-mac10.15/virtual/dark-color-scheme/fast/forms/color-scheme/media/video-overlay-menu-expected.png
index 823f964..650cae3 100644
--- a/third_party/blink/web_tests/platform/mac-mac10.15/virtual/dark-color-scheme/fast/forms/color-scheme/media/video-overlay-menu-expected.png
+++ b/third_party/blink/web_tests/platform/mac-mac10.15/virtual/dark-color-scheme/fast/forms/color-scheme/media/video-overlay-menu-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/virtual/dark-color-scheme/fast/forms/color-scheme/media/video-overlay-menu-expected.png b/third_party/blink/web_tests/platform/mac/virtual/dark-color-scheme/fast/forms/color-scheme/media/video-overlay-menu-expected.png
index 823f964..650cae3 100644
--- a/third_party/blink/web_tests/platform/mac/virtual/dark-color-scheme/fast/forms/color-scheme/media/video-overlay-menu-expected.png
+++ b/third_party/blink/web_tests/platform/mac/virtual/dark-color-scheme/fast/forms/color-scheme/media/video-overlay-menu-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/virtual/dark-color-scheme/fast/forms/color-scheme/media/video-overlay-menu-expected.png b/third_party/blink/web_tests/platform/win/virtual/dark-color-scheme/fast/forms/color-scheme/media/video-overlay-menu-expected.png
index d14dbb6..4a642cc 100644
--- a/third_party/blink/web_tests/platform/win/virtual/dark-color-scheme/fast/forms/color-scheme/media/video-overlay-menu-expected.png
+++ b/third_party/blink/web_tests/platform/win/virtual/dark-color-scheme/fast/forms/color-scheme/media/video-overlay-menu-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win7/virtual/dark-color-scheme/fast/forms/color-scheme/media/video-overlay-menu-expected.png b/third_party/blink/web_tests/platform/win7/virtual/dark-color-scheme/fast/forms/color-scheme/media/video-overlay-menu-expected.png
index d14dbb6..4a642cc 100644
--- a/third_party/blink/web_tests/platform/win7/virtual/dark-color-scheme/fast/forms/color-scheme/media/video-overlay-menu-expected.png
+++ b/third_party/blink/web_tests/platform/win7/virtual/dark-color-scheme/fast/forms/color-scheme/media/video-overlay-menu-expected.png
Binary files differ
diff --git a/third_party/blink/web_tests/virtual/dark-color-scheme/media/overflow-menu-background-color.html b/third_party/blink/web_tests/virtual/dark-color-scheme/media/overflow-menu-background-color.html
new file mode 100644
index 0000000..fe6461a0
--- /dev/null
+++ b/third_party/blink/web_tests/virtual/dark-color-scheme/media/overflow-menu-background-color.html
@@ -0,0 +1,28 @@
+<!DOCTYPE html>
+<title>Ensure overflow menu has the correct background color.</title>
+<meta name="color-scheme" content="dark">
+<script src='../../../resources/testharness.js'></script>
+<script src='../../../resources/testharnessreport.js'></script>
+<script src='../../../media/media-controls.js'></script>
+<video controls></video>
+<script>
+async_test(t => {
+  const  video = document.querySelector('video');
+  video.src = '../../../media/content/test.ogv';
+  const track = video.addTextTrack('captions');
+
+  video.onloadeddata = t.step_func(() => {
+    const menu = overflowMenu(video);
+    const button = overflowButton(video);
+
+    assert_not_equals(getComputedStyle(button).display, 'none');
+    assert_equals(getComputedStyle(menu).display, 'none');
+
+    // Clicking on the button should show the menu.
+    singleTapOnControl(button, t.step_func_done(() => {
+      assert_not_equals(getComputedStyle(menu).display, 'none');
+      assert_equals(getComputedStyle(menu).backgroundColor, 'rgb(59, 59, 59)');
+    }));
+  });
+});
+</script>
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml
index 8e9a136..638765f 100644
--- a/tools/metrics/histograms/enums.xml
+++ b/tools/metrics/histograms/enums.xml
@@ -30418,6 +30418,10 @@
   <int value="3734" label="ChangeTypeUsingConfig"/>
   <int value="3735" label="V8SourceBuffer_AppendEncodedChunks_Method"/>
   <int value="3736" label="OversrollBehaviorOnViewportBreaks"/>
+  <int value="3737" label="SameOriginJsonTypeForScript"/>
+  <int value="3738" label="CrossOriginJsonTypeForScript"/>
+  <int value="3739" label="SameOriginStrictNosniffWouldBlock"/>
+  <int value="3740" label="CrossOriginStrictNosniffWouldBlock"/>
 </enum>
 
 <enum name="FeaturePolicyAllowlistType">
diff --git a/tools/metrics/histograms/histograms_xml/content/histograms.xml b/tools/metrics/histograms/histograms_xml/content/histograms.xml
index bcaec12..9372fe75 100644
--- a/tools/metrics/histograms/histograms_xml/content/histograms.xml
+++ b/tools/metrics/histograms/histograms_xml/content/histograms.xml
@@ -307,6 +307,9 @@
 
 <histogram name="ContentSettings.EphemeralFlashPermission"
     enum="ContentSettings.EphemeralFlashPermission" expires_after="M89">
+  <obsolete>
+    Flash / Plugins is deprecated since M87 and removed in M89.
+  </obsolete>
   <owner>engedy@chromium.org</owner>
   <owner>src/components/permissions/PERMISSIONS_OWNERS</owner>
   <summary>
diff --git a/tools/metrics/histograms/histograms_xml/plugin/histograms.xml b/tools/metrics/histograms/histograms_xml/plugin/histograms.xml
index 90dec58..80214e0 100644
--- a/tools/metrics/histograms/histograms_xml/plugin/histograms.xml
+++ b/tools/metrics/histograms/histograms_xml/plugin/histograms.xml
@@ -178,8 +178,8 @@
 </histogram>
 
 <histogram name="PluginVm.Image.DownloadedSize" units="MB"
-    expires_after="2020-12-31">
-  <owner>aoldemeier@chromium.org</owner>
+    expires_after="2021-05-16">
+  <owner>joelhockey@chromium.org</owner>
   <owner>okalitova@chromium.org</owner>
   <owner>timloh@chromium.org</owner>
   <summary>
@@ -189,8 +189,8 @@
 </histogram>
 
 <histogram name="PluginVm.LaunchResult" enum="PluginVmLaunchResult"
-    expires_after="2020-12-31">
-  <owner>aoldemeier@chromium.org</owner>
+    expires_after="2021-05-16">
+  <owner>joelhockey@chromium.org</owner>
   <owner>okalitova@chromium.org</owner>
   <owner>timloh@chromium.org</owner>
   <summary>
@@ -208,7 +208,7 @@
 
 <histogram name="PluginVm.SetupResult" enum="PluginVmSetupResult"
     expires_after="2021-05-16">
-  <owner>aoldemeier@chromium.org</owner>
+  <owner>joelhockey@chromium.org</owner>
   <owner>okalitova@chromium.org</owner>
   <owner>timloh@chromium.org</owner>
   <summary>
@@ -218,8 +218,8 @@
   </summary>
 </histogram>
 
-<histogram name="PluginVm.SetupTime" units="ms" expires_after="2020-12-31">
-  <owner>aoldemeier@chromium.org</owner>
+<histogram name="PluginVm.SetupTime" units="ms" expires_after="2021-05-16">
+  <owner>joelhockey@chromium.org</owner>
   <owner>okalitova@chromium.org</owner>
   <owner>timloh@chromium.org</owner>
   <summary>
diff --git a/tools/perf/core/perfetto_binary_roller/binary_deps.json b/tools/perf/core/perfetto_binary_roller/binary_deps.json
index 6e582a3..7aa8920 100644
--- a/tools/perf/core/perfetto_binary_roller/binary_deps.json
+++ b/tools/perf/core/perfetto_binary_roller/binary_deps.json
@@ -1,8 +1,8 @@
 {
     "trace_processor_shell": {
         "win": {
-            "hash": "4cadd9ec68574ad75af15c2d54a08b3e3234c628",
-            "remote_path": "perfetto_binaries/trace_processor_shell/win/ae504d46b4c459c5ca024d3ba4f70990da6265d1/trace_processor_shell.exe"
+            "hash": "50c634c891c0c93d8afee401aa4f31adb86d2eba",
+            "remote_path": "perfetto_binaries/trace_processor_shell/win/a45552c0f29dc62ed601a22b258b27ed2838bc57/trace_processor_shell.exe"
         },
         "mac": {
             "hash": "50d02eb2ca79777ef1a5250242d821413d57e41f",
diff --git a/tools/perf/expectations.config b/tools/perf/expectations.config
index 2d4cee1bb..c71e212 100644
--- a/tools/perf/expectations.config
+++ b/tools/perf/expectations.config
@@ -263,6 +263,8 @@
 crbug.com/948789 [ android-nexus-5x ] startup.mobile/maps_pwa:with_http_cache [ Skip ]
 crbug.com/1030735 [ android-weblayer ] startup.mobile/maps_pwa:with_http_cache [ Skip ]
 crbug.com/1059717 [ android-pixel-2 ] startup.mobile/maps_pwa:with_http_cache [ Skip ]
+crbug.com/1142286 [ android-pixel-2 ] startup.mobile/cct:coldish:bbc [ Skip ]
+crbug.com/1142286 [ android-nexus-5 ] startup.mobile/cct:coldish:bbc [ Skip ]
 
 # Benchmark: system_health.common_desktop
 crbug.com/903417 [ mac ] system_health.common_desktop/long_running:tools:gmail-foreground [ Skip ]
@@ -287,6 +289,7 @@
 crbug.com/1044682 [ desktop ] system_health.common_desktop/browse:tools:gmail-search:2020 [ Skip ]
 crbug.com/1044682 [ desktop ] system_health.common_desktop/browse:tools:gmail-compose:2020 [ Skip ]
 crbug.com/1150432 [ linux ] system_health.common_desktop/long_running:tools:gmail-background [ Skip ]
+crbug.com/1154753 [ linux ] system_health.common_desktop/browse:media:imgur [ Skip ]
 
 # Benchmark: system_health.common_mobile
 crbug.com/1007355 [ android-go android-webview ] system_health.common_mobile/load:media:imgur:2018 [ Skip ]
@@ -372,6 +375,7 @@
 crbug.com/1147969 [ fuchsia ] system_health.memory_desktop/long_running:tools:gmail-foreground [ Skip ]
 crbug.com/1147969 [ fuchsia ] system_health.memory_desktop/multitab:misc:typical24 [ Skip ]
 crbug.com/1147969 [ fuchsia ] system_health.memory_desktop/multitab:misc:typical24:2018 [ Skip ]
+crbug.com/1154753 [ linux ] system_health.memory_desktop/browse:media:imgur [ Skip ]
 
 # Memory dumps don't work at the moment for Google Earth, see the issue.
 crbug.com/1057035 system_health.memory_desktop/browse:tools:earth:2020 [ Skip ]
diff --git a/ui/accessibility/platform/ax_platform_node_delegate.h b/ui/accessibility/platform/ax_platform_node_delegate.h
index 4b49d5e..28ba415 100644
--- a/ui/accessibility/platform/ax_platform_node_delegate.h
+++ b/ui/accessibility/platform/ax_platform_node_delegate.h
@@ -93,7 +93,9 @@
   // field.
   virtual base::string16 GetValueForControl() const = 0;
 
-  // Get the unignored selection from the tree
+  // Get the unignored selection from the tree, meaning the selection whose
+  // endpoints are on unignored nodes. (An ignored node means that the node
+  // should not be exposed to platform APIs: See "IsInvisibleOrIgnored".)
   virtual const AXTree::Selection GetUnignoredSelection() const = 0;
 
   // Creates a text position rooted at this object.
@@ -117,9 +119,20 @@
   virtual int GetIndexInParent() = 0;
 
   // Get the number of children of this node.
+  //
+  // Note that for accessibility trees that have ignored nodes, this method
+  // should return the number of unignored children. All ignored nodes are
+  // recursively removed from the children count. (An ignored node means that
+  // the node should not be exposed to platform APIs: See
+  // "IsInvisibleOrIgnored".)
   virtual int GetChildCount() const = 0;
 
-  // Get the child of a node given a 0-based index.
+  // Get a child of a node given a 0-based index.
+  //
+  // Note that for accessibility trees that have ignored nodes, this method
+  // returns only unignored children. All ignored nodes are recursively removed.
+  // (An ignored node means that the node should not be exposed to platform
+  // APIs: See "IsInvisibleOrIgnored".)
   virtual gfx::NativeViewAccessible ChildAtIndex(int index) = 0;
 
   // Returns true if it has a modal dialog.
@@ -152,7 +165,8 @@
   // layer.
   virtual bool IsLeaf() const = 0;
 
-  // Returns true if this node is invisible or ignored.
+  // Returns true if this node is invisible or ignored. (Only relevant for
+  // accessibility trees that support ignored nodes.)
   virtual bool IsInvisibleOrIgnored() const = 0;
 
   // Returns true if this node is focused.
diff --git a/ui/chromeos/user_activity_power_manager_notifier.cc b/ui/chromeos/user_activity_power_manager_notifier.cc
index 069de4d..87f780ae 100644
--- a/ui/chromeos/user_activity_power_manager_notifier.cc
+++ b/ui/chromeos/user_activity_power_manager_notifier.cc
@@ -112,7 +112,7 @@
 }
 
 void UserActivityPowerManagerNotifier::SuspendDone(
-    const base::TimeDelta& sleep_duration) {
+    base::TimeDelta sleep_duration) {
   suspending_ = false;
 }
 
diff --git a/ui/chromeos/user_activity_power_manager_notifier.h b/ui/chromeos/user_activity_power_manager_notifier.h
index 8703d22..6682d12 100644
--- a/ui/chromeos/user_activity_power_manager_notifier.h
+++ b/ui/chromeos/user_activity_power_manager_notifier.h
@@ -55,7 +55,7 @@
 
   // chromeos::PowerManagerClient::Observer:
   void SuspendImminent(power_manager::SuspendImminent::Reason reason) override;
-  void SuspendDone(const base::TimeDelta& sleep_duration) override;
+  void SuspendDone(base::TimeDelta sleep_duration) override;
 
  private:
   // Notifies power manager that the user is active and activity type. No-op if
diff --git a/ui/views/accessibility/view_accessibility.cc b/ui/views/accessibility/view_accessibility.cc
index 3bbe376..59edf73 100644
--- a/ui/views/accessibility/view_accessibility.cc
+++ b/ui/views/accessibility/view_accessibility.cc
@@ -135,6 +135,10 @@
   return is_leaf_;
 }
 
+bool ViewAccessibility::IsIgnored() const {
+  return is_ignored_;
+}
+
 void ViewAccessibility::GetAccessibleNodeData(ui::AXNodeData* data) const {
   data->id = GetUniqueId().Get();
 
@@ -174,7 +178,7 @@
   if (custom_data_.GetHasPopup() != ax::mojom::HasPopup::kFalse)
     data->SetHasPopup(custom_data_.GetHasPopup());
 
-  static const ax::mojom::IntAttribute kOverridableIntAttributes[]{
+  static constexpr ax::mojom::IntAttribute kOverridableIntAttributes[]{
       ax::mojom::IntAttribute::kPosInSet,
       ax::mojom::IntAttribute::kSetSize,
   };
@@ -183,7 +187,7 @@
       data->AddIntAttribute(attribute, custom_data_.GetIntAttribute(attribute));
   }
 
-  static const ax::mojom::IntListAttribute kOverridableIntListAttributes[]{
+  static constexpr ax::mojom::IntListAttribute kOverridableIntListAttributes[]{
       ax::mojom::IntListAttribute::kDescribedbyIds,
   };
   for (auto attribute : kOverridableIntListAttributes) {
@@ -212,17 +216,13 @@
   data->AddStringAttribute(ax::mojom::StringAttribute::kClassName,
                            view_->GetClassName());
 
-  if (IsIgnored()) {
-    // Prevent screen readers from navigating to or speaking ignored nodes.
-    data->AddState(ax::mojom::State::kInvisible);
+  if (is_ignored_ || data->role == ax::mojom::Role::kIgnored) {
     data->AddState(ax::mojom::State::kIgnored);
-    data->role = ax::mojom::Role::kIgnored;
-    return;
+  } else {
+    if (view_->IsAccessibilityFocusable() && !focused_virtual_child_)
+      data->AddState(ax::mojom::State::kFocusable);
   }
 
-  if (view_->IsAccessibilityFocusable() && !focused_virtual_child_)
-    data->AddState(ax::mojom::State::kFocusable);
-
   if (!view_->GetEnabled())
     data->SetRestriction(ax::mojom::Restriction::kDisabled);
 
diff --git a/ui/views/accessibility/view_accessibility.h b/ui/views/accessibility/view_accessibility.h
index 92989fe..1a5dd2e 100644
--- a/ui/views/accessibility/view_accessibility.h
+++ b/ui/views/accessibility/view_accessibility.h
@@ -113,7 +113,7 @@
   View* view() const { return view_; }
   AXVirtualView* FocusedVirtualChild() const { return focused_virtual_child_; }
   virtual bool IsLeaf() const;
-  bool IsIgnored() const { return is_ignored_; }
+  virtual bool IsIgnored() const;
 
   //
   // Methods for managing virtual views.
diff --git a/ui/views/accessibility/view_ax_platform_node_delegate.cc b/ui/views/accessibility/view_ax_platform_node_delegate.cc
index 7dd0469..a39b738 100644
--- a/ui/views/accessibility/view_ax_platform_node_delegate.cc
+++ b/ui/views/accessibility/view_ax_platform_node_delegate.cc
@@ -278,12 +278,14 @@
   // accessibility tree. We need to replace this with a cross-platform
   // solution that works for ChromeVox, too, and move it to ViewAccessibility.
   if (IsViewUnfocusableDescendantOfFocusableAncestor(view()))
-    data_.role = ax::mojom::Role::kIgnored;
+    data_.AddState(ax::mojom::State::kIgnored);
 
   return data_;
 }
 
 int ViewAXPlatformNodeDelegate::GetChildCount() const {
+  // We do not call "IsLeaf" here because "AXPlatformNodeDelegateBase::IsLeaf"
+  // calls "GetChildCount", and this will result in an infinit loop.
   if (ViewAccessibility::IsLeaf())
     return 0;
 
@@ -462,6 +464,10 @@
   return ViewAccessibility::IsLeaf() || AXPlatformNodeDelegateBase::IsLeaf();
 }
 
+bool ViewAXPlatformNodeDelegate::IsIgnored() const {
+  return ViewAccessibility::IsIgnored() || GetData().IsIgnored();
+}
+
 bool ViewAXPlatformNodeDelegate::IsFocused() const {
   return GetFocus() == GetNativeObject();
 }
@@ -755,15 +761,7 @@
           [](View* view) {
             ViewAccessibility& view_accessibility =
                 view->GetViewAccessibility();
-            bool is_ignored = view_accessibility.IsIgnored();
-            // TODO(dmazzoni): Remove the remainder of this lambda once the
-            // temporary code in GetData() setting the role to kIgnored is moved
-            // to ViewAccessibility.
-            ViewAXPlatformNodeDelegate* ax_delegate =
-                static_cast<ViewAXPlatformNodeDelegate*>(&view_accessibility);
-            if (ax_delegate)
-              is_ignored = is_ignored || ax_delegate->IsIgnored();
-            return is_ignored;
+            return view_accessibility.IsIgnored();
           }),
       views_in_group->end());
 }
diff --git a/ui/views/accessibility/view_ax_platform_node_delegate.h b/ui/views/accessibility/view_ax_platform_node_delegate.h
index 6bcc98c7..82cb7d68 100644
--- a/ui/views/accessibility/view_ax_platform_node_delegate.h
+++ b/ui/views/accessibility/view_ax_platform_node_delegate.h
@@ -49,13 +49,10 @@
 #if defined(OS_APPLE)
   void AnnounceText(const base::string16& text) override;
 #endif
+  bool IsIgnored() const override;
   void FireFocusAfterMenuClose() override;
 
   // ui::AXPlatformNodeDelegate
-  // Note that, for parents of virtual views, GetChildCount() and ChildAtIndex()
-  // present to assistive technologies the unignored accessibility subtree,
-  // which doesn't necessarily reflect the internal descendant tree. (An ignored
-  // node means that the node should not be exposed to the platform.)
   const ui::AXNodeData& GetData() const override;
   int GetChildCount() const override;
   gfx::NativeViewAccessible ChildAtIndex(int index) override;
diff --git a/ui/views/accessibility/view_ax_platform_node_delegate_unittest.cc b/ui/views/accessibility/view_ax_platform_node_delegate_unittest.cc
index 39d0657..23f1b65 100644
--- a/ui/views/accessibility/view_ax_platform_node_delegate_unittest.cc
+++ b/ui/views/accessibility/view_ax_platform_node_delegate_unittest.cc
@@ -240,18 +240,31 @@
   TableView* table_ = nullptr;  // Owned by parent.
 };
 
-TEST_F(ViewAXPlatformNodeDelegateTest, RoleShouldMatch) {
+TEST_F(ViewAXPlatformNodeDelegateTest, FocusBehaviorShouldAffectIgnoredState) {
   EXPECT_EQ(ax::mojom::Role::kButton, button_accessibility()->GetData().role);
+  EXPECT_FALSE(
+      button_accessibility()->GetData().HasState(ax::mojom::State::kIgnored));
+
   // Since the label is a subview of |button_|, and the button is keyboard
-  // focusable, the label is assumed to form part of the button and not have a
-  // role of its own.
-  EXPECT_EQ(ax::mojom::Role::kIgnored, label_accessibility()->GetData().role);
-  // This will happen for all potentially keyboard-focusable Views with
-  // non-keyboard-focusable children, so if we make the button unfocusable, the
-  // label will be allowed to have its own role again.
-  button_->SetFocusBehavior(View::FocusBehavior::NEVER);
+  // focusable, the label is assumed to form part of the button and should be
+  // ignored.
   EXPECT_EQ(ax::mojom::Role::kStaticText,
             label_accessibility()->GetData().role);
+  EXPECT_TRUE(
+      label_accessibility()->GetData().HasState(ax::mojom::State::kIgnored));
+
+  // This will happen for all potentially keyboard-focusable Views with
+  // non-keyboard-focusable children, so if we make the button unfocusable, the
+  // label will not be ignored any more.
+  button_->SetFocusBehavior(View::FocusBehavior::NEVER);
+
+  EXPECT_EQ(ax::mojom::Role::kButton, button_accessibility()->GetData().role);
+  EXPECT_FALSE(
+      button_accessibility()->GetData().HasState(ax::mojom::State::kIgnored));
+  EXPECT_EQ(ax::mojom::Role::kStaticText,
+            label_accessibility()->GetData().role);
+  EXPECT_FALSE(
+      label_accessibility()->GetData().HasState(ax::mojom::State::kIgnored));
 }
 
 TEST_F(ViewAXPlatformNodeDelegateTest, BoundsShouldMatch) {
@@ -269,21 +282,25 @@
   // be either before or after the label, which complicates correctness testing.
   button_->SetInstallFocusRingOnFocus(false);
 
-  // |button_| is focusable, so |label_| (as its child) should be ignored.
+  // Since the label is a subview of |button_|, and the button is keyboard
+  // focusable, the label is assumed to form part of the button and should be
+  // ignored, i.e. no visible in the accessibility tree that is available to
+  // platform APIs.
   EXPECT_NE(View::FocusBehavior::NEVER, button_->GetFocusBehavior());
-  EXPECT_EQ(1, button_accessibility()->GetChildCount());
-  EXPECT_EQ(button_->GetNativeViewAccessible(),
-            label_accessibility()->GetParent());
-  EXPECT_EQ(ax::mojom::Role::kIgnored, label_accessibility()->GetData().role);
+  EXPECT_EQ(0, button_accessibility()->GetChildCount());
+  EXPECT_EQ(ax::mojom::Role::kStaticText,
+            label_accessibility()->GetData().role);
 
-  // If |button_| is no longer focusable, |label_| should show up again.
+  // Modify the focus behavior to make the button unfocusable, and verify that
+  // the label is now a child of the button.
   button_->SetFocusBehavior(View::FocusBehavior::NEVER);
   EXPECT_EQ(1, button_accessibility()->GetChildCount());
   EXPECT_EQ(label_->GetNativeViewAccessible(),
             button_accessibility()->ChildAtIndex(0));
   EXPECT_EQ(button_->GetNativeViewAccessible(),
             label_accessibility()->GetParent());
-  EXPECT_NE(ax::mojom::Role::kIgnored, label_accessibility()->GetData().role);
+  EXPECT_EQ(ax::mojom::Role::kStaticText,
+            label_accessibility()->GetData().role);
 }
 
 // Verify Views with invisible ancestors have ax::mojom::State::kInvisible.
diff --git a/weblayer/browser/android/javatests/src/org/chromium/weblayer/test/NavigationTest.java b/weblayer/browser/android/javatests/src/org/chromium/weblayer/test/NavigationTest.java
index c483b2e0..e617f48 100644
--- a/weblayer/browser/android/javatests/src/org/chromium/weblayer/test/NavigationTest.java
+++ b/weblayer/browser/android/javatests/src/org/chromium/weblayer/test/NavigationTest.java
@@ -12,10 +12,13 @@
 
 import static org.chromium.content_public.browser.test.util.TestThreadUtils.runOnUiThreadBlocking;
 
+import android.content.Intent;
 import android.net.Uri;
+import android.os.Bundle;
 import android.support.test.InstrumentationRegistry;
 import android.webkit.WebResourceResponse;
 
+import androidx.fragment.app.Fragment;
 import androidx.test.filters.SmallTest;
 
 import org.hamcrest.Matchers;
@@ -73,8 +76,23 @@
     private static final String STREAM_HTML = "<html>foobar</html>";
     private static final String STREAM_INNER_BODY = "foobar";
 
+    // A URL with a custom scheme/host that is handled by WebLayer Shell.
+    private static final String CUSTOM_SCHEME_URL_WITH_DEFAULT_EXTERNAL_HANDLER =
+            "weblayer://weblayertest/intent";
+    // An intent that opens Chrome to view a specified URL.
+    private static final String INTENT_TO_CHROME_URL =
+            "intent://play.google.com/store/apps/details?id=com.facebook.katana/#Intent;scheme=https;action=android.intent.action.VIEW;package=com.android.chrome;end";
+
     private static boolean sShouldTrackPageInitiated;
 
+    // An IntentInterceptor that simply drops intents to ensure that intent launches don't interfere
+    // with running of tests.
+    private class IntentInterceptor implements InstrumentationActivity.IntentInterceptor {
+        @Override
+        public void interceptIntent(
+                Fragment fragment, Intent intent, int requestCode, Bundle options) {}
+    }
+
     private static class Callback extends NavigationCallback {
         public static class NavigationCallbackHelper extends CallbackHelper {
             private Uri mUri;
@@ -83,6 +101,7 @@
             private List<Uri> mRedirectChain;
             private @LoadError int mLoadError;
             private @NavigationState int mNavigationState;
+            private boolean mIsKnownProtocol;
             private boolean mIsPageInitiatedNavigation;
 
             public void notifyCalled(Navigation navigation) {
@@ -92,6 +111,7 @@
                 mRedirectChain = navigation.getRedirectChain();
                 mLoadError = navigation.getLoadError();
                 mNavigationState = navigation.getState();
+                mIsKnownProtocol = navigation.isKnownProtocol();
                 if (sShouldTrackPageInitiated) {
                     mIsPageInitiatedNavigation = navigation.isPageInitiated();
                 }
@@ -132,6 +152,10 @@
                 return mNavigationState;
             }
 
+            public boolean isKnownProtocol() {
+                return mIsKnownProtocol;
+            }
+
             public boolean isPageInitiated() {
                 assert sShouldTrackPageInitiated;
                 return mIsPageInitiatedNavigation;
@@ -527,6 +551,43 @@
         assertEquals(mCallback.onFailedCallback.getNavigationState(), NavigationState.FAILED);
     }
 
+    @MinWebLayerVersion(89)
+    @Test
+    @SmallTest
+    public void testIsKnownProtocol() throws Exception {
+        InstrumentationActivity activity = mActivityTestRule.launchShellWithUrl(URL1);
+        IntentInterceptor intentInterceptor = new IntentInterceptor();
+        activity.setIntentInterceptor(intentInterceptor);
+        setNavigationCallback(activity);
+
+        // Test various known protocol cases.
+        String httpUrl = mActivityTestRule.getTestDataURL("simple_page.html");
+        mActivityTestRule.navigateAndWait(httpUrl);
+        assertEquals(true, mCallback.onStartedCallback.isKnownProtocol());
+        assertEquals(true, mCallback.onCompletedCallback.isKnownProtocol());
+
+        mActivityTestRule.navigateAndWait("about:blank");
+        assertEquals(true, mCallback.onStartedCallback.isKnownProtocol());
+        assertEquals(true, mCallback.onCompletedCallback.isKnownProtocol());
+
+        String dataUrl = "data:text,foo";
+        mActivityTestRule.navigateAndWait(dataUrl);
+        assertEquals(true, mCallback.onStartedCallback.isKnownProtocol());
+        assertEquals(true, mCallback.onCompletedCallback.isKnownProtocol());
+
+        // Test external protocol cases.
+        mActivityTestRule.navigateAndWaitForFailure(activity.getTab(), INTENT_TO_CHROME_URL,
+                /*waitForPaint=*/false);
+        assertEquals(false, mCallback.onStartedCallback.isKnownProtocol());
+        assertEquals(false, mCallback.onFailedCallback.isKnownProtocol());
+
+        mActivityTestRule.navigateAndWaitForFailure(activity.getTab(),
+                CUSTOM_SCHEME_URL_WITH_DEFAULT_EXTERNAL_HANDLER,
+                /*waitForPaint=*/false);
+        assertEquals(false, mCallback.onStartedCallback.isKnownProtocol());
+        assertEquals(false, mCallback.onFailedCallback.isKnownProtocol());
+    }
+
     @Test
     @SmallTest
     public void testRepostConfirmation() throws Exception {
diff --git a/weblayer/browser/java/org/chromium/weblayer_private/NavigationImpl.java b/weblayer/browser/java/org/chromium/weblayer_private/NavigationImpl.java
index a3d9e82..616738d3 100644
--- a/weblayer/browser/java/org/chromium/weblayer_private/NavigationImpl.java
+++ b/weblayer/browser/java/org/chromium/weblayer_private/NavigationImpl.java
@@ -149,6 +149,13 @@
     }
 
     @Override
+    public boolean isKnownProtocol() {
+        StrictModeWorkaround.apply();
+        throwIfNativeDestroyed();
+        return NavigationImplJni.get().isKnownProtocol(mNativeNavigationImpl);
+    }
+
+    @Override
     public boolean wasIntentLaunched() {
         return mIntentLaunched;
     }
@@ -231,6 +238,7 @@
         boolean isSameDocument(long nativeNavigationImpl);
         boolean isErrorPage(long nativeNavigationImpl);
         boolean isDownload(long nativeNavigationImpl);
+        boolean isKnownProtocol(long nativeNavigationImpl);
         boolean wasStopCalled(long nativeNavigationImpl);
         int getLoadError(long nativeNavigationImpl);
         boolean setRequestHeader(long nativeNavigationImpl, String name, String value);
diff --git a/weblayer/browser/java/org/chromium/weblayer_private/interfaces/INavigation.aidl b/weblayer/browser/java/org/chromium/weblayer_private/interfaces/INavigation.aidl
index de8dcb7..97ac9f6 100644
--- a/weblayer/browser/java/org/chromium/weblayer_private/interfaces/INavigation.aidl
+++ b/weblayer/browser/java/org/chromium/weblayer_private/interfaces/INavigation.aidl
@@ -37,4 +37,5 @@
   // @since 89
   boolean wasIntentLaunched() = 13;
   boolean isUserDecidingIntentLaunch() = 14;
+  boolean isKnownProtocol() = 15;
 }
diff --git a/weblayer/browser/navigation_impl.cc b/weblayer/browser/navigation_impl.cc
index 8d97b07..43c59e1 100644
--- a/weblayer/browser/navigation_impl.cc
+++ b/weblayer/browser/navigation_impl.cc
@@ -149,6 +149,10 @@
   return navigation_handle_->IsDownload();
 }
 
+bool NavigationImpl::IsKnownProtocol() {
+  return !navigation_handle_->IsExternalProtocol();
+}
+
 bool NavigationImpl::WasStopCalled() {
   return was_stopped_;
 }
diff --git a/weblayer/browser/navigation_impl.h b/weblayer/browser/navigation_impl.h
index 06214309..ac30de83 100644
--- a/weblayer/browser/navigation_impl.h
+++ b/weblayer/browser/navigation_impl.h
@@ -69,6 +69,7 @@
   bool IsSameDocument(JNIEnv* env) { return IsSameDocument(); }
   bool IsErrorPage(JNIEnv* env) { return IsErrorPage(); }
   bool IsDownload(JNIEnv* env) { return IsDownload(); }
+  bool IsKnownProtocol(JNIEnv* env) { return IsKnownProtocol(); }
   bool WasStopCalled(JNIEnv* env) { return WasStopCalled(); }
   int GetLoadError(JNIEnv* env) { return static_cast<int>(GetLoadError()); }
   jboolean SetRequestHeader(JNIEnv* env,
@@ -97,6 +98,7 @@
   bool IsSameDocument() override;
   bool IsErrorPage() override;
   bool IsDownload() override;
+  bool IsKnownProtocol() override;
   bool WasStopCalled() override;
   LoadError GetLoadError() override;
   void SetRequestHeader(const std::string& name,
diff --git a/weblayer/public/java/org/chromium/weblayer/Navigation.java b/weblayer/public/java/org/chromium/weblayer/Navigation.java
index e312642..4b7cde4 100644
--- a/weblayer/public/java/org/chromium/weblayer/Navigation.java
+++ b/weblayer/public/java/org/chromium/weblayer/Navigation.java
@@ -145,6 +145,28 @@
     }
 
     /**
+     * Whether the target URL can be handled by the browser's internal protocol handlers, i.e., has
+     * a scheme that the browser knows how to process internally. Examples of such URLs are
+     * http(s) URLs, data URLs, and file URLs. A typical example of a URL for which there is no
+     * internal protocol handler (and for which this method would return also) is an intent:// URL.
+     *
+     * @return Whether the target URL of the navigation has a known protocol.
+     *
+     * @since 89
+     */
+    public boolean isKnownProtocol() {
+        ThreadCheck.ensureOnUiThread();
+        if (WebLayer.getSupportedMajorVersionInternal() < 89) {
+            throw new UnsupportedOperationException();
+        }
+        try {
+            return mNavigationImpl.isKnownProtocol();
+        } catch (RemoteException e) {
+            throw new APICallException(e);
+        }
+    }
+
+    /**
      * Whether this navigation resulted in an external intent being launched. Returns false if this
      * navigation did not do so, or if that status is not yet known for this navigation.  This
      * status is determined for a navigation when processing final (post redirect) HTTP response
diff --git a/weblayer/public/navigation.h b/weblayer/public/navigation.h
index 0108819..8881a84 100644
--- a/weblayer/public/navigation.h
+++ b/weblayer/public/navigation.h
@@ -70,6 +70,14 @@
   // NavigationObserver::NavigationFailed.
   virtual bool IsDownload() = 0;
 
+  // Whether the target URL can be handled by the browser's internal protocol
+  // handlers, i.e., has a scheme that the browser knows how to process
+  // internally. Examples of such URLs are http(s) URLs, data URLs, and file
+  // URLs. A typical example of a URL for which there is no internal protocol
+  // handler (and for which this method would return false) is an intent:// URL.
+  // Added in 89.
+  virtual bool IsKnownProtocol() = 0;
+
   // Returns true if the navigation was stopped before it could complete because
   // NavigationController::Stop() was called.
   virtual bool WasStopCalled() = 0;