diff --git a/DEPS b/DEPS
index 2d69e50..96627636 100644
--- a/DEPS
+++ b/DEPS
@@ -204,11 +204,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': 'a850a4a6b2a54be93d4f18bb347c7196069205d0',
+  'skia_revision': '01cb243b5e8cb31cbba5f9ce854fcd0b02a992d9',
   # 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': '5c86b9ed5fdab5a53c326ae37b77effcef0b67ff',
+  'v8_revision': 'af560a8bf8228e4c3ec67af7a567370c75ff17bc',
   # 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.
@@ -216,7 +216,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': 'faa3915ee3f06dade41a2bc260d850b99c5c6845',
+  'angle_revision': '2d07b04d5a2635ccf4527eb644e8b0ed1fd92b4c',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling SwiftShader
   # and whatever else without interference from each other.
@@ -283,7 +283,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': '505edf3ec225fca4e485183e3886096b714dc675',
+  'devtools_frontend_revision': '20ce25246086287e32b4d174433959af6d2cb7e5',
   # 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.
@@ -323,7 +323,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': '7c3b5740db6be782ca4d2e78139568b67db1fc0f',
+  'dawn_revision': '7fe018c06578ff04d0e4ec2a0ada2c34a82ef6b0',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling feed
   # and whatever else without interference from each other.
@@ -910,7 +910,7 @@
   # Tools used when building Chrome for Chrome OS. This affects both the Simple
   # Chrome workflow, as well as the chromeos-chrome ebuild.
   'src/third_party/chromite': {
-      'url': Var('chromium_git') + '/chromiumos/chromite.git' + '@' + 'e7097d3ded1dc884cf041d0bb07906b1fca17c5e',
+      'url': Var('chromium_git') + '/chromiumos/chromite.git' + '@' + '0b1154cfa33cf846ad3b4cb223b249705139bdcc',
       'condition': 'checkout_chromeos',
   },
 
@@ -1538,7 +1538,7 @@
     Var('chromium_git') + '/external/github.com/gpuweb/cts.git' + '@' + '66460536ee975a3e98931b7b40a661a63fd9cd57',
 
   'src/third_party/webrtc':
-    Var('webrtc_git') + '/src.git' + '@' + '3208bf102b75e8ec1eaa6640dfa3b545310b1e02',
+    Var('webrtc_git') + '/src.git' + '@' + '92d12707e00837a978485f731d72ef30cf19d2a2',
 
   'src/third_party/libgifcodec':
      Var('skia_git') + '/libgifcodec' + '@'+  Var('libgifcodec_revision'),
@@ -1586,7 +1586,7 @@
       'packages': [
         {
           'package': 'skia/tools/goldctl/windows-amd64',
-          'version': 'MKEUDKNT8DcyLZqnGZ2-o5TvzpNJbgsYtzzVAxVi2v4C',
+          'version': '5CX5n_psRKwMH74v7aAH4AHynDeTitubHLzeWYyCKv8C',
         },
       ],
       'dep_type': 'cipd',
@@ -1610,7 +1610,7 @@
     Var('chromium_git') + '/v8/v8.git' + '@' +  Var('v8_revision'),
 
   'src-internal': {
-    'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@fad3ef3d273a324cd3e09770be97563c3462b342',
+    'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@42ce056bf81b5a190b71589d515cf9c709d9f071',
     'condition': 'checkout_src_internal',
   },
 
@@ -1629,7 +1629,7 @@
     'packages': [
       {
         'package': 'chromeos_internal/apps/help_app/app',
-        'version': 'fR9RLLkXh04N53040QJ6_noXt19SljhJmIsn0YqtatgC',
+        'version': 'fZQVsch8-pFrKQYES9hXWDDG3REcUWuGXwmmVDiDjIgC',
       },
     ],
     'condition': 'checkout_chromeos and checkout_src_internal',
@@ -1640,7 +1640,7 @@
     'packages': [
       {
         'package': 'chromeos_internal/apps/media_app/app',
-        'version': '6OMz7SP6o3Hlhc5lXDZ9CNwQ0qS6QjpXUHbz2m_wBbsC',
+        'version': 'WW6coVuevgcsm8Aew4K1eh2I1colIiYcRhAJmEAgeMAC',
       },
     ],
     'condition': 'checkout_chromeos and checkout_src_internal',
diff --git a/android_webview/browser/aw_content_browser_client.cc b/android_webview/browser/aw_content_browser_client.cc
index 747057e..4866c9b 100644
--- a/android_webview/browser/aw_content_browser_client.cc
+++ b/android_webview/browser/aw_content_browser_client.cc
@@ -841,7 +841,8 @@
         url::kFileScheme,
         content::CreateFileURLLoaderFactory(
             aw_browser_context->GetPath(),
-            aw_browser_context->GetSharedCorsOriginAccessList()));
+            content::BrowserContext::GetSharedCorsOriginAccessList(
+                aw_browser_context)));
   }
 }
 
diff --git a/android_webview/lib/aw_main_delegate.cc b/android_webview/lib/aw_main_delegate.cc
index 0ff656c1b..c5d96dd 100644
--- a/android_webview/lib/aw_main_delegate.cc
+++ b/android_webview/lib/aw_main_delegate.cc
@@ -195,8 +195,6 @@
       features.EnableIfNotSet(autofill::features::kAutofillExtractAllDatalists);
       features.EnableIfNotSet(
           autofill::features::kAutofillSkipComparingInferredLabels);
-      features.DisableIfNotSet(
-          autofill::features::kAutofillRestrictUnownedFieldsToFormlessCheckout);
     }
 
     if (cl->HasSwitch(switches::kWebViewLogJsConsoleMessages)) {
diff --git a/android_webview/renderer/aw_render_frame_ext.cc b/android_webview/renderer/aw_render_frame_ext.cc
index 953b92e..b98fe6e 100644
--- a/android_webview/renderer/aw_render_frame_ext.cc
+++ b/android_webview/renderer/aw_render_frame_ext.cc
@@ -19,7 +19,6 @@
 #include "content/public/renderer/render_view.h"
 #include "third_party/blink/public/common/associated_interfaces/associated_interface_provider.h"
 #include "third_party/blink/public/platform/web_security_origin.h"
-#include "third_party/blink/public/platform/web_size.h"
 #include "third_party/blink/public/web/web_element.h"
 #include "third_party/blink/public/web/web_element_collection.h"
 #include "third_party/blink/public/web/web_frame_widget.h"
@@ -268,7 +267,7 @@
 
   const blink::WebHitTestResult result = webview->HitTestResultForTap(
       gfx::Point(touch_center.x(), touch_center.y()),
-      blink::WebSize(touch_area.width(), touch_area.height()));
+      gfx::Size(touch_area.width(), touch_area.height()));
   auto data = mojom::HitTestData::New();
 
   GURL absolute_image_url = result.AbsoluteImageURL();
diff --git a/ash/login/login_screen_controller.cc b/ash/login/login_screen_controller.cc
index ec1d56b..048a2cf 100644
--- a/ash/login/login_screen_controller.cc
+++ b/ash/login/login_screen_controller.cc
@@ -387,11 +387,13 @@
 }
 
 void LoginScreenController::ShowLockScreen() {
+  CHECK(!LockScreen::HasInstance());
   OnShow();
   LockScreen::Show(LockScreen::ScreenType::kLock);
 }
 
 void LoginScreenController::ShowLoginScreen() {
+  CHECK(!LockScreen::HasInstance());
   // Login screen can only be used during login.
   session_manager::SessionState session_state =
       Shell::Get()->session_controller()->GetSessionState();
@@ -478,6 +480,13 @@
   client_->OnFocusLeavingSystemTray(reverse);
 }
 
+void LoginScreenController::OnLockScreenDestroyed() {
+  DCHECK_EQ(authentication_stage_, AuthenticationStage::kIdle);
+
+  // Still handle it to avoid crashes during Login/Lock/Unlock flows.
+  authentication_stage_ = AuthenticationStage::kIdle;
+}
+
 void LoginScreenController::NotifyLoginScreenShown() {
   if (!client_)
     return;
diff --git a/ash/login/login_screen_controller.h b/ash/login/login_screen_controller.h
index a3cc00c..0c02bd9 100644
--- a/ash/login/login_screen_controller.h
+++ b/ash/login/login_screen_controller.h
@@ -136,6 +136,9 @@
     return authentication_stage_;
   }
 
+  // Called when Login or Lock screen is destroyed.
+  void OnLockScreenDestroyed();
+
   LoginDataDispatcher* data_dispatcher() { return &login_data_dispatcher_; }
 
   void NotifyLoginScreenShown();
diff --git a/ash/login/ui/lock_screen.cc b/ash/login/ui/lock_screen.cc
index 84edc53..c7d2e5e5 100644
--- a/ash/login/ui/lock_screen.cc
+++ b/ash/login/ui/lock_screen.cc
@@ -126,14 +126,7 @@
 }
 
 void LockScreen::Destroy() {
-  LoginScreenController::AuthenticationStage authentication_stage =
-      Shell::Get()->login_screen_controller()->authentication_stage();
-  base::debug::Alias(&authentication_stage);
-  if (Shell::Get()->login_screen_controller()->authentication_stage() !=
-      authentication_stage) {
-    LOG(FATAL) << "Unexpected authentication stage "
-               << static_cast<int>(authentication_stage);
-  }
+  Shell::Get()->login_screen_controller()->OnLockScreenDestroyed();
   CHECK_EQ(instance_, this);
 
   Shell::Get()->login_screen_controller()->data_dispatcher()->RemoveObserver(
diff --git a/ash/multi_user/multi_user_window_manager_impl.cc b/ash/multi_user/multi_user_window_manager_impl.cc
index c5b9b1b3..8270e8dd 100644
--- a/ash/multi_user/multi_user_window_manager_impl.cc
+++ b/ash/multi_user/multi_user_window_manager_impl.cc
@@ -161,7 +161,7 @@
   window_to_entry_[window] = std::move(window_entry_ptr);
 
   // Remember the initial visibility of the window.
-  window_entry->set_show(window->IsVisible());
+  window_entry->set_show(window->TargetVisibility());
 
   // Add observers to track state changes.
   window->AddObserver(this);
diff --git a/ash/system/phonehub/phone_hub_tray.cc b/ash/system/phonehub/phone_hub_tray.cc
index dcd1fc78..3490f55 100644
--- a/ash/system/phonehub/phone_hub_tray.cc
+++ b/ash/system/phonehub/phone_hub_tray.cc
@@ -116,8 +116,11 @@
     return;
   }
 
-  if (content_view_)
+  if (content_view_) {
     bubble_view->RemoveChildView(content_view_);
+    delete content_view_;
+  }
+
   content_view_ = content_view.get();
   bubble_view->AddChildView(std::move(content_view));
 
diff --git a/ash/wm/desks/desk.h b/ash/wm/desks/desk.h
index 1972a47..59a9d0d 100644
--- a/ash/wm/desks/desk.h
+++ b/ash/wm/desks/desk.h
@@ -164,7 +164,8 @@
   void RecordAndResetConsecutiveDailyVisits(bool being_removed);
 
   // Returns the time from base::Time::Now() to Jan 1, 2010 in the local
-  // timezeone in days as an int.
+  // timezeone in days as an int. We use Jan 1, 2010 as an arbitrary epoch
+  // since it is a well-known date in the past.
   int GetDaysFromLocalEpoch() const;
 
   // Overrides the |override_clock_| with |test_clock| for mocking time in
diff --git a/ash/wm/desks/desks_restore_util.cc b/ash/wm/desks/desks_restore_util.cc
index ba7f0dc..7b02f16 100644
--- a/ash/wm/desks/desks_restore_util.cc
+++ b/ash/wm/desks/desks_restore_util.cc
@@ -25,14 +25,15 @@
 
 namespace {
 
-// A key for the dictionaries stored in |kDesksMetricsList|. The entry is an int
-// which represents the number of minutes for
+// |kDesksMetricsList| stores a list of dictionaries with the following
+// key value pairs (<key> : <entry>):
+// |kCreationTimeKey| : an int which represents the number of minutes for
 // base::Time::FromDeltaSinceWindowsEpoch().
+// |kFirstDayVisitedKey| : an int which represents the number of days since
+// local epoch (Jan 1, 2010).
+// |kLastDayVisitedKey| : an int which represents the number of days since
+// local epoch (Jan 1, 2010).
 constexpr char kCreationTimeKey[] = "creation_time";
-
-// Keys for the dictionaries stored in |kDesksMetricsList|. The entries are ints
-// which represent the number of days for
-// base::Time::FromDeltaSinceWindowsEpoch().
 constexpr char kFirstDayVisitedKey[] = "first_day";
 constexpr char kLastDayVisitedKey[] = "last_day";
 
diff --git a/base/allocator/allocator_shim_default_dispatch_to_partition_alloc.cc b/base/allocator/allocator_shim_default_dispatch_to_partition_alloc.cc
index 42ba5ba..afa98fa 100644
--- a/base/allocator/allocator_shim_default_dispatch_to_partition_alloc.cc
+++ b/base/allocator/allocator_shim_default_dispatch_to_partition_alloc.cc
@@ -398,7 +398,7 @@
 
 #if PA_ALLOW_PCSCAN
 void EnablePCScan() {
-  auto& pcscan = internal::PCScan<internal::ThreadSafe>::Instance();
+  auto& pcscan = internal::PCScan::Instance();
   pcscan.RegisterScannableRoot(Allocator());
   if (Allocator() != AlignedAllocator())
     pcscan.RegisterScannableRoot(AlignedAllocator());
diff --git a/base/allocator/partition_allocator/memory_reclaimer.cc b/base/allocator/partition_allocator/memory_reclaimer.cc
index c8f6bbd..3c7daba 100644
--- a/base/allocator/partition_allocator/memory_reclaimer.cc
+++ b/base/allocator/partition_allocator/memory_reclaimer.cc
@@ -130,7 +130,7 @@
   // Lastly decommit empty slot spans and lastly try to discard unused pages at
   // the end of the remaining active slots.
   {
-    using PCScan = internal::PCScan<internal::ThreadSafe>;
+    using PCScan = internal::PCScan;
     const auto invocation_mode = flags & PartitionPurgeAggressiveReclaim
                                      ? PCScan::InvocationMode::kForcedBlocking
                                      : PCScan::InvocationMode::kBlocking;
diff --git a/base/allocator/partition_allocator/page_allocator_internals_fuchsia.h b/base/allocator/partition_allocator/page_allocator_internals_fuchsia.h
index a269c7d..05cfbcf 100644
--- a/base/allocator/partition_allocator/page_allocator_internals_fuchsia.h
+++ b/base/allocator/partition_allocator/page_allocator_internals_fuchsia.h
@@ -150,7 +150,7 @@
     void* address,
     size_t length,
     PageAccessibilityConfiguration accessibility) {
-  zx_status_t status = zx::vmar::root_self()->protect2(
+  zx_status_t status = zx::vmar::root_self()->protect(
       PageAccessibilityToZxVmOptions(accessibility),
       reinterpret_cast<uint64_t>(address), length);
   return status == ZX_OK;
@@ -160,7 +160,7 @@
     void* address,
     size_t length,
     PageAccessibilityConfiguration accessibility) {
-  zx_status_t status = zx::vmar::root_self()->protect2(
+  zx_status_t status = zx::vmar::root_self()->protect(
       PageAccessibilityToZxVmOptions(accessibility),
       reinterpret_cast<uint64_t>(address), length);
   ZX_CHECK(status == ZX_OK, status);
diff --git a/base/allocator/partition_allocator/partition_alloc.cc b/base/allocator/partition_allocator/partition_alloc.cc
index 1c62011..0f293772 100644
--- a/base/allocator/partition_allocator/partition_alloc.cc
+++ b/base/allocator/partition_allocator/partition_alloc.cc
@@ -76,8 +76,7 @@
 #endif  // defined(PA_HAS_64_BITS_POINTERS)
   }
 #endif  // !BUILDFLAG(USE_PARTITION_ALLOC_AS_MALLOC)
-  internal::PCScan<internal::ThreadSafe>::Instance()
-      .ClearRootsForTesting();  // IN-TEST
+  internal::PCScan::Instance().ClearRootsForTesting();  // IN-TEST
   internal::g_oom_handling_function = nullptr;
 }
 
diff --git a/base/allocator/partition_allocator/partition_root.h b/base/allocator/partition_allocator/partition_root.h
index c4610d31..cbdcd99c 100644
--- a/base/allocator/partition_allocator/partition_root.h
+++ b/base/allocator/partition_allocator/partition_root.h
@@ -152,7 +152,7 @@
       internal::PartitionSuperPageExtentEntry<thread_safe>;
   using DirectMapExtent = internal::PartitionDirectMapExtent<thread_safe>;
   using ScopedGuard = internal::ScopedGuard<thread_safe>;
-  using PCScan = internal::PCScan<thread_safe>;
+  using PCScan = internal::PCScan;
 
   // Defines whether objects should be quarantined for this root.
   enum class QuarantineMode : uint8_t {
@@ -842,7 +842,7 @@
   // by default.
   if (UNLIKELY(root->IsQuarantineEnabled()) &&
       LIKELY(!slot_span->bucket->is_direct_mapped())) {
-    PCScan::Instance().MoveToQuarantine(ptr, slot_span);
+    PCScan::Instance().MoveToQuarantine(ptr, slot_span->bucket->slot_size);
     return;
   }
 
diff --git a/base/allocator/partition_allocator/pcscan.cc b/base/allocator/partition_allocator/pcscan.cc
index 6befae35..534842c 100644
--- a/base/allocator/partition_allocator/pcscan.cc
+++ b/base/allocator/partition_allocator/pcscan.cc
@@ -172,12 +172,10 @@
           << ", survival rate: " << static_cast<double>(new_size) / last_size;
 }
 
-template <bool thread_safe>
-ALWAYS_INLINE uintptr_t
-GetObjectStartInSuperPage(uintptr_t maybe_ptr,
-                          const PartitionRoot<thread_safe>& root) {
+ALWAYS_INLINE uintptr_t GetObjectStartInSuperPage(uintptr_t maybe_ptr,
+                                                  const PCScan::Root& root) {
   char* allocation_start =
-      GetSlotStartInSuperPage<thread_safe>(reinterpret_cast<char*>(maybe_ptr));
+      GetSlotStartInSuperPage<ThreadSafe>(reinterpret_cast<char*>(maybe_ptr));
   if (!allocation_start) {
     // |maybe_ptr| refers to a garbage or is outside of the payload region.
     return 0;
@@ -342,7 +340,7 @@
 // Internal singleton that keeps cold data.
 class PCScanInternal final {
  public:
-  using Root = PartitionRoot<ThreadSafe>;
+  using Root = PCScan::Root;
 
   static constexpr size_t kMaxNumberOfRoots = 8u;
   class Roots final : private std::array<Root*, kMaxNumberOfRoots> {
@@ -431,7 +429,7 @@
 #endif
 }
 
-void CommitQuarantineBitmaps(PartitionRoot<ThreadSafe>& root) {
+void CommitQuarantineBitmaps(PCScan::Root& root) {
   size_t quarantine_bitmaps_size_to_commit = CommittedQuarantineBitmapsSize();
   for (auto* super_page_extent = root.first_extent; super_page_extent;
        super_page_extent = super_page_extent->next) {
@@ -493,8 +491,7 @@
 }  // namespace
 
 // This class is responsible for performing the entire PCScan task.
-template <bool thread_safe>
-class PCScan<thread_safe>::PCScanTask final {
+class PCScan::PCScanTask final {
  public:
   static void* operator new(size_t size) {
     return PCScanMetadataAllocator().AllocFlagsNoHooks(0, size);
@@ -507,9 +504,8 @@
   // Creates and initializes a PCScan state.
   explicit PCScanTask(PCScan& pcscan);
 
-  // Only allow moving to make sure that the state is not redundantly copied.
-  PCScanTask(PCScanTask&&) noexcept = default;
-  PCScanTask& operator=(PCScanTask&&) noexcept = default;
+  PCScanTask(PCScanTask&&) noexcept = delete;
+  PCScanTask& operator=(PCScanTask&&) noexcept = delete;
 
   // Execute PCScan. Must be executed only once.
   void RunOnce() &&;
@@ -517,7 +513,7 @@
  private:
   class ScanLoop;
 
-  using SlotSpan = SlotSpanMetadata<thread_safe>;
+  using SlotSpan = SlotSpanMetadata<ThreadSafe>;
 
   struct ScanArea {
     ScanArea(uintptr_t* begin, uintptr_t* end) : begin(begin), end(end) {}
@@ -591,7 +587,7 @@
   // objects.
   size_t SweepQuarantine();
 
-  PCScan<thread_safe>& pcscan_;
+  PCScan& pcscan_;
   // Cache the pcscan epoch to avoid the compiler loading the atomic
   // QuarantineData::epoch_ on each access.
   const size_t pcscan_epoch_;
@@ -603,11 +599,9 @@
   StatsCollector stats_;
 };
 
-template <bool thread_safe>
 template <typename LookupPolicy>
 ALWAYS_INLINE QuarantineBitmap*
-PCScan<thread_safe>::PCScanTask::TryFindScannerBitmapForPointer(
-    uintptr_t maybe_ptr) const {
+PCScan::PCScanTask::TryFindScannerBitmapForPointer(uintptr_t maybe_ptr) const {
   // First, check if |maybe_ptr| points to a valid super page or a quarantined
   // card.
   LookupPolicy lookup{*this};
@@ -633,11 +627,9 @@
 // TryMarkObjectInNormalBucketPool() marks it again in the bitmap and clears
 // from the scanner bitmap. This way, when scanning is done, all uncleared
 // entries in the scanner bitmap correspond to unreachable objects.
-template <bool thread_safe>
 template <typename LookupPolicy>
 ALWAYS_INLINE size_t
-PCScan<thread_safe>::PCScanTask::TryMarkObjectInNormalBucketPool(
-    uintptr_t maybe_ptr) const {
+PCScan::PCScanTask::TryMarkObjectInNormalBucketPool(uintptr_t maybe_ptr) const {
   using AccessType = QuarantineBitmap::AccessType;
   // Check if maybe_ptr points somewhere to the heap.
   auto* scanner_bitmap =
@@ -649,16 +641,15 @@
       Root::FromPointerInNormalBucketPool(reinterpret_cast<char*>(maybe_ptr));
 
   // Check if pointer was in the quarantine bitmap.
-  const uintptr_t base =
-      GetObjectStartInSuperPage<thread_safe>(maybe_ptr, *root);
+  const uintptr_t base = GetObjectStartInSuperPage(maybe_ptr, *root);
   if (!base || !scanner_bitmap->template CheckBit<AccessType::kNonAtomic>(base))
     return 0;
 
   PA_DCHECK((maybe_ptr & kSuperPageBaseMask) == (base & kSuperPageBaseMask));
 
-  auto target_slot_span =
+  auto* target_slot_span =
       SlotSpan::FromSlotInnerPtr(reinterpret_cast<void*>(base));
-  PA_DCHECK(root == PartitionRoot<thread_safe>::FromSlotSpan(target_slot_span));
+  PA_DCHECK(root == Root::FromSlotSpan(target_slot_span));
 
   const size_t usable_size = target_slot_span->GetUsableSize(root);
   // Range check for inner pointers.
@@ -676,9 +667,7 @@
   return target_slot_span->bucket->slot_size;
 }
 
-template <bool thread_safe>
-void PCScan<
-    thread_safe>::PCScanTask::ClearQuarantinedObjectsAndFilterSuperPages() {
+void PCScan::PCScanTask::ClearQuarantinedObjectsAndFilterSuperPages() {
   using AccessType = QuarantineBitmap::AccessType;
 
   StatsCollector::ScannerScope clear_scope(stats_,
@@ -722,8 +711,7 @@
 
 // Class used to perform actual scanning. Dispatches at runtime based on
 // supported SIMD extensions.
-template <bool thread_safe>
-class PCScan<thread_safe>::PCScanTask::ScanLoop final {
+class PCScan::PCScanTask::ScanLoop final {
  public:
   explicit ScanLoop(const PCScanTask& pcscan_task)
       : scan_function_(GetScanFunction()),
@@ -917,8 +905,7 @@
 #endif
 };
 
-template <bool thread_safe>
-size_t PCScan<thread_safe>::PCScanTask::ScanPartitions() {
+size_t PCScan::PCScanTask::ScanPartitions() {
   StatsCollector::ScannerScope scan_scope(stats_,
                                           StatsCollector::ScannerId::kScan);
 
@@ -956,8 +943,7 @@
   return new_quarantine_size;
 }
 
-template <bool thread_safe>
-size_t PCScan<thread_safe>::PCScanTask::SweepQuarantine() {
+size_t PCScan::PCScanTask::SweepQuarantine() {
   using AccessType = QuarantineBitmap::AccessType;
 
   StatsCollector::ScannerScope sweep_scope(stats_,
@@ -996,8 +982,7 @@
   return swept_bytes;
 }
 
-template <bool thread_safe>
-PCScan<thread_safe>::PCScanTask::PCScanTask(PCScan& pcscan)
+PCScan::PCScanTask::PCScanTask(PCScan& pcscan)
     : pcscan_(pcscan),
       pcscan_epoch_(pcscan.quarantine_data_.epoch()),
       stats_(PCScanInternal::Instance().process_name()) {
@@ -1022,28 +1007,27 @@
            super_page != super_page_extent->super_pages_end;
            super_page += kSuperPageSize) {
         // TODO(bikineev): Consider following freelists instead of slot spans.
-        const size_t visited_slot_spans =
-            IterateSlotSpans<thread_safe>(
-                super_page, true /*with_quarantine*/,
-                [this](SlotSpan* slot_span) -> bool {
-                  if (slot_span->is_empty() || slot_span->is_decommitted()) {
-                    return false;
-                  }
-                  auto* payload_begin = static_cast<uintptr_t*>(
-                      SlotSpan::ToSlotSpanStartPtr(slot_span));
-                  size_t provisioned_size = slot_span->GetProvisionedSize();
-                  // Free & decommitted slot spans are skipped.
-                  PA_DCHECK(provisioned_size > 0);
-                  auto* payload_end =
-                      payload_begin + (provisioned_size / sizeof(uintptr_t));
-                  if (slot_span->bucket->slot_size >= kLargeScanAreaThreshold) {
-                    large_scan_areas_.push_back({payload_begin, payload_end,
-                                                 slot_span->bucket->slot_size});
-                  } else {
-                    scan_areas_.push_back({payload_begin, payload_end});
-                  }
-                  return true;
-                });
+        const size_t visited_slot_spans = IterateSlotSpans<ThreadSafe>(
+            super_page, true /*with_quarantine*/,
+            [this](SlotSpan* slot_span) -> bool {
+              if (slot_span->is_empty() || slot_span->is_decommitted()) {
+                return false;
+              }
+              auto* payload_begin = static_cast<uintptr_t*>(
+                  SlotSpan::ToSlotSpanStartPtr(slot_span));
+              size_t provisioned_size = slot_span->GetProvisionedSize();
+              // Free & decommitted slot spans are skipped.
+              PA_DCHECK(provisioned_size > 0);
+              auto* payload_end =
+                  payload_begin + (provisioned_size / sizeof(uintptr_t));
+              if (slot_span->bucket->slot_size >= kLargeScanAreaThreshold) {
+                large_scan_areas_.push_back(
+                    {payload_begin, payload_end, slot_span->bucket->slot_size});
+              } else {
+                scan_areas_.push_back({payload_begin, payload_end});
+              }
+              return true;
+            });
         // If we haven't visited any slot spans, all the slot spans in the
         // super-page are either empty or decommitted. This means that all the
         // objects are freed and there are no quarantined objects.
@@ -1071,8 +1055,7 @@
   }
 }
 
-template <bool thread_safe>
-void PCScan<thread_safe>::PCScanTask::RunOnce() && {
+void PCScan::PCScanTask::RunOnce() && {
   size_t new_quarantine_size = 0;
   size_t swept_bytes = 0;
 
@@ -1103,8 +1086,7 @@
   PA_CHECK(pcscan_.in_progress_.exchange(false, std::memory_order_acq_rel));
 }
 
-template <bool thread_safe>
-class PCScan<thread_safe>::PCScanThread final {
+class PCScan::PCScanThread final {
  public:
   using TaskHandle = std::unique_ptr<PCScanTask>;
 
@@ -1153,17 +1135,14 @@
   TaskHandle posted_task_;
 };
 
-template <bool thread_safe>
-constexpr size_t PCScan<thread_safe>::QuarantineData::kQuarantineSizeMinLimit;
+constexpr size_t PCScan::QuarantineData::kQuarantineSizeMinLimit;
 
-template <bool thread_safe>
-void PCScan<thread_safe>::QuarantineData::ResetAndAdvanceEpoch() {
+void PCScan::QuarantineData::ResetAndAdvanceEpoch() {
   last_size_ = current_size_.exchange(0, std::memory_order_relaxed);
   epoch_.fetch_add(1, std::memory_order_relaxed);
 }
 
-template <bool thread_safe>
-void PCScan<thread_safe>::QuarantineData::GrowLimitIfNeeded(size_t heap_size) {
+void PCScan::QuarantineData::GrowLimitIfNeeded(size_t heap_size) {
   static constexpr double kQuarantineSizeFraction = 0.1;
   // |heap_size| includes the current quarantine size, we intentionally leave
   // some slack till hitting the limit.
@@ -1173,8 +1152,7 @@
       std::memory_order_relaxed);
 }
 
-template <bool thread_safe>
-void PCScan<thread_safe>::PerformScan(InvocationMode invocation_mode) {
+void PCScan::PerformScan(InvocationMode invocation_mode) {
 #if DCHECK_IS_ON()
   const auto& internal = PCScanInternal::Instance();
   const auto& scannable_roots = internal.scannable_roots();
@@ -1207,8 +1185,7 @@
   }
 }
 
-template <bool thread_safe>
-void PCScan<thread_safe>::PerformScanIfNeeded(InvocationMode invocation_mode) {
+void PCScan::PerformScanIfNeeded(InvocationMode invocation_mode) {
   if (!PCScanInternal::Instance().scannable_roots().size())
     return;
   if (invocation_mode == InvocationMode::kForcedBlocking ||
@@ -1216,69 +1193,23 @@
     PerformScan(invocation_mode);
 }
 
-template <bool thread_safe>
-void PCScan<thread_safe>::RegisterScannableRoot(Root* root) {
+void PCScan::RegisterScannableRoot(Root* root) {
   PCScanInternal::Instance().RegisterScannableRoot(root);
 }
 
-template <bool thread_safe>
-void PCScan<thread_safe>::RegisterNonScannableRoot(Root* root) {
+void PCScan::RegisterNonScannableRoot(Root* root) {
   PCScanInternal::Instance().RegisterNonScannableRoot(root);
 }
 
-template <bool thread_safe>
-void PCScan<thread_safe>::SetProcessName(const char* process_name) {
+void PCScan::SetProcessName(const char* process_name) {
   PCScanInternal::Instance().SetProcessName(process_name);
 }
 
-template <bool thread_safe>
-void PCScan<thread_safe>::ClearRootsForTesting() {
+void PCScan::ClearRootsForTesting() {
   PCScanInternal::Instance().ClearRootsForTesting();  // IN-TEST
 }
 
-// TODO(bikineev): Untemplatize the main PCScan class when chromium clang plugin
-// is fixed. To reduce the number of internal templates, explicitly specialize
-// all non-thread safe function members to immediately crash.
-
-// These not-thread-safe classes are never instantiated so just explicitly
-// specialize them to be incomplete.
-template <>
-class PCScan<NotThreadSafe>::PCScanTask;
-template <>
-class PCScan<NotThreadSafe>::PCScanThread;
-
-// These not-thread-safe functions are still instantiated, so make sure they are
-// never called.
-template <>
-void PCScan<NotThreadSafe>::PerformScan(InvocationMode) {
-  PA_CHECK(false);
-}
-template <>
-void PCScan<NotThreadSafe>::PerformScanIfNeeded(InvocationMode) {
-  PA_CHECK(false);
-}
-template <>
-void PCScan<NotThreadSafe>::RegisterScannableRoot(Root*) {
-  PA_CHECK(false);
-}
-template <>
-void PCScan<NotThreadSafe>::RegisterNonScannableRoot(Root*) {
-  PA_CHECK(false);
-}
-template <>
-void PCScan<NotThreadSafe>::SetProcessName(const char*) {
-  PA_CHECK(false);
-}
-template <>
-void PCScan<NotThreadSafe>::ClearRootsForTesting() {
-  PA_CHECK(false);
-}
-
-template <bool thread_safe>
-PCScan<thread_safe> PCScan<thread_safe>::instance_ PA_CONSTINIT;
-
-template class PCScan<ThreadSafe>;
-template class PCScan<NotThreadSafe>;
+PCScan PCScan::instance_ PA_CONSTINIT;
 
 }  // namespace internal
 }  // namespace base
diff --git a/base/allocator/partition_allocator/pcscan.h b/base/allocator/partition_allocator/pcscan.h
index 3250fa6..816643f 100644
--- a/base/allocator/partition_allocator/pcscan.h
+++ b/base/allocator/partition_allocator/pcscan.h
@@ -39,11 +39,10 @@
 // unreachable and therefore can be safely reclaimed.
 //
 // The driver class encapsulates the entire PCScan infrastructure.
-template <bool thread_safe>
 class BASE_EXPORT PCScan final {
  public:
-  using Root = PartitionRoot<thread_safe>;
-  using SlotSpan = SlotSpanMetadata<thread_safe>;
+  using Root = PartitionRoot<ThreadSafe>;
+  using SlotSpan = SlotSpanMetadata<ThreadSafe>;
 
   enum class InvocationMode {
     kBlocking,
@@ -69,7 +68,7 @@
   // quarantined objects.
   void RegisterNonScannableRoot(Root* root);
 
-  ALWAYS_INLINE void MoveToQuarantine(void* ptr, SlotSpan* slot_span);
+  ALWAYS_INLINE void MoveToQuarantine(void* ptr, size_t slot_size);
 
   // Performs scanning only if a certain quarantine threshold was reached.
   void PerformScanIfNeeded(InvocationMode invocation_mode);
@@ -91,6 +90,8 @@
 
   class QuarantineData final {
    public:
+    inline constexpr QuarantineData();
+
     // Account freed bytes. Returns true if limit was reached.
     ALWAYS_INLINE bool Account(size_t bytes);
 
@@ -116,7 +117,7 @@
     size_t last_size_ = 0;
   };
 
-  constexpr PCScan() = default;
+  inline constexpr PCScan();
 
   // Performs scanning unconditionally.
   void PerformScan(InvocationMode invocation_mode);
@@ -128,16 +129,18 @@
   std::atomic<bool> in_progress_{false};
 };
 
-template <bool thread_safe>
-bool PCScan<thread_safe>::QuarantineData::Account(size_t size) {
+// To please Chromium's clang plugin.
+constexpr PCScan::QuarantineData::QuarantineData() = default;
+
+ALWAYS_INLINE bool PCScan::QuarantineData::Account(size_t size) {
   size_t size_before = current_size_.fetch_add(size, std::memory_order_relaxed);
   return size_before + size > size_limit_.load(std::memory_order_relaxed);
 }
 
-template <bool thread_safe>
-ALWAYS_INLINE void PCScan<thread_safe>::MoveToQuarantine(void* ptr,
-                                                         SlotSpan* slot_span) {
-  PA_DCHECK(!slot_span->bucket->is_direct_mapped());
+// To please Chromium's clang plugin.
+constexpr PCScan::PCScan() = default;
+
+ALWAYS_INLINE void PCScan::MoveToQuarantine(void* ptr, size_t slot_size) {
   auto* quarantine = QuarantineBitmapFromPointer(QuarantineBitmapType::kMutator,
                                                  quarantine_data_.epoch(), ptr);
   const bool is_double_freed =
@@ -145,8 +148,7 @@
   if (UNLIKELY(is_double_freed))
     DoubleFreeAttempt();
 
-  const bool is_limit_reached =
-      quarantine_data_.Account(slot_span->bucket->slot_size);
+  const bool is_limit_reached = quarantine_data_.Account(slot_size);
   if (UNLIKELY(is_limit_reached)) {
     // Perform a quick check if another scan is already in progress.
     if (in_progress_.load(std::memory_order_relaxed))
diff --git a/base/allocator/partition_allocator/pcscan_unittest.cc b/base/allocator/partition_allocator/pcscan_unittest.cc
index 78d33654..a71f699 100644
--- a/base/allocator/partition_allocator/pcscan_unittest.cc
+++ b/base/allocator/partition_allocator/pcscan_unittest.cc
@@ -25,7 +25,7 @@
                      PartitionOptions::ThreadCache::kDisabled,
                      PartitionOptions::Quarantine::kAllowed,
                      PartitionOptions::RefCount::kDisabled});
-    PCScan<ThreadSafe>::Instance().RegisterScannableRoot(allocator_.root());
+    PCScan::Instance().RegisterScannableRoot(allocator_.root());
   }
   ~PCScanTest() override {
     allocator_.root()->PurgeMemory(PartitionPurgeDecommitEmptySlotSpans |
@@ -34,14 +34,13 @@
   }
 
   void RunPCScan() {
-    PCScan<true>::Instance().PerformScan(
-        PCScan<ThreadSafe>::InvocationMode::kBlocking);
+    PCScan::Instance().PerformScan(PCScan::InvocationMode::kBlocking);
   }
 
   bool IsInQuarantine(void* ptr) const {
     return QuarantineBitmapFromPointer(
                QuarantineBitmapType::kMutator,
-               PCScan<true>::Instance().quarantine_data_.epoch(), ptr)
+               PCScan::Instance().quarantine_data_.epoch(), ptr)
         ->CheckBit(reinterpret_cast<uintptr_t>(ptr));
   }
 
@@ -322,8 +321,8 @@
                                       PartitionOptions::Quarantine::kAllowed,
                                       PartitionOptions::RefCount::kDisabled});
 
-  PCScan<ThreadSafe>::Instance().RegisterScannableRoot(&source_root);
-  PCScan<ThreadSafe>::Instance().RegisterScannableRoot(&value_root);
+  PCScan::Instance().RegisterScannableRoot(&source_root);
+  PCScan::Instance().RegisterScannableRoot(&value_root);
 
   auto* source = SourceList::Create(source_root);
   auto* value = ValueList::Create(value_root);
@@ -345,8 +344,8 @@
                                       PartitionOptions::Quarantine::kAllowed,
                                       PartitionOptions::RefCount::kDisabled});
 
-  PCScan<ThreadSafe>::Instance().RegisterScannableRoot(&source_root);
-  PCScan<ThreadSafe>::Instance().RegisterNonScannableRoot(&value_root);
+  PCScan::Instance().RegisterScannableRoot(&source_root);
+  PCScan::Instance().RegisterNonScannableRoot(&value_root);
 
   auto* source = SourceList::Create(source_root);
   auto* value = ValueList::Create(value_root);
@@ -370,8 +369,8 @@
        base::PartitionOptions::Quarantine::kAllowed,
        PartitionOptions::RefCount::kDisabled});
 
-  PCScan<ThreadSafe>::Instance().RegisterNonScannableRoot(&source_root);
-  PCScan<ThreadSafe>::Instance().RegisterScannableRoot(&value_root);
+  PCScan::Instance().RegisterNonScannableRoot(&source_root);
+  PCScan::Instance().RegisterScannableRoot(&value_root);
 
   auto* source = SourceList::Create(source_root);
   auto* value = ValueList::Create(value_root);
diff --git a/base/memory/nonscannable_memory.cc b/base/memory/nonscannable_memory.cc
index 60e0ead2..02e8ccc 100644
--- a/base/memory/nonscannable_memory.cc
+++ b/base/memory/nonscannable_memory.cc
@@ -46,7 +46,7 @@
                                     PartitionOptions::ThreadCache::kDisabled,
                                     PartitionOptions::Quarantine::kAllowed,
                                     PartitionOptions::RefCount::kDisabled));
-  auto& pcscan = internal::PCScan<internal::ThreadSafe>::Instance();
+  auto& pcscan = internal::PCScan::Instance();
   pcscan.RegisterNonScannableRoot(allocator_->root());
   pcscan_enabled_.store(true, std::memory_order_release);
 }
diff --git a/base/memory/platform_shared_memory_region_unittest.cc b/base/memory/platform_shared_memory_region_unittest.cc
index 8588f9d..842fde9 100644
--- a/base/memory/platform_shared_memory_region_unittest.cc
+++ b/base/memory/platform_shared_memory_region_unittest.cc
@@ -285,8 +285,8 @@
   return VirtualProtect(addr, len, PAGE_READWRITE, &old_protection);
 #elif defined(OS_FUCHSIA)
   zx_status_t status =
-      zx::vmar::root_self()->protect2(ZX_VM_PERM_READ | ZX_VM_PERM_WRITE,
-                                      reinterpret_cast<uintptr_t>(addr), len);
+      zx::vmar::root_self()->protect(ZX_VM_PERM_READ | ZX_VM_PERM_WRITE,
+                                     reinterpret_cast<uintptr_t>(addr), len);
   return status == ZX_OK;
 #else
   return false;
diff --git a/base/task/sequence_manager/thread_controller_power_monitor.cc b/base/task/sequence_manager/thread_controller_power_monitor.cc
index 29ce8c4..3098a99 100644
--- a/base/task/sequence_manager/thread_controller_power_monitor.cc
+++ b/base/task/sequence_manager/thread_controller_power_monitor.cc
@@ -68,8 +68,9 @@
     return;
   DCHECK(!is_power_suspended_);
 
-  TRACE_EVENT_NESTABLE_ASYNC_BEGIN0("base", "ThreadController::Suspended",
-                                    this);
+  TRACE_EVENT_BEGIN("base", "ThreadController::Suspended",
+                    perfetto::Track(reinterpret_cast<uint64_t>(this),
+                                    perfetto::ThreadTrack::Current()));
   is_power_suspended_ = true;
 }
 
@@ -80,8 +81,9 @@
   // It is possible a suspend was already happening before the observer was
   // added to the power monitor. Ignoring the resume notification in that case.
   if (is_power_suspended_) {
-    TRACE_EVENT_NESTABLE_ASYNC_END0("base", "ThreadController::Suspended",
-                                    this);
+    TRACE_EVENT_END("base" /* ThreadController::Suspended */,
+                    perfetto::Track(reinterpret_cast<uint64_t>(this),
+                                    perfetto::ThreadTrack::Current()));
     is_power_suspended_ = false;
   }
 }
diff --git a/build/android/pylib/base/result_sink.py b/build/android/pylib/base/result_sink.py
index 936e1f3..af436183 100644
--- a/build/android/pylib/base/result_sink.py
+++ b/build/android/pylib/base/result_sink.py
@@ -58,7 +58,8 @@
         'Authorization': 'ResultSink %s' % context['auth_token'],
     }
 
-  def Post(self, test_id, status, test_log, test_file, artifacts=None):
+  def Post(self, test_id, status, duration, test_log, test_file,
+           artifacts=None):
     """Uploads the test result to the ResultSink server.
 
     This assumes that the rdb stream has been called already and that
@@ -67,6 +68,7 @@
     Args:
       test_id: A string representing the test's name.
       status: A string representing if the test passed, failed, etc...
+      duration: An int representing time in ms.
       test_log: A string representing the test's output.
       test_file: A string representing the file location of the test.
       artifacts: An optional dict of artifacts to attach to the test.
@@ -89,6 +91,9 @@
       test_log_formatted = '<pre>' + test_log_escaped + '</pre>'
 
     tr = {
+        # Duration must be formatted to avoid scientific notation in case
+        # number is too small or too large. Result_db takes seconds, not ms.
+        'duration': '%.9fs' % (duration / 1000.0),
         'expected': expected,
         'status': status,
         'summaryHtml': test_log_formatted,
diff --git a/build/android/test_runner.py b/build/android/test_runner.py
index 07c46002..b11ce23 100755
--- a/build/android/test_runner.py
+++ b/build/android/test_runner.py
@@ -982,7 +982,7 @@
             # Some tests put in non utf-8 char as part of the test
             # which breaks uploads, so need to decode and re-encode.
             result_sink_client.Post(
-                r.GetName(), r.GetType(),
+                r.GetName(), r.GetType(), r.GetDuration(),
                 r.GetLog().decode('utf-8', 'replace').encode('utf-8'),
                 test_file_name)
 
diff --git a/build/chromeos/test_runner.py b/build/chromeos/test_runner.py
index 1a496d1..2c18ca6e 100755
--- a/build/chromeos/test_runner.py
+++ b/build/chromeos/test_runner.py
@@ -440,7 +440,8 @@
         # inside as an RDB 'artifact'. (This could include system logs, screen
         # shots, etc.)
         artifacts = self.get_artifacts(test['outDir'])
-        self._rdb_client.Post(test['name'], result, error_log, artifacts)
+        self._rdb_client.Post(test['name'], result, duration_ms, error_log,
+                              artifacts)
 
     if self._rdb_client and self._logs_dir:
       # Attach artifacts from the device that don't apply to a single test.
diff --git a/build/config/android/config.gni b/build/config/android/config.gni
index c4ce2db..85bc8ead 100644
--- a/build/config/android/config.gni
+++ b/build/config/android/config.gni
@@ -248,6 +248,9 @@
 
     # The target to use as the system WebView implementation.
     system_webview_apk_target = "//android_webview:system_webview_apk"
+
+    # Where to write failed expectations for bots to read.
+    expectations_failure_dir = "$root_build_dir/failed_expectations"
   }
 
   # We need a second declare_args block to make sure we are using the overridden
diff --git a/build/config/android/internal_rules.gni b/build/config/android/internal_rules.gni
index 1b2972c..5d77334 100644
--- a/build/config/android/internal_rules.gni
+++ b/build/config/android/internal_rules.gni
@@ -88,9 +88,6 @@
 _desugar_jdk_libs_configuration_jar = "//third_party/android_deps/libs/com_android_tools_desugar_jdk_libs_configuration/desugar_jdk_libs_configuration-1.1.1.jar"
 _desugar_runtime_jar = "$root_build_dir/obj/third_party/bazel/desugar/Desugar_runtime.processed.jar"
 
-# Where to write failed expectations for bots to read.
-_expectations_failure_dir = "$root_build_dir/failed_expectations"
-
 _dexdump_path = "$android_sdk_build_tools/dexdump"
 _dexlayout_path = "//third_party/android_build_tools/art/dexlayout"
 _profman_path = "//third_party/android_build_tools/art/profman"
@@ -1296,7 +1293,7 @@
         ]
         _actual_file = "$target_gen_dir/$target_name.proguard_configs"
         _failure_file =
-            "$_expectations_failure_dir/" +
+            "$expectations_failure_dir/" +
             string_replace(invoker.expected_proguard_config, "/", "_")
         outputs = [
           _actual_file,
@@ -2569,7 +2566,7 @@
       action_with_pydeps(_expectations_target) {
         _actual_file = "${invoker.android_manifest}.normalized"
         _failure_file =
-            "$_expectations_failure_dir/" +
+            "$expectations_failure_dir/" +
             string_replace(invoker.expected_android_manifest, "/", "_")
         inputs = [
           invoker.android_manifest,
@@ -2856,7 +2853,7 @@
       action_with_pydeps(_expectations_target) {
         _actual_file = "$target_gen_dir/$target_name.libs_and_assets"
         _failure_file =
-            "$_expectations_failure_dir/" +
+            "$expectations_failure_dir/" +
             string_replace(invoker.expected_libs_and_assets, "/", "_")
         inputs = [
           invoker.build_config,
@@ -4139,7 +4136,7 @@
     _expectations_target = "${invoker.top_target_name}_validate_libs_and_assets"
     action_with_pydeps(_expectations_target) {
       _actual_file = "$target_gen_dir/$target_name.libs_and_assets"
-      _failure_file = "$_expectations_failure_dir/" +
+      _failure_file = "$expectations_failure_dir/" +
                       string_replace(invoker.expected_libs_and_assets, "/", "_")
       inputs = [
         invoker.expected_libs_and_assets,
diff --git a/build/config/mac/symbols.gni b/build/config/mac/symbols.gni
deleted file mode 100644
index 1d1f260..0000000
--- a/build/config/mac/symbols.gni
+++ /dev/null
@@ -1,9 +0,0 @@
-# Copyright 2016 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-# This file is there to allow moving //build/config/{mac => apple}/symbols.gni
-# without breaking third-party repositories that uses the old path. It will be
-# removed once those other repositories have been patched to use the new path.
-
-import("//build/config/apple/symbols.gni")
diff --git a/build/fuchsia/linux.sdk.sha1 b/build/fuchsia/linux.sdk.sha1
index b8c2d3c..fcc2e2d 100644
--- a/build/fuchsia/linux.sdk.sha1
+++ b/build/fuchsia/linux.sdk.sha1
@@ -1 +1 @@
-3.20210309.0.1
+3.20210309.2.1
diff --git a/build/fuchsia/mac.sdk.sha1 b/build/fuchsia/mac.sdk.sha1
index b8c2d3c..aca25bd 100644
--- a/build/fuchsia/mac.sdk.sha1
+++ b/build/fuchsia/mac.sdk.sha1
@@ -1 +1 @@
-3.20210309.0.1
+3.20210309.1.1
diff --git a/chrome/android/BUILD.gn b/chrome/android/BUILD.gn
index 4657766..39a1e344 100644
--- a/chrome/android/BUILD.gn
+++ b/chrome/android/BUILD.gn
@@ -576,6 +576,7 @@
     "//chrome/browser/notifications/scheduler/public:jni_enums",
     "//chrome/browser/supervised_user/supervised_user_error_page:enums_srcjar",
     "//components/autofill_assistant/browser:autofill_assistant_enums_java",
+    "//components/autofill_assistant/browser:autofill_assistant_intent_strings_java",
     "//components/browsing_data/core:browsing_data_utils_java",
     "//components/browsing_data/core:clear_browsing_data_tab_java",
     "//components/data_reduction_proxy/core/browser:data_reduction_proxy_savings_cleared_enum_java",
diff --git a/chrome/android/chrome_java_resources.gni b/chrome/android/chrome_java_resources.gni
index 3b86286..7b624d60f 100644
--- a/chrome/android/chrome_java_resources.gni
+++ b/chrome/android/chrome_java_resources.gni
@@ -616,6 +616,7 @@
   "java/res/drawable/ic_photo_camera_black.xml",
   "java/res/drawable/ic_reading_list_folder.xml",
   "java/res/drawable/ic_settings_black.xml",
+  "java/res/drawable/ic_share_small.xml",
   "java/res/drawable/ic_signal_cellular_0_bar.xml",
   "java/res/drawable/ic_signal_cellular_1_bar.xml",
   "java/res/drawable/ic_signal_cellular_2_bar.xml",
@@ -882,6 +883,7 @@
   "java/res/menu/custom_tabs_menu.xml",
   "java/res/menu/history_manager_menu.xml",
   "java/res/menu/main_menu.xml",
+  "java/res/menu/main_menu_regroup.xml",
   "java/res/menu/password_entry_viewer_action_bar_menu.xml",
   "java/res/menu/prefeditor_editor_menu.xml",
   "java/res/menu/save_password_preferences_action_bar_menu.xml",
diff --git a/chrome/android/chrome_java_sources.gni b/chrome/android/chrome_java_sources.gni
index 479e7c5..394ee199 100644
--- a/chrome/android/chrome_java_sources.gni
+++ b/chrome/android/chrome_java_sources.gni
@@ -1454,7 +1454,10 @@
   "java/src/org/chromium/chrome/browser/webauth/Fido2ApiHandler.java",
   "java/src/org/chromium/chrome/browser/webauth/Fido2CredentialRequest.java",
   "java/src/org/chromium/chrome/browser/webauth/Fido2Helper.java",
-  "java/src/org/chromium/chrome/browser/webauth/HandlerResponseCallback.java",
+  "java/src/org/chromium/chrome/browser/webauth/FidoErrorResponseCallback.java",
+  "java/src/org/chromium/chrome/browser/webauth/GetAssertionResponseCallback.java",
+  "java/src/org/chromium/chrome/browser/webauth/IsUvpaaResponseCallback.java",
+  "java/src/org/chromium/chrome/browser/webauth/MakeCredentialResponseCallback.java",
   "java/src/org/chromium/chrome/browser/webauth/authenticator/CableAuthenticatorActivity.java",
   "java/src/org/chromium/chrome/browser/webshare/ShareServiceImplementationFactory.java",
 ]
diff --git a/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantModuleEntryImpl.java b/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantModuleEntryImpl.java
index 8a8dcbe..ee75d95 100644
--- a/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantModuleEntryImpl.java
+++ b/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantModuleEntryImpl.java
@@ -129,8 +129,9 @@
             Context context, @NonNull WebContents webContents, boolean isChromeCustomTab,
             @NonNull String initialUrl, Map<String, String> parameters, String experimentIds,
             @Nullable String callerAccount, @Nullable String userName) {
+        String intent = parameters.get(BaseOnboardingCoordinator.INTENT_IDENTFIER);
         if (!AutofillAssistantPreferencesUtil.getShowOnboarding()) {
-            AutofillAssistantMetrics.recordOnBoarding(OnBoarding.OB_NOT_SHOWN);
+            AutofillAssistantMetrics.recordOnBoarding(OnBoarding.OB_NOT_SHOWN, intent);
             AutofillAssistantClient.fromWebContents(webContents)
                     .start(initialUrl, parameters, experimentIds, callerAccount, userName,
                             isChromeCustomTab, /* onboardingCoordinator= */ null);
@@ -147,20 +148,21 @@
         onboardingCoordinator.show(result -> {
             switch (result) {
                 case AssistantOnboardingResult.DISMISSED:
-                    AutofillAssistantMetrics.recordOnBoarding(OnBoarding.OB_NO_ANSWER);
+                    AutofillAssistantMetrics.recordOnBoarding(OnBoarding.OB_NO_ANSWER, intent);
                     AutofillAssistantMetrics.recordDropOut(
-                            DropOutReason.ONBOARDING_BACK_BUTTON_CLICKED);
+                            DropOutReason.ONBOARDING_BACK_BUTTON_CLICKED, intent);
                     break;
                 case AssistantOnboardingResult.REJECTED:
-                    AutofillAssistantMetrics.recordOnBoarding(OnBoarding.OB_CANCELLED);
-                    AutofillAssistantMetrics.recordDropOut(DropOutReason.DECLINED);
+                    AutofillAssistantMetrics.recordOnBoarding(OnBoarding.OB_CANCELLED, intent);
+                    AutofillAssistantMetrics.recordDropOut(DropOutReason.DECLINED, intent);
                     break;
                 case AssistantOnboardingResult.NAVIGATION:
-                    AutofillAssistantMetrics.recordOnBoarding(OnBoarding.OB_NO_ANSWER);
-                    AutofillAssistantMetrics.recordDropOut(DropOutReason.ONBOARDING_NAVIGATION);
+                    AutofillAssistantMetrics.recordOnBoarding(OnBoarding.OB_NO_ANSWER, intent);
+                    AutofillAssistantMetrics.recordDropOut(
+                            DropOutReason.ONBOARDING_NAVIGATION, intent);
                     break;
                 case AssistantOnboardingResult.ACCEPTED:
-                    AutofillAssistantMetrics.recordOnBoarding(OnBoarding.OB_ACCEPTED);
+                    AutofillAssistantMetrics.recordOnBoarding(OnBoarding.OB_ACCEPTED, intent);
                     break;
             }
             AutofillAssistantClient.onOnboardingUiChange(webContents, /* shown= */ false);
diff --git a/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/onboarding/BaseOnboardingCoordinator.java b/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/onboarding/BaseOnboardingCoordinator.java
index 906b5dee..520e536f 100644
--- a/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/onboarding/BaseOnboardingCoordinator.java
+++ b/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/onboarding/BaseOnboardingCoordinator.java
@@ -42,7 +42,7 @@
  */
 @JNINamespace("autofill_assistant")
 public abstract class BaseOnboardingCoordinator implements OnboardingView {
-    private static final String INTENT_IDENTFIER = "INTENT";
+    public static final String INTENT_IDENTFIER = "INTENT";
     private static final String FETCH_TIMEOUT_IDENTIFIER = "ONBOARDING_FETCH_TIMEOUT_MS";
     private static final String BUY_MOVIE_TICKETS_INTENT = "BUY_MOVIE_TICKET";
     private static final String RENT_CAR_INTENT = "RENT_CAR";
@@ -102,7 +102,8 @@
      * events.
      */
     public void show(Callback<Integer> callback) {
-        AutofillAssistantMetrics.recordOnBoarding(OnBoarding.OB_SHOWN);
+        AutofillAssistantMetrics.recordOnBoarding(
+                OnBoarding.OB_SHOWN, mParameters.get(INTENT_IDENTFIER));
         mOnboardingShown = true;
 
         initViewImpl(callback);
diff --git a/chrome/android/features/autofill_assistant/public/java/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantFacade.java b/chrome/android/features/autofill_assistant/public/java/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantFacade.java
index d6276cc..e94e0d2 100644
--- a/chrome/android/features/autofill_assistant/public/java/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantFacade.java
+++ b/chrome/android/features/autofill_assistant/public/java/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantFacade.java
@@ -111,8 +111,9 @@
             }
         }
 
+        String intent = arguments.getParameters().get("INTENT");
         // Have an "attempted starts" baseline for the drop out histogram.
-        AutofillAssistantMetrics.recordDropOut(DropOutReason.AA_START);
+        AutofillAssistantMetrics.recordDropOut(DropOutReason.AA_START, intent);
         waitForTabWithWebContents(activity, tab -> {
             if (arguments.containsTriggerScript()) {
                 // Create a field trial and assign experiment arm based on script parameter. This
@@ -142,7 +143,8 @@
             if (AutofillAssistantModuleEntryProvider.INSTANCE.getModuleEntryIfInstalled() == null) {
                 AutofillAssistantModuleEntryProvider.INSTANCE.getModuleEntry(tab, (moduleEntry) -> {
                     if (moduleEntry == null || activity.isActivityFinishingOrDestroyed()) {
-                        AutofillAssistantMetrics.recordDropOut(DropOutReason.DFM_INSTALL_FAILED);
+                        AutofillAssistantMetrics.recordDropOut(
+                                DropOutReason.DFM_INSTALL_FAILED, intent);
                         if (arguments.containsTriggerScript()) {
                             AutofillAssistantMetrics.recordLiteScriptFinished(tab.getWebContents(),
                                     LiteScriptStarted.LITE_SCRIPT_DFM_UNAVAILABLE);
diff --git a/chrome/android/features/autofill_assistant/public/java/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantMetrics.java b/chrome/android/features/autofill_assistant/public/java/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantMetrics.java
index 28196ad..1a8c68a 100644
--- a/chrome/android/features/autofill_assistant/public/java/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantMetrics.java
+++ b/chrome/android/features/autofill_assistant/public/java/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantMetrics.java
@@ -12,6 +12,7 @@
 import org.chromium.chrome.browser.autofill_assistant.metrics.LiteScriptFinishedState;
 import org.chromium.chrome.browser.autofill_assistant.metrics.LiteScriptStarted;
 import org.chromium.chrome.browser.autofill_assistant.metrics.OnBoarding;
+import org.chromium.chrome.browser.autofill_assistant.strings.IntentStrings;
 import org.chromium.chrome.browser.metrics.UkmRecorder;
 import org.chromium.content_public.browser.WebContents;
 
@@ -25,7 +26,13 @@
     /**
      * Records the reason for a drop out.
      */
-    public static void recordDropOut(@DropOutReason int reason) {
+    public static void recordDropOut(@DropOutReason int reason, String intent) {
+        String histogramSuffix = getHistogramSuffixForIntent(intent);
+
+        RecordHistogram.recordEnumeratedHistogram(
+                "Android.AutofillAssistant.DropOutReason." + histogramSuffix, reason,
+                DropOutReason.MAX_VALUE + 1);
+
         RecordHistogram.recordEnumeratedHistogram(
                 "Android.AutofillAssistant.DropOutReason", reason, DropOutReason.MAX_VALUE + 1);
     }
@@ -33,7 +40,13 @@
     /**
      * Records the onboarding related action.
      */
-    public static void recordOnBoarding(@OnBoarding int metric) {
+    public static void recordOnBoarding(@OnBoarding int metric, String intent) {
+        String histogramSuffix = getHistogramSuffixForIntent(intent);
+
+        RecordHistogram.recordEnumeratedHistogram(
+                "Android.AutofillAssistant.OnBoarding." + histogramSuffix, metric,
+                OnBoarding.MAX_VALUE + 1);
+
         RecordHistogram.recordEnumeratedHistogram(
                 "Android.AutofillAssistant.OnBoarding", metric, OnBoarding.MAX_VALUE + 1);
     }
@@ -50,9 +63,10 @@
     /**
      * UKM metric. Records the start of a lite script.
      *
-     * The events recorded by this call lacks a trigger type. This is appropriate when the trigger
-     * type is not yet known, because the Trigger protos sent by the server have not been processed
-     * yet. If trigger protos are available, record the metric from C++.
+     * The events recorded by this call lacks a trigger type. This is appropriate
+     * when the trigger type is not yet known, because the Trigger protos sent by
+     * the server have not been processed yet. If trigger protos are available,
+     * record the metric from C++.
      */
     public static void recordLiteScriptStarted(
             WebContents webContents, @LiteScriptStarted int started) {
@@ -68,9 +82,10 @@
     /**
      * UKM metric. Records the finish of a lite script.
      *
-     * The events recorded by this call lacks a trigger type. This is appropriate when the trigger
-     * type is not yet known, because the Trigger protos sent by the server have not been processed
-     * yet. If trigger protos are available, record the metric from C++.
+     * The events recorded by this call lacks a trigger type. This is appropriate
+     * when the trigger type is not yet known, because the Trigger protos sent by
+     * the server have not been processed yet. If trigger protos are available,
+     * record the metric from C++.
      */
     public static void recordLiteScriptFinished(
             WebContents webContents, @LiteScriptFinishedState int finishedState) {
@@ -84,10 +99,43 @@
     }
 
     /**
-     * Returns whether {@code webContents} are non-null and valid. Invalid webContents will cause a
-     * failed DCHECK when attempting to report UKM metrics.
+     * Returns whether {@code webContents} are non-null and valid. Invalid
+     * webContents will cause a failed DCHECK when attempting to report UKM metrics.
      */
     private static boolean areWebContentsValid(@Nullable WebContents webContents) {
         return webContents != null && !webContents.isDestroyed();
     }
+
+    /**
+     * Returns histogram suffix for given intent.
+     */
+    private static String getHistogramSuffixForIntent(String intent) {
+        if (intent == null) {
+            // Intent is not set.
+            return "NotSet";
+        }
+        switch (intent) {
+            case IntentStrings.BUY_MOVIE_TICKET:
+                return "BuyMovieTicket";
+            case IntentStrings.FLIGHTS_CHECKIN:
+                return "FlightsCheckin";
+            case IntentStrings.FOOD_ORDERING:
+                return "FoodOrdering";
+            case IntentStrings.FOOD_ORDERING_DELIVERY:
+                return "FoodOrderingDelivery";
+            case IntentStrings.FOOD_ORDERING_PICKUP:
+                return "FoodOrderingPickup";
+            case IntentStrings.PASSWORD_CHANGE:
+                return "PasswordChange";
+            case IntentStrings.RENT_CAR:
+                return "RentCar";
+            case IntentStrings.SHOPPING:
+                return "Shopping";
+            case IntentStrings.SHOPPING_ASSISTED_CHECKOUT:
+                return "ShoppingAssistedCheckout";
+            case IntentStrings.TELEPORT:
+                return "Teleport";
+        }
+        return "UnknownIntent";
+    }
 }
diff --git a/chrome/android/features/start_surface/internal/javatests/src/org/chromium/chrome/features/start_surface/InstantStartTest.java b/chrome/android/features/start_surface/internal/javatests/src/org/chromium/chrome/features/start_surface/InstantStartTest.java
index e07f8fc..31549a2 100644
--- a/chrome/android/features/start_surface/internal/javatests/src/org/chromium/chrome/features/start_surface/InstantStartTest.java
+++ b/chrome/android/features/start_surface/internal/javatests/src/org/chromium/chrome/features/start_surface/InstantStartTest.java
@@ -44,6 +44,7 @@
 import android.view.ViewGroup;
 import android.widget.ImageView;
 
+import androidx.annotation.Nullable;
 import androidx.recyclerview.widget.RecyclerView;
 import androidx.test.espresso.UiController;
 import androidx.test.espresso.ViewAction;
@@ -274,25 +275,37 @@
     }
 
     /**
-     * Create all the files so that tab models can be restored
+     * Create all the files so that tab models can be restored.
      * @param tabIds all the Tab IDs in the normal tab model.
      */
     public static void createTabStateFile(int[] tabIds) throws IOException {
-        createTabStateFile(tabIds, 0);
+        createTabStateFile(tabIds, null, 0);
     }
 
     /**
-     * Create all the files so that tab models can be restored
+     * Create all the files so that tab models can be restored.
      * @param tabIds all the Tab IDs in the normal tab model.
+     * @param urls all of the URLs in the normal tab model.
+     */
+    static void createTabStateFile(int[] tabIds, @Nullable String[] urls) throws IOException {
+        createTabStateFile(tabIds, urls, 0);
+    }
+
+    /**
+     * Create all the files so that tab models can be restored.
+     * @param tabIds all the Tab IDs in the normal tab model.
+     * @param urls all of the URLs in the normal tab model.
      * @param selectedIndex the selected index of normal tab model.
      */
-    public static void createTabStateFile(int[] tabIds, int selectedIndex) throws IOException {
+    public static void createTabStateFile(int[] tabIds, @Nullable String[] urls, int selectedIndex)
+            throws IOException {
         TabModelMetadata normalInfo = new TabModelMetadata(selectedIndex);
-        for (int tabId : tabIds) {
-            normalInfo.ids.add(tabId);
-            normalInfo.urls.add("");
+        for (int i = 0; i < tabIds.length; i++) {
+            normalInfo.ids.add(tabIds[i]);
+            String url = urls != null ? urls[i] : "about:blank";
+            normalInfo.urls.add(url);
 
-            saveTabState(tabId, false);
+            saveTabState(tabIds[i], false);
         }
         TabModelMetadata incognitoInfo = new TabModelMetadata(0);
 
@@ -744,8 +757,7 @@
             "/hide_switch_when_no_incognito_tabs/true" +
             "/show_last_active_tab_only/true"})
     @ParameterAnnotations.UseMethodParameter(FeedParams.class)
-    public void renderSingleAsHomepage_SingleTabNoMVTiles(boolean isFeedV2)
-        throws IOException, InterruptedException {
+    public void renderSingleAsHomepage_SingleTabNoMVTiles(boolean isFeedV2) throws IOException {
         // clang-format on
         setFeedVersion(isFeedV2);
 
@@ -1289,6 +1301,30 @@
                 mActivityTestRule.getActivity().getTabModelSelector().getCurrentModel().getCount());
     }
 
+    @Test
+    @MediumTest
+    @Restriction({UiRestriction.RESTRICTION_TYPE_PHONE})
+    // clang-format off
+    @EnableFeatures({ChromeFeatureList.TAB_SWITCHER_ON_RETURN + "<Study,",
+            ChromeFeatureList.START_SURFACE_ANDROID + "<Study"})
+    @CommandLineFlags.Add({ChromeSwitches.DISABLE_NATIVE_INITIALIZATION,
+            "force-fieldtrials=Study/Group",
+            IMMEDIATE_RETURN_PARAMS + "/start_surface_variation/single"})
+    public void doNotRestoreEmptyTabs() throws IOException {
+        // clang-format on
+        createTabStateFile(new int[] {0, 1}, new String[] {"", "about:blank"});
+        createThumbnailBitmapAndWriteToFile(0);
+        createThumbnailBitmapAndWriteToFile(1);
+        TabAttributeCache.setTitleForTesting(0, "");
+        TabAttributeCache.setTitleForTesting(0, "Google");
+
+        startMainActivityFromLauncher();
+        CriteriaHelper.pollUiThread(
+                () -> mActivityTestRule.getActivity().getLayoutManager().overviewVisible());
+        ViewUtils.onViewWaiting(withId(R.id.tab_list_view));
+        Assert.assertEquals(1, PseudoTab.getAllPseudoTabsFromStateFile().size());
+    }
+
     /**
      * Toggles the header and checks whether the header has the right status.
      *
diff --git a/chrome/android/features/start_surface/internal/javatests/src/org/chromium/chrome/features/start_surface/StartSurfaceTest.java b/chrome/android/features/start_surface/internal/javatests/src/org/chromium/chrome/features/start_surface/StartSurfaceTest.java
index a69d664..b789bbc3 100644
--- a/chrome/android/features/start_surface/internal/javatests/src/org/chromium/chrome/features/start_surface/StartSurfaceTest.java
+++ b/chrome/android/features/start_surface/internal/javatests/src/org/chromium/chrome/features/start_surface/StartSurfaceTest.java
@@ -1890,6 +1890,7 @@
     // clang-format off
     @CommandLineFlags.Add({BASE_PARAMS + "/single/exclude_mv_tiles/false"
             + "/new_home_surface_from_home_button/hide_mv_tiles_and_tab_switcher"})
+    @DisabledTest(message = "Failing/flaky on several bots, see crbug.com/1186218")
     public void testNewSurfaceFromHomeButton(){
         // clang-format on
         assumeTrue(mImmediateReturn);
diff --git a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/pseudotab/PseudoTab.java b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/pseudotab/PseudoTab.java
index a2edb6d..2ba0660 100644
--- a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/pseudotab/PseudoTab.java
+++ b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/pseudotab/PseudoTab.java
@@ -5,6 +5,7 @@
 package org.chromium.chrome.browser.tasks.pseudotab;
 
 import android.os.SystemClock;
+import android.text.TextUtils;
 
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
@@ -351,6 +352,9 @@
                         if (ReturnToChromeExperimentsUtil.isCanonicalizedNTPUrl(url)
                                 && !isStandardActiveIndex) {
                             return;
+                        } else if (TextUtils.isEmpty(url)) {
+                            // Skip restoring of empty Tabs.
+                            return;
                         }
                         PseudoTab tab = PseudoTab.fromTabId(id);
                         if (isStandardActiveIndex) {
diff --git a/chrome/android/java/res/drawable/ic_share_small.xml b/chrome/android/java/res/drawable/ic_share_small.xml
new file mode 100644
index 0000000..e8d14fd
--- /dev/null
+++ b/chrome/android/java/res/drawable/ic_share_small.xml
@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright 2020 The Chromium Authors. All rights reserved.
+     Use of this source code is governed by a BSD-style license that can be
+     found in the LICENSE file. -->
+
+<vector
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+    <path
+        android:pathData="M 16.5 15.733 C 15.867 15.733 15.3 15.983 14.867 16.375 L 8.925 12.917 C 8.967 12.725 9 12.533 9 12.333 C 9 12.133 8.967 11.942 8.925 11.75 L 14.8 8.325 C 15.25 8.742 15.842 9 16.5 9 C 17.883 9 19 7.883 19 6.5 C 19 5.117 17.883 4 16.5 4 C 15.117 4 14 5.117 14 6.5 C 14 6.7 14.033 6.892 14.075 7.083 L 8.2 10.508 C 7.75 10.092 7.158 9.833 6.5 9.833 C 5.117 9.833 4 10.95 4 12.333 C 4 13.717 5.117 14.833 6.5 14.833 C 7.158 14.833 7.75 14.575 8.2 14.158 L 14.133 17.625 C 14.092 17.8 14.067 17.983 14.067 18.167 C 14.067 19.508 15.158 20.6 16.5 20.6 C 17.842 20.6 18.933 19.508 18.933 18.167 C 18.933 16.825 17.842 15.733 16.5 15.733 Z"
+        android:fillColor="@color/default_icon_color"
+        android:strokeWidth="1"/>
+</vector>
\ No newline at end of file
diff --git a/chrome/android/java/res/menu/main_menu.xml b/chrome/android/java/res/menu/main_menu.xml
index 9917c59..69632c9 100644
--- a/chrome/android/java/res/menu/main_menu.xml
+++ b/chrome/android/java/res/menu/main_menu.xml
@@ -3,6 +3,13 @@
      Use of this source code is governed by a BSD-style license that can be
      found in the LICENSE file. -->
 
+<!-- We are working on redesigning menu (crbug.com/1109095), and the icons in
+     here are experimental. If you want to add a new menu item, you need to
+     update both main_menu.xml and main_menu_regroup.xml. If you want to add
+     a new menu item which always shows an icon even not in redesigned menu,
+     please also update AppMenuPropertiesDelegateImpl#prepareCommonMenuItems
+     to keep the icon, like reader_mode_prefs_id.  -->
+
 <!-- TODO(crbug.com/1119550): explore replacing with programatically created
      menu.  -->
 
@@ -38,76 +45,30 @@
         <item android:id="@+id/update_menu_id"
             android:title="@string/menu_update"
             android:icon="@drawable/menu_update" />
+        <item android:id="@+id/move_to_other_window_menu_id"
+            android:title="@string/menu_move_to_other_window"
+            android:icon="@drawable/ic_open_in_browser" />
         <item android:id="@+id/new_tab_menu_id"
             android:title="@string/menu_new_tab"
             android:icon="@drawable/ic_add_box_rounded_corner" />
         <item android:id="@+id/new_incognito_tab_menu_id"
             android:title="@string/menu_new_incognito_tab"
             android:icon="@drawable/incognito_simple" />
-        <item android:id="@+id/move_to_other_window_menu_id"
-            android:title="@string/menu_move_to_other_window"
-            android:icon="@drawable/ic_open_in_browser" />
-        <item android:id="@+id/divider_line_id"
-            android:title="@null" />
-        <item android:id="@+id/open_history_menu_id"
-            android:title="@string/menu_history"
-            android:icon="@drawable/ic_history_googblue_24dp" />
-        <item android:id="@+id/downloads_row_menu_id"
-            android:title="@null">
-          <menu>
-                <item android:id="@+id/downloads_menu_id"
-                    android:title="@string/menu_downloads"
-                    android:icon="@drawable/infobar_download_complete" />
-                <item android:id="@+id/offline_page_chip_id"
-                    android:title="@string/menu_download"
-                    android:icon="@drawable/ic_file_download_white_24dp" />
-          </menu>
-        </item>
-        <item android:id="@+id/all_bookmarks_row_menu_id"
-            android:title="@null">
-          <menu>
-                <item android:id="@+id/all_bookmarks_menu_id"
-                    android:title="@string/menu_bookmarks"
-                    android:icon="@drawable/btn_star_filled" />
-                <item android:id="@+id/bookmark_this_page_chip_id"
-                    android:title="@string/menu_bookmark"
-                    android:icon="@drawable/btn_star" />
-          </menu>
-        </item>
+        <item android:id="@+id/all_bookmarks_menu_id"
+            android:title="@string/menu_bookmarks"
+            android:icon="@drawable/btn_star_filled" />
         <item android:id="@+id/recent_tabs_menu_id"
             android:title="@string/menu_recent_tabs"
             android:icon="@drawable/devices_black_24dp" />
-        <item android:id="@+id/add_to_divider_line_id"
-            android:title="@null" />
-        <item android:id="@+id/add_to_menu_id"
-            android:title="@string/menu_add_to"
-            android:icon="@drawable/ic_add" >
-          <menu>
-                <item android:id="@+id/add_to_bookmarks_menu_id"
-                    android:title="@string/menu_bookmarks"
-                    android:icon="@drawable/btn_star" />
-                <item android:id="@+id/add_to_reading_list_menu_id"
-                    android:title="@string/reading_list_title"
-                    android:icon="@drawable/ic_reading_list_folder" />
-                <item android:id="@+id/add_to_downloads_menu_id"
-                    android:title="@string/menu_downloads"
-                    android:icon="@drawable/ic_file_download_white_24dp" />
-                <item android:id="@+id/add_to_homescreen_menu_id"
-                    android:title="@string/menu_homescreen"
-                    android:icon="@drawable/ic_add_to_home_screen" />
-          </menu>
-        </item>
-        <!-- Duplicating add_to_homescreen/install_app/open_webapk is for
-             the purpose of experiment, one of them will be removed once the
-             experiments are done. -->
-        <item android:id="@+id/install_app_id"
-            android:title="@string/menu_add_to_homescreen"
-            android:icon="@drawable/ic_add_to_home_screen" />
-        <item android:id="@+id/menu_open_webapk_id"
-            android:title="@string/menu_open_webapk"
-            android:icon="@drawable/ic_add_to_home_screen" />
-        <item android:id="@id/divider_line_id"
-            android:title="@null" />
+        <item android:id="@+id/open_history_menu_id"
+            android:title="@string/menu_history"
+            android:icon="@drawable/ic_history_googblue_24dp" />
+        <item android:id="@+id/downloads_menu_id"
+            android:title="@string/menu_downloads"
+            android:icon="@drawable/infobar_download_complete" />
+        <item android:id="@+id/translate_id"
+            android:title="@string/menu_translate"
+            android:icon="@drawable/ic_translate" />
         <item android:id="@+id/share_row_menu_id"
             android:title="@null">
           <menu>
@@ -121,12 +82,15 @@
         <item android:id="@+id/feed_follow_id"
             android:title="@string/menu_follow"
             android:icon="@drawable/ic_add"/>
+        <item android:id="@+id/get_image_descriptions_id"
+            android:title="@string/menu_get_image_descriptions"
+            android:icon="@drawable/ic_image_descriptions"/>
+        <item android:id="@+id/paint_preview_show_id"
+            android:title="@string/menu_paint_preview_show"
+            android:icon="@drawable/ic_photo_camera" />
         <item android:id="@+id/find_in_page_id"
             android:title="@string/menu_find_in_page"
             android:icon="@drawable/ic_find_in_page" />
-        <item android:id="@+id/translate_id"
-            android:title="@string/menu_translate"
-            android:icon="@drawable/ic_translate" />
         <item android:id="@+id/add_to_homescreen_id"
             android:title="@string/menu_add_to_homescreen"
             android:icon="@drawable/ic_add_to_home_screen" />
@@ -144,14 +108,6 @@
                 android:checkable="true" />
           </menu>
         </item>
-        <item android:id="@+id/paint_preview_show_id"
-            android:title="@string/menu_paint_preview_show"
-            android:icon="@drawable/ic_photo_camera" />
-        <item android:id="@+id/get_image_descriptions_id"
-            android:title="@string/menu_get_image_descriptions"
-            android:icon="@drawable/ic_image_descriptions"/>
-        <item android:id="@id/divider_line_id"
-            android:title="@null" />
         <item android:id="@+id/reader_mode_prefs_id"
             android:title="@string/menu_reader_mode_prefs"
             android:icon="@drawable/reader_mode_prefs_icon" />
@@ -203,22 +159,18 @@
         <item android:id="@id/new_incognito_tab_menu_id"
             android:title="@string/menu_new_incognito_tab"
             android:icon="@drawable/incognito_simple" />
-        <item android:id="@id/divider_line_id"
-            android:title="@null" />
-        <item android:id="@id/open_history_menu_id"
-            android:title="@string/menu_history"
-            android:icon="@drawable/ic_history_googblue_24dp" />
-        <item android:id="@id/downloads_menu_id"
-            android:title="@string/menu_downloads"
-            android:icon="@drawable/infobar_download_complete" />
         <item android:id="@id/all_bookmarks_menu_id"
             android:title="@string/menu_bookmarks"
             android:icon="@drawable/btn_star_filled" />
         <item android:id="@id/recent_tabs_menu_id"
             android:title="@string/menu_recent_tabs"
             android:icon="@drawable/devices_black_24dp" />
-        <item android:id="@id/divider_line_id"
-            android:title="@null" />
+        <item android:id="@id/open_history_menu_id"
+            android:title="@string/menu_history"
+            android:icon="@drawable/ic_history_googblue_24dp" />
+        <item android:id="@id/downloads_menu_id"
+            android:title="@string/menu_downloads"
+            android:icon="@drawable/infobar_download_complete" />
         <item android:id="@id/close_all_tabs_menu_id"
             android:title="@string/menu_close_all_tabs"
             android:icon="@drawable/btn_close_white" />
diff --git a/chrome/android/java/res/menu/main_menu_regroup.xml b/chrome/android/java/res/menu/main_menu_regroup.xml
new file mode 100644
index 0000000..737b73d
--- /dev/null
+++ b/chrome/android/java/res/menu/main_menu_regroup.xml
@@ -0,0 +1,270 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright 2015 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. -->
+
+<!-- We are working on redesigning menu (crbug.com/1109095), and the icons in
+     here are experimental. If you want to add a new menu item, you need to
+     update both main_menu.xml and main_menu_regroup.xml. If you want to add
+     a new menu item which always shows an icon even not in redesigned menu,
+     please also update AppMenuPropertiesDelegateImpl#prepareCommonMenuItems
+     to keep the icon, like reader_mode_prefs_id.  -->
+
+<!-- TODO(crbug.com/1119550): explore replacing with programatically created
+     menu.  -->
+
+<menu xmlns:android="http://schemas.android.com/apk/res/android">
+    <!-- These menu items are common to tablet and phone. -->
+    <group android:id="@+id/PAGE_MENU"
+        android:visible="false">
+        <item android:id="@+id/icon_row_menu_id"
+            android:title="@null">
+            <menu>
+              <item android:id="@+id/backward_menu_id"
+                android:title="@string/accessibility_toolbar_btn_back"
+                android:titleCondensed="@string/back"
+                android:icon="@drawable/btn_back"/>
+              <item android:id="@+id/forward_menu_id"
+                android:title="@string/accessibility_menu_forward"
+                android:titleCondensed="@string/menu_forward"
+                android:icon="@drawable/btn_forward"/>
+              <item android:id="@+id/bookmark_this_page_id"
+                android:title="@string/accessibility_menu_bookmark"
+                android:titleCondensed="@string/menu_bookmark"
+                android:icon="@drawable/btn_star"/>
+              <item android:id="@+id/offline_page_id"
+                android:title="@string/download_page"
+                android:titleCondensed="@string/menu_download"
+                android:icon="@drawable/ic_file_download_white_24dp"/>
+              <item android:id="@+id/share_menu_button_id"
+                android:title="@string/share"
+                android:titleCondensed="@string/share"
+                android:icon="@drawable/ic_share_small" />
+              <item android:id="@+id/info_menu_id"
+                android:title="@string/accessibility_menu_info"
+                android:titleCondensed="@string/menu_page_info"
+                android:icon="@drawable/btn_info" />
+              <item android:id="@+id/reload_menu_id"
+                android:title="@string/accessibility_btn_refresh"
+                android:titleCondensed="@string/menu_refresh"
+                android:icon="@drawable/btn_reload_stop"/>
+            </menu>
+        </item>
+        <item android:id="@+id/update_menu_id"
+            android:title="@string/menu_update"
+            android:icon="@drawable/menu_update" />
+        <item android:id="@+id/new_tab_menu_id"
+            android:title="@string/menu_new_tab"
+            android:icon="@drawable/ic_add_box_rounded_corner" />
+        <item android:id="@+id/new_incognito_tab_menu_id"
+            android:title="@string/menu_new_incognito_tab"
+            android:icon="@drawable/incognito_simple" />
+        <item android:id="@+id/move_to_other_window_menu_id"
+            android:title="@string/menu_move_to_other_window"
+            android:icon="@drawable/ic_open_in_browser" />
+        <item android:id="@+id/divider_line_id"
+            android:title="@null" />
+        <item android:id="@+id/open_history_menu_id"
+            android:title="@string/menu_history"
+            android:icon="@drawable/ic_history_googblue_24dp" />
+        <item android:id="@+id/downloads_row_menu_id"
+            android:title="@null">
+          <menu>
+                <item android:id="@+id/downloads_menu_id"
+                    android:title="@string/menu_downloads"
+                    android:icon="@drawable/infobar_download_complete" />
+                <item android:id="@+id/offline_page_chip_id"
+                    android:title="@string/menu_download"
+                    android:icon="@drawable/ic_file_download_white_24dp" />
+          </menu>
+        </item>
+        <item android:id="@+id/all_bookmarks_row_menu_id"
+            android:title="@null">
+          <menu>
+                <item android:id="@+id/all_bookmarks_menu_id"
+                    android:title="@string/menu_bookmarks"
+                    android:icon="@drawable/btn_star_filled" />
+                <item android:id="@+id/bookmark_this_page_chip_id"
+                    android:title="@string/menu_bookmark"
+                    android:icon="@drawable/btn_star" />
+          </menu>
+        </item>
+        <item android:id="@+id/recent_tabs_menu_id"
+            android:title="@string/menu_recent_tabs"
+            android:icon="@drawable/devices_black_24dp" />
+        <item android:id="@+id/add_to_divider_line_id"
+            android:title="@null" />
+        <item android:id="@+id/add_to_menu_id"
+            android:title="@string/menu_add_to"
+            android:icon="@drawable/ic_add" >
+          <menu>
+                <item android:id="@+id/add_to_bookmarks_menu_id"
+                    android:title="@string/menu_bookmarks"
+                    android:icon="@drawable/btn_star" />
+                <item android:id="@+id/add_to_reading_list_menu_id"
+                    android:title="@string/reading_list_title"
+                    android:icon="@drawable/ic_reading_list_folder" />
+                <item android:id="@+id/add_to_downloads_menu_id"
+                    android:title="@string/menu_downloads"
+                    android:icon="@drawable/ic_file_download_white_24dp" />
+                <item android:id="@+id/add_to_homescreen_menu_id"
+                    android:title="@string/menu_homescreen"
+                    android:icon="@drawable/ic_add_to_home_screen" />
+          </menu>
+        </item>
+        <!-- Duplicating add_to_homescreen/install_app/open_webapk is for
+             the purpose of experiment, one of them will be removed once the
+             experiments are done. -->
+        <item android:id="@+id/install_app_id"
+            android:title="@string/menu_add_to_homescreen"
+            android:icon="@drawable/ic_add_to_home_screen" />
+        <item android:id="@+id/menu_open_webapk_id"
+            android:title="@string/menu_open_webapk"
+            android:icon="@drawable/ic_add_to_home_screen" />
+        <item android:id="@id/divider_line_id"
+            android:title="@null" />
+        <item android:id="@+id/share_row_menu_id"
+            android:title="@null">
+          <menu>
+              <item android:id="@+id/share_menu_id"
+                android:title="@string/menu_share_page"
+                android:icon="@drawable/ic_share_white_24dp" />
+              <item android:id="@+id/direct_share_menu_id"
+                android:title="@null" />
+          </menu>
+        </item>
+        <item android:id="@+id/feed_follow_id"
+            android:title="@string/menu_follow"
+            android:icon="@drawable/ic_add"/>
+        <item android:id="@+id/find_in_page_id"
+            android:title="@string/menu_find_in_page"
+            android:icon="@drawable/ic_find_in_page" />
+        <item android:id="@+id/translate_id"
+            android:title="@string/menu_translate"
+            android:icon="@drawable/ic_translate" />
+        <item android:id="@+id/add_to_homescreen_id"
+            android:title="@string/menu_add_to_homescreen"
+            android:icon="@drawable/ic_add_to_home_screen" />
+        <item android:id="@+id/open_webapk_id"
+            android:title="@string/menu_open_webapk"
+            android:icon="@drawable/ic_add_to_home_screen" />
+        <item android:id="@+id/request_desktop_site_row_menu_id"
+            android:title="@null">
+          <menu>
+              <item android:id="@+id/request_desktop_site_id"
+                android:title="@string/menu_request_desktop_site"
+                android:icon="@drawable/ic_desktop_windows" />
+              <item android:id="@+id/request_desktop_site_check_id"
+                android:title="@null"
+                android:checkable="true" />
+          </menu>
+        </item>
+        <item android:id="@+id/paint_preview_show_id"
+            android:title="@string/menu_paint_preview_show"
+            android:icon="@drawable/ic_photo_camera" />
+        <item android:id="@+id/get_image_descriptions_id"
+            android:title="@string/menu_get_image_descriptions"
+            android:icon="@drawable/ic_image_descriptions"/>
+        <item android:id="@id/divider_line_id"
+            android:title="@null" />
+        <item android:id="@+id/reader_mode_prefs_id"
+            android:title="@string/menu_reader_mode_prefs"
+            android:icon="@drawable/reader_mode_prefs_icon" />
+        <item android:id="@+id/preferences_id"
+            android:title="@string/menu_settings"
+            android:icon="@drawable/settings_cog" />
+        <item android:id="@+id/info_id"
+            android:title="@string/menu_page_info"
+            android:icon="@drawable/btn_info" />
+        <item android:id="@+id/help_id"
+            android:title="@string/menu_help"
+            android:icon="@drawable/help_outline" />
+        <item android:id="@+id/enter_vr_id"
+            android:title="@string/enter_vr"
+            android:icon="@drawable/vr_headset" />
+        <item android:id="@+id/managed_by_menu_id"
+            android:title="@string/managed" />
+    </group>
+
+    <!-- Items shown only in the tab switcher -->
+    <group android:id="@+id/OVERVIEW_MODE_MENU"
+        android:visible="false">
+        <item android:id="@id/new_tab_menu_id"
+            android:title="@string/menu_new_tab"
+            android:icon="@drawable/ic_add_box_rounded_corner" />
+        <item android:id="@id/new_incognito_tab_menu_id"
+            android:title="@string/menu_new_incognito_tab"
+            android:icon="@drawable/incognito_simple" />
+        <item android:id="@+id/close_all_tabs_menu_id"
+            android:title="@string/menu_close_all_tabs"
+            android:icon="@drawable/btn_close_white" />
+        <item android:id="@+id/close_all_incognito_tabs_menu_id"
+            android:title="@string/menu_close_all_incognito_tabs"
+            android:icon="@drawable/btn_close_white" />
+        <item android:id="@+id/menu_group_tabs"
+            android:title="@string/menu_group_tabs"
+            android:icon="@drawable/ic_widgets" />
+        <item android:id="@+id/track_prices_row_menu_id"
+            android:title="@string/menu_track_prices"
+            android:icon="@drawable/ic_trending_down_black" />
+        <item android:id="@id/preferences_id"
+            android:title="@string/menu_settings"
+            android:icon="@drawable/settings_cog" />
+    </group>
+
+    <!-- Items shown only in the tab switcher when start surface is enabled -->
+    <group android:id="@+id/START_SURFACE_MODE_MENU"
+        android:visible="false">
+        <item android:id="@id/new_tab_menu_id"
+            android:title="@string/menu_new_tab"
+            android:icon="@drawable/ic_add_box_rounded_corner" />
+        <item android:id="@id/new_incognito_tab_menu_id"
+            android:title="@string/menu_new_incognito_tab"
+            android:icon="@drawable/incognito_simple" />
+        <item android:id="@id/divider_line_id"
+            android:title="@null" />
+        <item android:id="@id/open_history_menu_id"
+            android:title="@string/menu_history"
+            android:icon="@drawable/ic_history_googblue_24dp" />
+        <item android:id="@id/downloads_menu_id"
+            android:title="@string/menu_downloads"
+            android:icon="@drawable/infobar_download_complete" />
+        <item android:id="@id/all_bookmarks_menu_id"
+            android:title="@string/menu_bookmarks"
+            android:icon="@drawable/btn_star_filled" />
+        <item android:id="@id/recent_tabs_menu_id"
+            android:title="@string/menu_recent_tabs"
+            android:icon="@drawable/devices_black_24dp" />
+        <item android:id="@id/divider_line_id"
+            android:title="@null" />
+        <item android:id="@id/close_all_tabs_menu_id"
+            android:title="@string/menu_close_all_tabs"
+            android:icon="@drawable/btn_close_white" />
+        <item android:id="@id/close_all_incognito_tabs_menu_id"
+            android:title="@string/menu_close_all_incognito_tabs"
+            android:icon="@drawable/btn_close_white" />
+        <item android:id="@id/menu_group_tabs"
+            android:title="@string/menu_group_tabs"
+            android:icon="@drawable/ic_widgets" />
+        <item android:id="@id/track_prices_row_menu_id"
+            android:title="@string/menu_track_prices"
+            android:icon="@drawable/ic_trending_down_black" />
+        <item android:id="@id/preferences_id"
+            android:title="@string/menu_settings"
+            android:icon="@drawable/settings_cog" />
+    </group>
+
+    <!-- Items shown only when the tablet has no visible tabs -->
+    <group android:id="@+id/TABLET_EMPTY_MODE_MENU"
+        android:visible="false">
+        <item android:id="@id/new_tab_menu_id"
+            android:title="@string/menu_new_tab"
+            android:icon="@drawable/ic_add_box_rounded_corner" />
+        <item android:id="@id/new_incognito_tab_menu_id"
+            android:title="@string/menu_new_incognito_tab"
+            android:icon="@drawable/incognito_simple" />
+        <item android:id="@id/preferences_id"
+            android:title="@string/menu_settings"
+            android:icon="@drawable/settings_cog" />
+    </group>
+</menu>
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/app/ChromeActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/app/ChromeActivity.java
index 6b1d748..86b21b3e 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/app/ChromeActivity.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/app/ChromeActivity.java
@@ -2168,12 +2168,13 @@
             if (handler.handleMenuOrKeyboardAction(id, fromMenu)) return true;
         }
 
+        @BrowserProfileType
+        int type = Profile.getBrowserProfileTypeFromProfile(getCurrentTabModel().getProfile());
+
         if (id == R.id.preferences_id) {
             SettingsLauncher settingsLauncher = new SettingsLauncherImpl();
             settingsLauncher.launchSettingsActivity(this);
             RecordUserAction.record("MobileMenuSettings");
-            @BrowserProfileType
-            int type = Profile.getBrowserProfileTypeFromProfile(getCurrentTabModel().getProfile());
             RecordHistogram.recordEnumeratedHistogram(
                     "Settings.OpenSettingsFromMenu.PerProfileType", type,
                     BrowserProfileType.MAX_VALUE + 1);
@@ -2206,6 +2207,8 @@
             RecordUserAction.record("MobileMenuHistory");
             HistoryManagerUtils.showHistoryManager(
                     this, currentTab, getTabModelSelector().isIncognitoSelected());
+            RecordHistogram.recordEnumeratedHistogram("Android.OpenHistoryFromMenu.PerProfileType",
+                    type, BrowserProfileType.MAX_VALUE + 1);
             return true;
         }
 
@@ -2214,6 +2217,15 @@
             return false;
         }
 
+        if (id == R.id.backward_menu_id) {
+            if (currentTab.canGoBack()) {
+                currentTab.goBack();
+                RecordUserAction.record("MobileMenuBackward");
+                return true;
+            }
+            return false;
+        }
+
         if (id == R.id.forward_menu_id) {
             if (currentTab.canGoForward()) {
                 currentTab.goForward();
@@ -2257,7 +2269,7 @@
             return true;
         }
 
-        if (id == R.id.info_menu_id) {
+        if (id == R.id.info_menu_id || id == R.id.info_id) {
             WebContents webContents = currentTab.getWebContents();
             PageInfoController.show(this, webContents, null,
                     PageInfoController.OpenedFromSource.MENU,
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/app/appmenu/AppMenuPropertiesDelegateImpl.java b/chrome/android/java/src/org/chromium/chrome/browser/app/appmenu/AppMenuPropertiesDelegateImpl.java
index 2ee7c152..3ddad50d 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/app/appmenu/AppMenuPropertiesDelegateImpl.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/app/appmenu/AppMenuPropertiesDelegateImpl.java
@@ -85,6 +85,9 @@
  * items based on activity state.
  */
 public class AppMenuPropertiesDelegateImpl implements AppMenuPropertiesDelegate {
+    public static final StringCachedFieldTrialParameter ACTION_BAR_VARIATION =
+            new StringCachedFieldTrialParameter(
+                    ChromeFeatureList.TABBED_APP_OVERFLOW_MENU_REGROUP, "action_bar", "");
     public static final StringCachedFieldTrialParameter THREE_BUTTON_ACTION_BAR_VARIATION =
             new StringCachedFieldTrialParameter(
                     ChromeFeatureList.TABBED_APP_OVERFLOW_MENU_THREE_BUTTON_ACTIONBAR,
@@ -129,6 +132,13 @@
         int TABLET_EMPTY_MODE_MENU = 3;
     }
 
+    @IntDef({ActionBarType.STANDARD, ActionBarType.BACKWARD_BUTTON, ActionBarType.SHARE_BUTTON})
+    @interface ActionBarType {
+        int STANDARD = 0;
+        int BACKWARD_BUTTON = 1;
+        int SHARE_BUTTON = 2;
+    }
+
     @IntDef({ThreeButtonActionBarType.DISABLED, ThreeButtonActionBarType.ACTION_CHIP_VIEW,
             ThreeButtonActionBarType.DESTINATION_CHIP_VIEW, ThreeButtonActionBarType.ADD_TO_OPTION})
     @interface ThreeButtonActionBarType {
@@ -215,6 +225,9 @@
 
     @Override
     public int getAppMenuLayoutId() {
+        if (shouldShowRegroupedMenu() || shouldShowThreeButtonActionBar()) {
+            return R.menu.main_menu_regroup;
+        }
         return R.menu.main_menu;
     }
 
@@ -308,6 +321,17 @@
         if (shouldShowIconRow) {
             SubMenu actionBar = menu.findItem(R.id.icon_row_menu_id).getSubMenu();
 
+            @ActionBarType
+            int actionBarType = getActionBarType();
+            MenuItem backwardMenuItem = actionBar.findItem(R.id.backward_menu_id);
+            if (backwardMenuItem != null) {
+                if (actionBarType == ActionBarType.BACKWARD_BUTTON) {
+                    backwardMenuItem.setEnabled(currentTab.canGoBack());
+                } else {
+                    actionBar.removeItem(R.id.backward_menu_id);
+                }
+            }
+
             // Disable the "Forward" menu item if there is no page to go to.
             MenuItem forwardMenuItem = actionBar.findItem(R.id.forward_menu_id);
             forwardMenuItem.setEnabled(currentTab.canGoForward());
@@ -336,6 +360,19 @@
                 }
             }
 
+            MenuItem shareMenuItem = actionBar.findItem(R.id.share_menu_button_id);
+            if (shareMenuItem != null) {
+                if (shouldShowShareInMenu()) {
+                    actionBar.removeItem(R.id.share_menu_button_id);
+                } else {
+                    shareMenuItem.setEnabled(mShareUtils.shouldEnableShare(currentTab));
+                }
+            }
+
+            if (shouldShowInfoInMenu()) {
+                actionBar.removeItem(R.id.info_menu_id);
+            }
+
             if (shouldShowThreeButtonActionBar()) {
                 assert actionBar.size() == 3;
             } else {
@@ -437,7 +474,8 @@
         }
 
         // Don't allow either "chrome://" pages or interstitial pages to be shared.
-        menu.findItem(R.id.share_row_menu_id).setVisible(mShareUtils.shouldEnableShare(currentTab));
+        menu.findItem(R.id.share_row_menu_id)
+                .setVisible(mShareUtils.shouldEnableShare(currentTab) && shouldShowShareInMenu());
 
         ShareHelper.configureDirectShareMenuItem(
                 mContext, menu.findItem(R.id.direct_share_menu_id));
@@ -504,6 +542,11 @@
         // Only display reader mode settings menu option if the current page is in reader mode.
         menu.findItem(R.id.reader_mode_prefs_id).setVisible(shouldShowReaderModePrefs(currentTab));
 
+        MenuItem infoMenuItem = menu.findItem(R.id.info_id);
+        if (infoMenuItem != null) {
+            infoMenuItem.setVisible(shouldShowInfoInMenu());
+        }
+
         // Only display the Enter VR button if VR Shell Dev environment is enabled.
         menu.findItem(R.id.enter_vr_id).setVisible(shouldShowEnterVr());
 
@@ -947,11 +990,37 @@
         sItemBookmarkedForTesting = bookmarked;
     }
 
+    private boolean shouldShowRegroupedMenu() {
+        return CachedFeatureFlags.isEnabled(ChromeFeatureList.TABBED_APP_OVERFLOW_MENU_REGROUP);
+    }
+
     private static boolean shouldShowThreeButtonActionBar() {
         return CachedFeatureFlags.isEnabled(
                 ChromeFeatureList.TABBED_APP_OVERFLOW_MENU_THREE_BUTTON_ACTIONBAR);
     }
 
+    private boolean shouldShowShareInMenu() {
+        return getActionBarType() != ActionBarType.SHARE_BUTTON;
+    }
+
+    private boolean shouldShowInfoInMenu() {
+        return getActionBarType() != ActionBarType.STANDARD;
+    }
+
+    /**
+     * @return The type of action bar should be shown.
+     */
+    private @ActionBarType int getActionBarType() {
+        if (shouldShowRegroupedMenu()) {
+            if (ACTION_BAR_VARIATION.getValue().equals("backward_button")) {
+                return ActionBarType.BACKWARD_BUTTON;
+            } else if (ACTION_BAR_VARIATION.getValue().equals("share_button")) {
+                return ActionBarType.SHARE_BUTTON;
+            }
+        }
+        return ActionBarType.STANDARD;
+    }
+
     /**
      * @return The type of three button action bar should be shown.
      */
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/app/flags/ChromeCachedFlags.java b/chrome/android/java/src/org/chromium/chrome/browser/app/flags/ChromeCachedFlags.java
index 724377d..b2b0deb 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/app/flags/ChromeCachedFlags.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/app/flags/ChromeCachedFlags.java
@@ -81,6 +81,8 @@
                 ChromeFeatureList.TAB_GROUPS_ANDROID,
                 ChromeFeatureList.TAB_GROUPS_CONTINUATION_ANDROID,
                 ChromeFeatureList.TAB_TO_GTS_ANIMATION,
+                ChromeFeatureList.TABBED_APP_OVERFLOW_MENU_ICONS,
+                ChromeFeatureList.TABBED_APP_OVERFLOW_MENU_REGROUP,
                 ChromeFeatureList.TABBED_APP_OVERFLOW_MENU_THREE_BUTTON_ACTIONBAR,
                 ChromeFeatureList.THEME_REFACTOR_ANDROID,
                 ChromeFeatureList.TOOLBAR_USE_HARDWARE_BITMAP_DRAW,
@@ -94,6 +96,7 @@
         // clang-format off
         List<CachedFieldTrialParameter> fieldTrialsToCache = Arrays.asList(
                 AdaptiveToolbarFeatures.MODE_PARAM,
+                AppMenuPropertiesDelegateImpl.ACTION_BAR_VARIATION,
                 AppMenuPropertiesDelegateImpl.THREE_BUTTON_ACTION_BAR_VARIATION,
                 ConditionalTabStripUtils.CONDITIONAL_TAB_STRIP_INFOBAR_LIMIT,
                 ConditionalTabStripUtils.CONDITIONAL_TAB_STRIP_INFOBAR_PERIOD,
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/notifications/CustomNotificationBuilder.java b/chrome/android/java/src/org/chromium/chrome/browser/notifications/CustomNotificationBuilder.java
index faba1b3b..fa063a0 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/notifications/CustomNotificationBuilder.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/notifications/CustomNotificationBuilder.java
@@ -129,13 +129,9 @@
         addActionButtons(bigView);
         configureSettingsButton(bigView);
 
-        // Note: under the hood this is not a NotificationCompat builder so be mindful of the
-        // API level of methods you call on the builder.
-        // TODO(crbug.com/697104) We should probably use a Compat builder.
         NotificationWrapperBuilder builder =
                 NotificationWrapperBuilderFactory.createNotificationWrapperBuilder(
-                        false /* preferCompat */, mChannelId, mRemotePackageForBuilderContext,
-                        metadata);
+                        shouldUseCompat(), mChannelId, mRemotePackageForBuilderContext, metadata);
         builder.setTicker(mTickerText);
         builder.setContentIntent(mContentIntent);
         builder.setDeleteIntent(mDeleteIntent);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/notifications/NotificationBuilderBase.java b/chrome/android/java/src/org/chromium/chrome/browser/notifications/NotificationBuilderBase.java
index cd1c2bea..2c2d6ea 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/notifications/NotificationBuilderBase.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/notifications/NotificationBuilderBase.java
@@ -6,7 +6,7 @@
 
 import android.annotation.TargetApi;
 import android.app.Notification;
-import android.app.RemoteInput;
+import android.app.PendingIntent;
 import android.content.Context;
 import android.content.res.Resources;
 import android.graphics.Bitmap;
@@ -21,6 +21,8 @@
 import androidx.annotation.IntDef;
 import androidx.annotation.Nullable;
 import androidx.annotation.VisibleForTesting;
+import androidx.core.app.NotificationCompat;
+import androidx.core.graphics.drawable.IconCompat;
 
 import org.chromium.chrome.browser.flags.ChromeFeatureList;
 import org.chromium.components.browser_ui.notifications.NotificationMetadata;
@@ -478,10 +480,9 @@
      * on the lockscreen, displaying just the site origin and badge or generated icon.
      */
     protected Notification createPublicNotification(Context context) {
-        // Use a non-compat builder because we want the default small icon behaviour.
         NotificationWrapperBuilder builder =
                 NotificationWrapperBuilderFactory
-                        .createNotificationWrapperBuilder(false /* preferCompat */, mChannelId)
+                        .createNotificationWrapperBuilder(shouldUseCompat(), mChannelId)
                         .setContentText(context.getString(
                                 org.chromium.chrome.R.string.notification_hidden_text))
                         .setSmallIcon(org.chromium.chrome.R.drawable.ic_chrome);
@@ -522,6 +523,12 @@
         return input;
     }
 
+    @VisibleForTesting(otherwise = VisibleForTesting.PROTECTED)
+    static boolean shouldUseCompat() {
+        // TODO(crbug.com/697104): Enable this via a flag.
+        return false;
+    }
+
     /**
      * Sets the small icon on {@code builder} using a {@code Bitmap} if a non-null bitmap is
      * provided and the API level is high enough, otherwise the resource id is used.
@@ -567,13 +574,42 @@
      * Adds an action to {@code builder} using a {@code Bitmap} if a bitmap is provided and the API
      * level is high enough, otherwise a resource id is used.
      */
-    @SuppressWarnings("deprecation") // For addAction(int, CharSequence, PendingIntent)
     protected static void addActionToBuilder(NotificationWrapperBuilder builder, Action action) {
-        Notification.Action.Builder actionBuilder = getActionBuilder(action);
+        if (shouldUseCompat()) {
+            addActionToBuilderCompat(builder, action);
+        } else {
+            addActionToBuilderStandard(builder, action);
+        }
+    }
+
+    @SuppressWarnings("deprecation") // For addAction(Notification.Action)
+    private static void addActionToBuilderStandard(
+            NotificationWrapperBuilder builder, Action action) {
+        Notification.Action.Builder actionBuilder = getActionBuilderStandard(action);
         if (action.type == Action.Type.TEXT) {
             assert action.placeholder != null;
             actionBuilder.addRemoteInput(
-                    new RemoteInput.Builder(NotificationConstants.KEY_TEXT_REPLY)
+                    new android.app.RemoteInput.Builder(NotificationConstants.KEY_TEXT_REPLY)
+                            .setLabel(action.placeholder)
+                            .build());
+        }
+
+        if (action.umaActionType == NotificationUmaTracker.ActionType.UNKNOWN) {
+            builder.addAction(actionBuilder.build());
+        } else {
+            builder.addAction(
+                    actionBuilder.build(), action.intent.getFlags(), action.umaActionType);
+        }
+    }
+
+    @SuppressWarnings("deprecation") // For addAction(NotificationCompat.Action)
+    private static void addActionToBuilderCompat(
+            NotificationWrapperBuilder builder, Action action) {
+        NotificationCompat.Action.Builder actionBuilder = getActionBuilderCompat(action);
+        if (action.type == Action.Type.TEXT) {
+            assert action.placeholder != null;
+            actionBuilder.addRemoteInput(
+                    new androidx.core.app.RemoteInput.Builder(NotificationConstants.KEY_TEXT_REPLY)
                             .setLabel(action.placeholder)
                             .build());
         }
@@ -600,19 +636,22 @@
         // all Chrome notifications on N though (see crbug.com/674015).
     }
 
-    @SuppressWarnings("deprecation") // For Builder(int, CharSequence, PendingIntent)
-    private static Notification.Action.Builder getActionBuilder(Action action) {
-        Notification.Action.Builder actionBuilder;
+    private static Notification.Action.Builder getActionBuilderStandard(Action action) {
+        PendingIntent intent = action.intent.getPendingIntent();
         if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && action.iconBitmap != null) {
-            // Icon was added in Android M.
             Icon icon = Icon.createWithBitmap(action.iconBitmap);
-            actionBuilder = new Notification.Action.Builder(
-                    icon, action.title, action.intent.getPendingIntent());
-        } else {
-            actionBuilder = new Notification.Action.Builder(
-                    action.iconId, action.title, action.intent.getPendingIntent());
+            return new Notification.Action.Builder(icon, action.title, intent);
         }
-        return actionBuilder;
+        return new Notification.Action.Builder(action.iconId, action.title, intent);
+    }
+
+    private static NotificationCompat.Action.Builder getActionBuilderCompat(Action action) {
+        PendingIntent intent = action.intent.getPendingIntent();
+        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && action.iconBitmap != null) {
+            IconCompat icon = IconCompat.createWithBitmap(action.iconBitmap);
+            return new NotificationCompat.Action.Builder(icon, action.title, intent);
+        }
+        return new NotificationCompat.Action.Builder(action.iconId, action.title, intent);
     }
 
     /**
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/notifications/StandardNotificationBuilder.java b/chrome/android/java/src/org/chromium/chrome/browser/notifications/StandardNotificationBuilder.java
index dcd025f..2673af1 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/notifications/StandardNotificationBuilder.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/notifications/StandardNotificationBuilder.java
@@ -23,13 +23,9 @@
 
     @Override
     public NotificationWrapper build(NotificationMetadata metadata) {
-        // Note: this is not a NotificationCompat builder so be mindful of the
-        // API level of methods you call on the builder.
-        // TODO(crbug.com/697104) We should probably use a Compat builder.
         NotificationWrapperBuilder builder =
                 NotificationWrapperBuilderFactory.createNotificationWrapperBuilder(
-                        false /* preferCompat */, mChannelId, mRemotePackageForBuilderContext,
-                        metadata);
+                        shouldUseCompat(), mChannelId, mRemotePackageForBuilderContext, metadata);
 
         builder.setContentTitle(mTitle);
         builder.setContentText(mBody);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/status/StatusCoordinator.java b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/status/StatusCoordinator.java
index c84ffe8..f0f5b53 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/status/StatusCoordinator.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/status/StatusCoordinator.java
@@ -76,13 +76,23 @@
 
         PropertyModelChangeProcessor.create(mModel, mStatusView, new StatusViewBinder());
 
+        Runnable forceModelViewReconciliationRunnable = () -> {
+            final View securityIconView = getSecurityIconView();
+            mStatusView.setStatusIconAlpha(mModel.get(StatusProperties.STATUS_ICON_ALPHA));
+            securityIconView.setVisibility(mModel.get(StatusProperties.STATUS_ICON_ALPHA) > 0
+                                    && mModel.get(StatusProperties.SHOW_STATUS_ICON)
+                            ? View.VISIBLE
+                            : View.GONE);
+        };
+
         PageInfoIPHController pageInfoIPHController = new PageInfoIPHController(
                 ContextUtils.activityFromContext(mStatusView.getContext()), getSecurityIconView());
 
         mMediator = new StatusMediator(mModel, mStatusView.getResources(), mStatusView.getContext(),
-                urlBarEditingTextStateProvider, isTablet, locationBarDataProvider,
-                PermissionDialogController.getInstance(), searchEngineLogoUtils,
-                templateUrlServiceSupplier, profileSupplier, pageInfoIPHController);
+                urlBarEditingTextStateProvider, isTablet, forceModelViewReconciliationRunnable,
+                locationBarDataProvider, PermissionDialogController.getInstance(),
+                searchEngineLogoUtils, templateUrlServiceSupplier, profileSupplier,
+                pageInfoIPHController);
 
         Resources res = mStatusView.getResources();
         mMediator.setUrlMinWidth(res.getDimensionPixelSize(R.dimen.location_bar_min_url_width)
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/status/StatusMediator.java b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/status/StatusMediator.java
index baa5513..a89471f 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/status/StatusMediator.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/status/StatusMediator.java
@@ -83,6 +83,7 @@
 
     private final PermissionDialogController mPermissionDialogController;
     private final Handler mPermissionTaskHandler = new Handler();
+    private final Runnable mForceModelViewReconciliationRunnable;
     @ContentSettingsType
     private int mLastPermission = ContentSettingsType.DEFAULT;
     private final PageInfoIPHController mPageInfoIPHController;
@@ -102,6 +103,7 @@
 
     public StatusMediator(PropertyModel model, Resources resources, Context context,
             UrlBarEditingTextStateProvider urlBarEditingTextStateProvider, boolean isTablet,
+            Runnable forceModelViewReconciliationRunnable,
             LocationBarDataProvider locationBarDataProvider,
             PermissionDialogController permissionDialogController,
             SearchEngineLogoUtils searchEngineLogoUtils,
@@ -128,6 +130,7 @@
         mTextOffsetAdjustedScale = mTextOffsetThreshold == 1 ? 1 : (1 - mTextOffsetThreshold);
 
         mIsTablet = isTablet;
+        mForceModelViewReconciliationRunnable = forceModelViewReconciliationRunnable;
         mPermissionDialogController = permissionDialogController;
         mPermissionDialogController.addObserver(this);
     }
@@ -629,6 +632,29 @@
     public void onIncognitoStateChanged() {
         boolean incognitoBadgeVisible = mLocationBarDataProvider.isIncognito() && !mIsTablet;
         mModel.set(StatusProperties.INCOGNITO_BADGE_VISIBLE, incognitoBadgeVisible);
+        reconcileVisualState();
+    }
+
+    /**
+     * Temporary workaround for the divergent logic for status icon visibility changes for the dse
+     * icon experiment.
+     *
+     * The logic below resets the visual state for the StatusView widget when transitioning back
+     * and forth between incognito and non-incognito states.
+     * When the UrlBar is the first visible view when focused, the StatusView's alpha
+     * will be set to 0 in LocationBarPhone#populateFadeAnimations. When transitioning back from
+     * incognito, StatusView's state needs to be reset to match the current state of the status view
+     * {@link org.chromium.chrome.browser.omnibox.LocationBarPhone#updateVisualsForState}.
+     * property model.
+     *
+     * TODO(http://crbug.com/1185985): Delete this when all the code altering StatusView properties
+     * is consolidated and it is safe to do so.
+     **/
+    private void reconcileVisualState() {
+        // No reconciliation is needed on tablet because the status icon is always shown.
+        if (mIsTablet) return;
+        assert mForceModelViewReconciliationRunnable != null;
+        mForceModelViewReconciliationRunnable.run();
     }
 
     // PermissionDialogController.Observer interface
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/voice/AssistantVoiceSearchService.java b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/voice/AssistantVoiceSearchService.java
index 96d7de06..aef07c1 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/voice/AssistantVoiceSearchService.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/voice/AssistantVoiceSearchService.java
@@ -52,6 +52,8 @@
     @VisibleForTesting
     static final String USER_ELIGIBILITY_FAILURE_REASON_HISTOGRAM =
             "Assistant.VoiceSearch.UserEligibility.FailureReason";
+    @VisibleForTesting
+    static final String AGSA_VERSION_HISTOGRAM = "Assistant.VoiceSearch.AgsaVersion";
     private static final String DEFAULT_ASSISTANT_AGSA_MIN_VERSION = "12.7.2.23";
     private static final boolean DEFAULT_ASSISTANT_COLORFUL_MIC_ENABLED = false;
 
@@ -306,6 +308,14 @@
                 /* returnImmediately= */ false, /* outList */ failureReasons);
         RecordHistogram.recordBooleanHistogram(USER_ELIGIBILITY_HISTOGRAM, eligible);
 
+        // See notes in {@link GSAState#parseAgsaMajorMinorVersionAsInteger} for details about this
+        // number.
+        Integer versionNumber =
+                mGsaState.parseAgsaMajorMinorVersionAsInteger(mGsaState.getAgsaVersionName());
+        if (versionNumber != null) {
+            RecordHistogram.recordSparseHistogram(AGSA_VERSION_HISTOGRAM, (int) versionNumber);
+        }
+
         for (@EligibilityFailureReason int reason : failureReasons) {
             RecordHistogram.recordEnumeratedHistogram(USER_ELIGIBILITY_FAILURE_REASON_HISTOGRAM,
                     reason, EligibilityFailureReason.MAX_VALUE);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/signin/SigninBridge.java b/chrome/android/java/src/org/chromium/chrome/browser/signin/SigninBridge.java
index 3633071..0c3f495 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/signin/SigninBridge.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/signin/SigninBridge.java
@@ -17,9 +17,11 @@
 import org.chromium.chrome.browser.signin.services.IdentityServicesProvider;
 import org.chromium.chrome.browser.signin.services.SigninManager;
 import org.chromium.chrome.browser.signin.services.SigninMetricsUtils;
+import org.chromium.chrome.browser.signin.services.SigninPreferencesManager;
 import org.chromium.chrome.browser.signin.services.WebSigninBridge;
 import org.chromium.chrome.browser.signin.ui.account_picker.AccountPickerBottomSheetCoordinator;
 import org.chromium.chrome.browser.signin.ui.account_picker.AccountPickerDelegateImpl;
+import org.chromium.chrome.browser.signin.ui.account_picker.AccountPickerFeatureUtils;
 import org.chromium.chrome.browser.sync.settings.AccountManagementFragment;
 import org.chromium.chrome.browser.tabmodel.TabCreator;
 import org.chromium.chrome.browser.tabmodel.TabCreatorManager;
@@ -32,6 +34,7 @@
 import org.chromium.components.browser_ui.bottomsheet.BottomSheetControllerProvider;
 import org.chromium.components.signin.AccountManagerFacadeProvider;
 import org.chromium.components.signin.GAIAServiceType;
+import org.chromium.components.signin.metrics.AccountConsistencyPromoAction;
 import org.chromium.components.signin.metrics.SigninAccessPoint;
 import org.chromium.ui.base.WindowAndroid;
 
@@ -77,16 +80,20 @@
                 Profile.getLastUsedRegularProfile());
         if (!signinManager.isSignInAllowed()) {
             SigninMetricsUtils.logAccountConsistencyPromoAction(
-                    org.chromium.components.signin.metrics.AccountConsistencyPromoAction
-                            .SUPPRESSED_SIGNIN_NOT_ALLOWED);
+                    AccountConsistencyPromoAction.SUPPRESSED_SIGNIN_NOT_ALLOWED);
             return;
         }
         if (AccountManagerFacadeProvider.getInstance().tryGetGoogleAccounts().isEmpty()) {
             // TODO(https://crbug.com/1119720): Show the bottom sheet when no accounts on device
             //  in the future. This disabling is only temporary.
             SigninMetricsUtils.logAccountConsistencyPromoAction(
-                    org.chromium.components.signin.metrics.AccountConsistencyPromoAction
-                            .SUPPRESSED_NO_ACCOUNTS);
+                    AccountConsistencyPromoAction.SUPPRESSED_NO_ACCOUNTS);
+            return;
+        }
+        if (SigninPreferencesManager.getInstance().getAccountPickerBottomSheetActiveDismissalCount()
+                >= AccountPickerFeatureUtils.getDismissLimit()) {
+            SigninMetricsUtils.logAccountConsistencyPromoAction(
+                    AccountConsistencyPromoAction.SUPPRESSED_CONSECUTIVE_DISMISSALS);
             return;
         }
         BottomSheetController bottomSheetController =
@@ -111,8 +118,8 @@
         assert tabCreatorManagerSupplier.hasValue() : "No TabCreatorManager available.";
         final TabCreator incognitoTabCreator =
                 tabCreatorManagerSupplier.get().getTabCreator(/*incognito=*/true);
-        AccountPickerBottomSheetCoordinator coordinator = new AccountPickerBottomSheetCoordinator(
-                windowAndroid.getActivity().get(), bottomSheetController,
+        new AccountPickerBottomSheetCoordinator(windowAndroid.getActivity().get(),
+                bottomSheetController,
                 new AccountPickerDelegateImpl(windowAndroid,
                         TabModelUtils.getCurrentTab(regularTabModel), new WebSigninBridge.Factory(),
                         continueUrl),
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/tabbed_mode/TabbedAppMenuPropertiesDelegate.java b/chrome/android/java/src/org/chromium/chrome/browser/tabbed_mode/TabbedAppMenuPropertiesDelegate.java
index 5a0e384..5541c216 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/tabbed_mode/TabbedAppMenuPropertiesDelegate.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/tabbed_mode/TabbedAppMenuPropertiesDelegate.java
@@ -114,7 +114,9 @@
 
     @Override
     public boolean shouldShowIconBeforeItem() {
-        return true;
+        return CachedFeatureFlags.isEnabled(ChromeFeatureList.TABBED_APP_OVERFLOW_MENU_ICONS)
+                || CachedFeatureFlags.isEnabled(
+                        ChromeFeatureList.TABBED_APP_OVERFLOW_MENU_THREE_BUTTON_ACTIONBAR);
     }
 
     private boolean canShowDataReductionItem(int maxMenuHeight) {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/tabmodel/TabPersistentStore.java b/chrome/android/java/src/org/chromium/chrome/browser/tabmodel/TabPersistentStore.java
index c0c41b9..34bec149 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/tabmodel/TabPersistentStore.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/tabmodel/TabPersistentStore.java
@@ -684,6 +684,9 @@
                     && !tabToRestore.fromMerge) {
                 Log.i(TAG, "Skipping restore of non-selected NTP.");
                 return;
+            } else if (TextUtils.isEmpty(tabToRestore.url)) {
+                Log.i(TAG, "Skipping restore of empty Tabs.");
+                return;
             }
 
             Log.w(TAG, "Failed to restore TabState; creating Tab with last known URL.");
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ui/RootUiCoordinator.java b/chrome/android/java/src/org/chromium/chrome/browser/ui/RootUiCoordinator.java
index f710770..f3bc95b 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ui/RootUiCoordinator.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ui/RootUiCoordinator.java
@@ -529,7 +529,8 @@
                 RecordUserAction.record("MobileShortcutFindInPage");
             }
             return true;
-        } else if (id == R.id.share_menu_id || id == R.id.direct_share_menu_id) {
+        } else if (id == R.id.share_menu_button_id || id == R.id.share_menu_id
+                || id == R.id.direct_share_menu_id) {
             onShareMenuItemSelected(id == R.id.direct_share_menu_id,
                     mTabModelSelectorSupplier.get().isIncognitoSelected());
         } else if (id == R.id.paint_preview_show_id) {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/webauth/AuthenticatorImpl.java b/chrome/android/java/src/org/chromium/chrome/browser/webauth/AuthenticatorImpl.java
index e4036c5..ab1a4161 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/webauth/AuthenticatorImpl.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/webauth/AuthenticatorImpl.java
@@ -33,7 +33,7 @@
  * //chrome/browser/autofill/android/internal_authenticator_android.h, which is meant for requests
  * that originate in the browser process.
  */
-public class AuthenticatorImpl extends HandlerResponseCallback implements Authenticator {
+public class AuthenticatorImpl implements Authenticator {
     private final RenderFrameHost mRenderFrameHost;
 
     private static final String GMSCORE_PACKAGE_NAME = "com.google.android.gms";
@@ -109,7 +109,10 @@
         }
 
         mIsOperationPending = true;
-        Fido2ApiHandler.getInstance().makeCredential(options, mRenderFrameHost, mOrigin, this);
+        Fido2ApiHandler.getInstance().makeCredential(options, mRenderFrameHost, mOrigin,
+                (status, response)
+                        -> onRegisterResponse(status, response),
+                status -> onError(status));
     }
 
     /**
@@ -144,7 +147,8 @@
         }
 
         mIsOperationPending = true;
-        Fido2ApiHandler.getInstance().getAssertion(options, mRenderFrameHost, mOrigin, this);
+        Fido2ApiHandler.getInstance().getAssertion(options, mRenderFrameHost, mOrigin,
+                (status, response) -> onSignResponse(status, response), status -> onError(status));
     }
 
     /**
@@ -185,7 +189,8 @@
 
         mIsUserVerifyingPlatformAuthenticatorAvailableCallbackQueue.add(callback);
         Fido2ApiHandler.getInstance().isUserVerifyingPlatformAuthenticatorAvailable(
-                mRenderFrameHost, this);
+                mRenderFrameHost,
+                isUvpaa -> onIsUserVerifyingPlatformAuthenticatorAvailableResponse(isUvpaa));
     }
 
     /**
@@ -223,27 +228,23 @@
     /**
      * Callbacks for receiving responses from the internal handlers.
      */
-    @Override
     public void onRegisterResponse(Integer status, MakeCredentialAuthenticatorResponse response) {
         assert mMakeCredentialCallback != null;
         mMakeCredentialCallback.call(status, response);
         close();
     }
 
-    @Override
     public void onSignResponse(Integer status, GetAssertionAuthenticatorResponse response) {
         assert mGetAssertionCallback != null;
         mGetAssertionCallback.call(status, response);
         close();
     }
 
-    @Override
     public void onIsUserVerifyingPlatformAuthenticatorAvailableResponse(boolean isUVPAA) {
         assert !mIsUserVerifyingPlatformAuthenticatorAvailableCallbackQueue.isEmpty();
         mIsUserVerifyingPlatformAuthenticatorAvailableCallbackQueue.poll().call(isUVPAA);
     }
 
-    @Override
     public void onError(Integer status) {
         assert ((mMakeCredentialCallback != null && mGetAssertionCallback == null)
                 || (mMakeCredentialCallback == null && mGetAssertionCallback != null));
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/webauth/Fido2ApiHandler.java b/chrome/android/java/src/org/chromium/chrome/browser/webauth/Fido2ApiHandler.java
index 97be5376..e2bb9ab 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/webauth/Fido2ApiHandler.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/webauth/Fido2ApiHandler.java
@@ -47,19 +47,21 @@
     }
 
     protected void makeCredential(PublicKeyCredentialCreationOptions options,
-            RenderFrameHost frameHost, Origin origin, HandlerResponseCallback callback) {
+            RenderFrameHost frameHost, Origin origin, MakeCredentialResponseCallback callback,
+            FidoErrorResponseCallback errorCallback) {
         new Fido2CredentialRequest().handleMakeCredentialRequest(
-                options, frameHost, origin, callback);
+                options, frameHost, origin, callback, errorCallback);
     }
 
     protected void getAssertion(PublicKeyCredentialRequestOptions options,
-            RenderFrameHost frameHost, Origin origin, HandlerResponseCallback callback) {
+            RenderFrameHost frameHost, Origin origin, GetAssertionResponseCallback callback,
+            FidoErrorResponseCallback errorCallback) {
         new Fido2CredentialRequest().handleGetAssertionRequest(
-                options, frameHost, origin, callback);
+                options, frameHost, origin, callback, errorCallback);
     }
 
     protected void isUserVerifyingPlatformAuthenticatorAvailable(
-            RenderFrameHost frameHost, HandlerResponseCallback callback) {
+            RenderFrameHost frameHost, IsUvpaaResponseCallback callback) {
         new Fido2CredentialRequest().handleIsUserVerifyingPlatformAuthenticatorAvailableRequest(
                 frameHost, callback);
     }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/webauth/Fido2CredentialRequest.java b/chrome/android/java/src/org/chromium/chrome/browser/webauth/Fido2CredentialRequest.java
index 707d79a3..9dfd0af 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/webauth/Fido2CredentialRequest.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/webauth/Fido2CredentialRequest.java
@@ -51,8 +51,9 @@
  */
 public class Fido2CredentialRequest implements WindowAndroid.IntentCallback {
     private static final String TAG = "Fido2Request";
-    private HandlerResponseCallback mCallback;
-    private HandlerResponseCallback mIsUserVerifyingPlatformAuthenticatorAvailableCallback;
+    private GetAssertionResponseCallback mGetAssertionCallback;
+    private MakeCredentialResponseCallback mMakeCredentialCallback;
+    private FidoErrorResponseCallback mErrorCallback;
     private Fido2PrivilegedApiClient mFido2ApiClient;
     private WebContents mWebContents;
     private WindowAndroid mWindow;
@@ -77,10 +78,12 @@
     public static final String FIDO2_KEY_CREDENTIAL_EXTRA = "FIDO2_CREDENTIAL_EXTRA";
 
     private void returnErrorAndResetCallback(int error) {
-        assert mCallback != null;
-        if (mCallback == null) return;
-        mCallback.onError(error);
-        mCallback = null;
+        assert mErrorCallback != null;
+        if (mErrorCallback == null) return;
+        mErrorCallback.onError(error);
+        mErrorCallback = null;
+        mGetAssertionCallback = null;
+        mMakeCredentialCallback = null;
     }
 
     // Listens for a Fido2PendingIntent.
@@ -137,9 +140,11 @@
 
     public void handleMakeCredentialRequest(
             org.chromium.blink.mojom.PublicKeyCredentialCreationOptions options,
-            RenderFrameHost frameHost, Origin origin, HandlerResponseCallback callback) {
-        assert mCallback == null;
-        mCallback = callback;
+            RenderFrameHost frameHost, Origin origin, MakeCredentialResponseCallback callback,
+            FidoErrorResponseCallback errorCallback) {
+        assert mMakeCredentialCallback == null && mErrorCallback == null;
+        mMakeCredentialCallback = callback;
+        mErrorCallback = errorCallback;
         if (mWebContents == null) {
             mWebContents = WebContentsStatics.fromRenderFrameHost(frameHost);
         }
@@ -178,9 +183,11 @@
     }
 
     public void handleGetAssertionRequest(PublicKeyCredentialRequestOptions options,
-            RenderFrameHost frameHost, Origin origin, HandlerResponseCallback callback) {
-        assert mCallback == null;
-        mCallback = callback;
+            RenderFrameHost frameHost, Origin origin, GetAssertionResponseCallback callback,
+            FidoErrorResponseCallback errorCallback) {
+        assert mGetAssertionCallback == null && mErrorCallback == null;
+        mGetAssertionCallback = callback;
+        mErrorCallback = errorCallback;
         if (mWebContents == null) {
             mWebContents = WebContentsStatics.fromRenderFrameHost(frameHost);
         }
@@ -219,9 +226,7 @@
     }
 
     public void handleIsUserVerifyingPlatformAuthenticatorAvailableRequest(
-            RenderFrameHost frameHost, HandlerResponseCallback callback) {
-        assert mIsUserVerifyingPlatformAuthenticatorAvailableCallback == null;
-        mIsUserVerifyingPlatformAuthenticatorAvailableCallback = callback;
+            RenderFrameHost frameHost, IsUvpaaResponseCallback callback) {
         if (mWebContents == null) {
             mWebContents = WebContentsStatics.fromRenderFrameHost(frameHost);
         }
@@ -230,19 +235,15 @@
             // Note that |IsUserVerifyingPlatformAuthenticatorAvailable| only returns
             // true or false, making it unable to handle any error status.
             // So it callbacks with false if Fido2PrivilegedApi is not available.
-            mIsUserVerifyingPlatformAuthenticatorAvailableCallback
-                    .onIsUserVerifyingPlatformAuthenticatorAvailableResponse(false);
-            mIsUserVerifyingPlatformAuthenticatorAvailableCallback = null;
+            callback.onIsUserVerifyingPlatformAuthenticatorAvailableResponse(false);
             return;
         }
 
         Task<Boolean> result =
                 mFido2ApiClient.isUserVerifyingPlatformAuthenticatorAvailable()
                         .addOnSuccessListener((isUVPAA) -> {
-                            mIsUserVerifyingPlatformAuthenticatorAvailableCallback
-                                    .onIsUserVerifyingPlatformAuthenticatorAvailableResponse(
-                                            isUVPAA);
-                            mIsUserVerifyingPlatformAuthenticatorAvailableCallback = null;
+                            callback.onIsUserVerifyingPlatformAuthenticatorAvailableResponse(
+                                    isUVPAA);
                         });
     }
 
@@ -307,16 +308,16 @@
             processErrorResponse((AuthenticatorErrorResponse) response);
         } else if (response instanceof AuthenticatorAttestationResponse) {
             try {
-                mCallback.onRegisterResponse(AuthenticatorStatus.SUCCESS,
+                mMakeCredentialCallback.onRegisterResponse(AuthenticatorStatus.SUCCESS,
                         Fido2Helper.toMakeCredentialResponse(publicKeyCredential));
-                mCallback = null;
+                mMakeCredentialCallback = null;
             } catch (NoSuchAlgorithmException e) {
                 returnErrorAndResetCallback(AuthenticatorStatus.ALGORITHM_UNSUPPORTED);
             }
         } else if (response instanceof AuthenticatorAssertionResponse) {
-            mCallback.onSignResponse(AuthenticatorStatus.SUCCESS,
+            mGetAssertionCallback.onSignResponse(AuthenticatorStatus.SUCCESS,
                     Fido2Helper.toGetAssertionResponse(publicKeyCredential, mAppIdExtensionUsed));
-            mCallback = null;
+            mGetAssertionCallback = null;
         }
     }
 
@@ -334,7 +335,7 @@
             case REGISTER_REQUEST:
                 Log.e(TAG, "Received a register response from Google Play Services FIDO2 API");
                 try {
-                    mCallback.onRegisterResponse(AuthenticatorStatus.SUCCESS,
+                    mMakeCredentialCallback.onRegisterResponse(AuthenticatorStatus.SUCCESS,
                             Fido2Helper.toMakeCredentialResponse(
                                     AuthenticatorAttestationResponse.deserializeFromBytes(
                                             data.getByteArrayExtra(
@@ -345,14 +346,15 @@
                 break;
             case SIGN_REQUEST:
                 Log.e(TAG, "Received a sign response from Google Play Services FIDO2 API");
-                mCallback.onSignResponse(AuthenticatorStatus.SUCCESS,
+                mGetAssertionCallback.onSignResponse(AuthenticatorStatus.SUCCESS,
                         Fido2Helper.toGetAssertionResponse(
                                 AuthenticatorAssertionResponse.deserializeFromBytes(
                                         data.getByteArrayExtra(Fido.FIDO2_KEY_RESPONSE_EXTRA)),
                                 mAppIdExtensionUsed));
                 break;
         }
-        mCallback = null;
+        mMakeCredentialCallback = null;
+        mGetAssertionCallback = null;
     }
 
     private void processIntentResult(Intent data) {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/webauth/FidoErrorResponseCallback.java b/chrome/android/java/src/org/chromium/chrome/browser/webauth/FidoErrorResponseCallback.java
new file mode 100644
index 0000000..e94f21d
--- /dev/null
+++ b/chrome/android/java/src/org/chromium/chrome/browser/webauth/FidoErrorResponseCallback.java
@@ -0,0 +1,12 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.chrome.browser.webauth;
+
+/**
+ * Callback interface for handling any errors from register or sign requests.
+ */
+public interface FidoErrorResponseCallback {
+    public void onError(Integer status);
+}
\ No newline at end of file
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/webauth/GetAssertionResponseCallback.java b/chrome/android/java/src/org/chromium/chrome/browser/webauth/GetAssertionResponseCallback.java
new file mode 100644
index 0000000..bd6dbfb
--- /dev/null
+++ b/chrome/android/java/src/org/chromium/chrome/browser/webauth/GetAssertionResponseCallback.java
@@ -0,0 +1,15 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.chrome.browser.webauth;
+
+import org.chromium.blink.mojom.GetAssertionAuthenticatorResponse;
+
+/**
+ * Callback interface for receiving a response from a request to produce a
+ * signed assertion from an authenticator.
+ */
+public interface GetAssertionResponseCallback {
+    public void onSignResponse(Integer status, GetAssertionAuthenticatorResponse response);
+}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/webauth/HandlerResponseCallback.java b/chrome/android/java/src/org/chromium/chrome/browser/webauth/HandlerResponseCallback.java
deleted file mode 100644
index f90efbe6..0000000
--- a/chrome/android/java/src/org/chromium/chrome/browser/webauth/HandlerResponseCallback.java
+++ /dev/null
@@ -1,36 +0,0 @@
-// Copyright 2018 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-package org.chromium.chrome.browser.webauth;
-
-import org.chromium.blink.mojom.GetAssertionAuthenticatorResponse;
-import org.chromium.blink.mojom.MakeCredentialAuthenticatorResponse;
-
-/**
- * Callback for receiving responses from an internal handler.
- */
-public class HandlerResponseCallback {
-    /**
-     * Callback for handling the response from a request to register a
-     * credential with an authenticator.
-     */
-    public void onRegisterResponse(Integer status, MakeCredentialAuthenticatorResponse response){};
-
-    /**
-     * Callback for handling the response from a request to use a credential
-     * to produce a signed assertion.
-     */
-    public void onSignResponse(Integer status, GetAssertionAuthenticatorResponse response){};
-
-    /**
-     * Callback for handling response from a request to call
-     * isUserVerifyingPlatformAuthenticatorAvailable.
-     */
-    public void onIsUserVerifyingPlatformAuthenticatorAvailableResponse(boolean isUVPAA){};
-
-    /**
-     * Callback for handling any errors from either register or sign requests.
-     */
-    public void onError(Integer status){};
-}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/webauth/IsUvpaaResponseCallback.java b/chrome/android/java/src/org/chromium/chrome/browser/webauth/IsUvpaaResponseCallback.java
new file mode 100644
index 0000000..b3b8850d
--- /dev/null
+++ b/chrome/android/java/src/org/chromium/chrome/browser/webauth/IsUvpaaResponseCallback.java
@@ -0,0 +1,13 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.chrome.browser.webauth;
+
+/**
+ * Callback interface for receiving a response from a request to call
+ * IsUserVerifyingPlatformAuthenticator.
+ */
+public interface IsUvpaaResponseCallback {
+    public void onIsUserVerifyingPlatformAuthenticatorAvailableResponse(boolean isUVPAA);
+}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/webauth/MakeCredentialResponseCallback.java b/chrome/android/java/src/org/chromium/chrome/browser/webauth/MakeCredentialResponseCallback.java
new file mode 100644
index 0000000..225105437
--- /dev/null
+++ b/chrome/android/java/src/org/chromium/chrome/browser/webauth/MakeCredentialResponseCallback.java
@@ -0,0 +1,15 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.chrome.browser.webauth;
+
+import org.chromium.blink.mojom.MakeCredentialAuthenticatorResponse;
+
+/**
+ * Callback interface for receiving a response from a request to register a
+ * credential with an authenticator.
+ */
+public interface MakeCredentialResponseCallback {
+    public void onRegisterResponse(Integer status, MakeCredentialAuthenticatorResponse response);
+}
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/app/appmenu/OverviewAppMenuTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/app/appmenu/OverviewAppMenuTest.java
index 62bb587..5682b316c 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/app/appmenu/OverviewAppMenuTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/app/appmenu/OverviewAppMenuTest.java
@@ -143,10 +143,9 @@
                 int itemId = item.getItemId();
                 assertTrue(itemId == R.id.new_tab_menu_id
                         || itemId == R.id.new_incognito_tab_menu_id
-                        || itemId == R.id.divider_line_id || itemId == R.id.open_history_menu_id
-                        || itemId == R.id.downloads_menu_id || itemId == R.id.all_bookmarks_menu_id
-                        || itemId == R.id.recent_tabs_menu_id
-                        || itemId == R.id.close_all_tabs_menu_id
+                        || itemId == R.id.all_bookmarks_menu_id
+                        || itemId == R.id.recent_tabs_menu_id || itemId == R.id.open_history_menu_id
+                        || itemId == R.id.downloads_menu_id || itemId == R.id.close_all_tabs_menu_id
                         || itemId == R.id.close_all_incognito_tabs_menu_id
                         || itemId == R.id.menu_group_tabs || itemId == R.id.track_prices_row_menu_id
                         || itemId == R.id.preferences_id);
@@ -159,7 +158,7 @@
                 checkedMenuItems++;
             }
         }
-        assertThat(checkedMenuItems, equalTo(13));
+        assertThat(checkedMenuItems, equalTo(11));
     }
 
     @Test
@@ -182,10 +181,9 @@
                 int itemId = item.getItemId();
                 assertTrue(itemId == R.id.new_tab_menu_id
                         || itemId == R.id.new_incognito_tab_menu_id
-                        || itemId == R.id.divider_line_id || itemId == R.id.open_history_menu_id
-                        || itemId == R.id.downloads_menu_id || itemId == R.id.all_bookmarks_menu_id
-                        || itemId == R.id.recent_tabs_menu_id
-                        || itemId == R.id.close_all_tabs_menu_id
+                        || itemId == R.id.all_bookmarks_menu_id
+                        || itemId == R.id.recent_tabs_menu_id || itemId == R.id.open_history_menu_id
+                        || itemId == R.id.downloads_menu_id || itemId == R.id.close_all_tabs_menu_id
                         || itemId == R.id.close_all_incognito_tabs_menu_id
                         || itemId == R.id.menu_group_tabs || itemId == R.id.track_prices_row_menu_id
                         || itemId == R.id.preferences_id);
@@ -198,7 +196,7 @@
                 checkedMenuItems++;
             }
         }
-        assertThat(checkedMenuItems, equalTo(13));
+        assertThat(checkedMenuItems, equalTo(11));
     }
 
     @Test
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/app/appmenu/TabbedAppMenuTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/app/appmenu/TabbedAppMenuTest.java
index b6a1124..25ffa0f 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/app/appmenu/TabbedAppMenuTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/app/appmenu/TabbedAppMenuTest.java
@@ -247,9 +247,11 @@
     @Test
     @SmallTest
     @Feature({"Browser", "Main", "Bookmark", "RenderTest"})
-    @DisableFeatures({ChromeFeatureList.TABBED_APP_OVERFLOW_MENU_THREE_BUTTON_ACTIONBAR})
+    @DisableFeatures({ChromeFeatureList.TABBED_APP_OVERFLOW_MENU_REGROUP,
+            ChromeFeatureList.TABBED_APP_OVERFLOW_MENU_ICONS})
     @Restriction(UiRestriction.RESTRICTION_TYPE_PHONE)
-    public void testBookmarkMenuItem() throws IOException {
+    public void
+    testBookmarkMenuItem() throws IOException {
         MenuItem bookmarkStar =
                 AppMenuTestSupport.getMenu(mActivityTestRule.getAppMenuCoordinator())
                         .findItem(R.id.bookmark_this_page_id);
@@ -431,6 +433,7 @@
     @Test
     @SmallTest
     @Feature({"Browser", "Main", "RenderTest"})
+    @EnableFeatures({ChromeFeatureList.TABBED_APP_OVERFLOW_MENU_REGROUP})
     public void testDividerLineMenuItem() throws IOException {
         int firstDividerLineIndex = findIndexOfMenuItemById(R.id.divider_line_id);
         Assert.assertTrue("No divider line found.", firstDividerLineIndex != -1);
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/notifications/NotificationPlatformBridgeTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/notifications/NotificationPlatformBridgeTest.java
index af0df7b..77e032a 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/notifications/NotificationPlatformBridgeTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/notifications/NotificationPlatformBridgeTest.java
@@ -248,8 +248,16 @@
         Assert.assertNotNull(
                 NotificationTestUtil.getLargeIconFromNotification(context, notification));
 
-        // Validate the notification's behavior.
-        Assert.assertEquals(Notification.DEFAULT_ALL, notification.defaults);
+        // Validate the notification's behavior. On Android O+ the defaults are ignored as vibrate
+        // and silent moved to the notification channel. The silent flag is achieved by using a
+        // group alert summary.
+        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O
+                && NotificationBuilderBase.shouldUseCompat()) {
+            Assert.assertEquals(0, notification.defaults);
+            Assert.assertEquals(Notification.GROUP_ALERT_ALL, notification.getGroupAlertBehavior());
+        } else {
+            Assert.assertEquals(Notification.DEFAULT_ALL, notification.defaults);
+        }
         Assert.assertEquals(Notification.PRIORITY_DEFAULT, notification.priority);
     }
 
@@ -436,6 +444,14 @@
 
         // Zero indicates that no defaults should be inherited from the system.
         Assert.assertEquals(0, notification.defaults);
+
+        // On Android O+ the defaults are ignored as vibrate and silent moved to the notification
+        // channel. The silent flag is achieved by using a group alert summary.
+        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O
+                && NotificationBuilderBase.shouldUseCompat()) {
+            Assert.assertEquals(
+                    Notification.GROUP_ALERT_SUMMARY, notification.getGroupAlertBehavior());
+        }
     }
 
     private void verifyVibrationNotRequestedWhenDisabledInPrefs(String notificationOptions)
@@ -451,13 +467,20 @@
 
         Notification notification = showAndGetNotification("MyNotification", notificationOptions);
 
-        // Vibration should not be in the defaults.
-        Assert.assertEquals(
-                Notification.DEFAULT_ALL & ~Notification.DEFAULT_VIBRATE, notification.defaults);
+        // On Android O+ the defaults are ignored as vibrate and silent moved to the notification
+        // channel.
+        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O
+                && NotificationBuilderBase.shouldUseCompat()) {
+            Assert.assertEquals(0, notification.defaults);
+        } else {
+            // Vibration should not be in the defaults.
+            Assert.assertEquals(Notification.DEFAULT_ALL & ~Notification.DEFAULT_VIBRATE,
+                    notification.defaults);
 
-        // There should be a custom no-op vibration pattern.
-        Assert.assertEquals(1, notification.vibrate.length);
-        Assert.assertEquals(0L, notification.vibrate[0]);
+            // There should be a custom no-op vibration pattern.
+            Assert.assertEquals(1, notification.vibrate.length);
+            Assert.assertEquals(0L, notification.vibrate[0]);
+        }
     }
 
     /**
@@ -501,14 +524,21 @@
 
         Notification notification = showAndGetNotification("MyNotification", "{ vibrate: 42 }");
 
-        // Vibration should not be in the defaults, a custom pattern was provided.
-        Assert.assertEquals(
-                Notification.DEFAULT_ALL & ~Notification.DEFAULT_VIBRATE, notification.defaults);
+        // On Android O+ the defaults are ignored as vibrate and silent moved to the notification
+        // channel.
+        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O
+                && NotificationBuilderBase.shouldUseCompat()) {
+            Assert.assertEquals(0, notification.defaults);
+        } else {
+            // Vibration should not be in the defaults, a custom pattern was provided.
+            Assert.assertEquals(Notification.DEFAULT_ALL & ~Notification.DEFAULT_VIBRATE,
+                    notification.defaults);
 
-        // The custom pattern should have been passed along.
-        Assert.assertEquals(2, notification.vibrate.length);
-        Assert.assertEquals(0L, notification.vibrate[0]);
-        Assert.assertEquals(42L, notification.vibrate[1]);
+            // The custom pattern should have been passed along.
+            Assert.assertEquals(2, notification.vibrate.length);
+            Assert.assertEquals(0L, notification.vibrate[0]);
+            Assert.assertEquals(42L, notification.vibrate[1]);
+        }
     }
 
     /**
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/omnibox/status/StatusMediatorUnitTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/omnibox/status/StatusMediatorUnitTest.java
index fc5af59..4e1fb10 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/omnibox/status/StatusMediatorUnitTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/omnibox/status/StatusMediatorUnitTest.java
@@ -107,12 +107,14 @@
                 .when(mSearchEngineLogoUtils)
                 .getSearchEngineLogoFavicon(any(), eq(mResources), any(), any());
 
+        // clang-format off
         TestThreadUtils.runOnUiThreadBlocking(() -> {
             mMediator = new StatusMediator(mModel, mResources, mContext,
-                    mUrlBarEditingTextStateProvider,
-                    /* isTablet */ false, mLocationBarDataProvider, mPermissionDialogController,
-                    mSearchEngineLogoUtils, () -> mTemplateUrlService, () -> mProfile, null);
+                    mUrlBarEditingTextStateProvider, /* isTablet */ false, () -> {},
+                    mLocationBarDataProvider, mPermissionDialogController, mSearchEngineLogoUtils,
+                    () -> mTemplateUrlService, () -> mProfile, null);
         });
+        // clang-format on
         mBitmap = Bitmap.createBitmap(10, 10, Bitmap.Config.ARGB_8888);
     }
 
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/omnibox/voice/AssistantVoiceSearchServiceRenderTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/omnibox/voice/AssistantVoiceSearchServiceRenderTest.java
index 5a78ce07..108ac7c 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/omnibox/voice/AssistantVoiceSearchServiceRenderTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/omnibox/voice/AssistantVoiceSearchServiceRenderTest.java
@@ -12,9 +12,9 @@
 import static org.mockito.ArgumentMatchers.anyString;
 import static org.mockito.Mockito.doReturn;
 
+import static org.chromium.base.test.util.Restriction.RESTRICTION_TYPE_NON_LOW_END_DEVICE;
 import static org.chromium.chrome.browser.preferences.ChromePreferenceKeys.ASSISTANT_VOICE_SEARCH_ENABLED;
 
-import android.os.Build.VERSION_CODES;
 import android.support.test.filters.MediumTest;
 
 import org.junit.Before;
@@ -27,8 +27,8 @@
 import org.mockito.junit.MockitoRule;
 
 import org.chromium.base.test.util.CommandLineFlags;
-import org.chromium.base.test.util.DisableIf;
 import org.chromium.base.test.util.Feature;
+import org.chromium.base.test.util.Restriction;
 import org.chromium.chrome.R;
 import org.chromium.chrome.browser.flags.ChromeFeatureList;
 import org.chromium.chrome.browser.flags.ChromeSwitches;
@@ -48,6 +48,7 @@
 @CommandLineFlags.Add({ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE,
         "enable-features=" + ChromeFeatureList.OMNIBOX_ASSISTANT_VOICE_SEARCH + "<Study",
         "force-fieldtrials=Study/Group"})
+@Restriction({RESTRICTION_TYPE_NON_LOW_END_DEVICE})
 public class AssistantVoiceSearchServiceRenderTest {
     @Rule
     public ChromeTabbedActivityTestRule mActivityTestRule = new ChromeTabbedActivityTestRule();
@@ -85,8 +86,6 @@
     @MediumTest
     @CommandLineFlags.Add({"force-fieldtrial-params=Study.Group:colorful_mic/true"})
     @Feature({"RenderTest"})
-    @DisableIf.Build(message = "Flaky on Android M runners, see https://crbug.com/1185744",
-            sdk_is_less_than = VERSION_CODES.O)
     public void
     testAssistantColorfulMic() throws IOException {
         mActivityTestRule.loadUrl(UrlConstants.NTP_URL);
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/page_info/PageInfoDiscoverabilityTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/page_info/PageInfoDiscoverabilityTest.java
index 1b00e6fa..a9ce6934 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/page_info/PageInfoDiscoverabilityTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/page_info/PageInfoDiscoverabilityTest.java
@@ -77,12 +77,14 @@
         mModel = new PropertyModel(StatusProperties.ALL_KEYS);
         mPermissionDialogController = PermissionDialogController.getInstance();
 
+        // clang-format off
         TestThreadUtils.runOnUiThreadBlocking(() -> {
             mMediator = new StatusMediator(mModel, mResources, mContext,
-                    mUrlBarEditingTextStateProvider,
-                    /* isTablet */ false, mLocationBarDataProvider, mPermissionDialogController,
+                    mUrlBarEditingTextStateProvider, /* isTablet */ false,
+                    () -> {}, mLocationBarDataProvider, mPermissionDialogController,
                     mSearchEngineLogoUtils, () -> mTemplateUrlService, () -> mProfile, null);
         });
+        // clang-format on
     }
 
     @Test
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/signin/AccountPickerBottomSheetTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/signin/AccountPickerBottomSheetTest.java
index 1a7eb58..431d3a8 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/signin/AccountPickerBottomSheetTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/signin/AccountPickerBottomSheetTest.java
@@ -54,6 +54,7 @@
 import org.chromium.chrome.browser.incognito.interstitial.IncognitoInterstitialDelegate;
 import org.chromium.chrome.browser.preferences.ChromePreferenceKeys;
 import org.chromium.chrome.browser.preferences.SharedPreferencesManager;
+import org.chromium.chrome.browser.signin.services.SigninPreferencesManager;
 import org.chromium.chrome.browser.signin.ui.R;
 import org.chromium.chrome.browser.signin.ui.account_picker.AccountPickerBottomSheetCoordinator;
 import org.chromium.chrome.browser.signin.ui.account_picker.AccountPickerDelegate;
@@ -148,12 +149,14 @@
         mAccountManagerTestRule.addAccount(PROFILE_DATA2);
         SharedPreferencesManager.getInstance().removeKey(
                 ChromePreferenceKeys.ACCOUNT_PICKER_BOTTOM_SHEET_SHOWN_COUNT);
+        SigninPreferencesManager.getInstance().clearAccountPickerBottomSheetActiveDismissalCount();
     }
 
     @After
     public void tearDown() {
         SharedPreferencesManager.getInstance().removeKey(
                 ChromePreferenceKeys.ACCOUNT_PICKER_BOTTOM_SHEET_SHOWN_COUNT);
+        SigninPreferencesManager.getInstance().clearAccountPickerBottomSheetActiveDismissalCount();
     }
 
     @Test
@@ -241,6 +244,8 @@
         HistogramDelta accountConsistencyHistogram =
                 new HistogramDelta("Signin.AccountConsistencyPromoAction",
                         AccountConsistencyPromoAction.DISMISSED_BACK);
+        SharedPreferencesManager.getInstance().writeInt(
+                ChromePreferenceKeys.ACCOUNT_PICKER_BOTTOM_SHEET_ACTIVE_DISMISSAL_COUNT, 1);
         buildAndShowCollapsedBottomSheet();
         onView(withText(PROFILE_DATA1.getAccountEmail())).check(matches(isDisplayed()));
         BottomSheetController controller = getBottomSheetController();
@@ -251,6 +256,9 @@
         verify(mAccountPickerDelegateMock).onDismiss();
         Assert.assertEquals(0, mFakeProfileDataSource.getNumberOfObservers());
         Assert.assertEquals(1, accountConsistencyHistogram.getDelta());
+        Assert.assertEquals(2,
+                SigninPreferencesManager.getInstance()
+                        .getAccountPickerBottomSheetActiveDismissalCount());
     }
 
     @Test
@@ -259,6 +267,8 @@
         HistogramDelta accountConsistencyHistogram =
                 new HistogramDelta("Signin.AccountConsistencyPromoAction",
                         AccountConsistencyPromoAction.DISMISSED_BUTTON);
+        SharedPreferencesManager.getInstance().writeInt(
+                ChromePreferenceKeys.ACCOUNT_PICKER_BOTTOM_SHEET_ACTIVE_DISMISSAL_COUNT, 1);
         buildAndShowCollapsedBottomSheet();
         onView(withText(PROFILE_DATA1.getAccountEmail())).check(matches(isDisplayed()));
         BottomSheetController controller = getBottomSheetController();
@@ -269,6 +279,9 @@
         verify(mAccountPickerDelegateMock).onDismiss();
         Assert.assertEquals(0, mFakeProfileDataSource.getNumberOfObservers());
         Assert.assertEquals(1, accountConsistencyHistogram.getDelta());
+        Assert.assertEquals(2,
+                SigninPreferencesManager.getInstance()
+                        .getAccountPickerBottomSheetActiveDismissalCount());
     }
 
     @Test
@@ -397,6 +410,8 @@
                         AccountConsistencyPromoAction.SIGNED_IN_WITH_NON_DEFAULT_ACCOUNT);
         HistogramDelta signedInCountHistogram = new HistogramDelta(
                 "Signin.AccountConsistencyPromoAction.SignedIn.Count", mShowCount);
+        SharedPreferencesManager.getInstance().writeInt(
+                ChromePreferenceKeys.ACCOUNT_PICKER_BOTTOM_SHEET_ACTIVE_DISMISSAL_COUNT, 2);
         buildAndShowExpandedBottomSheet();
         onView(withText(PROFILE_DATA2.getAccountEmail())).perform(click());
         CriteriaHelper.pollUiThread(mCoordinator.getBottomSheetViewForTesting().findViewById(
@@ -404,6 +419,9 @@
         clickContinueButtonAndCheckSignInInProgressSheet();
         Assert.assertEquals(1, accountConsistencyHistogram.getDelta());
         Assert.assertEquals(1, signedInCountHistogram.getDelta());
+        Assert.assertEquals(0,
+                SigninPreferencesManager.getInstance()
+                        .getAccountPickerBottomSheetActiveDismissalCount());
     }
 
     @Test
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/webauth/AuthenticatorTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/webauth/AuthenticatorTest.java
index 8ab48bc..8df508db 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/webauth/AuthenticatorTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/webauth/AuthenticatorTest.java
@@ -53,19 +53,21 @@
     private class MockFido2ApiHandler extends Fido2ApiHandler {
         @Override
         protected void makeCredential(PublicKeyCredentialCreationOptions options,
-                RenderFrameHost frameHost, Origin origin, HandlerResponseCallback callback) {
-            callback.onError(AuthenticatorStatus.NOT_IMPLEMENTED);
+                RenderFrameHost frameHost, Origin origin, MakeCredentialResponseCallback callback,
+                FidoErrorResponseCallback errorCallback) {
+            errorCallback.onError(AuthenticatorStatus.NOT_IMPLEMENTED);
         }
 
         @Override
         protected void getAssertion(PublicKeyCredentialRequestOptions options,
-                RenderFrameHost frameHost, Origin origin, HandlerResponseCallback callback) {
-            callback.onError(AuthenticatorStatus.NOT_IMPLEMENTED);
+                RenderFrameHost frameHost, Origin origin, GetAssertionResponseCallback callback,
+                FidoErrorResponseCallback errorCallback) {
+            errorCallback.onError(AuthenticatorStatus.NOT_IMPLEMENTED);
         }
 
         @Override
         protected void isUserVerifyingPlatformAuthenticatorAvailable(
-                RenderFrameHost frameHost, HandlerResponseCallback callback) {
+                RenderFrameHost frameHost, IsUvpaaResponseCallback callback) {
             callback.onIsUserVerifyingPlatformAuthenticatorAvailableResponse(false);
         }
     }
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/webauth/Fido2CredentialRequestTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/webauth/Fido2CredentialRequestTest.java
index 26130c7..a3b37ce 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/webauth/Fido2CredentialRequestTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/webauth/Fido2CredentialRequestTest.java
@@ -215,7 +215,7 @@
         }
     }
 
-    private static class AuthenticatorCallback extends HandlerResponseCallback {
+    private static class AuthenticatorCallback {
         private Integer mStatus;
         private MakeCredentialAuthenticatorResponse mMakeCredentialResponse;
         private GetAssertionAuthenticatorResponse mGetAssertionAuthenticatorResponse;
@@ -225,7 +225,6 @@
 
         AuthenticatorCallback() {}
 
-        @Override
         public void onRegisterResponse(
                 Integer status, MakeCredentialAuthenticatorResponse response) {
             assert mStatus == null;
@@ -234,7 +233,6 @@
             unblock();
         }
 
-        @Override
         public void onSignResponse(Integer status, GetAssertionAuthenticatorResponse response) {
             assert mStatus == null;
             mStatus = status;
@@ -242,7 +240,6 @@
             unblock();
         }
 
-        @Override
         public void onError(Integer status) {
             assert mStatus == null;
             mStatus = status;
@@ -279,19 +276,22 @@
 
         @Override
         protected void makeCredential(PublicKeyCredentialCreationOptions options,
-                RenderFrameHost frameHost, Origin origin, HandlerResponseCallback callback) {
-            mRequest.handleMakeCredentialRequest(options, frameHost, origin, callback);
+                RenderFrameHost frameHost, Origin origin, MakeCredentialResponseCallback callback,
+                FidoErrorResponseCallback errorCallback) {
+            mRequest.handleMakeCredentialRequest(
+                    options, frameHost, origin, callback, errorCallback);
         }
 
         @Override
         protected void getAssertion(PublicKeyCredentialRequestOptions options,
-                RenderFrameHost frameHost, Origin origin, HandlerResponseCallback callback) {
-            mRequest.handleGetAssertionRequest(options, frameHost, origin, callback);
+                RenderFrameHost frameHost, Origin origin, GetAssertionResponseCallback callback,
+                FidoErrorResponseCallback errorCallback) {
+            mRequest.handleGetAssertionRequest(options, frameHost, origin, callback, errorCallback);
         }
 
         @Override
         protected void isUserVerifyingPlatformAuthenticatorAvailable(
-                RenderFrameHost frameHost, HandlerResponseCallback callback) {
+                RenderFrameHost frameHost, IsUvpaaResponseCallback callback) {
             mRequest.handleIsUserVerifyingPlatformAuthenticatorAvailableRequest(
                     frameHost, callback);
         }
@@ -440,7 +440,10 @@
         mWindowAndroid.setResponseIntent(Fido2ApiTestHelper.createSuccessfulMakeCredentialIntent());
         TestThreadUtils.runOnUiThreadBlocking(() -> mRequest.setWindowForTesting(mWindowAndroid));
 
-        mRequest.handleMakeCredentialRequest(mCreationOptions, mFrameHost, mOrigin, mCallback);
+        mRequest.handleMakeCredentialRequest(mCreationOptions, mFrameHost, mOrigin,
+                (responseStatus, response)
+                        -> mCallback.onRegisterResponse(responseStatus, response),
+                errorStatus -> mCallback.onError(errorStatus));
         mCallback.blockUntilCalled();
         Assert.assertEquals(mCallback.getStatus(), Integer.valueOf(AuthenticatorStatus.SUCCESS));
         Fido2ApiTestHelper.validateMakeCredentialResponse(mCallback.getMakeCredentialResponse());
@@ -453,7 +456,10 @@
         mWindowAndroid.setCancelableIntentSuccess(false);
         TestThreadUtils.runOnUiThreadBlocking(() -> mRequest.setWindowForTesting(mWindowAndroid));
 
-        mRequest.handleMakeCredentialRequest(mCreationOptions, mFrameHost, mOrigin, mCallback);
+        mRequest.handleMakeCredentialRequest(mCreationOptions, mFrameHost, mOrigin,
+                (responseStatus, response)
+                        -> mCallback.onRegisterResponse(responseStatus, response),
+                errorStatus -> mCallback.onError(errorStatus));
         mCallback.blockUntilCalled();
         Assert.assertEquals(
                 mCallback.getStatus(), Integer.valueOf(AuthenticatorStatus.UNKNOWN_ERROR));
@@ -467,7 +473,10 @@
         mWindowAndroid.setResponseIntent(new Intent());
         TestThreadUtils.runOnUiThreadBlocking(() -> mRequest.setWindowForTesting(mWindowAndroid));
 
-        mRequest.handleMakeCredentialRequest(mCreationOptions, mFrameHost, mOrigin, mCallback);
+        mRequest.handleMakeCredentialRequest(mCreationOptions, mFrameHost, mOrigin,
+                (responseStatus, response)
+                        -> mCallback.onRegisterResponse(responseStatus, response),
+                errorStatus -> mCallback.onError(errorStatus));
         mCallback.blockUntilCalled();
         Assert.assertEquals(
                 mCallback.getStatus(), Integer.valueOf(AuthenticatorStatus.UNKNOWN_ERROR));
@@ -480,7 +489,10 @@
         // Don't set an intent to be returned at all.
         TestThreadUtils.runOnUiThreadBlocking(() -> mRequest.setWindowForTesting(mWindowAndroid));
 
-        mRequest.handleMakeCredentialRequest(mCreationOptions, mFrameHost, mOrigin, mCallback);
+        mRequest.handleMakeCredentialRequest(mCreationOptions, mFrameHost, mOrigin,
+                (responseStatus, response)
+                        -> mCallback.onRegisterResponse(responseStatus, response),
+                errorStatus -> mCallback.onError(errorStatus));
         mCallback.blockUntilCalled();
         Assert.assertEquals(
                 mCallback.getStatus(), Integer.valueOf(AuthenticatorStatus.NOT_ALLOWED_ERROR));
@@ -493,7 +505,10 @@
         mWindowAndroid.setResultCode(Activity.RESULT_CANCELED);
         TestThreadUtils.runOnUiThreadBlocking(() -> mRequest.setWindowForTesting(mWindowAndroid));
 
-        mRequest.handleMakeCredentialRequest(mCreationOptions, mFrameHost, mOrigin, mCallback);
+        mRequest.handleMakeCredentialRequest(mCreationOptions, mFrameHost, mOrigin,
+                (responseStatus, response)
+                        -> mCallback.onRegisterResponse(responseStatus, response),
+                errorStatus -> mCallback.onError(errorStatus));
         mCallback.blockUntilCalled();
         Assert.assertEquals(
                 mCallback.getStatus(), Integer.valueOf(AuthenticatorStatus.NOT_ALLOWED_ERROR));
@@ -507,7 +522,10 @@
         mWindowAndroid.setResultCode(Activity.RESULT_FIRST_USER);
         TestThreadUtils.runOnUiThreadBlocking(() -> mRequest.setWindowForTesting(mWindowAndroid));
 
-        mRequest.handleMakeCredentialRequest(mCreationOptions, mFrameHost, mOrigin, mCallback);
+        mRequest.handleMakeCredentialRequest(mCreationOptions, mFrameHost, mOrigin,
+                (responseStatus, response)
+                        -> mCallback.onRegisterResponse(responseStatus, response),
+                errorStatus -> mCallback.onError(errorStatus));
         mCallback.blockUntilCalled();
         Assert.assertEquals(
                 mCallback.getStatus(), Integer.valueOf(AuthenticatorStatus.UNKNOWN_ERROR));
@@ -522,7 +540,10 @@
         mWindowAndroid.setResponseIntent(Fido2ApiTestHelper.createSuccessfulMakeCredentialIntent());
         TestThreadUtils.runOnUiThreadBlocking(() -> mRequest.setWindowForTesting(mWindowAndroid));
 
-        mRequest.handleMakeCredentialRequest(customOptions, mFrameHost, mOrigin, mCallback);
+        mRequest.handleMakeCredentialRequest(customOptions, mFrameHost, mOrigin,
+                (responseStatus, response)
+                        -> mCallback.onRegisterResponse(responseStatus, response),
+                errorStatus -> mCallback.onError(errorStatus));
         mCallback.blockUntilCalled();
         Assert.assertEquals(mCallback.getStatus(), Integer.valueOf(AuthenticatorStatus.SUCCESS));
         Fido2ApiTestHelper.validateMakeCredentialResponse(mCallback.getMakeCredentialResponse());
@@ -537,7 +558,10 @@
         mWindowAndroid.setResponseIntent(Fido2ApiTestHelper.createSuccessfulMakeCredentialIntent());
         TestThreadUtils.runOnUiThreadBlocking(() -> mRequest.setWindowForTesting(mWindowAndroid));
 
-        mRequest.handleMakeCredentialRequest(customOptions, mFrameHost, mOrigin, mCallback);
+        mRequest.handleMakeCredentialRequest(customOptions, mFrameHost, mOrigin,
+                (responseStatus, response)
+                        -> mCallback.onRegisterResponse(responseStatus, response),
+                errorStatus -> mCallback.onError(errorStatus));
         mCallback.blockUntilCalled();
         Assert.assertEquals(mCallback.getStatus(), Integer.valueOf(AuthenticatorStatus.SUCCESS));
         Fido2ApiTestHelper.validateMakeCredentialResponse(mCallback.getMakeCredentialResponse());
@@ -553,7 +577,10 @@
         parameters.type = PublicKeyCredentialType.PUBLIC_KEY;
         customOptions.publicKeyParameters = new PublicKeyCredentialParameters[] {parameters};
 
-        mRequest.handleMakeCredentialRequest(customOptions, mFrameHost, mOrigin, mCallback);
+        mRequest.handleMakeCredentialRequest(customOptions, mFrameHost, mOrigin,
+                (responseStatus, response)
+                        -> mCallback.onRegisterResponse(responseStatus, response),
+                errorStatus -> mCallback.onError(errorStatus));
         mCallback.blockUntilCalled();
         Assert.assertEquals(
                 mCallback.getStatus(), Integer.valueOf(AuthenticatorStatus.ALGORITHM_UNSUPPORTED));
@@ -568,7 +595,10 @@
         parameters.type = 10; // Not a valid type.
         customOptions.publicKeyParameters = new PublicKeyCredentialParameters[] {parameters};
 
-        mRequest.handleMakeCredentialRequest(customOptions, mFrameHost, mOrigin, mCallback);
+        mRequest.handleMakeCredentialRequest(customOptions, mFrameHost, mOrigin,
+                (responseStatus, response)
+                        -> mCallback.onRegisterResponse(responseStatus, response),
+                errorStatus -> mCallback.onError(errorStatus));
         mCallback.blockUntilCalled();
         Assert.assertEquals(
                 mCallback.getStatus(), Integer.valueOf(AuthenticatorStatus.ALGORITHM_UNSUPPORTED));
@@ -588,7 +618,10 @@
         mWindowAndroid.setResponseIntent(Fido2ApiTestHelper.createSuccessfulMakeCredentialIntent());
         TestThreadUtils.runOnUiThreadBlocking(() -> mRequest.setWindowForTesting(mWindowAndroid));
 
-        mRequest.handleMakeCredentialRequest(customOptions, mFrameHost, mOrigin, mCallback);
+        mRequest.handleMakeCredentialRequest(customOptions, mFrameHost, mOrigin,
+                (responseStatus, response)
+                        -> mCallback.onRegisterResponse(responseStatus, response),
+                errorStatus -> mCallback.onError(errorStatus));
         mCallback.blockUntilCalled();
         Assert.assertEquals(mCallback.getStatus(), Integer.valueOf(AuthenticatorStatus.SUCCESS));
         Fido2ApiTestHelper.validateMakeCredentialResponse(mCallback.getMakeCredentialResponse());
@@ -603,7 +636,10 @@
 
         PublicKeyCredentialCreationOptions customOptions = mCreationOptions;
         customOptions.excludeCredentials = null;
-        mRequest.handleMakeCredentialRequest(customOptions, mFrameHost, mOrigin, mCallback);
+        mRequest.handleMakeCredentialRequest(customOptions, mFrameHost, mOrigin,
+                (responseStatus, response)
+                        -> mCallback.onRegisterResponse(responseStatus, response),
+                errorStatus -> mCallback.onError(errorStatus));
         mCallback.blockUntilCalled();
         Assert.assertEquals(mCallback.getStatus(), Integer.valueOf(AuthenticatorStatus.SUCCESS));
         Fido2ApiTestHelper.validateMakeCredentialResponse(mCallback.getMakeCredentialResponse());
@@ -678,7 +714,10 @@
         mWindowAndroid.setResponseIntent(Fido2ApiTestHelper.createSuccessfulGetAssertionIntent());
         TestThreadUtils.runOnUiThreadBlocking(() -> mRequest.setWindowForTesting(mWindowAndroid));
 
-        mRequest.handleGetAssertionRequest(mRequestOptions, mFrameHost, mOrigin, mCallback);
+        mRequest.handleGetAssertionRequest(mRequestOptions, mFrameHost, mOrigin,
+                (responseStatus, response)
+                        -> mCallback.onSignResponse(responseStatus, response),
+                errorStatus -> mCallback.onError(errorStatus));
         mCallback.blockUntilCalled();
         Assert.assertEquals(mCallback.getStatus(), Integer.valueOf(AuthenticatorStatus.SUCCESS));
         Fido2ApiTestHelper.validateGetAssertionResponse(mCallback.getGetAssertionResponse());
@@ -691,7 +730,10 @@
         TestThreadUtils.runOnUiThreadBlocking(() -> mRequest.setWindowForTesting(mWindowAndroid));
 
         mRequestOptions.userVerificationMethods = true;
-        mRequest.handleGetAssertionRequest(mRequestOptions, mFrameHost, mOrigin, mCallback);
+        mRequest.handleGetAssertionRequest(mRequestOptions, mFrameHost, mOrigin,
+                (responseStatus, response)
+                        -> mCallback.onSignResponse(responseStatus, response),
+                errorStatus -> mCallback.onError(errorStatus));
         mCallback.blockUntilCalled();
         Assert.assertEquals(mCallback.getStatus(), Integer.valueOf(AuthenticatorStatus.SUCCESS));
         Fido2ApiTestHelper.validateGetAssertionResponse(mCallback.getGetAssertionResponse());
@@ -706,7 +748,10 @@
         TestThreadUtils.runOnUiThreadBlocking(() -> mRequest.setWindowForTesting(mWindowAndroid));
 
         mRequestOptions.userVerificationMethods = true;
-        mRequest.handleGetAssertionRequest(mRequestOptions, mFrameHost, mOrigin, mCallback);
+        mRequest.handleGetAssertionRequest(mRequestOptions, mFrameHost, mOrigin,
+                (responseStatus, response)
+                        -> mCallback.onSignResponse(responseStatus, response),
+                errorStatus -> mCallback.onError(errorStatus));
         mCallback.blockUntilCalled();
         Assert.assertEquals(mCallback.getStatus(), Integer.valueOf(AuthenticatorStatus.SUCCESS));
         Fido2ApiTestHelper.validateGetAssertionResponse(mCallback.getGetAssertionResponse());
@@ -719,7 +764,10 @@
         mWindowAndroid.setCancelableIntentSuccess(false);
         TestThreadUtils.runOnUiThreadBlocking(() -> mRequest.setWindowForTesting(mWindowAndroid));
 
-        mRequest.handleGetAssertionRequest(mRequestOptions, mFrameHost, mOrigin, mCallback);
+        mRequest.handleGetAssertionRequest(mRequestOptions, mFrameHost, mOrigin,
+                (responseStatus, response)
+                        -> mCallback.onSignResponse(responseStatus, response),
+                errorStatus -> mCallback.onError(errorStatus));
         mCallback.blockUntilCalled();
         Assert.assertEquals(
                 mCallback.getStatus(), Integer.valueOf(AuthenticatorStatus.UNKNOWN_ERROR));
@@ -733,7 +781,10 @@
         mWindowAndroid.setResponseIntent(new Intent());
         TestThreadUtils.runOnUiThreadBlocking(() -> mRequest.setWindowForTesting(mWindowAndroid));
 
-        mRequest.handleGetAssertionRequest(mRequestOptions, mFrameHost, mOrigin, mCallback);
+        mRequest.handleGetAssertionRequest(mRequestOptions, mFrameHost, mOrigin,
+                (responseStatus, response)
+                        -> mCallback.onSignResponse(responseStatus, response),
+                errorStatus -> mCallback.onError(errorStatus));
         mCallback.blockUntilCalled();
         Assert.assertEquals(
                 mCallback.getStatus(), Integer.valueOf(AuthenticatorStatus.UNKNOWN_ERROR));
@@ -746,7 +797,10 @@
         // Don't set an intent to be returned at all.
         TestThreadUtils.runOnUiThreadBlocking(() -> mRequest.setWindowForTesting(mWindowAndroid));
 
-        mRequest.handleGetAssertionRequest(mRequestOptions, mFrameHost, mOrigin, mCallback);
+        mRequest.handleGetAssertionRequest(mRequestOptions, mFrameHost, mOrigin,
+                (responseStatus, response)
+                        -> mCallback.onSignResponse(responseStatus, response),
+                errorStatus -> mCallback.onError(errorStatus));
         mCallback.blockUntilCalled();
         Assert.assertEquals(
                 mCallback.getStatus(), Integer.valueOf(AuthenticatorStatus.NOT_ALLOWED_ERROR));
@@ -759,7 +813,10 @@
         mWindowAndroid.setResultCode(Activity.RESULT_CANCELED);
         TestThreadUtils.runOnUiThreadBlocking(() -> mRequest.setWindowForTesting(mWindowAndroid));
 
-        mRequest.handleGetAssertionRequest(mRequestOptions, mFrameHost, mOrigin, mCallback);
+        mRequest.handleGetAssertionRequest(mRequestOptions, mFrameHost, mOrigin,
+                (responseStatus, response)
+                        -> mCallback.onSignResponse(responseStatus, response),
+                errorStatus -> mCallback.onError(errorStatus));
         mCallback.blockUntilCalled();
         Assert.assertEquals(
                 mCallback.getStatus(), Integer.valueOf(AuthenticatorStatus.NOT_ALLOWED_ERROR));
@@ -773,7 +830,10 @@
         mWindowAndroid.setResultCode(Activity.RESULT_FIRST_USER);
         TestThreadUtils.runOnUiThreadBlocking(() -> mRequest.setWindowForTesting(mWindowAndroid));
 
-        mRequest.handleGetAssertionRequest(mRequestOptions, mFrameHost, mOrigin, mCallback);
+        mRequest.handleGetAssertionRequest(mRequestOptions, mFrameHost, mOrigin,
+                (responseStatus, response)
+                        -> mCallback.onSignResponse(responseStatus, response),
+                errorStatus -> mCallback.onError(errorStatus));
         mCallback.blockUntilCalled();
         Assert.assertEquals(
                 mCallback.getStatus(), Integer.valueOf(AuthenticatorStatus.UNKNOWN_ERROR));
@@ -787,7 +847,10 @@
                 ErrorCode.UNKNOWN_ERR, "Low level error 0x6a80"));
         TestThreadUtils.runOnUiThreadBlocking(() -> mRequest.setWindowForTesting(mWindowAndroid));
 
-        mRequest.handleGetAssertionRequest(mRequestOptions, mFrameHost, mOrigin, mCallback);
+        mRequest.handleGetAssertionRequest(mRequestOptions, mFrameHost, mOrigin,
+                (responseStatus, response)
+                        -> mCallback.onSignResponse(responseStatus, response),
+                errorStatus -> mCallback.onError(errorStatus));
         mCallback.blockUntilCalled();
         Assert.assertEquals(mCallback.getStatus(),
                 Integer.valueOf(AuthenticatorStatus.CREDENTIAL_NOT_RECOGNIZED));
@@ -802,7 +865,10 @@
         mWindowAndroid.setResponseIntent(Fido2ApiTestHelper.createSuccessfulGetAssertionIntent());
         TestThreadUtils.runOnUiThreadBlocking(() -> mRequest.setWindowForTesting(mWindowAndroid));
 
-        mRequest.handleGetAssertionRequest(mRequestOptions, mFrameHost, mOrigin, mCallback);
+        mRequest.handleGetAssertionRequest(mRequestOptions, mFrameHost, mOrigin,
+                (responseStatus, response)
+                        -> mCallback.onSignResponse(responseStatus, response),
+                errorStatus -> mCallback.onError(errorStatus));
         mCallback.blockUntilCalled();
         Assert.assertEquals(mCallback.getStatus(), Integer.valueOf(AuthenticatorStatus.SUCCESS));
         GetAssertionAuthenticatorResponse response = mCallback.getGetAssertionResponse();
@@ -885,7 +951,10 @@
 
         PublicKeyCredentialCreationOptions customOptions = mCreationOptions;
         customOptions.attestation = org.chromium.blink.mojom.AttestationConveyancePreference.NONE;
-        mRequest.handleMakeCredentialRequest(customOptions, mFrameHost, mOrigin, mCallback);
+        mRequest.handleMakeCredentialRequest(customOptions, mFrameHost, mOrigin,
+                (responseStatus, response)
+                        -> mCallback.onRegisterResponse(responseStatus, response),
+                errorStatus -> mCallback.onError(errorStatus));
         mCallback.blockUntilCalled();
         Assert.assertEquals(mCallback.getStatus(), Integer.valueOf(AuthenticatorStatus.SUCCESS));
         Fido2ApiTestHelper.validateMakeCredentialResponse(mCallback.getMakeCredentialResponse());
@@ -901,7 +970,10 @@
         PublicKeyCredentialCreationOptions customOptions = mCreationOptions;
         customOptions.attestation =
                 org.chromium.blink.mojom.AttestationConveyancePreference.INDIRECT;
-        mRequest.handleMakeCredentialRequest(customOptions, mFrameHost, mOrigin, mCallback);
+        mRequest.handleMakeCredentialRequest(customOptions, mFrameHost, mOrigin,
+                (responseStatus, response)
+                        -> mCallback.onRegisterResponse(responseStatus, response),
+                errorStatus -> mCallback.onError(errorStatus));
         mCallback.blockUntilCalled();
         Assert.assertEquals(mCallback.getStatus(), Integer.valueOf(AuthenticatorStatus.SUCCESS));
         Fido2ApiTestHelper.validateMakeCredentialResponse(mCallback.getMakeCredentialResponse());
@@ -916,7 +988,10 @@
 
         PublicKeyCredentialCreationOptions customOptions = mCreationOptions;
         customOptions.attestation = org.chromium.blink.mojom.AttestationConveyancePreference.DIRECT;
-        mRequest.handleMakeCredentialRequest(customOptions, mFrameHost, mOrigin, mCallback);
+        mRequest.handleMakeCredentialRequest(customOptions, mFrameHost, mOrigin,
+                (responseStatus, response)
+                        -> mCallback.onRegisterResponse(responseStatus, response),
+                errorStatus -> mCallback.onError(errorStatus));
         mCallback.blockUntilCalled();
         Assert.assertEquals(mCallback.getStatus(), Integer.valueOf(AuthenticatorStatus.SUCCESS));
         Fido2ApiTestHelper.validateMakeCredentialResponse(mCallback.getMakeCredentialResponse());
@@ -932,7 +1007,10 @@
         PublicKeyCredentialCreationOptions customOptions = mCreationOptions;
         customOptions.attestation =
                 org.chromium.blink.mojom.AttestationConveyancePreference.ENTERPRISE;
-        mRequest.handleMakeCredentialRequest(customOptions, mFrameHost, mOrigin, mCallback);
+        mRequest.handleMakeCredentialRequest(customOptions, mFrameHost, mOrigin,
+                (responseStatus, response)
+                        -> mCallback.onRegisterResponse(responseStatus, response),
+                errorStatus -> mCallback.onError(errorStatus));
         mCallback.blockUntilCalled();
         Assert.assertEquals(mCallback.getStatus(), Integer.valueOf(AuthenticatorStatus.SUCCESS));
         Fido2ApiTestHelper.validateMakeCredentialResponse(mCallback.getMakeCredentialResponse());
@@ -946,7 +1024,10 @@
                 Fido2ApiTestHelper.createErrorIntent(ErrorCode.INVALID_STATE_ERR,
                         "One of the excluded credentials exists on the local device"));
         TestThreadUtils.runOnUiThreadBlocking(() -> mRequest.setWindowForTesting(mWindowAndroid));
-        mRequest.handleMakeCredentialRequest(mCreationOptions, mFrameHost, mOrigin, mCallback);
+        mRequest.handleMakeCredentialRequest(mCreationOptions, mFrameHost, mOrigin,
+                (responseStatus, response)
+                        -> mCallback.onRegisterResponse(responseStatus, response),
+                errorStatus -> mCallback.onError(errorStatus));
         mCallback.blockUntilCalled();
         Assert.assertEquals(
                 mCallback.getStatus(), Integer.valueOf(AuthenticatorStatus.CREDENTIAL_EXCLUDED));
@@ -963,7 +1044,10 @@
         mWindowAndroid.setResponseIntent(Fido2ApiTestHelper.createErrorIntent(
                 ErrorCode.NOT_ALLOWED_ERR, "Authentication request must have non-empty allowList"));
         TestThreadUtils.runOnUiThreadBlocking(() -> mRequest.setWindowForTesting(mWindowAndroid));
-        mRequest.handleGetAssertionRequest(mRequestOptions, mFrameHost, mOrigin, mCallback);
+        mRequest.handleGetAssertionRequest(mRequestOptions, mFrameHost, mOrigin,
+                (responseStatus, response)
+                        -> mCallback.onSignResponse(responseStatus, response),
+                errorStatus -> mCallback.onError(errorStatus));
         mCallback.blockUntilCalled();
         Assert.assertEquals(mCallback.getStatus(),
                 Integer.valueOf(AuthenticatorStatus.EMPTY_ALLOW_CREDENTIALS));
@@ -982,7 +1066,10 @@
                 Fido2ApiTestHelper.createErrorIntent(ErrorCode.NOT_ALLOWED_ERR,
                         "Request doesn't have a valid list of allowed credentials."));
         TestThreadUtils.runOnUiThreadBlocking(() -> mRequest.setWindowForTesting(mWindowAndroid));
-        mRequest.handleGetAssertionRequest(mRequestOptions, mFrameHost, mOrigin, mCallback);
+        mRequest.handleGetAssertionRequest(mRequestOptions, mFrameHost, mOrigin,
+                (responseStatus, response)
+                        -> mCallback.onSignResponse(responseStatus, response),
+                errorStatus -> mCallback.onError(errorStatus));
         mCallback.blockUntilCalled();
         Assert.assertEquals(mCallback.getStatus(),
                 Integer.valueOf(AuthenticatorStatus.EMPTY_ALLOW_CREDENTIALS));
@@ -996,7 +1083,10 @@
         mWindowAndroid.setResponseIntent(Fido2ApiTestHelper.createErrorIntent(
                 ErrorCode.CONSTRAINT_ERR, "The device is not secured with any screen lock"));
         TestThreadUtils.runOnUiThreadBlocking(() -> mRequest.setWindowForTesting(mWindowAndroid));
-        mRequest.handleMakeCredentialRequest(mCreationOptions, mFrameHost, mOrigin, mCallback);
+        mRequest.handleMakeCredentialRequest(mCreationOptions, mFrameHost, mOrigin,
+                (responseStatus, response)
+                        -> mCallback.onRegisterResponse(responseStatus, response),
+                errorStatus -> mCallback.onError(errorStatus));
         mCallback.blockUntilCalled();
         Assert.assertEquals(mCallback.getStatus(),
                 Integer.valueOf(AuthenticatorStatus.USER_VERIFICATION_UNSUPPORTED));
@@ -1009,7 +1099,10 @@
         mWindowAndroid.setResponseIntent(Fido2ApiTestHelper.createErrorIntent(
                 ErrorCode.CONSTRAINT_ERR, "The device is not secured with any screen lock"));
         TestThreadUtils.runOnUiThreadBlocking(() -> mRequest.setWindowForTesting(mWindowAndroid));
-        mRequest.handleGetAssertionRequest(mRequestOptions, mFrameHost, mOrigin, mCallback);
+        mRequest.handleGetAssertionRequest(mRequestOptions, mFrameHost, mOrigin,
+                (responseStatus, response)
+                        -> mCallback.onSignResponse(responseStatus, response),
+                errorStatus -> mCallback.onError(errorStatus));
         mCallback.blockUntilCalled();
         Assert.assertEquals(mCallback.getStatus(),
                 Integer.valueOf(AuthenticatorStatus.USER_VERIFICATION_UNSUPPORTED));
@@ -1024,7 +1117,10 @@
         mWindowAndroid.setResponseIntent(
                 Fido2ApiTestHelper.createErrorIntent(ErrorCode.valueOf(errorCodeName), errorMsg));
         TestThreadUtils.runOnUiThreadBlocking(() -> mRequest.setWindowForTesting(mWindowAndroid));
-        mRequest.handleMakeCredentialRequest(mCreationOptions, mFrameHost, mOrigin, mCallback);
+        mRequest.handleMakeCredentialRequest(mCreationOptions, mFrameHost, mOrigin,
+                (responseStatus, response)
+                        -> mCallback.onRegisterResponse(responseStatus, response),
+                errorStatus -> mCallback.onError(errorStatus));
         mCallback.blockUntilCalled();
         Assert.assertEquals(mCallback.getStatus(), status);
         Fido2ApiTestHelper.verifyRespondedBeforeTimeout(mStartTimeMs);
@@ -1037,7 +1133,10 @@
         mWindowAndroid.setResponseIntent(
                 Fido2ApiTestHelper.createErrorIntent(ErrorCode.valueOf(errorCodeName), errorMsg));
         TestThreadUtils.runOnUiThreadBlocking(() -> mRequest.setWindowForTesting(mWindowAndroid));
-        mRequest.handleGetAssertionRequest(mRequestOptions, mFrameHost, mOrigin, mCallback);
+        mRequest.handleGetAssertionRequest(mRequestOptions, mFrameHost, mOrigin,
+                (responseStatus, response)
+                        -> mCallback.onSignResponse(responseStatus, response),
+                errorStatus -> mCallback.onError(errorStatus));
         mCallback.blockUntilCalled();
         Assert.assertEquals(mCallback.getStatus(), status);
         Fido2ApiTestHelper.verifyRespondedBeforeTimeout(mStartTimeMs);
@@ -1051,7 +1150,10 @@
         mWindowAndroid.setResponseIntent(
                 Fido2ApiTestHelper.createErrorIntent(ErrorCode.valueOf(errorCodeName), null));
         TestThreadUtils.runOnUiThreadBlocking(() -> mRequest.setWindowForTesting(mWindowAndroid));
-        mRequest.handleMakeCredentialRequest(mCreationOptions, mFrameHost, mOrigin, mCallback);
+        mRequest.handleMakeCredentialRequest(mCreationOptions, mFrameHost, mOrigin,
+                (responseStatus, response)
+                        -> mCallback.onRegisterResponse(responseStatus, response),
+                errorStatus -> mCallback.onError(errorStatus));
         mCallback.blockUntilCalled();
         Assert.assertEquals(mCallback.getStatus(), status);
         Fido2ApiTestHelper.verifyRespondedBeforeTimeout(mStartTimeMs);
@@ -1065,7 +1167,10 @@
         mWindowAndroid.setResponseIntent(
                 Fido2ApiTestHelper.createErrorIntent(ErrorCode.valueOf(errorCodeName), null));
         TestThreadUtils.runOnUiThreadBlocking(() -> mRequest.setWindowForTesting(mWindowAndroid));
-        mRequest.handleGetAssertionRequest(mRequestOptions, mFrameHost, mOrigin, mCallback);
+        mRequest.handleGetAssertionRequest(mRequestOptions, mFrameHost, mOrigin,
+                (responseStatus, response)
+                        -> mCallback.onSignResponse(responseStatus, response),
+                errorStatus -> mCallback.onError(errorStatus));
         mCallback.blockUntilCalled();
         Assert.assertEquals(mCallback.getStatus(), status);
         Fido2ApiTestHelper.verifyRespondedBeforeTimeout(mStartTimeMs);
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/app/appmenu/AppMenuPropertiesDelegateUnitTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/app/appmenu/AppMenuPropertiesDelegateUnitTest.java
index b44b56fd..aa390b9 100644
--- a/chrome/android/junit/src/org/chromium/chrome/browser/app/appmenu/AppMenuPropertiesDelegateUnitTest.java
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/app/appmenu/AppMenuPropertiesDelegateUnitTest.java
@@ -246,10 +246,9 @@
         mAppMenuPropertiesDelegate.prepareMenu(menu, null);
 
         Integer[] expectedItems = {R.id.icon_row_menu_id, R.id.new_tab_menu_id,
-                R.id.new_incognito_tab_menu_id, R.id.divider_line_id, R.id.open_history_menu_id,
-                R.id.downloads_row_menu_id, R.id.all_bookmarks_row_menu_id,
-                R.id.recent_tabs_menu_id, R.id.divider_line_id, R.id.feed_follow_id,
-                R.id.request_desktop_site_row_menu_id, R.id.divider_line_id, R.id.preferences_id,
+                R.id.new_incognito_tab_menu_id, R.id.all_bookmarks_menu_id,
+                R.id.recent_tabs_menu_id, R.id.open_history_menu_id, R.id.downloads_menu_id,
+                R.id.feed_follow_id, R.id.request_desktop_site_row_menu_id, R.id.preferences_id,
                 R.id.help_id};
         assertMenuItemsAreEqual(menu, expectedItems);
     }
@@ -267,16 +266,16 @@
         mAppMenuPropertiesDelegate.prepareMenu(menu, null);
 
         Integer[] expectedItems = {R.id.icon_row_menu_id, R.id.new_tab_menu_id,
-                R.id.new_incognito_tab_menu_id, R.id.divider_line_id, R.id.open_history_menu_id,
-                R.id.downloads_row_menu_id, R.id.all_bookmarks_row_menu_id,
-                R.id.recent_tabs_menu_id, R.id.divider_line_id, R.id.share_row_menu_id,
-                R.id.feed_follow_id, R.id.find_in_page_id, R.id.translate_id,
-                R.id.add_to_homescreen_id, R.id.request_desktop_site_row_menu_id,
-                R.id.divider_line_id, R.id.preferences_id, R.id.help_id};
-        Integer[] expectedTitles = {0, R.string.menu_new_tab, R.string.menu_new_incognito_tab, 0,
-                R.string.menu_history, 0, 0, R.string.menu_recent_tabs, 0, 0, R.string.menu_follow,
-                R.string.menu_find_in_page, R.string.menu_translate,
-                R.string.menu_add_to_homescreen, 0, 0, R.string.menu_settings, R.string.menu_help};
+                R.id.new_incognito_tab_menu_id, R.id.all_bookmarks_menu_id,
+                R.id.recent_tabs_menu_id, R.id.open_history_menu_id, R.id.downloads_menu_id,
+                R.id.translate_id, R.id.share_row_menu_id, R.id.feed_follow_id,
+                R.id.find_in_page_id, R.id.add_to_homescreen_id,
+                R.id.request_desktop_site_row_menu_id, R.id.preferences_id, R.id.help_id};
+        Integer[] expectedTitles = {0, R.string.menu_new_tab, R.string.menu_new_incognito_tab,
+                R.string.menu_bookmarks, R.string.menu_recent_tabs, R.string.menu_history,
+                R.string.menu_downloads, R.string.menu_translate, 0, R.string.menu_follow,
+                R.string.menu_find_in_page, R.string.menu_add_to_homescreen, 0,
+                R.string.menu_settings, R.string.menu_help};
         Integer[] expectedActionBarItems = {R.id.forward_menu_id, R.id.bookmark_this_page_id,
                 R.id.offline_page_id, R.id.info_menu_id, R.id.reload_menu_id};
         assertMenuItemsAreEqual(menu, expectedItems);
@@ -301,18 +300,16 @@
         mAppMenuPropertiesDelegate.prepareMenu(menu, null);
 
         Integer[] expectedItems = {R.id.icon_row_menu_id, R.id.new_tab_menu_id,
-                R.id.new_incognito_tab_menu_id, R.id.divider_line_id,
-                R.id.all_bookmarks_row_menu_id, R.id.open_history_menu_id,
-                R.id.downloads_row_menu_id, R.id.recent_tabs_menu_id, R.id.divider_line_id,
+                R.id.new_incognito_tab_menu_id, R.id.all_bookmarks_menu_id,
+                R.id.recent_tabs_menu_id, R.id.open_history_menu_id, R.id.downloads_menu_id,
                 R.id.translate_id, R.id.share_row_menu_id, R.id.feed_follow_id,
                 R.id.find_in_page_id, R.id.add_to_homescreen_id,
-                R.id.request_desktop_site_row_menu_id, R.id.divider_line_id, R.id.preferences_id,
-                R.id.help_id};
-        Integer[] expectedTitles = {0, R.string.menu_new_tab, R.string.menu_new_incognito_tab, 0,
-                R.string.menu_history, 0, 0, R.string.menu_recent_tabs, 0, 0, R.string.menu_follow,
-                R.string.menu_find_in_page, R.string.menu_translate,
-                R.string.menu_add_to_homescreen_install, 0, 0, R.string.menu_settings,
-                R.string.menu_help};
+                R.id.request_desktop_site_row_menu_id, R.id.preferences_id, R.id.help_id};
+        Integer[] expectedTitles = {0, R.string.menu_new_tab, R.string.menu_new_incognito_tab,
+                R.string.menu_bookmarks, R.string.menu_recent_tabs, R.string.menu_history,
+                R.string.menu_downloads, R.string.menu_translate, 0, R.string.menu_follow,
+                R.string.menu_find_in_page, R.string.menu_add_to_homescreen_install, 0,
+                R.string.menu_settings, R.string.menu_help};
         Integer[] expectedActionBarItems = {R.id.forward_menu_id, R.id.bookmark_this_page_id,
                 R.id.offline_page_id, R.id.info_menu_id, R.id.reload_menu_id};
         assertMenuItemsAreEqual(menu, expectedItems);
@@ -334,12 +331,12 @@
         mAppMenuPropertiesDelegate.prepareMenu(menu, null);
 
         Integer[] expectedItems = {R.id.icon_row_menu_id, R.id.new_tab_menu_id,
-                R.id.new_incognito_tab_menu_id, R.id.divider_line_id, R.id.open_history_menu_id,
-                R.id.downloads_row_menu_id, R.id.all_bookmarks_row_menu_id,
-                R.id.recent_tabs_menu_id, R.id.divider_line_id, R.id.share_row_menu_id,
-                R.id.feed_follow_id, R.id.find_in_page_id, R.id.translate_id,
-                R.id.add_to_homescreen_id, R.id.request_desktop_site_row_menu_id,
-                R.id.divider_line_id, R.id.preferences_id, R.id.help_id, R.id.managed_by_menu_id};
+                R.id.new_incognito_tab_menu_id, R.id.all_bookmarks_menu_id,
+                R.id.recent_tabs_menu_id, R.id.open_history_menu_id, R.id.downloads_menu_id,
+                R.id.translate_id, R.id.share_row_menu_id, R.id.feed_follow_id,
+                R.id.find_in_page_id, R.id.add_to_homescreen_id,
+                R.id.request_desktop_site_row_menu_id, R.id.preferences_id, R.id.help_id,
+                R.id.managed_by_menu_id};
         assertMenuItemsAreEqual(menu, expectedItems);
     }
 
@@ -373,7 +370,8 @@
         mAppMenuPropertiesDelegate.prepareMenu(menu, null);
 
         Integer[] expectedItems = {R.id.update_menu_id, R.id.new_tab_menu_id,
-                R.id.new_incognito_tab_menu_id, R.id.recent_tabs_menu_id, R.id.open_history_menu_id,
+                R.id.new_incognito_tab_menu_id, R.id.all_bookmarks_menu_id,
+                R.id.recent_tabs_menu_id, R.id.open_history_menu_id, R.id.downloads_menu_id,
                 R.id.translate_id, R.id.feed_follow_id, R.id.find_in_page_id,
                 R.id.add_to_homescreen_id, R.id.reader_mode_prefs_id, R.id.preferences_id,
                 R.id.help_id};
@@ -383,6 +381,7 @@
     @Test
     @Config(qualifiers = "sw320dp")
     public void testPageMenuItems_Phone_RegularPage_regroup() {
+        CachedFeatureFlags.setForTesting(ChromeFeatureList.TABBED_APP_OVERFLOW_MENU_REGROUP, true);
         setUpMocksForPageMenu();
         setMenuOptions(false /*isNativePage*/, true /*showTranslate*/, true /*showUpdate*/,
                 true /*showMoveToOtherWindow*/, false /*showReaderModePrefs*/,
@@ -408,7 +407,63 @@
 
     @Test
     @Config(qualifiers = "sw320dp")
+    public void testPageMenuItems_Phone_RegularPage_backward_button_action_bar() {
+        CachedFeatureFlags.setForTesting(ChromeFeatureList.TABBED_APP_OVERFLOW_MENU_REGROUP, true);
+        AppMenuPropertiesDelegateImpl.ACTION_BAR_VARIATION.setForTesting("backward_button");
+        setUpMocksForPageMenu();
+        setMenuOptions(false /*isNativePage*/, true /*showTranslate*/, false /*showUpdate*/,
+                false /*showMoveToOtherWindow*/, false /*showReaderModePrefs*/,
+                true /*showAddToHomeScreen*/, false /*showPaintPreview*/);
+
+        Assert.assertEquals(MenuGroup.PAGE_MENU, mAppMenuPropertiesDelegate.getMenuGroup());
+        Menu menu = createTestMenu();
+        mAppMenuPropertiesDelegate.prepareMenu(menu, null);
+
+        Integer[] expectedItems = {R.id.icon_row_menu_id, R.id.new_tab_menu_id,
+                R.id.new_incognito_tab_menu_id, R.id.divider_line_id, R.id.open_history_menu_id,
+                R.id.downloads_row_menu_id, R.id.all_bookmarks_row_menu_id,
+                R.id.recent_tabs_menu_id, R.id.divider_line_id, R.id.share_row_menu_id,
+                R.id.feed_follow_id, R.id.find_in_page_id, R.id.translate_id,
+                R.id.add_to_homescreen_id, R.id.request_desktop_site_row_menu_id,
+                R.id.divider_line_id, R.id.preferences_id, R.id.info_id, R.id.help_id};
+        Integer[] expectedActionBarItems = {R.id.backward_menu_id, R.id.forward_menu_id,
+                R.id.offline_page_id, R.id.bookmark_this_page_id, R.id.reload_menu_id};
+        assertMenuItemsAreEqual(menu, expectedItems);
+        assertActionBarItemsAreEqual(menu, expectedActionBarItems);
+    }
+
+    @Test
+    @Config(qualifiers = "sw320dp")
+    public void testPageMenuItems_Phone_RegularPage_share_button_action_bar() {
+        CachedFeatureFlags.setForTesting(ChromeFeatureList.TABBED_APP_OVERFLOW_MENU_REGROUP, true);
+        AppMenuPropertiesDelegateImpl.ACTION_BAR_VARIATION.setForTesting("share_button");
+        setUpMocksForPageMenu();
+        setMenuOptions(false /*isNativePage*/, true /*showTranslate*/, false /*showUpdate*/,
+                false /*showMoveToOtherWindow*/, false /*showReaderModePrefs*/,
+                true /*showAddToHomeScreen*/, false /*showPaintPreview*/);
+
+        Assert.assertEquals(MenuGroup.PAGE_MENU, mAppMenuPropertiesDelegate.getMenuGroup());
+        Menu menu = createTestMenu();
+        mAppMenuPropertiesDelegate.prepareMenu(menu, null);
+
+        Integer[] expectedItems = {R.id.icon_row_menu_id, R.id.new_tab_menu_id,
+                R.id.new_incognito_tab_menu_id, R.id.divider_line_id, R.id.open_history_menu_id,
+                R.id.downloads_row_menu_id, R.id.all_bookmarks_row_menu_id,
+                R.id.recent_tabs_menu_id, R.id.divider_line_id, R.id.find_in_page_id,
+                R.id.feed_follow_id, R.id.translate_id, R.id.add_to_homescreen_id,
+                R.id.request_desktop_site_row_menu_id, R.id.divider_line_id, R.id.preferences_id,
+                R.id.info_id, R.id.help_id};
+        Integer[] expectedActionBarItems = {R.id.forward_menu_id, R.id.bookmark_this_page_id,
+                R.id.offline_page_id, R.id.share_menu_button_id, R.id.reload_menu_id};
+        assertMenuItemsAreEqual(menu, expectedItems);
+        assertActionBarItemsAreEqual(menu, expectedActionBarItems);
+    }
+
+    @Test
+    @Config(qualifiers = "sw320dp")
     public void testPageMenuItems_Phone_RegularPage_threebutton_actionbar() {
+        CachedFeatureFlags.setForTesting(ChromeFeatureList.TABBED_APP_OVERFLOW_MENU_REGROUP, true);
+        AppMenuPropertiesDelegateImpl.ACTION_BAR_VARIATION.setForTesting("");
         CachedFeatureFlags.setForTesting(
                 ChromeFeatureList.TABBED_APP_OVERFLOW_MENU_THREE_BUTTON_ACTIONBAR, true);
         AppMenuPropertiesDelegateImpl.THREE_BUTTON_ACTION_BAR_VARIATION.setForTesting(
@@ -438,10 +493,74 @@
 
     @Test
     @Config(qualifiers = "sw320dp")
+    public void testPageMenuItems_Phone_RegularPage_threebutton_actionbar_backward_actionbar() {
+        CachedFeatureFlags.setForTesting(ChromeFeatureList.TABBED_APP_OVERFLOW_MENU_REGROUP, true);
+        CachedFeatureFlags.setForTesting(
+                ChromeFeatureList.TABBED_APP_OVERFLOW_MENU_THREE_BUTTON_ACTIONBAR, true);
+        AppMenuPropertiesDelegateImpl.ACTION_BAR_VARIATION.setForTesting("backward_button");
+        AppMenuPropertiesDelegateImpl.THREE_BUTTON_ACTION_BAR_VARIATION.setForTesting(
+                "action_chip_view");
+        setUpMocksForPageMenu();
+        setMenuOptions(false /*isNativePage*/, true /*showTranslate*/, true /*showUpdate*/,
+                true /*showMoveToOtherWindow*/, false /*showReaderModePrefs*/,
+                true /*showAddToHomeScreen*/, true /*showPaintPreview*/);
+
+        Assert.assertEquals(MenuGroup.PAGE_MENU, mAppMenuPropertiesDelegate.getMenuGroup());
+        Menu menu = createTestMenu();
+        mAppMenuPropertiesDelegate.prepareMenu(menu, null);
+
+        Integer[] expectedItems = {R.id.icon_row_menu_id, R.id.update_menu_id, R.id.new_tab_menu_id,
+                R.id.new_incognito_tab_menu_id, R.id.move_to_other_window_menu_id,
+                R.id.divider_line_id, R.id.open_history_menu_id, R.id.downloads_row_menu_id,
+                R.id.all_bookmarks_row_menu_id, R.id.recent_tabs_menu_id, R.id.divider_line_id,
+                R.id.share_row_menu_id, R.id.feed_follow_id, R.id.paint_preview_show_id,
+                R.id.find_in_page_id, R.id.translate_id, R.id.add_to_homescreen_id,
+                R.id.request_desktop_site_row_menu_id, R.id.divider_line_id, R.id.preferences_id,
+                R.id.info_id, R.id.help_id};
+        Integer[] expectedActionBarItems = {
+                R.id.backward_menu_id, R.id.forward_menu_id, R.id.reload_menu_id};
+        assertMenuItemsAreEqual(menu, expectedItems);
+    }
+
+    @Test
+    @Config(qualifiers = "sw320dp")
+    public void testPageMenuItems_Phone_RegularPage_threebutton_actionbar_share_actionbar() {
+        CachedFeatureFlags.setForTesting(ChromeFeatureList.TABBED_APP_OVERFLOW_MENU_REGROUP, true);
+        CachedFeatureFlags.setForTesting(
+                ChromeFeatureList.TABBED_APP_OVERFLOW_MENU_THREE_BUTTON_ACTIONBAR, true);
+        AppMenuPropertiesDelegateImpl.ACTION_BAR_VARIATION.setForTesting("share_button");
+        AppMenuPropertiesDelegateImpl.THREE_BUTTON_ACTION_BAR_VARIATION.setForTesting(
+                "destination_chip_view");
+        setUpMocksForPageMenu();
+        setMenuOptions(false /*isNativePage*/, true /*showTranslate*/, true /*showUpdate*/,
+                true /*showMoveToOtherWindow*/, false /*showReaderModePrefs*/,
+                true /*showAddToHomeScreen*/, true /*showPaintPreview*/);
+
+        Assert.assertEquals(MenuGroup.PAGE_MENU, mAppMenuPropertiesDelegate.getMenuGroup());
+        Menu menu = createTestMenu();
+        mAppMenuPropertiesDelegate.prepareMenu(menu, null);
+
+        Integer[] expectedItems = {R.id.icon_row_menu_id, R.id.update_menu_id, R.id.new_tab_menu_id,
+                R.id.new_incognito_tab_menu_id, R.id.move_to_other_window_menu_id,
+                R.id.divider_line_id, R.id.open_history_menu_id, R.id.downloads_row_menu_id,
+                R.id.all_bookmarks_row_menu_id, R.id.recent_tabs_menu_id, R.id.divider_line_id,
+                R.id.feed_follow_id, R.id.paint_preview_show_id, R.id.find_in_page_id,
+                R.id.translate_id, R.id.add_to_homescreen_id, R.id.request_desktop_site_row_menu_id,
+                R.id.divider_line_id, R.id.preferences_id, R.id.info_id, R.id.help_id};
+        Integer[] expectedActionBarItems = {
+                R.id.forward_menu_id, R.id.share_menu_button_id, R.id.reload_menu_id};
+        assertMenuItemsAreEqual(menu, expectedItems);
+        assertActionBarItemsAreEqual(menu, expectedActionBarItems);
+    }
+
+    @Test
+    @Config(qualifiers = "sw320dp")
     public void testPageMenuItems_Phone_RegularPage_threebutton_actionbar_add_to_menuitem() {
+        CachedFeatureFlags.setForTesting(ChromeFeatureList.TABBED_APP_OVERFLOW_MENU_REGROUP, true);
         CachedFeatureFlags.setForTesting(
                 ChromeFeatureList.TABBED_APP_OVERFLOW_MENU_THREE_BUTTON_ACTIONBAR, true);
         CachedFeatureFlags.setForTesting(ChromeFeatureList.READ_LATER, true);
+        AppMenuPropertiesDelegateImpl.ACTION_BAR_VARIATION.setForTesting("share_button");
         AppMenuPropertiesDelegateImpl.THREE_BUTTON_ACTION_BAR_VARIATION.setForTesting(
                 "add_to_option");
         setUpMocksForPageMenu();
@@ -458,11 +577,11 @@
                 R.id.divider_line_id, R.id.open_history_menu_id, R.id.downloads_row_menu_id,
                 R.id.all_bookmarks_row_menu_id, R.id.recent_tabs_menu_id,
                 R.id.add_to_divider_line_id, R.id.add_to_menu_id, R.id.divider_line_id,
-                R.id.share_row_menu_id, R.id.feed_follow_id, R.id.paint_preview_show_id,
-                R.id.find_in_page_id, R.id.translate_id, R.id.request_desktop_site_row_menu_id,
-                R.id.divider_line_id, R.id.preferences_id, R.id.help_id};
+                R.id.feed_follow_id, R.id.paint_preview_show_id, R.id.find_in_page_id,
+                R.id.translate_id, R.id.request_desktop_site_row_menu_id, R.id.divider_line_id,
+                R.id.preferences_id, R.id.info_id, R.id.help_id};
         Integer[] expectedActionBarItems = {
-                R.id.forward_menu_id, R.id.info_menu_id, R.id.reload_menu_id};
+                R.id.forward_menu_id, R.id.share_menu_button_id, R.id.reload_menu_id};
         Integer[] expectedAddToItems = {R.id.add_to_bookmarks_menu_id,
                 R.id.add_to_reading_list_menu_id, R.id.add_to_downloads_menu_id,
                 R.id.add_to_homescreen_menu_id};
@@ -477,8 +596,10 @@
     @Config(qualifiers = "sw320dp")
     public void
     testPageMenuItems_Phone_RegularPage_threebutton_actionbar_add_to_menuitem_intall_app() {
+        CachedFeatureFlags.setForTesting(ChromeFeatureList.TABBED_APP_OVERFLOW_MENU_REGROUP, true);
         CachedFeatureFlags.setForTesting(
                 ChromeFeatureList.TABBED_APP_OVERFLOW_MENU_THREE_BUTTON_ACTIONBAR, true);
+        AppMenuPropertiesDelegateImpl.ACTION_BAR_VARIATION.setForTesting("share_button");
         AppMenuPropertiesDelegateImpl.THREE_BUTTON_ACTION_BAR_VARIATION.setForTesting(
                 "add_to_option");
         setUpMocksForPageMenu();
@@ -499,12 +620,11 @@
                 R.id.divider_line_id, R.id.open_history_menu_id, R.id.downloads_row_menu_id,
                 R.id.all_bookmarks_row_menu_id, R.id.recent_tabs_menu_id,
                 R.id.add_to_divider_line_id, R.id.add_to_menu_id, R.id.install_app_id,
-                R.id.divider_line_id, R.id.share_row_menu_id, R.id.feed_follow_id,
-                R.id.paint_preview_show_id, R.id.find_in_page_id, R.id.translate_id,
-                R.id.request_desktop_site_row_menu_id, R.id.divider_line_id, R.id.preferences_id,
-                R.id.help_id};
+                R.id.divider_line_id, R.id.feed_follow_id, R.id.paint_preview_show_id,
+                R.id.find_in_page_id, R.id.translate_id, R.id.request_desktop_site_row_menu_id,
+                R.id.divider_line_id, R.id.preferences_id, R.id.info_id, R.id.help_id};
         Integer[] expectedActionBarItems = {
-                R.id.forward_menu_id, R.id.info_menu_id, R.id.reload_menu_id};
+                R.id.forward_menu_id, R.id.share_menu_button_id, R.id.reload_menu_id};
         Integer[] expectedAddToItems = {
                 R.id.add_to_bookmarks_menu_id, R.id.add_to_downloads_menu_id};
         assertMenuItemsAreEqual(menu, expectedItems);
@@ -581,12 +701,11 @@
         mAppMenuPropertiesDelegate.prepareMenu(menu, null);
 
         Integer[] expectedItems = {R.id.icon_row_menu_id, R.id.new_tab_menu_id,
-                R.id.new_incognito_tab_menu_id, R.id.divider_line_id, R.id.open_history_menu_id,
-                R.id.all_bookmarks_row_menu_id, R.id.downloads_row_menu_id,
-                R.id.recent_tabs_menu_id, R.id.divider_line_id, R.id.share_row_menu_id,
-                R.id.feed_follow_id, R.id.get_image_descriptions_id, R.id.find_in_page_id,
-                R.id.add_to_homescreen_id, R.id.request_desktop_site_row_menu_id,
-                R.id.divider_line_id, R.id.preferences_id, R.id.help_id};
+                R.id.new_incognito_tab_menu_id, R.id.all_bookmarks_menu_id,
+                R.id.recent_tabs_menu_id, R.id.open_history_menu_id, R.id.downloads_menu_id,
+                R.id.share_row_menu_id, R.id.feed_follow_id, R.id.get_image_descriptions_id,
+                R.id.find_in_page_id, R.id.add_to_homescreen_id,
+                R.id.request_desktop_site_row_menu_id, R.id.preferences_id, R.id.help_id};
 
         assertMenuItemsAreEqual(menu, expectedItems);
 
@@ -745,6 +864,10 @@
                 AppMenuSimilarSelectionType.NO_MATCH,
                 mAppMenuPropertiesDelegate.findSimilarSelectionPattern(
                         R.id.downloads_menu_id, R.id.all_bookmarks_menu_id));
+        Assert.assertEquals("Should no match for all bookmarks then share",
+                AppMenuSimilarSelectionType.NO_MATCH,
+                mAppMenuPropertiesDelegate.findSimilarSelectionPattern(
+                        R.id.all_bookmarks_menu_id, R.id.share_menu_button_id));
         Assert.assertEquals("Should no match for new tab then find in page",
                 AppMenuSimilarSelectionType.NO_MATCH,
                 mAppMenuPropertiesDelegate.findSimilarSelectionPattern(
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/gsa/GSAStateUnitTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/gsa/GSAStateUnitTest.java
index 7ce610b..3d90b329 100644
--- a/chrome/android/junit/src/org/chromium/chrome/browser/gsa/GSAStateUnitTest.java
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/gsa/GSAStateUnitTest.java
@@ -104,4 +104,59 @@
 
         Assert.assertFalse(mGsaState.canAgsaHandleIntent(intent));
     }
+
+    @Test
+    public void parseAgsaMajorMinorVersionAsInteger() {
+        String versionName = "11.7";
+        Integer value = mGsaState.parseAgsaMajorMinorVersionAsInteger(versionName);
+        Assert.assertNotNull(value);
+        Assert.assertEquals("Major/minor verisons should be parsed correctly.", 11007, (int) value);
+
+        versionName = "12.72.100.1";
+        value = mGsaState.parseAgsaMajorMinorVersionAsInteger(versionName);
+        Assert.assertNotNull(value);
+        Assert.assertEquals("Verisons after major/minor should be ignored.", 12072, (int) value);
+
+        versionName = "999.999";
+        value = mGsaState.parseAgsaMajorMinorVersionAsInteger(versionName);
+        Assert.assertNotNull(value);
+        Assert.assertEquals("Test the upper edge case.", 999999, (int) value);
+
+        versionName = "0.0";
+        value = mGsaState.parseAgsaMajorMinorVersionAsInteger(versionName);
+        Assert.assertNotNull(value);
+        Assert.assertEquals("Test the lower edge case.", 0, (int) value);
+
+        versionName = "0.1";
+        value = mGsaState.parseAgsaMajorMinorVersionAsInteger(versionName);
+        Assert.assertNotNull(value);
+        Assert.assertEquals("Test 0 for major.", 1, (int) value);
+
+        versionName = "1.0";
+        value = mGsaState.parseAgsaMajorMinorVersionAsInteger(versionName);
+        Assert.assertNotNull(value);
+        Assert.assertEquals("Test 0 for minor.", 1000, (int) value);
+
+        // Exceed maximum for both major/minor.
+        versionName = "1000.999";
+        value = mGsaState.parseAgsaMajorMinorVersionAsInteger(versionName);
+        Assert.assertNull(value);
+        versionName = "999.9999";
+        value = mGsaState.parseAgsaMajorMinorVersionAsInteger(versionName);
+        Assert.assertNull(value);
+
+        // Formatting errors.
+        versionName = "999.";
+        value = mGsaState.parseAgsaMajorMinorVersionAsInteger(versionName);
+        Assert.assertNull(value);
+        versionName = ".999";
+        value = mGsaState.parseAgsaMajorMinorVersionAsInteger(versionName);
+        Assert.assertNull(value);
+        versionName = "999";
+        value = mGsaState.parseAgsaMajorMinorVersionAsInteger(versionName);
+        Assert.assertNull(value);
+        versionName = "12.7notavalidversion";
+        value = mGsaState.parseAgsaMajorMinorVersionAsInteger(versionName);
+        Assert.assertNull(value);
+    }
 }
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/omnibox/voice/AssistantVoiceSearchServiceUnitTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/omnibox/voice/AssistantVoiceSearchServiceUnitTest.java
index fdd45a0..ef7334a 100644
--- a/chrome/android/junit/src/org/chromium/chrome/browser/omnibox/voice/AssistantVoiceSearchServiceUnitTest.java
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/omnibox/voice/AssistantVoiceSearchServiceUnitTest.java
@@ -60,7 +60,7 @@
 @Features.EnableFeatures(ChromeFeatureList.OMNIBOX_ASSISTANT_VOICE_SEARCH)
 @CommandLineFlags.Add(BaseSwitches.DISABLE_LOW_END_DEVICE_MODE)
 public class AssistantVoiceSearchServiceUnitTest {
-    AssistantVoiceSearchService mAssistantVoiceSearchService;
+    private static final int AGSA_VERSION_NUMBER = 11007;
 
     @Rule
     public TestRule mProcessor = new Features.JUnitProcessor();
@@ -76,6 +76,7 @@
     @Mock
     IdentityManager mIdentityManager;
 
+    AssistantVoiceSearchService mAssistantVoiceSearchService;
     SharedPreferencesManager mSharedPreferencesManager;
     PackageInfo mPackageInfo;
     Context mContext;
@@ -101,6 +102,7 @@
         doReturn(true).when(mExternalAuthUtils).isGoogleSigned(IntentHandler.PACKAGE_GSA);
         doReturn(true).when(mTemplateUrlService).isDefaultSearchEngineGoogle();
         doReturn(false).when(mGsaState).isAgsaVersionBelowMinimum(any(), any());
+        doReturn(AGSA_VERSION_NUMBER).when(mGsaState).parseAgsaMajorMinorVersionAsInteger(any());
         doReturn(true).when(mGsaState).canAgsaHandleIntent(any());
         doReturn(true).when(mIdentityManager).hasPrimaryAccount();
         mSharedPreferencesManager.writeBoolean(ASSISTANT_VOICE_SEARCH_ENABLED, true);
@@ -245,6 +247,9 @@
         Assert.assertEquals(1,
                 ShadowRecordHistogram.getHistogramValueCountForTesting(
                         AssistantVoiceSearchService.USER_ELIGIBILITY_HISTOGRAM, /* eligible= */ 1));
+        Assert.assertEquals(1,
+                ShadowRecordHistogram.getHistogramValueCountForTesting(
+                        AssistantVoiceSearchService.AGSA_VERSION_HISTOGRAM, AGSA_VERSION_NUMBER));
 
         doReturn(true).when(mGsaState).isAgsaVersionBelowMinimum(any(), any());
         doReturn(false).when(mIdentityManager).hasPrimaryAccount();
@@ -252,6 +257,10 @@
         Assert.assertEquals(1,
                 ShadowRecordHistogram.getHistogramValueCountForTesting(
                         AssistantVoiceSearchService.USER_ELIGIBILITY_HISTOGRAM, /* eligible= */ 0));
+        Assert.assertEquals(2,
+                ShadowRecordHistogram.getHistogramValueCountForTesting(
+                        AssistantVoiceSearchService.AGSA_VERSION_HISTOGRAM, AGSA_VERSION_NUMBER));
+
         Assert.assertEquals(1,
                 ShadowRecordHistogram.getHistogramValueCountForTesting(
                         AssistantVoiceSearchService.USER_ELIGIBILITY_FAILURE_REASON_HISTOGRAM,
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/signin/SigninBridgeTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/signin/SigninBridgeTest.java
index 9c761c7a..f6c01499 100644
--- a/chrome/android/junit/src/org/chromium/chrome/browser/signin/SigninBridgeTest.java
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/signin/SigninBridgeTest.java
@@ -10,18 +10,27 @@
 
 import androidx.test.filters.SmallTest;
 
+import org.junit.After;
+import org.junit.Assert;
 import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.mockito.Mock;
+import org.robolectric.annotation.Config;
+import org.robolectric.annotation.Implementation;
+import org.robolectric.annotation.Implements;
 
 import org.chromium.base.metrics.UmaRecorder;
 import org.chromium.base.metrics.UmaRecorderHolder;
 import org.chromium.base.test.BaseRobolectricTestRunner;
+import org.chromium.chrome.browser.flags.ChromeFeatureList;
+import org.chromium.chrome.browser.preferences.ChromePreferenceKeys;
+import org.chromium.chrome.browser.preferences.SharedPreferencesManager;
 import org.chromium.chrome.browser.profiles.Profile;
 import org.chromium.chrome.browser.signin.services.IdentityServicesProvider;
 import org.chromium.chrome.browser.signin.services.SigninManager;
+import org.chromium.chrome.browser.signin.services.SigninPreferencesManager;
 import org.chromium.chrome.test.util.browser.signin.AccountManagerTestRule;
 import org.chromium.components.signin.metrics.AccountConsistencyPromoAction;
 import org.chromium.ui.base.WindowAndroid;
@@ -30,9 +39,25 @@
  * JUnit tests for the class {@link SigninBridge}.
  */
 @RunWith(BaseRobolectricTestRunner.class)
+@Config(shadows = {SigninBridgeTest.ShadowChromeFeatureList.class})
 public class SigninBridgeTest {
     private static final String CONTINUE_URL = "https://test-continue-url.com";
 
+    @Implements(ChromeFeatureList.class)
+    static class ShadowChromeFeatureList {
+        private static final String PARAM_NAME = "consecutive_active_dismissal_limit";
+        static final int PARAM_VALUE = 3;
+
+        @Implementation
+        public static int getFieldTrialParamByFeatureAsInt(
+                String featureName, String paramName, int defaultValue) {
+            Assert.assertEquals(ChromeFeatureList.MOBILE_IDENTITY_CONSISTENCY_VAR, featureName);
+            Assert.assertEquals(PARAM_NAME, paramName);
+            Assert.assertEquals(Integer.MAX_VALUE, defaultValue);
+            return PARAM_VALUE;
+        }
+    }
+
     @Rule
     public final AccountManagerTestRule mAccountManagerTestRule = new AccountManagerTestRule();
 
@@ -61,6 +86,11 @@
                 .thenReturn(mSigninManagerMock);
     }
 
+    @After
+    public void tearDown() {
+        SigninPreferencesManager.getInstance().clearAccountPickerBottomSheetActiveDismissalCount();
+    }
+
     @Test
     @SmallTest
     public void testAccountPickerSuppressedWhenSigninNotAllowed() {
@@ -77,6 +107,18 @@
         checkHistogramRecording(AccountConsistencyPromoAction.SUPPRESSED_NO_ACCOUNTS);
     }
 
+    @Test
+    @SmallTest
+    public void testAccountPickerSuppressedIfDismissLimitReached() {
+        when(mSigninManagerMock.isSignInAllowed()).thenReturn(true);
+        mAccountManagerTestRule.addAccount("account@test.com");
+        SharedPreferencesManager.getInstance().writeInt(
+                ChromePreferenceKeys.ACCOUNT_PICKER_BOTTOM_SHEET_ACTIVE_DISMISSAL_COUNT,
+                ShadowChromeFeatureList.PARAM_VALUE);
+        SigninBridge.openAccountPickerBottomSheet(mWindowAndroidMock, CONTINUE_URL);
+        checkHistogramRecording(AccountConsistencyPromoAction.SUPPRESSED_CONSECUTIVE_DISMISSALS);
+    }
+
     private void checkHistogramRecording(@AccountConsistencyPromoAction int action) {
         verify(mUmaRecorderMock)
                 .recordLinearHistogram("Signin.AccountConsistencyPromoAction", action, 1,
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/tabbed_mode/TabbedAppMenuPropertiesDelegateUnitTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/tabbed_mode/TabbedAppMenuPropertiesDelegateUnitTest.java
index c822bf9..df7c143 100644
--- a/chrome/android/junit/src/org/chromium/chrome/browser/tabbed_mode/TabbedAppMenuPropertiesDelegateUnitTest.java
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/tabbed_mode/TabbedAppMenuPropertiesDelegateUnitTest.java
@@ -177,12 +177,12 @@
         mTabbedAppMenuPropertiesDelegate.prepareMenu(menu, null);
 
         Integer[] expectedItems = {R.id.icon_row_menu_id, R.id.new_tab_menu_id,
-                R.id.new_incognito_tab_menu_id, R.id.divider_line_id, R.id.open_history_menu_id,
-                R.id.downloads_row_menu_id, R.id.all_bookmarks_row_menu_id,
-                R.id.recent_tabs_menu_id, R.id.divider_line_id, R.id.translate_id,
-                R.id.share_row_menu_id, R.id.feed_follow_id, R.id.find_in_page_id,
-                R.id.add_to_homescreen_id, R.id.request_desktop_site_row_menu_id,
-                R.id.divider_line_id, R.id.preferences_id, R.id.help_id, R.id.managed_by_menu_id};
+                R.id.new_incognito_tab_menu_id, R.id.all_bookmarks_menu_id,
+                R.id.recent_tabs_menu_id, R.id.open_history_menu_id, R.id.downloads_menu_id,
+                R.id.translate_id, R.id.share_row_menu_id, R.id.feed_follow_id,
+                R.id.find_in_page_id, R.id.add_to_homescreen_id,
+                R.id.request_desktop_site_row_menu_id, R.id.preferences_id, R.id.help_id,
+                R.id.managed_by_menu_id};
         assertMenuItemsAreEqual(menu, expectedItems);
     }
 
diff --git a/chrome/app/chrome_main_delegate.cc b/chrome/app/chrome_main_delegate.cc
index 826ef32..8b48730c 100644
--- a/chrome/app/chrome_main_delegate.cc
+++ b/chrome/app/chrome_main_delegate.cc
@@ -331,7 +331,7 @@
   if (command_line.HasSwitch(switches::kVersion)) {
     printf("%s %s %s\n", version_info::GetProductName().c_str(),
            version_info::GetVersionNumber().c_str(),
-           chrome::GetChannelName().c_str());
+           chrome::GetChannelName(chrome::WithExtendedStable(true)).c_str());
     return true;
   }
 
diff --git a/chrome/app/chromeos_strings.grdp b/chrome/app/chromeos_strings.grdp
index b097de90..04ab689e 100644
--- a/chrome/app/chromeos_strings.grdp
+++ b/chrome/app/chromeos_strings.grdp
@@ -5317,6 +5317,9 @@
   <message name="IDS_ACCOUNT_MANAGER_DIALOG_WELCOME_BODY" desc="Text body for the Welcome screen in Chrome OS 'Add account' dialog.">
     You can manage signed-in Google Accounts from <ph name="LINK_BEGIN">&lt;a id="osSettingsLink" href="$1<ex>https://google.com/</ex>"&gt;</ph>Settings<ph name="LINK_END">&lt;/a&gt;</ph>. Permissions you have granted to websites and apps may apply to all accounts. If you don't want sites or apps to access your account info, you can sign into your <ph name="DEVICE_TYPE">$2<ex>Chromebook</ex></ph> as a guest or browse the web in an <ph name="LINK_2_BEGIN">&lt;a id="incognitoLink" href="#"&gt;</ph>incognito window<ph name="LINK_2_END">&lt;/a&gt;</ph>.
   </message>
+  <message name="IDS_ACCOUNT_MANAGER_DIALOG_WELCOME_BODY_WITHOUT_INCOGNITO" desc="Text body for the Welcome screen in Chrome OS 'Add account' dialog without incognito link.">
+    You can manage signed-in Google Accounts from <ph name="LINK_BEGIN">&lt;a id="osSettingsLink" href="$1<ex>https://google.com/</ex>"&gt;</ph>Settings<ph name="LINK_END">&lt;/a&gt;</ph>. Permissions you have granted to websites and apps may apply to all accounts. If you don't want sites or apps to access your account info, you can sign into your <ph name="DEVICE_TYPE">$2<ex>Chromebook</ex></ph> as a guest.
+  </message>
   <message name="IDS_ACCOUNT_MANAGER_DIALOG_WELCOME_CHECKBOX" desc="Checkbox text for the Welcome screen in Chrome OS 'Add account' dialog. If user checks this checkbox, this screen will not be shown the next time they open the dialog.">
     Don't remind me next time
   </message>
diff --git a/chrome/app/chromeos_strings_grdp/IDS_ACCOUNT_MANAGER_DIALOG_WELCOME_BODY_WITHOUT_INCOGNITO.png.sha1 b/chrome/app/chromeos_strings_grdp/IDS_ACCOUNT_MANAGER_DIALOG_WELCOME_BODY_WITHOUT_INCOGNITO.png.sha1
new file mode 100644
index 0000000..bb4de6f
--- /dev/null
+++ b/chrome/app/chromeos_strings_grdp/IDS_ACCOUNT_MANAGER_DIALOG_WELCOME_BODY_WITHOUT_INCOGNITO.png.sha1
@@ -0,0 +1 @@
+52cc6864a9082b04f2fa876ab97ff615dc7aff0e
\ No newline at end of file
diff --git a/chrome/browser/BUILD.gn b/chrome/browser/BUILD.gn
index c4c4554..00c190f 100644
--- a/chrome/browser/BUILD.gn
+++ b/chrome/browser/BUILD.gn
@@ -446,8 +446,6 @@
     "download/download_target_determiner_delegate.h",
     "download/download_target_info.cc",
     "download/download_target_info.h",
-    "download/download_task_scheduler_impl.cc",
-    "download/download_task_scheduler_impl.h",
     "download/download_ui_controller.cc",
     "download/download_ui_controller.h",
     "download/download_ui_model.cc",
@@ -3452,8 +3450,6 @@
       "cart/commerce_hint_service.cc",
       "cart/commerce_hint_service.h",
       "certificate_viewer.h",
-      "chrome_browser_field_trials_desktop.cc",
-      "chrome_browser_field_trials_desktop.h",
       "chrome_process_singleton.cc",
       "chrome_process_singleton.h",
       "component_updater/intervention_policy_database_component_installer.cc",
@@ -6389,7 +6385,13 @@
       "net/nss_context.h",
     ]
     if (is_chromeos_ash) {
-      sources += [ "net/nss_context_chromeos.cc" ]
+      sources += [
+        "net/nss_context_chromeos.cc",
+        "net/nss_service_chromeos.cc",
+        "net/nss_service_chromeos.h",
+        "net/nss_service_chromeos_factory.cc",
+        "net/nss_service_chromeos_factory.h",
+      ]
     }
     if (is_linux || is_chromeos_lacros) {
       sources += [ "net/nss_context_linux.cc" ]
diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc
index 87cf329df..a572f14 100644
--- a/chrome/browser/about_flags.cc
+++ b/chrome/browser/about_flags.cc
@@ -496,9 +496,15 @@
 const FeatureEntry::FeatureParam kHideDismissButton[] = {
     {"dismiss_button", "hide"}};
 
+const FeatureEntry::FeatureParam kSuppressBottomSheet[] = {
+    {"consecutive_active_dismissal_limit", "3"}};
+
 const FeatureEntry::FeatureVariation kMobileIdentityConsistencyVariations[] = {
     {"Hide Dismiss Button", kHideDismissButton, base::size(kHideDismissButton),
-     nullptr}};
+     nullptr},
+    {"Suppress Bottom Sheet", kSuppressBottomSheet,
+     base::size(kSuppressBottomSheet), nullptr},
+};
 #endif  // OS_ANDROID
 
 #if !BUILDFLAG(IS_CHROMEOS_ASH)
@@ -2009,6 +2015,15 @@
          base::size(kPhotoPickerVideoSupportEnabledWithAnimatedThumbnails),
          nullptr}};
 
+const FeatureEntry::FeatureParam kTabbedAppOverflowMenuRegroupBackward[] = {
+    {"action_bar", "backward_button"}};
+const FeatureEntry::FeatureParam kTabbedAppOverflowMenuRegroupShare[] = {
+    {"action_bar", "share_button"}};
+const FeatureEntry::FeatureVariation kTabbedAppOverflowMenuRegroupVariations[] =
+    {{"(backward button)", kTabbedAppOverflowMenuRegroupBackward,
+      base::size(kTabbedAppOverflowMenuRegroupBackward), nullptr},
+     {"(share button)", kTabbedAppOverflowMenuRegroupShare,
+      base::size(kTabbedAppOverflowMenuRegroupShare), nullptr}};
 const FeatureEntry::FeatureParam
     kTabbedAppOverflowMenuThreeButtonActionbarAction[] = {
         {"three_button_action_bar", "action_chip_view"}};
@@ -4403,6 +4418,17 @@
 #endif  // OS_ANDROID
 
 #if defined(OS_ANDROID)
+    {"tabbed-app-overflow-menu-icons",
+     flag_descriptions::kTabbedAppOverflowMenuIconsName,
+     flag_descriptions::kTabbedAppOverflowMenuIconsDescription, kOsAndroid,
+     FEATURE_VALUE_TYPE(chrome::android::kTabbedAppOverflowMenuIcons)},
+    {"tabbed-app-overflow-menu-regroup",
+     flag_descriptions::kTabbedAppOverflowMenuRegroupName,
+     flag_descriptions::kTabbedAppOverflowMenuRegroupDescription, kOsAndroid,
+     FEATURE_WITH_PARAMS_VALUE_TYPE(
+         chrome::android::kTabbedAppOverflowMenuRegroup,
+         kTabbedAppOverflowMenuRegroupVariations,
+         "AndroidAppMenuUiRework")},
     {"tabbed-app-overflow-menu-three-button-actionbar",
      flag_descriptions::kTabbedAppOverflowMenuThreeButtonActionbarName,
      flag_descriptions::kTabbedAppOverflowMenuThreeButtonActionbarDescription,
@@ -4901,14 +4927,6 @@
      flag_descriptions::kAutofillProfileServerValidationDescription, kOsAll,
      FEATURE_VALUE_TYPE(autofill::features::kAutofillProfileServerValidation)},
 
-    {"autofill-restrict-formless-form-extraction",
-     flag_descriptions::kAutofillRestrictUnownedFieldsToFormlessCheckoutName,
-     flag_descriptions::
-         kAutofillRestrictUnownedFieldsToFormlessCheckoutDescription,
-     kOsAll,
-     FEATURE_VALUE_TYPE(
-         autofill::features::kAutofillRestrictUnownedFieldsToFormlessCheckout)},
-
 #if defined(OS_WIN)
     {"enable-windows-gaming-input-data-fetcher",
      flag_descriptions::kEnableWindowsGamingInputDataFetcherName,
diff --git a/chrome/browser/android/autofill_assistant/client_android.cc b/chrome/browser/android/autofill_assistant/client_android.cc
index ae59557..b7ebc48 100644
--- a/chrome/browser/android/autofill_assistant/client_android.cc
+++ b/chrome/browser/android/autofill_assistant/client_android.cc
@@ -53,6 +53,9 @@
 // the UI.
 const char* const kCancelActionName = "cancel";
 
+// Intent not set constant.
+const char* const kIntentNotSet = "NotSet";
+
 }  // namespace
 
 static base::android::ScopedJavaLocalRef<jobject>
@@ -84,7 +87,7 @@
     // In the case of an unexpected closing of the activity or tab, controller_
     // will not yet have been cleaned up (since that happens when a web
     // contents object gets destroyed).
-    Metrics::RecordDropOut(Metrics::DropOutReason::CONTENT_DESTROYED);
+    Metrics::RecordDropOut(Metrics::DropOutReason::CONTENT_DESTROYED, intent_);
   }
 
   Java_AutofillAssistantClient_clearNativePtr(AttachCurrentThread(),
@@ -132,6 +135,9 @@
       jonboarding_shown, /* is_direct_action = */ false, jcaller_account,
       jinitial_url, /* jusername = */ nullptr);
 
+  intent_ = trigger_context->GetScriptParameters().GetIntent().value_or(
+      kIntentNotSet);
+
   if (VLOG_IS_ON(2)) {
     std::string experiment_ids =
         base::android::ConvertJavaStringToUTF8(env, jexperiment_ids);
@@ -514,7 +520,7 @@
 
 void ClientAndroid::RecordDropOut(Metrics::DropOutReason reason) {
   if (started_)
-    Metrics::RecordDropOut(reason);
+    Metrics::RecordDropOut(reason, intent_);
 
   started_ = false;
 }
@@ -536,7 +542,7 @@
 
 void ClientAndroid::SafeDestroyControllerAndUI(Metrics::DropOutReason reason) {
   if (started_) {
-    Metrics::RecordDropOut(reason);
+    Metrics::RecordDropOut(reason, intent_);
   }
 
   DestroyUI();
diff --git a/chrome/browser/android/autofill_assistant/client_android.h b/chrome/browser/android/autofill_assistant/client_android.h
index 11de1d8..d021b91 100644
--- a/chrome/browser/android/autofill_assistant/client_android.h
+++ b/chrome/browser/android/autofill_assistant/client_android.h
@@ -165,6 +165,10 @@
   // True if Start() was called. This turns on the tracking of dropouts.
   bool started_ = false;
 
+  // Intent parameter used for tracking dropouts per intent.
+  // TODO(b/182164683) Do not store intent paramenter in |ClientAndroid|.
+  std::string intent_;
+
   // True if the UI was ever attached.
   bool has_had_ui_ = false;
 
diff --git a/chrome/browser/ash/login/screens/sync_consent_browsertest.cc b/chrome/browser/ash/login/screens/sync_consent_browsertest.cc
index 2ccb9e4..0871584 100644
--- a/chrome/browser/ash/login/screens/sync_consent_browsertest.cc
+++ b/chrome/browser/ash/login/screens/sync_consent_browsertest.cc
@@ -629,7 +629,7 @@
 
   histogram_tester_.ExpectUniqueSample(
       "OOBE.SyncConsentScreen.Behavior",
-      SyncConsentScreen::SyncScreenBehavior::kSkipFeaturePolicy, 1);
+      SyncConsentScreen::SyncScreenBehavior::kSkipPermissionsPolicy, 1);
   // We don't test SyncEnabled because this test fakes the policy disable and
   // the sync engine is still enabled.
 }
diff --git a/chrome/browser/ash/login/screens/sync_consent_screen.cc b/chrome/browser/ash/login/screens/sync_consent_screen.cc
index f9dbbf1..bca2ba8 100644
--- a/chrome/browser/ash/login/screens/sync_consent_screen.cc
+++ b/chrome/browser/ash/login/screens/sync_consent_screen.cc
@@ -131,7 +131,7 @@
       return false;
     case SyncScreenBehavior::kSkipNonGaiaAccount:
     case SyncScreenBehavior::kSkipPublicAccount:
-    case SyncScreenBehavior::kSkipFeaturePolicy:
+    case SyncScreenBehavior::kSkipPermissionsPolicy:
     case SyncScreenBehavior::kSkipAndEnableNonBrandedBuild:
     case SyncScreenBehavior::kSkipAndEnableEmphemeralUser:
     case SyncScreenBehavior::kSkipAndEnableScreenPolicy:
@@ -256,7 +256,7 @@
       return;
     case SyncScreenBehavior::kSkipNonGaiaAccount:
     case SyncScreenBehavior::kSkipPublicAccount:
-    case SyncScreenBehavior::kSkipFeaturePolicy:
+    case SyncScreenBehavior::kSkipPermissionsPolicy:
       // Nothing to do.
       return;
     case SyncScreenBehavior::kSkipAndEnableNonBrandedBuild:
@@ -308,7 +308,7 @@
 
   // Skip if sync-the-feature is disabled by policy.
   if (IsProfileSyncDisabledByPolicy())
-    return SyncScreenBehavior::kSkipFeaturePolicy;
+    return SyncScreenBehavior::kSkipPermissionsPolicy;
 
   if (IsProfileSyncEngineInitialized())
     return SyncScreenBehavior::kShow;
diff --git a/chrome/browser/ash/login/screens/sync_consent_screen.h b/chrome/browser/ash/login/screens/sync_consent_screen.h
index f51b603..ec6adef 100644
--- a/chrome/browser/ash/login/screens/sync_consent_screen.h
+++ b/chrome/browser/ash/login/screens/sync_consent_screen.h
@@ -35,7 +35,7 @@
     kShow = 1,
     kSkipNonGaiaAccount = 2,
     kSkipPublicAccount = 3,
-    kSkipFeaturePolicy = 4,
+    kSkipPermissionsPolicy = 4,
     kSkipAndEnableNonBrandedBuild = 5,
     kSkipAndEnableEmphemeralUser = 6,
     kSkipAndEnableScreenPolicy = 7,
diff --git a/chrome/browser/autofill/autofill_interactive_uitest.cc b/chrome/browser/autofill/autofill_interactive_uitest.cc
index b9d64ea0..673edb3b3 100644
--- a/chrome/browser/autofill/autofill_interactive_uitest.cc
+++ b/chrome/browser/autofill/autofill_interactive_uitest.cc
@@ -2516,32 +2516,9 @@
   ExpectFieldValue("CREDIT_CARD_EXP_4_DIGIT_YEAR", "2999");
 }
 
-// Test params:
-//  - bool restrict_unowned_fields_: whether autofill of unowned fields is
-//        restricted to checkout related pages.
-class AutofillRestrictUnownedFieldsTest
-    : public AutofillInteractiveTestBase,
-      public testing::WithParamInterface<bool> {
- protected:
-  AutofillRestrictUnownedFieldsTest() : restrict_unowned_fields_(GetParam()) {
-    std::vector<base::Feature> enabled;
-    std::vector<base::Feature> disabled;
-    (restrict_unowned_fields_ ? enabled : disabled)
-        .push_back(features::kAutofillRestrictUnownedFieldsToFormlessCheckout);
-    scoped_feature_list_.InitWithFeatures(enabled, disabled);
-  }
-
-  const bool restrict_unowned_fields_;
-
- private:
-  base::test::ScopedFeatureList scoped_feature_list_;
-};
-
 // Test that we do not fill formless non-checkout forms when we enable the
 // formless form restrictions.
-IN_PROC_BROWSER_TEST_P(AutofillRestrictUnownedFieldsTest, NoAutocomplete) {
-  SCOPED_TRACE(base::StringPrintf("restrict_unowned_fields_ = %d",
-                                  restrict_unowned_fields_));
+IN_PROC_BROWSER_TEST_F(AutofillInteractiveTestBase, NoAutocomplete) {
   base::HistogramTester histogram;
 
   CreateTestProfile();
@@ -2550,22 +2527,7 @@
       embedded_test_server()->GetURL("/autofill/formless_no_autocomplete.html");
   ASSERT_NO_FATAL_FAILURE(ui_test_utils::NavigateToURL(browser(), url));
 
-  // Of unowned forms are restricted, then there are no forms detected.
-  if (restrict_unowned_fields_) {
-    metrics::SubprocessMetricsProvider::MergeHistogramDeltasForTesting();
-    // We should only have samples saying that some elements were filtered.
-    auto buckets =
-        histogram.GetAllSamples("Autofill.UnownedFieldsWereFiltered");
-    ASSERT_EQ(1u, buckets.size());
-    EXPECT_EQ(1, buckets[0].min);  // The "true" bucket.
-
-    ASSERT_EQ(0U, GetAutofillManager()->NumFormsDetected());
-    return;
-  }
-
-  // If we reach this point, then unowned forms are not restricted. There
-  // should a form we can trigger fill on (using the firstname field)
-  ASSERT_FALSE(restrict_unowned_fields_);
+  // There should a form we can trigger fill on (using the firstname field).
   ASSERT_EQ(1U, GetAutofillManager()->NumFormsDetected());
   TriggerFormFill("firstname");
 
@@ -2573,15 +2535,14 @@
   bool has_filled = false;
   ASSERT_TRUE(content::ExecuteScriptAndExtractBool(GetWebContents(),
                                                    "hasFilled()", &has_filled));
-  EXPECT_EQ(has_filled, !restrict_unowned_fields_);
+  EXPECT_TRUE(has_filled);
 
   metrics::SubprocessMetricsProvider::MergeHistogramDeltasForTesting();
 
   // If only some form fields are tagged with autocomplete types, then the
   // number of input elements will not match the number of fields when autofill
   // triees to preview or fill.
-  histogram.ExpectUniqueSample("Autofill.NumElementsMatchesNumFields",
-                               !restrict_unowned_fields_, 2);
+  histogram.ExpectUniqueSample("Autofill.NumElementsMatchesNumFields", true, 2);
 
   ExpectFieldValue("firstname", "Milton");
   ExpectFieldValue("address", "4120 Freidrich Lane");
@@ -2597,9 +2558,7 @@
 // version of the the test in that at least one of the fields has an
 // autocomplete attribute, so autofill will always be aware of the existence
 // of the form.
-IN_PROC_BROWSER_TEST_P(AutofillRestrictUnownedFieldsTest, SomeAutocomplete) {
-  SCOPED_TRACE(base::StringPrintf("restrict_unowned_fields_ = %d",
-                                  restrict_unowned_fields_));
+IN_PROC_BROWSER_TEST_F(AutofillInteractiveTestBase, SomeAutocomplete) {
   CreateTestProfile();
 
   base::HistogramTester histogram;
@@ -2615,52 +2574,27 @@
   bool has_filled = false;
   ASSERT_TRUE(content::ExecuteScriptAndExtractBool(GetWebContents(),
                                                    "hasFilled()", &has_filled));
-  EXPECT_EQ(has_filled, !restrict_unowned_fields_);
+  EXPECT_TRUE(has_filled);
 
   metrics::SubprocessMetricsProvider::MergeHistogramDeltasForTesting();
 
   // If only some form fields are tagged with autocomplete types, then the
   // number of input elements will not match the number of fields when autofill
   // triees to preview or fill.
-  histogram.ExpectUniqueSample("Autofill.NumElementsMatchesNumFields",
-                               !restrict_unowned_fields_, 2);
+  histogram.ExpectUniqueSample("Autofill.NumElementsMatchesNumFields", true, 2);
 
-  // http://crbug.com/841784
-  // Formless fields with autocomplete attributes don't work because the
-  // extracted form and the form to be previewed/filled end up with a mismatched
-  // number of fields and early abort.
-  // This is fixed when !restrict_unowned_fields_
-  if (restrict_unowned_fields_) {
-    // We should only have samples saying that some elements were filtered.
-    auto buckets =
-        histogram.GetAllSamples("Autofill.UnownedFieldsWereFiltered");
-    ASSERT_EQ(1u, buckets.size());
-    EXPECT_EQ(1, buckets[0].min);  // The "true" bucket.
-
-    ExpectFieldValue("firstname", "M");
-    ExpectFieldValue("address", "");
-    ExpectFieldValue("state", "--");
-    ExpectFieldValue("city", "");
-    ExpectFieldValue("company", "");
-    ExpectFieldValue("email", "");
-    ExpectFieldValue("phone", "");
-  } else {
-    ExpectFieldValue("firstname", "Milton");
-    ExpectFieldValue("address", "4120 Freidrich Lane");
-    ExpectFieldValue("state", "TX");
-    ExpectFieldValue("city", "Austin");
-    ExpectFieldValue("company", "Initech");
-    ExpectFieldValue("email", "red.swingline@initech.com");
-    ExpectFieldValue("phone", "15125551234");
-  }
+  ExpectFieldValue("firstname", "Milton");
+  ExpectFieldValue("address", "4120 Freidrich Lane");
+  ExpectFieldValue("state", "TX");
+  ExpectFieldValue("city", "Austin");
+  ExpectFieldValue("company", "Initech");
+  ExpectFieldValue("email", "red.swingline@initech.com");
+  ExpectFieldValue("phone", "15125551234");
 }
 
 // Test that we do not fill formless non-checkout forms when we enable the
 // formless form restrictions.
-IN_PROC_BROWSER_TEST_P(AutofillRestrictUnownedFieldsTest,
-                       DISABLED_AllAutocomplete) {
-  SCOPED_TRACE(base::StringPrintf("restrict_unowned_fields_ = %d",
-                                  restrict_unowned_fields_));
+IN_PROC_BROWSER_TEST_F(AutofillInteractiveTestBase, DISABLED_AllAutocomplete) {
   CreateTestProfile();
 
   base::HistogramTester histogram;
@@ -2684,14 +2618,6 @@
   // available to be filled.
   histogram.ExpectUniqueSample("Autofill.NumElementsMatchesNumFields", true, 2);
 
-  if (restrict_unowned_fields_) {
-    // We should only have samples saying that no elements were filtered.
-    auto buckets =
-        histogram.GetAllSamples("Autofill.UnownedFieldsWereFiltered");
-    ASSERT_EQ(1u, buckets.size());
-    EXPECT_EQ(0, buckets[0].min);  // The "false" bucket.
-  }
-
   ExpectFieldValue("firstname", "Milton");
   ExpectFieldValue("address", "4120 Freidrich Lane");
   ExpectFieldValue("state", "TX");
@@ -3533,7 +3459,4 @@
                          AutofillDynamicFormReplacementInteractiveTest,
                          testing::Bool());
 
-INSTANTIATE_TEST_SUITE_P(All,
-                         AutofillRestrictUnownedFieldsTest,
-                         testing::Bool());
 }  // namespace autofill
diff --git a/chrome/browser/autofill/form_structure_browsertest.cc b/chrome/browser/autofill/form_structure_browsertest.cc
index 92133ae..efa86354 100644
--- a/chrome/browser/autofill/form_structure_browsertest.cc
+++ b/chrome/browser/autofill/form_structure_browsertest.cc
@@ -185,7 +185,7 @@
        // TODO(crbug/1165780): Remove once shared labels are launched.
        features::kAutofillEnableSupportForParsingWithSharedLabels},
       // Disabled
-      {features::kAutofillRestrictUnownedFieldsToFormlessCheckout});
+      {});
 }
 
 FormStructureBrowserTest::~FormStructureBrowserTest() {}
diff --git a/chrome/browser/chrome_browser_field_trials.cc b/chrome/browser/chrome_browser_field_trials.cc
index eb4c8c9..0c4ccb47b 100644
--- a/chrome/browser/chrome_browser_field_trials.cc
+++ b/chrome/browser/chrome_browser_field_trials.cc
@@ -32,8 +32,6 @@
 #include "chrome/browser/chrome_browser_field_trials_mobile.h"
 #include "chrome/browser/flags/android/cached_feature_flags.h"
 #include "chrome/common/chrome_features.h"
-#else
-#include "chrome/browser/chrome_browser_field_trials_desktop.h"
 #endif
 
 #if BUILDFLAG(IS_CHROMEOS_ASH)
@@ -75,8 +73,6 @@
 
 #if defined(OS_ANDROID)
   chrome::SetupMobileFieldTrials();
-#else
-  chrome::SetupDesktopFieldTrials();
 #endif
 }
 
diff --git a/chrome/browser/chrome_browser_field_trials_desktop.cc b/chrome/browser/chrome_browser_field_trials_desktop.cc
deleted file mode 100644
index 79c0af4..0000000
--- a/chrome/browser/chrome_browser_field_trials_desktop.cc
+++ /dev/null
@@ -1,49 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chrome/browser/chrome_browser_field_trials_desktop.h"
-
-#include <map>
-#include <string>
-
-#include "base/command_line.h"
-#include "base/feature_list.h"
-#include "base/metrics/field_trial.h"
-#include "base/metrics/field_trial_params.h"
-#include "chrome/common/chrome_paths.h"
-#include "chrome/common/chrome_switches.h"
-#include "components/metrics/persistent_system_profile.h"
-#include "components/variations/variations_associated_data.h"
-#include "content/public/common/content_switches.h"
-
-namespace chrome {
-
-namespace {
-
-void SetupStunProbeTrial() {
-  std::map<std::string, std::string> params;
-  if (!variations::GetVariationParams("StunProbeTrial2", &params))
-    return;
-
-  // The parameter, used by StartStunFieldTrial, should have the following
-  // format: "request_per_ip/interval/sharedsocket/batch_size/total_batches/
-  // server1:port/server2:port/server3:port/"
-  std::string cmd_param = params["request_per_ip"] + "/" + params["interval"] +
-                          "/" + params["sharedsocket"] + "/" +
-                          params["batch_size"] + "/" + params["total_batches"] +
-                          "/" + params["server1"] + "/" + params["server2"] +
-                          "/" + params["server3"] + "/" + params["server4"] +
-                          "/" + params["server5"] + "/" + params["server6"];
-
-  base::CommandLine::ForCurrentProcess()->AppendSwitchASCII(
-      switches::kWebRtcStunProbeTrialParameter, cmd_param);
-}
-
-}  // namespace
-
-void SetupDesktopFieldTrials() {
-  SetupStunProbeTrial();
-}
-
-}  // namespace chrome
diff --git a/chrome/browser/chrome_browser_field_trials_desktop.h b/chrome/browser/chrome_browser_field_trials_desktop.h
deleted file mode 100644
index 41d5fe9..0000000
--- a/chrome/browser/chrome_browser_field_trials_desktop.h
+++ /dev/null
@@ -1,18 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROME_BROWSER_CHROME_BROWSER_FIELD_TRIALS_DESKTOP_H_
-#define CHROME_BROWSER_CHROME_BROWSER_FIELD_TRIALS_DESKTOP_H_
-
-namespace chrome {
-
-// Sets up common desktop-only field trials.
-// Add an invocation of your field trial init function to this method, or to
-// SetupFieldTrials in chrome_browser_field_trials.cc if it is for all
-// platforms.
-void SetupDesktopFieldTrials();
-
-}  // namespace chrome
-
-#endif  // CHROME_BROWSER_CHROME_BROWSER_FIELD_TRIALS_DESKTOP_H_
diff --git a/chrome/browser/chrome_content_browser_client.cc b/chrome/browser/chrome_content_browser_client.cc
index 6804f2fb..1073428f 100644
--- a/chrome/browser/chrome_content_browser_client.cc
+++ b/chrome/browser/chrome_content_browser_client.cc
@@ -5035,7 +5035,7 @@
 base::DictionaryValue ChromeContentBrowserClient::GetNetLogConstants() {
   auto platform_dict = net_log::GetPlatformConstantsForNetLog(
       base::CommandLine::ForCurrentProcess()->GetCommandLineString(),
-      chrome::GetChannelName());
+      chrome::GetChannelName(chrome::WithExtendedStable(true)));
   if (platform_dict)
     return std::move(*platform_dict);
   else
diff --git a/chrome/browser/chromeos/plugin_vm/plugin_vm_drive_image_download_service.cc b/chrome/browser/chromeos/plugin_vm/plugin_vm_drive_image_download_service.cc
index e8a80156..d0923c1 100644
--- a/chrome/browser/chromeos/plugin_vm/plugin_vm_drive_image_download_service.cc
+++ b/chrome/browser/chromeos/plugin_vm/plugin_vm_drive_image_download_service.cc
@@ -234,12 +234,17 @@
 
 void PluginVmDriveImageDownloadService::GetContentCallback(
     google_apis::DriveApiErrorCode error_code,
-    std::unique_ptr<std::string> content) {
+    std::unique_ptr<std::string> content,
+    bool first_chunk) {
   if (ErrorCodeIndicatesFailure(error_code)) {
     LOG(ERROR) << "Download failed with error code: " << (int)error_code;
     plugin_vm_installer_->OnDownloadFailed(ConvertToFailureReason(error_code));
     return;
   }
+
+  if (first_chunk)
+    ResetState();
+
   secure_hash_service_->Update(content->c_str(), content->length());
   total_bytes_downloaded_ += content->length();
 }
diff --git a/chrome/browser/chromeos/plugin_vm/plugin_vm_drive_image_download_service.h b/chrome/browser/chromeos/plugin_vm/plugin_vm_drive_image_download_service.h
index c4341abf..bf37ec8 100644
--- a/chrome/browser/chromeos/plugin_vm/plugin_vm_drive_image_download_service.h
+++ b/chrome/browser/chromeos/plugin_vm/plugin_vm_drive_image_download_service.h
@@ -69,7 +69,8 @@
   void DownloadActionCallback(google_apis::DriveApiErrorCode error_code,
                               const base::FilePath& file_path);
   void GetContentCallback(google_apis::DriveApiErrorCode error_code,
-                          std::unique_ptr<std::string> content);
+                          std::unique_ptr<std::string> content,
+                          bool first_chunk);
   void ProgressCallback(int64_t progress, int64_t total);
 
   PluginVmInstaller* plugin_vm_installer_;
diff --git a/chrome/browser/chromeos/plugin_vm/plugin_vm_installer_unittest.cc b/chrome/browser/chromeos/plugin_vm/plugin_vm_installer_unittest.cc
index 591d75f..97721ee 100644
--- a/chrome/browser/chromeos/plugin_vm/plugin_vm_installer_unittest.cc
+++ b/chrome/browser/chromeos/plugin_vm/plugin_vm_installer_unittest.cc
@@ -111,7 +111,9 @@
 
   void RunGetContentCallback(google_apis::DriveApiErrorCode error,
                              std::unique_ptr<std::string> content) {
-    get_content_callback_.Run(error, std::move(content));
+    get_content_callback_.Run(error, std::move(content),
+                              !get_content_callback_called_);
+    get_content_callback_called_ = true;
   }
 
   void RunProgressCallback(int64_t progress, int64_t total) {
@@ -145,6 +147,8 @@
   DownloadActionCallback download_action_callback_;
   GetContentCallback get_content_callback_;
   ProgressCallback progress_callback_;
+
+  bool get_content_callback_called_{false};
 };
 
 class PluginVmInstallerTestBase : public testing::Test {
diff --git a/chrome/browser/download/download_service_factory.cc b/chrome/browser/download/download_service_factory.cc
index cde5250..33b5728 100644
--- a/chrome/browser/download/download_service_factory.cc
+++ b/chrome/browser/download/download_service_factory.cc
@@ -19,7 +19,6 @@
 #include "chrome/browser/chromeos/plugin_vm/plugin_vm_image_download_client.h"
 #include "chrome/browser/download/deferred_client_wrapper.h"
 #include "chrome/browser/download/download_manager_utils.h"
-#include "chrome/browser/download/download_task_scheduler_impl.h"
 #include "chrome/browser/download/simple_download_manager_coordinator_factory.h"
 #include "chrome/browser/net/system_network_context_manager.h"
 #include "chrome/browser/optimization_guide/prediction/prediction_model_download_client.h"
@@ -30,12 +29,12 @@
 #include "chrome/common/chrome_constants.h"
 #include "components/download/content/factory/download_service_factory_helper.h"
 #include "components/download/content/factory/navigation_monitor_factory.h"
+#include "components/download/public/background_service/basic_task_scheduler.h"
 #include "components/download/public/background_service/blob_context_getter_factory.h"
 #include "components/download/public/background_service/clients.h"
 #include "components/download/public/background_service/download_service.h"
 #include "components/download/public/background_service/features.h"
 #include "components/download/public/common/simple_download_manager_coordinator.h"
-#include "components/download/public/task/task_scheduler.h"
 #include "components/keyed_service/core/simple_dependency_manager.h"
 #include "components/leveldb_proto/public/proto_database_provider.h"
 #include "components/offline_pages/buildflags/buildflags.h"
@@ -196,7 +195,12 @@
     task_scheduler =
         std::make_unique<download::android::DownloadTaskScheduler>();
 #else
-    task_scheduler = std::make_unique<DownloadTaskSchedulerImpl>(key);
+    task_scheduler =
+        std::make_unique<download::BasicTaskScheduler>(base::BindRepeating(
+            [](SimpleFactoryKey* key) {
+              return DownloadServiceFactory::GetForKey(key);
+            },
+            key));
 #endif
     // Some tests doesn't initialize DownloadManager when profile is created,
     // and cause the download service to fail. Call
diff --git a/chrome/browser/download/download_task_scheduler_impl.cc b/chrome/browser/download/download_task_scheduler_impl.cc
deleted file mode 100644
index 45ae893..0000000
--- a/chrome/browser/download/download_task_scheduler_impl.cc
+++ /dev/null
@@ -1,65 +0,0 @@
-// Copyright 2017 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/download/download_task_scheduler_impl.h"
-
-#include "base/bind.h"
-#include "base/cancelable_callback.h"
-#include "base/sequenced_task_runner.h"
-#include "base/task/post_task.h"
-#include "base/task/task_traits.h"
-#include "base/threading/thread_task_runner_handle.h"
-#include "base/time/time.h"
-#include "chrome/browser/download/download_service_factory.h"
-#include "components/download/public/background_service/download_service.h"
-
-DownloadTaskSchedulerImpl::DownloadTaskSchedulerImpl(SimpleFactoryKey* key)
-    : key_(key) {}
-
-DownloadTaskSchedulerImpl::~DownloadTaskSchedulerImpl() = default;
-
-void DownloadTaskSchedulerImpl::ScheduleTask(
-    download::DownloadTaskType task_type,
-    bool require_unmetered_network,
-    bool require_charging,
-    int optimal_battery_percentage,
-    int64_t window_start_time_seconds,
-    int64_t window_end_time_seconds) {
-  // We only rely on this for cleanup tasks. Since this doesn't restart Chrome,
-  // for download tasks it doesn't do much and we handle them outside of task
-  // scheduler.
-  if (task_type != download::DownloadTaskType::CLEANUP_TASK)
-    return;
-
-  scheduled_tasks_[task_type].Reset(
-      base::BindOnce(&DownloadTaskSchedulerImpl::RunScheduledTask,
-                     weak_factory_.GetWeakPtr(), task_type));
-  base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
-      FROM_HERE, scheduled_tasks_[task_type].callback(),
-      base::TimeDelta::FromSeconds(window_start_time_seconds));
-}
-
-void DownloadTaskSchedulerImpl::CancelTask(
-    download::DownloadTaskType task_type) {
-  scheduled_tasks_[task_type].Cancel();
-}
-
-void DownloadTaskSchedulerImpl::RunScheduledTask(
-    download::DownloadTaskType task_type) {
-  if (task_type == download::DownloadTaskType::DOWNLOAD_AUTO_RESUMPTION_TASK) {
-    NOTREACHED();
-    return;
-  }
-
-  download::DownloadService* download_service =
-      DownloadServiceFactory::GetForKey(key_);
-  download_service->OnStartScheduledTask(
-      task_type, base::BindOnce(&DownloadTaskSchedulerImpl::OnTaskFinished,
-                                weak_factory_.GetWeakPtr()));
-}
-
-void DownloadTaskSchedulerImpl::OnTaskFinished(bool reschedule) {
-  // TODO(shaktisahu): Cache the original scheduling params and re-post task in
-  // case it needs reschedule.
-}
diff --git a/chrome/browser/download/download_task_scheduler_impl.h b/chrome/browser/download/download_task_scheduler_impl.h
deleted file mode 100644
index 8aaee811..0000000
--- a/chrome/browser/download/download_task_scheduler_impl.h
+++ /dev/null
@@ -1,50 +0,0 @@
-// Copyright 2017 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_DOWNLOAD_DOWNLOAD_TASK_SCHEDULER_IMPL_H_
-#define CHROME_BROWSER_DOWNLOAD_DOWNLOAD_TASK_SCHEDULER_IMPL_H_
-
-#include <stdint.h>
-#include <map>
-
-#include "base/cancelable_callback.h"
-#include "base/macros.h"
-#include "base/memory/weak_ptr.h"
-#include "components/download/public/task/task_scheduler.h"
-
-class SimpleFactoryKey;
-
-// A TaskScheduler implementation that doesn't do anything but posts the task
-// after the specified delay.
-// If Chrome is shut down, the implementation will not automatically restart it.
-class DownloadTaskSchedulerImpl : public download::TaskScheduler {
- public:
-  explicit DownloadTaskSchedulerImpl(SimpleFactoryKey* key);
-  ~DownloadTaskSchedulerImpl() override;
-
-  // TaskScheduler implementation.
-  void ScheduleTask(download::DownloadTaskType task_type,
-                    bool require_unmetered_network,
-                    bool require_charging,
-                    int optimal_battery_percentage,
-                    int64_t window_start_time_seconds,
-                    int64_t window_end_time_seconds) override;
-  void CancelTask(download::DownloadTaskType task_type) override;
-
- private:
-  void RunScheduledTask(download::DownloadTaskType task_type);
-  void OnTaskFinished(bool reschedule);
-
-  SimpleFactoryKey* key_;
-
-  // Keeps track of scheduled tasks so that they can be cancelled.
-  std::map<download::DownloadTaskType, base::CancelableOnceClosure>
-      scheduled_tasks_;
-
-  base::WeakPtrFactory<DownloadTaskSchedulerImpl> weak_factory_{this};
-
-  DISALLOW_COPY_AND_ASSIGN(DownloadTaskSchedulerImpl);
-};
-
-#endif  // CHROME_BROWSER_DOWNLOAD_DOWNLOAD_TASK_SCHEDULER_IMPL_H_
diff --git a/chrome/browser/extensions/active_tab_permission_granter.cc b/chrome/browser/extensions/active_tab_permission_granter.cc
index 5a8c7ee2..34382bae 100644
--- a/chrome/browser/extensions/active_tab_permission_granter.cc
+++ b/chrome/browser/extensions/active_tab_permission_granter.cc
@@ -27,6 +27,7 @@
 #include "extensions/common/cors_util.h"
 #include "extensions/common/extension.h"
 #include "extensions/common/extension_messages.h"
+#include "extensions/common/manifest_handlers/incognito_info.h"
 #include "extensions/common/mojom/renderer.mojom.h"
 #include "extensions/common/permissions/permission_set.h"
 #include "extensions/common/permissions/permissions_data.h"
@@ -112,6 +113,21 @@
              extension, web_contents);
 }
 
+void SetCorsOriginAccessList(content::BrowserContext* browser_context,
+                             const Extension& extension,
+                             base::OnceClosure closure) {
+  std::vector<content::BrowserContext*> target_contexts;
+  if (IncognitoInfo::IsSplitMode(&extension)) {
+    target_contexts = {browser_context};
+  } else {
+    target_contexts = util::GetAllRelatedProfiles(
+        Profile::FromBrowserContext(browser_context));
+  }
+
+  util::SetCorsOriginAccessListForExtension(target_contexts, extension,
+                                            std::move(closure));
+}
+
 }  // namespace
 
 ActiveTabPermissionGranter::ActiveTabPermissionGranter(
@@ -179,10 +195,8 @@
     PermissionSet new_permissions(std::move(new_apis), ManifestPermissionSet(),
                                   new_hosts.Clone(), new_hosts.Clone());
     permissions_data->UpdateTabSpecificPermissions(tab_id_, new_permissions);
-    util::SetCorsOriginAccessListForExtension(
-        browser_context, *extension,
-        base::nullopt,  // compute the `target_mode` based on the `extension`
-        base::DoNothing::Once());
+    SetCorsOriginAccessList(browser_context, *extension,
+                            base::DoNothing::Once());
 
     if (web_contents()->GetController().GetVisibleEntry()) {
       // We update all extension render views with the new tab permissions, and
@@ -257,10 +271,8 @@
   ProcessManager* process_manager = ProcessManager::Get(browser_context);
   for (const scoped_refptr<const Extension>& extension : granted_extensions_) {
     extension->permissions_data()->ClearTabSpecificPermissions(tab_id_);
-    util::SetCorsOriginAccessListForExtension(
-        browser_context, *extension,
-        base::nullopt,  // compute the `target_mode` based on the `extension`
-        base::DoNothing::Once());
+    SetCorsOriginAccessList(browser_context, *extension,
+                            base::DoNothing::Once());
 
     extension_ids.push_back(extension->id());
     std::set<content::RenderFrameHost*> extension_frame_hosts =
diff --git a/chrome/browser/extensions/api/permissions/permissions_api.cc b/chrome/browser/extensions/api/permissions/permissions_api.cc
index daaf9b5..238fd728 100644
--- a/chrome/browser/extensions/api/permissions/permissions_api.cc
+++ b/chrome/browser/extensions/api/permissions/permissions_api.cc
@@ -338,21 +338,22 @@
     return;
   }
   PermissionsUpdater permissions_updater(browser_context());
-  if (!requested_withheld_->IsEmpty()) {
-    requesting_withheld_permissions_ = true;
+  requesting_withheld_permissions_ = !requested_withheld_->IsEmpty();
+  requesting_optional_permissions_ = !requested_optional_->IsEmpty();
+  if (requesting_withheld_permissions_) {
     permissions_updater.GrantRuntimePermissions(
         *extension(), *requested_withheld_,
         base::BindOnce(&PermissionsRequestFunction::OnRuntimePermissionsGranted,
                        base::RetainedRef(this)));
   }
-  if (!requested_optional_->IsEmpty()) {
-    requesting_optional_permissions_ = true;
+  if (requesting_optional_permissions_) {
     permissions_updater.GrantOptionalPermissions(
         *extension(), *requested_optional_,
         base::BindOnce(
             &PermissionsRequestFunction::OnOptionalPermissionsGranted,
             base::RetainedRef(this)));
   }
+
   // Grant{Runtime|Optional}Permissions calls above can finish synchronously.
   if (!did_respond())
     RespondIfRequestsFinished();
diff --git a/chrome/browser/extensions/extension_util.cc b/chrome/browser/extensions/extension_util.cc
index d5e632d7..f6691357 100644
--- a/chrome/browser/extensions/extension_util.cc
+++ b/chrome/browser/extensions/extension_util.cc
@@ -311,5 +311,18 @@
   return permissions_to_display;
 }
 
+std::vector<content::BrowserContext*> GetAllRelatedProfiles(Profile* profile) {
+  std::vector<Profile*> off_the_record_profiles =
+      profile->GetAllOffTheRecordProfiles();
+
+  std::vector<content::BrowserContext*> related_contexts;
+  related_contexts.reserve(1 + off_the_record_profiles.size());
+  related_contexts.push_back(profile->GetOriginalProfile());
+  for (Profile* off_the_record_profile : off_the_record_profiles)
+    related_contexts.push_back(off_the_record_profile);
+
+  return related_contexts;
+}
+
 }  // namespace util
 }  // namespace extensions
diff --git a/chrome/browser/extensions/extension_util.h b/chrome/browser/extensions/extension_util.h
index 91ebf03..6ef7af1e 100644
--- a/chrome/browser/extensions/extension_util.h
+++ b/chrome/browser/extensions/extension_util.h
@@ -107,6 +107,10 @@
     Profile* profile,
     bool include_optional_permissions);
 
+// Returns all profiles affected by permissions of an extension running in
+// "spanning" (rather than "split) mode.
+std::vector<content::BrowserContext*> GetAllRelatedProfiles(Profile* profile);
+
 }  // namespace util
 }  // namespace extensions
 
diff --git a/chrome/browser/extensions/permissions_updater.cc b/chrome/browser/extensions/permissions_updater.cc
index 223bfa32..80da0d2 100644
--- a/chrome/browser/extensions/permissions_updater.cc
+++ b/chrome/browser/extensions/permissions_updater.cc
@@ -18,6 +18,7 @@
 #include "chrome/browser/extensions/api/permissions/permissions_api_helpers.h"
 #include "chrome/browser/extensions/extension_management.h"
 #include "chrome/browser/extensions/extension_system_factory.h"
+#include "chrome/browser/extensions/extension_util.h"
 #include "chrome/browser/extensions/scripting_permissions_modifier.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/common/extensions/api/permissions.h"
@@ -123,6 +124,15 @@
   DISALLOW_COPY_AND_ASSIGN(PermissionsUpdaterShutdownNotifierFactory);
 };
 
+void SetCorsOriginAccessListForAllRelatedProfiles(
+    content::BrowserContext* browser_context,
+    const Extension& extension,
+    base::OnceClosure closure) {
+  util::SetCorsOriginAccessListForExtension(
+      util::GetAllRelatedProfiles(Profile::FromBrowserContext(browser_context)),
+      extension, std::move(closure));
+}
+
 }  // namespace
 
 // A helper class to asynchronously dispatch the event to notify policy host
@@ -186,9 +196,8 @@
 
   // After an asynchronous call below, the helper will call
   // NotifyPermissionsUpdated if the profile is still valid.
-  util::SetCorsOriginAccessListForExtension(
+  SetCorsOriginAccessListForAllRelatedProfiles(
       browser_context, *extension,
-      content::BrowserContext::TargetBrowserContexts::kAllRelatedContexts,
       base::BindOnce(&NetworkPermissionsUpdateHelper::OnOriginAccessUpdated,
                      helper->weak_factory_.GetWeakPtr()));
 }
@@ -214,10 +223,8 @@
                      helper->weak_factory_.GetWeakPtr()));
 
   for (const auto& extension : extensions) {
-    util::SetCorsOriginAccessListForExtension(
-        browser_context, *extension,
-        content::BrowserContext::TargetBrowserContexts::kAllRelatedContexts,
-        barrier_closure);
+    SetCorsOriginAccessListForAllRelatedProfiles(browser_context, *extension,
+                                                 barrier_closure);
   }
 }
 
@@ -621,7 +628,7 @@
   UpdatedExtensionPermissionsInfo info =
       UpdatedExtensionPermissionsInfo(extension.get(), *changed, reason);
   content::NotificationService::current()->Notify(
-      extensions::NOTIFICATION_EXTENSION_PERMISSIONS_UPDATED,
+      NOTIFICATION_EXTENSION_PERMISSIONS_UPDATED,
       content::Source<Profile>(profile),
       content::Details<UpdatedExtensionPermissionsInfo>(&info));
 
diff --git a/chrome/browser/federated_learning/floc_eligibility_browsertest.cc b/chrome/browser/federated_learning/floc_eligibility_browsertest.cc
index 9a34689..e8b34cc 100644
--- a/chrome/browser/federated_learning/floc_eligibility_browsertest.cc
+++ b/chrome/browser/federated_learning/floc_eligibility_browsertest.cc
@@ -228,7 +228,7 @@
 }
 
 IN_PROC_BROWSER_TEST_F(FlocEligibilityBrowserTest,
-                       NotEligibleForHistoryDueToFeaturePolicy) {
+                       NotEligibleForHistoryDueToPermissionsPolicyLegacy) {
   net::IPAddress::ConsiderLoopbackIPToBePubliclyRoutableForTesting();
 
   SetRulesetWithRules(
@@ -381,7 +381,7 @@
 }
 
 IN_PROC_BROWSER_TEST_F(FlocEligibilityBrowserTest,
-                       ApiNotAllowedDueToFeaturePolicy) {
+                       ApiNotAllowedDueToPermissionsPolicy) {
   GURL main_page_url(https_server_.GetURL(
       "a.test",
       "/federated_learning/"
@@ -404,7 +404,7 @@
 }
 
 IN_PROC_BROWSER_TEST_F(FlocEligibilityBrowserTest,
-                       ApiNotAllowedInSubframeDueToFeaturePolicySelf) {
+                       ApiNotAllowedInSubframeDueToPermissionsPolicySelf) {
   GURL main_page_url(https_server_.GetURL(
       "a.test",
       "/federated_learning/"
@@ -445,18 +445,19 @@
           .ExtractString());
 }
 
-class FlocEligibilityBrowserTestChromeFeaturePolicyDisabled
+class FlocEligibilityBrowserTestChromePermissionsPolicyDisabled
     : public FlocEligibilityBrowserTest {
  public:
-  FlocEligibilityBrowserTestChromeFeaturePolicyDisabled() {
+  FlocEligibilityBrowserTestChromePermissionsPolicyDisabled() {
     scoped_feature_list_.Reset();
     scoped_feature_list_.InitAndDisableFeature(
         blink::features::kInterestCohortFeaturePolicy);
   }
 };
 
-IN_PROC_BROWSER_TEST_F(FlocEligibilityBrowserTestChromeFeaturePolicyDisabled,
-                       FeaturePolicyFeatureNotAvailable) {
+IN_PROC_BROWSER_TEST_F(
+    FlocEligibilityBrowserTestChromePermissionsPolicyDisabled,
+    PermissionsPolicyFeatureNotAvailable) {
   GURL main_page_url(https_server_.GetURL("a.test", "/title1.html"));
   ui_test_utils::NavigateToURL(browser(), main_page_url);
 
@@ -468,8 +469,9 @@
 
 // Try configuring the permissions policy anyway. Check that the API succeeds
 // and the history is eligible for floc computation.
-IN_PROC_BROWSER_TEST_F(FlocEligibilityBrowserTestChromeFeaturePolicyDisabled,
-                       FeaturePolicyFeatureNotEffective) {
+IN_PROC_BROWSER_TEST_F(
+    FlocEligibilityBrowserTestChromePermissionsPolicyDisabled,
+    PermissionsPolicyFeatureNotEffective) {
   net::IPAddress::ConsiderLoopbackIPToBePubliclyRoutableForTesting();
 
   GURL main_page_url(https_server_.GetURL(
diff --git a/chrome/browser/federated_learning/floc_eligibility_unittest.cc b/chrome/browser/federated_learning/floc_eligibility_unittest.cc
index 5633da76..d7ab0228ee 100644
--- a/chrome/browser/federated_learning/floc_eligibility_unittest.cc
+++ b/chrome/browser/federated_learning/floc_eligibility_unittest.cc
@@ -102,7 +102,7 @@
     }
 
     if (!floc_permissions_policy_enabled) {
-      simulator->SetFeaturePolicyHeader(
+      simulator->SetPermissionsPolicyHeader(
           {{blink::mojom::PermissionsPolicyFeature::kInterestCohort,
             /*values=*/{}, /*matches_all_origins=*/false,
             /*matches_opaque_src=*/false}});
@@ -187,7 +187,7 @@
   EXPECT_FALSE(IsUrlVisitEligibleToComputeFloc(url));
 }
 
-TEST_F(FlocEligibilityUnitTest, StopObservingFlocFeaturePolicyDisabled) {
+TEST_F(FlocEligibilityUnitTest, StopObservingFlocPermissionsPolicyDisabled) {
   GURL url("https://foo.com");
   NavigateToPage(url, /*publicly_routable=*/true,
                  /*floc_permissions_policy_enabled=*/false);
diff --git a/chrome/browser/flag-metadata.json b/chrome/browser/flag-metadata.json
index 345a1867..5f0f245 100644
--- a/chrome/browser/flag-metadata.json
+++ b/chrome/browser/flag-metadata.json
@@ -4942,6 +4942,16 @@
     "expiry_milestone": 82
   },
   {
+    "name": "tabbed-app-overflow-menu-icons",
+    "owners": [ "gangwu" ],
+    "expiry_milestone": 90
+  },
+  {
+    "name": "tabbed-app-overflow-menu-regroup",
+    "owners": [ "gangwu" ],
+    "expiry_milestone": 90
+  },
+  {
     "name": "tabbed-app-overflow-menu-three-button-actionbar",
     "owners": [ "gangwu" ],
     "expiry_milestone": 91
diff --git a/chrome/browser/flag_descriptions.cc b/chrome/browser/flag_descriptions.cc
index bc968a88..1869ce0 100644
--- a/chrome/browser/flag_descriptions.cc
+++ b/chrome/browser/flag_descriptions.cc
@@ -288,11 +288,6 @@
 const char kAutofillPruneSuggestionsDescription[] =
     "Further limits the number of suggestions in the Autofill dropdown.";
 
-const char kAutofillRestrictUnownedFieldsToFormlessCheckoutName[] =
-    "Restrict formless form extraction";
-const char kAutofillRestrictUnownedFieldsToFormlessCheckoutDescription[] =
-    "Restrict extraction of formless forms to checkout flows";
-
 const char kAutofillRichMetadataQueriesName[] =
     "Autofill - Rich metadata queries (Canary/Dev only)";
 const char kAutofillRichMetadataQueriesDescription[] =
@@ -3403,6 +3398,16 @@
     "Allows user to use touch gestures to move the text cursor around. This "
     "flag will only take effect on Android 11 and above.";
 
+const char kTabbedAppOverflowMenuIconsName[] =
+    "Android tabbed app overflow menu icons";
+const char kTabbedAppOverflowMenuIconsDescription[] =
+    "If enabled, shows icon in front of each overflow menu item.";
+
+const char kTabbedAppOverflowMenuRegroupName[] =
+    "Android tabbed app overflow menu Regroup";
+const char kTabbedAppOverflowMenuRegroupDescription[] =
+    "If enabled, regroup overflow menu items.";
+
 const char kTabbedAppOverflowMenuThreeButtonActionbarName[] =
     "Android tabbed app overflow menu three buttons actionbar";
 const char kTabbedAppOverflowMenuThreeButtonActionbarDescription[] =
diff --git a/chrome/browser/flag_descriptions.h b/chrome/browser/flag_descriptions.h
index a246b573..68ef72b 100644
--- a/chrome/browser/flag_descriptions.h
+++ b/chrome/browser/flag_descriptions.h
@@ -183,8 +183,8 @@
 extern const char kAutofillPruneSuggestionsName[];
 extern const char kAutofillPruneSuggestionsDescription[];
 
-extern const char kAutofillRestrictUnownedFieldsToFormlessCheckoutName[];
-extern const char kAutofillRestrictUnownedFieldsToFormlessCheckoutDescription[];
+extern const char kShelfAppScalingName[];
+extern const char kShelfAppScalingDescription[];
 
 extern const char kAutofillRichMetadataQueriesName[];
 extern const char kAutofillRichMetadataQueriesDescription[];
@@ -1970,6 +1970,12 @@
 extern const char kSwipeToMoveCursorName[];
 extern const char kSwipeToMoveCursorDescription[];
 
+extern const char kTabbedAppOverflowMenuIconsName[];
+extern const char kTabbedAppOverflowMenuIconsDescription[];
+
+extern const char kTabbedAppOverflowMenuRegroupName[];
+extern const char kTabbedAppOverflowMenuRegroupDescription[];
+
 extern const char kTabbedAppOverflowMenuThreeButtonActionbarName[];
 extern const char kTabbedAppOverflowMenuThreeButtonActionbarDescription[];
 
diff --git a/chrome/browser/flags/android/chrome_feature_list.cc b/chrome/browser/flags/android/chrome_feature_list.cc
index 4a9d59e5..1aeabac3 100644
--- a/chrome/browser/flags/android/chrome_feature_list.cc
+++ b/chrome/browser/flags/android/chrome_feature_list.cc
@@ -230,6 +230,8 @@
     &kTabReparenting,
     &kTabSwitcherOnReturn,
     &kTabToGTSAnimation,
+    &kTabbedAppOverflowMenuIcons,
+    &kTabbedAppOverflowMenuRegroup,
     &kTabbedAppOverflowMenuThreeButtonActionbar,
     &kTestDefaultDisabled,
     &kTestDefaultEnabled,
@@ -645,6 +647,12 @@
 const base::Feature kTabToGTSAnimation{"TabToGTSAnimation",
                                        base::FEATURE_ENABLED_BY_DEFAULT};
 
+const base::Feature kTabbedAppOverflowMenuIcons{
+    "TabbedAppOverflowMenuIcons", base::FEATURE_ENABLED_BY_DEFAULT};
+
+const base::Feature kTabbedAppOverflowMenuRegroup{
+    "TabbedAppOverflowMenuRegroup", base::FEATURE_ENABLED_BY_DEFAULT};
+
 const base::Feature kTabbedAppOverflowMenuThreeButtonActionbar{
     "TabbedAppOverflowMenuThreeButtonActionbar",
     base::FEATURE_DISABLED_BY_DEFAULT};
diff --git a/chrome/browser/flags/android/chrome_feature_list.h b/chrome/browser/flags/android/chrome_feature_list.h
index 872d9fb..99fc913 100644
--- a/chrome/browser/flags/android/chrome_feature_list.h
+++ b/chrome/browser/flags/android/chrome_feature_list.h
@@ -122,6 +122,8 @@
 extern const base::Feature kTabReparenting;
 extern const base::Feature kTabSwitcherOnReturn;
 extern const base::Feature kTabToGTSAnimation;
+extern const base::Feature kTabbedAppOverflowMenuIcons;
+extern const base::Feature kTabbedAppOverflowMenuRegroup;
 extern const base::Feature kTabbedAppOverflowMenuThreeButtonActionbar;
 extern const base::Feature kTestDefaultDisabled;
 extern const base::Feature kTestDefaultEnabled;
diff --git a/chrome/browser/flags/android/java/src/org/chromium/chrome/browser/flags/CachedFeatureFlags.java b/chrome/browser/flags/android/java/src/org/chromium/chrome/browser/flags/CachedFeatureFlags.java
index 162f0b0..cd62ec7 100644
--- a/chrome/browser/flags/android/java/src/org/chromium/chrome/browser/flags/CachedFeatureFlags.java
+++ b/chrome/browser/flags/android/java/src/org/chromium/chrome/browser/flags/CachedFeatureFlags.java
@@ -78,6 +78,8 @@
             put(ChromeFeatureList.TEST_DEFAULT_ENABLED, true);
             put(ChromeFeatureList.REPORT_FEED_USER_ACTIONS, false);
             put(ChromeFeatureList.INTEREST_FEED_V2, true);
+            put(ChromeFeatureList.TABBED_APP_OVERFLOW_MENU_ICONS, false);
+            put(ChromeFeatureList.TABBED_APP_OVERFLOW_MENU_REGROUP, false);
             put(ChromeFeatureList.TABBED_APP_OVERFLOW_MENU_THREE_BUTTON_ACTIONBAR, false);
             put(ChromeFeatureList.THEME_REFACTOR_ANDROID, false);
             put(ChromeFeatureList.USE_CHIME_ANDROID_SDK, false);
diff --git a/chrome/browser/flags/android/java/src/org/chromium/chrome/browser/flags/ChromeFeatureList.java b/chrome/browser/flags/android/java/src/org/chromium/chrome/browser/flags/ChromeFeatureList.java
index 17a5d276..9d3a1b08f 100644
--- a/chrome/browser/flags/android/java/src/org/chromium/chrome/browser/flags/ChromeFeatureList.java
+++ b/chrome/browser/flags/android/java/src/org/chromium/chrome/browser/flags/ChromeFeatureList.java
@@ -451,6 +451,8 @@
     public static final String TAB_REPARENTING = "TabReparenting";
     public static final String TAB_SWITCHER_ON_RETURN = "TabSwitcherOnReturn";
     public static final String TAB_TO_GTS_ANIMATION = "TabToGTSAnimation";
+    public static final String TABBED_APP_OVERFLOW_MENU_ICONS = "TabbedAppOverflowMenuIcons";
+    public static final String TABBED_APP_OVERFLOW_MENU_REGROUP = "TabbedAppOverflowMenuRegroup";
     public static final String TABBED_APP_OVERFLOW_MENU_THREE_BUTTON_ACTIONBAR =
             "TabbedAppOverflowMenuThreeButtonActionbar";
     public static final String TEST_DEFAULT_DISABLED = "TestDefaultDisabled";
diff --git a/chrome/browser/gsa/java/src/org/chromium/chrome/browser/gsa/GSAState.java b/chrome/browser/gsa/java/src/org/chromium/chrome/browser/gsa/GSAState.java
index 70980e372..b6b67909 100644
--- a/chrome/browser/gsa/java/src/org/chromium/chrome/browser/gsa/GSAState.java
+++ b/chrome/browser/gsa/java/src/org/chromium/chrome/browser/gsa/GSAState.java
@@ -18,6 +18,7 @@
 import androidx.annotation.Nullable;
 import androidx.annotation.VisibleForTesting;
 
+import org.chromium.base.Log;
 import org.chromium.base.ObserverList;
 import org.chromium.base.PackageManagerUtils;
 import org.chromium.base.PackageUtils;
@@ -29,6 +30,8 @@
 import org.chromium.components.signin.identitymanager.IdentityManager;
 
 import java.util.List;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
 
 /**
  * A class responsible for representing the current state of Chrome's integration with GSA.
@@ -67,6 +70,9 @@
     @SuppressLint("StaticFieldLeak")
     private static GSAState sGSAState;
 
+    private static final Pattern MAJOR_MINOR_VERSION_PATTERN =
+            Pattern.compile("^(\\d+)\\.(\\d+)(\\.\\d+)*$");
+
     /**
      * The application context to use.
      */
@@ -245,6 +251,44 @@
     }
 
     /**
+     * Converts the given version name into a reportable integer which contains the major and minor
+     * version.
+     * - The returned integer ranges between 1,000 - 999,999.
+     * - The major version is represented by the numbers in the hundred/ten/thousanths places.
+     * - The minor version is represented by the numbers in the tens/hundredths places.
+     * - The max for both major and minor versions is 999. If either exceeds the maximum, null is
+     *   returned.
+     *
+     * @param versionName The version name as a string (eg 11.9).
+     * @return The version name as an integer between 1,000 - 999,999 as described above or null if
+     *         the above conditions aren't satisfied.
+     */
+    public @Nullable Integer parseAgsaMajorMinorVersionAsInteger(String versionName) {
+        if (versionName == null) return null;
+
+        Matcher matcher = MAJOR_MINOR_VERSION_PATTERN.matcher(versionName);
+        if (!matcher.find() || matcher.groupCount() < 2) return null;
+
+        try {
+            int major = Integer.parseInt(matcher.group(1));
+            if (major > 999) {
+                Log.e(TAG, "Major verison exceeded maximum of 999.");
+                return null;
+            }
+
+            int minor = Integer.parseInt(matcher.group(2));
+            if (minor > 999) {
+                Log.e(TAG, "Minor verison exceeded maximum of 999.");
+                return null;
+            }
+            return major * 1000 + minor;
+        } catch (NumberFormatException e) {
+            Log.e(TAG, "Version was incorrectly formatted.");
+            return null;
+        }
+    }
+
+    /**
      * Adds an observer.
      * @param observer The observer to add.
      */
diff --git a/chrome/browser/media/webrtc/media_stream_devices_controller_browsertest.cc b/chrome/browser/media/webrtc/media_stream_devices_controller_browsertest.cc
index 413b0d3..e6e883ce 100644
--- a/chrome/browser/media/webrtc/media_stream_devices_controller_browsertest.cc
+++ b/chrome/browser/media/webrtc/media_stream_devices_controller_browsertest.cc
@@ -997,7 +997,7 @@
 }
 
 IN_PROC_BROWSER_TEST_F(MediaStreamDevicesControllerTest,
-                       RequestCamAndMicBlockedByFeaturePolicy) {
+                       RequestCamAndMicBlockedByPermissionsPolicy) {
   InitWithUrl(embedded_test_server()->GetURL("/iframe_blank.html"));
 
   // Create a cross-origin request by using localhost as the iframe origin.
@@ -1027,7 +1027,7 @@
 }
 
 IN_PROC_BROWSER_TEST_F(MediaStreamDevicesControllerTest,
-                       RequestCamBlockedByFeaturePolicy) {
+                       RequestCamBlockedByPermissionsPolicy) {
   InitWithUrl(embedded_test_server()->GetURL("/iframe_blank.html"));
 
   // Create a cross-origin request by using localhost as the iframe origin.
diff --git a/chrome/browser/media_galleries/chromeos/mtp_device_delegate_impl_chromeos.cc b/chrome/browser/media_galleries/chromeos/mtp_device_delegate_impl_chromeos.cc
index d742159..db2cc4ee 100644
--- a/chrome/browser/media_galleries/chromeos/mtp_device_delegate_impl_chromeos.cc
+++ b/chrome/browser/media_galleries/chromeos/mtp_device_delegate_impl_chromeos.cc
@@ -196,14 +196,15 @@
     const std::string& storage_name,
     const bool read_only,
     uint32_t file_id,
-    const MTPDeviceTaskHelper::GetFileInfoSuccessCallback& success_callback,
+    MTPDeviceTaskHelper::GetFileInfoSuccessCallback success_callback,
     const MTPDeviceTaskHelper::ErrorCallback& error_callback) {
   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
   MTPDeviceTaskHelper* task_helper =
       GetDeviceTaskHelperForStorage(storage_name, read_only);
   if (!task_helper)
     return;
-  task_helper->GetFileInfo(file_id, success_callback, error_callback);
+  task_helper->GetFileInfo(file_id, std::move(success_callback),
+                           error_callback);
 }
 
 // Copies the contents of |device_file_path| to |snapshot_file_path|.
@@ -394,14 +395,16 @@
     const base::FilePath& path,
     content::BrowserThread::ID thread_id,
     const base::Location& location,
-    const base::Closure& task)
-    : path(path), thread_id(thread_id), location(location), task(task) {}
+    base::OnceClosure task)
+    : path(path),
+      thread_id(thread_id),
+      location(location),
+      task(std::move(task)) {}
 
 MTPDeviceDelegateImplLinux::PendingTaskInfo::PendingTaskInfo(
-    const PendingTaskInfo& other) = default;
+    PendingTaskInfo&& other) = default;
 
-MTPDeviceDelegateImplLinux::PendingTaskInfo::~PendingTaskInfo() {
-}
+MTPDeviceDelegateImplLinux::PendingTaskInfo::~PendingTaskInfo() = default;
 
 // Represents a file on the MTP device.
 // Lives on the IO thread.
@@ -563,17 +566,18 @@
     components.push_back(directory_path);
   }
 
-  const base::Closure closure =
-      base::Bind(&MTPDeviceDelegateImplLinux::CreateDirectoryInternal,
-                 weak_ptr_factory_.GetWeakPtr(), components, exclusive,
-                 success_callback, error_callback);
-  EnsureInitAndRunTask(PendingTaskInfo(
-      directory_path, content::BrowserThread::IO, FROM_HERE, closure));
+  base::OnceClosure closure =
+      base::BindOnce(&MTPDeviceDelegateImplLinux::CreateDirectoryInternal,
+                     weak_ptr_factory_.GetWeakPtr(), components, exclusive,
+                     success_callback, error_callback);
+  EnsureInitAndRunTask(PendingTaskInfo(directory_path,
+                                       content::BrowserThread::IO, FROM_HERE,
+                                       std::move(closure)));
 }
 
 void MTPDeviceDelegateImplLinux::GetFileInfo(
     const base::FilePath& file_path,
-    const GetFileInfoSuccessCallback& success_callback,
+    GetFileInfoSuccessCallback success_callback,
     const ErrorCallback& error_callback) {
   DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
   DCHECK(!file_path.empty());
@@ -585,19 +589,15 @@
     // TODO(thestig): This code is repeated in several places. Combine them.
     // e.g. c/b/media_galleries/win/mtp_device_operations_util.cc
     const MTPDeviceTaskHelper::MTPEntry& cached_file_entry = it->second;
-    success_callback.Run(cached_file_entry.file_info);
+    std::move(success_callback).Run(cached_file_entry.file_info);
     return;
   }
-  base::Closure closure =
-      base::Bind(&MTPDeviceDelegateImplLinux::GetFileInfoInternal,
-                 weak_ptr_factory_.GetWeakPtr(),
-                 file_path,
-                 success_callback,
-                 error_callback);
-  EnsureInitAndRunTask(PendingTaskInfo(file_path,
-                                       content::BrowserThread::IO,
-                                       FROM_HERE,
-                                       closure));
+  base::OnceClosure closure =
+      base::BindOnce(&MTPDeviceDelegateImplLinux::GetFileInfoInternal,
+                     weak_ptr_factory_.GetWeakPtr(), file_path,
+                     std::move(success_callback), error_callback);
+  EnsureInitAndRunTask(PendingTaskInfo(file_path, content::BrowserThread::IO,
+                                       FROM_HERE, std::move(closure)));
 }
 
 void MTPDeviceDelegateImplLinux::ReadDirectory(
@@ -606,16 +606,11 @@
     const ErrorCallback& error_callback) {
   DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
   DCHECK(!root.empty());
-  base::Closure closure =
-      base::Bind(&MTPDeviceDelegateImplLinux::ReadDirectoryInternal,
-                 weak_ptr_factory_.GetWeakPtr(),
-                 root,
-                 success_callback,
-                 error_callback);
-  EnsureInitAndRunTask(PendingTaskInfo(root,
-                                       content::BrowserThread::IO,
-                                       FROM_HERE,
-                                       closure));
+  base::OnceClosure closure = base::BindOnce(
+      &MTPDeviceDelegateImplLinux::ReadDirectoryInternal,
+      weak_ptr_factory_.GetWeakPtr(), root, success_callback, error_callback);
+  EnsureInitAndRunTask(PendingTaskInfo(root, content::BrowserThread::IO,
+                                       FROM_HERE, std::move(closure)));
 }
 
 void MTPDeviceDelegateImplLinux::CreateSnapshotFile(
@@ -626,17 +621,13 @@
   DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
   DCHECK(!device_file_path.empty());
   DCHECK(!local_path.empty());
-  base::Closure closure =
-      base::Bind(&MTPDeviceDelegateImplLinux::CreateSnapshotFileInternal,
-                 weak_ptr_factory_.GetWeakPtr(),
-                 device_file_path,
-                 local_path,
-                 success_callback,
-                 error_callback);
+  base::OnceClosure closure =
+      base::BindOnce(&MTPDeviceDelegateImplLinux::CreateSnapshotFileInternal,
+                     weak_ptr_factory_.GetWeakPtr(), device_file_path,
+                     local_path, success_callback, error_callback);
   EnsureInitAndRunTask(PendingTaskInfo(device_file_path,
-                                       content::BrowserThread::IO,
-                                       FROM_HERE,
-                                       closure));
+                                       content::BrowserThread::IO, FROM_HERE,
+                                       std::move(closure)));
 }
 
 bool MTPDeviceDelegateImplLinux::IsStreaming() {
@@ -652,14 +643,13 @@
     const ErrorCallback& error_callback) {
   DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
   DCHECK(!device_file_path.empty());
-  base::Closure closure = base::Bind(
+  base::OnceClosure closure = base::BindOnce(
       &MTPDeviceDelegateImplLinux::ReadBytesInternal,
       weak_ptr_factory_.GetWeakPtr(), device_file_path, base::RetainedRef(buf),
       offset, buf_len, success_callback, error_callback);
   EnsureInitAndRunTask(PendingTaskInfo(device_file_path,
-                                       content::BrowserThread::IO,
-                                       FROM_HERE,
-                                       closure));
+                                       content::BrowserThread::IO, FROM_HERE,
+                                       std::move(closure)));
 }
 
 bool MTPDeviceDelegateImplLinux::IsReadOnly() const {
@@ -700,16 +690,17 @@
   DCHECK(!device_file_path.empty());
 
   // Get file info to move file on local.
-  const GetFileInfoSuccessCallback success_callback_wrapper = base::Bind(
+  GetFileInfoSuccessCallback success_callback_wrapper = base::BindOnce(
       &MTPDeviceDelegateImplLinux::MoveFileLocalInternal,
       weak_ptr_factory_.GetWeakPtr(), source_file_path, device_file_path,
       create_temporary_file_callback, success_callback, error_callback);
-  const base::Closure closure =
-      base::Bind(&MTPDeviceDelegateImplLinux::GetFileInfoInternal,
-                 weak_ptr_factory_.GetWeakPtr(), source_file_path,
-                 success_callback_wrapper, error_callback);
-  EnsureInitAndRunTask(PendingTaskInfo(
-      source_file_path, content::BrowserThread::IO, FROM_HERE, closure));
+  base::OnceClosure closure =
+      base::BindOnce(&MTPDeviceDelegateImplLinux::GetFileInfoInternal,
+                     weak_ptr_factory_.GetWeakPtr(), source_file_path,
+                     std::move(success_callback_wrapper), error_callback);
+  EnsureInitAndRunTask(PendingTaskInfo(source_file_path,
+                                       content::BrowserThread::IO, FROM_HERE,
+                                       std::move(closure)));
 }
 
 void MTPDeviceDelegateImplLinux::CopyFileFromLocal(
@@ -722,19 +713,20 @@
   DCHECK(!device_file_path.empty());
 
   // Get file info of destination file path.
-  const GetFileInfoSuccessCallback success_callback_wrapper = base::Bind(
+  GetFileInfoSuccessCallback success_callback_wrapper = base::BindOnce(
       &MTPDeviceDelegateImplLinux::OnDidGetDestFileInfoToCopyFileFromLocal,
       weak_ptr_factory_.GetWeakPtr(), error_callback);
   const ErrorCallback error_callback_wrapper = base::Bind(
       &MTPDeviceDelegateImplLinux::OnGetDestFileInfoErrorToCopyFileFromLocal,
       weak_ptr_factory_.GetWeakPtr(), source_file_path, device_file_path,
       success_callback, error_callback);
-  const base::Closure closure =
-      base::Bind(&MTPDeviceDelegateImplLinux::GetFileInfoInternal,
-                 weak_ptr_factory_.GetWeakPtr(), device_file_path,
-                 success_callback_wrapper, error_callback_wrapper);
-  EnsureInitAndRunTask(PendingTaskInfo(
-      device_file_path, content::BrowserThread::IO, FROM_HERE, closure));
+  base::OnceClosure closure = base::BindOnce(
+      &MTPDeviceDelegateImplLinux::GetFileInfoInternal,
+      weak_ptr_factory_.GetWeakPtr(), device_file_path,
+      std::move(success_callback_wrapper), error_callback_wrapper);
+  EnsureInitAndRunTask(PendingTaskInfo(device_file_path,
+                                       content::BrowserThread::IO, FROM_HERE,
+                                       std::move(closure)));
 }
 
 void MTPDeviceDelegateImplLinux::DeleteFile(
@@ -744,17 +736,17 @@
   DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
   DCHECK(!file_path.empty());
 
-  const GetFileInfoSuccessCallback& success_callback_wrapper =
-      base::Bind(&MTPDeviceDelegateImplLinux::DeleteFileInternal,
-                 weak_ptr_factory_.GetWeakPtr(), file_path, success_callback,
-                 error_callback);
+  GetFileInfoSuccessCallback success_callback_wrapper =
+      base::BindOnce(&MTPDeviceDelegateImplLinux::DeleteFileInternal,
+                     weak_ptr_factory_.GetWeakPtr(), file_path,
+                     success_callback, error_callback);
 
-  const base::Closure closure =
-      base::Bind(&MTPDeviceDelegateImplLinux::GetFileInfoInternal,
-                 weak_ptr_factory_.GetWeakPtr(), file_path,
-                 success_callback_wrapper, error_callback);
+  base::OnceClosure closure =
+      base::BindOnce(&MTPDeviceDelegateImplLinux::GetFileInfoInternal,
+                     weak_ptr_factory_.GetWeakPtr(), file_path,
+                     std::move(success_callback_wrapper), error_callback);
   EnsureInitAndRunTask(PendingTaskInfo(file_path, content::BrowserThread::IO,
-                                       FROM_HERE, closure));
+                                       FROM_HERE, std::move(closure)));
 }
 
 void MTPDeviceDelegateImplLinux::DeleteDirectory(
@@ -764,17 +756,17 @@
   DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
   DCHECK(!file_path.empty());
 
-  const GetFileInfoSuccessCallback& success_callback_wrapper =
-      base::Bind(&MTPDeviceDelegateImplLinux::DeleteDirectoryInternal,
-                 weak_ptr_factory_.GetWeakPtr(), file_path, success_callback,
-                 error_callback);
+  GetFileInfoSuccessCallback success_callback_wrapper =
+      base::BindOnce(&MTPDeviceDelegateImplLinux::DeleteDirectoryInternal,
+                     weak_ptr_factory_.GetWeakPtr(), file_path,
+                     success_callback, error_callback);
 
-  const base::Closure closure =
-      base::Bind(&MTPDeviceDelegateImplLinux::GetFileInfoInternal,
-                 weak_ptr_factory_.GetWeakPtr(), file_path,
-                 success_callback_wrapper, error_callback);
+  base::OnceClosure closure =
+      base::BindOnce(&MTPDeviceDelegateImplLinux::GetFileInfoInternal,
+                     weak_ptr_factory_.GetWeakPtr(), file_path,
+                     std::move(success_callback_wrapper), error_callback);
   EnsureInitAndRunTask(PendingTaskInfo(file_path, content::BrowserThread::IO,
-                                       FROM_HERE, closure));
+                                       FROM_HERE, std::move(closure)));
 }
 
 void MTPDeviceDelegateImplLinux::AddWatcher(
@@ -857,27 +849,25 @@
 
 void MTPDeviceDelegateImplLinux::GetFileInfoInternal(
     const base::FilePath& file_path,
-    const GetFileInfoSuccessCallback& success_callback,
+    GetFileInfoSuccessCallback success_callback,
     const ErrorCallback& error_callback) {
   DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
 
   base::Optional<uint32_t> file_id = CachedPathToId(file_path);
   if (file_id) {
-    GetFileInfoSuccessCallback success_callback_wrapper =
-        base::Bind(&MTPDeviceDelegateImplLinux::OnDidGetFileInfo,
-                   weak_ptr_factory_.GetWeakPtr(),
-                   success_callback);
+    GetFileInfoSuccessCallback success_callback_wrapper = base::BindOnce(
+        &MTPDeviceDelegateImplLinux::OnDidGetFileInfo,
+        weak_ptr_factory_.GetWeakPtr(), std::move(success_callback));
     ErrorCallback error_callback_wrapper =
         base::Bind(&MTPDeviceDelegateImplLinux::HandleDeviceFileError,
                    weak_ptr_factory_.GetWeakPtr(), error_callback, *file_id);
 
-    base::Closure closure =
-        base::Bind(&GetFileInfoOnUIThread, storage_name_, read_only_, *file_id,
-                   success_callback_wrapper, error_callback_wrapper);
+    base::OnceClosure closure = base::BindOnce(
+        &GetFileInfoOnUIThread, storage_name_, read_only_, *file_id,
+        std::move(success_callback_wrapper), error_callback_wrapper);
     EnsureInitAndRunTask(PendingTaskInfo(base::FilePath(),
-                                         content::BrowserThread::UI,
-                                         FROM_HERE,
-                                         closure));
+                                         content::BrowserThread::UI, FROM_HERE,
+                                         std::move(closure)));
   } else {
     error_callback.Run(base::File::FILE_ERROR_NOT_FOUND);
   }
@@ -901,12 +891,13 @@
     base::Optional<uint32_t> parent_id =
         CachedPathToId(current_component.DirName());
     if (parent_id) {
-      const base::Closure closure =
-          base::Bind(&MTPDeviceDelegateImplLinux::CreateSingleDirectory,
-                     weak_ptr_factory_.GetWeakPtr(), current_component,
-                     exclusive, success_callback, error_callback);
-      EnsureInitAndRunTask(PendingTaskInfo(
-          base::FilePath(), content::BrowserThread::IO, FROM_HERE, closure));
+      base::OnceClosure closure =
+          base::BindOnce(&MTPDeviceDelegateImplLinux::CreateSingleDirectory,
+                         weak_ptr_factory_.GetWeakPtr(), current_component,
+                         exclusive, success_callback, error_callback);
+      EnsureInitAndRunTask(PendingTaskInfo(base::FilePath(),
+                                           content::BrowserThread::IO,
+                                           FROM_HERE, std::move(closure)));
     } else {
       error_callback.Run(base::File::FILE_ERROR_NOT_FOUND);
     }
@@ -916,12 +907,13 @@
     if (directory_id) {
       // Parent directory |current_component| already exists, continue creating
       // directories.
-      const base::Closure closure =
-          base::Bind(&MTPDeviceDelegateImplLinux::CreateDirectoryInternal,
-                     weak_ptr_factory_.GetWeakPtr(), other_components,
-                     exclusive, success_callback, error_callback);
-      EnsureInitAndRunTask(PendingTaskInfo(
-          base::FilePath(), content::BrowserThread::IO, FROM_HERE, closure));
+      base::OnceClosure closure =
+          base::BindOnce(&MTPDeviceDelegateImplLinux::CreateDirectoryInternal,
+                         weak_ptr_factory_.GetWeakPtr(), other_components,
+                         exclusive, success_callback, error_callback);
+      EnsureInitAndRunTask(PendingTaskInfo(base::FilePath(),
+                                           content::BrowserThread::IO,
+                                           FROM_HERE, std::move(closure)));
     } else {
       // If parent directory |current_component| does not exist, create it.
       const CreateDirectorySuccessCallback success_callback_wrapper =
@@ -936,13 +928,14 @@
           base::Bind(&MTPDeviceDelegateImplLinux::
                          OnCreateParentDirectoryErrorToCreateDirectory,
                      weak_ptr_factory_.GetWeakPtr(), error_callback);
-      const base::Closure closure =
-          base::Bind(&MTPDeviceDelegateImplLinux::CreateSingleDirectory,
-                     weak_ptr_factory_.GetWeakPtr(), current_component,
-                     false /* not exclusive */, success_callback_wrapper,
-                     error_callback_wrapper);
-      EnsureInitAndRunTask(PendingTaskInfo(
-          base::FilePath(), content::BrowserThread::IO, FROM_HERE, closure));
+      base::OnceClosure closure =
+          base::BindOnce(&MTPDeviceDelegateImplLinux::CreateSingleDirectory,
+                         weak_ptr_factory_.GetWeakPtr(), current_component,
+                         false /* not exclusive */, success_callback_wrapper,
+                         error_callback_wrapper);
+      EnsureInitAndRunTask(PendingTaskInfo(base::FilePath(),
+                                           content::BrowserThread::IO,
+                                           FROM_HERE, std::move(closure)));
     }
   }
 
@@ -963,18 +956,18 @@
     return;
   }
 
-  GetFileInfoSuccessCallback success_callback_wrapper =
-      base::Bind(&MTPDeviceDelegateImplLinux::OnDidGetFileInfoToReadDirectory,
-                 weak_ptr_factory_.GetWeakPtr(), *dir_id, success_callback,
-                 error_callback);
+  GetFileInfoSuccessCallback success_callback_wrapper = base::BindOnce(
+      &MTPDeviceDelegateImplLinux::OnDidGetFileInfoToReadDirectory,
+      weak_ptr_factory_.GetWeakPtr(), *dir_id, success_callback,
+      error_callback);
   ErrorCallback error_callback_wrapper =
       base::Bind(&MTPDeviceDelegateImplLinux::HandleDeviceFileError,
                  weak_ptr_factory_.GetWeakPtr(), error_callback, *dir_id);
-  base::Closure closure =
-      base::Bind(&GetFileInfoOnUIThread, storage_name_, read_only_, *dir_id,
-                 success_callback_wrapper, error_callback_wrapper);
+  base::OnceClosure closure = base::BindOnce(
+      &GetFileInfoOnUIThread, storage_name_, read_only_, *dir_id,
+      std::move(success_callback_wrapper), error_callback_wrapper);
 
-  content::GetUIThreadTaskRunner({})->PostTask(FROM_HERE, closure);
+  content::GetUIThreadTaskRunner({})->PostTask(FROM_HERE, std::move(closure));
 }
 
 void MTPDeviceDelegateImplLinux::CreateSnapshotFileInternal(
@@ -988,21 +981,18 @@
   if (file_id) {
     auto request_info = std::make_unique<SnapshotRequestInfo>(
         *file_id, local_path, success_callback, error_callback);
-    GetFileInfoSuccessCallback success_callback_wrapper =
-        base::Bind(
-            &MTPDeviceDelegateImplLinux::OnDidGetFileInfoToCreateSnapshotFile,
-            weak_ptr_factory_.GetWeakPtr(),
-            base::Passed(&request_info));
+    GetFileInfoSuccessCallback success_callback_wrapper = base::BindOnce(
+        &MTPDeviceDelegateImplLinux::OnDidGetFileInfoToCreateSnapshotFile,
+        weak_ptr_factory_.GetWeakPtr(), std::move(request_info));
     ErrorCallback error_callback_wrapper =
         base::Bind(&MTPDeviceDelegateImplLinux::HandleDeviceFileError,
                    weak_ptr_factory_.GetWeakPtr(), error_callback, *file_id);
-    base::Closure closure =
-        base::Bind(&GetFileInfoOnUIThread, storage_name_, read_only_, *file_id,
-                   success_callback_wrapper, error_callback_wrapper);
+    base::OnceClosure closure = base::BindOnce(
+        &GetFileInfoOnUIThread, storage_name_, read_only_, *file_id,
+        std::move(success_callback_wrapper), error_callback_wrapper);
     EnsureInitAndRunTask(PendingTaskInfo(base::FilePath(),
-                                         content::BrowserThread::UI,
-                                         FROM_HERE,
-                                         closure));
+                                         content::BrowserThread::UI, FROM_HERE,
+                                         std::move(closure)));
   } else {
     error_callback.Run(base::File::FILE_ERROR_NOT_FOUND);
   }
@@ -1028,12 +1018,11 @@
                             weak_ptr_factory_.GetWeakPtr(), error_callback,
                             *file_id));
 
-    base::Closure closure =
-        base::Bind(&ReadBytesOnUIThread, storage_name_, read_only_, request);
+    base::OnceClosure closure = base::BindOnce(
+        &ReadBytesOnUIThread, storage_name_, read_only_, request);
     EnsureInitAndRunTask(PendingTaskInfo(base::FilePath(),
-                                         content::BrowserThread::UI,
-                                         FROM_HERE,
-                                         closure));
+                                         content::BrowserThread::UI, FROM_HERE,
+                                         std::move(closure)));
   } else {
     error_callback.Run(base::File::FILE_ERROR_NOT_FOUND);
   }
@@ -1066,12 +1055,13 @@
       const MTPDeviceTaskHelper::ErrorCallback error_callback_wrapper =
           base::Bind(&MTPDeviceDelegateImplLinux::HandleDeviceFileError,
                      weak_ptr_factory_.GetWeakPtr(), error_callback, *file_id);
-      const base::Closure closure =
-          base::Bind(&RenameObjectOnUIThread, storage_name_, read_only_,
-                     *file_id, device_file_path.BaseName().value(),
-                     success_callback_wrapper, error_callback_wrapper);
-      EnsureInitAndRunTask(PendingTaskInfo(
-          base::FilePath(), content::BrowserThread::UI, FROM_HERE, closure));
+      base::OnceClosure closure =
+          base::BindOnce(&RenameObjectOnUIThread, storage_name_, read_only_,
+                         *file_id, device_file_path.BaseName().value(),
+                         success_callback_wrapper, error_callback_wrapper);
+      EnsureInitAndRunTask(PendingTaskInfo(base::FilePath(),
+                                           content::BrowserThread::UI,
+                                           FROM_HERE, std::move(closure)));
     } else {
       error_callback.Run(base::File::FILE_ERROR_NOT_FOUND);
     }
@@ -1121,13 +1111,14 @@
       &MTPDeviceDelegateImplLinux::HandleCopyFileFromLocalError,
       weak_ptr_factory_.GetWeakPtr(), error_callback, source_file_descriptor);
 
-  base::Closure closure = base::Bind(
+  base::OnceClosure closure = base::BindOnce(
       &CopyFileFromLocalOnUIThread, storage_name_, read_only_,
       source_file_descriptor, *parent_id, device_file_path.BaseName().value(),
       success_callback_wrapper, error_callback_wrapper);
 
-  EnsureInitAndRunTask(PendingTaskInfo(
-      base::FilePath(), content::BrowserThread::UI, FROM_HERE, closure));
+  EnsureInitAndRunTask(PendingTaskInfo(base::FilePath(),
+                                       content::BrowserThread::UI, FROM_HERE,
+                                       std::move(closure)));
 }
 
 void MTPDeviceDelegateImplLinux::DeleteFileInternal(
@@ -1190,11 +1181,12 @@
   const MTPDeviceTaskHelper::ErrorCallback error_callback_wrapper =
       base::Bind(&MTPDeviceDelegateImplLinux::HandleDeviceFileError,
                  weak_ptr_factory_.GetWeakPtr(), error_callback, *directory_id);
-  const base::Closure closure = base::Bind(
+  base::OnceClosure closure = base::BindOnce(
       &CheckDirectoryEmptyOnUIThread, storage_name_, read_only_, *directory_id,
-      base::Passed(&success_callback_wrapper), error_callback_wrapper);
-  EnsureInitAndRunTask(PendingTaskInfo(
-      base::FilePath(), content::BrowserThread::UI, FROM_HERE, closure));
+      std::move(success_callback_wrapper), error_callback_wrapper);
+  EnsureInitAndRunTask(PendingTaskInfo(base::FilePath(),
+                                       content::BrowserThread::UI, FROM_HERE,
+                                       std::move(closure)));
 }
 
 void MTPDeviceDelegateImplLinux::CreateSingleDirectory(
@@ -1204,7 +1196,7 @@
     const ErrorCallback& error_callback) {
   DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
 
-  const GetFileInfoSuccessCallback success_callback_wrapper = base::Bind(
+  GetFileInfoSuccessCallback success_callback_wrapper = base::BindOnce(
       &MTPDeviceDelegateImplLinux::OnPathAlreadyExistsForCreateSingleDirectory,
       weak_ptr_factory_.GetWeakPtr(), exclusive, success_callback,
       error_callback);
@@ -1212,12 +1204,13 @@
       &MTPDeviceDelegateImplLinux::OnPathDoesNotExistForCreateSingleDirectory,
       weak_ptr_factory_.GetWeakPtr(), directory_path, success_callback,
       error_callback);
-  const base::Closure closure =
-      base::Bind(&MTPDeviceDelegateImplLinux::GetFileInfoInternal,
-                 weak_ptr_factory_.GetWeakPtr(), directory_path,
-                 success_callback_wrapper, error_callback_wrapper);
-  EnsureInitAndRunTask(PendingTaskInfo(
-      base::FilePath(), content::BrowserThread::IO, FROM_HERE, closure));
+  base::OnceClosure closure = base::BindOnce(
+      &MTPDeviceDelegateImplLinux::GetFileInfoInternal,
+      weak_ptr_factory_.GetWeakPtr(), directory_path,
+      std::move(success_callback_wrapper), error_callback_wrapper);
+  EnsureInitAndRunTask(PendingTaskInfo(base::FilePath(),
+                                       content::BrowserThread::IO, FROM_HERE,
+                                       std::move(closure)));
   PendingRequestDone();
 }
 
@@ -1233,12 +1226,13 @@
   if (has_more)
     return;  // Wait until all entries have been read.
 
-  const base::Closure closure =
-      base::Bind(&MTPDeviceDelegateImplLinux::CreateDirectoryInternal,
-                 weak_ptr_factory_.GetWeakPtr(), components, exclusive,
-                 success_callback, error_callback);
-  EnsureInitAndRunTask(PendingTaskInfo(
-      base::FilePath(), content::BrowserThread::IO, FROM_HERE, closure));
+  base::OnceClosure closure =
+      base::BindOnce(&MTPDeviceDelegateImplLinux::CreateDirectoryInternal,
+                     weak_ptr_factory_.GetWeakPtr(), components, exclusive,
+                     success_callback, error_callback);
+  EnsureInitAndRunTask(PendingTaskInfo(base::FilePath(),
+                                       content::BrowserThread::IO, FROM_HERE,
+                                       std::move(closure)));
 }
 
 void MTPDeviceDelegateImplLinux::OnDidCheckDirectoryEmptyToDeleteDirectory(
@@ -1274,27 +1268,28 @@
       base::Bind(&MTPDeviceDelegateImplLinux::HandleDeleteFileOrDirectoryError,
                  weak_ptr_factory_.GetWeakPtr(), error_callback);
 
-  const base::Closure closure =
-      base::Bind(&DeleteObjectOnUIThread, storage_name_, read_only_, object_id,
-                 success_callback_wrapper, error_callback_wrapper);
-  EnsureInitAndRunTask(PendingTaskInfo(
-      base::FilePath(), content::BrowserThread::UI, FROM_HERE, closure));
+  base::OnceClosure closure = base::BindOnce(
+      &DeleteObjectOnUIThread, storage_name_, read_only_, object_id,
+      success_callback_wrapper, error_callback_wrapper);
+  EnsureInitAndRunTask(PendingTaskInfo(base::FilePath(),
+                                       content::BrowserThread::UI, FROM_HERE,
+                                       std::move(closure)));
 }
 
 void MTPDeviceDelegateImplLinux::EnsureInitAndRunTask(
-    const PendingTaskInfo& task_info) {
+    PendingTaskInfo task_info) {
   DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
   if ((init_state_ == INITIALIZED) && !task_in_progress_) {
-    RunTask(task_info);
+    RunTask(std::move(task_info));
     return;
   }
 
   // Only *Internal functions have empty paths. Since they are the continuation
   // of the current running task, they get to cut in line.
   if (task_info.path.empty())
-    pending_tasks_.push_front(task_info);
+    pending_tasks_.push_front(std::move(task_info));
   else
-    pending_tasks_.push_back(task_info);
+    pending_tasks_.push_back(std::move(task_info));
 
   if (init_state_ == UNINITIALIZED) {
     init_state_ = PENDING_INIT;
@@ -1307,7 +1302,7 @@
   }
 }
 
-void MTPDeviceDelegateImplLinux::RunTask(const PendingTaskInfo& task_info) {
+void MTPDeviceDelegateImplLinux::RunTask(PendingTaskInfo task_info) {
   DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
   DCHECK_EQ(INITIALIZED, init_state_);
   DCHECK(!task_in_progress_);
@@ -1319,13 +1314,14 @@
         NextUncachedPathComponent(task_info.path, task_info.cached_path);
     if (!uncached_path.empty()) {
       // Save the current task and do a cache lookup first.
-      pending_tasks_.push_front(task_info);
+      pending_tasks_.push_front(std::move(task_info));
       FillFileCache(uncached_path);
       return;
     }
   }
 
-  base::PostTask(task_info.location, {task_info.thread_id}, task_info.task);
+  base::PostTask(task_info.location, {task_info.thread_id},
+                 std::move(task_info.task));
 }
 
 void MTPDeviceDelegateImplLinux::WriteDataIntoSnapshotFile(
@@ -1343,12 +1339,11 @@
           &MTPDeviceDelegateImplLinux::OnWriteDataIntoSnapshotFileError,
           weak_ptr_factory_.GetWeakPtr()));
 
-  base::Closure task_closure = base::Bind(&WriteDataIntoSnapshotFileOnUIThread,
-                                          storage_name_,
-                                          read_only_,
-                                          request_info,
-                                          file_info);
-  content::GetUIThreadTaskRunner({})->PostTask(FROM_HERE, task_closure);
+  base::OnceClosure task_closure =
+      base::BindOnce(&WriteDataIntoSnapshotFileOnUIThread, storage_name_,
+                     read_only_, request_info, file_info);
+  content::GetUIThreadTaskRunner({})->PostTask(FROM_HERE,
+                                               std::move(task_closure));
 }
 
 void MTPDeviceDelegateImplLinux::PendingRequestDone() {
@@ -1364,9 +1359,9 @@
   if (pending_tasks_.empty())
     return;
 
-  PendingTaskInfo task_info = pending_tasks_.front();
+  PendingTaskInfo task_info = std::move(pending_tasks_.front());
   pending_tasks_.pop_front();
-  RunTask(task_info);
+  RunTask(std::move(task_info));
 }
 
 void MTPDeviceDelegateImplLinux::OnInitCompleted(bool succeeded) {
@@ -1376,10 +1371,10 @@
 }
 
 void MTPDeviceDelegateImplLinux::OnDidGetFileInfo(
-    const GetFileInfoSuccessCallback& success_callback,
+    GetFileInfoSuccessCallback success_callback,
     const base::File::Info& file_info) {
   DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
-  success_callback.Run(file_info);
+  std::move(success_callback).Run(file_info);
   PendingRequestDone();
 }
 
@@ -1421,12 +1416,13 @@
   const MTPDeviceTaskHelper::ErrorCallback error_callback_wrapper =
       base::Bind(&MTPDeviceDelegateImplLinux::HandleDeviceFileError,
                  weak_ptr_factory_.GetWeakPtr(), error_callback, *parent_id);
-  const base::Closure closure =
-      base::Bind(&CreateDirectoryOnUIThread, storage_name_, read_only_,
-                 *parent_id, directory_path.BaseName().value(),
-                 success_callback_wrapper, error_callback_wrapper);
-  EnsureInitAndRunTask(PendingTaskInfo(
-      base::FilePath(), content::BrowserThread::UI, FROM_HERE, closure));
+  base::OnceClosure closure =
+      base::BindOnce(&CreateDirectoryOnUIThread, storage_name_, read_only_,
+                     *parent_id, directory_path.BaseName().value(),
+                     success_callback_wrapper, error_callback_wrapper);
+  EnsureInitAndRunTask(PendingTaskInfo(base::FilePath(),
+                                       content::BrowserThread::UI, FROM_HERE,
+                                       std::move(closure)));
 }
 
 void MTPDeviceDelegateImplLinux::OnDidGetFileInfoToReadDirectory(
@@ -1442,13 +1438,14 @@
                                  base::File::FILE_ERROR_NOT_A_DIRECTORY);
   }
 
-  base::Closure task_closure = base::Bind(
+  base::OnceClosure task_closure = base::BindOnce(
       &ReadDirectoryOnUIThread, storage_name_, read_only_, dir_id,
       base::Bind(&MTPDeviceDelegateImplLinux::OnDidReadDirectory,
                  weak_ptr_factory_.GetWeakPtr(), dir_id, success_callback),
       base::Bind(&MTPDeviceDelegateImplLinux::HandleDeviceFileError,
                  weak_ptr_factory_.GetWeakPtr(), error_callback, dir_id));
-  content::GetUIThreadTaskRunner({})->PostTask(FROM_HERE, task_closure);
+  content::GetUIThreadTaskRunner({})->PostTask(FROM_HERE,
+                                               std::move(task_closure));
 }
 
 void MTPDeviceDelegateImplLinux::OnDidGetFileInfoToCreateSnapshotFile(
@@ -1543,12 +1540,13 @@
       &MTPDeviceDelegateImplLinux::OnDidReadDirectoryToCreateDirectory,
       weak_ptr_factory_.GetWeakPtr(), components, exclusive, success_callback,
       error_callback);
-  const base::Closure closure =
-      base::Bind(&MTPDeviceDelegateImplLinux::ReadDirectoryInternal,
-                 weak_ptr_factory_.GetWeakPtr(), created_directory.DirName(),
-                 success_callback_wrapper, error_callback);
-  EnsureInitAndRunTask(PendingTaskInfo(
-      base::FilePath(), content::BrowserThread::IO, FROM_HERE, closure));
+  base::OnceClosure closure = base::BindOnce(
+      &MTPDeviceDelegateImplLinux::ReadDirectoryInternal,
+      weak_ptr_factory_.GetWeakPtr(), created_directory.DirName(),
+      success_callback_wrapper, error_callback);
+  EnsureInitAndRunTask(PendingTaskInfo(base::FilePath(),
+                                       content::BrowserThread::IO, FROM_HERE,
+                                       std::move(closure)));
 }
 
 void MTPDeviceDelegateImplLinux::OnCreateParentDirectoryErrorToCreateDirectory(
diff --git a/chrome/browser/media_galleries/chromeos/mtp_device_delegate_impl_chromeos.h b/chrome/browser/media_galleries/chromeos/mtp_device_delegate_impl_chromeos.h
index ae011007..90b16c3 100644
--- a/chrome/browser/media_galleries/chromeos/mtp_device_delegate_impl_chromeos.h
+++ b/chrome/browser/media_galleries/chromeos/mtp_device_delegate_impl_chromeos.h
@@ -52,15 +52,17 @@
     PendingTaskInfo(const base::FilePath& path,
                     content::BrowserThread::ID thread_id,
                     const base::Location& location,
-                    const base::Closure& task);
-    PendingTaskInfo(const PendingTaskInfo& other);
+                    base::OnceClosure task);
+    PendingTaskInfo(PendingTaskInfo&& other);
+    PendingTaskInfo(const PendingTaskInfo&) = delete;
+    PendingTaskInfo& operator=(const PendingTaskInfo&) = delete;
     ~PendingTaskInfo();
 
     base::FilePath path;
     base::FilePath cached_path;
     const content::BrowserThread::ID thread_id;
     const base::Location location;
-    const base::Closure task;
+    base::OnceClosure task;
   };
 
   class MTPFileNode;
@@ -84,7 +86,7 @@
 
   // MTPDeviceAsyncDelegate:
   void GetFileInfo(const base::FilePath& file_path,
-                   const GetFileInfoSuccessCallback& success_callback,
+                   GetFileInfoSuccessCallback success_callback,
                    const ErrorCallback& error_callback) override;
   void CreateDirectory(const base::FilePath& directory_path,
                        const bool exclusive,
@@ -146,7 +148,7 @@
   // The internal methods correspond to the similarly named methods above.
   // The |root_node_| cache should be filled at this point.
   void GetFileInfoInternal(const base::FilePath& file_path,
-                           const GetFileInfoSuccessCallback& success_callback,
+                           GetFileInfoSuccessCallback success_callback,
                            const ErrorCallback& error_callback);
   void CreateDirectoryInternal(
       const std::vector<base::FilePath>& components,
@@ -233,13 +235,13 @@
   // If the device is uninitialized, store the |task_info| in a pending task
   // queue and runs the pending tasks in the queue once the device is
   // successfully initialized.
-  void EnsureInitAndRunTask(const PendingTaskInfo& task_info);
+  void EnsureInitAndRunTask(PendingTaskInfo task_info);
 
   // Runs a task. If |task_info.path| is empty, or if the path is cached, runs
   // the task immediately.
   // Otherwise, fills the cache first before running the task.
   // |task_info.task| runs on the UI thread.
-  void RunTask(const PendingTaskInfo& task_info);
+  void RunTask(PendingTaskInfo task_info);
 
   // Writes data from the device to the snapshot file path based on the
   // parameters in |current_snapshot_request_info_| by doing a call-and-reply to
@@ -263,7 +265,7 @@
   // Called when GetFileInfo() succeeds. |file_info| specifies the
   // requested file details. |success_callback| is invoked to notify the caller
   // about the requested file details.
-  void OnDidGetFileInfo(const GetFileInfoSuccessCallback& success_callback,
+  void OnDidGetFileInfo(GetFileInfoSuccessCallback success_callback,
                         const base::File::Info& file_info);
 
   // Called when GetFileInfo() of |directory_path| succeeded at checking the
diff --git a/chrome/browser/media_galleries/chromeos/mtp_device_task_helper.cc b/chrome/browser/media_galleries/chromeos/mtp_device_task_helper.cc
index fb16423..da844455 100644
--- a/chrome/browser/media_galleries/chromeos/mtp_device_task_helper.cc
+++ b/chrome/browser/media_galleries/chromeos/mtp_device_task_helper.cc
@@ -106,7 +106,7 @@
 
 void MTPDeviceTaskHelper::GetFileInfo(
     uint32_t file_id,
-    const GetFileInfoSuccessCallback& success_callback,
+    GetFileInfoSuccessCallback success_callback,
     const ErrorCallback& error_callback) {
   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
   if (device_handle_.empty())
@@ -116,8 +116,8 @@
   GetMediaTransferProtocolManager()->GetFileInfo(
       device_handle_, file_ids,
       base::BindOnce(&MTPDeviceTaskHelper::OnGetFileInfo,
-                     weak_ptr_factory_.GetWeakPtr(), success_callback,
-                     error_callback));
+                     weak_ptr_factory_.GetWeakPtr(),
+                     std::move(success_callback), error_callback));
 }
 
 void MTPDeviceTaskHelper::CreateDirectory(
@@ -260,7 +260,7 @@
 }
 
 void MTPDeviceTaskHelper::OnGetFileInfo(
-    const GetFileInfoSuccessCallback& success_callback,
+    GetFileInfoSuccessCallback success_callback,
     const ErrorCallback& error_callback,
     std::vector<device::mojom::MtpFileEntryPtr> entries,
     bool error) const {
@@ -271,8 +271,9 @@
   }
 
   content::GetIOThreadTaskRunner({})->PostTask(
-      FROM_HERE, base::BindOnce(success_callback, FileInfoFromMTPFileEntry(
-                                                      std::move(entries[0]))));
+      FROM_HERE,
+      base::BindOnce(std::move(success_callback),
+                     FileInfoFromMTPFileEntry(std::move(entries[0]))));
 }
 
 void MTPDeviceTaskHelper::OnCreateDirectory(
diff --git a/chrome/browser/media_galleries/chromeos/mtp_device_task_helper.h b/chrome/browser/media_galleries/chromeos/mtp_device_task_helper.h
index 85fe6694..2fbd7a7 100644
--- a/chrome/browser/media_galleries/chromeos/mtp_device_task_helper.h
+++ b/chrome/browser/media_galleries/chromeos/mtp_device_task_helper.h
@@ -42,8 +42,8 @@
 
   typedef base::Callback<void(bool succeeded)> OpenStorageCallback;
 
-  typedef MTPDeviceAsyncDelegate::GetFileInfoSuccessCallback
-      GetFileInfoSuccessCallback;
+  using GetFileInfoSuccessCallback =
+      MTPDeviceAsyncDelegate::GetFileInfoSuccessCallback;
 
   typedef base::Closure CreateDirectorySuccessCallback;
 
@@ -86,7 +86,7 @@
   // If there is an error, |error_callback| is invoked on the IO thread to
   // notify the caller about the file error.
   void GetFileInfo(uint32_t file_id,
-                   const GetFileInfoSuccessCallback& success_callback,
+                   GetFileInfoSuccessCallback success_callback,
                    const ErrorCallback& error_callback);
 
   // Forwards CreateDirectory request to the MediaTransferProtocolManager.
@@ -184,7 +184,7 @@
   // When |entries| has a size other than 1, or if |error| is true, then an
   // error has occurred. In this case, |error_callback| is invoked on the IO
   // thread to notify the caller.
-  void OnGetFileInfo(const GetFileInfoSuccessCallback& success_callback,
+  void OnGetFileInfo(GetFileInfoSuccessCallback success_callback,
                      const ErrorCallback& error_callback,
                      std::vector<device::mojom::MtpFileEntryPtr> entries,
                      bool error) const;
diff --git a/chrome/browser/media_galleries/fileapi/device_media_async_file_util.cc b/chrome/browser/media_galleries/fileapi/device_media_async_file_util.cc
index 47400a7c..732583f 100644
--- a/chrome/browser/media_galleries/fileapi/device_media_async_file_util.cc
+++ b/chrome/browser/media_galleries/fileapi/device_media_async_file_util.cc
@@ -375,10 +375,10 @@
   auto copyable_callback = base::AdaptCallbackForRepeating(std::move(callback));
   delegate->GetFileInfo(
       url.path(),
-      base::Bind(&DeviceMediaAsyncFileUtil::OnDidGetFileInfo,
-                 weak_ptr_factory_.GetWeakPtr(),
-                 base::RetainedRef(context->task_runner()), url.path(),
-                 copyable_callback),
+      base::BindOnce(&DeviceMediaAsyncFileUtil::OnDidGetFileInfo,
+                     weak_ptr_factory_.GetWeakPtr(),
+                     base::RetainedRef(context->task_runner()), url.path(),
+                     copyable_callback),
       base::BindRepeating(&OnGetFileInfoError, copyable_callback));
 }
 
diff --git a/chrome/browser/media_galleries/fileapi/mtp_device_async_delegate.h b/chrome/browser/media_galleries/fileapi/mtp_device_async_delegate.h
index 012ba38..97b5033e6 100644
--- a/chrome/browser/media_galleries/fileapi/mtp_device_async_delegate.h
+++ b/chrome/browser/media_galleries/fileapi/mtp_device_async_delegate.h
@@ -30,8 +30,8 @@
 class MTPDeviceAsyncDelegate {
  public:
   // A callback to be called when GetFileInfo method call succeeds.
-  typedef base::Callback<
-      void(const base::File::Info& file_info)> GetFileInfoSuccessCallback;
+  using GetFileInfoSuccessCallback =
+      base::OnceCallback<void(const base::File::Info& file_info)>;
 
   // A callback to be called when CreateDirectory method call succeeds.
   typedef base::RepeatingClosure CreateDirectorySuccessCallback;
@@ -98,10 +98,9 @@
 
   // Gets information about the given |file_path| and invokes the appropriate
   // callback asynchronously when complete.
-  virtual void GetFileInfo(
-      const base::FilePath& file_path,
-      const GetFileInfoSuccessCallback& success_callback,
-      const ErrorCallback& error_callback) = 0;
+  virtual void GetFileInfo(const base::FilePath& file_path,
+                           GetFileInfoSuccessCallback success_callback,
+                           const ErrorCallback& error_callback) = 0;
 
   // Creates a directory to |directory_path|. When |exclusive| is true, this
   // returns base::File::FILE_ERROR_EXISTS if a directory already exists for
diff --git a/chrome/browser/media_galleries/fileapi/mtp_file_stream_reader.cc b/chrome/browser/media_galleries/fileapi/mtp_file_stream_reader.cc
index 1441ef6..7604e4f1 100644
--- a/chrome/browser/media_galleries/fileapi/mtp_file_stream_reader.cc
+++ b/chrome/browser/media_galleries/fileapi/mtp_file_stream_reader.cc
@@ -91,8 +91,8 @@
   get_length_callback_ = std::move(callback);
   delegate->GetFileInfo(
       url_.path(),
-      base::Bind(&MTPFileStreamReader::FinishGetLength,
-                 weak_factory_.GetWeakPtr()),
+      base::BindOnce(&MTPFileStreamReader::FinishGetLength,
+                     weak_factory_.GetWeakPtr()),
       base::BindRepeating(
           &MTPFileStreamReader::CallGetLengthCallbackWithPlatformFileError,
           weak_factory_.GetWeakPtr()));
diff --git a/chrome/browser/media_galleries/mac/mtp_device_delegate_impl_mac.h b/chrome/browser/media_galleries/mac/mtp_device_delegate_impl_mac.h
index d6eec8c..061d088 100644
--- a/chrome/browser/media_galleries/mac/mtp_device_delegate_impl_mac.h
+++ b/chrome/browser/media_galleries/mac/mtp_device_delegate_impl_mac.h
@@ -36,7 +36,7 @@
   // IO thread by the async filesystem file util. They forward to
   // similarly-named methods on the UI thread.
   void GetFileInfo(const base::FilePath& file_path,
-                   const GetFileInfoSuccessCallback& success_callback,
+                   GetFileInfoSuccessCallback success_callback,
                    const ErrorCallback& error_callback) override;
 
   void CreateDirectory(const base::FilePath& directory_path,
diff --git a/chrome/browser/media_galleries/mac/mtp_device_delegate_impl_mac.mm b/chrome/browser/media_galleries/mac/mtp_device_delegate_impl_mac.mm
index 557e596..b133424 100644
--- a/chrome/browser/media_galleries/mac/mtp_device_delegate_impl_mac.mm
+++ b/chrome/browser/media_galleries/mac/mtp_device_delegate_impl_mac.mm
@@ -149,13 +149,12 @@
 
 namespace {
 
-void ForwardGetFileInfo(
-    base::File::Info* info,
-    base::File::Error* error,
-    const GetFileInfoSuccessCallback& success_callback,
-    const ErrorCallback& error_callback) {
+void ForwardGetFileInfo(base::File::Info* info,
+                        base::File::Error* error,
+                        GetFileInfoSuccessCallback success_callback,
+                        const ErrorCallback& error_callback) {
   if (*error == base::File::FILE_OK)
-    success_callback.Run(*info);
+    std::move(success_callback).Run(*info);
   else
     error_callback.Run(*error);
 }
@@ -164,7 +163,7 @@
 
 void MTPDeviceDelegateImplMac::GetFileInfo(
     const base::FilePath& file_path,
-    const GetFileInfoSuccessCallback& success_callback,
+    GetFileInfoSuccessCallback success_callback,
     const ErrorCallback& error_callback) {
   base::File::Info* info = new base::File::Info;
   base::File::Error* error = new base::File::Error;
@@ -173,8 +172,8 @@
       FROM_HERE,
       base::Bind(&MTPDeviceDelegateImplMac::GetFileInfoImpl,
                  base::Unretained(this), file_path, info, error),
-      base::Bind(&ForwardGetFileInfo, base::Owned(info), base::Owned(error),
-                 success_callback, error_callback));
+      base::BindOnce(&ForwardGetFileInfo, base::Owned(info), base::Owned(error),
+                     std::move(success_callback), error_callback));
 }
 
 void MTPDeviceDelegateImplMac::CreateDirectory(
diff --git a/chrome/browser/media_galleries/win/mtp_device_delegate_impl_win.cc b/chrome/browser/media_galleries/win/mtp_device_delegate_impl_win.cc
index 96e5634..0ebf5fe 100644
--- a/chrome/browser/media_galleries/win/mtp_device_delegate_impl_win.cc
+++ b/chrome/browser/media_galleries/win/mtp_device_delegate_impl_win.cc
@@ -373,7 +373,7 @@
 
 void MTPDeviceDelegateImplWin::GetFileInfo(
     const base::FilePath& file_path,
-    const GetFileInfoSuccessCallback& success_callback,
+    GetFileInfoSuccessCallback success_callback,
     const ErrorCallback& error_callback) {
   DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
   DCHECK(!file_path.empty());
@@ -383,8 +383,9 @@
       base::BindOnce(&GetFileInfoOnBlockingPoolThread, storage_device_info_,
                      file_path, base::Unretained(file_info)),
       base::BindOnce(&MTPDeviceDelegateImplWin::OnGetFileInfo,
-                     weak_ptr_factory_.GetWeakPtr(), success_callback,
-                     error_callback, base::Owned(file_info))));
+                     weak_ptr_factory_.GetWeakPtr(),
+                     std::move(success_callback), error_callback,
+                     base::Owned(file_info))));
 }
 
 void MTPDeviceDelegateImplWin::CreateDirectory(
@@ -582,14 +583,14 @@
 }
 
 void MTPDeviceDelegateImplWin::OnGetFileInfo(
-    const GetFileInfoSuccessCallback& success_callback,
+    GetFileInfoSuccessCallback success_callback,
     const ErrorCallback& error_callback,
     base::File::Info* file_info,
     base::File::Error error) {
   DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
   DCHECK(file_info);
   if (error == base::File::FILE_OK)
-    success_callback.Run(*file_info);
+    std::move(success_callback).Run(*file_info);
   else
     error_callback.Run(error);
   task_in_progress_ = false;
diff --git a/chrome/browser/media_galleries/win/mtp_device_delegate_impl_win.h b/chrome/browser/media_galleries/win/mtp_device_delegate_impl_win.h
index 1611a6d5..b7a087b 100644
--- a/chrome/browser/media_galleries/win/mtp_device_delegate_impl_win.h
+++ b/chrome/browser/media_galleries/win/mtp_device_delegate_impl_win.h
@@ -95,7 +95,7 @@
 
   // MTPDeviceAsyncDelegate:
   void GetFileInfo(const base::FilePath& file_path,
-                   const GetFileInfoSuccessCallback& success_callback,
+                   GetFileInfoSuccessCallback success_callback,
                    const ErrorCallback& error_callback) override;
   void CreateDirectory(
       const base::FilePath& directory_path,
@@ -189,7 +189,7 @@
   //
   // If the GetFileInfo() fails, |file_info| is not set and |error_callback| is
   // invoked to notify the caller about the platform file |error|.
-  void OnGetFileInfo(const GetFileInfoSuccessCallback& success_callback,
+  void OnGetFileInfo(GetFileInfoSuccessCallback success_callback,
                      const ErrorCallback& error_callback,
                      base::File::Info* file_info,
                      base::File::Error error);
diff --git a/chrome/browser/net/nss_service_chromeos.cc b/chrome/browser/net/nss_service_chromeos.cc
new file mode 100644
index 0000000..f252ad4
--- /dev/null
+++ b/chrome/browser/net/nss_service_chromeos.cc
@@ -0,0 +1,188 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/net/nss_service_chromeos.h"
+
+#include <memory>
+
+#include "base/bind.h"
+#include "base/callback.h"
+#include "base/logging.h"
+#include "base/single_thread_task_runner.h"
+#include "chrome/browser/ash/login/startup_utils.h"
+#include "chrome/browser/ash/profiles/profile_helper.h"
+#include "chrome/browser/net/nss_context.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chromeos/dbus/cryptohome/cryptohome_client.h"
+#include "chromeos/dbus/dbus_thread_manager.h"
+#include "chromeos/settings/cros_settings_names.h"
+#include "chromeos/tpm/tpm_token_info_getter.h"
+#include "components/user_manager/user.h"
+#include "components/user_manager/user_manager.h"
+#include "content/public/browser/browser_task_traits.h"
+#include "content/public/browser/browser_thread.h"
+#include "crypto/nss_util.h"
+#include "crypto/nss_util_internal.h"
+
+using content::BrowserThread;
+
+namespace {
+
+// The following four functions are responsible for initializing NSS for each
+// profile on ChromeOS Ash, which has a separate NSS database and TPM slot
+// per-profile.
+//
+// Initialization basically follows these steps:
+// 1) Get some info from user_manager::UserManager about the User for this
+// profile.
+// 2) Tell nss_util to initialize the software slot for this profile.
+// 3) Wait for the TPM module to be loaded by nss_util if it isn't already.
+// 4) Ask CryptohomeClient which TPM slot id corresponds to this profile.
+// 5) Tell nss_util to use that slot id on the TPM module.
+//
+// Some of these steps must happen on the UI thread, others must happen on the
+// IO thread:
+//               UI thread                              IO Thread
+//
+//  NssServiceChromeOS::NssServiceChromeOS
+//                   |
+//  ProfileHelper::Get()->GetUserByProfile()
+//                   \---------------------------------------v
+//                                                 StartNSSInitOnIOThread
+//                                                           |
+//                                          crypto::InitializeNSSForChromeOSUser
+//                                                           |
+//                                                crypto::IsTPMTokenReady
+//                                                           |
+//                                          StartTPMSlotInitializationOnIOThread
+//                   v---------------------------------------/
+//     GetTPMInfoForUserOnUIThread
+//                   |
+// chromeos::TPMTokenInfoGetter::Start
+//                   |
+//     DidGetTPMInfoForUserOnUIThread
+//                   \---------------------------------------v
+//                                          crypto::InitializeTPMForChromeOSUser
+
+void DidGetTPMInfoForUserOnUIThread(
+    std::unique_ptr<chromeos::TPMTokenInfoGetter> getter,
+    const std::string& username_hash,
+    base::Optional<chromeos::CryptohomeClient::TpmTokenInfo> token_info) {
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  if (token_info.has_value() && token_info->slot != -1) {
+    DVLOG(1) << "Got TPM slot for " << username_hash << ": "
+             << token_info->slot;
+    content::GetIOThreadTaskRunner({})->PostTask(
+        FROM_HERE, base::BindOnce(&crypto::InitializeTPMForChromeOSUser,
+                                  username_hash, token_info->slot));
+  } else {
+    NOTREACHED() << "TPMTokenInfoGetter reported invalid token.";
+  }
+}
+
+void GetTPMInfoForUserOnUIThread(const AccountId& account_id,
+                                 const std::string& username_hash) {
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  DVLOG(1) << "Getting TPM info from cryptohome for "
+           << " " << account_id.Serialize() << " " << username_hash;
+  std::unique_ptr<chromeos::TPMTokenInfoGetter> scoped_token_info_getter =
+      chromeos::TPMTokenInfoGetter::CreateForUserToken(
+          account_id, chromeos::CryptohomeClient::Get(),
+          base::ThreadTaskRunnerHandle::Get());
+  chromeos::TPMTokenInfoGetter* token_info_getter =
+      scoped_token_info_getter.get();
+
+  // Bind |token_info_getter| to the callback to ensure it does not go away
+  // before TPM token info is fetched.
+  token_info_getter->Start(base::BindOnce(&DidGetTPMInfoForUserOnUIThread,
+                                          std::move(scoped_token_info_getter),
+                                          username_hash));
+}
+
+void StartTPMSlotInitializationOnIOThread(const AccountId& account_id,
+                                          const std::string& username_hash) {
+  DCHECK_CURRENTLY_ON(BrowserThread::IO);
+
+  content::GetUIThreadTaskRunner({})->PostTask(
+      FROM_HERE,
+      base::BindOnce(&GetTPMInfoForUserOnUIThread, account_id, username_hash));
+}
+
+void StartNSSInitOnIOThread(const AccountId& account_id,
+                            const std::string& username_hash,
+                            const base::FilePath& path) {
+  DCHECK_CURRENTLY_ON(BrowserThread::IO);
+  DVLOG(1) << "Starting NSS init for " << account_id.Serialize()
+           << "  hash:" << username_hash;
+
+  // Make sure NSS is initialized for the user.
+  crypto::InitializeNSSForChromeOSUser(username_hash, path);
+
+  // Check if it's OK to initialize TPM for the user before continuing. This
+  // may not be the case if the TPM slot initialization was previously
+  // requested for the same user.
+  if (!crypto::ShouldInitializeTPMForChromeOSUser(username_hash))
+    return;
+
+  crypto::WillInitializeTPMForChromeOSUser(username_hash);
+
+  if (crypto::IsTPMTokenEnabledForNSS()) {
+    if (crypto::IsTPMTokenReady(
+            base::BindOnce(&StartTPMSlotInitializationOnIOThread, account_id,
+                           username_hash))) {
+      StartTPMSlotInitializationOnIOThread(account_id, username_hash);
+    } else {
+      DVLOG(1) << "Waiting for tpm ready ...";
+    }
+  } else {
+    crypto::InitializePrivateSoftwareSlotForChromeOSUser(username_hash);
+  }
+}
+
+void EnableNSSSystemKeySlotOnIOThread(
+    content::ResourceContext* resource_context,
+    const std::string& username_hash,
+    bool user_is_affiliated) {
+  SetNSSCertDatabaseUsernameHash(resource_context, username_hash);
+  if (user_is_affiliated)
+    EnableNSSSystemKeySlotForResourceContext(resource_context);
+}
+
+}  // namespace
+
+NssServiceChromeOS::NssServiceChromeOS(Profile* profile) {
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+
+  const user_manager::User* user =
+      chromeos::ProfileHelper::Get()->GetUserByProfile(profile);
+  // No need to initialize NSS for users with empty username hash:
+  // Getters for a user's NSS slots always return a null slot if the user's
+  // username hash is empty, even when the NSS is not initialized for the
+  // user.
+  std::string username_hash;
+  bool user_is_affiliated = false;
+  if (user && !user->username_hash().empty()) {
+    username_hash = user->username_hash();
+    DCHECK(!username_hash.empty());
+    content::GetIOThreadTaskRunner({})->PostTask(
+        FROM_HERE, base::BindOnce(&StartNSSInitOnIOThread, user->GetAccountId(),
+                                  username_hash, profile->GetPath()));
+
+    user_is_affiliated = user->IsAffiliated();
+  }
+
+  // We need to make sure that content initializes its own data structures that
+  // are associated with each ResourceContext because we might post this
+  // object to the IO thread after this function.
+  content::BrowserContext::EnsureResourceContextInitialized(profile);
+
+  DCHECK(!(username_hash.empty() && user_is_affiliated));
+
+  content::GetIOThreadTaskRunner({})->PostTask(
+      FROM_HERE, base::BindOnce(&EnableNSSSystemKeySlotOnIOThread,
+                                profile->GetResourceContext(), username_hash,
+                                user_is_affiliated));
+}
+
+NssServiceChromeOS::~NssServiceChromeOS() = default;
diff --git a/chrome/browser/net/nss_service_chromeos.h b/chrome/browser/net/nss_service_chromeos.h
new file mode 100644
index 0000000..5f1d3c3
--- /dev/null
+++ b/chrome/browser/net/nss_service_chromeos.h
@@ -0,0 +1,26 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_NET_NSS_SERVICE_CHROMEOS_H_
+#define CHROME_BROWSER_NET_NSS_SERVICE_CHROMEOS_H_
+
+#include "components/keyed_service/core/keyed_service.h"
+
+class Profile;
+
+// ChromeOS Ash service that manages initialization of NSS and the per-profile
+// certificate database.
+class NssServiceChromeOS : public KeyedService {
+ public:
+  explicit NssServiceChromeOS(Profile* profile);
+  NssServiceChromeOS(const NssServiceChromeOS&) = delete;
+  NssServiceChromeOS& operator=(const NssServiceChromeOS&) = delete;
+  ~NssServiceChromeOS() override;
+
+ private:
+  // TODO(https://cbug.com/1018972):  Move ownership of
+  // NSSCertDatabaseChromeOSManager to this class.
+};
+
+#endif  // CHROME_BROWSER_NET_NSS_SERVICE_CHROMEOS_H_
diff --git a/chrome/browser/net/nss_service_chromeos_factory.cc b/chrome/browser/net/nss_service_chromeos_factory.cc
new file mode 100644
index 0000000..747245ea
--- /dev/null
+++ b/chrome/browser/net/nss_service_chromeos_factory.cc
@@ -0,0 +1,40 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/net/nss_service_chromeos_factory.h"
+
+#include "base/no_destructor.h"
+#include "build/build_config.h"
+#include "chrome/browser/net/nss_service_chromeos.h"
+#include "chrome/browser/profiles/profile.h"
+#include "components/keyed_service/content/browser_context_dependency_manager.h"
+
+NssServiceChromeOS* NssServiceChromeOSFactory::GetForContext(
+    content::BrowserContext* browser_context) {
+  return static_cast<NssServiceChromeOS*>(
+      GetInstance().GetServiceForBrowserContext(browser_context, true));
+}
+
+NssServiceChromeOSFactory::NssServiceChromeOSFactory()
+    : BrowserContextKeyedServiceFactory(
+          "NssServiceChromeOSFactory",
+          BrowserContextDependencyManager::GetInstance()) {}
+
+NssServiceChromeOSFactory::~NssServiceChromeOSFactory() = default;
+
+NssServiceChromeOSFactory& NssServiceChromeOSFactory::GetInstance() {
+  static base::NoDestructor<NssServiceChromeOSFactory> instance;
+  return *instance;
+}
+
+KeyedService* NssServiceChromeOSFactory::BuildServiceInstanceFor(
+    content::BrowserContext* profile) const {
+  return new NssServiceChromeOS(Profile::FromBrowserContext(profile));
+}
+
+content::BrowserContext* NssServiceChromeOSFactory::GetBrowserContextToUse(
+    content::BrowserContext* context) const {
+  // Create separate service for incognito profiles.
+  return context;
+}
diff --git a/chrome/browser/net/nss_service_chromeos_factory.h b/chrome/browser/net/nss_service_chromeos_factory.h
new file mode 100644
index 0000000..dd8c68f
--- /dev/null
+++ b/chrome/browser/net/nss_service_chromeos_factory.h
@@ -0,0 +1,41 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_NET_NSS_SERVICE_CHROMEOS_FACTORY_H_
+#define CHROME_BROWSER_NET_NSS_SERVICE_CHROMEOS_FACTORY_H_
+
+#include "base/no_destructor.h"
+#include "components/keyed_service/content/browser_context_keyed_service_factory.h"
+
+class NssServiceChromeOS;
+
+namespace content {
+class BrowserContext;
+}
+
+class NssServiceChromeOSFactory : public BrowserContextKeyedServiceFactory {
+ public:
+  // Returns the NssServiceChromeOS for |browser_context|.
+  static NssServiceChromeOS* GetForContext(
+      content::BrowserContext* browser_context);
+
+ private:
+  friend base::NoDestructor<NssServiceChromeOSFactory>;
+
+  NssServiceChromeOSFactory();
+  NssServiceChromeOSFactory(const NssServiceChromeOSFactory&) = delete;
+  NssServiceChromeOSFactory& operator=(const NssServiceChromeOSFactory&) =
+      delete;
+  ~NssServiceChromeOSFactory() override;
+
+  static NssServiceChromeOSFactory& GetInstance();
+
+  // BrowserContextKeyedServiceFactory implementation:
+  KeyedService* BuildServiceInstanceFor(
+      content::BrowserContext* profile) const override;
+  content::BrowserContext* GetBrowserContextToUse(
+      content::BrowserContext* context) const override;
+};
+
+#endif  // CHROME_BROWSER_NET_NSS_SERVICE_CHROMEOS_FACTORY_H_
diff --git a/chrome/browser/net/profile_network_context_service.cc b/chrome/browser/net/profile_network_context_service.cc
index fef9dd72..3adf28ee 100644
--- a/chrome/browser/net/profile_network_context_service.cc
+++ b/chrome/browser/net/profile_network_context_service.cc
@@ -852,7 +852,7 @@
 
   // Should be initialized with existing per-profile CORS access lists.
   network_context_params->cors_origin_access_list =
-      profile_->GetSharedCorsOriginAccessList()
+      content::BrowserContext::GetSharedCorsOriginAccessList(profile_)
           ->GetOriginAccessList()
           .CreateCorsOriginAccessPatternsList();
 
diff --git a/chrome/browser/net/profile_network_context_service.h b/chrome/browser/net/profile_network_context_service.h
index 44a7648..61572b2 100644
--- a/chrome/browser/net/profile_network_context_service.h
+++ b/chrome/browser/net/profile_network_context_service.h
@@ -104,7 +104,7 @@
   FRIEND_TEST_ALL_PREFIXES(ProfileNetworkContextServiceDiskCacheBrowsertest,
                            DiskCacheSize);
   FRIEND_TEST_ALL_PREFIXES(
-      ProfileNetworkContextServiceCertVerifierBuiltinFeaturePolicyTest,
+      ProfileNetworkContextServiceCertVerifierBuiltinPermissionsPolicyTest,
       Test);
 
   friend class AmbientAuthenticationTestHelper;
diff --git a/chrome/browser/net/profile_network_context_service_browsertest.cc b/chrome/browser/net/profile_network_context_service_browsertest.cc
index 3e0ef84..d4ed4cf 100644
--- a/chrome/browser/net/profile_network_context_service_browsertest.cc
+++ b/chrome/browser/net/profile_network_context_service_browsertest.cc
@@ -508,7 +508,7 @@
 }
 }  // namespace
 
-class ProfileNetworkContextServiceCertVerifierBuiltinFeaturePolicyTest
+class ProfileNetworkContextServiceCertVerifierBuiltinPermissionsPolicyTest
     : public policy::PolicyTest,
       public testing::WithParamInterface<bool> {
  public:
@@ -566,7 +566,7 @@
 };
 
 IN_PROC_BROWSER_TEST_P(
-    ProfileNetworkContextServiceCertVerifierBuiltinFeaturePolicyTest,
+    ProfileNetworkContextServiceCertVerifierBuiltinPermissionsPolicyTest,
     Test) {
   {
     content::BrowserContext::GetDefaultStoragePartition(CreateNewProfile())
@@ -614,7 +614,7 @@
 
 INSTANTIATE_TEST_SUITE_P(
     All,
-    ProfileNetworkContextServiceCertVerifierBuiltinFeaturePolicyTest,
+    ProfileNetworkContextServiceCertVerifierBuiltinPermissionsPolicyTest,
     ::testing::Bool());
 #endif  // BUILDFLAG(BUILTIN_CERT_VERIFIER_FEATURE_SUPPORTED)
 
diff --git a/chrome/browser/net/system_network_context_manager.cc b/chrome/browser/net/system_network_context_manager.cc
index c15186c8..0110dc7 100644
--- a/chrome/browser/net/system_network_context_manager.cc
+++ b/chrome/browser/net/system_network_context_manager.cc
@@ -594,7 +594,10 @@
   if (base::FeatureList::IsEnabled(blink::features::kFreezeUserAgent)) {
     quic_user_agent_id = "";
   } else {
-    quic_user_agent_id = chrome::GetChannelName();
+    // Extended stable reports as regular stable due to the similarity, and to
+    // avoid adding more signal to the user agent string.
+    quic_user_agent_id =
+        chrome::GetChannelName(chrome::WithExtendedStable(false));
     if (!quic_user_agent_id.empty())
       quic_user_agent_id.push_back(' ');
     quic_user_agent_id.append(
diff --git a/chrome/browser/net/system_network_context_manager.h b/chrome/browser/net/system_network_context_manager.h
index 95903f64..6cee89ba 100644
--- a/chrome/browser/net/system_network_context_manager.h
+++ b/chrome/browser/net/system_network_context_manager.h
@@ -165,7 +165,7 @@
 
  private:
   FRIEND_TEST_ALL_PREFIXES(
-      SystemNetworkContextServiceCertVerifierBuiltinFeaturePolicyTest,
+      SystemNetworkContextServiceCertVerifierBuiltinPermissionsPolicyTest,
       Test);
 
   class URLLoaderFactoryForSystem;
diff --git a/chrome/browser/net/system_network_context_manager_browsertest.cc b/chrome/browser/net/system_network_context_manager_browsertest.cc
index c2dc67db8..7a0831a 100644
--- a/chrome/browser/net/system_network_context_manager_browsertest.cc
+++ b/chrome/browser/net/system_network_context_manager_browsertest.cc
@@ -392,7 +392,8 @@
   if (GetParam()) {  // if the UA Freeze feature is turned on
     EXPECT_EQ("", quic_ua);
   } else {
-    EXPECT_THAT(quic_ua, testing::HasSubstr(chrome::GetChannelName()));
+    EXPECT_THAT(quic_ua, testing::HasSubstr(chrome::GetChannelName(
+                             chrome::WithExtendedStable(false))));
     EXPECT_THAT(quic_ua,
                 testing::HasSubstr(
                     version_info::GetProductNameAndVersionForUserAgent()));
@@ -482,11 +483,11 @@
     ::testing::Values(base::nullopt, true, false));
 
 #if BUILDFLAG(BUILTIN_CERT_VERIFIER_FEATURE_SUPPORTED)
-class SystemNetworkContextServiceCertVerifierBuiltinFeaturePolicyTest
+class SystemNetworkContextServiceCertVerifierBuiltinPermissionsPolicyTest
     : public policy::PolicyTest,
       public testing::WithParamInterface<bool> {
  public:
-  SystemNetworkContextServiceCertVerifierBuiltinFeaturePolicyTest() {
+  SystemNetworkContextServiceCertVerifierBuiltinPermissionsPolicyTest() {
     bool use_builtin_cert_verifier = GetParam();
     cert_verifier_impl_ =
         use_builtin_cert_verifier
@@ -548,7 +549,7 @@
 };
 
 IN_PROC_BROWSER_TEST_P(
-    SystemNetworkContextServiceCertVerifierBuiltinFeaturePolicyTest,
+    SystemNetworkContextServiceCertVerifierBuiltinPermissionsPolicyTest,
     Test) {
   network::mojom::NetworkContextParamsPtr network_context_params_ptr;
 
@@ -591,6 +592,6 @@
 
 INSTANTIATE_TEST_SUITE_P(
     All,
-    SystemNetworkContextServiceCertVerifierBuiltinFeaturePolicyTest,
+    SystemNetworkContextServiceCertVerifierBuiltinPermissionsPolicyTest,
     ::testing::Bool());
 #endif  // BUILDFLAG(BUILTIN_CERT_VERIFIER_FEATURE_SUPPORTED)
diff --git a/chrome/browser/payments/android/java/src/org/chromium/chrome/browser/payments/ChromePaymentRequestFactoryTest.java b/chrome/browser/payments/android/java/src/org/chromium/chrome/browser/payments/ChromePaymentRequestFactoryTest.java
index f94a3ab0c..bbd681d5 100644
--- a/chrome/browser/payments/android/java/src/org/chromium/chrome/browser/payments/ChromePaymentRequestFactoryTest.java
+++ b/chrome/browser/payments/android/java/src/org/chromium/chrome/browser/payments/ChromePaymentRequestFactoryTest.java
@@ -55,10 +55,10 @@
         Mockito.doReturn(true).when(mProfile).isOffTheRecord();
         ShadowProfile.setProfile(mProfile);
 
-        setPaymentFeaturePolicy(true);
+        setPaymentPermissionsPolicy(true);
     }
 
-    private void setPaymentFeaturePolicy(boolean enabled) {
+    private void setPaymentPermissionsPolicy(boolean enabled) {
         Mockito.doReturn(enabled)
                 .when(mRenderFrameHost)
                 .isFeatureEnabled(PermissionsPolicyFeature.PAYMENT);
@@ -82,7 +82,7 @@
     @Test
     @Feature({"Payments"})
     public void testDisabledPolicyCausesBadMessage() {
-        setPaymentFeaturePolicy(false);
+        setPaymentPermissionsPolicy(false);
         AtomicInteger isKilledReason = new AtomicInteger(0);
         Mockito.doAnswer(invocation -> {
                    isKilledReason.set((int) invocation.getArguments()[0]);
diff --git a/chrome/browser/permissions/permission_context_base_permissions_policy_unittest.cc b/chrome/browser/permissions/permission_context_base_permissions_policy_unittest.cc
index 181f63d..3ef9edc6 100644
--- a/chrome/browser/permissions/permission_context_base_permissions_policy_unittest.cc
+++ b/chrome/browser/permissions/permission_context_base_permissions_policy_unittest.cc
@@ -34,10 +34,10 @@
 // permissions_policy_unittest.cc and in
 // render_frame_host_permissions_policy_unittest.cc. Instead they are meant to
 // ensure that integration with content::PermissionContextBase works correctly.
-class PermissionContextBaseFeaturePolicyTest
+class PermissionContextBasePermissionsPolicyTest
     : public ChromeRenderViewHostTestHarness {
  public:
-  PermissionContextBaseFeaturePolicyTest()
+  PermissionContextBasePermissionsPolicyTest()
       : last_request_result_(CONTENT_SETTING_DEFAULT), request_id_(0) {}
 
   void SetUp() override { ChromeRenderViewHostTestHarness::SetUp(); }
@@ -86,7 +86,7 @@
     std::vector<url::Origin> parsed_origins;
     for (const std::string& origin : origins)
       parsed_origins.push_back(url::Origin::Create(GURL(origin)));
-    navigation->SetFeaturePolicyHeader(
+    navigation->SetPermissionsPolicyHeader(
         {{feature, parsed_origins, false, false}});
     navigation->Commit();
     *rfh = navigation->GetFinalRenderFrameHost();
@@ -108,7 +108,7 @@
     pcb->RequestPermission(
         content::WebContents::FromRenderFrameHost(rfh), id,
         rfh->GetLastCommittedURL(), /*user_gesture=*/true,
-        base::BindOnce(&PermissionContextBaseFeaturePolicyTest::
+        base::BindOnce(&PermissionContextBasePermissionsPolicyTest::
                            RequestPermissionForFrameFinished,
                        base::Unretained(this)));
     EXPECT_NE(CONTENT_SETTING_DEFAULT, last_request_result_);
@@ -145,7 +145,7 @@
   int request_id_;
 };
 
-TEST_F(PermissionContextBaseFeaturePolicyTest, DefaultPolicy) {
+TEST_F(PermissionContextBasePermissionsPolicyTest, DefaultPolicy) {
   content::RenderFrameHost* parent = GetMainRFH(kOrigin1);
   content::RenderFrameHost* child = AddChildRFH(parent, kOrigin2);
 
@@ -168,7 +168,7 @@
             GetPermissionForFrame(&notifications, child));
 }
 
-TEST_F(PermissionContextBaseFeaturePolicyTest, DisabledTopLevelFrame) {
+TEST_F(PermissionContextBasePermissionsPolicyTest, DisabledTopLevelFrame) {
   content::RenderFrameHost* parent = GetMainRFH(kOrigin1);
 
   // Disable midi in the top level frame.
@@ -192,7 +192,7 @@
             GetPermissionForFrame(geolocation.get(), child));
 }
 
-TEST_F(PermissionContextBaseFeaturePolicyTest, EnabledForChildFrame) {
+TEST_F(PermissionContextBasePermissionsPolicyTest, EnabledForChildFrame) {
   content::RenderFrameHost* parent = GetMainRFH(kOrigin1);
 
   // Enable midi for the child frame.
@@ -212,7 +212,7 @@
             GetPermissionForFrame(geolocation.get(), child));
 }
 
-TEST_F(PermissionContextBaseFeaturePolicyTest, RequestPermission) {
+TEST_F(PermissionContextBasePermissionsPolicyTest, RequestPermission) {
   content::RenderFrameHost* parent = GetMainRFH(kOrigin1);
 
   HostContentSettingsMapFactory::GetForProfile(profile())
diff --git a/chrome/browser/preferences/android/java/src/org/chromium/chrome/browser/preferences/ChromePreferenceKeys.java b/chrome/browser/preferences/android/java/src/org/chromium/chrome/browser/preferences/ChromePreferenceKeys.java
index 31ffae1b..5b4bfbc 100644
--- a/chrome/browser/preferences/android/java/src/org/chromium/chrome/browser/preferences/ChromePreferenceKeys.java
+++ b/chrome/browser/preferences/android/java/src/org/chromium/chrome/browser/preferences/ChromePreferenceKeys.java
@@ -52,6 +52,9 @@
     public static final String ACCOUNT_PICKER_BOTTOM_SHEET_SHOWN_COUNT =
             "Chrome.AccountPickerBottomSheet.ShownCount";
 
+    public static final String ACCOUNT_PICKER_BOTTOM_SHEET_ACTIVE_DISMISSAL_COUNT =
+            "Chrome.AccountPickerBottomSheet.ConsecutiveActiveDismissalCount";
+
     /** The language code to override application language with. */
     public static final String APPLICATION_OVERRIDE_LANGUAGE =
             "Chrome.Language.ApplicationOverrideLanguage";
@@ -855,6 +858,7 @@
         // clang-format off
         return Arrays.asList(
                 ACCOUNT_PICKER_BOTTOM_SHEET_SHOWN_COUNT,
+                ACCOUNT_PICKER_BOTTOM_SHEET_ACTIVE_DISMISSAL_COUNT,
                 ASSISTANT_VOICE_SEARCH_ENABLED,
                 AUTOFILL_ASSISTANT_FIRST_TIME_LITE_SCRIPT_USER,
                 AUTOFILL_ASSISTANT_NUMBER_OF_LITE_SCRIPTS_CANCELED,
diff --git a/chrome/browser/profiles/profile.cc b/chrome/browser/profiles/profile.cc
index 8e8a7ab..3840c66 100644
--- a/chrome/browser/profiles/profile.cc
+++ b/chrome/browser/profiles/profile.cc
@@ -25,7 +25,6 @@
 #include "components/variations/variations.mojom.h"
 #include "components/variations/variations_client.h"
 #include "components/variations/variations_ids_provider.h"
-#include "content/public/browser/cors_origin_pattern_setter.h"
 #include "content/public/browser/shared_cors_origin_access_list.h"
 #include "content/public/browser/storage_partition.h"
 #include "content/public/browser/web_contents.h"
@@ -169,9 +168,7 @@
 }
 #endif
 
-Profile::Profile()
-    : shared_cors_origin_access_list_(
-          content::SharedCorsOriginAccessList::Create()) {
+Profile::Profile() {
 #if DCHECK_IS_ON()
   base::AutoLock lock(g_profile_instances_lock.Get());
   g_profile_instances.Get().insert(this);
@@ -502,65 +499,3 @@
     chrome_variations_client_ = std::make_unique<ChromeVariationsClient>(this);
   return chrome_variations_client_.get();
 }
-
-content::SharedCorsOriginAccessList* Profile::GetSharedCorsOriginAccessList() {
-  return shared_cors_origin_access_list_.get();
-}
-
-void Profile::SetCorsOriginAccessListForOrigin(
-    TargetBrowserContexts target_mode,
-    const url::Origin& source_origin,
-    std::vector<network::mojom::CorsOriginPatternPtr> allow_patterns,
-    std::vector<network::mojom::CorsOriginPatternPtr> block_patterns,
-    base::OnceClosure closure) {
-  using content::CorsOriginPatternSetter;
-  switch (target_mode) {
-    case content::BrowserContext::TargetBrowserContexts::kSingleContext: {
-      SetCorsOriginAccessListForThisContextOnly(
-          source_origin, std::move(allow_patterns), std::move(block_patterns),
-          std::move(closure));
-      break;
-    }
-
-    case content::BrowserContext::TargetBrowserContexts::kAllRelatedContexts: {
-      Profile* regular_profile = GetOriginalProfile();
-      std::vector<Profile*> otr_profiles = GetAllOffTheRecordProfiles();
-      // We need one callback for modifying the `regular_profile`, and one for
-      // each off-the-record profile.
-      auto barrier_closure =
-          BarrierClosure(1 + otr_profiles.size(), std::move(closure));
-      regular_profile->SetCorsOriginAccessListForThisContextOnly(
-          source_origin, CorsOriginPatternSetter::ClonePatterns(allow_patterns),
-          CorsOriginPatternSetter::ClonePatterns(block_patterns),
-          barrier_closure);
-      for (Profile* otr : otr_profiles) {
-        otr->SetCorsOriginAccessListForThisContextOnly(
-            source_origin,
-            CorsOriginPatternSetter::ClonePatterns(allow_patterns),
-            CorsOriginPatternSetter::ClonePatterns(block_patterns),
-            barrier_closure);
-      }
-      break;
-    }
-  }
-}
-
-void Profile::SetCorsOriginAccessListForThisContextOnly(
-    const url::Origin& source_origin,
-    std::vector<network::mojom::CorsOriginPatternPtr> allow_patterns,
-    std::vector<network::mojom::CorsOriginPatternPtr> block_patterns,
-    base::OnceClosure closure) {
-  using content::CorsOriginPatternSetter;
-  auto barrier_closure = BarrierClosure(2, std::move(closure));
-  base::MakeRefCounted<CorsOriginPatternSetter>(
-      source_origin, CorsOriginPatternSetter::ClonePatterns(allow_patterns),
-      CorsOriginPatternSetter::ClonePatterns(block_patterns), barrier_closure)
-      ->ApplyToEachStoragePartition(this);
-
-  // Keep the per-profile access list up to date so that we can use this to
-  // restore NetworkContext settings at anytime, e.g. on restarting the
-  // network service.
-  shared_cors_origin_access_list_->SetForOrigin(
-      source_origin, std::move(allow_patterns), std::move(block_patterns),
-      barrier_closure);
-}
diff --git a/chrome/browser/profiles/profile.h b/chrome/browser/profiles/profile.h
index e77f4b1..c327279 100644
--- a/chrome/browser/profiles/profile.h
+++ b/chrome/browser/profiles/profile.h
@@ -221,7 +221,6 @@
   virtual const OTRProfileID& GetOTRProfileID() const = 0;
 
   variations::VariationsClient* GetVariationsClient() override;
-  content::SharedCorsOriginAccessList* GetSharedCorsOriginAccessList() override;
 
   // Returns the creation time of this profile. This will either be the creation
   // time of the profile directory or, for ephemeral off-the-record profiles,
@@ -516,13 +515,6 @@
 
   virtual void RecordMainFrameNavigation() = 0;
 
-  void SetCorsOriginAccessListForOrigin(
-      TargetBrowserContexts target_mode,
-      const url::Origin& source_origin,
-      std::vector<network::mojom::CorsOriginPatternPtr> allow_patterns,
-      std::vector<network::mojom::CorsOriginPatternPtr> block_patterns,
-      base::OnceClosure closure) override;
-
  protected:
   void set_is_guest_profile(bool is_guest_profile) {
     is_guest_profile_ = is_guest_profile;
@@ -547,13 +539,6 @@
   // Returns whether the user has signed in this profile to an account.
   virtual bool IsSignedIn() = 0;
 
-  // TODO(lukasza): Move this method to the //content layer.
-  void SetCorsOriginAccessListForThisContextOnly(
-      const url::Origin& source_origin,
-      std::vector<network::mojom::CorsOriginPatternPtr> allow_patterns,
-      std::vector<network::mojom::CorsOriginPatternPtr> block_patterns,
-      base::OnceClosure closure);
-
  private:
   bool restored_last_session_ = false;
 
@@ -576,10 +561,6 @@
 
   class ChromeVariationsClient;
   std::unique_ptr<variations::VariationsClient> chrome_variations_client_;
-
-  // TODO(lukasza): Move this field to the //content layer.
-  scoped_refptr<content::SharedCorsOriginAccessList>
-      shared_cors_origin_access_list_;
 };
 
 // The comparator for profile pointers as key in a map.
diff --git a/chrome/browser/profiles/profile_impl.cc b/chrome/browser/profiles/profile_impl.cc
index 9a3c5813..335fe41 100644
--- a/chrome/browser/profiles/profile_impl.cc
+++ b/chrome/browser/profiles/profile_impl.cc
@@ -11,7 +11,6 @@
 #include <utility>
 #include <vector>
 
-#include "base/barrier_closure.h"
 #include "base/bind.h"
 #include "base/callback.h"
 #include "base/callback_helpers.h"
diff --git a/chrome/browser/profiles/profile_io_data.cc b/chrome/browser/profiles/profile_io_data.cc
index 7e214c1..db023c1 100644
--- a/chrome/browser/profiles/profile_io_data.cc
+++ b/chrome/browser/profiles/profile_io_data.cc
@@ -4,32 +4,21 @@
 
 #include "chrome/browser/profiles/profile_io_data.h"
 
-#include <stddef.h>
-
-#include <utility>
-
 #include "base/bind.h"
-#include "base/callback.h"
-#include "base/callback_helpers.h"
-#include "base/compiler_specific.h"
-#include "base/feature_list.h"
-#include "base/files/file_util.h"
 #include "base/logging.h"
 #include "base/single_thread_task_runner.h"
-#include "base/strings/string_util.h"
 #include "base/task/task_traits.h"
-#include "base/threading/thread_task_runner_handle.h"
 #include "build/build_config.h"
 #include "build/chromeos_buildflags.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/common/buildflags.h"
 #include "chrome/common/chrome_constants.h"
-#include "chrome/common/chrome_features.h"
 #include "chrome/common/url_constants.h"
 #include "components/dom_distiller/core/url_constants.h"
 #include "content/public/browser/browser_task_traits.h"
 #include "content/public/browser/browser_thread.h"
 #include "extensions/buildflags/buildflags.h"
+#include "net/net_buildflags.h"
 #include "third_party/blink/public/common/features.h"
 
 #if BUILDFLAG(ENABLE_EXTENSIONS)
@@ -37,187 +26,25 @@
 #endif  // BUILDFLAG(ENABLE_EXTENSIONS)
 
 #if BUILDFLAG(IS_CHROMEOS_ASH)
-#include "chrome/browser/ash/login/startup_utils.h"
-#include "chrome/browser/ash/profiles/profile_helper.h"
-#include "chrome/browser/net/nss_context.h"
-#include "chromeos/dbus/cryptohome/cryptohome_client.h"
-#include "chromeos/dbus/dbus_thread_manager.h"
-#include "chromeos/settings/cros_settings_names.h"
-#include "chromeos/tpm/tpm_token_info_getter.h"
-#include "components/user_manager/user.h"
-#include "components/user_manager/user_manager.h"
-#include "crypto/nss_util.h"
-#include "crypto/nss_util_internal.h"
+#include "chrome/browser/net/nss_service_chromeos_factory.h"
 #endif  // BUILDFLAG(IS_CHROMEOS_ASH)
 
-using content::BrowserContext;
 using content::BrowserThread;
-using content::ResourceContext;
-
-namespace {
-
-#if BUILDFLAG(IS_CHROMEOS_ASH)
-// The following four functions are responsible for initializing NSS for each
-// profile on ChromeOS, which has a separate NSS database and TPM slot
-// per-profile.
-//
-// Initialization basically follows these steps:
-// 1) Get some info from user_manager::UserManager about the User for this
-// profile.
-// 2) Tell nss_util to initialize the software slot for this profile.
-// 3) Wait for the TPM module to be loaded by nss_util if it isn't already.
-// 4) Ask CryptohomeClient which TPM slot id corresponds to this profile.
-// 5) Tell nss_util to use that slot id on the TPM module.
-//
-// Some of these steps must happen on the UI thread, others must happen on the
-// IO thread:
-//               UI thread                              IO Thread
-//
-//  ProfileIOData::InitializeOnUIThread
-//                   |
-//  ProfileHelper::Get()->GetUserByProfile()
-//                   \---------------------------------------v
-//                                                 StartNSSInitOnIOThread
-//                                                           |
-//                                          crypto::InitializeNSSForChromeOSUser
-//                                                           |
-//                                                crypto::IsTPMTokenReady
-//                                                           |
-//                                          StartTPMSlotInitializationOnIOThread
-//                   v---------------------------------------/
-//     GetTPMInfoForUserOnUIThread
-//                   |
-// chromeos::TPMTokenInfoGetter::Start
-//                   |
-//     DidGetTPMInfoForUserOnUIThread
-//                   \---------------------------------------v
-//                                          crypto::InitializeTPMForChromeOSUser
-
-void DidGetTPMInfoForUserOnUIThread(
-    std::unique_ptr<chromeos::TPMTokenInfoGetter> getter,
-    const std::string& username_hash,
-    base::Optional<chromeos::CryptohomeClient::TpmTokenInfo> token_info) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
-  if (token_info.has_value() && token_info->slot != -1) {
-    DVLOG(1) << "Got TPM slot for " << username_hash << ": "
-             << token_info->slot;
-    content::GetIOThreadTaskRunner({})->PostTask(
-        FROM_HERE, base::BindOnce(&crypto::InitializeTPMForChromeOSUser,
-                                  username_hash, token_info->slot));
-  } else {
-    NOTREACHED() << "TPMTokenInfoGetter reported invalid token.";
-  }
-}
-
-void GetTPMInfoForUserOnUIThread(const AccountId& account_id,
-                                 const std::string& username_hash) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
-  DVLOG(1) << "Getting TPM info from cryptohome for "
-           << " " << account_id.Serialize() << " " << username_hash;
-  std::unique_ptr<chromeos::TPMTokenInfoGetter> scoped_token_info_getter =
-      chromeos::TPMTokenInfoGetter::CreateForUserToken(
-          account_id, chromeos::CryptohomeClient::Get(),
-          base::ThreadTaskRunnerHandle::Get());
-  chromeos::TPMTokenInfoGetter* token_info_getter =
-      scoped_token_info_getter.get();
-
-  // Bind |token_info_getter| to the callback to ensure it does not go away
-  // before TPM token info is fetched.
-  // TODO(tbarzic, pneubeck): Handle this in a nicer way when this logic is
-  //     moved to a separate profile service.
-  token_info_getter->Start(base::BindOnce(&DidGetTPMInfoForUserOnUIThread,
-                                          std::move(scoped_token_info_getter),
-                                          username_hash));
-}
-
-void StartTPMSlotInitializationOnIOThread(const AccountId& account_id,
-                                          const std::string& username_hash) {
-  DCHECK_CURRENTLY_ON(BrowserThread::IO);
-
-  content::GetUIThreadTaskRunner({})->PostTask(
-      FROM_HERE,
-      base::BindOnce(&GetTPMInfoForUserOnUIThread, account_id, username_hash));
-}
-
-void StartNSSInitOnIOThread(const AccountId& account_id,
-                            const std::string& username_hash,
-                            const base::FilePath& path) {
-  DCHECK_CURRENTLY_ON(BrowserThread::IO);
-  DVLOG(1) << "Starting NSS init for " << account_id.Serialize()
-           << "  hash:" << username_hash;
-
-  // Make sure NSS is initialized for the user.
-  crypto::InitializeNSSForChromeOSUser(username_hash, path);
-
-  // Check if it's OK to initialize TPM for the user before continuing. This
-  // may not be the case if the TPM slot initialization was previously
-  // requested for the same user.
-  if (!crypto::ShouldInitializeTPMForChromeOSUser(username_hash))
-    return;
-
-  crypto::WillInitializeTPMForChromeOSUser(username_hash);
-
-  if (crypto::IsTPMTokenEnabledForNSS()) {
-    if (crypto::IsTPMTokenReady(
-            base::BindOnce(&StartTPMSlotInitializationOnIOThread, account_id,
-                           username_hash))) {
-      StartTPMSlotInitializationOnIOThread(account_id, username_hash);
-    } else {
-      DVLOG(1) << "Waiting for tpm ready ...";
-    }
-  } else {
-    crypto::InitializePrivateSoftwareSlotForChromeOSUser(username_hash);
-  }
-}
-
-void EnableNSSSystemKeySlotOnIOThread(ResourceContext* resource_context,
-                                      const std::string& username_hash,
-                                      bool user_is_affiliated) {
-  SetNSSCertDatabaseUsernameHash(resource_context, username_hash);
-  if (user_is_affiliated)
-    EnableNSSSystemKeySlotForResourceContext(resource_context);
-}
-#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
-
-}  // namespace
 
 void ProfileIOData::InitializeOnUIThread(Profile* profile) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
 
 #if BUILDFLAG(IS_CHROMEOS_ASH)
-  const user_manager::User* user =
-      chromeos::ProfileHelper::Get()->GetUserByProfile(profile);
-  // No need to initialize NSS for users with empty username hash:
-  // Getters for a user's NSS slots always return a null slot if the user's
-  // username hash is empty, even when the NSS is not initialized for the
-  // user.
-  std::string username_hash;
-  bool user_is_affiliated = false;
-  if (user && !user->username_hash().empty()) {
-    username_hash = user->username_hash();
-    DCHECK(!username_hash.empty());
-    content::GetIOThreadTaskRunner({})->PostTask(
-        FROM_HERE, base::BindOnce(&StartNSSInitOnIOThread, user->GetAccountId(),
-                                  username_hash, profile->GetPath()));
-
-    user_is_affiliated = user->IsAffiliated();
-  }
-
-  // We need to make sure that content initializes its own data structures that
-  // are associated with each ResourceContext because we might post this
-  // object to the IO thread after this function.
-  BrowserContext::EnsureResourceContextInitialized(profile);
-
-  DCHECK(!(username_hash.empty() && user_is_affiliated));
-
-  content::GetIOThreadTaskRunner({})->PostTask(
-      FROM_HERE, base::BindOnce(&EnableNSSSystemKeySlotOnIOThread,
-                                profile->GetResourceContext(), username_hash,
-                                user_is_affiliated));
+  // This triggers ResourceContext creation and initializes the per-profile NSS
+  // database.
+  //
+  // TODO(https://crbug.com/1018972): Remove this line once NSS initialization
+  // no longer depends on the ResourceContext.
+  NssServiceChromeOSFactory::GetForContext(profile);
 #else  // !BUILDFLAG(IS_CHROMEOS_ASH)
   // Make sure the ResourceContext is initialized.  It's unclear if this is
   // still needed.
-  BrowserContext::EnsureResourceContextInitialized(profile);
+  content::BrowserContext::EnsureResourceContextInitialized(profile);
 #endif
 }
 
diff --git a/chrome/browser/resources/inline_login/welcome_page_app.js b/chrome/browser/resources/inline_login/welcome_page_app.js
index e24811d..f22f98d 100644
--- a/chrome/browser/resources/inline_login/welcome_page_app.js
+++ b/chrome/browser/resources/inline_login/welcome_page_app.js
@@ -22,8 +22,10 @@
         .addEventListener(
             'click',
             () => this.dispatchEvent(new CustomEvent('opened-new-window')));
-    this.$$('#incognitoLink')
-        .addEventListener('click', () => this.openIncognitoLink_());
+    const incognitoLink = this.$$('#incognitoLink');
+    if (incognitoLink) {
+      incognitoLink.addEventListener('click', () => this.openIncognitoLink_());
+    }
   },
 
   /** @return {boolean} */
diff --git a/chrome/browser/resources/inspect/inspect.css b/chrome/browser/resources/inspect/inspect.css
index e67cc96..0de2d74 100644
--- a/chrome/browser/resources/inspect/inspect.css
+++ b/chrome/browser/resources/inspect/inspect.css
@@ -316,6 +316,10 @@
   width: 35ex;
 }
 
+.settings-bar button {
+  margin: 7px 0;
+}
+
 .node-frontend-action {
   margin: 6px 4px;
 }
diff --git a/chrome/browser/resources/inspect/inspect.html b/chrome/browser/resources/inspect/inspect.html
index 0a1c3eed..91fa7545 100644
--- a/chrome/browser/resources/inspect/inspect.html
+++ b/chrome/browser/resources/inspect/inspect.html
@@ -45,12 +45,12 @@
           Open dedicated DevTools for Node
         </div>
       </div>
-      <div id="devices-help" hidden="true">No devices detected. Please read the
+      <div id="devices-help" hidden>No devices detected. Please read the
         <a href="https://developers.google.com/chrome-developer-tools/docs/remote-debugging">
         remote debugging documentation</a> to verify your device is enabled for
         USB debugging.
       </div>
-      <div id="devices-incognito" hidden="true">
+      <div id="devices-incognito" hidden>
         Remote debugging is not available in Incognito mode.
       </div>
       <div id="devices-list"></div>
@@ -75,6 +75,18 @@
       <div class="content-header">Service workers</div>
       <div id="service-workers-list" class="list"></div>
     </div>
+    <div id="native-ui" hidden>
+      <div class="content-header">Native UI</div>
+        <div class="settings-bar">
+          <button id="launch-ui-devtools" hidden>
+            Inspect Native UI</button>
+        </div>
+        <div id="ui-devtools-disabled-text" hidden>
+          The following front-end is running:</div>
+        <div id="ui-devtools-enabled-text" hidden>
+          Click to start a single-use session for native UI inspection.</div>
+        <div id="native-ui-list" class="list"></div>
+    </div>
     <div id="other">
       <div class="content-header">Other</div>
       <div id="others-list" class="list"></div>
diff --git a/chrome/browser/resources/inspect/inspect.js b/chrome/browser/resources/inspect/inspect.js
index 8661533..4f8fabc 100644
--- a/chrome/browser/resources/inspect/inspect.js
+++ b/chrome/browser/resources/inspect/inspect.js
@@ -69,22 +69,6 @@
   element.textContent = '';
 }
 
-function removeAdditionalChildren(element_id) {
-  const element = $(element_id);
-  const elements = element.querySelectorAll('.row.additional');
-  for (let i = 0; i != elements.length; i++) {
-    element.removeChild(elements[i]);
-  }
-}
-
-function removeChildrenExceptAdditional(element_id) {
-  const element = $(element_id);
-  const elements = element.querySelectorAll('.row:not(.additional)');
-  for (let i = 0; i != elements.length; i++) {
-    element.removeChild(elements[i]);
-  }
-}
-
 function onload() {
   const tabContents = document.querySelectorAll('#content > div');
   for (let i = 0; i != tabContents.length; i++) {
@@ -93,12 +77,14 @@
 
     const tabHeader = document.createElement('div');
     tabHeader.className = 'tab-header';
+    tabHeader.id = 'tab-'.concat(tabContent.id);
     const button = document.createElement('button');
     button.textContent = tabName;
     tabHeader.appendChild(button);
     tabHeader.addEventListener('click', selectTab.bind(null, tabContent.id));
     $('navigation').appendChild(tabHeader);
   }
+  $('tab-native-ui').hidden = true;
   onHashChange();
   initSettings();
   sendCommand('init-ui');
@@ -148,20 +134,29 @@
   }
 }
 
-function populateAdditionalTargets(data) {
-  removeAdditionalChildren('others-list');
+function populateNativeUITargets(data) {
+  removeChildren('native-ui-list');
   for (let i = 0; i < data.length; i++) {
-    addAdditionalTargetsToOthersList(data[i]);
+    addToNativeUIList(data[i]);
   }
 }
 
+function showNativeUILaunchButton(enabled) {
+  $('native-ui').hidden = false;
+  $('tab-native-ui').hidden = false;
+  $('launch-ui-devtools').hidden = false;
+  $('launch-ui-devtools').disabled = !enabled;
+  $('ui-devtools-disabled-text').hidden = enabled;
+  $('ui-devtools-enabled-text').hidden = !enabled;
+}
+
 function populateLocalTargets(data) {
   removeChildren('pages-list');
   removeChildren('extensions-list');
   removeChildren('apps-list');
   removeChildren('workers-list');
   removeChildren('service-workers-list');
-  removeChildrenExceptAdditional('others-list');
+  removeChildren('others-list');
 
   data.sort((a, b) => a.name.localeCompare(b.name));
 
@@ -520,8 +515,8 @@
   addTargetToList(data, $('others-list'), ['url']);
 }
 
-function addAdditionalTargetsToOthersList(data) {
-  addTargetToList(data, $('others-list'), ['name', 'url']);
+function addToNativeUIList(data) {
+  addTargetToList(data, $('native-ui-list'), ['name', 'url']);
 }
 
 function formatValue(data, property) {
@@ -675,12 +670,8 @@
   actionBox.className = 'actions';
   subrowBox.appendChild(actionBox);
 
-  if (data.isAdditional) {
-    addActionLink(
-        row, 'inspect', sendCommand.bind(null, 'inspect-additional', data.url),
-        false);
-    row.classList.add('additional');
-  } else if (!data.hasCustomInspectAction && data.type !== 'iframe') {
+  if (!data.isNative && !data.hasCustomInspectAction &&
+      data.type !== 'iframe') {
     addActionLink(
         row, 'inspect', sendTargetCommand.bind(null, 'inspect', data),
         data.hasNoUniqueId || data.adbAttachedForeign);
@@ -724,6 +715,8 @@
   checkboxSendsCommand(
       'discover-tcp-devices-enable', 'set-discover-tcp-targets-enabled');
 
+  $('launch-ui-devtools')
+      .addEventListener('click', sendCommand.bind(null, 'launch-ui-devtools'));
   $('port-forwarding-config-open')
       .addEventListener('click', openPortForwardingConfig);
   $('tcp-discovery-config-open').addEventListener('click', openTargetsConfig);
@@ -1145,10 +1138,11 @@
   updatePortForwardingConfig,
   updateTCPDiscoveryEnabled,
   updateTCPDiscoveryConfig,
+  populateNativeUITargets,
   populateTargets,
-  populateAdditionalTargets,
   populatePortStatus,
   showIncognitoWarning,
+  showNativeUILaunchButton,
 });
 
 document.addEventListener('DOMContentLoaded', onload);
diff --git a/chrome/browser/resources/new_tab_page/modules/drive/module.html b/chrome/browser/resources/new_tab_page/modules/drive/module.html
index 2437d41e..cec9cb10 100644
--- a/chrome/browser/resources/new_tab_page/modules/drive/module.html
+++ b/chrome/browser/resources/new_tab_page/modules/drive/module.html
@@ -47,7 +47,8 @@
 <div id="files">
   <template id="fileRepeat" is="dom-repeat" on-dom-change="onDomChange_"
       items="[[files]]">
-    <a class="file" href="[[item.url.url]]">
+    <a class="file" href="[[item.url.url]]" on-click="onFileClick_"
+        on-auxclick="onFileClick_">
       <div class="file-icon-container">
         <img
             class="file-icon"
diff --git a/chrome/browser/resources/new_tab_page/modules/drive/module.js b/chrome/browser/resources/new_tab_page/modules/drive/module.js
index 169c893..1d1956d4 100644
--- a/chrome/browser/resources/new_tab_page/modules/drive/module.js
+++ b/chrome/browser/resources/new_tab_page/modules/drive/module.js
@@ -91,6 +91,16 @@
     this.shadowRoot.querySelectorAll('.file').forEach(
         el => this.intersectionObserver_.observe(el));
   }
+
+  /**
+   * @param {!Event} e
+   * @private
+   */
+  onFileClick_(e) {
+    this.dispatchEvent(new Event('usage', {bubbles: true, composed: true}));
+    const index = this.$.fileRepeat.indexForElement(e.target);
+    chrome.metricsPrivate.recordSmallCount('NewTabPage.Drive.FileClick', index);
+  }
 }
 
 customElements.define(DriveModuleElement.is, DriveModuleElement);
diff --git a/chrome/browser/resources/settings/chromeos/os_people_page/account_manager.js b/chrome/browser/resources/settings/chromeos/os_people_page/account_manager.js
index 904931a..9fc5efa 100644
--- a/chrome/browser/resources/settings/chromeos/os_people_page/account_manager.js
+++ b/chrome/browser/resources/settings/chromeos/os_people_page/account_manager.js
@@ -445,5 +445,6 @@
     this.browserProxy_.removeAccount(
         /** @type {?settings.Account} */ (this.actionMenuAccount_));
     this.closeActionMenu_();
+    this.$$('#add-account-button').focus();
   },
 });
diff --git a/chrome/browser/resources/signin/profile_picker/BUILD.gn b/chrome/browser/resources/signin/profile_picker/BUILD.gn
index 1eb98fb..4f4ffdc 100644
--- a/chrome/browser/resources/signin/profile_picker/BUILD.gn
+++ b/chrome/browser/resources/signin/profile_picker/BUILD.gn
@@ -106,6 +106,7 @@
     "profile_creation_flow/local_profile_customization.js",
     "profile_picker_shared_css.js",
     "profile_creation_flow/shared_css.js",
+    "profile_switch.js",
   ]
 }
 
@@ -150,6 +151,7 @@
     ":profile_picker",
     ":profile_picker_app",
     ":profile_picker_main_view",
+    ":profile_switch",
   ]
 }
 
@@ -168,6 +170,7 @@
 
 js_library("lazy_load") {
   deps = [
+    ":profile_switch",
     "profile_creation_flow:local_profile_customization",
     "profile_creation_flow:profile_type_choice",
   ]
@@ -201,6 +204,7 @@
     ":ensure_lazy_loaded",
     ":navigation_behavior",
     ":profile_picker_main_view",
+    ":profile_switch",
     "//third_party/polymer/v3_0/components-chromium/polymer:polymer_bundled",
     "//ui/webui/resources/cr_elements/cr_lazy_render:cr_lazy_render.m",
     "//ui/webui/resources/cr_elements/cr_view_manager:cr_view_manager.m",
@@ -242,6 +246,10 @@
   deps = [ "//ui/webui/resources/js:load_time_data.m" ]
 }
 
+js_library("profile_switch") {
+  deps = [ ":manage_profiles_browser_proxy" ]
+}
+
 group("web_components") {
   public_deps = [
     ":web_components_local",
@@ -256,5 +264,6 @@
     "profile_card.js",
     "profile_card_menu.js",
     "profile_picker_shared_css.js",
+    "profile_switch.js",
   ]
 }
diff --git a/chrome/browser/resources/signin/profile_picker/ensure_lazy_loaded.js b/chrome/browser/resources/signin/profile_picker/ensure_lazy_loaded.js
index 78ccede..c72fef6 100644
--- a/chrome/browser/resources/signin/profile_picker/ensure_lazy_loaded.js
+++ b/chrome/browser/resources/signin/profile_picker/ensure_lazy_loaded.js
@@ -19,6 +19,7 @@
     lazyLoadPromise = Promise.all([
       'profile-type-choice',
       'local-profile-customization',
+      'profile-switch',
     ].map(name => customElements.whenDefined(name)));
   }
   return lazyLoadPromise;
diff --git a/chrome/browser/resources/signin/profile_picker/lazy_load.js b/chrome/browser/resources/signin/profile_picker/lazy_load.js
index 6ed3d8f8..baff46e4 100644
--- a/chrome/browser/resources/signin/profile_picker/lazy_load.js
+++ b/chrome/browser/resources/signin/profile_picker/lazy_load.js
@@ -4,3 +4,4 @@
 
 import './profile_creation_flow/profile_type_choice.js';
 import './profile_creation_flow/local_profile_customization.js';
+import './profile_switch.js';
diff --git a/chrome/browser/resources/signin/profile_picker/manage_profiles_browser_proxy.js b/chrome/browser/resources/signin/profile_picker/manage_profiles_browser_proxy.js
index d2e4df8..e6b71cf1 100644
--- a/chrome/browser/resources/signin/profile_picker/manage_profiles_browser_proxy.js
+++ b/chrome/browser/resources/signin/profile_picker/manage_profiles_browser_proxy.js
@@ -137,6 +137,24 @@
 
   /** Records impression of a sign-in promo to metrics. */
   recordSignInPromoImpression() {}
+
+  /**
+   * Gets a profile for which the profile switch screen is shown.
+   * @return {!Promise<!ProfileState>}
+   */
+  getSwitchProfile() {}
+
+  /**
+   * Switches to an already existing profile at `profile_path`.
+   * @param {string} profilePath
+   */
+  confirmProfileSwitch(profilePath) {}
+
+  /**
+   * Cancels the profile switch which aborts the sign-in profile creation
+   * flow.
+   */
+  cancelProfileSwitch() {}
 }
 
 /** @implements {ManageProfilesBrowserProxy} */
@@ -212,6 +230,21 @@
   recordSignInPromoImpression() {
     chrome.send('recordSignInPromoImpression');
   }
+
+  /** @override */
+  getSwitchProfile() {
+    return sendWithPromise('getSwitchProfile');
+  }
+
+  /** @override */
+  confirmProfileSwitch(profilePath) {
+    chrome.send('confirmProfileSwitch', [profilePath]);
+  }
+
+  /** @override */
+  cancelProfileSwitch() {
+    chrome.send('cancelProfileSwitch');
+  }
 }
 
 addSingletonGetter(ManageProfilesBrowserProxyImpl);
diff --git a/chrome/browser/resources/signin/profile_picker/navigation_behavior.js b/chrome/browser/resources/signin/profile_picker/navigation_behavior.js
index 4f30c4a..dfde8de 100644
--- a/chrome/browser/resources/signin/profile_picker/navigation_behavior.js
+++ b/chrome/browser/resources/signin/profile_picker/navigation_behavior.js
@@ -19,6 +19,7 @@
   LOCAL_PROFILE_CUSTOMIZATION: 2,
   LOAD_SIGNIN: 3,
   LOAD_FORCE_SIGNIN: 4,
+  PROFILE_SWITCH: 5,
 };
 
 /**
@@ -28,6 +29,7 @@
 export const Routes = {
   MAIN: 'main-view',
   NEW_PROFILE: 'new-profile',
+  PROFILE_SWITCH: 'profile-switch',
 };
 
 /**
@@ -57,6 +59,8 @@
         return ProfileCreationSteps.LOCAL_PROFILE_CUSTOMIZATION;
       }
       return ProfileCreationSteps.PROFILE_TYPE_CHOICE;
+    case Routes.PROFILE_SWITCH:
+      return 'profileSwitch';
     default:
       assertNotReached();
   }
@@ -75,6 +79,15 @@
           },
           '', path);
       break;
+    case `/${Routes.PROFILE_SWITCH}`:
+      history.replaceState(
+          {
+            route: Routes.PROFILE_SWITCH,
+            step: computeStep(Routes.PROFILE_SWITCH),
+            isFirst: true
+          },
+          '', path);
+      break;
     default:
       history.replaceState(
           {route: Routes.MAIN, step: computeStep(Routes.MAIN), isFirst: true},
@@ -104,6 +117,9 @@
     case ProfileCreationSteps.LOAD_FORCE_SIGNIN:
       page = Pages.LOAD_FORCE_SIGNIN;
       break;
+    case 'profileSwitch':
+      page = Pages.PROFILE_SWITCH;
+      break;
     default:
       assertNotReached();
   }
@@ -132,7 +148,8 @@
  * @param {!Routes} route
  */
 export function navigateTo(route) {
-  assert([Routes.MAIN, Routes.NEW_PROFILE].includes(route));
+  assert(
+      [Routes.MAIN, Routes.NEW_PROFILE, Routes.PROFILE_SWITCH].includes(route));
   navigateToStep(route, computeStep(route));
 }
 
diff --git a/chrome/browser/resources/signin/profile_picker/profile_picker_app.html b/chrome/browser/resources/signin/profile_picker/profile_picker_app.html
index c18b7cc..9db07bd 100644
--- a/chrome/browser/resources/signin/profile_picker/profile_picker_app.html
+++ b/chrome/browser/resources/signin/profile_picker/profile_picker_app.html
@@ -26,7 +26,14 @@
     <template>
       <local-profile-customization slot="view"
           profile-theme-info="{{newProfileThemeInfo}}">
-      </local-profile-customizatione>
+      </local-profile-customization>
+    </template>
+  </cr-lazy-render>
+
+  <cr-lazy-render id="profileSwitch">
+    <template>
+      <profile-switch slot="view">
+      </profile-switch>
     </template>
   </cr-lazy-render>
 </cr-view-manager>
diff --git a/chrome/browser/resources/signin/profile_picker/profile_picker_app.js b/chrome/browser/resources/signin/profile_picker/profile_picker_app.js
index 0115fd5..09f8beb 100644
--- a/chrome/browser/resources/signin/profile_picker/profile_picker_app.js
+++ b/chrome/browser/resources/signin/profile_picker/profile_picker_app.js
@@ -116,6 +116,8 @@
         return this.i18n('profileTypeChoiceTitle');
       case ProfileCreationSteps.LOCAL_PROFILE_CUSTOMIZATION:
         return this.i18n('localProfileCreationTitle');
+      case 'profileSwitch':
+        return this.i18n('profileSwitchTitle');
       default:
         return '';
     }
@@ -132,6 +134,8 @@
       case Routes.NEW_PROFILE:
         return Promise.all(
             [this.initializeNewProfileThemeInfo_(), ensureLazyLoaded()]);
+      case Routes.PROFILE_SWITCH:
+        return ensureLazyLoaded();
       default:
         // |this.currentRoute_| should be set by now.
         assertNotReached();
diff --git a/chrome/browser/resources/signin/profile_picker/profile_picker_main_view.html b/chrome/browser/resources/signin/profile_picker/profile_picker_main_view.html
index bd94755..52597098 100644
--- a/chrome/browser/resources/signin/profile_picker/profile_picker_main_view.html
+++ b/chrome/browser/resources/signin/profile_picker/profile_picker_main_view.html
@@ -3,9 +3,7 @@
     --avatar-icon-size: 74px;
     --banner-img-height: 400px;
     --banner-img-width: 169px;
-    --profile-item-height: 178px;
     --profile-item-margin: 4px;
-    --profile-item-width: 162px;
   }
 
   .banner {
diff --git a/chrome/browser/resources/signin/profile_picker/profile_picker_shared_css.html b/chrome/browser/resources/signin/profile_picker/profile_picker_shared_css.html
index cbcb9db..394dd4a 100644
--- a/chrome/browser/resources/signin/profile_picker/profile_picker_shared_css.html
+++ b/chrome/browser/resources/signin/profile_picker/profile_picker_shared_css.html
@@ -6,6 +6,8 @@
       --scrollbar-background: var(--google-grey-refresh-100);
       --footer-spacing: 40px;
       --profile-card-hover-color: var(--md-background-color);
+      --profile-item-height: 178px;
+      --profile-item-width: 162px;
     }
 
     html {
diff --git a/chrome/browser/resources/signin/profile_picker/profile_switch.html b/chrome/browser/resources/signin/profile_picker/profile_switch.html
new file mode 100644
index 0000000..2a813f6
--- /dev/null
+++ b/chrome/browser/resources/signin/profile_picker/profile_switch.html
@@ -0,0 +1,78 @@
+<style include="profile-picker-shared">
+  #outerContainer {
+    display: flex;
+    flex-flow: column;
+    height: 100%;
+  }
+
+  #profileCardContainer {
+    align-items: center;
+    align-self: center;
+    border: 1px solid var(--google-grey-300);
+    border-radius: 8px;
+    display: flex;
+    flex-direction: column;
+    height: var(--profile-item-height);
+    justify-content: center;
+    margin: 200px 0 37px;
+    position: relative;
+    width: var(--profile-item-width);
+  }
+
+  #avatarContainer {
+    height: var(--avatar-icon-size);
+    position: relative;
+  }
+
+  #profileName {
+    top: 0;
+  }
+
+  #gaiaName {
+    bottom: 0;
+  }
+
+  #titleContainer {
+    text-align: center;
+  }
+
+  h2 {
+    margin-block-start: 0;
+  }
+
+  #actionContainer {
+    margin: auto 40px 40px auto;
+  }
+
+  cr-button {
+    margin-inline-start: 8px;
+    min-width: 111px;
+  }
+</style>
+
+<div id="outerContainer">
+  <div id="profileCardContainer">
+    <div id="avatarContainer">
+      <img class="profile-avatar" alt="" src="[[profileState_.avatarIcon]]">
+    </div>
+    <div id="profileName" class="profile-card-info prominent-text">
+      [[profileState_.localProfileName]]
+    </div>
+    <div id="gaiaName" class="profile-card-info secondary-text">
+      [[profileState_.gaiaName]]
+    </div>
+  </div>
+  <div id="titleContainer">
+    <h2>$i18n{profileSwitchTitle}</h2>
+    <h3>$i18n{profileSwitchSubtitle}</h3>
+  </div>
+  <div id="actionContainer">
+    <cr-button id="cancelButton" on-click="onCancelClick_">
+      $i18n{cancel}
+    </cr-button>
+    <cr-button id="switchButton" class="action-button"
+        disabled="[[!isProfileStateInitialized_]]" on-click="onSwitchClick_">
+      $i18n{switchButtonLabel}
+    </cr-button>
+  </div>
+</div>
diff --git a/chrome/browser/resources/signin/profile_picker/profile_switch.js b/chrome/browser/resources/signin/profile_picker/profile_switch.js
new file mode 100644
index 0000000..0d535705
--- /dev/null
+++ b/chrome/browser/resources/signin/profile_picker/profile_switch.js
@@ -0,0 +1,53 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+import 'chrome://resources/cr_elements/cr_button/cr_button.m.js';
+import './profile_picker_shared_css.js';
+
+import {html, Polymer} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
+
+import {ManageProfilesBrowserProxy, ManageProfilesBrowserProxyImpl, ProfileState} from './manage_profiles_browser_proxy.js';
+
+Polymer({
+  is: 'profile-switch',
+
+  _template: html`{__html_template__}`,
+
+  properties: {
+    /** @type {ProfileState} */
+    profileState_: {
+      type: Object,
+    },
+
+    /** @type {boolean} */
+    isProfileStateInitialized_: {
+      type: Boolean,
+      value: false,
+    },
+  },
+
+  /** @private {?ManageProfilesBrowserProxy} */
+  manageProfilesBrowserProxy_: null,
+
+  /** @override */
+  ready() {
+    this.manageProfilesBrowserProxy_ =
+        ManageProfilesBrowserProxyImpl.getInstance();
+    this.manageProfilesBrowserProxy_.getSwitchProfile().then(profileState => {
+      this.profileState_ = profileState;
+      this.isProfileStateInitialized_ = true;
+    });
+  },
+
+  /** @private */
+  onCancelClick_() {
+    this.manageProfilesBrowserProxy_.cancelProfileSwitch();
+  },
+
+  /** @private */
+  onSwitchClick_() {
+    this.manageProfilesBrowserProxy_.confirmProfileSwitch(
+        this.profileState_.profilePath);
+  },
+});
diff --git a/chrome/browser/safety_check/android/java/src/org/chromium/chrome/browser/safety_check/SafetyCheckMediator.java b/chrome/browser/safety_check/android/java/src/org/chromium/chrome/browser/safety_check/SafetyCheckMediator.java
index db5f118..288d483 100644
--- a/chrome/browser/safety_check/android/java/src/org/chromium/chrome/browser/safety_check/SafetyCheckMediator.java
+++ b/chrome/browser/safety_check/android/java/src/org/chromium/chrome/browser/safety_check/SafetyCheckMediator.java
@@ -481,7 +481,8 @@
         if (state == PasswordsState.SIGNED_OUT) {
             listener = (p) -> {
                 // Open the sign in page.
-                mSigninLauncher.launchActivity(p.getContext(), SigninAccessPoint.SAFETY_CHECK);
+                mSigninLauncher.launchActivityIfAllowed(
+                        p.getContext(), SigninAccessPoint.SAFETY_CHECK);
                 return true;
             };
         } else if (state == PasswordsState.COMPROMISED_EXIST || state == PasswordsState.SAFE) {
diff --git a/chrome/browser/signin/services/android/java/src/org/chromium/chrome/browser/signin/services/SigninHelper.java b/chrome/browser/signin/services/android/java/src/org/chromium/chrome/browser/signin/services/SigninHelper.java
index 4d25336..290b748 100644
--- a/chrome/browser/signin/services/android/java/src/org/chromium/chrome/browser/signin/services/SigninHelper.java
+++ b/chrome/browser/signin/services/android/java/src/org/chromium/chrome/browser/signin/services/SigninHelper.java
@@ -102,9 +102,6 @@
     private void validateAccountsInternal(boolean accountsChanged) {
         // Ensure System accounts have been seeded.
         mAccountTrackerService.checkAndSeedSystemAccounts();
-        if (!accountsChanged) {
-            mAccountTrackerService.validateSystemAccounts();
-        }
         if (mSigninManager.isOperationInProgress()) {
             // Wait for ongoing sign-in/sign-out operation to finish before validating accounts.
             mSigninManager.runAfterOperationInProgress(
diff --git a/chrome/browser/signin/services/android/java/src/org/chromium/chrome/browser/signin/services/SigninPreferencesManager.java b/chrome/browser/signin/services/android/java/src/org/chromium/chrome/browser/signin/services/SigninPreferencesManager.java
index 2d611a5e..46ccaa40 100644
--- a/chrome/browser/signin/services/android/java/src/org/chromium/chrome/browser/signin/services/SigninPreferencesManager.java
+++ b/chrome/browser/signin/services/android/java/src/org/chromium/chrome/browser/signin/services/SigninPreferencesManager.java
@@ -211,4 +211,27 @@
     public int getAccountPickerBottomSheetShownCount() {
         return mManager.readInt(ChromePreferenceKeys.ACCOUNT_PICKER_BOTTOM_SHEET_SHOWN_COUNT);
     }
+
+    /**
+     * Increments the active dismissal count for the account picker bottom sheet.
+     */
+    public void incrementAccountPickerBottomSheetActiveDismissalCount() {
+        mManager.incrementInt(
+                ChromePreferenceKeys.ACCOUNT_PICKER_BOTTOM_SHEET_ACTIVE_DISMISSAL_COUNT);
+    }
+
+    /**
+     * Returns the number of times account picker bottom sheet has been actively dismissed.
+     */
+    public int getAccountPickerBottomSheetActiveDismissalCount() {
+        return mManager.readInt(
+                ChromePreferenceKeys.ACCOUNT_PICKER_BOTTOM_SHEET_ACTIVE_DISMISSAL_COUNT);
+    }
+
+    /**
+     * Clears the active dismissal count for the account picker bottom sheet.
+     */
+    public void clearAccountPickerBottomSheetActiveDismissalCount() {
+        mManager.removeKey(ChromePreferenceKeys.ACCOUNT_PICKER_BOTTOM_SHEET_ACTIVE_DISMISSAL_COUNT);
+    }
 }
diff --git a/chrome/browser/signin/signin_manager.cc b/chrome/browser/signin/signin_manager.cc
index 62dc79f..9c28467 100644
--- a/chrome/browser/signin/signin_manager.cc
+++ b/chrome/browser/signin/signin_manager.cc
@@ -24,11 +24,23 @@
 void SigninManager::UpdateUnconsentedPrimaryAccount() {
   base::Optional<CoreAccountInfo> account =
       ComputeUnconsentedPrimaryAccountInfo();
-  if (!account)
-    return;
 
-  identity_manager_->GetPrimaryAccountMutator()->SetUnconsentedPrimaryAccount(
-      account->account_id);
+  DCHECK(!account || !account->IsEmpty());
+  if (account) {
+    if (identity_manager_->GetPrimaryAccountInfo(
+            signin::ConsentLevel::kNotRequired) != account) {
+      DCHECK(
+          !identity_manager_->HasPrimaryAccount(signin::ConsentLevel::kSync));
+      identity_manager_->GetPrimaryAccountMutator()
+          ->SetUnconsentedPrimaryAccount(account->account_id);
+    }
+  } else if (identity_manager_->HasPrimaryAccount(
+                 signin::ConsentLevel::kNotRequired)) {
+    DCHECK(!identity_manager_->HasPrimaryAccount(signin::ConsentLevel::kSync));
+    identity_manager_->GetPrimaryAccountMutator()->ClearPrimaryAccount(
+        signin_metrics::USER_DELETED_ACCOUNT_COOKIES,
+        signin_metrics::SignoutDelete::IGNORE_METRIC);
+  }
 }
 
 base::Optional<CoreAccountInfo>
@@ -53,7 +65,7 @@
     // in cookies if it exists and has a refresh token.
     if (cookie_accounts.empty()) {
       // Cookies are empty, the UPA is empty.
-      return CoreAccountInfo();
+      return base::nullopt;
     }
 
     base::Optional<AccountInfo> account_info =
@@ -67,7 +79,7 @@
         identity_manager_->HasAccountWithRefreshTokenInPersistentErrorState(
             account_info->account_id);
 
-    return error_state ? AccountInfo() : account_info;
+    return error_state ? base::nullopt : account_info;
   }
 
   if (!identity_manager_->HasPrimaryAccount(signin::ConsentLevel::kNotRequired))
@@ -83,26 +95,27 @@
       !identity_manager_->HasAccountWithRefreshToken(current_account)) {
     // Tokens are loaded, but the current UPA doesn't have a refresh token.
     // Clear the current UPA.
-    return CoreAccountInfo();
+    return base::nullopt;
   }
 
   if (!are_refresh_tokens_loaded &&
       unconsented_primary_account_revoked_during_load_) {
     // Tokens are not loaded, but the current UPA's refresh token has been
     // revoked. Clear the current UPA.
-    return CoreAccountInfo();
+    return base::nullopt;
   }
 
   if (cookie_info.accounts_are_fresh) {
     if (cookie_accounts.empty() || cookie_accounts[0].id != current_account) {
       // The current UPA is not the first in fresh cookies. It needs to be
       // cleared.
-      return CoreAccountInfo();
+      return base::nullopt;
     }
   }
 
-  // No indication that the current UPA is invalid, return no op.
-  return base::nullopt;
+  // No indication that the current UPA is invalid, return current UPA.
+  return identity_manager_->GetPrimaryAccountInfo(
+      signin::ConsentLevel::kNotRequired);
 }
 
 // signin::IdentityManager::Observer implementation.
diff --git a/chrome/browser/signin/signin_manager.h b/chrome/browser/signin/signin_manager.h
index 3b14dac..4085b6b 100644
--- a/chrome/browser/signin/signin_manager.h
+++ b/chrome/browser/signin/signin_manager.h
@@ -23,17 +23,16 @@
 
   // Computes and returns the unconsented primary account (UPA).
   // - If a primary account with sync consent exists, the UPA is equal to it.
-  // - Otherwise, the UPA is the first account in cookies and must have a
-  // refresh token. For the UPA to be computed, it needs fresh cookies and
-  // tokens to be loaded.
+  // - The UPA is the first account in cookies and must have a refresh token.
+  // For the UPA to be computed, it needs fresh cookies and tokens to be loaded.
   // - If tokens are not loaded or cookies are not fresh, the UPA can't be
   // computed but if one already exists it might be invalid. That can happen if
   // cookies are fresh but are empty or the first account is different than the
   // current UPA, the other cases are if tokens are not loaded but the current
   // UPA's refresh token has been rekoved or tokens are loaded but the current
   // UPA does not have a refresh token. If the UPA is invalid, it needs to be
-  // cleared, an empty UPA is returned. If it is still valid, returns
-  // |base::nullopt| which is no op.
+  // cleared, |base::nullopt| is returned. If it is still valid, returns the
+  // valid UPA.
   base::Optional<CoreAccountInfo> ComputeUnconsentedPrimaryAccountInfo() const;
 
   // signin::IdentityManager::Observer implementation.
diff --git a/chrome/browser/signin/signin_manager_unittest.cc b/chrome/browser/signin/signin_manager_unittest.cc
index c2daa3d..3bd0628 100644
--- a/chrome/browser/signin/signin_manager_unittest.cc
+++ b/chrome/browser/signin/signin_manager_unittest.cc
@@ -179,9 +179,7 @@
       identity_manager()->HasPrimaryAccount(ConsentLevel::kNotRequired));
 
   // Update with a valid token.
-  UpdatePersistentErrorOfRefreshTokenForAccount(
-      identity_manager(), account.account_id,
-      GoogleServiceAuthError::AuthErrorNone());
+  SetRefreshTokenForAccount(identity_manager(), account.account_id, "");
   ExpectUnconsentedPrimaryAccountSetEvent(account);
   EXPECT_EQ(
       identity_manager()->GetPrimaryAccountInfo(ConsentLevel::kNotRequired),
diff --git a/chrome/browser/signin/ui/android/java/src/org/chromium/chrome/browser/signin/ui/account_picker/AccountPickerBottomSheetCoordinator.java b/chrome/browser/signin/ui/android/java/src/org/chromium/chrome/browser/signin/ui/account_picker/AccountPickerBottomSheetCoordinator.java
index 222a5c9..54727f7 100644
--- a/chrome/browser/signin/ui/android/java/src/org/chromium/chrome/browser/signin/ui/account_picker/AccountPickerBottomSheetCoordinator.java
+++ b/chrome/browser/signin/ui/android/java/src/org/chromium/chrome/browser/signin/ui/account_picker/AccountPickerBottomSheetCoordinator.java
@@ -49,6 +49,8 @@
                 // Return for other dismiss cases so we don't record web signin metrics for them.
                 return;
             }
+            SigninPreferencesManager.getInstance()
+                    .incrementAccountPickerBottomSheetActiveDismissalCount();
             SigninMetricsUtils.logWebSignin();
         }
 
diff --git a/chrome/browser/signin/ui/android/java/src/org/chromium/chrome/browser/signin/ui/account_picker/AccountPickerBottomSheetMediator.java b/chrome/browser/signin/ui/android/java/src/org/chromium/chrome/browser/signin/ui/account_picker/AccountPickerBottomSheetMediator.java
index f5bd1ebd..b83ca72f 100644
--- a/chrome/browser/signin/ui/android/java/src/org/chromium/chrome/browser/signin/ui/account_picker/AccountPickerBottomSheetMediator.java
+++ b/chrome/browser/signin/ui/android/java/src/org/chromium/chrome/browser/signin/ui/account_picker/AccountPickerBottomSheetMediator.java
@@ -14,6 +14,7 @@
 import org.chromium.base.task.AsyncTask;
 import org.chromium.chrome.browser.signin.services.ProfileDataCache;
 import org.chromium.chrome.browser.signin.services.SigninMetricsUtils;
+import org.chromium.chrome.browser.signin.services.SigninPreferencesManager;
 import org.chromium.chrome.browser.signin.ui.account_picker.AccountPickerBottomSheetProperties.ViewState;
 import org.chromium.components.signin.AccountManagerFacade;
 import org.chromium.components.signin.AccountManagerFacadeProvider;
@@ -53,6 +54,8 @@
         OnClickListener onDismissClicked = v -> {
             SigninMetricsUtils.logAccountConsistencyPromoAction(
                     AccountConsistencyPromoAction.DISMISSED_BUTTON);
+            SigninPreferencesManager.getInstance()
+                    .incrementAccountPickerBottomSheetActiveDismissalCount();
             dismissBottomSheetRunnable.run();
         };
         mModel = AccountPickerBottomSheetProperties.createModel(
@@ -229,6 +232,7 @@
             SigninMetricsUtils.logAccountConsistencyPromoAction(
                     AccountConsistencyPromoAction.SIGNED_IN_WITH_NON_DEFAULT_ACCOUNT);
         }
+        SigninPreferencesManager.getInstance().clearAccountPickerBottomSheetActiveDismissalCount();
         new AsyncTask<String>() {
             @Override
             protected String doInBackground() {
diff --git a/chrome/browser/signin/ui/android/java/src/org/chromium/chrome/browser/signin/ui/account_picker/AccountPickerFeatureUtils.java b/chrome/browser/signin/ui/android/java/src/org/chromium/chrome/browser/signin/ui/account_picker/AccountPickerFeatureUtils.java
index 1c9c85a..b24a839 100644
--- a/chrome/browser/signin/ui/android/java/src/org/chromium/chrome/browser/signin/ui/account_picker/AccountPickerFeatureUtils.java
+++ b/chrome/browser/signin/ui/android/java/src/org/chromium/chrome/browser/signin/ui/account_picker/AccountPickerFeatureUtils.java
@@ -10,7 +10,9 @@
  * This class is used to handle state of feature flags in the project
  * MobileIdentityConsistency.
  */
-class AccountPickerFeatureUtils {
+public class AccountPickerFeatureUtils {
+    private static final String CONSECUTIVE_ACTIVE_DISMISSAL_LIMIT_PARAM =
+            "consecutive_active_dismissal_limit";
     private static final String DISMISS_BUTTON_PARAM = "dismiss_button";
     private static final String HIDE_DISMISS_BUTTON = "hide";
 
@@ -18,4 +20,10 @@
         return HIDE_DISMISS_BUTTON.equals(ChromeFeatureList.getFieldTrialParamByFeature(
                 ChromeFeatureList.MOBILE_IDENTITY_CONSISTENCY_VAR, DISMISS_BUTTON_PARAM));
     }
+
+    public static int getDismissLimit() {
+        return ChromeFeatureList.getFieldTrialParamByFeatureAsInt(
+                ChromeFeatureList.MOBILE_IDENTITY_CONSISTENCY_VAR,
+                CONSECUTIVE_ACTIVE_DISMISSAL_LIMIT_PARAM, Integer.MAX_VALUE);
+    }
 }
diff --git a/chrome/browser/tab_contents/view_source_browsertest.cc b/chrome/browser/tab_contents/view_source_browsertest.cc
index 3f89025c..cb6d6d3 100644
--- a/chrome/browser/tab_contents/view_source_browsertest.cc
+++ b/chrome/browser/tab_contents/view_source_browsertest.cc
@@ -61,9 +61,9 @@
   DISALLOW_COPY_AND_ASSIGN(ViewSourceTest);
 };
 
-class ViewSourceFeaturePolicyTest : public ViewSourceTest {
+class ViewSourcePermissionsPolicyTest : public ViewSourceTest {
  public:
-  ViewSourceFeaturePolicyTest() : ViewSourceTest() {}
+  ViewSourcePermissionsPolicyTest() : ViewSourceTest() {}
 
  protected:
   void SetUpOnMainThread() override {
@@ -77,7 +77,7 @@
   }
 
  private:
-  DISALLOW_COPY_AND_ASSIGN(ViewSourceFeaturePolicyTest);
+  DISALLOW_COPY_AND_ASSIGN(ViewSourcePermissionsPolicyTest);
 };
 
 // This test renders a page in view-source and then checks to see if the title
@@ -736,7 +736,7 @@
 
 // This test verifies that 'view-source' documents are not affected by vertical
 // scroll (see https://crbug.com/898688).
-IN_PROC_BROWSER_TEST_F(ViewSourceFeaturePolicyTest,
+IN_PROC_BROWSER_TEST_F(ViewSourcePermissionsPolicyTest,
                        ViewSourceNotAffectedByHeaderPolicy) {
   ASSERT_TRUE(embedded_test_server()->Start());
   const std::string k_verify_feature = R"(
diff --git a/chrome/browser/ui/android/appmenu/internal/java/src/org/chromium/chrome/browser/ui/appmenu/AppMenuAdapter.java b/chrome/browser/ui/android/appmenu/internal/java/src/org/chromium/chrome/browser/ui/appmenu/AppMenuAdapter.java
index dbf4cce..6eb57937 100644
--- a/chrome/browser/ui/android/appmenu/internal/java/src/org/chromium/chrome/browser/ui/appmenu/AppMenuAdapter.java
+++ b/chrome/browser/ui/android/appmenu/internal/java/src/org/chromium/chrome/browser/ui/appmenu/AppMenuAdapter.java
@@ -26,6 +26,8 @@
 import androidx.appcompat.content.res.AppCompatResources;
 
 import org.chromium.base.ApiCompatibilityUtils;
+import org.chromium.chrome.browser.flags.CachedFeatureFlags;
+import org.chromium.chrome.browser.flags.ChromeFeatureList;
 import org.chromium.chrome.browser.ui.appmenu.internal.R;
 import org.chromium.components.browser_ui.widget.highlight.ViewHighlighter;
 import org.chromium.components.browser_ui.widget.text.TextViewWithCompoundDrawables;
@@ -496,9 +498,13 @@
             setupImageButton(holder.buttons[i], item.getSubMenu().getItem(i));
         }
 
-        // Tint action bar's background.
-        convertView.setBackgroundDrawable(ApiCompatibilityUtils.getDrawable(
-                convertView.getContext().getResources(), R.drawable.menu_action_bar_bg));
+        if (CachedFeatureFlags.isEnabled(ChromeFeatureList.TABBED_APP_OVERFLOW_MENU_ICONS)
+                || CachedFeatureFlags.isEnabled(
+                        ChromeFeatureList.TABBED_APP_OVERFLOW_MENU_THREE_BUTTON_ACTIONBAR)) {
+            // Tint action bar's background.
+            convertView.setBackgroundDrawable(ApiCompatibilityUtils.getDrawable(
+                    convertView.getContext().getResources(), R.drawable.menu_action_bar_bg));
+        }
 
         convertView.setFocusable(false);
         convertView.setEnabled(false);
diff --git a/chrome/browser/ui/ash/multi_user/DEPS b/chrome/browser/ui/ash/multi_user/DEPS
index d36c07e..751cdcc 100644
--- a/chrome/browser/ui/ash/multi_user/DEPS
+++ b/chrome/browser/ui/ash/multi_user/DEPS
@@ -6,6 +6,8 @@
     "+ash/multi_user/user_switch_animator.h",
     "+ash/session/session_controller_impl.h",
     "+ash/ws/window_lookup.h",
+    "+ash/wm/desks/desks_controller.h"
+    "+ash/wm/desks/desks_test_util.h",
   ],
   "multi_user_context_menu_chromeos_unittest\.cc": [
     "+ash/test/ash_test_helper.h",
diff --git a/chrome/browser/ui/ash/multi_user/multi_profile_support_unittest.cc b/chrome/browser/ui/ash/multi_user/multi_profile_support_unittest.cc
index ed79a87..bf9a96f5 100644
--- a/chrome/browser/ui/ash/multi_user/multi_profile_support_unittest.cc
+++ b/chrome/browser/ui/ash/multi_user/multi_profile_support_unittest.cc
@@ -19,6 +19,8 @@
 #include "ash/shell.h"
 #include "ash/test/ash_test_helper.h"
 #include "ash/test_shell_delegate.h"
+#include "ash/wm/desks/desks_controller.h"
+#include "ash/wm/desks/desks_test_util.h"
 #include "ash/wm/mru_window_tracker.h"
 #include "ash/wm/tablet_mode/tablet_mode_controller.h"
 #include "ash/wm/tablet_mode/tablet_mode_window_manager.h"
@@ -135,6 +137,12 @@
   // Set up the test environment for this many windows.
   void SetUpForThisManyWindows(int windows);
 
+  // If |windows_| is empty, set up one window each desk for a given user
+  // without activating any desk and return a list of created widgets.
+  // Otherwise, do nothing and return an empty vector.
+  std::vector<std::unique_ptr<views::Widget>> SetUpOneWindowEachDeskForUser(
+      AccountId account_id);
+
   // Switch the user and wait until the animation is finished.
   void SwitchUserAndWaitForAnimation(const AccountId& account_id) {
     EnsureTestUser(account_id);
@@ -301,7 +309,7 @@
 }
 
 void MultiProfileSupportTest::SetUpForThisManyWindows(int windows) {
-  DCHECK(windows_.empty());
+  ASSERT_TRUE(windows_.empty());
   for (int i = 0; i < windows; i++) {
     windows_.push_back(CreateTestWindowInShellWithId(i));
     windows_[i]->Show();
@@ -315,6 +323,38 @@
   wallpaper_controller_client_->InitForTesting(&test_wallpaper_controller_);
 }
 
+std::vector<std::unique_ptr<views::Widget>>
+MultiProfileSupportTest::SetUpOneWindowEachDeskForUser(AccountId account_id) {
+  if (!windows_.empty())
+    return std::vector<std::unique_ptr<views::Widget>>();
+  std::vector<std::unique_ptr<views::Widget>> widgets;
+  std::vector<int> container_ids = desks_util::GetDesksContainersIds();
+  TestShellDelegate* test_shell_delegate =
+      static_cast<TestShellDelegate*>(Shell::Get()->shell_delegate());
+  // Set restore in progress to avoid activating desk activation during
+  // `window->Show()` in `CreateTestWidget()`.
+  test_shell_delegate->SetSessionRestoreInProgress(true);
+  auto* desks_helper = ash::DesksHelper::Get();
+  const int kActiveDeskIndex = 0;
+  for (int i = 0; i < desks_helper->GetNumberOfDesks(); i++) {
+    widgets.push_back(
+        CreateTestWidget(nullptr, container_ids[i], gfx::Rect(700, 0, 50, 50)));
+    aura::Window* win = widgets[i]->GetNativeWindow();
+    windows_.push_back(win);
+    // `TargetVisibility` is the local visibility of the window
+    // regardless of the invisibility of its inactive parent desk.
+    EXPECT_TRUE(win->TargetVisibility());
+    // `IsVisible` is the window global visibility on the current workarea.
+    // Thus, any window in non-active desk is considered invisible.
+    EXPECT_EQ(i == kActiveDeskIndex, win->IsVisible());
+    EXPECT_TRUE(ash::AutotestDesksApi().IsWindowInDesk(win,
+                                                       /*desk_index=*/i));
+  }
+  EXPECT_EQ(kActiveDeskIndex, desks_helper->GetActiveDeskIndex());
+  test_shell_delegate->SetSessionRestoreInProgress(false);
+  return widgets;
+}
+
 void MultiProfileSupportTest::TearDown() {
   // Since the AuraTestBase is needed to create our assets, we have to
   // also delete them before we tear it down.
@@ -641,6 +681,65 @@
   EXPECT_EQ("S[a], S[a], S[b,a], S[b,a], S[]", GetStatus());
 }
 
+// Tests that windows in active and inactive desks show up correctly after
+// switching profile (crbug.com/1182069). This test checks the followings:
+// 1. window local visibility (appearance in desk miniviews) regardless
+// of its ancestors' visibility like hidden parent desk container
+// (see `Window::TargetVisibility()`).
+// 2. window global visibility (appearance in the user screen) which takes
+// its ancestor views' visibility into account (see `Window::IsVisible()`).
+TEST_F(MultiProfileSupportTest, WindowVisibilityInMultipleDesksTests) {
+  const AccountId account_id_A(AccountId::FromUserEmail("a"));
+  const AccountId account_id_B(AccountId::FromUserEmail("b"));
+  ::MultiUserWindowManagerHelper::CreateInstanceForTest(account_id_A);
+  ash::MultiUserWindowManagerImpl::Get()->SetAnimationSpeedForTest(
+      ash::MultiUserWindowManagerImpl::ANIMATION_SPEED_DISABLED);
+  AddTestUser(account_id_A);
+  AddTestUser(account_id_B);
+
+  // In the user A, setup two desks with one window each.
+  SwitchActiveUser(account_id_A);
+  ash::AutotestDesksApi().CreateNewDesk();
+  std::vector<std::unique_ptr<views::Widget>> widgets =
+      SetUpOneWindowEachDeskForUser(account_id_A);
+  ASSERT_FALSE(widgets.empty());
+  multi_user_window_manager()->SetWindowOwner(window(0), account_id_A);
+  multi_user_window_manager()->SetWindowOwner(window(1), account_id_A);
+
+  // Tests that both windows are locally visible, but only the first window
+  // in the first active desk is globally visible.
+  // GetStatus checks the global visibility `window::IsVisible()`.
+  EXPECT_EQ("S[a], H[a]", GetStatus());
+  // Local visibilties are true because both windows show up in desks miniview.
+  EXPECT_TRUE(window(0)->TargetVisibility());
+  EXPECT_TRUE(window(1)->TargetVisibility());
+
+  // Tests that switching to userB globally and locally hides both userA's
+  // windows.
+  SwitchActiveUser(account_id_B);
+  EXPECT_EQ("H[a], H[a]", GetStatus());
+  EXPECT_FALSE(window(0)->TargetVisibility());
+  EXPECT_FALSE(window(1)->TargetVisibility());
+
+  // Tests that switching to userA globally shows both userA's windows, but does
+  // not change windows' local visibility.
+  SwitchActiveUser(account_id_A);
+  EXPECT_EQ("S[a], H[a]", GetStatus());
+  EXPECT_TRUE(window(0)->TargetVisibility());
+  EXPECT_TRUE(window(1)->TargetVisibility());
+
+  // Tests that activating the second desk globally shows userA's second window
+  // but does not change windows' local visibility.
+  auto* desk_2 = ash::DesksController::Get()->desks()[1].get();
+  ash::ActivateDesk(desk_2);
+  EXPECT_EQ("H[a], S[a]", GetStatus());
+  EXPECT_TRUE(window(0)->TargetVisibility());
+  EXPECT_TRUE(window(1)->TargetVisibility());
+
+  delete_window_at(0);
+  delete_window_at(1);
+}
+
 // Check that minimizing a window which is owned by another user will move it
 // back and gets restored upon switching back to the original user.
 TEST_F(MultiProfileSupportTest, MinimizeChangesOwnershipBack) {
diff --git a/chrome/browser/ui/browser_browsertest.cc b/chrome/browser/ui/browser_browsertest.cc
index 7d23203e..0630aaab 100644
--- a/chrome/browser/ui/browser_browsertest.cc
+++ b/chrome/browser/ui/browser_browsertest.cc
@@ -17,7 +17,6 @@
 
 #include "base/bind.h"
 #include "base/callback_helpers.h"
-#include "base/cfi_buildflags.h"
 #include "base/command_line.h"
 #include "base/compiler_specific.h"
 #include "base/files/file_path.h"
@@ -2962,20 +2961,9 @@
   EXPECT_FALSE(nav_observer.was_same_document());
 }
 
-// TODO(1184168): Flaky on linux dbg, linux asan, and linux CFI.
-#if defined(OS_LINUX) &&                                        \
-    (!defined(NDEBUG) || defined(ADDRESS_SANITIZER) ||          \
-     BUILDFLAG(CFI_CAST_CHECK) || BUILDFLAG(CFI_ICALL_CHECK) || \
-     BUILDFLAG(CFI_ENFORCEMENT_TRAP) || BUILDFLAG(CFI_ENFORCEMENT_DIAGNOSTIC))
-#define MAYBE_SameDocumentHistoryNavigationWithNothingCommittedAfterCrash \
-  DISABLED_SameDocumentHistoryNavigationWithNothingCommittedAfterCrash
-#else
-#define MAYBE_SameDocumentHistoryNavigationWithNothingCommittedAfterCrash \
-  SameDocumentHistoryNavigationWithNothingCommittedAfterCrash
-#endif
 IN_PROC_BROWSER_TEST_F(
     BrowserTest,
-    MAYBE_SameDocumentHistoryNavigationWithNothingCommittedAfterCrash) {
+    SameDocumentHistoryNavigationWithNothingCommittedAfterCrash) {
   content::SlowHttpResponse::GotRequestCallback got_slow_request;
 
   embedded_test_server()->RegisterRequestHandler(base::BindLambdaForTesting(
diff --git a/chrome/browser/ui/browser_window.h b/chrome/browser/ui/browser_window.h
index 5e1d5b7..9de83c8 100644
--- a/chrome/browser/ui/browser_window.h
+++ b/chrome/browser/ui/browser_window.h
@@ -474,10 +474,15 @@
 
   // Shows User Happiness Tracking Survey's dialog after the survey associated
   // with |site_id| has been successfully loaded. Failure to load the survey
-  // will result in the dialog not being shown.
-  virtual void ShowHatsDialog(const std::string& site_id,
-                              base::OnceClosure success_callback,
-                              base::OnceClosure failure_callback) = 0;
+  // will result in the dialog not being shown. |product_specific_data| should
+  // contain key-value pairs where the keys match the field names set for
+  // the survey in hats_service.cc, and the values are those which will be
+  // associated with the survey response.
+  virtual void ShowHatsDialog(
+      const std::string& site_id,
+      base::OnceClosure success_callback,
+      base::OnceClosure failure_callback,
+      const std::map<std::string, bool>& product_specific_data) = 0;
 
   // Returns object implementing ExclusiveAccessContext interface.
   virtual ExclusiveAccessContext* GetExclusiveAccessContext() = 0;
diff --git a/chrome/browser/ui/exclusive_access/fullscreen_controller_interactive_browsertest.cc b/chrome/browser/ui/exclusive_access/fullscreen_controller_interactive_browsertest.cc
index 8aa552e..670ca9d 100644
--- a/chrome/browser/ui/exclusive_access/fullscreen_controller_interactive_browsertest.cc
+++ b/chrome/browser/ui/exclusive_access/fullscreen_controller_interactive_browsertest.cc
@@ -817,7 +817,8 @@
 // Tests async fullscreen requests on screenschange event.
 // TODO(crbug.com/1134731): Disabled on Windows, where RenderWidgetHostViewAura
 // blindly casts display::Screen::GetScreen() to display::win::ScreenWin*.
-#if defined(OS_WIN)
+// TODO(crbug.com/1183791): Disabled on Mac due to flaky ObserverList crashes.
+#if defined(OS_WIN) || defined(OS_MAC)
 #define MAYBE_FullscreenOnScreensChange DISABLED_FullscreenOnScreensChange
 #else
 #define MAYBE_FullscreenOnScreensChange FullscreenOnScreensChange
diff --git a/chrome/browser/ui/hats/hats_helper.cc b/chrome/browser/ui/hats/hats_helper.cc
index 7aa1574..f639625 100644
--- a/chrome/browser/ui/hats/hats_helper.cc
+++ b/chrome/browser/ui/hats/hats_helper.cc
@@ -40,8 +40,15 @@
         profile(), /*create_if_necessary=*/true);
 
     if (hats_service) {
-      hats_service->LaunchSurvey(demo_enabled ? kHatsSurveyTriggerTesting
-                                              : kHatsSurveyTriggerSatisfaction);
+      if (demo_enabled) {
+        hats_service->LaunchSurvey(kHatsSurveyTriggerTesting, base::DoNothing(),
+                                   base::DoNothing(),
+                                   {{"Test Field 1", true},
+                                    {"Test Field 2", false},
+                                    {"Test Field 3", true}});
+      } else {
+        hats_service->LaunchSurvey(kHatsSurveyTriggerSatisfaction);
+      }
     }
   }
 }
diff --git a/chrome/browser/ui/hats/hats_service.cc b/chrome/browser/ui/hats/hats_service.cc
index 56cb4533..49616a8 100644
--- a/chrome/browser/ui/hats/hats_service.cc
+++ b/chrome/browser/ui/hats/hats_service.cc
@@ -49,8 +49,6 @@
 
 constexpr double kHatsSurveyProbabilityDefault = 0;
 
-constexpr char kHatsSurveyEnSiteIDDefault[] = "bhej2dndhpc33okm6xexsbyv4y";
-
 // TODO(crbug.com/1160661): When the minimum time between any survey, and the
 // minimum time between a specific survey, are the same, the logic supporting
 // the latter check is superfluous.
@@ -92,8 +90,86 @@
 
 constexpr char kAnyLastSurveyStartedTimePath[] = "any_last_survey_started_time";
 
+std::vector<HatsService::SurveyConfig> GetSurveyConfigs() {
+  std::vector<HatsService::SurveyConfig> survey_configs;
+
+  // NTP survey.
+  survey_configs.emplace_back(&features::kHappinessTrackingSurveysForDesktop,
+                              kHatsSurveyTriggerSatisfaction);
+
+  // Dev tools surveys.
+  survey_configs.emplace_back(&features::kHaTSDesktopDevToolsIssuesCOEP,
+                              "devtools-issues-coep",
+                              "1DbEs89FS0ugnJ3q1cK0Nx6T99yT");
+  survey_configs.emplace_back(&features::kHaTSDesktopDevToolsIssuesMixedContent,
+                              "devtools-issues-mixed-content",
+                              "BhCYpUmyf0ugnJ3q1cK0VtxCftzo");
+  survey_configs.emplace_back(
+      &features::
+          kHappinessTrackingSurveysForDesktopDevToolsIssuesCookiesSameSite,
+      "devtools-issues-cookies-samesite", "w9JqqpmEr0ugnJ3q1cK0NezVg4iK");
+  survey_configs.emplace_back(&features::kHaTSDesktopDevToolsIssuesHeavyAd,
+                              "devtools-issues-heavy-ad",
+                              "bAeiT5J4P0ugnJ3q1cK0Ra6jg7s8");
+  survey_configs.emplace_back(&features::kHaTSDesktopDevToolsIssuesCSP,
+                              "devtools-issues-csp",
+                              "c9fjDmwjb0ugnJ3q1cK0USeAJJ9C");
+  survey_configs.emplace_back(&features::kHaTSDesktopDevToolsLayoutPanel,
+                              "devtools-layout-panel",
+                              "hhoMFLFq70ugnJ3q1cK0XYpqkErh");
+
+  // Settings surveys.
+  survey_configs.emplace_back(
+      &features::kHappinessTrackingSurveysForDesktopSettings,
+      kHatsSurveyTriggerSettings);
+  survey_configs.emplace_back(
+      &features::kHappinessTrackingSurveysForDesktopSettingsPrivacy,
+      kHatsSurveyTriggerSettingsPrivacy);
+
+  return survey_configs;
+}
+
 }  // namespace
 
+HatsService::SurveyConfig::SurveyConfig(
+    const base::Feature* feature,
+    const std::string& trigger,
+    const base::Optional<std::string>& presupplied_trigger_id,
+    const std::vector<std::string>& product_specific_data_fields)
+    : trigger(trigger),
+      product_specific_data_fields(product_specific_data_fields) {
+  DCHECK(product_specific_data_fields.size() <= 3)
+      << "A maximum of 3 survey specific data fields is supported";
+
+  enabled = base::FeatureList::IsEnabled(*feature);
+  if (!enabled)
+    return;
+
+  probability = base::FeatureParam<double>(feature, kHatsSurveyProbability,
+                                           kHatsSurveyProbabilityDefault)
+                    .Get();
+
+  // The trigger_id may be provided through the associated feature parameter or
+  // may have been included in the source code. The latter is required to enable
+  // multiple surveys with a single finch group, as a limitation with finch
+  // prevents duplicate param names even for different features within a group.
+  // The feature parameter name is "en_site_id" for legacy reasons, as this
+  // was the HaTS v1 equivalent of a trigger ID in HaTS Next.
+  trigger_id = presupplied_trigger_id ? *presupplied_trigger_id
+                                      : base::FeatureParam<std::string>(
+                                            feature, kHatsSurveyEnSiteID, "")
+                                            .Get();
+
+  user_prompted =
+      base::FeatureParam<bool>(feature, "user_prompted", false).Get();
+}
+
+HatsService::SurveyConfig::SurveyConfig() = default;
+
+HatsService::SurveyConfig::SurveyConfig(const SurveyConfig&) = default;
+
+HatsService::SurveyConfig::~SurveyConfig() = default;
+
 HatsService::SurveyMetadata::SurveyMetadata() = default;
 
 HatsService::SurveyMetadata::~SurveyMetadata() = default;
@@ -101,8 +177,11 @@
 HatsService::DelayedSurveyTask::DelayedSurveyTask(
     HatsService* hats_service,
     const std::string& trigger,
-    content::WebContents* web_contents)
-    : hats_service_(hats_service), trigger_(trigger) {
+    content::WebContents* web_contents,
+    const std::map<std::string, bool>& product_specific_data)
+    : hats_service_(hats_service),
+      trigger_(trigger),
+      product_specific_data_(product_specific_data) {
   Observe(web_contents);
 }
 
@@ -114,7 +193,8 @@
 }
 
 void HatsService::DelayedSurveyTask::Launch() {
-  hats_service_->LaunchSurveyForWebContents(trigger_, web_contents());
+  hats_service_->LaunchSurveyForWebContents(trigger_, web_contents(),
+                                            product_specific_data_);
   hats_service_->RemoveTask(*this);
 }
 
@@ -126,67 +206,33 @@
   const base::Feature* feature;
   const char* trigger;
   const char* trigger_id;
-};
-
-const char* kTriggerIdProvidedByFeatureParams = "";
-
-// The Feature for each survey is generally disabled by default, and only
-// enabled via a Finch config. The trigger_id can be provided via feature
-// params. If the feature params don't contain a trigger_id (called en_site_id
-// in the params), the fallback here will be used. For features that we want to
-// enable all at the same time (in the same 'group'), we can't provide the
-// trigger_id via feature params due to a limitation that prevents duplicate
-// param names, even for different features within a group.
-const SurveyIdentifiers surveys[] = {
-    {&features::kHappinessTrackingSurveysForDesktop,
-     kHatsSurveyTriggerSatisfaction, "test_site_id"},
-    {&features::kHaTSDesktopDevToolsIssuesCOEP, "devtools-issues-coep",
-     "1DbEs89FS0ugnJ3q1cK0Nx6T99yT"},
-    {&features::kHaTSDesktopDevToolsIssuesMixedContent,
-     "devtools-issues-mixed-content", "BhCYpUmyf0ugnJ3q1cK0VtxCftzo"},
-    {&features::
-         kHappinessTrackingSurveysForDesktopDevToolsIssuesCookiesSameSite,
-     "devtools-issues-cookies-samesite", "w9JqqpmEr0ugnJ3q1cK0NezVg4iK"},
-    {&features::kHaTSDesktopDevToolsIssuesHeavyAd, "devtools-issues-heavy-ad",
-     "bAeiT5J4P0ugnJ3q1cK0Ra6jg7s8"},
-    {&features::kHaTSDesktopDevToolsIssuesCSP, "devtools-issues-csp",
-     "c9fjDmwjb0ugnJ3q1cK0USeAJJ9C"},
-    {&features::kHaTSDesktopDevToolsLayoutPanel, "devtools-layout-panel",
-     "hhoMFLFq70ugnJ3q1cK0XYpqkErh"},
-    {&features::kHappinessTrackingSurveysForDesktopSettings,
-     kHatsSurveyTriggerSettings, kTriggerIdProvidedByFeatureParams},
-    {&features::kHappinessTrackingSurveysForDesktopSettingsPrivacy,
-     kHatsSurveyTriggerSettingsPrivacy, kTriggerIdProvidedByFeatureParams},
+  std::vector<std::string> product_specific_data_fields;
 };
 
 HatsService::HatsService(Profile* profile) : profile_(profile) {
-  constexpr char kHatsSurveyUserPrompted[] = "user_prompted";
-  constexpr bool kHatsSurveyUserPromptedDefault = false;
+  auto surveys = GetSurveyConfigs();
 
-  for (const SurveyIdentifiers& survey : surveys) {
-    if (!base::FeatureList::IsEnabled(*survey.feature))
+  // Filter down to active surveys configs and store them in a map for faster
+  // access. Triggers within the browser may attempt to show surveys regardless
+  // of whether the feature is enabled, so checking whether a particular survey
+  // is enabled should be fast.
+  for (const SurveyConfig& survey : surveys) {
+    if (!survey.enabled)
       continue;
-    survey_configs_by_triggers_.emplace(
-        survey.trigger,
-        SurveyConfig(
-            base::FeatureParam<double>(survey.feature, kHatsSurveyProbability,
-                                       kHatsSurveyProbabilityDefault)
-                .Get(),
-            base::FeatureParam<std::string>(survey.feature, kHatsSurveyEnSiteID,
-                                            survey.trigger_id)
-                .Get(),
-            base::FeatureParam<bool>(survey.feature, kHatsSurveyUserPrompted,
-                                     kHatsSurveyUserPromptedDefault)
-                .Get()));
+
+    survey_configs_by_triggers_.emplace(survey.trigger, survey);
   }
+
   // Ensure a default survey exists (for testing and demo purpose).
-  auto* default_survey_id =
-      base::FeatureList::IsEnabled(
-          features::kHappinessTrackingSurveysForDesktopMigration)
-          ? kHatsNextSurveyTriggerIDTesting
-          : kHatsSurveyEnSiteIDDefault;
-  survey_configs_by_triggers_.emplace(
-      kHatsSurveyTriggerTesting, SurveyConfig(1.0f, default_survey_id, false));
+  SurveyConfig default_survey;
+  default_survey.enabled = true;
+  default_survey.probability = 1.0f;
+  default_survey.trigger = kHatsSurveyTriggerTesting;
+  default_survey.trigger_id = kHatsNextSurveyTriggerIDTesting;
+  default_survey.product_specific_data_fields = {"Test Field 1", "Test Field 2",
+                                                 "Test Field 3"};
+  survey_configs_by_triggers_.emplace(kHatsSurveyTriggerTesting,
+                                      default_survey);
 }
 
 HatsService::~HatsService() = default;
@@ -199,35 +245,43 @@
       user_prefs::PrefRegistrySyncable::SYNCABLE_PREF);
 }
 
-void HatsService::LaunchSurvey(const std::string& trigger,
-                               base::OnceClosure success_callback,
-                               base::OnceClosure failure_callback) {
+void HatsService::LaunchSurvey(
+    const std::string& trigger,
+    base::OnceClosure success_callback,
+    base::OnceClosure failure_callback,
+    const std::map<std::string, bool>& product_specific_data) {
   if (!ShouldShowSurvey(trigger)) {
     std::move(failure_callback).Run();
     return;
   }
+
   LaunchSurveyForBrowser(chrome::FindLastActiveWithProfile(profile_), trigger,
                          std::move(success_callback),
-                         std::move(failure_callback));
+                         std::move(failure_callback), product_specific_data);
 }
 
-bool HatsService::LaunchDelayedSurvey(const std::string& trigger,
-                                      int timeout_ms) {
+bool HatsService::LaunchDelayedSurvey(
+    const std::string& trigger,
+    int timeout_ms,
+    const std::map<std::string, bool>& product_specific_data) {
   return base::SequencedTaskRunnerHandle::Get()->PostDelayedTask(
       FROM_HERE,
       base::BindOnce(&HatsService::LaunchSurvey, weak_ptr_factory_.GetWeakPtr(),
-                     trigger, base::DoNothing::Once(), base::DoNothing::Once()),
+                     trigger, base::DoNothing::Once(), base::DoNothing::Once(),
+                     product_specific_data),
       base::TimeDelta::FromMilliseconds(timeout_ms));
 }
 
 bool HatsService::LaunchDelayedSurveyForWebContents(
     const std::string& trigger,
     content::WebContents* web_contents,
-    int timeout_ms) {
+    int timeout_ms,
+    const std::map<std::string, bool>& product_specific_data) {
   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
   if (!web_contents)
     return false;
-  auto result = pending_tasks_.emplace(this, trigger, web_contents);
+  auto result = pending_tasks_.emplace(this, trigger, web_contents,
+                                       product_specific_data);
   if (!result.second)
     return false;
   auto success = base::SequencedTaskRunnerHandle::Get()->PostDelayedTask(
@@ -243,17 +297,15 @@
   return success;
 }
 
-void HatsService::RecordSurveyAsShown(std::string survey_id) {
-  // Record the trigger associated with the survey_id. This is recorded instead
-  // of the survey ID itself, as the ID is specific to individual survey
+void HatsService::RecordSurveyAsShown(std::string trigger_id) {
+  // Record the trigger associated with the trigger_id. This is recorded instead
+  // of the trigger ID itself, as the ID is specific to individual survey
   // versions. There should be a cooldown before a user is prompted to take a
   // survey from the same trigger, regardless of whether the survey was updated.
-  // TODO(crbug.com/1110888): When HaTS V1 is deprecated, improve nomenclature
-  // to remove confusion between trigger, trigger ID, survey ID and site ID.
   auto trigger_survey_config = std::find_if(
       survey_configs_by_triggers_.begin(), survey_configs_by_triggers_.end(),
       [&](const std::pair<std::string, SurveyConfig>& pair) {
-        return pair.second.en_site_id_ == survey_id;
+        return pair.second.trigger_id == trigger_id;
       });
 
   DCHECK(trigger_survey_config != survey_configs_by_triggers_.end());
@@ -366,18 +418,22 @@
 
 void HatsService::LaunchSurveyForWebContents(
     const std::string& trigger,
-    content::WebContents* web_contents) {
+    content::WebContents* web_contents,
+    const std::map<std::string, bool>& product_specific_data) {
   if (ShouldShowSurvey(trigger) && web_contents &&
       web_contents->GetVisibility() == content::Visibility::VISIBLE) {
     LaunchSurveyForBrowser(chrome::FindBrowserWithWebContents(web_contents),
-                           trigger, base::DoNothing(), base::DoNothing());
+                           trigger, base::DoNothing(), base::DoNothing(),
+                           product_specific_data);
   }
 }
 
-void HatsService::LaunchSurveyForBrowser(Browser* browser,
-                                         const std::string& trigger,
-                                         base::OnceClosure success_callback,
-                                         base::OnceClosure failure_callback) {
+void HatsService::LaunchSurveyForBrowser(
+    Browser* browser,
+    const std::string& trigger,
+    base::OnceClosure success_callback,
+    base::OnceClosure failure_callback,
+    const std::map<std::string, bool>& product_specific_data) {
   if (!browser ||
       (!browser->is_type_normal() && !browser->is_type_devtools()) ||
       !profiles::IsRegularOrGuestSession(browser)) {
@@ -399,7 +455,8 @@
   // Checking survey's status could be costly due to a network request, so
   // we check it at the last.
   CheckSurveyStatusAndMaybeShow(browser, trigger, std::move(success_callback),
-                                std::move(failure_callback));
+                                std::move(failure_callback),
+                                product_specific_data);
 }
 
 bool HatsService::CanShowSurvey(const std::string& trigger) const {
@@ -461,7 +518,7 @@
 
   base::Time now = base::Time::Now();
 
-  if (!config.user_prompted_) {
+  if (!config.user_prompted) {
     if ((now - profile_->GetCreationTime()) < kMinimumProfileAge) {
       UMA_HISTOGRAM_ENUMERATION(kHatsShouldShowSurveyReasonHistogram,
                                 ShouldShowSurveyReasons::kNoProfileTooNew);
@@ -515,8 +572,8 @@
   if (!CanShowSurvey(trigger))
     return false;
 
-  auto probability_ = survey_configs_by_triggers_.at(trigger).probability_;
-  bool should_show_survey = base::RandDouble() < probability_;
+  auto probability = survey_configs_by_triggers_.at(trigger).probability;
+  bool should_show_survey = base::RandDouble() < probability;
   if (!should_show_survey) {
     UMA_HISTOGRAM_ENUMERATION(
         kHatsShouldShowSurveyReasonHistogram,
@@ -530,7 +587,8 @@
     Browser* browser,
     const std::string& trigger,
     base::OnceClosure success_callback,
-    base::OnceClosure failure_callback) {
+    base::OnceClosure failure_callback,
+    const std::map<std::string, bool>& product_specific_data) {
   // Check the survey status in profile first.
   // We record the survey's over capacity information in user profile to avoid
   // duplicated checks since the survey won't change once it is full.
@@ -545,6 +603,18 @@
 
   DCHECK(survey_configs_by_triggers_.find(trigger) !=
          survey_configs_by_triggers_.end());
+  auto survey_config = survey_configs_by_triggers_[trigger];
+
+  // Check that the |product_specific_data| matches the fields for this trigger.
+  // If fields are set for a trigger, they must be provided.
+  DCHECK_EQ(product_specific_data.size(),
+            survey_config.product_specific_data_fields.size());
+  for (auto field_value : product_specific_data) {
+    DCHECK(std::find(survey_config.product_specific_data_fields.begin(),
+                     survey_config.product_specific_data_fields.end(),
+                     field_value.first) !=
+           survey_config.product_specific_data_fields.end());
+  }
 
   // As soon as the HaTS Next dialog is created it will attempt to contact
   // the HaTS servers to check for a survey.
@@ -554,7 +624,8 @@
 
   DCHECK(!hats_next_dialog_exists_);
   browser->window()->ShowHatsDialog(
-      survey_configs_by_triggers_[trigger].en_site_id_,
-      std::move(success_callback), std::move(failure_callback));
+      survey_configs_by_triggers_[trigger].trigger_id,
+      std::move(success_callback), std::move(failure_callback),
+      product_specific_data);
   hats_next_dialog_exists_ = true;
 }
diff --git a/chrome/browser/ui/hats/hats_service.h b/chrome/browser/ui/hats/hats_service.h
index b94d83c..6e3a6ea 100644
--- a/chrome/browser/ui/hats/hats_service.h
+++ b/chrome/browser/ui/hats/hats_service.h
@@ -54,22 +54,39 @@
 class HatsService : public KeyedService {
  public:
   struct SurveyConfig {
-    SurveyConfig(double probability, std::string en_site_id, bool user_prompted)
-        : probability_(probability),
-          en_site_id_(std::move(en_site_id)),
-          user_prompted_(user_prompted) {}
+    // Constructs a SurveyConfig by inspecting |feature|. This includes checking
+    // if the feature is enabled, as well as inspecting the feature parameters
+    // for the survey probability, and if |presupplied_trigger_id| is not
+    // provided, the trigger ID.
+    SurveyConfig(
+        const base::Feature* feature,
+        const std::string& trigger,
+        const base::Optional<std::string>& presupplied_trigger_id =
+            base::nullopt,
+        const std::vector<std::string>& product_specific_data_fields = {});
+    SurveyConfig();
+    SurveyConfig(const SurveyConfig&);
+    ~SurveyConfig();
 
-    SurveyConfig() = default;
+    // Whether the survey is currently enabled and can be shown.
+    bool enabled = false;
 
     // Probability [0,1] of how likely a chosen user will see the survey.
-    double probability_;
+    double probability = 0.0f;
 
-    // Site ID for the survey.
-    std::string en_site_id_;
+    // The trigger for this survey within the browser.
+    std::string trigger;
+
+    // Trigger ID for the survey.
+    std::string trigger_id;
 
     // The survey will prompt every time because the user has explicitly decided
     // to take the survey e.g. clicking a link.
-    bool user_prompted_;
+    bool user_prompted = false;
+
+    // Product Specific Data fields which are sent with the survey
+    // response.
+    std::vector<std::string> product_specific_data_fields;
   };
 
   struct SurveyMetadata {
@@ -90,7 +107,8 @@
    public:
     DelayedSurveyTask(HatsService* hats_service,
                       const std::string& trigger,
-                      content::WebContents* web_contents);
+                      content::WebContents* web_contents,
+                      const std::map<std::string, bool>& product_specific_data);
 
     // Not copyable or movable
     DelayedSurveyTask(const DelayedSurveyTask&) = delete;
@@ -116,6 +134,7 @@
    private:
     HatsService* hats_service_;
     std::string trigger_;
+    std::map<std::string, bool> product_specific_data_;
     base::WeakPtrFactory<DelayedSurveyTask> weak_ptr_factory_{this};
   };
 
@@ -151,16 +170,23 @@
   // Launches survey with identifier |trigger| if appropriate.
   // |success_callback| is called when the survey is shown to the user.
   // |failure_callback| is called if the survey does not launch for any reason.
+  // |product_specific_data| should contain key-value pairs where the keys match
+  // the field names set for the survey in hats_service.cc, and the values are
+  // those which will be associated with the survey response.
   virtual void LaunchSurvey(
       const std::string& trigger,
       base::OnceClosure success_callback = base::DoNothing(),
-      base::OnceClosure failure_callback = base::DoNothing());
+      base::OnceClosure failure_callback = base::DoNothing(),
+      const std::map<std::string, bool>& product_specific_data = {});
 
   // Launches survey (with id |trigger|) with a timeout |timeout_ms| if
   // appropriate. Survey will be shown at the active window/tab by the
   // time of launching. Rejects (and returns false) if the underlying task
   // posting fails.
-  virtual bool LaunchDelayedSurvey(const std::string& trigger, int timeout_ms);
+  virtual bool LaunchDelayedSurvey(
+      const std::string& trigger,
+      int timeout_ms,
+      const std::map<std::string, bool>& product_specific_data = {});
 
   // Launches survey (with id |trigger|) with a timeout |timeout_ms| for tab
   // |web_contents| if appropriate. |web_contents| required to be non-nullptr.
@@ -172,13 +198,13 @@
   virtual bool LaunchDelayedSurveyForWebContents(
       const std::string& trigger,
       content::WebContents* web_contents,
-      int timeout_ms);
+      int timeout_ms,
+      const std::map<std::string, bool>& product_specific_data = {});
 
   // Updates the user preferences to record that the survey associated with
-  // |survey_id| was shown to the user. |survey_id| is the unique_id provided
-  // to the HaTS Service to identify a survey. This is the trigger ID for HaTS
-  // Next, and the site ID for HaTS v1.
-  void RecordSurveyAsShown(std::string survey_id);
+  // |survey_id| was shown to the user. |trigger_id| is the HaTS next Trigger
+  // ID for the survey.
+  void RecordSurveyAsShown(std::string trigger_id);
 
   // Indicates to the service that the HaTS Next dialog has been closed.
   // Virtual to allow mocking in tests.
@@ -204,13 +230,17 @@
   friend class DelayedSurveyTask;
   FRIEND_TEST_ALL_PREFIXES(HatsServiceProbabilityOne, SingleHatsNextDialog);
 
-  void LaunchSurveyForWebContents(const std::string& trigger,
-                                  content::WebContents* web_contents);
+  void LaunchSurveyForWebContents(
+      const std::string& trigger,
+      content::WebContents* web_contents,
+      const std::map<std::string, bool>& product_specific_data);
 
-  void LaunchSurveyForBrowser(Browser* browser,
-                              const std::string& trigger,
-                              base::OnceClosure success_callback,
-                              base::OnceClosure failure_callback);
+  void LaunchSurveyForBrowser(
+      Browser* browser,
+      const std::string& trigger,
+      base::OnceClosure success_callback,
+      base::OnceClosure failure_callback,
+      const std::map<std::string, bool>& product_specific_data);
 
   // Returns true is the survey trigger specified should be shown.
   bool ShouldShowSurvey(const std::string& trigger) const;
@@ -218,10 +248,12 @@
   // Check whether the survey is reachable and under capacity and show it.
   // |success_callback| is called when the survey is shown to the user.
   // |failure_callback| is called if the survey does not launch for any reason.
-  void CheckSurveyStatusAndMaybeShow(Browser* browser,
-                                     const std::string& trigger,
-                                     base::OnceClosure success_callback,
-                                     base::OnceClosure failure_callback);
+  void CheckSurveyStatusAndMaybeShow(
+      Browser* browser,
+      const std::string& trigger,
+      base::OnceClosure success_callback,
+      base::OnceClosure failure_callback,
+      const std::map<std::string, bool>& product_specific_data);
 
   // Remove |task| from the set of |pending_tasks_|.
   void RemoveTask(const DelayedSurveyTask& task);
diff --git a/chrome/browser/ui/hats/mock_hats_service.h b/chrome/browser/ui/hats/mock_hats_service.h
index b145c439..e3a00bc 100644
--- a/chrome/browser/ui/hats/mock_hats_service.h
+++ b/chrome/browser/ui/hats/mock_hats_service.h
@@ -26,17 +26,21 @@
               LaunchSurvey,
               (const std::string& trigger,
                base::OnceClosure success_callback,
-               base::OnceClosure failure_callback),
+               base::OnceClosure failure_callback,
+               (const std::map<std::string, bool>&)survey_specific_data),
               (override));
   MOCK_METHOD(bool,
               LaunchDelayedSurvey,
-              (const std::string& trigger, int timeout_ms),
+              (const std::string& trigger,
+               int timeout_ms,
+               (const std::map<std::string, bool>&)survey_specific_data),
               (override));
   MOCK_METHOD(bool,
               LaunchDelayedSurveyForWebContents,
               (const std::string& trigger,
                content::WebContents* web_contents,
-               int timeout_ms),
+               int timeout_ms,
+               (const std::map<std::string, bool>&)survey_specific_data),
               (override));
   MOCK_METHOD(void, HatsNextDialogClosed, (), (override));
 };
diff --git a/chrome/browser/ui/profile_picker.h b/chrome/browser/ui/profile_picker.h
index e39e831..cff72c6 100644
--- a/chrome/browser/ui/profile_picker.h
+++ b/chrome/browser/ui/profile_picker.h
@@ -90,6 +90,11 @@
   // uses the same new profile created by `SwitchToSignIn()`.
   static void SwitchToSyncConfirmation();
 
+  // When the sign-in flow cannot be completed because another profile at
+  // `profile_path` is already syncing with a chosen account, shows the profile
+  // switch screen. It uses the system profile.
+  static void SwitchToProfileSwitch(const base::FilePath& profile_path);
+
   // Shows a dialog where the user can auth the profile or see the
   // auth error message. If a dialog is already shown, this destroys the current
   // dialog and creates a new one.
@@ -108,6 +113,10 @@
   // profile selection instead of the new tab page.
   static GURL GetOnSelectProfileTargetUrl();
 
+  // Getter of the path of profile which is displayed on the profile switch
+  // screen.
+  static base::FilePath GetSwitchProfilePath();
+
   // Hides the profile picker.
   static void Hide();
 
diff --git a/chrome/browser/ui/views/frame/browser_view.cc b/chrome/browser/ui/views/frame/browser_view.cc
index 71551fff..e84e97a 100644
--- a/chrome/browser/ui/views/frame/browser_view.cc
+++ b/chrome/browser/ui/views/frame/browser_view.cc
@@ -3496,12 +3496,16 @@
                                   focus_first_profile_button);
 }
 
-void BrowserView::ShowHatsDialog(const std::string& site_id,
-                                 base::OnceClosure success_callback,
-                                 base::OnceClosure failure_callback) {
+void BrowserView::ShowHatsDialog(
+    const std::string& site_id,
+    base::OnceClosure success_callback,
+    base::OnceClosure failure_callback,
+    const std::map<std::string, bool>& product_specific_data) {
   // Self deleting on close.
   new HatsNextWebDialog(browser(), site_id, std::move(success_callback),
-                        std::move(failure_callback));
+                        std::move(failure_callback), product_specific_data
+
+  );
 }
 
 ExclusiveAccessContext* BrowserView::GetExclusiveAccessContext() {
diff --git a/chrome/browser/ui/views/frame/browser_view.h b/chrome/browser/ui/views/frame/browser_view.h
index 72e6cc4..d872b40c 100644
--- a/chrome/browser/ui/views/frame/browser_view.h
+++ b/chrome/browser/ui/views/frame/browser_view.h
@@ -466,9 +466,11 @@
       AvatarBubbleMode mode,
       signin_metrics::AccessPoint access_point,
       bool is_source_keyboard) override;
-  void ShowHatsDialog(const std::string& site_id,
-                      base::OnceClosure success_callback,
-                      base::OnceClosure failure_callback) override;
+  void ShowHatsDialog(
+      const std::string& site_id,
+      base::OnceClosure success_callback,
+      base::OnceClosure failure_callback,
+      const std::map<std::string, bool>& product_specific_data) override;
   ExclusiveAccessContext* GetExclusiveAccessContext() override;
   std::string GetWorkspace() const override;
   bool IsVisibleOnAllWorkspaces() const override;
diff --git a/chrome/browser/ui/views/hats/hats_browsertest.cc b/chrome/browser/ui/views/hats/hats_browsertest.cc
index e6cf03af..7b2466f 100644
--- a/chrome/browser/ui/views/hats/hats_browsertest.cc
+++ b/chrome/browser/ui/views/hats/hats_browsertest.cc
@@ -32,20 +32,34 @@
 #include "third_party/blink/public/common/page/page_zoom.h"
 #include "url/gurl.h"
 
+namespace {
+
+// The product specific data expected by the test survey. The boolean values are
+// checked in hats_next_mock.html.
+const std::map<std::string, bool> kHatsNextTestSurveyProductSpecificData{
+    {"Test Field 1", true},
+    {"Test Field 2", false},
+    {"Test Field 3", true}};
+
+}  // namespace
+
 class MockHatsNextWebDialog : public HatsNextWebDialog {
  public:
-  MockHatsNextWebDialog(Browser* browser,
-                        const std::string& trigger_id,
-                        const GURL& hats_survey_url,
-                        const base::TimeDelta& timeout,
-                        base::OnceClosure success_callback,
-                        base::OnceClosure failure_callback)
+  MockHatsNextWebDialog(
+      Browser* browser,
+      const std::string& trigger_id,
+      const GURL& hats_survey_url,
+      const base::TimeDelta& timeout,
+      base::OnceClosure success_callback,
+      base::OnceClosure failure_callback,
+      const std::map<std::string, bool>& product_specific_data)
       : HatsNextWebDialog(browser,
                           trigger_id,
                           hats_survey_url,
                           timeout,
                           std::move(success_callback),
-                          std::move(failure_callback)) {}
+                          std::move(failure_callback),
+                          product_specific_data) {}
 
   MOCK_METHOD0(ShowWidget, void());
   MOCK_METHOD0(CloseWidget, void());
@@ -120,7 +134,7 @@
       browser(), kHatsNextSurveyTriggerIDTesting,
       embedded_test_server()->GetURL("/hats/hats_next_mock.html"),
       base::TimeDelta::FromSeconds(100), GetSuccessClosure(),
-      GetFailureClosure());
+      GetFailureClosure(), kHatsNextTestSurveyProductSpecificData);
 
   // Check that no record of a survey being shown is present.
   const base::DictionaryValue* pref_data =
@@ -169,7 +183,7 @@
       browser(), "close_for_testing",
       embedded_test_server()->GetURL("/hats/hats_next_mock.html"),
       base::TimeDelta::FromSeconds(100), GetSuccessClosure(),
-      GetFailureClosure());
+      GetFailureClosure(), {});
 
   // The hats_next_mock.html will provide a state update to the dialog to
   // indicate that the survey window should be closed.
@@ -195,7 +209,7 @@
       browser(), kHatsNextSurveyTriggerIDTesting,
       embedded_test_server()->GetURL("/hats/hats_next_mock.html"),
       base::TimeDelta::FromSeconds(100), GetSuccessClosure(),
-      GetFailureClosure());
+      GetFailureClosure(), kHatsNextTestSurveyProductSpecificData);
   dialog->WaitForClose();
 
   EXPECT_EQ(1, success_count);
@@ -218,7 +232,7 @@
       browser(), "invalid_test",
       embedded_test_server()->GetURL("/hats/non_existent.html"),
       base::TimeDelta::FromMilliseconds(1), GetSuccessClosure(),
-      GetFailureClosure());
+      GetFailureClosure(), {});
 
   dialog->WaitForClose();
 
@@ -239,7 +253,7 @@
       browser(), "invalid_url_fragment_for_testing",
       embedded_test_server()->GetURL("/hats/hats_next_mock.html"),
       base::TimeDelta::FromSeconds(100), GetSuccessClosure(),
-      GetFailureClosure());
+      GetFailureClosure(), {});
 
   dialog->WaitForClose();
   EXPECT_EQ(0, success_count);
@@ -252,7 +266,8 @@
   auto* dialog = new MockHatsNextWebDialog(
       browser(), "open_new_web_contents_for_testing",
       embedded_test_server()->GetURL("/hats/hats_next_mock.html"),
-      base::TimeDelta::FromSeconds(100), base::DoNothing(), base::DoNothing());
+      base::TimeDelta::FromSeconds(100), base::DoNothing(), base::DoNothing(),
+      {});
 
   // The mock hats dialog will push a close state after it has attempted to
   // open another web contents.
@@ -277,7 +292,8 @@
   auto* dialog = new MockHatsNextWebDialog(
       devtools_browser, "open_new_web_contents_for_testing",
       embedded_test_server()->GetURL("/hats/hats_next_mock.html"),
-      base::TimeDelta::FromSeconds(100), base::DoNothing(), base::DoNothing());
+      base::TimeDelta::FromSeconds(100), base::DoNothing(), base::DoNothing(),
+      {});
 
   // The mock hats dialog will push a close state after it has attempted to
   // open another web contents.
@@ -297,7 +313,8 @@
   auto* dialog = new MockHatsNextWebDialog(
       browser(), "resize_for_testing",
       embedded_test_server()->GetURL("/hats/hats_next_mock.html"),
-      base::TimeDelta::FromSeconds(100), base::DoNothing(), base::DoNothing());
+      base::TimeDelta::FromSeconds(100), base::DoNothing(), base::DoNothing(),
+      {});
 
   // Check that the dialog reports a preferred size the same as the size defined
   // in hats_next_mock.html.
@@ -321,7 +338,8 @@
   auto* dialog = new MockHatsNextWebDialog(
       browser(), "resize_to_large_for_testing",
       embedded_test_server()->GetURL("/hats/hats_next_mock.html"),
-      base::TimeDelta::FromSeconds(100), base::DoNothing(), base::DoNothing());
+      base::TimeDelta::FromSeconds(100), base::DoNothing(), base::DoNothing(),
+      {});
 
   // Check that the maximum size of the dialog is bounded appropriately by the
   // dialogs maximum size. Depending on renderer warm-up, an initial empty size
@@ -345,7 +363,8 @@
   auto* dialog = new MockHatsNextWebDialog(
       browser(), kHatsNextSurveyTriggerIDTesting,
       embedded_test_server()->GetURL("/hats/hats_next_mock.html"),
-      base::TimeDelta::FromSeconds(100), base::DoNothing(), base::DoNothing());
+      base::TimeDelta::FromSeconds(100), GetSuccessClosure(),
+      GetFailureClosure(), kHatsNextTestSurveyProductSpecificData);
 
   // Allow the dialog to open before checking the zoom level of the contents.
   base::RunLoop run_loop;
diff --git a/chrome/browser/ui/views/hats/hats_next_web_dialog.cc b/chrome/browser/ui/views/hats/hats_next_web_dialog.cc
index de599d1..0285354 100644
--- a/chrome/browser/ui/views/hats/hats_next_web_dialog.cc
+++ b/chrome/browser/ui/views/hats/hats_next_web_dialog.cc
@@ -6,6 +6,8 @@
 
 #include "chrome/browser/ui/browser_dialogs.h"
 
+#include "base/base64url.h"
+#include "base/json/json_writer.h"
 #include "base/metrics/histogram_functions.h"
 #include "base/util/values/values_util.h"
 #include "chrome/browser/profiles/profile.h"
@@ -118,17 +120,20 @@
 BEGIN_METADATA(HatsNextWebDialog, HatsWebView, views::WebView)
 END_METADATA
 
-HatsNextWebDialog::HatsNextWebDialog(Browser* browser,
-                                     const std::string& trigger_id,
-                                     base::OnceClosure success_callback,
-                                     base::OnceClosure failure_callback)
+HatsNextWebDialog::HatsNextWebDialog(
+    Browser* browser,
+    const std::string& trigger_id,
+    base::OnceClosure success_callback,
+    base::OnceClosure failure_callback,
+    const std::map<std::string, bool>& product_specific_data)
     : HatsNextWebDialog(
           browser,
           trigger_id,
           GURL("https://storage.googleapis.com/chrome_hats_staging/index.html"),
           base::TimeDelta::FromSeconds(10),
           std::move(success_callback),
-          std::move(failure_callback)) {}
+          std::move(failure_callback),
+          product_specific_data) {}
 
 gfx::Size HatsNextWebDialog::CalculatePreferredSize() const {
   gfx::Size preferred_size = views::View::CalculatePreferredSize();
@@ -142,12 +147,14 @@
   otr_profile_ = nullptr;
 }
 
-HatsNextWebDialog::HatsNextWebDialog(Browser* browser,
-                                     const std::string& trigger_id,
-                                     const GURL& hats_survey_url,
-                                     const base::TimeDelta& timeout,
-                                     base::OnceClosure success_callback,
-                                     base::OnceClosure failure_callback)
+HatsNextWebDialog::HatsNextWebDialog(
+    Browser* browser,
+    const std::string& trigger_id,
+    const GURL& hats_survey_url,
+    const base::TimeDelta& timeout,
+    base::OnceClosure success_callback,
+    base::OnceClosure failure_callback,
+    const std::map<std::string, bool>& product_specific_data)
     : BubbleDialogDelegateView(
           browser->is_type_devtools()
               ? static_cast<views::View*>(
@@ -164,7 +171,8 @@
       hats_survey_url_(hats_survey_url),
       timeout_(timeout),
       success_callback_(std::move(success_callback)),
-      failure_callback_(std::move(failure_callback)) {
+      failure_callback_(std::move(failure_callback)),
+      product_specific_data_(product_specific_data) {
   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
   otr_profile_->AddObserver(this);
   set_close_on_deactivate(false);
@@ -209,6 +217,19 @@
 GURL HatsNextWebDialog::GetParameterizedHatsURL() const {
   GURL param_url =
       net::AppendQueryParameter(hats_survey_url_, "trigger_id", trigger_id_);
+
+  // Append any Product Specific Data to the query. This will be interpreted
+  // by the wrapper website and provided to the HaTS backend service.
+  base::DictionaryValue dict;
+  for (const auto& field_value : product_specific_data_)
+    dict.SetStringKey(field_value.first, field_value.second ? "true" : "false");
+
+  std::string product_specific_data_json;
+  base::JSONWriter::Write(dict, &product_specific_data_json);
+
+  param_url = net::AppendQueryParameter(param_url, "product_specific_data",
+                                        product_specific_data_json);
+
   if (base::FeatureList::IsEnabled(
           features::kHappinessTrackingSurveysForDesktopDemo)) {
     param_url = net::AppendQueryParameter(param_url, "enable_testing", "true");
diff --git a/chrome/browser/ui/views/hats/hats_next_web_dialog.h b/chrome/browser/ui/views/hats/hats_next_web_dialog.h
index b4d97958b..0b3aaa1 100644
--- a/chrome/browser/ui/views/hats/hats_next_web_dialog.h
+++ b/chrome/browser/ui/views/hats/hats_next_web_dialog.h
@@ -34,7 +34,8 @@
   HatsNextWebDialog(Browser* browser,
                     const std::string& trigger_id,
                     base::OnceClosure success_callback,
-                    base::OnceClosure failure_callback);
+                    base::OnceClosure failure_callback,
+                    const std::map<std::string, bool>& product_specific_data);
   ~HatsNextWebDialog() override;
   HatsNextWebDialog(const HatsNextWebDialog&) = delete;
   HatsNextWebDialog& operator=(const HatsNextWebDialog&) = delete;
@@ -57,7 +58,8 @@
                     const GURL& hats_survey_url_,
                     const base::TimeDelta& timeout,
                     base::OnceClosure success_callback,
-                    base::OnceClosure failure_callback);
+                    base::OnceClosure failure_callback,
+                    const std::map<std::string, bool>& product_specific_data);
 
   class HatsWebView;
 
@@ -125,6 +127,8 @@
   base::OnceClosure success_callback_;
   base::OnceClosure failure_callback_;
 
+  std::map<std::string, bool> product_specific_data_;
+
   base::WeakPtrFactory<HatsNextWebDialog> weak_factory_{this};
 };
 
diff --git a/chrome/browser/ui/views/profiles/profile_picker_interactive_uitest.cc b/chrome/browser/ui/views/profiles/profile_picker_interactive_uitest.cc
index 1103627..19914106 100644
--- a/chrome/browser/ui/views/profiles/profile_picker_interactive_uitest.cc
+++ b/chrome/browser/ui/views/profiles/profile_picker_interactive_uitest.cc
@@ -64,6 +64,12 @@
     bool control = false;
     bool shift = false;
     bool command = true;
+    // Mac needs the widget to get focused (once again) for
+    // SendKeyPressToWindowSync to work. A test-only particularity, pressing the
+    // keybinding manually right in the run of the test actually replaces the
+    // need of this call.
+    ASSERT_TRUE(
+        ui_test_utils::ShowAndFocusNativeWindow(widget()->GetNativeWindow()));
 #else
     // Use Ctrl-Shift-W on other platforms.
     bool control = true;
@@ -82,6 +88,12 @@
     bool alt = false;
     bool command = true;
     ui::KeyboardCode key = ui::VKEY_OEM_4;
+    // Mac needs the widget to get focused (once again) for
+    // SendKeyPressToWindowSync to work. A test-only particularity, pressing the
+    // keybinding manually right in the run of the test actually replaces the
+    // need of this call.
+    ASSERT_TRUE(
+        ui_test_utils::ShowAndFocusNativeWindow(widget()->GetNativeWindow()));
 #else
     // Use Ctrl-left on other platforms.
     bool alt = true;
diff --git a/chrome/browser/ui/views/profiles/profile_picker_view.cc b/chrome/browser/ui/views/profiles/profile_picker_view.cc
index b6f23db..0ec88ff 100644
--- a/chrome/browser/ui/views/profiles/profile_picker_view.cc
+++ b/chrome/browser/ui/views/profiles/profile_picker_view.cc
@@ -254,6 +254,14 @@
 }
 
 // static
+base::FilePath ProfilePicker::GetSwitchProfilePath() {
+  if (g_profile_picker_view) {
+    return g_profile_picker_view->GetSwitchProfilePath();
+  }
+  return base::FilePath();
+}
+
+// static
 void ProfilePicker::SwitchToSignIn(
     SkColor profile_color,
     base::OnceCallback<void(bool)> switch_finished_callback) {
@@ -278,6 +286,13 @@
 }
 
 // static
+void ProfilePicker::SwitchToProfileSwitch(const base::FilePath& profile_path) {
+  if (g_profile_picker_view) {
+    g_profile_picker_view->SwitchToProfileSwitch(profile_path);
+  }
+}
+
+// static
 void ProfilePicker::ShowDialog(content::BrowserContext* browser_context,
                                const GURL& url,
                                const base::FilePath& profile_path) {
@@ -531,9 +546,8 @@
   DeleteDelegate();
 }
 
-void ProfilePickerView::OnSystemProfileCreated(
-    Profile* system_profile,
-    Profile::CreateStatus status) {
+void ProfilePickerView::OnSystemProfileCreated(Profile* system_profile,
+                                               Profile::CreateStatus status) {
   DCHECK_NE(status, Profile::CREATE_STATUS_LOCAL_FAIL);
   if (status != Profile::CREATE_STATUS_INITIALIZED)
     return;
@@ -612,7 +626,6 @@
 
 void ProfilePickerView::CancelSignIn() {
   DCHECK(sign_in_);
-  DCHECK_EQ(web_view_->GetWebContents(), sign_in_->contents.get());
 
   g_browser_process->profile_manager()->ScheduleProfileForDeletion(
       sign_in_->profile->GetPath(), base::DoNothing());
@@ -734,6 +747,18 @@
       sign_in_->profile_color);
 }
 
+void ProfilePickerView::SwitchToProfileSwitch(
+    const base::FilePath& profile_path) {
+  DCHECK(sign_in_);
+  sign_in_->is_aborted = true;
+
+  switch_profile_path_ = profile_path;
+  ShowScreen(system_profile_contents_.get(),
+             GURL(chrome::kChromeUIProfilePickerUrl).Resolve("profile-switch"),
+             /*show_toolbar=*/false,
+             /*enable_navigating_back=*/false);
+}
+
 void ProfilePickerView::WindowClosing() {
   // Now that the window is closed, we can allow a new one to be opened.
   // (WindowClosing comes in asynchronously from the call to Close() and we
@@ -916,7 +941,7 @@
                                    bool show_toolbar,
                                    bool enable_navigating_back) {
   web_view_->SetWebContents(contents);
-  web_view_->RequestFocus();
+  contents->Focus();
 
   // Change visibility of the toolbar after swapping wc in `web_view_` to make
   // it easier for tests to detect changing of the screen.
@@ -1057,6 +1082,10 @@
 void ProfilePickerView::FinishSignedInCreationFlow(
     BrowserOpenedCallback callback,
     bool enterprise_sync_consent_needed) {
+  DCHECK(sign_in_);
+  // Sign-in flow is aborted, do nothing.
+  if (sign_in_->is_aborted)
+    return;
   // This can get called first time from a special case handling (such as the
   // Settings link) and than second time when the consent flow finishes. We need
   // to make sure only the first call gets handled.
@@ -1220,6 +1249,10 @@
   return on_select_profile_target_url_;
 }
 
+base::FilePath ProfilePickerView::GetSwitchProfilePath() const {
+  return switch_profile_path_;
+}
+
 BEGIN_METADATA(ProfilePickerView, views::WidgetDelegateView)
 ADD_READONLY_PROPERTY_METADATA(bool, SigningIn)
 ADD_READONLY_PROPERTY_METADATA(base::FilePath, ForceSigninProfilePath)
diff --git a/chrome/browser/ui/views/profiles/profile_picker_view.h b/chrome/browser/ui/views/profiles/profile_picker_view.h
index 9541ec5..825bc25f 100644
--- a/chrome/browser/ui/views/profiles/profile_picker_view.h
+++ b/chrome/browser/ui/views/profiles/profile_picker_view.h
@@ -87,6 +87,10 @@
     // for GAIA sign-in (that uses the ThemeProvider of the current profile).
     SkColor profile_color;
 
+    // Controls whether `profile` browser window should be shown at the end of
+    // the sign-in flow.
+    bool is_aborted = false;
+
     base::string16 name_for_signed_in_profile;
     base::OnceClosure on_profile_name_available;
 
@@ -123,6 +127,8 @@
       Profile::CreateStatus status);
   // Switches the layout to the sync confirmation screen.
   void SwitchToSyncConfirmation();
+  // Switches the layout to the profile switch screen.
+  void SwitchToProfileSwitch(const base::FilePath& profile_path);
 
   // views::WidgetDelegate:
   void WindowClosing() override;
@@ -225,10 +231,14 @@
   // signin.
   base::FilePath GetForceSigninProfilePath() const;
 
-  // Getter of the target page  url. If not empty and is valid, it opens on
+  // Getter of the target page url. If not empty and is valid, it opens on
   // profile selection instead of the new tab page.
   GURL GetOnSelectProfileTargetUrl() const;
 
+  // Getter of the path of profile which is displayed on the profile switch
+  // screen.
+  base::FilePath GetSwitchProfilePath() const;
+
   ScopedKeepAlive keep_alive_;
   ProfilePicker::EntryPoint entry_point_ =
       ProfilePicker::EntryPoint::kOnStartup;
@@ -261,10 +271,13 @@
   // Hosts dialog displayed when a locked profile is selected in ProfilePicker.
   ProfilePickerForceSigninDialogHost dialog_host_;
 
-  // A target page  url that opens on profile selection instead of the new tab
+  // A target page url that opens on profile selection instead of the new tab
   // page.
   GURL on_select_profile_target_url_;
 
+  // Path to a profile that should be displayed on the profile switch screen.
+  base::FilePath switch_profile_path_;
+
   base::WeakPtrFactory<ProfilePickerView> weak_ptr_factory_{this};
 };
 
diff --git a/chrome/browser/ui/views/profiles/profile_picker_view_browsertest.cc b/chrome/browser/ui/views/profiles/profile_picker_view_browsertest.cc
index 85967f1..5a6fc99e 100644
--- a/chrome/browser/ui/views/profiles/profile_picker_view_browsertest.cc
+++ b/chrome/browser/ui/views/profiles/profile_picker_view_browsertest.cc
@@ -9,6 +9,7 @@
 #include "base/test/bind.h"
 #include "base/test/mock_callback.h"
 #include "base/time/time.h"
+#include "base/util/values/values_util.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/policy/cloud/user_policy_signin_service.h"
 #include "chrome/browser/policy/cloud/user_policy_signin_service_factory.h"
@@ -29,6 +30,8 @@
 #include "chrome/browser/ui/views/profiles/profile_picker_test_base.h"
 #include "chrome/browser/ui/webui/signin/login_ui_service.h"
 #include "chrome/browser/ui/webui/signin/login_ui_service_factory.h"
+#include "chrome/browser/ui/webui/signin/profile_picker_handler.h"
+#include "chrome/browser/ui/webui/signin/profile_picker_ui.h"
 #include "chrome/common/pref_names.h"
 #include "chrome/test/base/in_process_browser_test.h"
 #include "components/keyed_service/content/browser_context_dependency_manager.h"
@@ -210,6 +213,8 @@
   base::RunLoop* run_loop_;
 };
 
+}  // namespace
+
 class ProfilePickerCreationFlowBrowserTest : public ProfilePickerTestBase {
  public:
   ProfilePickerCreationFlowBrowserTest() {
@@ -459,18 +464,18 @@
                     kURL);
 }
 
-// TODO(crbug.com/1144065): Flaky on multiple platforms.
 IN_PROC_BROWSER_TEST_F(ProfilePickerCreationFlowBrowserTest,
-                       DISABLED_CreateSignedInProfileSigninAlreadyExists) {
+                       CreateSignedInProfileSigninAlreadyExists_ConfirmSwitch) {
   ASSERT_EQ(1u, BrowserList::GetInstance()->size());
 
   // Create a pre-existing profile syncing with the same account as the profile
   // being created.
   ProfileManager* profile_manager = g_browser_process->profile_manager();
-  base::FilePath new_path = profile_manager->GenerateNextProfileDirectoryPath();
+  base::FilePath other_path =
+      profile_manager->GenerateNextProfileDirectoryPath();
   base::RunLoop run_loop;
   profile_manager->CreateProfileAsync(
-      new_path,
+      other_path,
       base::BindLambdaForTesting(
           [&run_loop](Profile* profile, Profile::CreateStatus status) {
             if (status == Profile::CREATE_STATUS_INITIALIZED) {
@@ -482,7 +487,7 @@
   ProfileAttributesStorage& storage =
       profile_manager->GetProfileAttributesStorage();
   ProfileAttributesEntry* other_entry =
-      storage.GetProfileAttributesWithPath(new_path);
+      storage.GetProfileAttributesWithPath(other_path);
   ASSERT_NE(other_entry, nullptr);
   // Fake sync is enabled in this profile with Joe's account.
   other_entry->SetAuthInfo(std::string(),
@@ -502,23 +507,107 @@
   AccountInfo account_info = FillAccountInfo(core_account_info, "Joe");
   signin::UpdateAccountInfoForAccount(identity_manager, account_info);
 
-  // Instead of sync confirmation, a browser is displayed (with a login error).
+  // The profile switch screen should be displayed.
+  WaitForLayoutWithoutToolbar();
+  WaitForFirstPaint(web_contents(),
+                    GURL("chrome://profile-picker/profile-switch"));
+  EXPECT_EQ(ProfilePicker::GetSwitchProfilePath(), other_path);
+
+  // Simulate clicking on the confirm switch button.
+  ProfilePickerHandler* handler = web_contents()
+                                      ->GetWebUI()
+                                      ->GetController()
+                                      ->GetAs<ProfilePickerUI>()
+                                      ->GetProfilePickerHandlerForTesting();
+  base::ListValue args;
+  args.Append(base::Value::ToUniquePtrValue(util::FilePathToValue(other_path)));
+  handler->HandleConfirmProfileSwitch(&args);
+
+  // Browser for a pre-existing profile is displayed.
   Browser* new_browser = BrowserAddedWaiter(2u).Wait();
   WaitForFirstPaint(new_browser->tab_strip_model()->GetActiveWebContents(),
                     GURL("chrome://newtab/"));
+  EXPECT_EQ(new_browser->profile()->GetPath(), other_path);
 
   // Check expectations when the profile creation flow is done.
   WaitForPickerClosed();
 
+  // Profile creation shouldn't be finished.
   ProfileAttributesEntry* entry =
       storage.GetProfileAttributesWithPath(profile_being_created->GetPath());
-  ASSERT_NE(entry, nullptr);
-  EXPECT_FALSE(entry->IsEphemeral());
-  EXPECT_FALSE(entry->IsAuthenticated());
-  EXPECT_EQ(entry->GetLocalProfileName(), base::UTF8ToUTF16("Joe"));
-  EXPECT_EQ(ThemeServiceFactory::GetForProfile(profile_being_created)
-                ->GetAutogeneratedThemeColor(),
-            kProfileColor);
+  EXPECT_NE(entry, nullptr);
+  EXPECT_TRUE(entry->IsEphemeral());
+  EXPECT_TRUE(entry->IsOmitted());
+}
+
+IN_PROC_BROWSER_TEST_F(ProfilePickerCreationFlowBrowserTest,
+                       CreateSignedInProfileSigninAlreadyExists_CancelSwitch) {
+  ASSERT_EQ(1u, BrowserList::GetInstance()->size());
+
+  // Create a pre-existing profile syncing with the same account as the profile
+  // being created.
+  ProfileManager* profile_manager = g_browser_process->profile_manager();
+  base::FilePath other_path =
+      profile_manager->GenerateNextProfileDirectoryPath();
+  base::RunLoop run_loop;
+  profile_manager->CreateProfileAsync(
+      other_path,
+      base::BindLambdaForTesting(
+          [&run_loop](Profile* profile, Profile::CreateStatus status) {
+            if (status == Profile::CREATE_STATUS_INITIALIZED) {
+              run_loop.Quit();
+            }
+          }),
+      base::string16(), std::string());
+  run_loop.Run();
+  ProfileAttributesStorage& storage =
+      profile_manager->GetProfileAttributesStorage();
+  ProfileAttributesEntry* other_entry =
+      storage.GetProfileAttributesWithPath(other_path);
+  ASSERT_NE(other_entry, nullptr);
+  // Fake sync is enabled in this profile with Joe's account.
+  other_entry->SetAuthInfo(std::string(),
+                           base::UTF8ToUTF16("joe.consumer@gmail.com"),
+                           /*is_consented_primary_account=*/true);
+
+  Profile* profile_being_created = StartSigninFlow();
+  base::FilePath profile_being_created_path = profile_being_created->GetPath();
+
+  // Add an account - simulate a successful Gaia sign-in.
+  signin::IdentityManager* identity_manager =
+      IdentityManagerFactory::GetForProfile(profile_being_created);
+  CoreAccountInfo core_account_info =
+      signin::MakeAccountAvailable(identity_manager, "joe.consumer@gmail.com");
+  ASSERT_TRUE(identity_manager->HasAccountWithRefreshToken(
+      core_account_info.account_id));
+
+  AccountInfo account_info = FillAccountInfo(core_account_info, "Joe");
+  signin::UpdateAccountInfoForAccount(identity_manager, account_info);
+
+  // The profile switch screen should be displayed.
+  WaitForLayoutWithoutToolbar();
+  WaitForFirstPaint(web_contents(),
+                    GURL("chrome://profile-picker/profile-switch"));
+  EXPECT_EQ(ProfilePicker::GetSwitchProfilePath(), other_path);
+
+  // Simulate clicking on the cancel button.
+  ProfilePickerHandler* handler = web_contents()
+                                      ->GetWebUI()
+                                      ->GetController()
+                                      ->GetAs<ProfilePickerUI>()
+                                      ->GetProfilePickerHandlerForTesting();
+  base::ListValue args;
+  handler->HandleCancelProfileSwitch(&args);
+
+  // Check expectations when the profile creation flow is done.
+  WaitForPickerClosed();
+
+  // Only one browser should be displayed.
+  EXPECT_EQ(BrowserList::GetInstance()->size(), 1u);
+
+  // The sign-in profile should be marked for deletion.
+  ProfileManager::IsProfileDirectoryMarkedForDeletion(
+      profile_being_created_path);
 }
 
 IN_PROC_BROWSER_TEST_F(ProfilePickerCreationFlowBrowserTest,
@@ -976,5 +1065,3 @@
     testing::Values(ForceEphemeralProfilesPolicy::kUnset,
                     ForceEphemeralProfilesPolicy::kDisabled,
                     ForceEphemeralProfilesPolicy::kEnabled));
-
-}  // namespace
diff --git a/chrome/browser/ui/views/profiles/profile_picker_view_sync_delegate.cc b/chrome/browser/ui/views/profiles/profile_picker_view_sync_delegate.cc
index 713e85b..40e92a9 100644
--- a/chrome/browser/ui/views/profiles/profile_picker_view_sync_delegate.cc
+++ b/chrome/browser/ui/views/profiles/profile_picker_view_sync_delegate.cc
@@ -91,6 +91,15 @@
   ProfileMetrics::LogProfileAddSignInFlowOutcome(
       ProfileMetrics::ProfileAddSignInFlowOutcome::kLoginError);
 
+  // Show the profile switch confirmation screen inside of the profile picker if
+  // the user cannot sign in because the account already used by another
+  // profile.
+  if (error.type() ==
+      SigninUIError::Type::kAccountAlreadyUsedByAnotherProfile) {
+    ProfilePicker::SwitchToProfileSwitch(error.another_profile_path());
+    return;
+  }
+
   // Open the browser and when it's done, show the login error.
   // TODO(crbug.com/1126913): In some cases, the current behavior is not ideal
   // because it is not designed with profile creation in mind. Concretely, for
diff --git a/chrome/browser/ui/webui/DEPS b/chrome/browser/ui/webui/DEPS
index 424b070..dbc34f2 100644
--- a/chrome/browser/ui/webui/DEPS
+++ b/chrome/browser/ui/webui/DEPS
@@ -13,3 +13,9 @@
   "+third_party/brotli",      # For compressed resources.
   "+third_party/zlib/zlib.h", # For compression level constants.
 ]
+
+specific_include_rules = {
+  "inspect_ui\.cc": [
+    "+chrome/browser/ui/views/chrome_browser_main_extra_parts_views.h",
+  ],
+}
diff --git a/chrome/browser/ui/webui/inspect_ui.cc b/chrome/browser/ui/webui/inspect_ui.cc
index 4f6ab10..469853c 100644
--- a/chrome/browser/ui/webui/inspect_ui.cc
+++ b/chrome/browser/ui/webui/inspect_ui.cc
@@ -4,23 +4,29 @@
 
 #include "chrome/browser/ui/webui/inspect_ui.h"
 
+#include <memory>
 #include <utility>
 
 #include "base/bind.h"
+#include "base/callback_forward.h"
 #include "base/macros.h"
+#include "base/memory/weak_ptr.h"
 #include "base/metrics/user_metrics.h"
+#include "base/values.h"
 #include "chrome/browser/devtools/devtools_targets_ui.h"
 #include "chrome/browser/devtools/devtools_ui_bindings.h"
 #include "chrome/browser/devtools/devtools_window.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/ui/browser_navigator_params.h"
 #include "chrome/browser/ui/singleton_tabs.h"
+#include "chrome/browser/ui/views/chrome_browser_main_extra_parts_views.h"
 #include "chrome/browser/ui/webui/theme_source.h"
 #include "chrome/common/pref_names.h"
 #include "chrome/common/url_constants.h"
 #include "chrome/grit/browser_resources.h"
 #include "components/prefs/pref_service.h"
 #include "components/ui_devtools/devtools_server.h"
+#include "components/ui_devtools/switches.h"
 #include "content/public/browser/devtools_agent_host.h"
 #include "content/public/browser/navigation_entry.h"
 #include "content/public/browser/navigation_handle.h"
@@ -29,6 +35,7 @@
 #include "content/public/browser/web_ui.h"
 #include "content/public/browser/web_ui_data_source.h"
 #include "content/public/browser/web_ui_message_handler.h"
+#include "ui/base/ui_base_features.h"
 
 using content::DevToolsAgentHost;
 using content::WebContents;
@@ -39,7 +46,6 @@
 const char kInspectUiInitUICommand[] = "init-ui";
 const char kInspectUiInspectCommand[] = "inspect";
 const char kInspectUiInspectFallbackCommand[] = "inspect-fallback";
-const char kInspectUiInspectAdditionalCommand[] = "inspect-additional";
 const char kInspectUiActivateCommand[] = "activate";
 const char kInspectUiCloseCommand[] = "close";
 const char kInspectUiReloadCommand[] = "reload";
@@ -58,13 +64,14 @@
     "set-discover-tcp-targets-enabled";
 const char kInspectUiTCPDiscoveryConfigCommand[] = "set-tcp-discovery-config";
 const char kInspectUiOpenNodeFrontendCommand[] = "open-node-frontend";
+const char kInspectUiLaunchUIDevToolsCommand[] = "launch-ui-devtools";
 
 const char kInspectUiPortForwardingDefaultPort[] = "8080";
 const char kInspectUiPortForwardingDefaultLocation[] = "localhost:8080";
 
 const char kInspectUiNameField[] = "name";
 const char kInspectUiUrlField[] = "url";
-const char kInspectUiIsAdditionalField[] = "isAdditional";
+const char kInspectUiIsNativeField[] = "isNative";
 
 base::Value GetUiDevToolsTargets() {
   base::Value targets(base::Value::Type::LIST);
@@ -73,19 +80,95 @@
     base::Value target_data(base::Value::Type::DICTIONARY);
     target_data.SetStringKey(kInspectUiNameField, client_pair.first);
     target_data.SetStringKey(kInspectUiUrlField, client_pair.second);
-    target_data.SetBoolKey(kInspectUiIsAdditionalField, true);
+    target_data.SetBoolKey(kInspectUiIsNativeField, true);
     targets.Append(std::move(target_data));
   }
   return targets;
 }
 
+// DevToolsFrontEndObserver ----------------------------------------
+
+class DevToolsFrontEndObserver : public content::WebContentsObserver {
+ public:
+  DevToolsFrontEndObserver(WebContents* web_contents, const GURL& url);
+  DevToolsFrontEndObserver(const DevToolsFrontEndObserver&) = delete;
+  DevToolsFrontEndObserver& operator=(const DevToolsFrontEndObserver&) = delete;
+  ~DevToolsFrontEndObserver() override = default;
+
+  void SetOnFrontEndFinished(base::OnceClosure callback);
+
+ protected:
+  // contents::WebContentsObserver
+  void WebContentsDestroyed() override;
+  void DidFinishNavigation(
+      content::NavigationHandle* navigation_handle) override;
+
+ private:
+  GURL url_;
+  // Callback function executed when the front end is finished.
+  base::OnceClosure on_front_end_finished_;
+};
+
+DevToolsFrontEndObserver::DevToolsFrontEndObserver(WebContents* web_contents,
+                                                   const GURL& url)
+    : WebContentsObserver(web_contents), url_(url) {}
+
+void DevToolsFrontEndObserver::SetOnFrontEndFinished(
+    base::OnceClosure callback) {
+  on_front_end_finished_ = std::move(callback);
+}
+
+void DevToolsFrontEndObserver::WebContentsDestroyed() {
+  if (on_front_end_finished_)
+    std::move(on_front_end_finished_).Run();
+  delete this;
+}
+
+void DevToolsFrontEndObserver::DidFinishNavigation(
+    content::NavigationHandle* navigation_handle) {
+  if (!navigation_handle->IsInMainFrame() || !navigation_handle->HasCommitted())
+    return;
+
+  if (url_ != navigation_handle->GetURL()) {
+    if (on_front_end_finished_)
+      std::move(on_front_end_finished_).Run();
+    delete this;
+  }
+}
+
+// DevToolsUIBindingsEnabler ----------------------------------------
+
+class DevToolsUIBindingsEnabler : public DevToolsFrontEndObserver {
+ public:
+  DevToolsUIBindingsEnabler(WebContents* web_contents, const GURL& url);
+  DevToolsUIBindingsEnabler(const DevToolsUIBindingsEnabler&) = delete;
+  DevToolsUIBindingsEnabler& operator=(const DevToolsUIBindingsEnabler&) =
+      delete;
+  ~DevToolsUIBindingsEnabler() override = default;
+
+  DevToolsUIBindings* GetBindings();
+
+ private:
+  DevToolsUIBindings bindings_;
+};
+
+DevToolsUIBindingsEnabler::DevToolsUIBindingsEnabler(WebContents* web_contents,
+                                                     const GURL& url)
+    : DevToolsFrontEndObserver(web_contents, url), bindings_(web_contents) {}
+
+DevToolsUIBindings* DevToolsUIBindingsEnabler::GetBindings() {
+  return &bindings_;
+}
+
 // InspectMessageHandler --------------------------------------------
 
 class InspectMessageHandler : public WebUIMessageHandler {
  public:
   explicit InspectMessageHandler(InspectUI* inspect_ui)
       : inspect_ui_(inspect_ui) {}
-  ~InspectMessageHandler() override {}
+  InspectMessageHandler(const InspectMessageHandler&) = delete;
+  InspectMessageHandler& operator=(const InspectMessageHandler&) = delete;
+  ~InspectMessageHandler() override = default;
 
  private:
   // WebUIMessageHandler implementation.
@@ -94,7 +177,6 @@
   void HandleInitUICommand(const base::ListValue* args);
   void HandleInspectCommand(const base::ListValue* args);
   void HandleInspectFallbackCommand(const base::ListValue* args);
-  void HandleInspectAdditionalCommand(const base::ListValue* args);
   void HandleActivateCommand(const base::ListValue* args);
   void HandleCloseCommand(const base::ListValue* args);
   void HandleReloadCommand(const base::ListValue* args);
@@ -106,10 +188,14 @@
   void HandlePortForwardingConfigCommand(const base::ListValue* args);
   void HandleTCPDiscoveryConfigCommand(const base::ListValue* args);
   void HandleOpenNodeFrontendCommand(const base::ListValue* args);
+  void HandleLaunchUIDevToolsCommand(const base::ListValue* args);
+
+  void CreateNativeUIInspectionSession(const std::string& url);
+  void OnFrontEndFinished();
 
   InspectUI* const inspect_ui_;
 
-  DISALLOW_COPY_AND_ASSIGN(InspectMessageHandler);
+  base::WeakPtrFactory<InspectMessageHandler> weak_factory_{this};
 };
 
 void InspectMessageHandler::RegisterMessages() {
@@ -126,11 +212,6 @@
       base::BindRepeating(&InspectMessageHandler::HandleInspectFallbackCommand,
                           base::Unretained(this)));
   web_ui()->RegisterMessageCallback(
-      kInspectUiInspectAdditionalCommand,
-      base::BindRepeating(
-          &InspectMessageHandler::HandleInspectAdditionalCommand,
-          base::Unretained(this)));
-  web_ui()->RegisterMessageCallback(
       kInspectUiActivateCommand,
       base::BindRepeating(&InspectMessageHandler::HandleActivateCommand,
                           base::Unretained(this)));
@@ -163,6 +244,10 @@
                           base::Unretained(this),
                           &prefs::kDevToolsDiscoverTCPTargetsEnabled[0]));
   web_ui()->RegisterMessageCallback(
+      kInspectUiLaunchUIDevToolsCommand,
+      base::BindRepeating(&InspectMessageHandler::HandleLaunchUIDevToolsCommand,
+                          base::Unretained(this)));
+  web_ui()->RegisterMessageCallback(
       kInspectUiTCPDiscoveryConfigCommand,
       base::BindRepeating(
           &InspectMessageHandler::HandleTCPDiscoveryConfigCommand,
@@ -214,19 +299,6 @@
     inspect_ui_->InspectFallback(source, id);
 }
 
-void InspectMessageHandler::HandleInspectAdditionalCommand(
-    const base::ListValue* args) {
-  std::string url;
-  if (ParseStringArgs(args, &url, nullptr)) {
-    WebContents* inspect_ui = web_ui()->GetWebContents();
-    web_ui()->GetWebContents()->GetDelegate()->OpenURLFromTab(
-        inspect_ui,
-        content::OpenURLParams(GURL(url), content::Referrer(),
-                               WindowOpenDisposition::NEW_FOREGROUND_TAB,
-                               ui::PAGE_TRANSITION_AUTO_TOPLEVEL, false));
-  }
-}
-
 void InspectMessageHandler::HandleActivateCommand(const base::ListValue* args) {
   std::string source;
   std::string id;
@@ -316,51 +388,53 @@
   DevToolsWindow::OpenNodeFrontendWindow(profile);
 }
 
-// DevToolsUIBindingsEnabler ----------------------------------------
+void InspectMessageHandler::HandleLaunchUIDevToolsCommand(
+    const base::ListValue* args) {
+  // Start the UI DevTools server if needed and launch the front-end.
+  if (!ChromeBrowserMainExtraPartsViews::Get()->GetUiDevToolsServerInstance()) {
+    ChromeBrowserMainExtraPartsViews::Get()->CreateUiDevTools();
 
-class DevToolsUIBindingsEnabler
-    : public content::WebContentsObserver {
- public:
-  DevToolsUIBindingsEnabler(WebContents* web_contents,
-                            const GURL& url);
-  ~DevToolsUIBindingsEnabler() override {}
+    // Make the server only lasts for a session.
+    const ui_devtools::UiDevToolsServer* server =
+        ChromeBrowserMainExtraPartsViews::Get()->GetUiDevToolsServerInstance();
+    server->SetOnSessionEnded(base::BindOnce([]() {
+      if (ChromeBrowserMainExtraPartsViews::Get()
+              ->GetUiDevToolsServerInstance())
+        ChromeBrowserMainExtraPartsViews::Get()->DestroyUiDevTools();
+    }));
+  }
+  inspect_ui_->PopulateNativeUITargets(GetUiDevToolsTargets());
 
-  DevToolsUIBindings* GetBindings();
-
- private:
-  // contents::WebContentsObserver overrides.
-  void WebContentsDestroyed() override;
-  void DidFinishNavigation(
-      content::NavigationHandle* navigation_handle) override;
-
-  DevToolsUIBindings bindings_;
-  GURL url_;
-  DISALLOW_COPY_AND_ASSIGN(DevToolsUIBindingsEnabler);
-};
-
-DevToolsUIBindingsEnabler::DevToolsUIBindingsEnabler(
-    WebContents* web_contents,
-    const GURL& url)
-    : WebContentsObserver(web_contents),
-      bindings_(web_contents),
-      url_(url) {
+  std::vector<ui_devtools::UiDevToolsServer::NameUrlPair> pairs =
+      ui_devtools::UiDevToolsServer::GetClientNamesAndUrls();
+  if (!pairs.empty())
+    CreateNativeUIInspectionSession(pairs[0].second);
 }
 
-DevToolsUIBindings* DevToolsUIBindingsEnabler::GetBindings() {
-  return &bindings_;
+void InspectMessageHandler::CreateNativeUIInspectionSession(
+    const std::string& url) {
+  WebContents* inspect_ui = web_ui()->GetWebContents();
+  const GURL gurl(url);
+  content::WebContents* front_end = inspect_ui->GetDelegate()->OpenURLFromTab(
+      inspect_ui,
+      content::OpenURLParams(gurl, content::Referrer(),
+                             WindowOpenDisposition::NEW_FOREGROUND_TAB,
+                             ui::PAGE_TRANSITION_AUTO_TOPLEVEL, false));
+  // When the front-end is started, disable the launch button.
+  inspect_ui_->ShowNativeUILaunchButton(/* enabled = */ false);
+
+  // The observer will delete itself when the front-end finishes.
+  DevToolsFrontEndObserver* front_end_observer =
+      new DevToolsFrontEndObserver(front_end, gurl);
+  front_end_observer->SetOnFrontEndFinished(base::BindOnce(
+      &InspectMessageHandler::OnFrontEndFinished, weak_factory_.GetWeakPtr()));
 }
 
-void DevToolsUIBindingsEnabler::WebContentsDestroyed() {
-  delete this;
-}
-
-void DevToolsUIBindingsEnabler::DidFinishNavigation(
-    content::NavigationHandle* navigation_handle) {
-  if (!navigation_handle->IsInMainFrame() || !navigation_handle->HasCommitted())
-    return;
-
-  if (url_ != navigation_handle->GetURL())
-    delete this;
+void InspectMessageHandler::OnFrontEndFinished() {
+  // Clear the client list and re-enable the launch button when the front-end is
+  // gone.
+  inspect_ui_->PopulateNativeUITargets(base::ListValue());
+  inspect_ui_->ShowNativeUILaunchButton(/* enabled = */ true);
 }
 
 }  // namespace
@@ -507,7 +581,12 @@
   DevToolsTargetsUIHandler::Callback callback =
       base::BindRepeating(&InspectUI::PopulateTargets, base::Unretained(this));
 
-  PopulateAdditionalTargets(GetUiDevToolsTargets());
+  // Show native UI launch button according to the command line or feature flag.
+  if (ui_devtools::UiDevToolsServer::IsUiDevToolsEnabled(
+          ui_devtools::switches::kEnableUiDevTools) ||
+      base::FeatureList::IsEnabled(features::kUIDebugTools)) {
+    ShowNativeUILaunchButton(/* enabled = */ true);
+  }
 
   AddTargetUIHandler(
       DevToolsTargetsUIHandler::CreateForLocal(callback, profile));
@@ -659,8 +738,8 @@
                                          targets);
 }
 
-void InspectUI::PopulateAdditionalTargets(const base::Value& targets) {
-  web_ui()->CallJavascriptFunctionUnsafe("populateAdditionalTargets", targets);
+void InspectUI::PopulateNativeUITargets(const base::Value& targets) {
+  web_ui()->CallJavascriptFunctionUnsafe("populateNativeUITargets", targets);
 }
 
 void InspectUI::PopulatePortStatus(base::Value status) {
@@ -671,3 +750,8 @@
 void InspectUI::ShowIncognitoWarning() {
   web_ui()->CallJavascriptFunctionUnsafe("showIncognitoWarning");
 }
+
+void InspectUI::ShowNativeUILaunchButton(bool enabled) {
+  web_ui()->CallJavascriptFunctionUnsafe("showNativeUILaunchButton",
+                                         base::Value(enabled));
+}
diff --git a/chrome/browser/ui/webui/inspect_ui.h b/chrome/browser/ui/webui/inspect_ui.h
index 2537c92..0a89ad8e 100644
--- a/chrome/browser/ui/webui/inspect_ui.h
+++ b/chrome/browser/ui/webui/inspect_ui.h
@@ -34,6 +34,8 @@
                   public content::WebContentsObserver {
  public:
   explicit InspectUI(content::WebUI* web_ui);
+  InspectUI(const InspectUI&) = delete;
+  InspectUI& operator=(const InspectUI&) = delete;
   ~InspectUI() override;
 
   void InitUI();
@@ -52,6 +54,9 @@
       const std::string& browser_id,
       const GURL& frontend_url);
 
+  void PopulateNativeUITargets(const base::Value& targets);
+  void ShowNativeUILaunchButton(bool enabled);
+
   static void InspectDevices(Browser* browser);
 
  private:
@@ -84,8 +89,6 @@
   void PopulateTargets(const std::string& source_id,
                        const base::ListValue& targets);
 
-  void PopulateAdditionalTargets(const base::Value& targets);
-
   void PopulatePortStatus(base::Value status);
 
   void ShowIncognitoWarning();
@@ -97,8 +100,6 @@
       target_handlers_;
 
   std::unique_ptr<PortForwardingStatusSerializer> port_status_serializer_;
-
-  DISALLOW_COPY_AND_ASSIGN(InspectUI);
 };
 
 #endif  // CHROME_BROWSER_UI_WEBUI_INSPECT_UI_H_
diff --git a/chrome/browser/ui/webui/net_export_ui.cc b/chrome/browser/ui/webui/net_export_ui.cc
index a233236..cb18396 100644
--- a/chrome/browser/ui/webui/net_export_ui.cc
+++ b/chrome/browser/ui/webui/net_export_ui.cc
@@ -319,7 +319,7 @@
   file_writer_->StartNetLog(
       path, capture_mode_, max_log_file_size_,
       base::CommandLine::ForCurrentProcess()->GetCommandLineString(),
-      chrome::GetChannelName(),
+      chrome::GetChannelName(chrome::WithExtendedStable(true)),
       content::BrowserContext::GetDefaultStoragePartition(
           Profile::FromWebUI(web_ui()))
           ->GetNetworkContext());
diff --git a/chrome/browser/ui/webui/settings/hats_handler_unittest.cc b/chrome/browser/ui/webui/settings/hats_handler_unittest.cc
index dc45994..3d64b2a 100644
--- a/chrome/browser/ui/webui/settings/hats_handler_unittest.cc
+++ b/chrome/browser/ui/webui/settings/hats_handler_unittest.cc
@@ -54,9 +54,9 @@
 };
 
 TEST_F(HatsHandlerTest, HandleTryShowHatsSurvey) {
-  EXPECT_CALL(*mock_hats_service_,
-              LaunchDelayedSurveyForWebContents(
-                  kHatsSurveyTriggerSettingsPrivacy, web_contents(), 20000));
+  EXPECT_CALL(*mock_hats_service_, LaunchDelayedSurveyForWebContents(
+                                       kHatsSurveyTriggerSettingsPrivacy,
+                                       web_contents(), 20000, testing::_));
   base::ListValue args;
   handler()->HandleTryShowHatsSurvey(&args);
   task_environment()->RunUntilIdle();
diff --git a/chrome/browser/ui/webui/settings/settings_ui_browsertest.cc b/chrome/browser/ui/webui/settings/settings_ui_browsertest.cc
index fea44d1..bde9f8e 100644
--- a/chrome/browser/ui/webui/settings/settings_ui_browsertest.cc
+++ b/chrome/browser/ui/webui/settings/settings_ui_browsertest.cc
@@ -54,7 +54,7 @@
       HatsServiceFactory::GetInstance()->SetTestingFactoryAndUse(
           browser()->profile(), base::BindRepeating(&BuildMockHatsService)));
   EXPECT_CALL(*mock_hats_service_, LaunchDelayedSurveyForWebContents(
-                                       kHatsSurveyTriggerSettings, _, _));
+                                       kHatsSurveyTriggerSettings, _, _, _));
   NavigateToURL(browser(), GURL(chrome::kChromeUISettingsURL));
   base::RunLoop().RunUntilIdle();
 }
diff --git a/chrome/browser/ui/webui/signin/inline_login_ui.cc b/chrome/browser/ui/webui/signin/inline_login_ui.cc
index 5bc7bc72d..9879153 100644
--- a/chrome/browser/ui/webui/signin/inline_login_ui.cc
+++ b/chrome/browser/ui/webui/signin/inline_login_ui.cc
@@ -38,6 +38,7 @@
 #include "ash/constants/ash_features.h"
 #include "ash/constants/ash_pref_names.h"
 #include "chrome/browser/ash/profiles/profile_helper.h"
+#include "chrome/browser/prefs/incognito_mode_prefs.h"
 #include "chrome/browser/supervised_user/supervised_user_features.h"
 #include "chrome/browser/ui/chrome_pages.h"
 #include "chrome/browser/ui/webui/chromeos/edu_account_login_handler_chromeos.h"
@@ -207,10 +208,17 @@
   source->AddBoolean("shouldSkipWelcomePage",
                      profile->GetPrefs()->GetBoolean(
                          chromeos::prefs::kShouldSkipInlineLoginWelcomePage));
+  bool is_incognito_enabled =
+      (IncognitoModePrefs::GetAvailability(profile->GetPrefs()) !=
+       IncognitoModePrefs::DISABLED);
+  int message_id =
+      is_incognito_enabled
+          ? IDS_ACCOUNT_MANAGER_DIALOG_WELCOME_BODY
+          : IDS_ACCOUNT_MANAGER_DIALOG_WELCOME_BODY_WITHOUT_INCOGNITO;
   source->AddString(
       "accountManagerDialogWelcomeBody",
       l10n_util::GetStringFUTF16(
-          IDS_ACCOUNT_MANAGER_DIALOG_WELCOME_BODY,
+          message_id,
           base::UTF8ToUTF16(
               chrome::GetOSSettingsUrl(
                   chromeos::settings::mojom::kMyAccountsSubpagePath)
diff --git a/chrome/browser/ui/webui/signin/profile_picker_handler.cc b/chrome/browser/ui/webui/signin/profile_picker_handler.cc
index f989d28..c0459a7 100644
--- a/chrome/browser/ui/webui/signin/profile_picker_handler.cc
+++ b/chrome/browser/ui/webui/signin/profile_picker_handler.cc
@@ -168,6 +168,29 @@
   }
 }
 
+base::Value CreateProfileEntry(const ProfileAttributesEntry* entry,
+                               int avatar_icon_size) {
+  base::Value profile_entry(base::Value::Type::DICTIONARY);
+  profile_entry.SetKey("profilePath", util::FilePathToValue(entry->GetPath()));
+  profile_entry.SetStringKey("localProfileName", entry->GetLocalProfileName());
+  profile_entry.SetBoolKey(
+      "isSyncing", entry->GetSigninState() ==
+                       SigninState::kSignedInWithConsentedPrimaryAccount);
+  profile_entry.SetBoolKey("needsSignin", entry->IsSigninRequired());
+  // GAIA full name/user name can be empty, if the profile is not signed in to
+  // chrome.
+  profile_entry.SetStringKey("gaiaName", entry->GetGAIAName());
+  profile_entry.SetStringKey("userName", entry->GetUserName());
+  profile_entry.SetBoolKey("isManaged",
+                           AccountInfo::IsManaged(entry->GetHostedDomain()));
+  gfx::Image icon =
+      profiles::GetSizedAvatarIcon(entry->GetAvatarIcon(avatar_icon_size), true,
+                                   avatar_icon_size, avatar_icon_size);
+  std::string icon_url = webui::GetBitmapDataUrl(icon.AsBitmap());
+  profile_entry.SetStringKey("avatarIcon", icon_url);
+  return profile_entry;
+}
+
 }  // namespace
 
 ProfilePickerHandler::ProfilePickerHandler() = default;
@@ -240,6 +263,18 @@
       base::BindRepeating(&ProfilePickerHandler::HandleCreateProfile,
                           base::Unretained(this)));
   web_ui()->RegisterMessageCallback(
+      "getSwitchProfile",
+      base::BindRepeating(&ProfilePickerHandler::HandleGetSwitchProfile,
+                          base::Unretained(this)));
+  web_ui()->RegisterMessageCallback(
+      "confirmProfileSwitch",
+      base::BindRepeating(&ProfilePickerHandler::HandleConfirmProfileSwitch,
+                          base::Unretained(this)));
+  web_ui()->RegisterMessageCallback(
+      "cancelProfileSwitch",
+      base::BindRepeating(&ProfilePickerHandler::HandleCancelProfileSwitch,
+                          base::Unretained(this)));
+  web_ui()->RegisterMessageCallback(
       "setProfileName",
       base::BindRepeating(&ProfilePickerHandler::HandleSetProfileName,
                           base::Unretained(this)));
@@ -423,6 +458,46 @@
                           create_shortcut));
 }
 
+void ProfilePickerHandler::HandleGetSwitchProfile(const base::ListValue* args) {
+  AllowJavascript();
+  CHECK_EQ(1U, args->GetSize());
+  const base::Value& callback_id = args->GetList()[0];
+  int avatar_icon_size =
+      kProfileCardAvatarSize * web_ui()->GetDeviceScaleFactor();
+  base::FilePath profile_path = ProfilePicker::GetSwitchProfilePath();
+  ProfileAttributesEntry* entry =
+      g_browser_process->profile_manager()
+          ->GetProfileAttributesStorage()
+          .GetProfileAttributesWithPath(profile_path);
+  CHECK(entry);
+  base::Value dict = CreateProfileEntry(entry, avatar_icon_size);
+  ResolveJavascriptCallback(callback_id, std::move(dict));
+}
+
+void ProfilePickerHandler::HandleConfirmProfileSwitch(
+    const base::ListValue* args) {
+  const base::Value* profile_path_value = nullptr;
+  if (!args->Get(0, &profile_path_value))
+    return;
+
+  base::Optional<base::FilePath> profile_path =
+      util::ValueToFilePath(*profile_path_value);
+  if (!profile_path)
+    return;
+
+  // TODO(https://crbug.com/1182206): remove the profile used for the sign-in
+  // flow.
+  profiles::SwitchToProfile(
+      *profile_path, /*always_create=*/false,
+      base::BindRepeating(&ProfilePickerHandler::OnSwitchToProfileComplete,
+                          weak_factory_.GetWeakPtr(), false, false));
+}
+
+void ProfilePickerHandler::HandleCancelProfileSwitch(
+    const base::ListValue* args) {
+  ProfilePicker::CancelSignIn();
+}
+
 void ProfilePickerHandler::OnProfileCreated(
     base::Optional<SkColor> profile_color,
     bool create_shortcut,
@@ -692,33 +767,14 @@
 }
 
 base::Value ProfilePickerHandler::GetProfilesList() {
-  base::ListValue profiles_list;
+  base::Value profiles_list(base::Value::Type::LIST);
   std::vector<ProfileAttributesEntry*> entries = GetProfileAttributes();
   const int avatar_icon_size =
       kProfileCardAvatarSize * web_ui()->GetDeviceScaleFactor();
   for (const ProfileAttributesEntry* entry : entries) {
-    auto profile_entry = std::make_unique<base::DictionaryValue>();
-    profile_entry->SetKey("profilePath",
-                          util::FilePathToValue(entry->GetPath()));
-    profile_entry->SetString("localProfileName", entry->GetLocalProfileName());
-    profile_entry->SetBoolPath(
-        "isSyncing", entry->GetSigninState() ==
-                         SigninState::kSignedInWithConsentedPrimaryAccount);
-    profile_entry->SetBoolPath("needsSignin", entry->IsSigninRequired());
-    // GAIA full name/user name can be empty, if the profile is not signed in to
-    // chrome.
-    profile_entry->SetString("gaiaName", entry->GetGAIAName());
-    profile_entry->SetString("userName", entry->GetUserName());
-    profile_entry->SetBoolPath(
-        "isManaged", AccountInfo::IsManaged(entry->GetHostedDomain()));
-    gfx::Image icon =
-        profiles::GetSizedAvatarIcon(entry->GetAvatarIcon(avatar_icon_size),
-                                     true, avatar_icon_size, avatar_icon_size);
-    std::string icon_url = webui::GetBitmapDataUrl(icon.AsBitmap());
-    profile_entry->SetString("avatarIcon", icon_url);
-    profiles_list.Append(std::move(profile_entry));
+    profiles_list.Append(CreateProfileEntry(entry, avatar_icon_size));
   }
-  return std::move(profiles_list);
+  return profiles_list;
 }
 
 void ProfilePickerHandler::AddProfileToList(
diff --git a/chrome/browser/ui/webui/signin/profile_picker_handler.h b/chrome/browser/ui/webui/signin/profile_picker_handler.h
index 666ed53..8498f460 100644
--- a/chrome/browser/ui/webui/signin/profile_picker_handler.h
+++ b/chrome/browser/ui/webui/signin/profile_picker_handler.h
@@ -36,6 +36,12 @@
 
  private:
   friend class ProfilePickerHandlerTest;
+  FRIEND_TEST_ALL_PREFIXES(
+      ProfilePickerCreationFlowBrowserTest,
+      CreateSignedInProfileSigninAlreadyExists_ConfirmSwitch);
+  FRIEND_TEST_ALL_PREFIXES(
+      ProfilePickerCreationFlowBrowserTest,
+      CreateSignedInProfileSigninAlreadyExists_CancelSwitch);
 
   void HandleMainViewInitialize(const base::ListValue* args);
   void HandleLaunchSelectedProfile(bool open_settings,
@@ -53,6 +59,11 @@
   void HandleGetAvailableIcons(const base::ListValue* args);
   void HandleCreateProfile(const base::ListValue* args);
 
+  // Profile switch screen:
+  void HandleGetSwitchProfile(const base::ListValue* args);
+  void HandleConfirmProfileSwitch(const base::ListValue* args);
+  void HandleCancelProfileSwitch(const base::ListValue* args);
+
   // |args| is unused.
   void HandleRecordSignInPromoImpression(const base::ListValue* args);
 
diff --git a/chrome/browser/ui/webui/signin/profile_picker_ui.cc b/chrome/browser/ui/webui/signin/profile_picker_ui.cc
index 0bc191d..60042a0 100644
--- a/chrome/browser/ui/webui/signin/profile_picker_ui.cc
+++ b/chrome/browser/ui/webui/signin/profile_picker_ui.cc
@@ -123,6 +123,10 @@
        IDS_PROFILE_PICKER_PROFILE_CREATION_FLOW_LOCAL_PROFILE_CREATION_AVATAR_TEXT},
       {"selectAvatarDoneButtonLabel",
        IDS_PROFILE_PICKER_PROFILE_CREATION_FLOW_LOCAL_PROFILE_CREATION_AVATAR_DONE},
+      {"profileSwitchTitle", IDS_PROFILE_PICKER_PROFILE_SWITCH_TITLE},
+      {"profileSwitchSubtitle", IDS_PROFILE_PICKER_PROFILE_SWITCH_SUBTITLE},
+      {"switchButtonLabel",
+       IDS_PROFILE_PICKER_PROFILE_SWITCH_SWITCH_BUTTON_LABEL},
 
       // Color picker.
       {"colorPickerLabel", IDS_NTP_CUSTOMIZE_COLOR_PICKER_LABEL},
@@ -179,12 +183,12 @@
 
   std::unique_ptr<ProfilePickerHandler> handler =
       std::make_unique<ProfilePickerHandler>();
-  ProfilePickerHandler* raw_handler = handler.get();
+  profile_picker_handler_ = handler.get();
   web_ui->AddMessageHandler(std::move(handler));
 
   if (web_ui->GetWebContents()->GetURL().query() ==
       chrome::kChromeUIProfilePickerStartupQuery) {
-    raw_handler->EnableStartupMetrics();
+    profile_picker_handler_->EnableStartupMetrics();
   }
 
   AddStrings(html_source);
@@ -212,6 +216,10 @@
   customize_themes_factory_receiver_.Bind(std::move(pending_receiver));
 }
 
+ProfilePickerHandler* ProfilePickerUI::GetProfilePickerHandlerForTesting() {
+  return profile_picker_handler_;
+}
+
 void ProfilePickerUI::CreateCustomizeThemesHandler(
     mojo::PendingRemote<customize_themes::mojom::CustomizeThemesClient>
         pending_client,
diff --git a/chrome/browser/ui/webui/signin/profile_picker_ui.h b/chrome/browser/ui/webui/signin/profile_picker_ui.h
index 0bc1e8e..c0ef04a5 100644
--- a/chrome/browser/ui/webui/signin/profile_picker_ui.h
+++ b/chrome/browser/ui/webui/signin/profile_picker_ui.h
@@ -13,6 +13,7 @@
 #include "ui/webui/resources/cr_components/customize_themes/customize_themes.mojom.h"
 
 class ProfileCreationCustomizeThemesHandler;
+class ProfilePickerHandler;
 
 // The WebUI controller for chrome://profile-picker/.
 class ProfilePickerUI
@@ -35,6 +36,9 @@
                      customize_themes::mojom::CustomizeThemesHandlerFactory>
                          pending_receiver);
 
+  // Allows tests to trigger page events.
+  ProfilePickerHandler* GetProfilePickerHandlerForTesting();
+
  private:
   // customize_themes::mojom::CustomizeThemesHandlerFactory:
   void CreateCustomizeThemesHandler(
@@ -48,6 +52,9 @@
   mojo::Receiver<customize_themes::mojom::CustomizeThemesHandlerFactory>
       customize_themes_factory_receiver_;
 
+  // Stored for tests.
+  ProfilePickerHandler* profile_picker_handler_ = nullptr;
+
   WEB_UI_CONTROLLER_TYPE_DECL();
 };
 
diff --git a/chrome/browser/ui/webui/signin/signin_ui_error.cc b/chrome/browser/ui/webui/signin/signin_ui_error.cc
index 7f021d0..79f67af 100644
--- a/chrome/browser/ui/webui/signin/signin_ui_error.cc
+++ b/chrome/browser/ui/webui/signin/signin_ui_error.cc
@@ -41,10 +41,13 @@
 
 // static
 SigninUIError SigninUIError::AccountAlreadyUsedByAnotherProfile(
-    const std::string& email) {
-  return SigninUIError(
+    const std::string& email,
+    const base::FilePath& another_profile_path) {
+  SigninUIError error(
       Type::kAccountAlreadyUsedByAnotherProfile, email,
       l10n_util::GetStringUTF16(IDS_SYNC_USER_NAME_IN_USE_ERROR));
+  error.another_profile_path_ = another_profile_path;
+  return error;
 }
 
 // static
@@ -57,6 +60,9 @@
                                  base::UTF8ToUTF16(last_email)));
 }
 
+SigninUIError::SigninUIError(const SigninUIError& other) = default;
+SigninUIError& SigninUIError::operator=(const SigninUIError& other) = default;
+
 bool SigninUIError::IsOk() const {
   return type_ == Type::kOk;
 }
@@ -73,9 +79,15 @@
   return message_;
 }
 
+const base::FilePath& SigninUIError::another_profile_path() const {
+  DCHECK(type() == Type::kAccountAlreadyUsedByAnotherProfile);
+  return another_profile_path_;
+}
+
 bool SigninUIError::operator==(const SigninUIError& other) const {
-  return std::tie(type_, email_, message_) ==
-         std::tie(other.type_, other.email_, other.message_);
+  return std::tie(type_, email_, message_, another_profile_path_) ==
+         std::tie(other.type_, other.email_, other.message_,
+                  other.another_profile_path_);
 }
 
 bool SigninUIError::operator!=(const SigninUIError& other) const {
diff --git a/chrome/browser/ui/webui/signin/signin_ui_error.h b/chrome/browser/ui/webui/signin/signin_ui_error.h
index 6c49516f..3861ab89 100644
--- a/chrome/browser/ui/webui/signin/signin_ui_error.h
+++ b/chrome/browser/ui/webui/signin/signin_ui_error.h
@@ -7,6 +7,7 @@
 
 #include <string>
 
+#include "base/files/file_path.h"
 #include "base/strings/string16.h"
 
 // Holds different sign-in error types along with error messages for displaying
@@ -33,11 +34,15 @@
   static SigninUIError WrongReauthAccount(const std::string& email,
                                           const std::string& current_email);
   static SigninUIError AccountAlreadyUsedByAnotherProfile(
-      const std::string& email);
+      const std::string& email,
+      const base::FilePath& another_profile_path);
   static SigninUIError ProfileWasUsedByAnotherAccount(
       const std::string& email,
       const std::string& last_email);
 
+  SigninUIError(const SigninUIError& other);
+  SigninUIError& operator=(const SigninUIError& other);
+
   // Returns true if the instance contains a non-error type.
   bool IsOk() const;
 
@@ -45,6 +50,10 @@
   const base::string16& email() const;
   const base::string16& message() const;
 
+  // Should be called only if `type()` == //
+  // `Type::kAccountAlreadyUsedByAnotherProfile`.
+  const base::FilePath& another_profile_path() const;
+
   bool operator==(const SigninUIError& other) const;
   bool operator!=(const SigninUIError& other) const;
 
@@ -57,6 +66,9 @@
   Type type_;
   base::string16 email_;
   base::string16 message_;
+
+  // Defined only for Type::kAccountAlreadyUsedByAnotherProfile
+  base::FilePath another_profile_path_;
 };
 
 #endif  // CHROME_BROWSER_UI_WEBUI_SIGNIN_SIGNIN_UI_ERROR_H_
diff --git a/chrome/browser/ui/webui/signin/signin_utils_desktop.cc b/chrome/browser/ui/webui/signin/signin_utils_desktop.cc
index 6acf6a1..8d1b3360 100644
--- a/chrome/browser/ui/webui/signin/signin_utils_desktop.cc
+++ b/chrome/browser/ui/webui/signin/signin_utils_desktop.cc
@@ -87,7 +87,8 @@
           std::string profile_email = base::UTF16ToUTF8(entry->GetUserName());
           if (gaia_id == profile_gaia_id ||
               gaia::AreEmailsSame(email, profile_email)) {
-            return SigninUIError::AccountAlreadyUsedByAnotherProfile(email);
+            return SigninUIError::AccountAlreadyUsedByAnotherProfile(
+                email, entry->GetPath());
           }
         }
       }
diff --git a/chrome/browser/usb/frame_usb_services.cc b/chrome/browser/usb/frame_usb_services.cc
index 7aac9c1..6dfe3c364 100644
--- a/chrome/browser/usb/frame_usb_services.cc
+++ b/chrome/browser/usb/frame_usb_services.cc
@@ -52,7 +52,7 @@
 
 void FrameUsbServices::InitializeWebUsbService(
     mojo::PendingReceiver<blink::mojom::WebUsbService> receiver) {
-  if (!AllowedByFeaturePolicy()) {
+  if (!AllowedByPermissionsPolicy()) {
     mojo::ReportBadMessage(kPermissionsPolicyViolation);
     return;
   }
@@ -65,7 +65,7 @@
   web_usb_service_->BindReceiver(std::move(receiver));
 }
 
-bool FrameUsbServices::AllowedByFeaturePolicy() const {
+bool FrameUsbServices::AllowedByPermissionsPolicy() const {
   return render_frame_host_->IsFeatureEnabled(
       blink::mojom::PermissionsPolicyFeature::kUsb);
 }
diff --git a/chrome/browser/usb/frame_usb_services.h b/chrome/browser/usb/frame_usb_services.h
index 17f087e1..4ee71faf 100644
--- a/chrome/browser/usb/frame_usb_services.h
+++ b/chrome/browser/usb/frame_usb_services.h
@@ -39,7 +39,7 @@
   void InitializeWebUsbService(
       mojo::PendingReceiver<blink::mojom::WebUsbService> receiver);
 
-  bool AllowedByFeaturePolicy() const;
+  bool AllowedByPermissionsPolicy() const;
 
   std::unique_ptr<WebUsbChooser> usb_chooser_;
   std::unique_ptr<WebUsbServiceImpl> web_usb_service_;
diff --git a/chrome/browser/web_applications/components/os_integration_manager.cc b/chrome/browser/web_applications/components/os_integration_manager.cc
index 9217b4c..a7d87841 100644
--- a/chrome/browser/web_applications/components/os_integration_manager.cc
+++ b/chrome/browser/web_applications/components/os_integration_manager.cc
@@ -10,6 +10,7 @@
 #include "base/auto_reset.h"
 #include "base/bind.h"
 #include "base/callback.h"
+#include "base/callback_helpers.h"
 #include "base/feature_list.h"
 #include "base/memory/ref_counted.h"
 #include "base/optional.h"
@@ -237,7 +238,7 @@
   UpdateShortcuts(app_id, old_name);
   UpdateShortcutsMenu(app_id, web_app_info);
 
-  UpdateUrlHandlers(app_id);
+  UpdateUrlHandlers(app_id, base::DoNothing());
 }
 
 void OsIntegrationManager::GetShortcutInfoForApp(
@@ -503,11 +504,13 @@
   }
 }
 
-void OsIntegrationManager::UpdateUrlHandlers(const AppId& app_id) {
+void OsIntegrationManager::UpdateUrlHandlers(
+    const AppId& app_id,
+    base::OnceCallback<void(bool success)> callback) {
   if (!url_handler_manager_)
     return;
 
-  url_handler_manager_->UpdateUrlHandlers(app_id);
+  url_handler_manager_->UpdateUrlHandlers(app_id, std::move(callback));
 }
 
 std::unique_ptr<ShortcutInfo> OsIntegrationManager::BuildShortcutInfo(
diff --git a/chrome/browser/web_applications/components/os_integration_manager.h b/chrome/browser/web_applications/components/os_integration_manager.h
index dc27981..3f63b01 100644
--- a/chrome/browser/web_applications/components/os_integration_manager.h
+++ b/chrome/browser/web_applications/components/os_integration_manager.h
@@ -138,6 +138,15 @@
 
   virtual TestOsIntegrationManager* AsTestOsIntegrationManager();
 
+  void set_url_handler_manager(
+      std::unique_ptr<UrlHandlerManager> url_handler_manager) {
+    url_handler_manager_ = std::move(url_handler_manager);
+  }
+
+  virtual void UpdateUrlHandlers(
+      const AppId& app_id,
+      base::OnceCallback<void(bool success)> callback);
+
  protected:
   AppShortcutManager* shortcut_manager() { return shortcut_manager_.get(); }
   FileHandlerManager* file_handler_manager() {
@@ -161,10 +170,7 @@
       std::unique_ptr<ProtocolHandlerManager> protocol_handler_manager) {
     protocol_handler_manager_ = std::move(protocol_handler_manager);
   }
-  void set_url_handler_manager(
-      std::unique_ptr<UrlHandlerManager> url_handler_manager) {
-    url_handler_manager_ = std::move(url_handler_manager);
-  }
+
   virtual void CreateShortcuts(const AppId& app_id,
                                bool add_to_desktop,
                                CreateShortcutsCallback callback);
@@ -214,7 +220,6 @@
   virtual void UpdateShortcuts(const AppId& app_id, base::StringPiece old_name);
   virtual void UpdateShortcutsMenu(const AppId& app_id,
                                    const WebApplicationInfo& web_app_info);
-  virtual void UpdateUrlHandlers(const AppId& app_id);
 
   // Utility methods:
   virtual std::unique_ptr<ShortcutInfo> BuildShortcutInfo(const AppId& app_id);
diff --git a/chrome/browser/web_applications/components/os_integration_manager_unittest.cc b/chrome/browser/web_applications/components/os_integration_manager_unittest.cc
index d004fec..4f81f1e 100644
--- a/chrome/browser/web_applications/components/os_integration_manager_unittest.cc
+++ b/chrome/browser/web_applications/components/os_integration_manager_unittest.cc
@@ -123,7 +123,11 @@
               UpdateShortcutsMenu,
               (const AppId& app_id, const WebApplicationInfo& web_app_info),
               (override));
-  MOCK_METHOD(void, UpdateUrlHandlers, (const AppId& app_id), (override));
+  MOCK_METHOD(void,
+              UpdateUrlHandlers,
+              (const AppId& app_id,
+               base::OnceCallback<void(bool success)> callback),
+              (override));
 
   // Utility methods:
   MOCK_METHOD(std::unique_ptr<ShortcutInfo>,
@@ -284,7 +288,7 @@
 
   EXPECT_CALL(manager, UpdateShortcuts(app_id, old_name)).Times(1);
   EXPECT_CALL(manager, UpdateShortcutsMenu(app_id, testing::_)).Times(1);
-  EXPECT_CALL(manager, UpdateUrlHandlers(app_id)).Times(1);
+  EXPECT_CALL(manager, UpdateUrlHandlers(app_id, testing::_)).Times(1);
 
   manager.UpdateOsHooks(app_id, old_name, web_app_info);
 }
diff --git a/chrome/browser/web_applications/components/url_handler_manager.h b/chrome/browser/web_applications/components/url_handler_manager.h
index 36d19bb..f1acdf54 100644
--- a/chrome/browser/web_applications/components/url_handler_manager.h
+++ b/chrome/browser/web_applications/components/url_handler_manager.h
@@ -35,7 +35,9 @@
   // Returns true if unregistration succeeds, false otherwise.
   virtual bool UnregisterUrlHandlers(const AppId& app_id) = 0;
   // Returns true if update succeeds, false otherwise.
-  virtual bool UpdateUrlHandlers(const AppId& app_id) = 0;
+  virtual void UpdateUrlHandlers(
+      const AppId& app_id,
+      base::OnceCallback<void(bool success)> callback) = 0;
 
  protected:
   Profile* profile() const { return profile_; }
diff --git a/chrome/browser/web_applications/components/url_handler_manager_impl.cc b/chrome/browser/web_applications/components/url_handler_manager_impl.cc
index 24a6ee5b..c02e418 100644
--- a/chrome/browser/web_applications/components/url_handler_manager_impl.cc
+++ b/chrome/browser/web_applications/components/url_handler_manager_impl.cc
@@ -123,19 +123,35 @@
   return true;
 }
 
-bool UrlHandlerManagerImpl::UpdateUrlHandlers(const AppId& app_id) {
+void UrlHandlerManagerImpl::UpdateUrlHandlers(
+    const AppId& app_id,
+    base::OnceCallback<void(bool success)> callback) {
   auto url_handlers = registrar()->GetAppUrlHandlers(app_id);
 
   if (!base::FeatureList::IsEnabled(
           blink::features::kWebAppEnableUrlHandlers)) {
     url_handler_prefs::RemoveWebApp(GetLocalState(), app_id,
                                     profile()->GetPath());
-    return false;
-  } else {
-    url_handler_prefs::UpdateWebApp(GetLocalState(), app_id,
-                                    profile()->GetPath(), url_handlers);
-    return true;
+    std::move(callback).Run(false);
+    return;
   }
+
+  association_manager_->GetWebAppOriginAssociations(
+      registrar()->GetAppManifestUrl(app_id), std::move(url_handlers),
+      base::BindOnce(&UrlHandlerManagerImpl::OnDidGetAssociationsAtUpdate,
+                     weak_ptr_factory_.GetWeakPtr(), app_id,
+                     std::move(callback)));
+}
+
+void UrlHandlerManagerImpl::OnDidGetAssociationsAtUpdate(
+    const AppId& app_id,
+    base::OnceCallback<void(bool success)> callback,
+    apps::UrlHandlers url_handlers) {
+  // TODO(crbug/1072058): Only overwrite existing url_handlers if associations
+  // changed. Allow this after user permission is implemented.
+  url_handler_prefs::UpdateWebApp(GetLocalState(), app_id, profile()->GetPath(),
+                                  std::move(url_handlers));
+  std::move(callback).Run(true);
 }
 
 void UrlHandlerManagerImpl::SetAssociationManagerForTesting(
diff --git a/chrome/browser/web_applications/components/url_handler_manager_impl.h b/chrome/browser/web_applications/components/url_handler_manager_impl.h
index 89c0e9d..f401b8d 100644
--- a/chrome/browser/web_applications/components/url_handler_manager_impl.h
+++ b/chrome/browser/web_applications/components/url_handler_manager_impl.h
@@ -64,7 +64,9 @@
 
   // Returns false and unregisters url handlers for |app_id| if
   // blink::features::kWebAppEnableUrlHandlers is disabled.
-  bool UpdateUrlHandlers(const AppId& app_id) override;
+  void UpdateUrlHandlers(
+      const AppId& app_id,
+      base::OnceCallback<void(bool success)> callback) override;
 
   void SetAssociationManagerForTesting(
       std::unique_ptr<WebAppOriginAssociationManager> manager);
@@ -74,7 +76,10 @@
       const AppId& app_id,
       base::OnceCallback<void(bool success)> callback,
       apps::UrlHandlers url_handlers);
-
+  void OnDidGetAssociationsAtUpdate(
+      const AppId& app_id,
+      base::OnceCallback<void(bool success)> callback,
+      apps::UrlHandlers url_handlers);
   // Returns the local state pref service of the browser process.
   PrefService* GetLocalState();
 
diff --git a/chrome/browser/web_applications/components/url_handler_manager_impl_unittest.cc b/chrome/browser/web_applications/components/url_handler_manager_impl_unittest.cc
index 7427b2f..358cebf7 100644
--- a/chrome/browser/web_applications/components/url_handler_manager_impl_unittest.cc
+++ b/chrome/browser/web_applications/components/url_handler_manager_impl_unittest.cc
@@ -61,7 +61,7 @@
         {apps::UrlHandlerInfo(origin_1_),
          apps::UrlHandlerInfo(origin_1_, false, {"/abc"}, {"/foo"})},
         {apps::UrlHandlerInfo(origin_2_),
-         apps::UrlHandlerInfo(origin_1_, false, {"/abc"}, {"/bar"})},
+         apps::UrlHandlerInfo(origin_2_, false, {"/abc"}, {"/bar"})},
     };
     association_manager->SetData(std::move(data));
     url_handler_manager->SetAssociationManagerForTesting(
@@ -123,7 +123,13 @@
     controller().UnregisterApp(app_id);
     controller().RegisterApp(std::move(web_app));
 
-    EXPECT_TRUE(url_handler_manager().UpdateUrlHandlers(app_id));
+    base::RunLoop run_loop;
+    url_handler_manager().UpdateUrlHandlers(
+        app_id, base::BindLambdaForTesting([&](bool success) {
+          EXPECT_TRUE(success);
+          run_loop.Quit();
+        }));
+    run_loop.Run();
     return app_id;
   }
 
@@ -202,6 +208,12 @@
     EXPECT_EQ(params.profile_path, profile()->GetPath());
     EXPECT_EQ(params.app_id, app_id);
     EXPECT_EQ(params.url, kOriginUrl2);
+
+    // Check excluded path shouldn't match
+    cmd_2 = base::CommandLine(base::CommandLine::NO_PROGRAM);
+    cmd_2.AppendArg("https://origin-2.com/bar");
+    matches = UrlHandlerManagerImpl::GetUrlHandlerMatches(cmd_2);
+    EXPECT_TRUE(matches.empty());
   }
 }
 
@@ -283,7 +295,12 @@
     controller().UnregisterApp(app_id);
     controller().RegisterApp(std::move(web_app));
 
-    EXPECT_FALSE(url_handler_manager().UpdateUrlHandlers(app_id));
+    base::RunLoop run_loop;
+    url_handler_manager().UpdateUrlHandlers(
+        app_id, base::BindLambdaForTesting([&](bool success) {
+          EXPECT_FALSE(success);
+          run_loop.Quit();
+        }));
   }
 
   // Expect that url handlers have been removed.
diff --git a/chrome/browser/web_applications/manifest_update_manager.cc b/chrome/browser/web_applications/manifest_update_manager.cc
index e940435..5609fff 100644
--- a/chrome/browser/web_applications/manifest_update_manager.cc
+++ b/chrome/browser/web_applications/manifest_update_manager.cc
@@ -10,6 +10,7 @@
 #include "chrome/browser/content_settings/host_content_settings_map_factory.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/web_applications/components/app_registrar.h"
+#include "chrome/browser/web_applications/components/os_integration_manager.h"
 #include "chrome/browser/web_applications/components/web_app_constants.h"
 #include "chrome/browser/web_applications/system_web_app_manager.h"
 #include "chrome/common/chrome_features.h"
@@ -30,12 +31,14 @@
     AppIconManager* icon_manager,
     WebAppUiManager* ui_manager,
     InstallManager* install_manager,
-    SystemWebAppManager* system_web_app_manager) {
+    SystemWebAppManager* system_web_app_manager,
+    OsIntegrationManager* os_integration_manager) {
   registrar_ = registrar;
   icon_manager_ = icon_manager;
   ui_manager_ = ui_manager;
   install_manager_ = install_manager;
   system_web_app_manager_ = system_web_app_manager;
+  os_integration_manager_ = os_integration_manager;
 }
 
 void ManifestUpdateManager::Start() {
@@ -88,7 +91,7 @@
                   base::BindOnce(&ManifestUpdateManager::OnUpdateStopped,
                                  base::Unretained(this)),
                   hang_update_checks_for_testing_, *registrar_, *icon_manager_,
-                  ui_manager_, install_manager_));
+                  ui_manager_, install_manager_, *os_integration_manager_));
 }
 
 // AppRegistrarObserver:
diff --git a/chrome/browser/web_applications/manifest_update_manager.h b/chrome/browser/web_applications/manifest_update_manager.h
index d549d26..9979e3e 100644
--- a/chrome/browser/web_applications/manifest_update_manager.h
+++ b/chrome/browser/web_applications/manifest_update_manager.h
@@ -25,6 +25,7 @@
 
 class WebAppUiManager;
 class InstallManager;
+class OsIntegrationManager;
 class SystemWebAppManager;
 
 // Checks for updates to a web app's manifest and triggers a reinstall if the
@@ -47,7 +48,8 @@
                      AppIconManager* icon_manager,
                      WebAppUiManager* ui_manager,
                      InstallManager* install_manager,
-                     SystemWebAppManager* system_web_app_manager);
+                     SystemWebAppManager* system_web_app_manager,
+                     OsIntegrationManager* os_integration_manager);
   void Start();
   void Shutdown();
 
@@ -88,6 +90,7 @@
   WebAppUiManager* ui_manager_ = nullptr;
   InstallManager* install_manager_ = nullptr;
   SystemWebAppManager* system_web_app_manager_ = nullptr;
+  OsIntegrationManager* os_integration_manager_ = nullptr;
 
   ScopedObserver<AppRegistrar, AppRegistrarObserver> registrar_observer_{this};
 
diff --git a/chrome/browser/web_applications/manifest_update_manager_browsertest.cc b/chrome/browser/web_applications/manifest_update_manager_browsertest.cc
index ef1bb7d..42c181f06 100644
--- a/chrome/browser/web_applications/manifest_update_manager_browsertest.cc
+++ b/chrome/browser/web_applications/manifest_update_manager_browsertest.cc
@@ -4,10 +4,13 @@
 
 #include "chrome/browser/web_applications/manifest_update_manager.h"
 
+#include <map>
+#include <memory>
 #include <string>
 #include <vector>
 
 #include "base/callback_helpers.h"
+#include "base/containers/contains.h"
 #include "base/memory/scoped_refptr.h"
 #include "base/strings/string_util.h"
 #include "base/strings/utf_string_conversions.h"
@@ -15,6 +18,7 @@
 #include "base/test/metrics/histogram_tester.h"
 #include "base/test/scoped_feature_list.h"
 #include "base/time/time.h"
+#include "build/build_config.h"
 #include "chrome/app/chrome_command_ids.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/ui/browser.h"
@@ -51,6 +55,13 @@
 #include "third_party/blink/public/common/manifest/manifest.h"
 #include "third_party/skia/include/core/SkColor.h"
 
+#if defined(OS_WIN) || defined(OS_MAC) || \
+    (defined(OS_LINUX) && !BUILDFLAG(IS_CHROMEOS_LACROS))
+#include "base/command_line.h"
+#include "chrome/browser/web_applications/components/url_handler_manager_impl.h"
+#include "chrome/browser/web_applications/test/fake_web_app_origin_association_manager.h"
+#endif
+
 namespace web_app {
 
 namespace {
@@ -1816,4 +1827,215 @@
             SK_ColorBLACK);
 }
 
+class ManifestUpdateManagerBrowserTest_UrlHandlers
+    : public ManifestUpdateManagerBrowserTest {
+ public:
+  ManifestUpdateManagerBrowserTest_UrlHandlers() {
+    scoped_feature_list_.InitAndEnableFeature(
+        blink::features::kWebAppEnableUrlHandlers);
+  }
+
+#if defined(OS_WIN) || defined(OS_MAC) || \
+    (defined(OS_LINUX) && !BUILDFLAG(IS_CHROMEOS_LACROS))
+  void SetUpUrlHandlerManager() {
+    auto url_handler_manager =
+        std::make_unique<UrlHandlerManagerImpl>(browser()->profile());
+
+    // Set up web app origin association manager and expected data.
+    auto association_manager =
+        std::make_unique<FakeWebAppOriginAssociationManager>();
+    url::Origin foo_origin = url::Origin::Create(GURL("https://foo.com"));
+    url::Origin bar_origin = url::Origin::Create(GURL("https://bar.com"));
+    std::map<apps::UrlHandlerInfo, apps::UrlHandlerInfo> data = {
+        {apps::UrlHandlerInfo(foo_origin),
+         apps::UrlHandlerInfo(foo_origin, false, /*paths*/ {},
+                              /*exclude_paths*/ {"/exclude"})},
+        {apps::UrlHandlerInfo(bar_origin),
+         apps::UrlHandlerInfo(bar_origin, false, /*paths*/ {},
+                              /*exclude_paths*/ {"/exclude"})},
+    };
+    association_manager->SetData(std::move(data));
+
+    url_handler_manager->SetAssociationManagerForTesting(
+        std::move(association_manager));
+    url_handler_manager->SetSubsystems(&(GetProvider().registrar()));
+    GetProvider().os_integration_manager().set_url_handler_manager(
+        std::move(url_handler_manager));
+  }
+#endif
+
+ private:
+  base::test::ScopedFeatureList scoped_feature_list_;
+};
+
+IN_PROC_BROWSER_TEST_F(ManifestUpdateManagerBrowserTest_UrlHandlers,
+                       UpdateWithDifferentUrlHandlers) {
+  constexpr char kManifestTemplate[] = R"(
+    {
+      "name": "Test app name",
+      "start_url": ".",
+      "scope": "/",
+      "display": "standalone",
+      "icons": $1,
+      "url_handlers": [$2]
+    }
+  )";
+
+  OverrideManifest(kManifestTemplate, {
+                                          kInstallableIconList,
+                                          R"({"origin": "https://foo.com"})",
+                                      });
+  AppId app_id = InstallWebApp();
+  ASSERT_EQ(1u, GetProvider().registrar().GetAppUrlHandlers(app_id).size());
+
+  OverrideManifest(
+      kManifestTemplate,
+      {kInstallableIconList,
+       R"({"origin": "https://foo.com"}, {"origin": "https://bar.com"})"});
+  EXPECT_EQ(GetResultAfterPageLoad(GetAppURL(), &app_id),
+            ManifestUpdateResult::kAppUpdated);
+
+  apps::UrlHandlers url_handlers =
+      GetProvider().registrar().GetAppUrlHandlers(app_id);
+  ASSERT_EQ(2u, url_handlers.size());
+  EXPECT_TRUE(base::Contains(
+      url_handlers,
+      apps::UrlHandlerInfo(url::Origin::Create(GURL("https://foo.com")))));
+  EXPECT_TRUE(base::Contains(
+      url_handlers,
+      apps::UrlHandlerInfo(url::Origin::Create(GURL("https://bar.com")))));
+}
+
+IN_PROC_BROWSER_TEST_F(ManifestUpdateManagerBrowserTest_UrlHandlers,
+                       UpdateFromNoUrlHandlersToHaveUrlHandlers) {
+  constexpr char kManifestTemplate[] = R"(
+    {
+      "name": "Test app name",
+      "start_url": ".",
+      "scope": "/",
+      "display": "standalone",
+      "icons": $1
+      $2
+    }
+  )";
+
+  OverrideManifest(kManifestTemplate, {
+                                          kInstallableIconList,
+                                          R"()",
+                                      });
+  AppId app_id = InstallWebApp();
+  ASSERT_EQ(0u, GetProvider().registrar().GetAppUrlHandlers(app_id).size());
+
+  OverrideManifest(kManifestTemplate,
+                   {kInstallableIconList,
+                    R"(,"url_handlers": [{"origin": "https://foo.com"}])"});
+  EXPECT_EQ(GetResultAfterPageLoad(GetAppURL(), &app_id),
+            ManifestUpdateResult::kAppUpdated);
+
+  apps::UrlHandlers url_handlers =
+      GetProvider().registrar().GetAppUrlHandlers(app_id);
+  ASSERT_EQ(1u, url_handlers.size());
+  EXPECT_TRUE(base::Contains(
+      url_handlers,
+      apps::UrlHandlerInfo(url::Origin::Create(GURL("https://foo.com")))));
+}
+
+IN_PROC_BROWSER_TEST_F(ManifestUpdateManagerBrowserTest_UrlHandlers,
+                       UpdateFromUrlHandlersToNoUrlHandlers) {
+  constexpr char kManifestTemplate[] = R"(
+    {
+      "name": "Test app name",
+      "start_url": ".",
+      "scope": "/",
+      "display": "standalone",
+      "icons": $1
+      $2
+    }
+  )";
+
+  OverrideManifest(kManifestTemplate,
+                   {
+                       kInstallableIconList,
+                       R"(,"url_handlers": [{"origin": "https://foo.com"}])",
+                   });
+  AppId app_id = InstallWebApp();
+  apps::UrlHandlers url_handlers =
+      GetProvider().registrar().GetAppUrlHandlers(app_id);
+  ASSERT_EQ(1u, url_handlers.size());
+  EXPECT_TRUE(base::Contains(
+      url_handlers,
+      apps::UrlHandlerInfo(url::Origin::Create(GURL("https://foo.com")))));
+
+  OverrideManifest(kManifestTemplate, {kInstallableIconList, R"()"});
+  EXPECT_EQ(GetResultAfterPageLoad(GetAppURL(), &app_id),
+            ManifestUpdateResult::kAppUpdated);
+
+  url_handlers = GetProvider().registrar().GetAppUrlHandlers(app_id);
+  ASSERT_EQ(0u, url_handlers.size());
+}
+
+#if defined(OS_WIN) || defined(OS_MAC) || \
+    (defined(OS_LINUX) && !BUILDFLAG(IS_CHROMEOS_LACROS))
+IN_PROC_BROWSER_TEST_F(ManifestUpdateManagerBrowserTest_UrlHandlers,
+                       NoHandlersChangeUpdateAssociations) {
+  constexpr char kManifestTemplate[] = R"(
+    {
+      "name": "Test app name",
+      "start_url": ".",
+      "scope": "/",
+      "display": "standalone",
+      "icons": $1,
+      "url_handlers": [
+        {
+          "origin": "https://foo.com"
+        },
+        {
+          "origin": "https://bar.com"
+        }
+      ]
+    }
+  )";
+
+  OverrideManifest(kManifestTemplate, {kInstallableIconList});
+  AppId app_id = InstallWebApp();
+  apps::UrlHandlers url_handlers =
+      GetProvider().registrar().GetAppUrlHandlers(app_id);
+  ASSERT_EQ(2u, url_handlers.size());
+  EXPECT_TRUE(base::Contains(
+      url_handlers,
+      apps::UrlHandlerInfo(url::Origin::Create(GURL("https://foo.com")))));
+  EXPECT_TRUE(base::Contains(
+      url_handlers,
+      apps::UrlHandlerInfo(url::Origin::Create(GURL("https://bar.com")))));
+
+  // Prepare for association fetching at manifest update.
+  SetUpUrlHandlerManager();
+  OverrideManifest(kManifestTemplate, {kInstallableIconList});
+  EXPECT_EQ(GetResultAfterPageLoad(GetAppURL(), &app_id),
+            ManifestUpdateResult::kAppAssociationsUpdated);
+
+  // Verify url handlers are saved to prefs.
+  base::CommandLine cmd = base::CommandLine(base::CommandLine::NO_PROGRAM);
+  cmd.AppendArg("https://foo.com/ok");
+  std::vector<UrlHandlerLaunchParams> matches =
+      UrlHandlerManagerImpl::GetUrlHandlerMatches(cmd);
+  ASSERT_EQ(matches.size(), 1u);
+  // Check exclude paths came through.
+  cmd = base::CommandLine(base::CommandLine::NO_PROGRAM);
+  cmd.AppendArg("https://foo.com/exclude");
+  matches = UrlHandlerManagerImpl::GetUrlHandlerMatches(cmd);
+  ASSERT_EQ(matches.size(), 0u);
+
+  cmd = base::CommandLine(base::CommandLine::NO_PROGRAM);
+  cmd.AppendArg("https://bar.com/ok");
+  matches = UrlHandlerManagerImpl::GetUrlHandlerMatches(cmd);
+  ASSERT_EQ(matches.size(), 1u);
+  // Check exclude paths came through.
+  cmd = base::CommandLine(base::CommandLine::NO_PROGRAM);
+  cmd.AppendArg("https://bar.com/exclude");
+  matches = UrlHandlerManagerImpl::GetUrlHandlerMatches(cmd);
+  ASSERT_EQ(matches.size(), 0u);
+}
+#endif
+
 }  // namespace web_app
diff --git a/chrome/browser/web_applications/manifest_update_task.cc b/chrome/browser/web_applications/manifest_update_task.cc
index ee95f39..1933adb 100644
--- a/chrome/browser/web_applications/manifest_update_task.cc
+++ b/chrome/browser/web_applications/manifest_update_task.cc
@@ -14,6 +14,7 @@
 #include "chrome/browser/web_applications/components/app_icon_manager.h"
 #include "chrome/browser/web_applications/components/app_registrar.h"
 #include "chrome/browser/web_applications/components/install_manager.h"
+#include "chrome/browser/web_applications/components/os_integration_manager.h"
 #include "chrome/browser/web_applications/components/web_app_constants.h"
 #include "chrome/browser/web_applications/components/web_app_helpers.h"
 #include "chrome/browser/web_applications/components/web_app_install_utils.h"
@@ -62,20 +63,23 @@
 
 }  // namespace
 
-ManifestUpdateTask::ManifestUpdateTask(const GURL& url,
-                                       const AppId& app_id,
-                                       content::WebContents* web_contents,
-                                       StoppedCallback stopped_callback,
-                                       bool hang_for_testing,
-                                       const AppRegistrar& registrar,
-                                       const AppIconManager& icon_manager,
-                                       WebAppUiManager* ui_manager,
-                                       InstallManager* install_manager)
+ManifestUpdateTask::ManifestUpdateTask(
+    const GURL& url,
+    const AppId& app_id,
+    content::WebContents* web_contents,
+    StoppedCallback stopped_callback,
+    bool hang_for_testing,
+    const AppRegistrar& registrar,
+    const AppIconManager& icon_manager,
+    WebAppUiManager* ui_manager,
+    InstallManager* install_manager,
+    OsIntegrationManager& os_integration_manager)
     : content::WebContentsObserver(web_contents),
       registrar_(registrar),
       icon_manager_(icon_manager),
       ui_manager_(*ui_manager),
       install_manager_(*install_manager),
+      os_integration_manager_(os_integration_manager),
       url_(url),
       app_id_(app_id),
       stopped_callback_(std::move(stopped_callback)),
@@ -126,6 +130,7 @@
     case Stage::kPendingWindowsClosed:
     case Stage::kPendingMaybeReadExistingIcons:
     case Stage::kPendingInstallation:
+    case Stage::kPendingAssociationsUpdate:
       // These stages should have stopped listening to the web contents.
       NOTREACHED();
       Observe(nullptr);
@@ -219,6 +224,12 @@
     return true;
   }
 
+  if (base::FeatureList::IsEnabled(blink::features::kWebAppEnableUrlHandlers) &&
+      web_application_info_->url_handlers !=
+          registrar_.GetAppUrlHandlers(app_id_)) {
+    return true;
+  }
+
   // TODO(crbug.com/1072058): Check the manifest URL.
   // TODO(crbug.com/926083): Check more manifest fields.
   return false;
@@ -236,7 +247,7 @@
 }
 
 void ManifestUpdateTask::LoadAndCheckIconContents() {
-  DCHECK(stage_ == Stage::kPendingInstallableData);
+  DCHECK_EQ(stage_, Stage::kPendingInstallableData);
   stage_ = Stage::kPendingIconDownload;
 
   DCHECK(web_application_info_.has_value());
@@ -252,7 +263,7 @@
 }
 
 void ManifestUpdateTask::OnIconsDownloaded(bool success, IconsMap icons_map) {
-  DCHECK(stage_ == Stage::kPendingIconDownload);
+  DCHECK_EQ(stage_, Stage::kPendingIconDownload);
 
   if (!success) {
     DestroySelf(ManifestUpdateResult::kIconDownloadFailed);
@@ -268,7 +279,7 @@
 
 void ManifestUpdateTask::OnAllIconsRead(IconsMap downloaded_icons_map,
                                         IconBitmaps disk_icon_bitmaps) {
-  DCHECK(stage_ == Stage::kPendingIconReadFromDisk);
+  DCHECK_EQ(stage_, Stage::kPendingIconReadFromDisk);
 
   if (disk_icon_bitmaps.empty()) {
     DestroySelf(ManifestUpdateResult::kIconReadFromDiskFailed);
@@ -312,7 +323,7 @@
         base::BindOnce(&ManifestUpdateTask::OnAllShortcutsMenuIconsRead,
                        AsWeakPtr()));
   } else {
-    DestroySelf(ManifestUpdateResult::kAppUpToDate);
+    NoManifestUpdateRequired();
   }
 }
 
@@ -325,7 +336,7 @@
 
 void ManifestUpdateTask::OnAllShortcutsMenuIconsRead(
     ShortcutsMenuIconBitmaps disk_shortcuts_menu_icon_bitmaps) {
-  DCHECK(stage_ == Stage::kPendingIconReadFromDisk);
+  DCHECK_EQ(stage_, Stage::kPendingIconReadFromDisk);
 
   DCHECK(web_application_info_.has_value());
 
@@ -335,7 +346,7 @@
     return;
   }
 
-  DestroySelf(ManifestUpdateResult::kAppUpToDate);
+  NoManifestUpdateRequired();
 }
 
 bool ManifestUpdateTask::IsUpdateNeededForShortcutsMenuIconsContents(
@@ -359,6 +370,39 @@
   return false;
 }
 
+bool ManifestUpdateTask::IsUpdateNeededForWebAppOriginAssociations() const {
+  // Web app origin association update is tied to the manifest update process.
+  // If there are url handlers for the current app, associations need to be
+  // revalidated.
+  DCHECK(web_application_info_.has_value());
+  if (base::FeatureList::IsEnabled(blink::features::kWebAppEnableUrlHandlers) &&
+      !web_application_info_->url_handlers.empty()) {
+    return true;
+  }
+
+  return false;
+}
+
+void ManifestUpdateTask::NoManifestUpdateRequired() {
+  DCHECK_EQ(stage_, Stage::kPendingIconReadFromDisk);
+  stage_ = Stage::kPendingAssociationsUpdate;
+  if (!IsUpdateNeededForWebAppOriginAssociations()) {
+    DestroySelf(ManifestUpdateResult::kAppUpToDate);
+    return;
+  }
+
+  os_integration_manager_.UpdateUrlHandlers(
+      app_id_,
+      base::BindOnce(&ManifestUpdateTask::OnWebAppOriginAssociationsUpdated,
+                     AsWeakPtr()));
+}
+
+void ManifestUpdateTask::OnWebAppOriginAssociationsUpdated(bool success) {
+  DCHECK_EQ(stage_, Stage::kPendingAssociationsUpdate);
+  success ? DestroySelf(ManifestUpdateResult::kAppAssociationsUpdated)
+          : DestroySelf(ManifestUpdateResult::kAppAssociationsUpdateFailed);
+}
+
 void ManifestUpdateTask::OnAllAppWindowsClosed() {
   DCHECK_EQ(stage_, Stage::kPendingWindowsClosed);
 
diff --git a/chrome/browser/web_applications/manifest_update_task.h b/chrome/browser/web_applications/manifest_update_task.h
index d99b336..cd5a8332 100644
--- a/chrome/browser/web_applications/manifest_update_task.h
+++ b/chrome/browser/web_applications/manifest_update_task.h
@@ -29,6 +29,7 @@
 class AppRegistrar;
 class WebAppUiManager;
 class InstallManager;
+class OsIntegrationManager;
 enum class InstallResultCode;
 
 // This enum is recorded by UMA, the numeric values must not change.
@@ -46,7 +47,9 @@
   kIconDownloadFailed = 10,
   kIconReadFromDiskFailed = 11,
   kAppIdMismatch = 12,
-  kMaxValue = kAppIdMismatch,
+  kAppAssociationsUpdateFailed = 13,
+  kAppAssociationsUpdated = 14,
+  kMaxValue = kAppAssociationsUpdated,
 };
 
 // Checks whether the installed web app associated with a given WebContents has
@@ -79,7 +82,8 @@
                      const AppRegistrar& registrar,
                      const AppIconManager& icon_manager,
                      WebAppUiManager* ui_manager,
-                     InstallManager* install_manager);
+                     InstallManager* install_manager,
+                     OsIntegrationManager& os_integration_manager);
 
   ~ManifestUpdateTask() override;
 
@@ -100,6 +104,7 @@
     kPendingWindowsClosed,
     kPendingMaybeReadExistingIcons,
     kPendingInstallation,
+    kPendingAssociationsUpdate,
   };
 
   void OnDidGetInstallableData(const webapps::InstallableData& data);
@@ -114,6 +119,9 @@
       ShortcutsMenuIconBitmaps disk_shortcuts_menu_icons);
   bool IsUpdateNeededForShortcutsMenuIconsContents(
       const ShortcutsMenuIconBitmaps& disk_shortcuts_menu_icons) const;
+  bool IsUpdateNeededForWebAppOriginAssociations() const;
+  void NoManifestUpdateRequired();
+  void OnWebAppOriginAssociationsUpdated(bool success);
   void UpdateAfterWindowsClose();
   void OnAllAppWindowsClosed();
   void OnExistingIconsRead(IconBitmaps icon_bitmaps);
@@ -126,6 +134,7 @@
   const AppIconManager& icon_manager_;
   WebAppUiManager& ui_manager_;
   InstallManager& install_manager_;
+  OsIntegrationManager& os_integration_manager_;
 
   Stage stage_;
   base::Optional<WebApplicationInfo> web_application_info_;
diff --git a/chrome/browser/web_applications/test/fake_url_handler_manager.cc b/chrome/browser/web_applications/test/fake_url_handler_manager.cc
index 0d076d7..eb25c495 100644
--- a/chrome/browser/web_applications/test/fake_url_handler_manager.cc
+++ b/chrome/browser/web_applications/test/fake_url_handler_manager.cc
@@ -23,8 +23,10 @@
   return true;
 }
 
-bool FakeUrlHandlerManager::UpdateUrlHandlers(const AppId& app_id) {
-  return true;
+void FakeUrlHandlerManager::UpdateUrlHandlers(
+    const AppId& app_id,
+    base::OnceCallback<void(bool success)> callback) {
+  std::move(callback).Run(true);
 }
 
 }  // namespace web_app
diff --git a/chrome/browser/web_applications/test/fake_url_handler_manager.h b/chrome/browser/web_applications/test/fake_url_handler_manager.h
index 8b27ef6..5fdc439 100644
--- a/chrome/browser/web_applications/test/fake_url_handler_manager.h
+++ b/chrome/browser/web_applications/test/fake_url_handler_manager.h
@@ -22,7 +22,9 @@
       const AppId& app_id,
       base::OnceCallback<void(bool success)> callback) override;
   bool UnregisterUrlHandlers(const AppId& app_id) override;
-  bool UpdateUrlHandlers(const AppId& app_id) override;
+  void UpdateUrlHandlers(
+      const AppId& app_id,
+      base::OnceCallback<void(bool success)> callback) override;
 };
 
 }  // namespace web_app
diff --git a/chrome/browser/web_applications/web_app_provider.cc b/chrome/browser/web_applications/web_app_provider.cc
index c51fd91..e1219b94 100644
--- a/chrome/browser/web_applications/web_app_provider.cc
+++ b/chrome/browser/web_applications/web_app_provider.cc
@@ -269,7 +269,8 @@
                                   install_finalizer_.get());
   manifest_update_manager_->SetSubsystems(
       registrar_.get(), icon_manager_.get(), ui_manager_.get(),
-      install_manager_.get(), system_web_app_manager_.get());
+      install_manager_.get(), system_web_app_manager_.get(),
+      os_integration_manager_.get());
   pending_app_manager_->SetSubsystems(
       registrar_.get(), os_integration_manager_.get(), ui_manager_.get(),
       install_finalizer_.get(), install_manager_.get());
diff --git a/chrome/install_static/install_util.cc b/chrome/install_static/install_util.cc
index fe82935..3f3cf4b 100644
--- a/chrome/install_static/install_util.cc
+++ b/chrome/install_static/install_util.cc
@@ -705,6 +705,11 @@
   return InstallDetails::Get().channel();
 }
 
+bool IsExtendedStableChannel() {
+  // TODO(https://crbug.com/1185621): Detect extended stable.
+  return false;
+}
+
 bool MatchPattern(const std::wstring& source, const std::wstring& pattern) {
   assert(pattern.find(L"**") == std::wstring::npos);
   return MatchPatternImpl(source, pattern, 0, 0);
diff --git a/chrome/install_static/install_util.h b/chrome/install_static/install_util.h
index 5e5342f..4acdd0d 100644
--- a/chrome/install_static/install_util.h
+++ b/chrome/install_static/install_util.h
@@ -245,6 +245,9 @@
 version_info::Channel GetChromeChannel();
 std::wstring GetChromeChannelName();
 
+// Returns true if the current Chrome process is on the extended stable channel.
+bool IsExtendedStableChannel();
+
 // Returns true if the |source| string matches the |pattern|. The pattern
 // may contain wildcards like '?', which matches one character or a '*'
 // which matches 0 or more characters.
diff --git a/chrome/installer/mac/signing/README.md b/chrome/installer/mac/signing/README.md
index 157f8ed3..4d22a94 100644
--- a/chrome/installer/mac/signing/README.md
+++ b/chrome/installer/mac/signing/README.md
@@ -68,9 +68,18 @@
 In addition, the Chromium [code sign
 config](https://cs.chromium.org/chromium/src/chrome/installer/mac/signing/chromium_config.py)
 only produces one Distribution to sign just the .app. An
-`is_chrome_build=true` build produces several Distributions for the official
+`is_chrome_branded=true` build produces several Distributions for the official
 release system.
 
+## Google Chrome
+
+If you attempt to sign an `is_chrome_branded=true` build locally, the app will
+fail to launch because certain entitlements are tied to the official Google code
+signing identity/certificate. To test an `is_chrome_branded=true` build locally,
+replace the contents of
+[`app-entitlements-chrome.plist`](../../../app/app-entitlements-chrome.plist) with
+an empty plist.
+
 ### System Detached Signatures
 
 MacOS may itself sign Chromium build binaries when it needs to record a
diff --git a/chrome/renderer/autofill/form_autofill_browsertest.cc b/chrome/renderer/autofill/form_autofill_browsertest.cc
index f48385c..9f4871d 100644
--- a/chrome/renderer/autofill/form_autofill_browsertest.cc
+++ b/chrome/renderer/autofill/form_autofill_browsertest.cc
@@ -277,10 +277,7 @@
 
 class FormAutofillTest : public ChromeRenderViewTest {
  public:
-  FormAutofillTest() : ChromeRenderViewTest() {
-    scoped_feature_list_.InitAndEnableFeature(
-        features::kAutofillRestrictUnownedFieldsToFormlessCheckout);
-  }
+  FormAutofillTest() : ChromeRenderViewTest() {}
   ~FormAutofillTest() override {}
 
 #if defined(OS_WIN)
@@ -666,20 +663,6 @@
     EXPECT_EQ(0, firstname.SelectionEnd());
   }
 
-  void TestUnmatchedUnownedForm(const char* html, const char* url_override) {
-    if (url_override)
-      LoadHTMLWithUrlOverride(html, url_override);
-    else
-      LoadHTML(html);
-
-    WebLocalFrame* web_frame = GetMainFrame();
-    ASSERT_NE(nullptr, web_frame);
-
-    FormCache form_cache(web_frame);
-    std::vector<FormData> forms = form_cache.ExtractNewForms(nullptr);
-    ASSERT_EQ(0U, forms.size());
-  }
-
   void TestFindFormForInputElement(const char* html, bool unowned) {
     LoadHTML(html);
     WebLocalFrame* web_frame = GetMainFrame();
@@ -3564,40 +3547,6 @@
   TestPreviewForm(kUnownedNonEnglishFormHtml, true, nullptr);
 }
 
-// Data that looks like an unowned form should NOT be matched unless an
-// additional indicator is present, such as title tag or url, to prevent false
-// positives. The fields that have an autocomplete attribute should match since
-// there is no chance of making a prediction error.
-
-TEST_F(FormAutofillTest, UnmatchedFormNoURL) {
-  TestUnmatchedUnownedForm(kUnownedUntitledFormHtml, nullptr);
-}
-
-TEST_F(FormAutofillTest, UnmatchedFormPathWithoutKeywords) {
-  TestUnmatchedUnownedForm(kUnownedUntitledFormHtml,
-                           "http://example.test/path_without_keywords");
-}
-
-TEST_F(FormAutofillTest, UnmatchedFormKeywordInQueryOnly) {
-  TestUnmatchedUnownedForm(kUnownedUntitledFormHtml,
-                           "http://example.test/search?q=checkout+in+query");
-}
-
-TEST_F(FormAutofillTest, UnmatchedFormTitleWithoutKeywords) {
-  std::string wrong_title_html(
-      "<TITLE>This title has nothing to do with autofill</TITLE>");
-  wrong_title_html += kUnownedUntitledFormHtml;
-  TestUnmatchedUnownedForm(wrong_title_html.c_str(), nullptr);
-}
-
-TEST_F(FormAutofillTest, UnmatchedFormNonASCII) {
-  std::string html("<HEAD><TITLE>Non-ASCII soft hyphen in the middle of "
-                   "keyword prevents a match here: check\xC2\xADout"
-                   "</TITLE></HEAD>");
-  html.append(kUnownedUntitledFormHtml);
-  TestUnmatchedUnownedForm(html.c_str(), nullptr);
-}
-
 
 TEST_F(FormAutofillTest, Labels) {
   ExpectJohnSmithLabelsAndIdAttributes(
@@ -5373,7 +5322,7 @@
   ASSERT_EQ(2U, fieldsets.size());
 
   FormData form;
-  EXPECT_TRUE(UnownedCheckoutFormElementsAndFieldSetsToFormData(
+  EXPECT_TRUE(UnownedFormElementsAndFieldSetsToFormData(
       fieldsets, control_elements, nullptr, frame->GetDocument(), nullptr,
       extract_mask, &form, nullptr));
 
@@ -5436,7 +5385,7 @@
   ASSERT_EQ(1U, fieldsets.size());
 
   FormData form;
-  EXPECT_TRUE(UnownedCheckoutFormElementsAndFieldSetsToFormData(
+  EXPECT_TRUE(UnownedFormElementsAndFieldSetsToFormData(
       fieldsets, control_elements, nullptr, frame->GetDocument(), nullptr,
       extract_mask, &form, nullptr));
 
@@ -5488,7 +5437,7 @@
   ASSERT_TRUE(fieldsets.empty());
 
   FormData form;
-  EXPECT_FALSE(UnownedCheckoutFormElementsAndFieldSetsToFormData(
+  EXPECT_FALSE(UnownedFormElementsAndFieldSetsToFormData(
       fieldsets, control_elements, nullptr, frame->GetDocument(), nullptr,
       extract_mask, &form, nullptr));
 }
@@ -5511,21 +5460,8 @@
   ASSERT_TRUE(fieldsets.empty());
 
   {
-    base::test::ScopedFeatureList feature_list;
-    feature_list.InitAndEnableFeature(
-        features::kAutofillRestrictUnownedFieldsToFormlessCheckout);
     FormData form;
-    EXPECT_FALSE(UnownedCheckoutFormElementsAndFieldSetsToFormData(
-        fieldsets, control_elements, nullptr, frame->GetDocument(), nullptr,
-        extract_mask, &form, nullptr));
-  }
-
-  {
-    base::test::ScopedFeatureList feature_list;
-    feature_list.InitAndDisableFeature(
-        features::kAutofillRestrictUnownedFieldsToFormlessCheckout);
-    FormData form;
-    EXPECT_TRUE(UnownedCheckoutFormElementsAndFieldSetsToFormData(
+    EXPECT_TRUE(UnownedFormElementsAndFieldSetsToFormData(
         fieldsets, control_elements, nullptr, frame->GetDocument(), nullptr,
         extract_mask, &form, nullptr));
   }
@@ -5535,29 +5471,28 @@
   struct {
     const char* description;
     const char* html;
-    const bool has_extracted_form;
+    const size_t number_of_extracted_forms;
     const bool is_form_tag;
-    const bool is_formless_checkout;
   } test_cases[] = {
       // An empty form should not be extracted
       {"Empty Form",
        "<FORM name='TestForm' action='http://abc.com' method='post'>"
        "</FORM>",
-       false, true, false},
+       0u, true},
       // A form with less than three fields with no autocomplete type(s) should
       // be extracted because no minimum is being enforced for upload.
       {"Small Form no autocomplete",
        "<FORM name='TestForm' action='http://abc.com' method='post'>"
        "  <INPUT type='text' id='firstname'/>"
        "</FORM>",
-       true, true, false},
+       1u, true},
       // A form with less than three fields with at least one autocomplete type
       // should be extracted.
       {"Small Form w/ autocomplete",
        "<FORM name='TestForm' action='http://abc.com' method='post'>"
        "  <INPUT type='text' id='firstname' autocomplete='given-name'/>"
        "</FORM>",
-       true, true, false},
+       1u, true},
       // A form with three or more fields should be extracted.
       {"3 Field Form",
        "<FORM name='TestForm' action='http://abc.com' method='post'>"
@@ -5566,33 +5501,32 @@
        "  <INPUT type='text' id='email'/>"
        "  <INPUT type='submit' value='Send'/>"
        "</FORM>",
-       true, true, false},
+       1u, true},
       // An input field with an autocomplete attribute outside of a form should
-      // be extracted. The is_formless_checkout attribute should
-      // then be true.
+      // be extracted.
       {"Small, formless, with autocomplete",
        "<INPUT type='text' id='firstname' autocomplete='given-name'/>"
        "<INPUT type='submit' value='Send'/>",
-       true, false, false},
+       1u, false},
       // An input field without an autocomplete attribute outside of a form,
       // with no checkout hints, should not be extracted.
       {"Small, formless, no autocomplete",
        "<INPUT type='text' id='firstname'/>"
        "<INPUT type='submit' value='Send'/>",
-       false, false, false},
+       1u, false},
       // A form with one field which is password gets extracted.
       {"Password-Only",
        "<FORM name='TestForm' action='http://abc.com' method='post'>"
        "  <INPUT type='password' id='pw'/>"
        "</FORM>",
-       true, true, false},
+       1u, true},
       // A form with two fields which are passwords should be extracted.
       {"two passwords",
        "<FORM name='TestForm' action='http://abc.com' method='post'>"
        "  <INPUT type='password' id='pw'/>"
        "  <INPUT type='password' id='new_pw'/>"
        "</FORM>",
-       true, true, false},
+       1u, true},
   };
 
   for (auto test_case : test_cases) {
@@ -5604,12 +5538,9 @@
 
     FormCache form_cache(web_frame);
     std::vector<FormData> forms = form_cache.ExtractNewForms(nullptr);
-    EXPECT_EQ(test_case.has_extracted_form, forms.size() == 1);
-
-    if (test_case.has_extracted_form) {
-      EXPECT_EQ(test_case.is_form_tag, forms[0].is_form_tag);
-      EXPECT_EQ(test_case.is_formless_checkout, forms[0].is_formless_checkout);
-    }
+    EXPECT_EQ(test_case.number_of_extracted_forms, forms.size());
+    if (!forms.empty())
+      EXPECT_EQ(test_case.is_form_tag, forms.back().is_form_tag);
   }
 }
 
diff --git a/chrome/renderer/autofill/form_control_click_detection_browsertest.cc b/chrome/renderer/autofill/form_control_click_detection_browsertest.cc
index eaa8874a..d81433d1 100644
--- a/chrome/renderer/autofill/form_control_click_detection_browsertest.cc
+++ b/chrome/renderer/autofill/form_control_click_detection_browsertest.cc
@@ -8,7 +8,6 @@
 #include "components/autofill/content/renderer/autofill_agent.h"
 #include "content/public/renderer/render_view.h"
 #include "testing/gtest/include/gtest/gtest.h"
-#include "third_party/blink/public/platform/web_size.h"
 #include "third_party/blink/public/web/web_document.h"
 #include "third_party/blink/public/web/web_frame_widget.h"
 #include "third_party/blink/public/web/web_input_element.h"
@@ -35,7 +34,7 @@
         "  <input type='button' id='button'></input><br>"
         "  <input type='button' id='button_2' disabled></input><br>"
         "</form>");
-    GetWebFrameWidget()->Resize(blink::WebSize(500, 500));
+    GetWebFrameWidget()->Resize(gfx::Size(500, 500));
     GetWebFrameWidget()->SetFocus(true);
     blink::WebDocument document = GetMainFrame()->GetDocument();
     text_ = document.GetElementById("text_1");
diff --git a/chrome/renderer/autofill/password_autofill_agent_browsertest.cc b/chrome/renderer/autofill/password_autofill_agent_browsertest.cc
index 49f243f5..e27ad01 100644
--- a/chrome/renderer/autofill/password_autofill_agent_browsertest.cc
+++ b/chrome/renderer/autofill/password_autofill_agent_browsertest.cc
@@ -390,7 +390,7 @@
     LoadHTML(kFormHTML);
 
     // Necessary for SimulateElementClick() to work correctly.
-    GetWebFrameWidget()->Resize(blink::WebSize(500, 500));
+    GetWebFrameWidget()->Resize(gfx::Size(500, 500));
     GetWebFrameWidget()->SetFocus(true);
 
     // Now retrieve the input elements so the test can access them.
diff --git a/chrome/services/sharing/nearby/platform/count_down_latch_unittest.cc b/chrome/services/sharing/nearby/platform/count_down_latch_unittest.cc
index 32d1dd6a..2fb943d 100644
--- a/chrome/services/sharing/nearby/platform/count_down_latch_unittest.cc
+++ b/chrome/services/sharing/nearby/platform/count_down_latch_unittest.cc
@@ -20,6 +20,7 @@
 #include "base/threading/platform_thread.h"
 #include "base/threading/thread_restrictions.h"
 #include "base/unguessable_token.h"
+#include "build/build_config.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace location {
@@ -142,8 +143,16 @@
   VerifyExceptionResultForAttemptId(attempt_id, Exception::kSuccess);
 }
 
+// TODO(crbug.com/1185706): Hangs on ChromeOS MSAN.
+#if defined(OS_CHROMEOS) && defined(MEMORY_SANITIZER)
+#define MAYBE_InitializeCount2_UnblocksAllBlockedThreadsWhenCountIsZero \
+  DISABLED_InitializeCount2_UnblocksAllBlockedThreadsWhenCountIsZero
+#else
+#define MAYBE_InitializeCount2_UnblocksAllBlockedThreadsWhenCountIsZero \
+  InitializeCount2_UnblocksAllBlockedThreadsWhenCountIsZero
+#endif
 TEST_F(CountDownLatchTest,
-       InitializeCount2_UnblocksAllBlockedThreadsWhenCountIsZero) {
+       MAYBE_InitializeCount2_UnblocksAllBlockedThreadsWhenCountIsZero) {
   InitializeCountDownLatch(2);
 
   base::RunLoop run_loop_1;
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn
index f1d6b10..40f287c 100644
--- a/chrome/test/BUILD.gn
+++ b/chrome/test/BUILD.gn
@@ -1095,7 +1095,6 @@
       "../browser/lifetime/browser_close_manager_browsertest.cc",
       "../browser/lifetime/browser_shutdown_browsertest.cc",
       "../browser/lite_video/lite_video_keyed_service_browsertest.cc",
-      "../browser/loader/cors_origin_access_list_browsertest.cc",
       "../browser/loader/signed_exchange_policy_browsertest.cc",
       "../browser/loadtimes_extension_bindings_browsertest.cc",
       "../browser/locale_tests_browsertest.cc",
diff --git a/chrome/test/base/test_browser_window.h b/chrome/test/base/test_browser_window.h
index 70833b3..10438e07 100644
--- a/chrome/test/base/test_browser_window.h
+++ b/chrome/test/base/test_browser_window.h
@@ -178,9 +178,11 @@
 
 #if defined(OS_CHROMEOS) || defined(OS_MAC) || defined(OS_WIN) || \
     defined(OS_LINUX)
-  void ShowHatsDialog(const std::string& site_id,
-                      base::OnceClosure success_callback,
-                      base::OnceClosure failure_callback) override {}
+  void ShowHatsDialog(
+      const std::string& site_id,
+      base::OnceClosure success_callback,
+      base::OnceClosure failure_callback,
+      const std::map<std::string, bool>& product_specific_data) override {}
 #endif
 
   ExclusiveAccessContext* GetExclusiveAccessContext() override;
diff --git a/chrome/test/base/testing_profile.cc b/chrome/test/base/testing_profile.cc
index 55dcc4d..349e3645 100644
--- a/chrome/test/base/testing_profile.cc
+++ b/chrome/test/base/testing_profile.cc
@@ -956,17 +956,6 @@
   return ChromeBrowsingDataRemoverDelegateFactory::GetForProfile(this);
 }
 
-void TestingProfile::SetCorsOriginAccessListForOrigin(
-    TargetBrowserContexts target_mode,
-    const url::Origin& source_origin,
-    std::vector<network::mojom::CorsOriginPatternPtr> allow_patterns,
-    std::vector<network::mojom::CorsOriginPatternPtr> block_patterns,
-    base::OnceClosure closure) {
-  // Extensions need to set the list, but just can be ignored unless they need
-  // to make actual network requests beyond the CORS policy.
-  base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, std::move(closure));
-}
-
 bool TestingProfile::WasCreatedByVersionOrLater(const std::string& version) {
   return true;
 }
diff --git a/chrome/test/base/testing_profile.h b/chrome/test/base/testing_profile.h
index 93cdee02..cd6a28a 100644
--- a/chrome/test/base/testing_profile.h
+++ b/chrome/test/base/testing_profile.h
@@ -316,12 +316,6 @@
   content::BackgroundSyncController* GetBackgroundSyncController() override;
   content::BrowsingDataRemoverDelegate* GetBrowsingDataRemoverDelegate()
       override;
-  void SetCorsOriginAccessListForOrigin(
-      TargetBrowserContexts target_mode,
-      const url::Origin& source_origin,
-      std::vector<network::mojom::CorsOriginPatternPtr> allow_patterns,
-      std::vector<network::mojom::CorsOriginPatternPtr> block_patterns,
-      base::OnceClosure closure) override;
 
   TestingProfile* AsTestingProfile() override;
 
diff --git a/chrome/test/data/hats/hats_next_mock.html b/chrome/test/data/hats/hats_next_mock.html
index 86d1cd8..7fdfed6 100644
--- a/chrome/test/data/hats/hats_next_mock.html
+++ b/chrome/test/data/hats/hats_next_mock.html
@@ -15,7 +15,16 @@
       // Watch for the testing trigger_id for HaTS Next, defined on the browser
       // side in hats_service.cc.
       if (params.get('trigger_id') == 'zishSVViB0kPN8UwQ150VGjBKuBP') {
-        history.pushState('', '', '#loaded');
+        // Check that the provided product specific data matches the values
+        // defined in hats_browsertest.cc, if it does provide a loaded response
+        // before closing.
+        const productSpecificData = JSON.parse(
+                  decodeURIComponent(params.get('product_specific_data')));
+        if (productSpecificData['Test Field 1'] === 'true' &&
+            productSpecificData['Test Field 2'] === 'false' &&
+            productSpecificData['Test Field 3'] === 'true') {
+          history.pushState('', '', '#loaded');
+        }
         history.pushState('', '', '#close');
       }
 
diff --git a/chrome/test/data/webui/chromeos/diagnostics/overview_card_test.js b/chrome/test/data/webui/chromeos/diagnostics/overview_card_test.js
index 4006ccb8..fc884377 100644
--- a/chrome/test/data/webui/chromeos/diagnostics/overview_card_test.js
+++ b/chrome/test/data/webui/chromeos/diagnostics/overview_card_test.js
@@ -5,9 +5,10 @@
 import 'chrome://diagnostics/overview_card.js';
 
 import {SystemInfo} from 'chrome://diagnostics/diagnostics_types.js';
-import {fakeSystemInfo, fakeSystemInfoWithTBD} from 'chrome://diagnostics/fake_data.js';
+import {fakeSystemInfo, fakeSystemInfoWithoutBoardName, fakeSystemInfoWithTBD} from 'chrome://diagnostics/fake_data.js';
 import {FakeSystemDataProvider} from 'chrome://diagnostics/fake_system_data_provider.js';
 import {getSystemDataProvider, setSystemDataProviderForTesting} from 'chrome://diagnostics/mojo_interface_provider.js';
+import {loadTimeData} from 'chrome://resources/js/load_time_data.m.js';
 
 import {assertEquals, assertFalse, assertTrue} from '../../chai_assert.js';
 import {flushTasks, isVisible} from '../../test_util.m.js';
@@ -68,6 +69,23 @@
     return initializeOverviewCard(fakeSystemInfoWithTBD).then(() => {
       assertFalse(isVisible(
           /** @type {!HTMLElement} */ (overviewElement.$$('#marketingName'))));
+
+      // Device info should not be surrounded by parentheses when the marketing
+      // name is hidden.
+      const deviceInfoText = overviewElement.$$('#deviceInfo').textContent;
+      assertTrue(deviceInfoText[0] !== '(');
+      assertTrue(deviceInfoText[deviceInfoText.length - 1] !== ')');
+    });
+  });
+
+  test('BoardNameMissing', () => {
+    return initializeOverviewCard(fakeSystemInfoWithoutBoardName).then(() => {
+      const versionInfo = loadTimeData.getStringF(
+          'versionInfo',
+          fakeSystemInfoWithoutBoardName.versionInfo.milestoneVersion);
+      assertEquals(
+          overviewElement.$$('#deviceInfo').textContent,
+          versionInfo[0].toUpperCase() + versionInfo.slice(1));
     });
   });
 }
diff --git a/chrome/test/data/webui/settings/chromeos/people_page_account_manager_test.js b/chrome/test/data/webui/settings/chromeos/people_page_account_manager_test.js
index 5987c5a..76654ae1 100644
--- a/chrome/test/data/webui/settings/chromeos/people_page_account_manager_test.js
+++ b/chrome/test/data/webui/settings/chromeos/people_page_account_manager_test.js
@@ -222,6 +222,10 @@
 
       const account = await browserProxy.whenCalled('removeAccount');
       assertEquals('456', account.id);
+      // Add account button should be in focus now.
+      assertEquals(
+          accountManager.$$('#add-account-button'),
+          accountManager.root.activeElement);
     });
 
     test('Deep link to remove account button', async () => {
diff --git a/chrome/test/data/webui/signin/BUILD.gn b/chrome/test/data/webui/signin/BUILD.gn
index 5135df15..4ad145c 100644
--- a/chrome/test/data/webui/signin/BUILD.gn
+++ b/chrome/test/data/webui/signin/BUILD.gn
@@ -19,6 +19,7 @@
     ":profile_card_menu_test",
     ":profile_customization_test",
     ":profile_picker_app_test",
+    ":profile_switch_test",
     ":profile_type_choice_test",
     ":test_dice_web_signin_intercept_browser_proxy",
     ":test_manage_profiles_browser_proxy",
@@ -93,6 +94,16 @@
   ]
 }
 
+js_library("profile_switch_test") {
+  deps = [
+    "..:chai_assert",
+    "..:test_browser_proxy.m",
+    "..:test_util.m",
+    "//chrome/browser/resources/signin/profile_picker:profile_switch",
+    "//ui/webui/resources/js:promise_resolver.m",
+  ]
+}
+
 js_library("test_dice_web_signin_intercept_browser_proxy") {
   deps = [
     "..:test_browser_proxy.m",
diff --git a/chrome/test/data/webui/signin/profile_switch_test.js b/chrome/test/data/webui/signin/profile_switch_test.js
new file mode 100644
index 0000000..709cec0
--- /dev/null
+++ b/chrome/test/data/webui/signin/profile_switch_test.js
@@ -0,0 +1,76 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+import 'chrome://profile-picker/lazy_load.js';
+
+import {ManageProfilesBrowserProxyImpl, ProfileState} from 'chrome://profile-picker/profile_picker.js';
+import {PromiseResolver} from 'chrome://resources/js/promise_resolver.m.js';
+
+import {assertEquals, assertFalse, assertTrue} from '../chai_assert.js';
+import {waitBeforeNextRender} from '../test_util.m.js';
+
+import {TestManageProfilesBrowserProxy} from './test_manage_profiles_browser_proxy.js';
+
+suite('ProfilePickerMainViewTest', function() {
+  /** @type {!ProfileSwitchElement} */
+  let profileSwitchElement;
+
+  /** @type {!TestManageProfilesBrowserProxy} */
+  let browserProxy;
+
+  /** @type {!PromiseResolver} */
+  let getSwitchProfilePromiseResolver;
+
+  setup(function() {
+    browserProxy = new TestManageProfilesBrowserProxy();
+    ManageProfilesBrowserProxyImpl.instance_ = browserProxy;
+    getSwitchProfilePromiseResolver = new PromiseResolver();
+    browserProxy.setGetSwitchProfilePromise(
+        getSwitchProfilePromiseResolver.promise);
+    document.body.innerHTML = '';
+    profileSwitchElement = /** @type {!ProfileSwitchElement} */ (
+        document.createElement('profile-switch'));
+    document.body.appendChild(profileSwitchElement);
+    return waitBeforeNextRender(profileSwitchElement);
+  });
+
+  test('getSwitchProfile', async function() {
+    assertTrue(profileSwitchElement.$$('#switchButton').disabled);
+
+    getSwitchProfilePromiseResolver.resolve(browserProxy.profileSample);
+    await browserProxy.whenCalled('getSwitchProfile');
+
+    assertFalse(profileSwitchElement.$$('#switchButton').disabled);
+    assertEquals(
+        profileSwitchElement.$$('img.profile-avatar').src.split('/').pop(),
+        'url');
+    assertEquals(profileSwitchElement.$$('#profileName').innerText, 'Work');
+    assertEquals(profileSwitchElement.$$('#gaiaName').innerText, 'Alice');
+  });
+
+  test('confirmSwitch', async function() {
+    getSwitchProfilePromiseResolver.resolve(browserProxy.profileSample);
+    await browserProxy.whenCalled('getSwitchProfile');
+
+    assertFalse(profileSwitchElement.$$('#switchButton').disabled);
+    profileSwitchElement.$$('#switchButton').click();
+    const [profilePath] = await browserProxy.whenCalled('confirmProfileSwitch');
+    assertEquals(profilePath, 'profile1');
+  });
+
+  test('cancelSwitch_beforeGetSwitchProfile', async function() {
+    assertFalse(profileSwitchElement.$$('#cancelButton').disabled);
+    profileSwitchElement.$$('#cancelButton').click();
+    await browserProxy.whenCalled('cancelProfileSwitch');
+  });
+
+  test('cancelSwitch_afterGetSwitchProfile', async function() {
+    getSwitchProfilePromiseResolver.resolve(browserProxy.profileSample);
+    await browserProxy.whenCalled('getSwitchProfile');
+
+    assertFalse(profileSwitchElement.$$('#cancelButton').disabled);
+    profileSwitchElement.$$('#cancelButton').click();
+    await browserProxy.whenCalled('cancelProfileSwitch');
+  });
+});
diff --git a/chrome/test/data/webui/signin/signin_browsertest.js b/chrome/test/data/webui/signin/signin_browsertest.js
index 54f6457..e6fcaa5 100644
--- a/chrome/test/data/webui/signin/signin_browsertest.js
+++ b/chrome/test/data/webui/signin/signin_browsertest.js
@@ -217,6 +217,23 @@
 
 /**
  * Test fixture for
+ * chrome/browser/resources/signin/profile_picker/profile_switch.js.
+ * This has to be declared as a variable for TEST_F to find it correctly.
+ */
+// eslint-disable-next-line no-var
+var ProfileSwitchTest = class extends SigninBrowserTest {
+  /** @override */
+  get browsePreload() {
+    return 'chrome://profile-picker/test_loader.html?module=signin/profile_switch_test.js';
+  }
+};
+
+TEST_F('ProfileSwitchTest', 'All', function() {
+  mocha.run();
+});
+
+/**
+ * Test fixture for
  * chrome/browser/resources/signin/profile_customization/profile_customization_app.html.
  * This has to be declared as a variable for TEST_F to find it correctly.
  */
diff --git a/chrome/test/data/webui/signin/test_manage_profiles_browser_proxy.js b/chrome/test/data/webui/signin/test_manage_profiles_browser_proxy.js
index 2896af2..af077c7 100644
--- a/chrome/test/data/webui/signin/test_manage_profiles_browser_proxy.js
+++ b/chrome/test/data/webui/signin/test_manage_profiles_browser_proxy.js
@@ -24,6 +24,9 @@
       'setProfileName',
       'recordSignInPromoImpression',
       'getAvailableIcons',
+      'getSwitchProfile',
+      'confirmProfileSwitch',
+      'cancelProfileSwitch',
     ]);
 
     /** @type {!AutogeneratedThemeColorInfo} */
@@ -47,6 +50,12 @@
       isManaged: false,
       avatarIcon: 'url',
     };
+
+    /**
+     * The promise to return from `getSwitchProfile()`.
+     * @private {?Promise}
+     */
+    this.getSwitchProfilePromise_ = null;
   }
 
   /** @param {!AutogeneratedThemeColorInfo} profileThemeInfo */
@@ -54,6 +63,11 @@
     this.profileThemeInfo = profileThemeInfo;
   }
 
+  /** @param {!Promise} promise */
+  setGetSwitchProfilePromise(promise) {
+    this.getSwitchProfilePromise_ = promise;
+  }
+
   /** @override */
   initializeMainView() {
     this.methodCalled('initializeMainView');
@@ -132,4 +146,20 @@
       {url: 'fake-icon-3.png', label: 'fake-icon-3', index: 3, selected: false},
     ]);
   }
+
+  /** @override */
+  getSwitchProfile() {
+    this.methodCalled('getSwitchProfile');
+    return this.getSwitchProfilePromise_ || Promise.resolve(this.profileSample);
+  }
+
+  /** @override */
+  confirmProfileSwitch(profilePath) {
+    this.methodCalled('confirmProfileSwitch', [profilePath]);
+  }
+
+  /** @override */
+  cancelProfileSwitch() {
+    this.methodCalled('cancelProfileSwitch');
+  }
 }
diff --git a/chromecast/browser/DEPS b/chromecast/browser/DEPS
index af5fb06..c9667099 100644
--- a/chromecast/browser/DEPS
+++ b/chromecast/browser/DEPS
@@ -88,14 +88,8 @@
   # TODO(slan): Remove this when the network service is shipped on Cast.
   "+services/network",
 
-  # Needed to insert video plane callback.
-  # TODO(halliwell): Need to re-work this dependency otherwise Cast can't run
-  # with Viz out of process.
-  "+components/viz/service/display/overlay_strategy_underlay_cast.h",
-  # TODO(guohuideng): 1. When Display Compositor is fully moved to GPU process,
-  # remove the above dependency on "overlay_strategy_underlay_cast.h".
-  # 2. Separate SetGeometry from VideoPlaneController, and get rid of the
-  # dependency on.
+  # TODO(guohuideng): Separate SetGeometry from VideoPlaneController, and get
+  # rid of the dependency on cast_renderer.h.
   "+chromecast/media/service/cast_renderer.h",
 
   # For favicon url
diff --git a/chromecast/browser/cast_browser_context.cc b/chromecast/browser/cast_browser_context.cc
index f9018f6b..ae2a026 100644
--- a/chromecast/browser/cast_browser_context.cc
+++ b/chromecast/browser/cast_browser_context.cc
@@ -7,7 +7,6 @@
 #include <memory>
 #include <utility>
 
-#include "base/barrier_closure.h"
 #include "base/command_line.h"
 #include "base/files/file_util.h"
 #include "base/macros.h"
@@ -19,9 +18,7 @@
 #include "components/keyed_service/core/simple_key_map.h"
 #include "content/public/browser/browser_task_traits.h"
 #include "content/public/browser/browser_thread.h"
-#include "content/public/browser/cors_origin_pattern_setter.h"
 #include "content/public/browser/resource_context.h"
-#include "content/public/browser/shared_cors_origin_access_list.h"
 #include "content/public/browser/storage_partition.h"
 #include "content/public/common/content_switches.h"
 
@@ -32,8 +29,6 @@
 const void* const kDownloadManagerDelegateKey = &kDownloadManagerDelegateKey;
 }  // namespace
 
-using content::CorsOriginPatternSetter;
-
 class CastBrowserContext::CastResourceContext
     : public content::ResourceContext {
  public:
@@ -45,9 +40,7 @@
 };
 
 CastBrowserContext::CastBrowserContext()
-    : resource_context_(new CastResourceContext),
-      shared_cors_origin_access_list_(
-          content::SharedCorsOriginAccessList::Create()) {
+    : resource_context_(new CastResourceContext) {
   InitWhileIOAllowed();
   simple_factory_key_ =
       std::make_unique<SimpleFactoryKey>(GetPath(), IsOffTheRecord());
@@ -156,32 +149,5 @@
   return nullptr;
 }
 
-void CastBrowserContext::SetCorsOriginAccessListForOrigin(
-    TargetBrowserContexts target_mode,
-    const url::Origin& source_origin,
-    std::vector<network::mojom::CorsOriginPatternPtr> allow_patterns,
-    std::vector<network::mojom::CorsOriginPatternPtr> block_patterns,
-    base::OnceClosure closure) {
-  auto barrier_closure = BarrierClosure(2, std::move(closure));
-
-  // Keep profile storage partitions' NetworkContexts synchronized.
-  base::MakeRefCounted<CorsOriginPatternSetter>(
-      source_origin, CorsOriginPatternSetter::ClonePatterns(allow_patterns),
-      CorsOriginPatternSetter::ClonePatterns(block_patterns), barrier_closure)
-      ->ApplyToEachStoragePartition(this);
-
-  // Keep the per-profile access list up to date so that we can use this to
-  // restore NetworkContext settings at anytime, e.g. on restarting the
-  // network service.
-  shared_cors_origin_access_list_->SetForOrigin(
-      source_origin, std::move(allow_patterns), std::move(block_patterns),
-      barrier_closure);
-}
-
-content::SharedCorsOriginAccessList*
-CastBrowserContext::GetSharedCorsOriginAccessList() {
-  return shared_cors_origin_access_list_.get();
-}
-
 }  // namespace shell
 }  // namespace chromecast
diff --git a/chromecast/browser/cast_browser_context.h b/chromecast/browser/cast_browser_context.h
index add7423..a0bb9e3 100644
--- a/chromecast/browser/cast_browser_context.h
+++ b/chromecast/browser/cast_browser_context.h
@@ -46,13 +46,6 @@
   content::BackgroundSyncController* GetBackgroundSyncController() override;
   content::BrowsingDataRemoverDelegate* GetBrowsingDataRemoverDelegate()
       override;
-  void SetCorsOriginAccessListForOrigin(
-      TargetBrowserContexts target_mode,
-      const url::Origin& source_origin,
-      std::vector<network::mojom::CorsOriginPatternPtr> allow_patterns,
-      std::vector<network::mojom::CorsOriginPatternPtr> block_patterns,
-      base::OnceClosure closure) override;
-  content::SharedCorsOriginAccessList* GetSharedCorsOriginAccessList() override;
 
  private:
   class CastResourceContext;
@@ -65,8 +58,6 @@
   std::unique_ptr<CastResourceContext> resource_context_;
   std::unique_ptr<content::PermissionControllerDelegate> permission_manager_;
   std::unique_ptr<SimpleFactoryKey> simple_factory_key_;
-  scoped_refptr<content::SharedCorsOriginAccessList>
-      shared_cors_origin_access_list_;
 
   DISALLOW_COPY_AND_ASSIGN(CastBrowserContext);
 };
diff --git a/chromecast/browser/cast_browser_main_parts.cc b/chromecast/browser/cast_browser_main_parts.cc
index a9131339..e12788d 100644
--- a/chromecast/browser/cast_browser_main_parts.cc
+++ b/chromecast/browser/cast_browser_main_parts.cc
@@ -112,7 +112,6 @@
 #include "components/ui_devtools/devtools_server.h"  // nogncheck
 #include "components/ui_devtools/switches.h"         // nogncheck
 #endif
-#include "components/viz/service/display/overlay_strategy_underlay_cast.h"  // nogncheck
 #include "ui/display/screen.h"
 #include "ui/views/views_delegate.h"  // nogncheck
 #else
@@ -580,11 +579,6 @@
   video_plane_controller_.reset(new media::VideoPlaneController(
       Size(display_size.width(), display_size.height()),
       cast_content_browser_client_->GetMediaTaskRunner()));
-  // TODO(crbug.com/925450): Once compositor migrates to GPU process, We
-  // don't need to set the callback in viz::OverlayStrategyUnderlayCast.
-  viz::OverlayStrategyUnderlayCast::SetOverlayCompositedCallback(
-      base::BindRepeating(&media::VideoPlaneController::SetGeometry,
-                          base::Unretained(video_plane_controller_.get())));
   media::CastRenderer::SetOverlayCompositedCallback(BindToCurrentThread(
       base::BindRepeating(&media::VideoPlaneController::SetGeometry,
                           base::Unretained(video_plane_controller_.get()))));
diff --git a/chromecast/browser/webview/webview_browser_context.cc b/chromecast/browser/webview/webview_browser_context.cc
index 08bf430e..bb44ef4 100644
--- a/chromecast/browser/webview/webview_browser_context.cc
+++ b/chromecast/browser/webview/webview_browser_context.cc
@@ -100,11 +100,6 @@
   return nullptr;
 }
 
-content::SharedCorsOriginAccessList*
-WebviewBrowserContext::GetSharedCorsOriginAccessList() {
-  return main_browser_context_->GetSharedCorsOriginAccessList();
-}
-
 std::unique_ptr<content::ZoomLevelDelegate>
 WebviewBrowserContext::CreateZoomLevelDelegate(const base::FilePath&) {
   return nullptr;
diff --git a/chromecast/browser/webview/webview_browser_context.h b/chromecast/browser/webview/webview_browser_context.h
index 235f6525..2880ae32 100644
--- a/chromecast/browser/webview/webview_browser_context.h
+++ b/chromecast/browser/webview/webview_browser_context.h
@@ -36,7 +36,6 @@
   content::BackgroundSyncController* GetBackgroundSyncController() override;
   content::BrowsingDataRemoverDelegate* GetBrowsingDataRemoverDelegate()
       override;
-  content::SharedCorsOriginAccessList* GetSharedCorsOriginAccessList() override;
   std::unique_ptr<content::ZoomLevelDelegate> CreateZoomLevelDelegate(
       const base::FilePath&) override;
 
diff --git a/chromeos/chromeos_strings.grd b/chromeos/chromeos_strings.grd
index 87a682b..0c26a3074 100644
--- a/chromeos/chromeos_strings.grd
+++ b/chromeos/chromeos_strings.grd
@@ -712,7 +712,10 @@
         Learn more
       </message>
       <message name="IDS_DIAGNOSTICS_DEVICE_INFO_TEXT" desc="The text that displays the device's name and milestone version.">
-        (<ph name="BOARD_NAME">$1<ex>Atlas</ex></ph>, version <ph name="MILESTONE_VERSION">$2<ex>88</ex></ph>)
+        <ph name="BOARD_NAME">$1<ex>Atlas</ex></ph>, version <ph name="MILESTONE_VERSION">$2<ex>88</ex></ph>
+      </message>
+      <message name="IDS_DIAGNOSTICS_VERSION_INFO_TEXT" desc="The text that displays the device's milestone version. Substring of 'Atlas, version 88'">
+        version <ph name="MILESTONE_VERSION">$1<ex>88</ex></ph>
       </message>
       <message name="IDS_DIAGNOSTICS_BATTERY_HEALTH_TOOLTIP_TEXT" desc="The tooltip that states that battery capacity declines with usage.">
         Battery capacity declines with usage
diff --git a/chromeos/chromeos_strings_grd/IDS_DIAGNOSTICS_DEVICE_INFO_TEXT.png.sha1 b/chromeos/chromeos_strings_grd/IDS_DIAGNOSTICS_DEVICE_INFO_TEXT.png.sha1
index c4d6943d..913eb44 100644
--- a/chromeos/chromeos_strings_grd/IDS_DIAGNOSTICS_DEVICE_INFO_TEXT.png.sha1
+++ b/chromeos/chromeos_strings_grd/IDS_DIAGNOSTICS_DEVICE_INFO_TEXT.png.sha1
@@ -1 +1 @@
-4e13946ab4d1e7f76f40c3c1c488630c10219e2c
\ No newline at end of file
+3854f1f55068ced4d1b4643212771dc01fbe35d8
\ No newline at end of file
diff --git a/chromeos/chromeos_strings_grd/IDS_DIAGNOSTICS_VERSION_INFO_TEXT.png.sha1 b/chromeos/chromeos_strings_grd/IDS_DIAGNOSTICS_VERSION_INFO_TEXT.png.sha1
new file mode 100644
index 0000000..28eec13
--- /dev/null
+++ b/chromeos/chromeos_strings_grd/IDS_DIAGNOSTICS_VERSION_INFO_TEXT.png.sha1
@@ -0,0 +1 @@
+11b316332921b5cd5c7650335d7a255e90d6c0b0
\ No newline at end of file
diff --git a/chromeos/components/diagnostics_ui/diagnostics_ui.cc b/chromeos/components/diagnostics_ui/diagnostics_ui.cc
index 4891807..d4f4ca9 100644
--- a/chromeos/components/diagnostics_ui/diagnostics_ui.cc
+++ b/chromeos/components/diagnostics_ui/diagnostics_ui.cc
@@ -47,6 +47,7 @@
       {"batteryHealthText", IDS_DIAGNOSTICS_BATTERY_HEALTH_TEXT},
       {"batteryHealthTooltipText", IDS_DIAGNOSTICS_BATTERY_HEALTH_TOOLTIP_TEXT},
       {"batteryTitle", IDS_DIAGNOSTICS_BATTERY_TITLE},
+      {"boardAndVersionInfo", IDS_DIAGNOSTICS_DEVICE_INFO_TEXT},
       {"chargeTestResultText", IDS_CHARGE_TEST_RESULT},
       {"cpuCacheRoutineText", IDS_DIAGNOSTICS_CPU_CACHE_ROUTINE_TEXT},
       {"cpuChipText", IDS_DIAGNOSTICS_CPU_CHIP_TEXT},
@@ -70,7 +71,6 @@
       {"currentNowTooltipText", IDS_DIAGNOSTICS_CURRENT_NOW_TOOLTIP_TEXT},
       {"cycleCount", IDS_DIAGNOSTICS_CYCLE_COUNT_LABEL},
       {"cycleCountTooltipText", IDS_DIAGNOSTICS_CYCLE_COUNT_TOOLTIP_TEXT},
-      {"deviceInfo", IDS_DIAGNOSTICS_DEVICE_INFO_TEXT},
       {"diagnosticsTitle", IDS_DIAGNOSTICS_TITLE},
       {"dischargeTestResultText", IDS_DISCHARGE_TEST_RESULT},
       {"hideReportText", IDS_DIAGNOSTICS_HIDE_REPORT_TEXT},
@@ -110,6 +110,7 @@
       {"testStoppedBadgeText", IDS_DIAGNOSTICS_TEST_STOPPED_BADGE_TEXT},
       {"testSuccess", IDS_DIAGNOSTICS_TEST_SUCCESS_TEXT},
       {"testSucceededBadgeText", IDS_DIAGNOSTICS_TEST_SUCCESS_BADGE_TEXT},
+      {"versionInfo", IDS_DIAGNOSTICS_VERSION_INFO_TEXT},
   };
   html_source->AddLocalizedStrings(kLocalizedStrings);
   html_source->UseStringsJs();
diff --git a/chromeos/components/diagnostics_ui/resources/fake_data.js b/chromeos/components/diagnostics_ui/resources/fake_data.js
index f1a51909..da7d294 100644
--- a/chromeos/components/diagnostics_ui/resources/fake_data.js
+++ b/chromeos/components/diagnostics_ui/resources/fake_data.js
@@ -198,6 +198,17 @@
   versionInfo: {milestoneVersion: 'M99'},
 };
 
+/** @type {!SystemInfo} */
+export const fakeSystemInfoWithoutBoardName = {
+  boardName: '',
+  cpuModelName: 'BestCpu SoFast 1000',
+  cpuThreadsCount: 8,
+  cpuMaxClockSpeedKhz: 1000,
+  deviceCapabilities: {hasBattery: true},
+  marketingName: 'TBD',
+  totalMemoryKib: 128000,
+  versionInfo: {milestoneVersion: 'M99'},
+};
 /** @type {!Map<!RoutineType, !StandardRoutineResult>} */
 export const fakeRoutineResults = new Map([
   [
diff --git a/chromeos/components/diagnostics_ui/resources/overview_card.js b/chromeos/components/diagnostics_ui/resources/overview_card.js
index 33addbd..98254a9 100644
--- a/chromeos/components/diagnostics_ui/resources/overview_card.js
+++ b/chromeos/components/diagnostics_ui/resources/overview_card.js
@@ -65,9 +65,23 @@
 
   /** @private */
   getDeviceInfo_() {
-    return loadTimeData.getStringF(
-        'deviceInfo', this.systemInfo_.boardName,
-        this.systemInfo_.versionInfo.milestoneVersion);
+    const marketingNameValid = !this.shouldHideMarketingName_();
+    const boardName = this.systemInfo_.boardName;
+    const milestoneVersion = this.systemInfo_.versionInfo.milestoneVersion;
+
+    if (!boardName && !marketingNameValid) {
+      const versionInfo =
+          loadTimeData.getStringF('versionInfo', milestoneVersion);
+      // Capitalize "v" in "version" if board and marketing name are missing.
+      return versionInfo[0].toUpperCase() + versionInfo.slice(1);
+    }
+
+    let deviceInfo = this.systemInfo_.boardName ?
+        loadTimeData.getStringF(
+            'boardAndVersionInfo', this.systemInfo_.boardName,
+            milestoneVersion) :
+        loadTimeData.getStringF('versionInfo', milestoneVersion);
+    return marketingNameValid ? `(${deviceInfo})` : deviceInfo;
   },
 
   /**
@@ -75,6 +89,7 @@
    * @return {boolean}
    */
   shouldHideMarketingName_() {
-    return this.systemInfo_.marketingName === 'TBD';
+    return this.systemInfo_.marketingName === 'TBD' ||
+        this.systemInfo_.marketingName === '';
   },
 });
diff --git a/chromeos/services/assistant/assistant_manager_service_impl.cc b/chromeos/services/assistant/assistant_manager_service_impl.cc
index 267c3ea..f4bdbb1 100644
--- a/chromeos/services/assistant/assistant_manager_service_impl.cc
+++ b/chromeos/services/assistant/assistant_manager_service_impl.cc
@@ -524,30 +524,6 @@
   receive_url_response_ = url.spec();
 }
 
-void AssistantManagerServiceImpl::OnScheduleWait(int id, int time_ms) {
-  ENSURE_MAIN_THREAD(&AssistantManagerServiceImpl::OnScheduleWait, id, time_ms);
-  DCHECK(features::IsWaitSchedulingEnabled());
-
-  // Schedule a wait for |time_ms|, notifying the CrosActionModule when the wait
-  // has finished so that it can inform LibAssistant to resume execution.
-  main_task_runner()->PostDelayedTask(
-      FROM_HERE,
-      base::BindOnce(
-          [](const base::WeakPtr<AssistantManagerServiceImpl>& weak_ptr,
-             int id) {
-            if (weak_ptr && weak_ptr->action_module()) {
-              weak_ptr->action_module()->OnScheduledWaitDone(
-                  id, /*cancelled=*/false);
-            }
-          },
-          weak_factory_.GetWeakPtr(), id),
-      base::TimeDelta::FromMilliseconds(time_ms));
-
-  // Notify subscribers that a wait has been started.
-  for (auto& it : interaction_subscribers_)
-    it.OnWaitStarted();
-}
-
 void AssistantManagerServiceImpl::OnShowNotification(
     const action::Notification& notification) {
   ENSURE_MAIN_THREAD(&AssistantManagerServiceImpl::OnShowNotification,
diff --git a/chromeos/services/assistant/assistant_manager_service_impl.h b/chromeos/services/assistant/assistant_manager_service_impl.h
index 42d0e17..ea2d67e 100644
--- a/chromeos/services/assistant/assistant_manager_service_impl.h
+++ b/chromeos/services/assistant/assistant_manager_service_impl.h
@@ -173,7 +173,6 @@
   void AddRemoteConversationObserver(ConversationObserver* observer) override;
 
   // AssistantActionObserver overrides:
-  void OnScheduleWait(int id, int time_ms) override;
   void OnShowNotification(const action::Notification& notification) override;
   void OnVerifyAndroidApp(const std::vector<AndroidAppInfo>& apps_info,
                           const InteractionInfo& interaction) override;
diff --git a/chromeos/services/assistant/public/cpp/assistant_service.h b/chromeos/services/assistant/public/cpp/assistant_service.h
index 8becf97..f9d4e0b26 100644
--- a/chromeos/services/assistant/public/cpp/assistant_service.h
+++ b/chromeos/services/assistant/public/cpp/assistant_service.h
@@ -55,10 +55,6 @@
 
   // Assistant got an instantaneous speech level update in dB.
   virtual void OnSpeechLevelUpdated(float speech_level) {}
-
-  // Assistant has started waiting. This occur during execution of a routine to
-  // give the user time to digest a response before continuing execution.
-  virtual void OnWaitStarted() {}
 };
 
 class COMPONENT_EXPORT(ASSISTANT_SERVICE_PUBLIC) Assistant {
diff --git a/chromeos/services/assistant/public/cpp/conversation_observer.h b/chromeos/services/assistant/public/cpp/conversation_observer.h
index 601d977..91ea183 100644
--- a/chromeos/services/assistant/public/cpp/conversation_observer.h
+++ b/chromeos/services/assistant/public/cpp/conversation_observer.h
@@ -29,6 +29,7 @@
       const std::vector<AssistantSuggestion>& suggestions) override {}
   void OnOpenUrlResponse(const GURL& url, bool in_background) override {}
   void OnOpenAppResponse(const AndroidAppInfo& app_info) override {}
+  void OnWaitStarted() override {}
   void OnNotificationRemoved(const std::string& id) override {}
   void OnAllNotificationsRemoved() override {}
 
diff --git a/chromeos/services/libassistant/conversation_controller.cc b/chromeos/services/libassistant/conversation_controller.cc
index 2577a1d..5e23278 100644
--- a/chromeos/services/libassistant/conversation_controller.cc
+++ b/chromeos/services/libassistant/conversation_controller.cc
@@ -372,6 +372,30 @@
       [](auto) {});
 }
 
+void ConversationController::OnScheduleWait(int id, int time_ms) {
+  ENSURE_MOJOM_THREAD(&ConversationController::OnScheduleWait, id, time_ms);
+
+  DCHECK(assistant::features::IsWaitSchedulingEnabled());
+
+  // Schedule a wait for |time_ms|, notifying the CrosActionModule when the wait
+  // has finished so that it can inform LibAssistant to resume execution.
+  mojom_task_runner_->PostDelayedTask(
+      FROM_HERE,
+      base::BindOnce(
+          [](const base::WeakPtr<ConversationController>& weak_ptr, int id) {
+            if (weak_ptr) {
+              weak_ptr->action_module_->OnScheduledWaitDone(
+                  id, /*cancelled=*/false);
+            }
+          },
+          weak_factory_.GetWeakPtr(), id),
+      base::TimeDelta::FromMilliseconds(time_ms));
+
+  // Notify subscribers that a wait has been started.
+  for (auto& observer : observers_)
+    observer->OnWaitStarted();
+}
+
 void ConversationController::SendVoicelessInteraction(
     const std::string& interaction,
     const std::string& description,
diff --git a/chromeos/services/libassistant/conversation_controller.h b/chromeos/services/libassistant/conversation_controller.h
index 022eff7a..958b47f 100644
--- a/chromeos/services/libassistant/conversation_controller.h
+++ b/chromeos/services/libassistant/conversation_controller.h
@@ -78,6 +78,7 @@
   void OnOpenAndroidApp(
       const chromeos::assistant::AndroidAppInfo& app_info,
       const chromeos::assistant::InteractionInfo& interaction) override;
+  void OnScheduleWait(int id, int time_ms) override;
 
   const mojo::RemoteSet<mojom::ConversationObserver>* conversation_observers() {
     return &observers_;
diff --git a/chromeos/services/libassistant/conversation_observer_unittest.cc b/chromeos/services/libassistant/conversation_observer_unittest.cc
index 57738694..7d19ae6e 100644
--- a/chromeos/services/libassistant/conversation_observer_unittest.cc
+++ b/chromeos/services/libassistant/conversation_observer_unittest.cc
@@ -58,6 +58,11 @@
       observer->OnOpenAndroidApp(app_info, info);
   }
 
+  void ScheduleWait() {
+    for (auto* observer : action_observers())
+      observer->OnScheduleWait(/*id=*/012, /*time_ms=*/123);
+  }
+
  private:
   const std::vector<assistant::action::AssistantActionObserver*>&
   action_observers() {
@@ -96,6 +101,7 @@
   MOCK_METHOD(void,
               OnOpenAppResponse,
               (const chromeos::assistant::AndroidAppInfo& app_info));
+  MOCK_METHOD(void, OnWaitStarted, ());
 
   mojo::PendingRemote<mojom::ConversationObserver> BindNewPipeAndPassRemote() {
     return receiver_.BindNewPipeAndPassRemote();
@@ -251,5 +257,12 @@
   observer_mock().FlushForTesting();
 }
 
+TEST_F(ConversationObserverTest, ShouldReceiveOnWaitStarted) {
+  EXPECT_CALL(observer_mock(), OnWaitStarted());
+
+  action_module_helper().ScheduleWait();
+  observer_mock().FlushForTesting();
+}
+
 }  // namespace libassistant
 }  // namespace chromeos
diff --git a/chromeos/services/libassistant/libassistant_service.cc b/chromeos/services/libassistant/libassistant_service.cc
index 5981bd4..8e5ae23 100644
--- a/chromeos/services/libassistant/libassistant_service.cc
+++ b/chromeos/services/libassistant/libassistant_service.cc
@@ -9,16 +9,6 @@
 
 #include "base/check.h"
 #include "base/logging.h"
-#include "chromeos/services/libassistant/audio_input_controller.h"
-#include "chromeos/services/libassistant/conversation_controller.h"
-#include "chromeos/services/libassistant/conversation_state_listener_impl.h"
-#include "chromeos/services/libassistant/display_controller.h"
-#include "chromeos/services/libassistant/media_controller.h"
-#include "chromeos/services/libassistant/platform_api.h"
-#include "chromeos/services/libassistant/service_controller.h"
-#include "chromeos/services/libassistant/settings_controller.h"
-#include "chromeos/services/libassistant/speaker_id_enrollment_controller.h"
-#include "chromeos/services/libassistant/timer_controller.h"
 
 namespace chromeos {
 namespace libassistant {
@@ -27,49 +17,39 @@
     mojo::PendingReceiver<mojom::LibassistantService> receiver,
     assistant::AssistantManagerServiceDelegate* delegate)
     : receiver_(this, std::move(receiver)),
-      platform_api_(std::make_unique<PlatformApi>()),
-      audio_input_controller_(std::make_unique<AudioInputController>()),
-      service_controller_(
-          std::make_unique<ServiceController>(delegate, platform_api_.get())),
-      conversation_controller_(
-          std::make_unique<ConversationController>(service_controller_.get())),
+      platform_api_(),
+      audio_input_controller_(),
+      service_controller_(delegate, &platform_api_),
+      conversation_controller_(&service_controller_),
       conversation_state_listener_(
-          std::make_unique<ConversationStateListenerImpl>(
-              &speech_recognition_observers_,
-              conversation_controller_->conversation_observers(),
-              audio_input_controller_.get())),
-      display_controller_(
-          std::make_unique<DisplayController>(&speech_recognition_observers_)),
-      media_controller_(std::make_unique<MediaController>()),
-      settings_controller_(std::make_unique<SettingsController>()),
-      speaker_id_enrollment_controller_(
-          std::make_unique<SpeakerIdEnrollmentController>(
-              audio_input_controller_.get())),
-      timer_controller_(std::make_unique<TimerController>()) {
-  service_controller_->AddAndFireAssistantManagerObserver(
-      conversation_controller_.get());
-  service_controller_->AddAndFireAssistantManagerObserver(
-      conversation_state_listener_.get());
-  service_controller_->AddAndFireAssistantManagerObserver(
-      display_controller_.get());
-  service_controller_->AddAndFireAssistantManagerObserver(
-      media_controller_.get());
-  service_controller_->AddAndFireAssistantManagerObserver(
-      speaker_id_enrollment_controller_.get());
-  service_controller_->AddAndFireAssistantManagerObserver(
-      settings_controller_.get());
-  service_controller_->AddAndFireAssistantManagerObserver(
-      timer_controller_.get());
+          &speech_recognition_observers_,
+          conversation_controller_.conversation_observers(),
+          &audio_input_controller_),
+      display_controller_(&speech_recognition_observers_),
+      media_controller_(),
+      settings_controller_(),
+      speaker_id_enrollment_controller_(&audio_input_controller_),
+      timer_controller_() {
+  service_controller_.AddAndFireAssistantManagerObserver(
+      &conversation_controller_);
+  service_controller_.AddAndFireAssistantManagerObserver(
+      &conversation_state_listener_);
+  service_controller_.AddAndFireAssistantManagerObserver(&display_controller_);
+  service_controller_.AddAndFireAssistantManagerObserver(&media_controller_);
+  service_controller_.AddAndFireAssistantManagerObserver(
+      &speaker_id_enrollment_controller_);
+  service_controller_.AddAndFireAssistantManagerObserver(&settings_controller_);
+  service_controller_.AddAndFireAssistantManagerObserver(&timer_controller_);
 
-  platform_api_->SetAudioInputProvider(
-      &audio_input_controller_->audio_input_provider());
+  platform_api_.SetAudioInputProvider(
+      &audio_input_controller_.audio_input_provider());
 }
 
 LibassistantService::~LibassistantService() {
   // We explicitly stop the Libassistant service before destroying anything,
   // to prevent use-after-free bugs.
-  service_controller_->Stop();
-  service_controller_->RemoveAllAssistantManagerObservers();
+  service_controller_.Stop();
+  service_controller_.RemoveAllAssistantManagerObservers();
 }
 
 void LibassistantService::Bind(
@@ -89,21 +69,21 @@
     mojo::PendingRemote<mojom::PlatformDelegate> platform_delegate,
     mojo::PendingRemote<mojom::TimerDelegate> timer_delegate) {
   platform_delegate_.Bind(std::move(platform_delegate));
-  audio_input_controller_->Bind(std::move(audio_input_controller),
-                                platform_delegate_.get());
-  conversation_controller_->Bind(std::move(conversation_controller));
-  display_controller_->Bind(std::move(display_controller));
-  media_controller_->Bind(std::move(media_controller),
-                          std::move(media_delegate));
-  platform_api_->Bind(std::move(audio_output_delegate),
-                      platform_delegate_.get());
-  settings_controller_->Bind(std::move(settings_controller));
-  service_controller_->Bind(std::move(service_controller),
-                            settings_controller_.get());
-  speaker_id_enrollment_controller_->Bind(
+  audio_input_controller_.Bind(std::move(audio_input_controller),
+                               platform_delegate_.get());
+  conversation_controller_.Bind(std::move(conversation_controller));
+  display_controller_.Bind(std::move(display_controller));
+  media_controller_.Bind(std::move(media_controller),
+                         std::move(media_delegate));
+  platform_api_.Bind(std::move(audio_output_delegate),
+                     platform_delegate_.get());
+  settings_controller_.Bind(std::move(settings_controller));
+  service_controller_.Bind(std::move(service_controller),
+                           &settings_controller_);
+  speaker_id_enrollment_controller_.Bind(
       std::move(speaker_id_enrollment_controller));
-  timer_controller_->Bind(std::move(timer_controller),
-                          std::move(timer_delegate));
+  timer_controller_.Bind(std::move(timer_controller),
+                         std::move(timer_delegate));
 }
 
 void LibassistantService::AddSpeechRecognitionObserver(
@@ -114,7 +94,7 @@
 void LibassistantService::AddAuthenticationStateObserver(
     mojo::PendingRemote<
         chromeos::libassistant::mojom::AuthenticationStateObserver> observer) {
-  conversation_controller_->AddAuthenticationStateObserver(std::move(observer));
+  conversation_controller_.AddAuthenticationStateObserver(std::move(observer));
 }
 
 }  // namespace libassistant
diff --git a/chromeos/services/libassistant/libassistant_service.h b/chromeos/services/libassistant/libassistant_service.h
index 3da42ded..3cf1811a 100644
--- a/chromeos/services/libassistant/libassistant_service.h
+++ b/chromeos/services/libassistant/libassistant_service.h
@@ -8,10 +8,17 @@
 #include <memory>
 
 #include "base/component_export.h"
-#include "chromeos/services/libassistant/public/mojom/audio_input_controller.mojom-forward.h"
-#include "chromeos/services/libassistant/public/mojom/conversation_controller.mojom-forward.h"
-#include "chromeos/services/libassistant/public/mojom/platform_delegate.mojom-forward.h"
+#include "chromeos/services/libassistant/audio_input_controller.h"
+#include "chromeos/services/libassistant/conversation_controller.h"
+#include "chromeos/services/libassistant/conversation_state_listener_impl.h"
+#include "chromeos/services/libassistant/display_controller.h"
+#include "chromeos/services/libassistant/media_controller.h"
+#include "chromeos/services/libassistant/platform_api.h"
 #include "chromeos/services/libassistant/public/mojom/service.mojom.h"
+#include "chromeos/services/libassistant/service_controller.h"
+#include "chromeos/services/libassistant/settings_controller.h"
+#include "chromeos/services/libassistant/speaker_id_enrollment_controller.h"
+#include "chromeos/services/libassistant/timer_controller.h"
 #include "mojo/public/cpp/bindings/pending_receiver.h"
 #include "mojo/public/cpp/bindings/receiver.h"
 #include "mojo/public/cpp/bindings/remote_set.h"
@@ -25,17 +32,6 @@
 namespace chromeos {
 namespace libassistant {
 
-class AudioInputController;
-class ConversationController;
-class ConversationStateListenerImpl;
-class DisplayController;
-class MediaController;
-class PlatformApi;
-class ServiceController;
-class SettingsController;
-class SpeakerIdEnrollmentController;
-class TimerController;
-
 class COMPONENT_EXPORT(LIBASSISTANT_SERVICE) LibassistantService
     : public mojom::LibassistantService {
  public:
@@ -72,7 +68,7 @@
       override;
 
  private:
-  ServiceController& service_controller() { return *service_controller_; }
+  ServiceController& service_controller() { return service_controller_; }
 
   mojo::Receiver<mojom::LibassistantService> receiver_;
   mojo::Remote<mojom::PlatformDelegate> platform_delegate_;
@@ -82,21 +78,20 @@
 
   // These controllers are part of the platform api which is called from
   // Libassistant, and thus they must outlive |service_controller_|.
-  std::unique_ptr<PlatformApi> platform_api_;
-  std::unique_ptr<AudioInputController> audio_input_controller_;
+  PlatformApi platform_api_;
+  AudioInputController audio_input_controller_;
 
-  std::unique_ptr<ServiceController> service_controller_;
+  ServiceController service_controller_;
 
   // These controllers call Libassistant, and thus they must *not* outlive
   // |service_controller_|.
-  std::unique_ptr<ConversationController> conversation_controller_;
-  std::unique_ptr<ConversationStateListenerImpl> conversation_state_listener_;
-  std::unique_ptr<DisplayController> display_controller_;
-  std::unique_ptr<MediaController> media_controller_;
-  std::unique_ptr<SettingsController> settings_controller_;
-  std::unique_ptr<SpeakerIdEnrollmentController>
-      speaker_id_enrollment_controller_;
-  std::unique_ptr<TimerController> timer_controller_;
+  ConversationController conversation_controller_;
+  ConversationStateListenerImpl conversation_state_listener_;
+  DisplayController display_controller_;
+  MediaController media_controller_;
+  SettingsController settings_controller_;
+  SpeakerIdEnrollmentController speaker_id_enrollment_controller_;
+  TimerController timer_controller_;
 };
 
 }  // namespace libassistant
diff --git a/chromeos/services/libassistant/public/mojom/conversation_observer.mojom b/chromeos/services/libassistant/public/mojom/conversation_observer.mojom
index b0dd9b8a7..b4888c3a 100644
--- a/chromeos/services/libassistant/public/mojom/conversation_observer.mojom
+++ b/chromeos/services/libassistant/public/mojom/conversation_observer.mojom
@@ -42,6 +42,10 @@
   // Assistant got open Android app response from server.
   OnOpenAppResponse(AndroidAppInfo app_info);
 
+  // Assistant has started waiting. This occur during execution of a routine to
+  // give the user time to digest a response before continuing execution.
+  OnWaitStarted();
+
   // Libassistant is removing the notification with the given id.
   OnNotificationRemoved(string id);
 
diff --git a/components/autofill/content/renderer/autofill_agent.cc b/components/autofill/content/renderer/autofill_agent.cc
index 52e5547..5ada06d 100644
--- a/components/autofill/content/renderer/autofill_agent.cc
+++ b/components/autofill/content/renderer/autofill_agent.cc
@@ -88,7 +88,7 @@
 
 using form_util::ExtractMask;
 using form_util::FindFormAndFieldForFormControlElement;
-using form_util::UnownedCheckoutFormElementsAndFieldSetsToFormData;
+using form_util::UnownedFormElementsAndFieldSetsToFormData;
 using mojom::SubmissionSource;
 using ShowAll = PasswordAutofillAgent::ShowAll;
 using GenerationShowing = PasswordAutofillAgent::GenerationShowing;
@@ -613,7 +613,7 @@
   const ExtractMask extract_mask = static_cast<ExtractMask>(
       form_util::EXTRACT_VALUE | form_util::EXTRACT_OPTIONS);
 
-  return UnownedCheckoutFormElementsAndFieldSetsToFormData(
+  return UnownedFormElementsAndFieldSetsToFormData(
       fieldsets, control_elements, nullptr, document, field_data_manager_.get(),
       extract_mask, output, nullptr);
 }
diff --git a/components/autofill/content/renderer/form_autofill_util.cc b/components/autofill/content/renderer/form_autofill_util.cc
index 2c4d15b..abd1aad 100644
--- a/components/autofill/content/renderer/form_autofill_util.cc
+++ b/components/autofill/content/renderer/form_autofill_util.cc
@@ -1369,10 +1369,8 @@
     FormFieldData* field) {
   static base::NoDestructor<WebString> kLabel("label");
 
-  if (form_element)
-    DCHECK(fieldsets.empty());
-  if (field)
-    DCHECK(form_control_element);
+  DCHECK(!form_element || fieldsets.empty());
+  DCHECK(!field || form_control_element);
 
   // A map from a FormFieldData's name to the FormFieldData itself.
   std::map<WebFormControlElement, FormFieldData*> element_map;
@@ -1463,29 +1461,6 @@
   return true;
 }
 
-bool UnownedFormElementsAndFieldSetsToFormData(
-    const std::vector<blink::WebElement>& fieldsets,
-    const std::vector<blink::WebFormControlElement>& control_elements,
-    const blink::WebFormControlElement* element,
-    const blink::WebDocument& document,
-    const FieldDataManager* field_data_manager,
-    ExtractMask extract_mask,
-    FormData* form,
-    FormFieldData* field) {
-  form->url = GetCanonicalOriginForDocument(document);
-  if (document.GetFrame() && document.GetFrame()->Top()) {
-    form->main_frame_origin = document.GetFrame()->Top()->GetSecurityOrigin();
-  } else {
-    form->main_frame_origin = url::Origin();
-  }
-
-  form->is_form_tag = false;
-
-  return FormOrFieldsetsToFormData(nullptr, element, fieldsets,
-                                   control_elements, field_data_manager,
-                                   extract_mask, form, field);
-}
-
 // Check if a script modified username is suitable for Password Manager to
 // remember.
 bool ScriptModifiedUsernameAcceptable(
@@ -1940,7 +1915,7 @@
       GetUnownedFormFieldElements(elements, fieldsets));
 }
 
-bool UnownedCheckoutFormElementsAndFieldSetsToFormData(
+bool UnownedFormElementsAndFieldSetsToFormData(
     const std::vector<blink::WebElement>& fieldsets,
     const std::vector<blink::WebFormControlElement>& control_elements,
     const blink::WebFormControlElement* element,
@@ -1949,102 +1924,18 @@
     ExtractMask extract_mask,
     FormData* form,
     FormFieldData* field) {
-  if (!base::FeatureList::IsEnabled(
-          features::kAutofillRestrictUnownedFieldsToFormlessCheckout)) {
-    return UnownedFormElementsAndFieldSetsToFormData(
-        fieldsets, control_elements, element, document, field_data_manager,
-        extract_mask, form, field);
+  form->url = GetCanonicalOriginForDocument(document);
+  if (document.GetFrame() && document.GetFrame()->Top()) {
+    form->main_frame_origin = document.GetFrame()->Top()->GetSecurityOrigin();
+  } else {
+    form->main_frame_origin = url::Origin();
   }
 
-  // Only attempt formless Autofill on checkout flows. This avoids the many
-  // false positives found on the non-checkout web. See
-  // http://crbug.com/462375.
-  WebElement html_element = document.DocumentElement();
+  form->is_form_tag = false;
 
-  // For now this restriction only applies to English-language pages, because
-  // the keywords are not translated. Note that an empty "lang" attribute
-  // counts as English.
-  std::string lang;
-  if (!html_element.IsNull())
-    lang = html_element.GetAttribute("lang").Utf8();
-  if (!lang.empty() &&
-      !base::StartsWith(lang, "en", base::CompareCase::INSENSITIVE_ASCII)) {
-    return UnownedFormElementsAndFieldSetsToFormData(
-        fieldsets, control_elements, element, document, field_data_manager,
-        extract_mask, form, field);
-  }
-
-  // A potential problem is that this only checks document.title(), but should
-  // actually check the main frame's title. Thus it may make bad decisions for
-  // iframes.
-  base::string16 title(base::ToLowerASCII(document.Title().Utf16()));
-
-  // Don't check the path for url's without a standard format path component,
-  // such as data:.
-  std::string path;
-  GURL url(document.Url());
-  if (url.IsStandard())
-    path = base::ToLowerASCII(url.path());
-
-  const char* const kKeywords[] = {"payment",  "checkout", "address",
-                                   "delivery", "shipping", "wallet"};
-
-  for (const auto* keyword : kKeywords) {
-    // Compare char16 elements of |title| with char elements of |keyword| using
-    // operator==.
-    auto title_pos = std::search(title.begin(), title.end(), keyword,
-                                 keyword + strlen(keyword));
-    if (title_pos != title.end() || path.find(keyword) != std::string::npos) {
-      form->is_formless_checkout = true;
-      // Found a keyword: treat this as an unowned form.
-      return UnownedFormElementsAndFieldSetsToFormData(
-          fieldsets, control_elements, element, document, field_data_manager,
-          extract_mask, form, field);
-    }
-  }
-
-  // Since it's not a checkout flow, only add fields that have a non-"off"
-  // autocomplete attribute to the formless autofill.
-  static base::NoDestructor<WebString> kOffAttribute("off");
-  static base::NoDestructor<WebString> kFalseAttribute("false");
-  std::vector<WebFormControlElement> elements_with_autocomplete;
-  for (const WebFormControlElement& element : control_elements) {
-    blink::WebString autocomplete = element.GetAttribute("autocomplete");
-    if (autocomplete.length() && autocomplete != *kOffAttribute &&
-        autocomplete != *kFalseAttribute) {
-      elements_with_autocomplete.push_back(element);
-    }
-  }
-
-  // http://crbug.com/841784
-  // Capture the number of times this formless checkout logic prevents a from
-  // being autofilled (fill logic expects to receive a autofill field entry,
-  // possibly not fillable, for each control element).
-  // Note: this will be fixed by http://crbug.com/806987
-  UMA_HISTOGRAM_BOOLEAN(
-      "Autofill.UnownedFieldsWereFiltered",
-      elements_with_autocomplete.size() != control_elements.size());
-
-  if (elements_with_autocomplete.empty())
-    return false;
-
-  return UnownedFormElementsAndFieldSetsToFormData(
-      fieldsets, elements_with_autocomplete, element, document,
-      field_data_manager, extract_mask, form, field);
-}
-
-bool UnownedPasswordFormElementsAndFieldSetsToFormData(
-    const std::vector<blink::WebElement>& fieldsets,
-    const std::vector<blink::WebFormControlElement>& control_elements,
-    const blink::WebFormControlElement* element,
-    const blink::WebDocument& document,
-    const FieldDataManager* field_data_manager,
-    ExtractMask extract_mask,
-    FormData* form,
-    FormFieldData* field) {
-  return UnownedFormElementsAndFieldSetsToFormData(
-      fieldsets, control_elements, element, document, field_data_manager,
-      extract_mask, form, field);
+  return FormOrFieldsetsToFormData(nullptr, element, fieldsets,
+                                   control_elements, field_data_manager,
+                                   extract_mask, form, field);
 }
 
 bool FindFormAndFieldForFormControlElement(
@@ -2067,7 +1958,7 @@
     std::vector<WebElement> fieldsets;
     std::vector<WebFormControlElement> control_elements =
         GetUnownedAutofillableFormFieldElements(document.All(), &fieldsets);
-    return UnownedCheckoutFormElementsAndFieldSetsToFormData(
+    return UnownedFormElementsAndFieldSetsToFormData(
         fieldsets, control_elements, &element, document, field_data_manager,
         extract_mask, form, field);
   }
diff --git a/components/autofill/content/renderer/form_autofill_util.h b/components/autofill/content/renderer/form_autofill_util.h
index a37ff05..399f677a 100644
--- a/components/autofill/content/renderer/form_autofill_util.h
+++ b/components/autofill/content/renderer/form_autofill_util.h
@@ -199,27 +199,14 @@
     std::vector<blink::WebElement>* fieldsets);
 
 // Fills |form| with the form data derived from |fieldsets|, |control_elements|
-// and |origin|. If |field| is non-NULL, fill it with the FormField
-// representation for |element|.
+// and |origin|. If |field| is not nullptr, fills it with the FormFieldData
+// representation of |element|.
 // |extract_mask| usage and the return value are the same as
 // WebFormElementToFormData() above.
-// This function will return false and not perform any extraction if
-// |document| does not pertain to checkout.
-bool UnownedCheckoutFormElementsAndFieldSetsToFormData(
-    const std::vector<blink::WebElement>& fieldsets,
-    const std::vector<blink::WebFormControlElement>& control_elements,
-    const blink::WebFormControlElement* element,
-    const blink::WebDocument& document,
-    const FieldDataManager* field_data_manager,
-    ExtractMask extract_mask,
-    FormData* form,
-    FormFieldData* field);
-
-// Same as above, but without the requirement that the elements only be
-// related to checkout. Field properties of |control_elements| will be copied
-// from |field_data_manager|, if the argument is not null and has corresponding
-// entries (see properties in FieldPropertiesFlags).
-bool UnownedPasswordFormElementsAndFieldSetsToFormData(
+// Returns false iff the extraction fails because the number of fields exceeds
+// |kMaxParseableFields|, or |field| and |element| are not nullptr but
+// |element| is not among |control_elements|.
+bool UnownedFormElementsAndFieldSetsToFormData(
     const std::vector<blink::WebElement>& fieldsets,
     const std::vector<blink::WebFormControlElement>& control_elements,
     const blink::WebFormControlElement* element,
diff --git a/components/autofill/content/renderer/form_autofill_util_browsertest.cc b/components/autofill/content/renderer/form_autofill_util_browsertest.cc
index 705b9c8..47b8208 100644
--- a/components/autofill/content/renderer/form_autofill_util_browsertest.cc
+++ b/components/autofill/content/renderer/form_autofill_util_browsertest.cc
@@ -443,7 +443,7 @@
   }
 
   autofill::FormData target;
-  EXPECT_TRUE(UnownedPasswordFormElementsAndFieldSetsToFormData(
+  EXPECT_TRUE(UnownedFormElementsAndFieldSetsToFormData(
       dummy_fieldsets, control_elements, nullptr, web_frame->GetDocument(),
       nullptr, EXTRACT_NONE, &target, nullptr));
   const struct {
@@ -484,7 +484,7 @@
   }
 
   autofill::FormData target;
-  EXPECT_TRUE(UnownedPasswordFormElementsAndFieldSetsToFormData(
+  EXPECT_TRUE(UnownedFormElementsAndFieldSetsToFormData(
       dummy_fieldsets, control_elements, nullptr, web_frame->GetDocument(),
       nullptr, EXTRACT_NONE, &target, nullptr));
   const struct {
@@ -527,7 +527,7 @@
   EXPECT_FALSE(autofill::form_util::IsWebElementVisible(control_elements[1]));
 
   autofill::FormData target;
-  EXPECT_TRUE(UnownedPasswordFormElementsAndFieldSetsToFormData(
+  EXPECT_TRUE(UnownedFormElementsAndFieldSetsToFormData(
       dummy_fieldsets, control_elements, nullptr, web_frame->GetDocument(),
       nullptr, EXTRACT_NONE, &target, nullptr));
   ASSERT_EQ(2u, target.fields.size());
diff --git a/components/autofill/content/renderer/form_cache.cc b/components/autofill/content/renderer/form_cache.cc
index ab2c36aa..179a339 100644
--- a/components/autofill/content/renderer/form_cache.cc
+++ b/components/autofill/content/renderer/form_cache.cc
@@ -194,7 +194,7 @@
   }
 
   FormData synthetic_form;
-  if (!UnownedCheckoutFormElementsAndFieldSetsToFormData(
+  if (!UnownedFormElementsAndFieldSetsToFormData(
           fieldsets, control_elements, nullptr, document, field_data_manager,
           extract_mask, &synthetic_form, nullptr)) {
     PruneInitialValueCaches(observed_unique_renderer_ids);
diff --git a/components/autofill/content/renderer/password_form_conversion_utils.cc b/components/autofill/content/renderer/password_form_conversion_utils.cc
index 81cea7d9..bb1bb71 100644
--- a/components/autofill/content/renderer/password_form_conversion_utils.cc
+++ b/components/autofill/content/renderer/password_form_conversion_utils.cc
@@ -171,7 +171,7 @@
     return nullptr;
 
   auto form_data = std::make_unique<FormData>();
-  if (!UnownedPasswordFormElementsAndFieldSetsToFormData(
+  if (!UnownedFormElementsAndFieldSetsToFormData(
           fieldsets, control_elements, nullptr, frame.GetDocument(),
           field_data_manager, form_util::EXTRACT_VALUE, form_data.get(),
           nullptr /* FormFieldData */)) {
diff --git a/components/autofill/core/browser/autofill_form_test_utils.cc b/components/autofill/core/browser/autofill_form_test_utils.cc
index 97d4e4c..802cabc 100644
--- a/components/autofill/core/browser/autofill_form_test_utils.cc
+++ b/components/autofill/core/browser/autofill_form_test_utils.cc
@@ -118,7 +118,6 @@
     field.should_autocomplete = field_description.should_autocomplete;
     form_data.fields.push_back(field);
   }
-  form_data.is_formless_checkout = test_form_attributes.is_formless_checkout;
   form_data.is_form_tag = test_form_attributes.is_form_tag;
 
   return form_data;
diff --git a/components/autofill/core/browser/autofill_form_test_utils.h b/components/autofill/core/browser/autofill_form_test_utils.h
index 0c4c9b9..660cbcb 100644
--- a/components/autofill/core/browser/autofill_form_test_utils.h
+++ b/components/autofill/core/browser/autofill_form_test_utils.h
@@ -59,7 +59,6 @@
   const char* url = kFormUrl;
   const char* action = kFormActionUrl;
   base::Optional<url::Origin> main_frame_origin = base::nullopt;
-  bool is_formless_checkout = false;
   bool is_form_tag = true;
 };
 
diff --git a/components/autofill/core/browser/autofill_manager_unittest.cc b/components/autofill/core/browser/autofill_manager_unittest.cc
index f852b08..8dcec72e 100644
--- a/components/autofill/core/browser/autofill_manager_unittest.cc
+++ b/components/autofill/core/browser/autofill_manager_unittest.cc
@@ -99,7 +99,6 @@
 
 namespace autofill {
 
-using features::kAutofillRestrictUnownedFieldsToFormlessCheckout;
 using mojom::SubmissionIndicatorEvent;
 using mojom::SubmissionSource;
 
@@ -8959,12 +8958,6 @@
 
     has_active_screen_reader_ = GetParam();
     external_delegate_->set_has_active_screen_reader(has_active_screen_reader_);
-
-    scoped_feature_list_.InitWithFeatures(
-        // Enabled
-        {},
-        // Disabled
-        {kAutofillRestrictUnownedFieldsToFormlessCheckout});
   }
 
   void TearDown() override {
diff --git a/components/autofill/core/browser/autofill_metrics_unittest.cc b/components/autofill/core/browser/autofill_metrics_unittest.cc
index 7a43731..93edb4104 100644
--- a/components/autofill/core/browser/autofill_metrics_unittest.cc
+++ b/components/autofill/core/browser/autofill_metrics_unittest.cc
@@ -9583,9 +9583,6 @@
 }
 
 TEST_F(AutofillMetricsTest, DynamicFormMetrics) {
-  scoped_feature_list_.InitAndDisableFeature(
-      features::kAutofillRestrictUnownedFieldsToFormlessCheckout);
-
   // Set up our form data.
   FormData form;
   form.unique_renderer_id = MakeFormRendererId();
diff --git a/components/autofill/core/browser/form_structure.cc b/components/autofill/core/browser/form_structure.cc
index 9a13c2ba9..7155e142 100644
--- a/components/autofill/core/browser/form_structure.cc
+++ b/components/autofill/core/browser/form_structure.cc
@@ -630,7 +630,6 @@
       target_url_(form.action),
       main_frame_origin_(form.main_frame_origin),
       is_form_tag_(form.is_form_tag),
-      is_formless_checkout_(form.is_formless_checkout),
       all_fields_are_passwords_(!form.fields.empty()),
       form_parsed_timestamp_(AutofillTickClock::NowTicks()),
       passwords_were_revealed_(false),
@@ -1077,10 +1076,7 @@
 
 bool FormStructure::ShouldRunHeuristics() const {
   return active_field_count() >= kMinRequiredFieldsForHeuristics &&
-         HasAllowedScheme(source_url_) &&
-         (is_form_tag_ || is_formless_checkout_ ||
-          !base::FeatureList::IsEnabled(
-              features::kAutofillRestrictUnownedFieldsToFormlessCheckout));
+         HasAllowedScheme(source_url_);
 }
 
 bool FormStructure::ShouldBeQueried() const {
@@ -1516,7 +1512,6 @@
   data.action = target_url_;
   data.main_frame_origin = main_frame_origin_;
   data.is_form_tag = is_form_tag_;
-  data.is_formless_checkout = is_formless_checkout_;
   data.unique_renderer_id = unique_renderer_id_;
 
   for (const auto& field : fields_) {
diff --git a/components/autofill/core/browser/form_structure.h b/components/autofill/core/browser/form_structure.h
index 8151d28e..71fe6cd 100644
--- a/components/autofill/core/browser/form_structure.h
+++ b/components/autofill/core/browser/form_structure.h
@@ -597,12 +597,6 @@
   // True if the form is a <form>.
   bool is_form_tag_ = true;
 
-  // True if the form is made of unowned fields (i.e., not within a <form> tag)
-  // in what appears to be a checkout flow. This attribute is only calculated
-  // and used if features::kAutofillRestrictUnownedFieldsToFormlessCheckout is
-  // enabled, to prevent heuristics from running on formless non-checkout.
-  bool is_formless_checkout_ = false;
-
   // True if all form fields are password fields.
   bool all_fields_are_passwords_ = false;
 
diff --git a/components/autofill/core/browser/form_structure_unittest.cc b/components/autofill/core/browser/form_structure_unittest.cc
index fc22851..4a95dd7 100644
--- a/components/autofill/core/browser/form_structure_unittest.cc
+++ b/components/autofill/core/browser/form_structure_unittest.cc
@@ -558,50 +558,6 @@
                                      UNKNOWN_TYPE}}}});
 }
 
-// // Verify that the heuristics are not run for non checkout formless forms.
-TEST_F(FormStructureTestImpl, Heuristics_FormlessNonCheckoutForm) {
-  base::test::ScopedFeatureList feature_list;
-  feature_list.InitAndEnableFeature(
-      features::kAutofillRestrictUnownedFieldsToFormlessCheckout);
-
-  CheckFormStructureTestData(
-      {{{.description_for_logging = "Heuristics_NonCheckoutForm",
-         .fields = {{.role = ServerFieldType::NAME_FIRST,
-                     .autocomplete_attribute = "given-name"},
-                    {.role = ServerFieldType::NAME_LAST,
-                     .autocomplete_attribute = "family-name"},
-                    {.role = ServerFieldType::EMAIL_ADDRESS,
-                     .autocomplete_attribute = "email"}}},
-        {
-            .determine_heuristic_type = true,
-            .is_autofillable = true,
-            .field_count = 3,
-            .autofill_count = 3,
-        },
-        {.expected_html_type = {HTML_TYPE_GIVEN_NAME, HTML_TYPE_FAMILY_NAME,
-                                HTML_TYPE_EMAIL},
-         .expected_heuristic_type = {NAME_FIRST, NAME_LAST, EMAIL_ADDRESS}}},
-
-       {{.description_for_logging = "Heuristics_FormlessNonCheckoutForm",
-         .fields = {{.role = ServerFieldType::NAME_FIRST,
-                     .autocomplete_attribute = "given-name"},
-                    {.role = ServerFieldType::NAME_LAST,
-                     .autocomplete_attribute = "family-name"},
-                    {.role = ServerFieldType::EMAIL_ADDRESS,
-                     .autocomplete_attribute = "email"}},
-         .is_form_tag = false},
-        {
-            .determine_heuristic_type = true,
-            .is_autofillable = true,
-            .field_count = 3,
-            .autofill_count = 3,
-        },
-        {.expected_html_type = {HTML_TYPE_GIVEN_NAME, HTML_TYPE_FAMILY_NAME,
-                                HTML_TYPE_EMAIL},
-         .expected_heuristic_type = {UNKNOWN_TYPE, UNKNOWN_TYPE,
-                                     UNKNOWN_TYPE}}}});
-}
-
 // All fields share a common prefix which could confuse the heuristics. Test
 // that the common prefixes are stripped out before running heuristics.
 // This test ensures that |parseable_name| is used for heuristics.
diff --git a/components/autofill/core/common/autofill_features.cc b/components/autofill/core/common/autofill_features.cc
index 866f6a92..4ab3692 100644
--- a/components/autofill/core/common/autofill_features.cc
+++ b/components/autofill/core/common/autofill_features.cc
@@ -274,13 +274,6 @@
 const base::Feature kAutofillProfileServerValidation{
     "AutofillProfileServerValidation", base::FEATURE_DISABLED_BY_DEFAULT};
 
-// Controls whether or not a group of fields not enclosed in a form can be
-// considered a form. If this is enabled, unowned fields will only constitute
-// a form if there are signals to suggest that this might a checkout page.
-const base::Feature kAutofillRestrictUnownedFieldsToFormlessCheckout{
-    "AutofillRestrictUnownedFieldsToFormlessCheckout",
-    base::FEATURE_DISABLED_BY_DEFAULT};
-
 // Controls whether or not overall prediction are retrieved from the cache.
 const base::Feature kAutofillRetrieveOverallPredictionsFromCache{
     "AutofillRetrieveOverallPredictionsFromCache",
diff --git a/components/autofill/core/common/autofill_features.h b/components/autofill/core/common/autofill_features.h
index 934b738..110e93b 100644
--- a/components/autofill/core/common/autofill_features.h
+++ b/components/autofill/core/common/autofill_features.h
@@ -67,7 +67,6 @@
 extern const base::Feature kAutofillProfileClientValidation;
 extern const base::Feature kAutofillProfileImportFromUnfocusableFields;
 extern const base::Feature kAutofillProfileServerValidation;
-extern const base::Feature kAutofillRestrictUnownedFieldsToFormlessCheckout;
 extern const base::Feature kAutofillRetrieveOverallPredictionsFromCache;
 extern const base::Feature kAutofillRichMetadataQueries;
 extern const base::Feature kAutofillSaveAndFillVPA;
diff --git a/components/autofill/core/common/form_data.cc b/components/autofill/core/common/form_data.cc
index dd5ccbc..e1fdb2c 100644
--- a/components/autofill/core/common/form_data.cc
+++ b/components/autofill/core/common/form_data.cc
@@ -18,7 +18,7 @@
 
 namespace {
 
-const int kFormDataPickleVersion = 6;
+const int kFormDataPickleVersion = 7;
 
 bool ReadGURL(base::PickleIterator* iter, GURL* url) {
   std::string spec;
@@ -85,7 +85,6 @@
   if (name != form.name || id_attribute != form.id_attribute ||
       name_attribute != form.name_attribute || url != form.url ||
       action != form.action || is_form_tag != form.is_form_tag ||
-      is_formless_checkout != form.is_formless_checkout ||
       fields.size() != form.fields.size())
     return false;
   for (size_t i = 0; i < fields.size(); ++i) {
@@ -100,7 +99,6 @@
       name_attribute != form.name_attribute || url != form.url ||
       action != form.action || is_action_empty != form.is_action_empty ||
       is_form_tag != form.is_form_tag ||
-      is_formless_checkout != form.is_formless_checkout ||
       fields.size() != form.fields.size()) {
     return false;
   }
@@ -130,8 +128,7 @@
   // as well.
   auto tie = [](const FormData& f) {
     return std::tie(f.unique_renderer_id, f.name, f.id_attribute,
-                    f.name_attribute, f.url, f.action, f.is_form_tag,
-                    f.is_formless_checkout);
+                    f.name_attribute, f.url, f.action, f.is_form_tag);
   };
   if (tie(a) < tie(b))
     return true;
@@ -155,7 +152,6 @@
 std::ostream& operator<<(std::ostream& os, const FormData& form) {
   os << base::UTF16ToUTF8(form.name) << " " << form.url << " " << form.action
      << " " << form.main_frame_origin << " " << form.is_form_tag << " "
-     << form.is_formless_checkout << " "
      << "Fields:";
   for (size_t i = 0; i < form.fields.size(); ++i) {
     os << form.fields[i] << ",";
@@ -170,7 +166,6 @@
   pickle->WriteString(form_data.action.spec());
   SerializeFormFieldDataVector(form_data.fields, pickle);
   pickle->WriteBool(form_data.is_form_tag);
-  pickle->WriteBool(form_data.is_formless_checkout);
   pickle->WriteString(form_data.main_frame_origin.Serialize());
 }
 
@@ -219,8 +214,9 @@
     form_data->is_form_tag = true;
   }
 
-  if (version >= 5) {
-    if (!iter->ReadBool(&temp_form_data.is_formless_checkout)) {
+  if (version >= 5 && version <= 6) {
+    bool is_formless_checkout;
+    if (!iter->ReadBool(&is_formless_checkout)) {
       LogDeserializationError(version);
       return false;
     }
diff --git a/components/autofill/core/common/form_data.h b/components/autofill/core/common/form_data.h
index b57d18df..5f974f68 100644
--- a/components/autofill/core/common/form_data.h
+++ b/components/autofill/core/common/form_data.h
@@ -91,11 +91,6 @@
   url::Origin main_frame_origin;
   // True if this form is a form tag.
   bool is_form_tag = true;
-  // True if the form is made of unowned fields (i.e., not within a <form> tag)
-  // in what appears to be a checkout flow. This attribute is only calculated
-  // and used if features::kAutofillRestrictUnownedFieldsToFormlessCheckout is
-  // enabled, to prevent heuristics from running on formless non-checkout.
-  bool is_formless_checkout = false;
   // Unique renderer id returned by WebFormElement::UniqueRendererFormId(). It
   // is not persistent between page loads, so it is not saved and not used in
   // comparison in SameFormAs().
diff --git a/components/autofill/core/common/form_data_unittest.cc b/components/autofill/core/common/form_data_unittest.cc
index eae97e5c2..91a3352 100644
--- a/components/autofill/core/common/form_data_unittest.cc
+++ b/components/autofill/core/common/form_data_unittest.cc
@@ -84,7 +84,7 @@
     SerializeFormFieldData(form_data.fields[i], pickle);
   }
   pickle->WriteBool(form_data.is_form_tag);
-  pickle->WriteBool(form_data.is_formless_checkout);
+  pickle->WriteBool(/*is_formless_checkout=*/true);
 }
 
 void SerializeInVersion6Format(const FormData& form_data,
@@ -98,7 +98,21 @@
     SerializeFormFieldData(form_data.fields[i], pickle);
   }
   pickle->WriteBool(form_data.is_form_tag);
-  pickle->WriteBool(form_data.is_formless_checkout);
+  pickle->WriteBool(/*is_formless_checkout=*/true);
+  pickle->WriteString(form_data.main_frame_origin.Serialize());
+}
+
+void SerializeInVersion7Format(const FormData& form_data,
+                               base::Pickle* pickle) {
+  pickle->WriteInt(7);
+  pickle->WriteString16(form_data.name);
+  pickle->WriteString(form_data.url.spec());
+  pickle->WriteString(form_data.action.spec());
+  pickle->WriteInt(static_cast<int>(form_data.fields.size()));
+  for (size_t i = 0; i < form_data.fields.size(); ++i) {
+    SerializeFormFieldData(form_data.fields[i], pickle);
+  }
+  pickle->WriteBool(form_data.is_form_tag);
   pickle->WriteString(form_data.main_frame_origin.Serialize());
 }
 
@@ -122,7 +136,6 @@
   data->main_frame_origin =
       url::Origin::Create(GURL("https://origin-example.com"));
   data->is_form_tag = true;            // Default value.
-  data->is_formless_checkout = false;  // Default value.
 
   FormFieldData field_data;
   field_data.label = base::ASCIIToUTF16("label");
@@ -240,7 +253,6 @@
 TEST(FormDataTest, Serialize_v5_Deserialize_vCurrent) {
   FormData data;
   FillInDummyFormData(&data);
-  data.is_formless_checkout = true;
 
   base::Pickle pickle;
   SerializeInVersion5Format(data, &pickle);
@@ -255,7 +267,6 @@
 TEST(FormDataTest, Serialize_v6_Deserialize_vCurrent) {
   FormData data;
   FillInDummyFormData(&data);
-  data.is_formless_checkout = true;
 
   base::Pickle pickle;
   SerializeInVersion6Format(data, &pickle);
@@ -267,6 +278,20 @@
   EXPECT_TRUE(actual.SameFormAs(data));
 }
 
+TEST(FormDataTest, Serialize_v7_Deserialize_vCurrent) {
+  FormData data;
+  FillInDummyFormData(&data);
+
+  base::Pickle pickle;
+  SerializeInVersion7Format(data, &pickle);
+
+  base::PickleIterator iter(pickle);
+  FormData actual;
+  EXPECT_TRUE(DeserializeFormData(&iter, &actual));
+
+  EXPECT_TRUE(actual.SameFormAs(data));
+}
+
 TEST(FormDataTest, SerializeIncorrectFormatAndDeserialize) {
   FormData data;
   FillInDummyFormData(&data);
diff --git a/components/autofill/core/common/mojom/autofill_types.mojom b/components/autofill/core/common/mojom/autofill_types.mojom
index f0a1654c..92fc4d26 100644
--- a/components/autofill/core/common/mojom/autofill_types.mojom
+++ b/components/autofill/core/common/mojom/autofill_types.mojom
@@ -162,7 +162,6 @@
   bool is_action_empty;
   url.mojom.Origin main_frame_origin;
   bool is_form_tag;
-  bool is_formless_checkout;
   FormRendererId unique_renderer_id;
   SubmissionIndicatorEvent submission_event;
   array<FormFieldData> fields;
diff --git a/components/autofill/core/common/mojom/autofill_types_mojom_traits.cc b/components/autofill/core/common/mojom/autofill_types_mojom_traits.cc
index 7f9fb93..8f35824 100644
--- a/components/autofill/core/common/mojom/autofill_types_mojom_traits.cc
+++ b/components/autofill/core/common/mojom/autofill_types_mojom_traits.cc
@@ -143,7 +143,6 @@
     return false;
 
   out->is_form_tag = data.is_form_tag();
-  out->is_formless_checkout = data.is_formless_checkout();
 
   if (!data.ReadUniqueRendererId(&out->unique_renderer_id))
     return false;
diff --git a/components/autofill/core/common/mojom/autofill_types_mojom_traits.h b/components/autofill/core/common/mojom/autofill_types_mojom_traits.h
index 4863cad..bf49837 100644
--- a/components/autofill/core/common/mojom/autofill_types_mojom_traits.h
+++ b/components/autofill/core/common/mojom/autofill_types_mojom_traits.h
@@ -243,10 +243,6 @@
 
   static bool is_form_tag(const autofill::FormData& r) { return r.is_form_tag; }
 
-  static bool is_formless_checkout(const autofill::FormData& r) {
-    return r.is_formless_checkout;
-  }
-
   static autofill::FormRendererId unique_renderer_id(
       const autofill::FormData& r) {
     return r.unique_renderer_id;
diff --git a/components/autofill/ios/browser/autofill_agent_unittests.mm b/components/autofill/ios/browser/autofill_agent_unittests.mm
index 2e1a8d3..9286b170 100644
--- a/components/autofill/ios/browser/autofill_agent_unittests.mm
+++ b/components/autofill/ios/browser/autofill_agent_unittests.mm
@@ -331,36 +331,6 @@
             fake_main_frame_->GetLastJavaScriptCall());
 }
 
-// Tests that when a user initiated form activity is registered the script to
-// extract forms is executed.
-TEST_F(AutofillAgentTests,
-       CheckIfSuggestionsAvailable_UserInitiatedActivity1FrameMessaging) {
-  base::test::ScopedFeatureList scoped_feature_list;
-  std::vector<base::Feature> enabled_features;
-  std::vector<base::Feature> disabled_features;
-  enabled_features.push_back(
-      autofill::features::kAutofillRestrictUnownedFieldsToFormlessCheckout);
-  scoped_feature_list.InitWithFeatures(enabled_features, disabled_features);
-  FormSuggestionProviderQuery* form_query =
-      [[FormSuggestionProviderQuery alloc] initWithFormName:@"form"
-                                               uniqueFormID:FormRendererId(0)
-                                            fieldIdentifier:@"address"
-                                              uniqueFieldID:FieldRendererId(1)
-                                                  fieldType:@"text"
-                                                       type:@"focus"
-                                                 typedValue:@""
-                                                    frameID:@"frameID"];
-
-  [autofill_agent_ checkIfSuggestionsAvailableForForm:form_query
-                                          isMainFrame:YES
-                                       hasUserGesture:YES
-                                             webState:&fake_web_state_
-                                    completionHandler:nil];
-  fake_web_state_.WasShown();
-  EXPECT_EQ("__gCrWeb.autofill.extractForms(1, true);",
-            fake_main_frame_->GetLastJavaScriptCall());
-}
-
 // Tests that when a non user initiated form activity is registered the
 // completion callback passed to the call to check if suggestions are available
 // is invoked with no suggestions.
diff --git a/components/autofill/ios/browser/autofill_util.mm b/components/autofill/ios/browser/autofill_util.mm
index 2114e10..7a8f84c 100644
--- a/components/autofill/ios/browser/autofill_util.mm
+++ b/components/autofill/ios/browser/autofill_util.mm
@@ -135,8 +135,6 @@
   form_dictionary->GetString("name_attribute", &form_data->name_attribute);
   form_dictionary->GetString("id_attribute", &form_data->id_attribute);
   form_dictionary->GetBoolean("is_form_tag", &form_data->is_form_tag);
-  form_dictionary->GetBoolean("is_formless_checkout",
-                              &form_data->is_formless_checkout);
   form_dictionary->GetString("frame_id", &form_data->frame_id);
 
   // Field list (mandatory) is extracted.
diff --git a/components/autofill/ios/browser/js_autofill_manager.mm b/components/autofill/ios/browser/js_autofill_manager.mm
index 9fb27990..9a551d3 100644
--- a/components/autofill/ios/browser/js_autofill_manager.mm
+++ b/components/autofill/ios/browser/js_autofill_manager.mm
@@ -53,8 +53,7 @@
                                    (void (^)(NSString*))completionHandler {
   DCHECK(completionHandler);
 
-  bool restrictUnownedFieldsToFormlessCheckout = base::FeatureList::IsEnabled(
-      autofill::features::kAutofillRestrictUnownedFieldsToFormlessCheckout);
+  bool restrictUnownedFieldsToFormlessCheckout = false;
   std::vector<base::Value> parameters;
   parameters.push_back(base::Value(static_cast<int>(requiredFieldsCount)));
   parameters.push_back(base::Value(restrictUnownedFieldsToFormlessCheckout));
diff --git a/components/autofill/ios/form_util/form_activity_observer.h b/components/autofill/ios/form_util/form_activity_observer.h
index 854646c..cb34d5a6 100644
--- a/components/autofill/ios/form_util/form_activity_observer.h
+++ b/components/autofill/ios/form_util/form_activity_observer.h
@@ -44,12 +44,12 @@
   // It is in a JSON format and can be decoded by autofill::ExtractFormsData.
   // It is a list (for compatibility reason) containing 0 or 1 dictionary.
   // The dictionary has some element containing some form attributes (HTML or
-  // computed ('name', 'action', 'is_formless_checkout'...) and a 'field'
-  // element containing a list of dictionaries, each representing a field of the
-  // form and contianing some attributes ('name', 'type',...).
-  // |sender_frame| is the WebFrame that sent the form submission message.
-  // |sender_frame| can be null if frame messaging is not enabled (see
-  // web::WebState::ScriptCommandCallback comment for details).
+  // computed ('name', 'action', ...) and a 'field' element containing a list of
+  // dictionaries, each representing a field of the form and containing some
+  // attributes ('name', 'type', ...). |sender_frame| is the WebFrame that sent
+  // the form submission message. |sender_frame| can be null if frame messaging
+  // is not enabled (see web::WebState::ScriptCommandCallback comment for
+  // details).
   // TODO(crbug.com/881811): remove |form_in_main_frame| once frame messaging is
   // fully enabled.
   // TODO(crbug.com/881816): Update comment once WebFrame cannot be null.
diff --git a/components/autofill/ios/form_util/form_activity_params.h b/components/autofill/ios/form_util/form_activity_params.h
index 6639ecc..0feafa8 100644
--- a/components/autofill/ios/form_util/form_activity_params.h
+++ b/components/autofill/ios/form_util/form_activity_params.h
@@ -10,9 +10,6 @@
 
 namespace autofill {
 
-// HTML password field type.
-constexpr char kPasswordFieldType[] = "password";
-
 // Wraps information about event happening in a form.
 // Example HTML
 // <form name="np" id="np1" action="https://example.com/" method="post">
diff --git a/components/autofill/ios/form_util/resources/fill.js b/components/autofill/ios/form_util/resources/fill.js
index 8de3606..0fb2dc2 100644
--- a/components/autofill/ios/form_util/resources/fill.js
+++ b/components/autofill/ios/form_util/resources/fill.js
@@ -2253,7 +2253,6 @@
   for (let index = 0; index < count; index++) {
     const keyword = keywords[index];
     if (title.includes(keyword) || path.includes(keyword)) {
-      form['is_formless_checkout'] = true;
       return __gCrWeb.fill.formOrFieldsetsToFormData(
           null /* formElement*/, null /* formControlElement */, fieldsets,
           controlElements, extractMask, form, null /* field */);
diff --git a/components/autofill_assistant/browser/BUILD.gn b/components/autofill_assistant/browser/BUILD.gn
index 8f060ef..3f994f2 100644
--- a/components/autofill_assistant/browser/BUILD.gn
+++ b/components/autofill_assistant/browser/BUILD.gn
@@ -143,6 +143,8 @@
     "generic_ui_replace_placeholders.h",
     "info_box.cc",
     "info_box.h",
+    "intent_strings.cc",
+    "intent_strings.h",
     "metrics.cc",
     "metrics.h",
     "onboarding_result.h",
@@ -467,6 +469,12 @@
     ]
   }
 
+  java_cpp_strings("autofill_assistant_intent_strings_java") {
+    sources = [ "intent_strings.cc" ]
+
+    template = "java_templates/IntentStrings.java.tmpl"
+  }
+
   static_library("test_support") {
     testonly = true
     sources = [
diff --git a/components/autofill_assistant/browser/intent_strings.cc b/components/autofill_assistant/browser/intent_strings.cc
new file mode 100644
index 0000000..66df76b
--- /dev/null
+++ b/components/autofill_assistant/browser/intent_strings.cc
@@ -0,0 +1,18 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/autofill_assistant/browser/intent_strings.h"
+
+namespace autofill_assistant {
+const char kBuyMovieTicket[] = "BUY_MOVIE_TICKET";
+const char kFlightsCheckin[] = "FLIGHTS_CHECKIN";
+const char kFoodOrdering[] = "FOOD_ORDERING";
+const char kFoodOrderingDelivery[] = "FOOD_ORDERING_DELIVERY";
+const char kFoodOrderingPickup[] = "FOOD_ORDERING_PICKUP";
+const char kPasswordChange[] = "PASSWORD_CHANGE";
+const char kRentCar[] = "RENT_CAR";
+const char kShopping[] = "SHOPPING";
+const char kShoppingAssistedCheckout[] = "SHOPPING_ASSISTED_CHECKOUT";
+const char kTeleport[] = "TELEPORT";
+}  // namespace autofill_assistant
diff --git a/components/autofill_assistant/browser/intent_strings.h b/components/autofill_assistant/browser/intent_strings.h
new file mode 100644
index 0000000..94ee0fa
--- /dev/null
+++ b/components/autofill_assistant/browser/intent_strings.h
@@ -0,0 +1,27 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_INTENT_STRINGS_H_
+#define COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_INTENT_STRINGS_H_
+
+namespace autofill_assistant {
+// Autofill assistant intents.
+
+// These strings are referenced from both C++ and Java (through the
+// auto-generated file AutofillAssistantIntentStrings.java).
+
+// Please keep the list alphabetized.
+extern const char kBuyMovieTicket[];
+extern const char kFlightsCheckin[];
+extern const char kFoodOrdering[];
+extern const char kFoodOrderingDelivery[];
+extern const char kFoodOrderingPickup[];
+extern const char kPasswordChange[];
+extern const char kRentCar[];
+extern const char kShopping[];
+extern const char kShoppingAssistedCheckout[];
+extern const char kTeleport[];
+}  // namespace autofill_assistant
+
+#endif
diff --git a/components/autofill_assistant/browser/java_templates/IntentStrings.java.tmpl b/components/autofill_assistant/browser/java_templates/IntentStrings.java.tmpl
new file mode 100644
index 0000000..adcbbd0
--- /dev/null
+++ b/components/autofill_assistant/browser/java_templates/IntentStrings.java.tmpl
@@ -0,0 +1,14 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.chrome.browser.autofill_assistant.strings;
+
+/** Payment method identifier strings. */
+public abstract class IntentStrings {{
+
+{NATIVE_STRINGS}
+
+    // Prevent instantiation.
+    private IntentStrings() {{}}
+}}
diff --git a/components/autofill_assistant/browser/metrics.cc b/components/autofill_assistant/browser/metrics.cc
index bb2f39e..5a92fef 100644
--- a/components/autofill_assistant/browser/metrics.cc
+++ b/components/autofill_assistant/browser/metrics.cc
@@ -6,9 +6,12 @@
 
 #include "base/logging.h"
 #include "base/metrics/histogram_functions.h"
+#include "components/autofill_assistant/browser/intent_strings.h"
 #include "components/ukm/content/source_url_recorder.h"
 #include "services/metrics/public/cpp/ukm_builders.h"
 
+#include <map>
+
 namespace autofill_assistant {
 
 namespace {
@@ -22,16 +25,39 @@
 const char kPaymentRequestMandatoryPostalCode[] =
     "Android.AutofillAssistant.PaymentRequest.MandatoryPostalCode";
 static bool DROPOUT_RECORDED = false;
+
+std::string GetSuffixForIntent(const std::string& intent) {
+  std::map<std::string, std::string> histogramsSuffixes = {
+      {kBuyMovieTicket, ".BuyMovieTicket"},
+      {kFlightsCheckin, ".FlightsCheckin"},
+      {kFoodOrdering, ".FoodOrdering"},
+      {kFoodOrderingDelivery, ".FoodOrderingDelivery"},
+      {kFoodOrderingPickup, ".FoodOrderingPickup"},
+      {kPasswordChange, ".PasswordChange"},
+      {kRentCar, ".RentCar"},
+      {kShopping, ".Shopping"},
+      {kShoppingAssistedCheckout, ".ShoppingAssistedCheckout"},
+      {kTeleport, ".Teleport"}};
+
+  // Check if histogram exists for given intent.
+  if (histogramsSuffixes.count(intent) == 0) {
+    DVLOG(2) << "Unknow intent " << intent;
+    return ".UnknownIntent";
+  }
+  return histogramsSuffixes[intent];
+}
 }  // namespace
 
 // static
-void Metrics::RecordDropOut(DropOutReason reason) {
+void Metrics::RecordDropOut(DropOutReason reason, const std::string& intent) {
   DCHECK_LE(reason, DropOutReason::kMaxValue);
   if (DROPOUT_RECORDED) {
     return;
   }
   DVLOG_IF(3, reason != DropOutReason::AA_START)
       << "Drop out with reason: " << reason;
+  auto suffix = GetSuffixForIntent(intent);
+  base::UmaHistogramEnumeration(kDropOutEnumName + suffix, reason);
   base::UmaHistogramEnumeration(kDropOutEnumName, reason);
   DROPOUT_RECORDED = true;
 }
diff --git a/components/autofill_assistant/browser/metrics.h b/components/autofill_assistant/browser/metrics.h
index 9416af5..a513aa0 100644
--- a/components/autofill_assistant/browser/metrics.h
+++ b/components/autofill_assistant/browser/metrics.h
@@ -333,7 +333,7 @@
     kMaxValue = LITE_SCRIPT_ONBOARDING_SEEN_AND_INTERRUPTED_BY_NAVIGATION
   };
 
-  static void RecordDropOut(DropOutReason reason);
+  static void RecordDropOut(DropOutReason reason, const std::string& intent);
   static void RecordPaymentRequestPrefilledSuccess(bool initially_complete,
                                                    bool success);
   static void RecordPaymentRequestAutofillChanged(bool changed, bool success);
diff --git a/components/autofill_assistant/browser/script_parameters.cc b/components/autofill_assistant/browser/script_parameters.cc
index 310af0c..8152273 100644
--- a/components/autofill_assistant/browser/script_parameters.cc
+++ b/components/autofill_assistant/browser/script_parameters.cc
@@ -78,6 +78,9 @@
 const char kTriggerScriptExperimentParameterName[] =
     "TRIGGER_SCRIPT_EXPERIMENT";
 
+// The intent parameter.
+const char kIntent[] = "INTENT";
+
 // The list of script parameters that trigger scripts are allowed to send to
 // the backend.
 constexpr std::array<const char*, 5> kAllowlistedTriggerScriptParameters = {
@@ -200,6 +203,10 @@
                                  kTriggerScriptExperimentParameterName);
 }
 
+base::Optional<std::string> ScriptParameters::GetIntent() const {
+  return GetParameter(kIntent);
+}
+
 base::Optional<bool> ScriptParameters::GetDetailsShowInitial() const {
   return GetTypedParameter<bool>(parameters_, kDetailsShowInitialParameterName);
 }
diff --git a/components/autofill_assistant/browser/script_parameters.h b/components/autofill_assistant/browser/script_parameters.h
index 3b18bdbd..ba0d963 100644
--- a/components/autofill_assistant/browser/script_parameters.h
+++ b/components/autofill_assistant/browser/script_parameters.h
@@ -45,6 +45,7 @@
   base::Optional<bool> GetEnabled() const;
   base::Optional<std::string> GetOriginalDeeplink() const;
   base::Optional<bool> GetTriggerScriptExperiment() const;
+  base::Optional<std::string> GetIntent() const;
 
   // Details parameters.
   base::Optional<bool> GetDetailsShowInitial() const;
diff --git a/components/download/public/background_service/BUILD.gn b/components/download/public/background_service/BUILD.gn
index c9d96905..0e22c56 100644
--- a/components/download/public/background_service/BUILD.gn
+++ b/components/download/public/background_service/BUILD.gn
@@ -9,6 +9,8 @@
 
 source_set("public") {
   sources = [
+    "basic_task_scheduler.cc",
+    "basic_task_scheduler.h",
     "blob_context_getter_factory.h",
     "client.cc",
     "client.h",
diff --git a/components/download/public/background_service/basic_task_scheduler.cc b/components/download/public/background_service/basic_task_scheduler.cc
new file mode 100644
index 0000000..69dd08e
--- /dev/null
+++ b/components/download/public/background_service/basic_task_scheduler.cc
@@ -0,0 +1,53 @@
+// Copyright 2017 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/download/public/background_service/basic_task_scheduler.h"
+
+#include "base/bind.h"
+#include "base/sequenced_task_runner.h"
+#include "base/task/post_task.h"
+#include "base/task/task_traits.h"
+#include "base/threading/thread_task_runner_handle.h"
+#include "base/time/time.h"
+#include "components/download/public/background_service/download_service.h"
+
+namespace download {
+
+BasicTaskScheduler::BasicTaskScheduler(
+    const base::RepeatingCallback<DownloadService*()>& get_download_service)
+    : get_download_service_(get_download_service) {}
+
+BasicTaskScheduler::~BasicTaskScheduler() = default;
+
+void BasicTaskScheduler::ScheduleTask(download::DownloadTaskType task_type,
+                                      bool require_unmetered_network,
+                                      bool require_charging,
+                                      int optimal_battery_percentage,
+                                      int64_t window_start_time_seconds,
+                                      int64_t window_end_time_seconds) {
+  scheduled_tasks_[task_type].Reset(
+      base::BindOnce(&BasicTaskScheduler::RunScheduledTask,
+                     weak_factory_.GetWeakPtr(), task_type));
+  base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
+      FROM_HERE, scheduled_tasks_[task_type].callback(),
+      base::TimeDelta::FromSeconds(window_start_time_seconds));
+}
+
+void BasicTaskScheduler::CancelTask(download::DownloadTaskType task_type) {
+  scheduled_tasks_[task_type].Cancel();
+}
+
+void BasicTaskScheduler::RunScheduledTask(
+    download::DownloadTaskType task_type) {
+  get_download_service_.Run()->OnStartScheduledTask(
+      task_type, base::BindOnce(&BasicTaskScheduler::OnTaskFinished,
+                                weak_factory_.GetWeakPtr()));
+}
+
+void BasicTaskScheduler::OnTaskFinished(bool reschedule) {
+  // TODO(shaktisahu): Cache the original scheduling params and re-post task in
+  // case it needs reschedule.
+}
+
+}  // namespace download
diff --git a/components/download/public/background_service/basic_task_scheduler.h b/components/download/public/background_service/basic_task_scheduler.h
new file mode 100644
index 0000000..aa4fef38
--- /dev/null
+++ b/components/download/public/background_service/basic_task_scheduler.h
@@ -0,0 +1,54 @@
+// Copyright 2017 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_DOWNLOAD_PUBLIC_BACKGROUND_SERVICE_BASIC_TASK_SCHEDULER_H_
+#define COMPONENTS_DOWNLOAD_PUBLIC_BACKGROUND_SERVICE_BASIC_TASK_SCHEDULER_H_
+
+#include <map>
+
+#include "base/callback.h"
+#include "base/cancelable_callback.h"
+#include "base/macros.h"
+#include "base/memory/weak_ptr.h"
+#include "components/download/public/task/task_scheduler.h"
+
+namespace download {
+
+class DownloadService;
+
+// A TaskScheduler implementation that doesn't do anything but posts the task
+// after the specified delay.
+class BasicTaskScheduler : public download::TaskScheduler {
+ public:
+  explicit BasicTaskScheduler(
+      const base::RepeatingCallback<DownloadService*()>& get_download_service);
+  BasicTaskScheduler(const BasicTaskScheduler& other) = delete;
+  BasicTaskScheduler& operator=(const BasicTaskScheduler& other) = delete;
+  ~BasicTaskScheduler() override;
+
+  // TaskScheduler implementation.
+  void ScheduleTask(download::DownloadTaskType task_type,
+                    bool require_unmetered_network,
+                    bool require_charging,
+                    int optimal_battery_percentage,
+                    int64_t window_start_time_seconds,
+                    int64_t window_end_time_seconds) override;
+  void CancelTask(download::DownloadTaskType task_type) override;
+
+ private:
+  void RunScheduledTask(download::DownloadTaskType task_type);
+  void OnTaskFinished(bool reschedule);
+
+  // Keeps track of scheduled tasks so that they can be cancelled.
+  std::map<download::DownloadTaskType, base::CancelableOnceClosure>
+      scheduled_tasks_;
+
+  base::RepeatingCallback<DownloadService*()> get_download_service_;
+
+  base::WeakPtrFactory<BasicTaskScheduler> weak_factory_{this};
+};
+
+}  // namespace download
+
+#endif  // COMPONENTS_DOWNLOAD_PUBLIC_TASK_TASK_SCHEDULER_H_
diff --git a/components/drive/service/fake_drive_service.cc b/components/drive/service/fake_drive_service.cc
index 2557034..3b1ea6b 100644
--- a/components/drive/service/fake_drive_service.cc
+++ b/components/drive/service/fake_drive_service.cc
@@ -796,7 +796,7 @@
           new std::string(content_data.substr(i, size)));
       base::ThreadTaskRunnerHandle::Get()->PostTask(
           FROM_HERE, base::BindOnce(get_content_callback, HTTP_SUCCESS,
-                                    std::move(content_for_callback)));
+                                    std::move(content_for_callback), i == 0));
     }
   }
 
diff --git a/components/installedapp/android/java/src/org/chromium/components/installedapp/InstalledAppProviderImpl.java b/components/installedapp/android/java/src/org/chromium/components/installedapp/InstalledAppProviderImpl.java
index 30e720c..62ee47be 100644
--- a/components/installedapp/android/java/src/org/chromium/components/installedapp/InstalledAppProviderImpl.java
+++ b/components/installedapp/android/java/src/org/chromium/components/installedapp/InstalledAppProviderImpl.java
@@ -62,6 +62,9 @@
     @VisibleForTesting
     public static final String INSTANT_APP_HOLDBACK_ID_STRING = "instantapp:holdback";
 
+    // The delay, in ms, of the most recent invocation of FilterInstalledAppsResponse.
+    int mLastDelayForTesting;
+
     // The maximum number of related apps declared in the Web Manifest taken into account when
     // determining whether the related app is installed and mutually related.
     @VisibleForTesting
@@ -91,6 +94,7 @@
     private final RenderFrameHost mRenderFrameHost;
     // May be overridden in tests.
     private PackageManagerDelegate mPackageManagerDelegate;
+    private boolean mIsInTest;
     @Nullable
     private final InstantAppProvider mInstantAppProvider;
 
@@ -103,6 +107,7 @@
     }
 
     void setPackageManagerDelegateForTest(PackageManagerDelegate packageManagerDelegate) {
+        mIsInTest = true;
         mPackageManagerDelegate = packageManagerDelegate;
     }
 
@@ -198,8 +203,8 @@
      * @param callback The mojo callback for sending the installed apps.
      */
     @UiThread
-    private void onFilteredInstalledApps(ArrayList<RelatedApplication> installedApps,
-            Integer delayMs, FilterInstalledAppsResponse callback) {
+    private void onFilteredInstalledApps(ArrayList<RelatedApplication> installedApps, int delayMs,
+            FilterInstalledAppsResponse callback) {
         RelatedApplication[] installedAppsArray;
 
         if (mRenderFrameHost.isIncognito()) {
@@ -212,7 +217,9 @@
             installedApps.toArray(installedAppsArray);
         }
 
-        delayThenRun(() -> callback.call(installedAppsArray), delayMs);
+        mLastDelayForTesting = delayMs;
+        PostTask.postDelayedTask(UiThreadTaskTraits.DEFAULT,
+                () -> callback.call(installedAppsArray), mIsInTest ? 0 : delayMs);
     }
 
     @WorkerThread
@@ -224,12 +231,12 @@
                 && !mInstantAppProvider.isInstantAppAvailable(frameUrl.getSpec(),
                         INSTANT_APP_HOLDBACK_ID_STRING.equals(app.id),
                         true /* includeUserPrefersBrowser */)) {
-            delayThenRun(() -> resultHolder.onResult(null, taskIdx, delayMs), 0);
+            postResultOnUiThread(resultHolder, null, taskIdx, delayMs);
             return;
         }
 
         setVersionInfo(app);
-        delayThenRun(() -> resultHolder.onResult(app, taskIdx, delayMs), 0);
+        postResultOnUiThread(resultHolder, app, taskIdx, delayMs);
     }
 
     @WorkerThread
@@ -238,12 +245,12 @@
         int delayMs = calculateDelayForPackageMs(app.id);
 
         if (!isAppInstalledAndAssociatedWithOrigin(app.id, frameUrl, mPackageManagerDelegate)) {
-            delayThenRun(() -> resultHolder.onResult(null, taskIdx, delayMs), 0);
+            postResultOnUiThread(resultHolder, null, taskIdx, delayMs);
             return;
         }
 
         setVersionInfo(app);
-        delayThenRun(() -> resultHolder.onResult(app, taskIdx, delayMs), 0);
+        postResultOnUiThread(resultHolder, app, taskIdx, delayMs);
     }
 
     @WorkerThread
@@ -252,13 +259,13 @@
         int delayMs = calculateDelayForPackageMs(app.url);
 
         if (!isWebApkInstalled(app.url)) {
-            delayThenRun(() -> resultHolder.onResult(null, taskIdx, delayMs), 0);
+            postResultOnUiThread(resultHolder, null, taskIdx, delayMs);
             return;
         }
 
         // TODO(crbug.com/1043970): Should we expose the package name and the
         // version?
-        delayThenRun(() -> resultHolder.onResult(app, taskIdx, delayMs), 0);
+        postResultOnUiThread(resultHolder, app, taskIdx, delayMs);
     }
 
     @UiThread
@@ -435,9 +442,8 @@
         } catch (Resources.NotFoundException e) {
             // This should never happen, but it could if there was a broken APK, so handle it
             // gracefully without crashing.
-            Log.w(TAG,
-                    "Android package " + packageName + " missing asset statements resource (0x"
-                            + Integer.toHexString(identifier) + ").");
+            Log.w(TAG, "Android package %s missing asset statements resource (0x%s).", packageName,
+                    Integer.toHexString(identifier));
             return new JSONArray();
         }
 
@@ -446,9 +452,8 @@
         } catch (JSONException e) {
             // If the JSON is invalid or not an array, assume it is empty.
             Log.w(TAG,
-                    "Android package " + packageName
-                            + " has JSON syntax error in asset statements resource (0x"
-                            + Integer.toHexString(identifier) + ").");
+                    "Android package %s has JSON syntax error in asset statements resource (0x%s).",
+                    packageName, Integer.toHexString(identifier));
             return new JSONArray();
         }
     }
@@ -507,17 +512,10 @@
                 && assetUrl.getPort().equals(frameUrl.getPort());
     }
 
-    /**
-     * Runs a Runnable task after a given delay.
-     *
-     * Protected and non-static for testing.
-     *
-     * @param r The Runnable that will be executed.
-     * @param delayMillis The delay (in ms) until the Runnable will be executed.
-     * @return True if the Runnable was successfully placed into the message queue.
-     */
-    protected void delayThenRun(Runnable r, long delayMillis) {
-        PostTask.postDelayedTask(UiThreadTaskTraits.DEFAULT, r, delayMillis);
+    private static void postResultOnUiThread(
+            ResultHolder resultHolder, RelatedApplication app, int taskIdx, int delayMs) {
+        PostTask.postTask(
+                UiThreadTaskTraits.DEFAULT, () -> resultHolder.onResult(app, taskIdx, delayMs));
     }
 
     @NativeMethods
diff --git a/components/installedapp/android/java/src/org/chromium/components/installedapp/InstalledAppProviderTest.java b/components/installedapp/android/java/src/org/chromium/components/installedapp/InstalledAppProviderTest.java
index 00d0f12..80e7e8d3 100644
--- a/components/installedapp/android/java/src/org/chromium/components/installedapp/InstalledAppProviderTest.java
+++ b/components/installedapp/android/java/src/org/chromium/components/installedapp/InstalledAppProviderTest.java
@@ -138,8 +138,6 @@
     }
 
     private class InstalledAppProviderTestImpl extends InstalledAppProviderImpl {
-        private long mLastDelayMillis;
-
         public InstalledAppProviderTestImpl(
                 RenderFrameHost renderFrameHost, FakeInstantAppsHandler instantAppsHandler) {
             super(new BrowserContextHandle() {
@@ -150,16 +148,6 @@
             }, renderFrameHost, instantAppsHandler::isInstantAppAvailable);
         }
 
-        public long getLastDelayMillis() {
-            return mLastDelayMillis;
-        }
-
-        @Override
-        protected void delayThenRun(Runnable r, long delayMillis) {
-            mLastDelayMillis = delayMillis;
-            super.delayThenRun(r, 0);
-        }
-
         @Override
         public boolean isWebApkInstalled(String manifestUrl) {
             return mFakePackageManager.isWebApkInstalled(manifestUrl);
@@ -902,7 +890,7 @@
         verifyInstalledApps(manifestRelatedApps, expectedInstalledRelatedApps);
         // This expectation is based on HMAC_SHA256(salt, packageName encoded in UTF-8), taking the
         // low 10 bits of the first two bytes of the result / 100.
-        Assert.assertEquals(2, mInstalledAppProvider.getLastDelayMillis());
+        Assert.assertEquals(2, mInstalledAppProvider.mLastDelayForTesting);
 
         // Non-installed app.
         manifestRelatedApps = new RelatedApplication[] {
@@ -911,7 +899,7 @@
         verifyInstalledApps(manifestRelatedApps, expectedInstalledRelatedApps);
         // This expectation is based on HMAC_SHA256(salt, packageName encoded in UTF-8), taking the
         // low 10 bits of the first two bytes of the result / 100.
-        Assert.assertEquals(5, mInstalledAppProvider.getLastDelayMillis());
+        Assert.assertEquals(5, mInstalledAppProvider.mLastDelayForTesting);
 
         // Own WebAPK.
         manifestRelatedApps = new RelatedApplication[] {
@@ -920,7 +908,7 @@
         verifyInstalledApps(manifestRelatedApps, expectedInstalledRelatedApps);
         // This expectation is based on HMAC_SHA256(salt, manifestUrl encoded in UTF-8), taking the
         // low 10 bits of the first two bytes of the result / 100.
-        Assert.assertEquals(3, mInstalledAppProvider.getLastDelayMillis());
+        Assert.assertEquals(3, mInstalledAppProvider.mLastDelayForTesting);
 
         // Another WebAPK.
         manifestRelatedApps = new RelatedApplication[] {
@@ -929,7 +917,7 @@
         verifyInstalledApps(manifestRelatedApps, expectedInstalledRelatedApps);
         // This expectation is based on HMAC_SHA256(salt, manifestUrl encoded in UTF-8), taking the
         // low 10 bits of the first two bytes of the result / 100.
-        Assert.assertEquals(8, mInstalledAppProvider.getLastDelayMillis());
+        Assert.assertEquals(8, mInstalledAppProvider.mLastDelayForTesting);
     }
 
     @Test
diff --git a/components/paint_preview/common/mojom/paint_preview_recorder.mojom b/components/paint_preview/common/mojom/paint_preview_recorder.mojom
index 1d851ad..5779f87 100644
--- a/components/paint_preview/common/mojom/paint_preview_recorder.mojom
+++ b/components/paint_preview/common/mojom/paint_preview_recorder.mojom
@@ -97,6 +97,7 @@
   uint64 serialized_size;
 
   // Scroll offsets of the frame at capture time.
+  // TODO(crbug.com/738465): This should likely be a gfx.mojom.ScrollOffset.
   gfx.mojom.Size scroll_offsets;
 
   // The serialized skia picture. See |SerializedRecording| for details on
diff --git a/components/paint_preview/renderer/paint_preview_recorder_impl.cc b/components/paint_preview/renderer/paint_preview_recorder_impl.cc
index e2d8f2d..5ae7238 100644
--- a/components/paint_preview/renderer/paint_preview_recorder_impl.cc
+++ b/components/paint_preview/renderer/paint_preview_recorder_impl.cc
@@ -278,8 +278,8 @@
 
   auto tracker = std::make_unique<PaintPreviewTracker>(
       params->guid, frame->GetEmbeddingToken(), is_main_frame_);
-  auto size = frame->GetScrollOffset();
-  response->scroll_offsets = gfx::Size(size.width, size.height);
+  auto offset = frame->GetScrollOffset();
+  response->scroll_offsets = gfx::Size(offset.x(), offset.y());
 
   cc::PaintRecorder recorder;
   cc::PaintCanvas* canvas =
diff --git a/components/password_manager/core/browser/form_parsing/fuzzer/form_data_essentials.proto b/components/password_manager/core/browser/form_parsing/fuzzer/form_data_essentials.proto
index fde6d4bd..bbc0834 100644
--- a/components/password_manager/core/browser/form_parsing/fuzzer/form_data_essentials.proto
+++ b/components/password_manager/core/browser/form_parsing/fuzzer/form_data_essentials.proto
@@ -23,7 +23,6 @@
 message Form {
   bool is_mode_filling = 1;
   bool is_form_tag = 2;
-  bool is_formless_checkout = 3;
   string name = 4;
   string action = 5;
   string origin = 6;
diff --git a/components/password_manager/core/browser/form_parsing/fuzzer/form_data_producer.cc b/components/password_manager/core/browser/form_parsing/fuzzer/form_data_producer.cc
index 0b955de..aed5909 100644
--- a/components/password_manager/core/browser/form_parsing/fuzzer/form_data_producer.cc
+++ b/components/password_manager/core/browser/form_parsing/fuzzer/form_data_producer.cc
@@ -70,7 +70,6 @@
   // First determine the main non-string attributes not specific to particular
   // fields.
   result.is_form_tag = accessor->ConsumeBit();
-  result.is_formless_checkout = accessor->ConsumeBit();
 
   // To minimize wasting bits, string-based data itself gets extracted after all
   // numbers and flags are. Their length can be determined now, however. A
diff --git a/components/password_manager/core/browser/form_parsing/fuzzer/form_data_proto_producer.cc b/components/password_manager/core/browser/form_parsing/fuzzer/form_data_proto_producer.cc
index 9e20bc4..342f5d4 100644
--- a/components/password_manager/core/browser/form_parsing/fuzzer/form_data_proto_producer.cc
+++ b/components/password_manager/core/browser/form_parsing/fuzzer/form_data_proto_producer.cc
@@ -35,7 +35,6 @@
   result.id_attribute = UTF8ToUTF16(form_proto.id());
   result.name_attribute = UTF8ToUTF16(form_proto.name());
   result.is_form_tag = form_proto.is_form_tag();
-  result.is_formless_checkout = form_proto.is_formless_checkout();
   result.name = UTF8ToUTF16(form_proto.name());
   result.action = GURL(form_proto.action());
   result.url = GURL(form_proto.origin());
diff --git a/components/password_manager/ios/BUILD.gn b/components/password_manager/ios/BUILD.gn
index 9cdd83f..e22a07d9 100644
--- a/components/password_manager/ios/BUILD.gn
+++ b/components/password_manager/ios/BUILD.gn
@@ -32,7 +32,6 @@
     "js_password_manager.mm",
     "password_form_helper.h",
     "password_form_helper.mm",
-    "password_generation_provider.h",
     "password_manager_client_bridge.h",
     "password_manager_driver_bridge.h",
     "password_manager_ios_util.h",
diff --git a/components/password_manager/ios/password_generation_provider.h b/components/password_manager/ios/password_generation_provider.h
deleted file mode 100644
index 990f521..0000000
--- a/components/password_manager/ios/password_generation_provider.h
+++ /dev/null
@@ -1,15 +0,0 @@
-// Copyright 2021 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef COMPONENTS_PASSWORD_MANAGER_IOS_PASSWORD_GENERATION_PROVIDER_H_
-#define COMPONENTS_PASSWORD_MANAGER_IOS_PASSWORD_GENERATION_PROVIDER_H_
-
-@protocol PasswordGenerationProvider <NSObject>
-
-// Triggers password generation on the active field.
-- (void)triggerPasswordGeneration;
-
-@end
-
-#endif  // COMPONENTS_PASSWORD_MANAGER_IOS_PASSWORD_GENERATION_PROVIDER_H_
diff --git a/components/password_manager/ios/shared_password_controller.h b/components/password_manager/ios/shared_password_controller.h
index eed7c63..2762a3c2 100644
--- a/components/password_manager/ios/shared_password_controller.h
+++ b/components/password_manager/ios/shared_password_controller.h
@@ -12,7 +12,6 @@
 #import "components/autofill/ios/form_util/form_activity_observer.h"
 #include "components/password_manager/core/browser/password_manager_interface.h"
 #import "components/password_manager/ios/password_form_helper.h"
-#import "components/password_manager/ios/password_generation_provider.h"
 #import "components/password_manager/ios/password_manager_driver_bridge.h"
 #import "components/password_manager/ios/password_suggestion_helper.h"
 #import "ios/web/public/web_state_observer_bridge.h"
@@ -55,12 +54,11 @@
 // suggestions, filling forms, and generating passwords.
 @interface SharedPasswordController
     : NSObject <CRWWebStateObserver,
-                FormActivityObserver,
-                FormSuggestionProvider,
-                PasswordFormHelperDelegate,
-                PasswordGenerationProvider,
                 PasswordManagerDriverBridge,
-                PasswordSuggestionHelperDelegate>
+                PasswordSuggestionHelperDelegate,
+                PasswordFormHelperDelegate,
+                FormSuggestionProvider,
+                FormActivityObserver>
 
 // Helper contains common password form processing logic.
 @property(nonatomic, readonly) PasswordFormHelper* formHelper;
diff --git a/components/password_manager/ios/shared_password_controller.mm b/components/password_manager/ios/shared_password_controller.mm
index cbe1084..69840a1 100644
--- a/components/password_manager/ios/shared_password_controller.mm
+++ b/components/password_manager/ios/shared_password_controller.mm
@@ -52,27 +52,27 @@
 #error "This file requires ARC support."
 #endif
 
-using autofill::FieldRendererId;
 using autofill::FormActivityObserverBridge;
 using autofill::FormData;
-using autofill::FormRendererId;
 using autofill::PasswordFormGenerationData;
+using autofill::FormRendererId;
+using autofill::FieldRendererId;
 using base::SysNSStringToUTF16;
-using base::SysUTF16ToNSString;
 using base::SysUTF8ToNSString;
+using base::SysUTF16ToNSString;
 using l10n_util::GetNSString;
 using l10n_util::GetNSStringF;
+using password_manager::metrics_util::LogPasswordDropdownShown;
+using password_manager::metrics_util::PasswordDropdownState;
 using password_manager::AccountSelectFillData;
 using password_manager::FillData;
 using password_manager::GetPageURLAndCheckTrustLevel;
 using password_manager::JsonStringToFormData;
-using password_manager::metrics_util::LogPasswordDropdownShown;
-using password_manager::metrics_util::PasswordDropdownState;
 using password_manager::PasswordFormManagerForUI;
 using password_manager::PasswordGenerationFrameHelper;
+using password_manager::PasswordManagerInterface;
 using password_manager::PasswordManagerClient;
 using password_manager::PasswordManagerDriver;
-using password_manager::PasswordManagerInterface;
 using password_manager::SerializePasswordFormFillData;
 
 namespace {
@@ -121,12 +121,6 @@
 
   FieldRendererId _lastTypedfieldIdentifier;
   NSString* _lastTypedValue;
-
-  // Identifier of the last focused form.
-  FormRendererId _lastFocusedFormIdentifier;
-
-  // Identifier of the last focused field.
-  FieldRendererId _lastFocusedFieldIdentifier;
 }
 
 - (instancetype)initWithWebState:(web::WebState*)webState
@@ -163,17 +157,6 @@
   return _delegate.passwordManagerClient->IsIncognito();
 }
 
-#pragma mark - PasswordGenerationProvider
-
-- (void)triggerPasswordGeneration {
-  if (!_lastFocusedFieldIdentifier) {
-    return;
-  }
-  [self generatePasswordForFormId:_lastFocusedFormIdentifier
-                  fieldIdentifier:_lastFocusedFieldIdentifier
-              isManuallyTriggered:YES];
-}
-
 #pragma mark - CRWWebStateObserver
 
 - (void)webState:(web::WebState*)webState
@@ -259,8 +242,6 @@
   _isPasswordGenerated = NO;
   _lastTypedfieldIdentifier = FieldRendererId();
   _lastTypedValue = nil;
-  _lastFocusedFormIdentifier = FormRendererId();
-  _lastFocusedFieldIdentifier = FieldRendererId();
 }
 
 #pragma mark - FormSuggestionProvider
@@ -407,8 +388,7 @@
       // Don't call completion because current suggestion state should remain
       // whether user injects a generated password or cancels.
       [self generatePasswordForFormId:uniqueFormID
-                      fieldIdentifier:uniqueFieldID
-                  isManuallyTriggered:NO];
+                      fieldIdentifier:uniqueFieldID];
       password_manager::metrics_util::LogPasswordDropdownItemSelected(
           password_manager::metrics_util::PasswordDropdownSelectedOption::
               kGenerate,
@@ -569,24 +549,9 @@
 }
 
 - (void)generatePasswordForFormId:(FormRendererId)formIdentifier
-                  fieldIdentifier:(FieldRendererId)fieldIdentifier
-              isManuallyTriggered:(BOOL)isManuallyTriggered {
-  const autofill::PasswordFormGenerationData* generationData =
-      [self formForGenerationFromFormID:formIdentifier];
-  if (!isManuallyTriggered && !generationData) {
+                  fieldIdentifier:(FieldRendererId)fieldIdentifier {
+  if (![self formForGenerationFromFormID:formIdentifier])
     return;
-  }
-
-  BOOL shouldUpdateGenerationData =
-      !generationData ||
-      generationData->new_password_renderer_id != fieldIdentifier;
-  if (isManuallyTriggered && shouldUpdateGenerationData) {
-    PasswordFormGenerationData generation_data = {
-        .form_renderer_id = formIdentifier,
-        .new_password_renderer_id = fieldIdentifier,
-    };
-    [self formEligibleForGenerationFound:generation_data];
-  }
 
   // TODO(crbug.com/886583): pass correct |max_length|.
   base::string16 generatedPassword =
@@ -665,17 +630,15 @@
   DCHECK_EQ(_webState, webState);
 
   GURL pageURL;
-  if (!GetPageURLAndCheckTrustLevel(webState, &pageURL) || !frame ||
-      !frame->CanCallJavaScriptFunction() || params.input_missing) {
-    _lastFocusedFormIdentifier = FormRendererId();
-    _lastFocusedFieldIdentifier = FieldRendererId();
+  if (!GetPageURLAndCheckTrustLevel(webState, &pageURL))
     return;
-  }
 
-  if (params.type == "focus") {
-    _lastFocusedFormIdentifier = params.unique_form_id;
-    _lastFocusedFieldIdentifier = params.unique_field_id;
-  }
+  if (!frame || !frame->CanCallJavaScriptFunction())
+    return;
+
+  // Return early if |params| is not complete.
+  if (params.input_missing)
+    return;
 
   // If there's a change in password forms on a page, they should be parsed
   // again.
diff --git a/components/password_manager/ios/shared_password_controller_unittest.mm b/components/password_manager/ios/shared_password_controller_unittest.mm
index 917beb6..cee9df8d 100644
--- a/components/password_manager/ios/shared_password_controller_unittest.mm
+++ b/components/password_manager/ios/shared_password_controller_unittest.mm
@@ -9,7 +9,6 @@
 #include "components/autofill/core/common/password_form_generation_data.h"
 #import "components/autofill/ios/browser/form_suggestion.h"
 #import "components/autofill/ios/browser/form_suggestion_provider_query.h"
-#include "components/autofill/ios/form_util/form_activity_params.h"
 #include "components/autofill/ios/form_util/unique_id_data_tab_helper.h"
 #include "components/password_manager/core/browser/password_manager_interface.h"
 #include "components/password_manager/core/browser/stub_password_manager_client.h"
@@ -426,57 +425,6 @@
   [delegate_ verify];
 }
 
-// Tests that triggering password generation on the last focused field triggers
-// the generation flow.
-TEST_F(SharedPasswordControllerTest, TriggerPasswordGeneration) {
-  autofill::FormActivityParams params;
-  params.unique_form_id = autofill::FormRendererId(0);
-  params.field_type = "password";
-  params.unique_field_id = autofill::FieldRendererId(1);
-  params.type = "focus";
-  params.input_missing = false;
-
-  web::FakeWebFrame web_frame("frame-id", /*is_main_frame=*/true, GURL());
-
-  [controller_ webState:&web_state_
-      didRegisterFormActivity:params
-                      inFrame:&web_frame];
-
-  [[delegate_ expect] sharedPasswordController:controller_
-                showGeneratedPotentialPassword:[OCMArg isNotNil]
-                               decisionHandler:[OCMArg any]];
-
-  [controller_ triggerPasswordGeneration];
-
-  [delegate_ verify];
-}
-
-// Tests that triggering password generation on the last focused field does not
-// trigger the generation flow if the last reported form activity did not
-// provide valid form and field identifiers.
-TEST_F(SharedPasswordControllerTest, LastFocusedFieldData) {
-  autofill::FormActivityParams params;
-  params.unique_form_id = autofill::FormRendererId(0);
-  params.field_type = "password";
-  params.unique_field_id = autofill::FieldRendererId(1);
-  params.type = "focus";
-  params.input_missing = true;
-
-  web::FakeWebFrame web_frame("frame-id", /*is_main_frame=*/true, GURL());
-
-  [controller_ webState:&web_state_
-      didRegisterFormActivity:params
-                      inFrame:&web_frame];
-
-  [[delegate_ reject] sharedPasswordController:controller_
-                showGeneratedPotentialPassword:[OCMArg isNotNil]
-                               decisionHandler:[OCMArg any]];
-
-  [controller_ triggerPasswordGeneration];
-
-  [delegate_ verify];
-}
-
 // TODO(crbug.com/1097353): Finish unit testing the rest of the public API.
 
 }  // namespace password_manager
diff --git a/components/performance_manager/freezing/freezing.cc b/components/performance_manager/freezing/freezing.cc
index 0a1fba4..6f0f1ca 100644
--- a/components/performance_manager/freezing/freezing.cc
+++ b/components/performance_manager/freezing/freezing.cc
@@ -4,15 +4,28 @@
 
 #include "components/performance_manager/public/freezing/freezing.h"
 
+#include <memory>
+
 #include "base/bind.h"
+#include "base/containers/contains.h"
+#include "base/containers/flat_map.h"
+#include "base/containers/flat_set.h"
+#include "base/memory/ptr_util.h"
 #include "base/scoped_observation.h"
 #include "base/sequence_checker.h"
 #include "base/sequenced_task_runner.h"
 #include "base/task/post_task.h"
+#include "base/thread_annotations.h"
 #include "components/performance_manager/freezing/freezing_vote_aggregator.h"
+#include "components/performance_manager/graph/graph_impl.h"
+#include "components/performance_manager/graph/node_attached_data_impl.h"
+#include "components/performance_manager/graph/page_node_impl.h"
 #include "components/performance_manager/performance_manager_impl.h"
+#include "components/performance_manager/public/graph/graph.h"
+#include "components/performance_manager/public/graph/graph_registered.h"
 #include "components/performance_manager/public/graph/page_node.h"
 #include "components/performance_manager/public/performance_manager.h"
+#include "content/public/browser/browser_thread.h"
 #include "content/public/browser/web_contents.h"
 
 namespace performance_manager {
@@ -21,37 +34,101 @@
 
 namespace {
 
-// The counterpart of a FreezingVoteToken that lives on the PM sequence.
-class FreezingVoteTokenPMImpl : public PageNode::ObserverDefaultImpl {
- public:
-  FreezingVoteTokenPMImpl(content::WebContents* content,
-                          FreezingVoteValue vote_value,
-                          const char* vote_reason);
-  ~FreezingVoteTokenPMImpl() override;
-  FreezingVoteTokenPMImpl(const FreezingVoteTokenPMImpl& other) = delete;
-  FreezingVoteTokenPMImpl& operator=(const FreezingVoteTokenPMImpl&) = delete;
+class FreezingVoteTokenImpl;
 
-  void InitializeOnGraph(base::WeakPtr<PageNode> page_node,
-                         FreezingVote vote,
-                         Graph* graph);
+// NodeAttachedData used to store the set of FreezingVoteTokenImpl objects
+// associated with a PageNode.
+class FreezingVoteNodeData : public NodeAttachedDataImpl<FreezingVoteNodeData> {
+ public:
+  struct Traits : public NodeAttachedDataInMap<PageNodeImpl> {};
+
+  ~FreezingVoteNodeData() override = default;
+
+  void AddVote(FreezingVoteTokenImpl* token);
+  void RemoveVote(FreezingVoteTokenImpl* token);
+  bool IsEmpty() { return vote_tokens_.empty(); }
+  const base::flat_set<FreezingVoteTokenImpl*>& vote_tokens() {
+    return vote_tokens_;
+  }
+
+ private:
+  friend class ::performance_manager::NodeAttachedDataImpl<
+      FreezingVoteNodeData>;
+  explicit FreezingVoteNodeData(const PageNodeImpl* page_node) {}
+
+  // The freezing votes associated with this node.
+  base::flat_set<FreezingVoteTokenImpl*> vote_tokens_;
+};
+
+// A registry of FreezingVoteToken that lives on the PM sequence.
+//
+// There can be multiple freezing votes associated with the same page node.
+class FreezingVoteTokenPMRegistry
+    : public PageNode::ObserverDefaultImpl,
+      public GraphOwned,
+      public GraphRegisteredImpl<FreezingVoteTokenPMRegistry> {
+ public:
+  // A map that associates a voting token to a
+  // <FreezingVotingChannel, const PageNode*> pair.
+  using VotingChannelsMap =
+      base::flat_map<FreezingVoteTokenImpl*,
+                     std::pair<FreezingVotingChannel, const PageNode*>>;
+
+  // Returns the FreezingVoteTokenPMRegistry graph owned instance, creates it if
+  // necessary. Can only be called from the PM sequence.
+  static FreezingVoteTokenPMRegistry* GetOrCreateInstance(Graph* graph);
+
+  FreezingVoteTokenPMRegistry(const FreezingVoteTokenPMRegistry& other) =
+      delete;
+  FreezingVoteTokenPMRegistry& operator=(const FreezingVoteTokenPMRegistry&) =
+      delete;
+
+  // Register a freezing vote for |contents|. |token| is an ID to associate with
+  // this vote, there can be only one vote associated with this ID and it as to
+  // be passed |UnregisterVote| when the vote is invalidated. This can only be
+  // called from the UI thread.
+  static void RegisterVoteForWebContents(content::WebContents* contents,
+                                         FreezingVoteValue vote_value,
+                                         const char* vote_reason,
+                                         FreezingVoteTokenImpl* token);
+
+  // Unregister the vote associated with |token|. This can only be called from
+  // the UI thread.
+  static void UnregisterVote(FreezingVoteTokenImpl* token);
+
+  const VotingChannelsMap& voting_channels_for_testing() {
+    return voting_channels_;
+  }
+
+ private:
+  FreezingVoteTokenPMRegistry() = default;
+
+  // Register a vote for |page_node| on the PM sequence. |token| is an ID
+  // associated with this vote that will be used when invalidating it.
+  void RegisterVoteOnPMSequence(base::WeakPtr<PageNode> page_node,
+                                FreezingVote vote,
+                                FreezingVoteTokenImpl* token);
+
+  // Unregister the vote associated with |token|.
+  void UnregisterVoteOnPMSequence(FreezingVoteTokenImpl* token);
 
   // PageNodeObserver:
   void OnBeforePageNodeRemoved(const PageNode* page_node) override;
 
- private:
-  // Resets this instance so it is no longer casting a vote for |page_node_|.
-  void Reset();
+  // GraphOwned:
+  void OnPassedToGraph(Graph* graph) override;
+  void OnTakenFromGraph(Graph* graph) override;
 
-  const PageNode* page_node_ = nullptr;
+  // Reset the voting channel associated with |voting_channel_iter| and remove
+  // this entry from |voting_channels_|. |voting_channel_iter| has to be a valid
+  // iterator from |voting_channels_|
+  void ResetAndRemoveVotingChannel(
+      VotingChannelsMap::iterator& voting_channel_iter,
+      const PageNode* page_node);
 
-  base::ScopedObservation<Graph,
-                          PageNodeObserver,
-                          &Graph::AddPageNodeObserver,
-                          &Graph::RemovePageNodeObserver>
-      page_node_observation_{this};
+  VotingChannelsMap voting_channels_ GUARDED_BY_CONTEXT(sequence_checker_);
 
-  // Voting channel.
-  FreezingVotingChannel voting_channel_;
+  Graph* graph_ GUARDED_BY_CONTEXT(sequence_checker_);
 
   SEQUENCE_CHECKER(sequence_checker_);
 };
@@ -59,16 +136,12 @@
 // Concrete implementation of a FreezingVoteToken.
 class FreezingVoteTokenImpl : public FreezingVoteToken {
  public:
-  FreezingVoteTokenImpl(content::WebContents* content,
+  FreezingVoteTokenImpl(content::WebContents* contents,
                         FreezingVoteValue vote_value,
                         const char* vote_reason);
   ~FreezingVoteTokenImpl() override;
   FreezingVoteTokenImpl(const FreezingVoteTokenImpl& other) = delete;
   FreezingVoteTokenImpl& operator=(const FreezingVoteTokenImpl&) = delete;
-
- private:
-  // Implementation that lives on the PM sequence.
-  std::unique_ptr<FreezingVoteTokenPMImpl, base::OnTaskRunnerDeleter> pm_impl_;
 };
 
 }  // namespace
@@ -76,82 +149,170 @@
 FreezingVoteToken::FreezingVoteToken() = default;
 FreezingVoteToken::~FreezingVoteToken() = default;
 
-FreezingVoteTokenPMImpl::FreezingVoteTokenPMImpl(content::WebContents* content,
-                                                 FreezingVoteValue vote_value,
-                                                 const char* vote_reason) {
-  DETACH_FROM_SEQUENCE(sequence_checker_);
+void FreezingVoteNodeData::AddVote(FreezingVoteTokenImpl* token) {
+  DCHECK(!base::Contains(vote_tokens_, token));
+  vote_tokens_.insert(token);
+}
+
+void FreezingVoteNodeData::RemoveVote(FreezingVoteTokenImpl* token) {
+  DCHECK(base::Contains(vote_tokens_, token));
+  vote_tokens_.erase(token);
+}
+
+// static
+FreezingVoteTokenPMRegistry* FreezingVoteTokenPMRegistry::GetOrCreateInstance(
+    Graph* graph) {
+  DCHECK(PerformanceManager::GetTaskRunner()->RunsTasksInCurrentSequence());
+  auto* instance = graph->GetRegisteredObjectAs<FreezingVoteTokenPMRegistry>();
+  if (!instance) {
+    auto registry = base::WrapUnique(new FreezingVoteTokenPMRegistry());
+    instance = registry.get();
+    graph->PassToGraph(std::move(registry));
+  }
+  return instance;
+}
+
+// static
+void FreezingVoteTokenPMRegistry::RegisterVoteForWebContents(
+    content::WebContents* contents,
+    FreezingVoteValue vote_value,
+    const char* vote_reason,
+    FreezingVoteTokenImpl* token) {
+  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
   // Register the vote on the PM sequence.
   PerformanceManager::CallOnGraph(
       FROM_HERE,
       base::BindOnce(
-          &FreezingVoteTokenPMImpl::InitializeOnGraph,
-          // It's safe to use Unretained because |this| can only be deleted
-          // from a task running on the PM sequence after this callback.
-          base::Unretained(this),
-          PerformanceManager::GetPageNodeForWebContents(content),
-          FreezingVote(vote_value, vote_reason)));
+          [](base::WeakPtr<PageNode> page_node, FreezingVote vote,
+             FreezingVoteTokenImpl* token, Graph* graph) {
+            auto* registry =
+                FreezingVoteTokenPMRegistry::GetOrCreateInstance(graph);
+            registry->RegisterVoteOnPMSequence(page_node, vote, token);
+          },
+          PerformanceManager::GetPageNodeForWebContents(contents),
+          FreezingVote(vote_value, vote_reason), token));
 }
 
-FreezingVoteTokenPMImpl::~FreezingVoteTokenPMImpl() {
-  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-  Reset();
+// static
+void FreezingVoteTokenPMRegistry::UnregisterVote(FreezingVoteTokenImpl* token) {
+  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+  // Unregister the vote on the PM sequence.
+  PerformanceManager::CallOnGraph(
+      FROM_HERE,
+      base::BindOnce(
+          [](FreezingVoteTokenImpl* token, Graph* graph) {
+            auto* registry =
+                FreezingVoteTokenPMRegistry::GetOrCreateInstance(graph);
+            registry->UnregisterVoteOnPMSequence(token);
+          },
+          token));
 }
 
-void FreezingVoteTokenPMImpl::InitializeOnGraph(
+void FreezingVoteTokenPMRegistry::RegisterVoteOnPMSequence(
     base::WeakPtr<PageNode> page_node,
     FreezingVote vote,
-    Graph* graph) {
+    FreezingVoteTokenImpl* token) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  DCHECK(page_node);
 
-  // No need to initialize if the page node doesn't exist anymore.
-  if (!page_node)
-    return;
+  DCHECK(!base::Contains(voting_channels_, token));
 
-  page_node_ = page_node.get();
-  page_node_observation_.Observe(graph);
+  auto* node_data = FreezingVoteNodeData::GetOrCreate(
+      PageNodeImpl::FromNode(page_node.get()));
 
-  voting_channel_ = graph->GetRegisteredObjectAs<FreezingVoteAggregator>()
-                        ->GetVotingChannel();
-  voting_channel_.SubmitVote(page_node_, vote);
+  auto voting_channel = graph_->GetRegisteredObjectAs<FreezingVoteAggregator>()
+                            ->GetVotingChannel();
+  voting_channel.SubmitVote(page_node.get(), vote);
+  voting_channels_[token] =
+      std::make_pair(std::move(voting_channel), page_node.get());
+
+  node_data->AddVote(token);
 }
 
-void FreezingVoteTokenPMImpl::OnBeforePageNodeRemoved(
+void FreezingVoteTokenPMRegistry::UnregisterVoteOnPMSequence(
+    FreezingVoteTokenImpl* token) {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  auto voting_channel = voting_channels_.find(token);
+  // The vote might be missing from |voting_channels_| if this gets called
+  // after the corresponding PageNode has been destroyed.
+  if (voting_channel == voting_channels_.end()) {
+    return;
+  }
+
+  auto* page_node = voting_channel->second.second;
+  ResetAndRemoveVotingChannel(voting_channel, page_node);
+
+  auto* node_data =
+      FreezingVoteNodeData::Get(PageNodeImpl::FromNode(page_node));
+  DCHECK(node_data);
+  node_data->RemoveVote(token);
+
+  // Removes the node attached data if there's no more vote associated with this
+  // node.
+  if (node_data->IsEmpty())
+    FreezingVoteNodeData::Destroy(PageNodeImpl::FromNode(page_node));
+}
+
+void FreezingVoteTokenPMRegistry::OnBeforePageNodeRemoved(
     const PageNode* page_node) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
 
-  if (page_node != page_node_)
+  auto* node_data =
+      FreezingVoteNodeData::Get(PageNodeImpl::FromNode(page_node));
+
+  if (!node_data)
     return;
 
-  // Invalidate the vote if its associated page node is destroyed. This can
+  // Invalidate the votes if its associated page node is destroyed. This can
   // happen if a freezing vote token is released after the destruction of the
   // WebContents it's associated with.
-  Reset();
+  for (const auto* token_iter : node_data->vote_tokens()) {
+    auto voting_channel = voting_channels_.find(token_iter);
+    DCHECK(voting_channel != voting_channels_.end());
+    ResetAndRemoveVotingChannel(voting_channel, page_node);
+  }
 }
 
-void FreezingVoteTokenPMImpl::Reset() {
-  if (!page_node_)
-    return;
-
-  voting_channel_.InvalidateVote(page_node_);
-  voting_channel_.Reset();
-  page_node_observation_.Reset();
-  page_node_ = nullptr;
+void FreezingVoteTokenPMRegistry::OnPassedToGraph(Graph* graph) {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  graph->RegisterObject(this);
+  graph->AddPageNodeObserver(this);
+  graph_ = graph;
 }
 
-FreezingVoteTokenImpl::FreezingVoteTokenImpl(content::WebContents* content,
+void FreezingVoteTokenPMRegistry::OnTakenFromGraph(Graph* graph) {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  graph->UnregisterObject(this);
+  graph->RemovePageNodeObserver(this);
+  graph_ = nullptr;
+}
+
+void FreezingVoteTokenPMRegistry::ResetAndRemoveVotingChannel(
+    VotingChannelsMap::iterator& voting_channel_iter,
+    const PageNode* page_node) {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  voting_channel_iter->second.first.InvalidateVote(page_node);
+  voting_channel_iter->second.first.Reset();
+  voting_channels_.erase(voting_channel_iter);
+}
+
+FreezingVoteTokenImpl::FreezingVoteTokenImpl(content::WebContents* contents,
                                              FreezingVoteValue vote_value,
-                                             const char* vote_reason)
-    : pm_impl_(new FreezingVoteTokenPMImpl(content, vote_value, vote_reason),
-               base::OnTaskRunnerDeleter(PerformanceManager::GetTaskRunner())) {
+                                             const char* vote_reason) {
+  FreezingVoteTokenPMRegistry::RegisterVoteForWebContents(contents, vote_value,
+                                                          vote_reason, this);
 }
 
-FreezingVoteTokenImpl::~FreezingVoteTokenImpl() = default;
+FreezingVoteTokenImpl::~FreezingVoteTokenImpl() {
+  FreezingVoteTokenPMRegistry::UnregisterVote(this);
+}
 
 std::unique_ptr<FreezingVoteToken> EmitFreezingVoteForWebContents(
-    content::WebContents* content,
+    content::WebContents* contents,
     FreezingVoteValue vote_value,
     const char* vote_reason) {
-  return std::make_unique<FreezingVoteTokenImpl>(content, vote_value,
+  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+  return std::make_unique<FreezingVoteTokenImpl>(contents, vote_value,
                                                  vote_reason);
 }
 
@@ -163,5 +324,37 @@
   }
 }
 
+size_t FreezingVoteCountForPageOnPMForTesting(PageNode* page_node) {
+  DCHECK(PerformanceManager::GetTaskRunner()->RunsTasksInCurrentSequence());
+
+  auto* node_data =
+      FreezingVoteNodeData::Get(PageNodeImpl::FromNode(page_node));
+
+  if (!node_data)
+    return 0;
+
+  return node_data->vote_tokens().size();
+}
+
+size_t TotalFreezingVoteCountOnPMForTesting(Graph* graph) {
+  DCHECK(PerformanceManager::GetTaskRunner()->RunsTasksInCurrentSequence());
+
+  auto* registry = FreezingVoteTokenPMRegistry::GetOrCreateInstance(graph);
+
+  size_t registry_size = registry->voting_channels_for_testing().size();
+  size_t page_nodes_vote_count = 0U;
+
+  for (const PageNode* page_node : graph->GetAllPageNodes()) {
+    auto* node_data =
+        FreezingVoteNodeData::Get(PageNodeImpl::FromNode(page_node));
+    if (node_data)
+      page_nodes_vote_count += node_data->vote_tokens().size();
+  }
+
+  DCHECK_EQ(registry_size, page_nodes_vote_count);
+
+  return registry_size;
+}
+
 }  // namespace freezing
 }  // namespace performance_manager
diff --git a/components/performance_manager/freezing/freezing_unittest.cc b/components/performance_manager/freezing/freezing_unittest.cc
index 044f599..751efb5 100644
--- a/components/performance_manager/freezing/freezing_unittest.cc
+++ b/components/performance_manager/freezing/freezing_unittest.cc
@@ -4,6 +4,7 @@
 
 #include "components/performance_manager/public/freezing/freezing.h"
 
+#include "base/optional.h"
 #include "components/performance_manager/public/graph/page_node.h"
 #include "components/performance_manager/public/performance_manager.h"
 #include "components/performance_manager/test_support/performance_manager_test_harness.h"
@@ -20,25 +21,62 @@
 constexpr char kCanFreeze[] = "Can freeze";
 constexpr char kCannotFreeze[] = "Cannot freeze";
 
-// Check that the freezing vote attached to the page node associated with
-// |content| has the expected value.
-void ExpectFreezingVote(content::WebContents* content,
-                        base::Optional<FreezingVote> expected_vote) {
+// Get the aggregated freezing vote associated with |contents|.
+base::Optional<FreezingVote> GetFreezingVote(content::WebContents* contents) {
   base::RunLoop run_loop;
+  base::Optional<FreezingVote> ret;
   auto quit_closure = run_loop.QuitClosure();
   PerformanceManager::CallOnGraph(
       FROM_HERE,
       base::BindOnce(
           [](base::WeakPtr<PageNode> page_node, base::OnceClosure quit_closure,
-             base::Optional<FreezingVote> expected_vote) {
+             base::Optional<FreezingVote>* expected_vote) {
             EXPECT_TRUE(page_node);
             auto vote = page_node->GetFreezingVote();
-            EXPECT_EQ(expected_vote, vote);
+            *expected_vote = vote;
             std::move(quit_closure).Run();
           },
-          PerformanceManager::GetPageNodeForWebContents(content),
-          std::move(quit_closure), expected_vote));
+          PerformanceManager::GetPageNodeForWebContents(contents),
+          std::move(quit_closure), &ret));
   run_loop.Run();
+  return ret;
+}
+
+// Get the number of freezing votes associated with |contents|.
+size_t GetVoteCount(content::WebContents* contents) {
+  base::RunLoop run_loop;
+  size_t ret = 0;
+  auto quit_closure = run_loop.QuitClosure();
+  PerformanceManager::CallOnGraph(
+      FROM_HERE, base::BindOnce(
+                     [](base::WeakPtr<PageNode> page_node,
+                        base::OnceClosure quit_closure, size_t* vote_count) {
+                       EXPECT_TRUE(page_node);
+                       *vote_count = FreezingVoteCountForPageOnPMForTesting(
+                           page_node.get());
+                       std::move(quit_closure).Run();
+                     },
+                     PerformanceManager::GetPageNodeForWebContents(contents),
+                     std::move(quit_closure), &ret));
+  run_loop.Run();
+  return ret;
+}
+
+// Get the total number of freezing votes.
+size_t GetTotalVoteCount() {
+  base::RunLoop run_loop;
+  size_t ret = 0;
+  auto quit_closure = run_loop.QuitClosure();
+  PerformanceManager::CallOnGraph(
+      FROM_HERE,
+      base::BindOnce(
+          [](base::OnceClosure quit_closure, size_t* vote_count, Graph* graph) {
+            *vote_count = TotalFreezingVoteCountOnPMForTesting(graph);
+            std::move(quit_closure).Run();
+          },
+          std::move(quit_closure), &ret));
+  run_loop.Run();
+  return ret;
 }
 
 }  // namespace
@@ -58,45 +96,170 @@
 };
 
 TEST_F(FreezingTest, FreezingToken) {
-  content::WebContentsTester* web_contents_tester =
-      content::WebContentsTester::For(web_contents());
-  EXPECT_TRUE(web_contents_tester);
-  web_contents_tester->NavigateAndCommit(GURL("https:/foo.com"));
-
   {
     // Emit a positive freezing vote, this should make the page node freezable.
     auto token = EmitFreezingVoteForWebContents(
         web_contents(), FreezingVoteValue::kCanFreeze, kCanFreeze);
-    ExpectFreezingVote(web_contents(),
-                       FreezingVote(FreezingVoteValue::kCanFreeze, kCanFreeze));
+    EXPECT_EQ(1U, GetVoteCount(web_contents()));
+    EXPECT_EQ(1U, GetTotalVoteCount());
+    EXPECT_EQ(GetFreezingVote(web_contents()),
+              FreezingVote(FreezingVoteValue::kCanFreeze, kCanFreeze));
   }
   // Once the freezing vote token is destroyed the vote should be invalidated.
-  ExpectFreezingVote(web_contents(), base::nullopt);
+  EXPECT_EQ(GetFreezingVote(web_contents()), base::nullopt);
+  EXPECT_EQ(0U, GetVoteCount(web_contents()));
+  EXPECT_EQ(0U, GetTotalVoteCount());
 
   // Same test but for a negative freezing vote.
   {
     auto token = EmitFreezingVoteForWebContents(
         web_contents(), FreezingVoteValue::kCannotFreeze, kCannotFreeze);
-    ExpectFreezingVote(
-        web_contents(),
-        FreezingVote(FreezingVoteValue::kCannotFreeze, kCannotFreeze));
+    EXPECT_EQ(1U, GetVoteCount(web_contents()));
+    EXPECT_EQ(1U, GetTotalVoteCount());
+    EXPECT_EQ(GetFreezingVote(web_contents()),
+              FreezingVote(FreezingVoteValue::kCannotFreeze, kCannotFreeze));
   }
-  ExpectFreezingVote(web_contents(), base::nullopt);
+  EXPECT_EQ(GetFreezingVote(web_contents()), base::nullopt);
+  EXPECT_EQ(0U, GetTotalVoteCount());
+
+  // Emit multiple positive token for the same page.
+  {
+    auto token1 = EmitFreezingVoteForWebContents(
+        web_contents(), FreezingVoteValue::kCanFreeze, kCanFreeze);
+    EXPECT_EQ(1U, GetVoteCount(web_contents()));
+    EXPECT_EQ(1U, GetTotalVoteCount());
+    auto token2 = EmitFreezingVoteForWebContents(
+        web_contents(), FreezingVoteValue::kCanFreeze, kCanFreeze);
+    EXPECT_EQ(2U, GetVoteCount(web_contents()));
+    EXPECT_EQ(2U, GetTotalVoteCount());
+    auto token3 = EmitFreezingVoteForWebContents(
+        web_contents(), FreezingVoteValue::kCanFreeze, kCanFreeze);
+    EXPECT_EQ(GetFreezingVote(web_contents()),
+              FreezingVote(FreezingVoteValue::kCanFreeze, kCanFreeze));
+    EXPECT_EQ(3U, GetVoteCount(web_contents()));
+    EXPECT_EQ(3U, GetTotalVoteCount());
+    token3.reset();
+    EXPECT_EQ(2U, GetVoteCount(web_contents()));
+    EXPECT_EQ(2U, GetTotalVoteCount());
+    EXPECT_EQ(GetFreezingVote(web_contents()),
+              FreezingVote(FreezingVoteValue::kCanFreeze, kCanFreeze));
+    token2.reset();
+    EXPECT_EQ(1U, GetVoteCount(web_contents()));
+    EXPECT_EQ(1U, GetTotalVoteCount());
+    EXPECT_EQ(GetFreezingVote(web_contents()),
+              FreezingVote(FreezingVoteValue::kCanFreeze, kCanFreeze));
+    token1.reset();
+    EXPECT_EQ(0U, GetVoteCount(web_contents()));
+    EXPECT_EQ(0U, GetTotalVoteCount());
+    EXPECT_EQ(GetFreezingVote(web_contents()), base::nullopt);
+  }
 }
 
 TEST_F(FreezingTest, WebContentsDestroyedBeforeToken) {
-  content::WebContentsTester* web_contents_tester =
-      content::WebContentsTester::For(web_contents());
-  EXPECT_TRUE(web_contents_tester);
-  web_contents_tester->NavigateAndCommit(GURL("https:/foo.com"));
-
   // Emit a positive freezing vote, this should make the page node freezable.
   auto token = EmitFreezingVoteForWebContents(
       web_contents(), FreezingVoteValue::kCanFreeze, kCanFreeze);
-  ExpectFreezingVote(web_contents(),
-                     FreezingVote(FreezingVoteValue::kCanFreeze, kCanFreeze));
+  EXPECT_EQ(GetFreezingVote(web_contents()),
+            FreezingVote(FreezingVoteValue::kCanFreeze, kCanFreeze));
   DeleteContents();
   base::RunLoop().RunUntilIdle();
+  EXPECT_EQ(0U, GetTotalVoteCount());
+  token.reset();
+  EXPECT_EQ(0U, GetTotalVoteCount());
+}
+
+TEST_F(FreezingTest, FreezingTokenMultiplePages) {
+  auto contents2 = CreateTestWebContents();
+  auto contents3 = CreateTestWebContents();
+
+  auto contents1_token1 = EmitFreezingVoteForWebContents(
+      web_contents(), FreezingVoteValue::kCanFreeze, kCanFreeze);
+  EXPECT_EQ(GetFreezingVote(web_contents()),
+            FreezingVote(FreezingVoteValue::kCanFreeze, kCanFreeze));
+  EXPECT_EQ(GetFreezingVote(contents2.get()), base::nullopt);
+  EXPECT_EQ(GetFreezingVote(contents3.get()), base::nullopt);
+  EXPECT_EQ(1U, GetVoteCount(web_contents()));
+  EXPECT_EQ(0U, GetVoteCount(contents2.get()));
+  EXPECT_EQ(0U, GetVoteCount(contents3.get()));
+  EXPECT_EQ(1U, GetTotalVoteCount());
+
+  auto contents1_token2 = EmitFreezingVoteForWebContents(
+      web_contents(), FreezingVoteValue::kCanFreeze, kCanFreeze);
+  EXPECT_EQ(GetFreezingVote(web_contents()),
+            FreezingVote(FreezingVoteValue::kCanFreeze, kCanFreeze));
+  EXPECT_EQ(GetFreezingVote(contents2.get()), base::nullopt);
+  EXPECT_EQ(GetFreezingVote(contents3.get()), base::nullopt);
+  EXPECT_EQ(2U, GetVoteCount(web_contents()));
+  EXPECT_EQ(0U, GetVoteCount(contents2.get()));
+  EXPECT_EQ(0U, GetVoteCount(contents3.get()));
+  EXPECT_EQ(2U, GetTotalVoteCount());
+
+  auto contents2_token = EmitFreezingVoteForWebContents(
+      contents2.get(), FreezingVoteValue::kCanFreeze, kCanFreeze);
+  EXPECT_EQ(GetFreezingVote(web_contents()),
+            FreezingVote(FreezingVoteValue::kCanFreeze, kCanFreeze));
+  EXPECT_EQ(GetFreezingVote(contents2.get()),
+            FreezingVote(FreezingVoteValue::kCanFreeze, kCanFreeze));
+  EXPECT_EQ(GetFreezingVote(contents3.get()), base::nullopt);
+  EXPECT_EQ(2U, GetVoteCount(web_contents()));
+  EXPECT_EQ(1U, GetVoteCount(contents2.get()));
+  EXPECT_EQ(0U, GetVoteCount(contents3.get()));
+  EXPECT_EQ(3U, GetTotalVoteCount());
+
+  auto contents3_token = EmitFreezingVoteForWebContents(
+      contents3.get(), FreezingVoteValue::kCanFreeze, kCanFreeze);
+  EXPECT_EQ(GetFreezingVote(web_contents()),
+            FreezingVote(FreezingVoteValue::kCanFreeze, kCanFreeze));
+  EXPECT_EQ(GetFreezingVote(contents2.get()),
+            FreezingVote(FreezingVoteValue::kCanFreeze, kCanFreeze));
+  EXPECT_EQ(GetFreezingVote(contents3.get()),
+            FreezingVote(FreezingVoteValue::kCanFreeze, kCanFreeze));
+  EXPECT_EQ(2U, GetVoteCount(web_contents()));
+  EXPECT_EQ(1U, GetVoteCount(contents2.get()));
+  EXPECT_EQ(1U, GetVoteCount(contents3.get()));
+  EXPECT_EQ(4U, GetTotalVoteCount());
+
+  contents1_token1.reset();
+  EXPECT_EQ(GetFreezingVote(web_contents()),
+            FreezingVote(FreezingVoteValue::kCanFreeze, kCanFreeze));
+  EXPECT_EQ(GetFreezingVote(contents2.get()),
+            FreezingVote(FreezingVoteValue::kCanFreeze, kCanFreeze));
+  EXPECT_EQ(GetFreezingVote(contents3.get()),
+            FreezingVote(FreezingVoteValue::kCanFreeze, kCanFreeze));
+  EXPECT_EQ(1U, GetVoteCount(web_contents()));
+  EXPECT_EQ(1U, GetVoteCount(contents2.get()));
+  EXPECT_EQ(1U, GetVoteCount(contents3.get()));
+  EXPECT_EQ(3U, GetTotalVoteCount());
+
+  contents1_token2.reset();
+  EXPECT_EQ(GetFreezingVote(web_contents()), base::nullopt);
+  EXPECT_EQ(GetFreezingVote(contents2.get()),
+            FreezingVote(FreezingVoteValue::kCanFreeze, kCanFreeze));
+  EXPECT_EQ(GetFreezingVote(contents3.get()),
+            FreezingVote(FreezingVoteValue::kCanFreeze, kCanFreeze));
+  EXPECT_EQ(0U, GetVoteCount(web_contents()));
+  EXPECT_EQ(1U, GetVoteCount(contents2.get()));
+  EXPECT_EQ(1U, GetVoteCount(contents3.get()));
+  EXPECT_EQ(2U, GetTotalVoteCount());
+
+  contents2_token.reset();
+  EXPECT_EQ(GetFreezingVote(web_contents()), base::nullopt);
+  EXPECT_EQ(GetFreezingVote(contents2.get()), base::nullopt);
+  EXPECT_EQ(GetFreezingVote(contents3.get()),
+            FreezingVote(FreezingVoteValue::kCanFreeze, kCanFreeze));
+  EXPECT_EQ(0U, GetVoteCount(web_contents()));
+  EXPECT_EQ(0U, GetVoteCount(contents2.get()));
+  EXPECT_EQ(1U, GetVoteCount(contents3.get()));
+  EXPECT_EQ(1U, GetTotalVoteCount());
+
+  contents3_token.reset();
+  EXPECT_EQ(GetFreezingVote(web_contents()), base::nullopt);
+  EXPECT_EQ(GetFreezingVote(contents2.get()), base::nullopt);
+  EXPECT_EQ(GetFreezingVote(contents3.get()), base::nullopt);
+  EXPECT_EQ(0U, GetVoteCount(web_contents()));
+  EXPECT_EQ(0U, GetVoteCount(contents2.get()));
+  EXPECT_EQ(0U, GetVoteCount(contents3.get()));
+  EXPECT_EQ(0U, GetTotalVoteCount());
 }
 
 }  // namespace freezing
diff --git a/components/performance_manager/public/freezing/freezing.h b/components/performance_manager/public/freezing/freezing.h
index 1ad13a20..caec167 100644
--- a/components/performance_manager/public/freezing/freezing.h
+++ b/components/performance_manager/public/freezing/freezing.h
@@ -18,6 +18,7 @@
 
 namespace performance_manager {
 
+class Graph;
 class PageNode;
 
 namespace freezing {
@@ -48,17 +49,23 @@
 
 // Allows emiting a freezing vote for a WebContents. The vote's lifetime will
 // follow the lifetime of this object, as soon as it's released the vote will be
-// invalidated.
+// invalidated. This can only be called from the UI thread.
 //
 // NOTE: |vote_reason| *must* be a static string.
 std::unique_ptr<FreezingVoteToken> EmitFreezingVoteForWebContents(
-    content::WebContents* content,
+    content::WebContents* contents,
     FreezingVoteValue vote_value,
     const char* vote_reason);
 
 // Converts a FreezingVoteValue to a textual representation.
 const char* FreezingVoteValueToString(FreezingVoteValue freezing_vote_value);
 
+// Used to retrieve the number of freezing votes associated with |page_node|.
+size_t FreezingVoteCountForPageOnPMForTesting(PageNode* page_node);
+
+// Get the total number of freezing votes.
+size_t TotalFreezingVoteCountOnPMForTesting(Graph* graph);
+
 }  // namespace freezing
 }  // namespace performance_manager
 
diff --git a/components/permissions/permission_context_base.cc b/components/permissions/permission_context_base.cc
index f2669f6..8dcc6d5 100644
--- a/components/permissions/permission_context_base.cc
+++ b/components/permissions/permission_context_base.cc
@@ -71,7 +71,7 @@
     "information.";
 #endif
 
-const char kPermissionBlockedFeaturePolicyMessage[] =
+const char kPermissionBlockedPermissionsPolicyMessage[] =
     "%s permission has been blocked because of a permissions policy applied to"
     " the current document. See https://goo.gl/EuHzyv for more details.";
 
@@ -165,7 +165,7 @@
         break;
       case PermissionStatusSource::FEATURE_POLICY:
         LogPermissionBlockedMessage(web_contents,
-                                    kPermissionBlockedFeaturePolicyMessage,
+                                    kPermissionBlockedPermissionsPolicyMessage,
                                     content_settings_type_);
         break;
       case PermissionStatusSource::PORTAL:
@@ -232,7 +232,7 @@
   // Check whether the feature is enabled for the frame by permissions policy.
   // We can only do this when a RenderFrameHost has been provided.
   if (render_frame_host &&
-      !PermissionAllowedByFeaturePolicy(render_frame_host)) {
+      !PermissionAllowedByPermissionsPolicy(render_frame_host)) {
     return PermissionResult(CONTENT_SETTING_BLOCK,
                             PermissionStatusSource::FEATURE_POLICY);
   }
@@ -470,7 +470,7 @@
                       : Constraints());
 }
 
-bool PermissionContextBase::PermissionAllowedByFeaturePolicy(
+bool PermissionContextBase::PermissionAllowedByPermissionsPolicy(
     content::RenderFrameHost* rfh) const {
   // Some features don't have an associated permissions policy yet. Allow those.
   if (permissions_policy_feature_ ==
diff --git a/components/permissions/permission_context_base.h b/components/permissions/permission_context_base.h
index 7b78261..f53b712 100644
--- a/components/permissions/permission_context_base.h
+++ b/components/permissions/permission_context_base.h
@@ -171,7 +171,8 @@
  private:
   friend class PermissionContextBaseTests;
 
-  bool PermissionAllowedByFeaturePolicy(content::RenderFrameHost* rfh) const;
+  bool PermissionAllowedByPermissionsPolicy(
+      content::RenderFrameHost* rfh) const;
 
   // Called when a request is no longer used so it can be cleaned up.
   void CleanUpRequest(const PermissionRequestID& id);
diff --git a/components/permissions/permission_manager_unittest.cc b/components/permissions/permission_manager_unittest.cc
index 0618e48..1946121 100644
--- a/components/permissions/permission_manager_unittest.cc
+++ b/components/permissions/permission_manager_unittest.cc
@@ -208,7 +208,7 @@
     std::vector<url::Origin> parsed_origins;
     for (const std::string& origin : origins)
       parsed_origins.push_back(url::Origin::Create(GURL(origin)));
-    navigation->SetFeaturePolicyHeader(
+    navigation->SetPermissionsPolicyHeader(
         {{feature, parsed_origins, false, false}});
     navigation->Commit();
     *rfh = navigation->GetFinalRenderFrameHost();
diff --git a/components/policy/core/common/policy_service_impl.cc b/components/policy/core/common/policy_service_impl.cc
index 00f7622..679ac5e9 100644
--- a/components/policy/core/common/policy_service_impl.cc
+++ b/components/policy/core/common/policy_service_impl.cc
@@ -161,13 +161,19 @@
 // Metrics should not be enforced so if this policy is set as mandatory
 // downgrade it to a recommended level policy.
 void DowngradeMetricsReportingToRecommendedPolicy(PolicyMap* policies) {
-  PolicyMap::Entry* policy =
-      policies->GetMutable(policy::key::kMetricsReportingEnabled);
-  if (policy && policy->level != POLICY_LEVEL_RECOMMENDED && policy->value() &&
-      policy->value()->is_bool() && policy->value()->GetBool()) {
-    policy->level = POLICY_LEVEL_RECOMMENDED;
-    policy->AddMessage(PolicyMap::MessageType::kInfo,
-                       IDS_POLICY_IGNORED_MANDATORY_REPORTING_POLICY);
+  // Capture both the Chrome-only and device-level policies on Chrome OS.
+  const std::vector<const char*> metrics_keys = {
+      policy::key::kMetricsReportingEnabled,
+      policy::key::kDeviceMetricsReportingEnabled};
+  for (const char* policy_key : metrics_keys) {
+    PolicyMap::Entry* policy = policies->GetMutable(policy_key);
+    if (policy && policy->level != POLICY_LEVEL_RECOMMENDED &&
+        policy->value() && policy->value()->is_bool() &&
+        policy->value()->GetBool()) {
+      policy->level = POLICY_LEVEL_RECOMMENDED;
+      policy->AddMessage(PolicyMap::MessageType::kInfo,
+                         IDS_POLICY_IGNORED_MANDATORY_REPORTING_POLICY);
+    }
   }
 }
 
diff --git a/components/printing/renderer/print_render_frame_helper.cc b/components/printing/renderer/print_render_frame_helper.cc
index b9bf563..9383361 100644
--- a/components/printing/renderer/print_render_frame_helper.cc
+++ b/components/printing/renderer/print_render_frame_helper.cc
@@ -51,7 +51,6 @@
 #include "third_party/blink/public/platform/scheduler/web_thread_scheduler.h"
 #include "third_party/blink/public/platform/web_data.h"
 #include "third_party/blink/public/platform/web_double_size.h"
-#include "third_party/blink/public/platform/web_size.h"
 #include "third_party/blink/public/platform/web_url.h"
 #include "third_party/blink/public/platform/web_url_request.h"
 #include "third_party/blink/public/web/web_console_message.h"
diff --git a/components/signin/public/base/signin_metrics.h b/components/signin/public/base/signin_metrics.h
index da72fc992..7a712ff 100644
--- a/components/signin/public/base/signin_metrics.h
+++ b/components/signin/public/base/signin_metrics.h
@@ -263,6 +263,9 @@
   // User has completed the account addition flow triggered from the bottom
   // sheet.
   ADD_ACCOUNT_COMPLETED,
+  // The bottom sheet was suppressed as the user hit consecutive active
+  // dismissal limit.
+  SUPPRESSED_CONSECUTIVE_DISMISSALS,
 
   MAX,
 };
diff --git a/components/ui_devtools/devtools_server.cc b/components/ui_devtools/devtools_server.cc
index 1036411..12c78b0 100644
--- a/components/ui_devtools/devtools_server.cc
+++ b/components/ui_devtools/devtools_server.cc
@@ -178,6 +178,10 @@
   server_->SendOverWebSocket(connection_id, message, tag_);
 }
 
+void UiDevToolsServer::SetOnSessionEnded(base::OnceClosure callback) const {
+  on_session_ended_ = std::move(callback);
+}
+
 void UiDevToolsServer::MakeServer(
     mojo::PendingRemote<network::mojom::TCPServerSocket> server_socket,
     int result,
@@ -235,6 +239,9 @@
   UiDevToolsClient* client = it->second;
   client->Disconnect();
   connections_.erase(it);
+
+  if (connections_.empty() && on_session_ended_)
+    std::move(on_session_ended_).Run();
 }
 
 }  // namespace ui_devtools
diff --git a/components/ui_devtools/devtools_server.h b/components/ui_devtools/devtools_server.h
index 8c083646..4bfb455 100644
--- a/components/ui_devtools/devtools_server.h
+++ b/components/ui_devtools/devtools_server.h
@@ -7,6 +7,7 @@
 
 #include <vector>
 
+#include "base/callback_forward.h"
 #include "base/compiler_specific.h"
 #include "base/memory/weak_ptr.h"
 #include "base/single_thread_task_runner.h"
@@ -75,6 +76,11 @@
   TracingAgent* tracing_agent() { return tracing_agent_; }
   void set_tracing_agent(TracingAgent* agent) { tracing_agent_ = agent; }
 
+  // Sets the callback which will be invoked when the session is closed.
+  // Marks as a const function so it can be called after the server is set up
+  // and used as a constant instance.
+  void SetOnSessionEnded(base::OnceClosure callback) const;
+
  private:
   UiDevToolsServer(int port, const net::NetworkTrafficAnnotationTag tag);
 
@@ -108,6 +114,9 @@
 
   TracingAgent* tracing_agent_ = nullptr;
 
+  // Invoked when the server doesn't have any live connection.
+  mutable base::OnceClosure on_session_ended_;
+
   // The server (owned by Chrome for now)
   static UiDevToolsServer* devtools_server_;
 
diff --git a/components/viz/service/display/overlay_strategy_underlay_cast.cc b/components/viz/service/display/overlay_strategy_underlay_cast.cc
index 64de00d..bae8d3a 100644
--- a/components/viz/service/display/overlay_strategy_underlay_cast.cc
+++ b/components/viz/service/display/overlay_strategy_underlay_cast.cc
@@ -8,7 +8,6 @@
 #include <vector>
 
 #include "base/containers/adapters.h"
-#include "base/lazy_instance.h"
 #include "base/logging.h"
 #include "base/unguessable_token.h"
 #include "build/chromecast_buildflags.h"
@@ -25,9 +24,6 @@
 namespace viz {
 namespace {
 
-base::LazyInstance<OverlayStrategyUnderlayCast::OverlayCompositedCallback>::
-    DestructorAtExit g_overlay_composited_callback = LAZY_INSTANCE_INITIALIZER;
-
 #if BUILDFLAG(IS_CHROMECAST)
 // This persistent mojo::Remote is bound then used by all the instances
 // of OverlayStrategyUnderlayCast.
@@ -119,18 +115,11 @@
         continue;
       }
 
-      // TODO(guohuideng): when migration to GPU process complete, remove
-      // the code that's for the browser process compositor.
 #if BUILDFLAG(IS_CHROMECAST)
-      if (g_overlay_composited_callback.Get().is_null()) {
-        DCHECK(GetVideoGeometrySetter());
-        GetVideoGeometrySetter()->SetVideoGeometry(
-            candidate.display_rect, candidate.transform,
-            VideoHoleDrawQuad::MaterialCast(*it)->overlay_plane_id);
-      } else {
-        g_overlay_composited_callback.Get().Run(candidate.display_rect,
-                                                candidate.transform);
-      }
+      DCHECK(GetVideoGeometrySetter());
+      GetVideoGeometrySetter()->SetVideoGeometry(
+          candidate.display_rect, candidate.transform,
+          VideoHoleDrawQuad::MaterialCast(*it)->overlay_plane_id);
 #endif
 
       render_pass->ReplaceExistingQuadWithOpaqueTransparentSolidColor(it);
@@ -259,18 +248,11 @@
         continue;
       }
 
-      // TODO(guohuideng): when migration to GPU process complete, remove
-      // the code that's for the browser process compositor.
 #if BUILDFLAG(IS_CHROMECAST)
-      if (g_overlay_composited_callback.Get().is_null()) {
-        DCHECK(GetVideoGeometrySetter());
-        GetVideoGeometrySetter()->SetVideoGeometry(
-            candidate.display_rect, candidate.transform,
-            VideoHoleDrawQuad::MaterialCast(*it)->overlay_plane_id);
-      } else {
-        g_overlay_composited_callback.Get().Run(candidate.display_rect,
-                                                candidate.transform);
-      }
+      DCHECK(GetVideoGeometrySetter());
+      GetVideoGeometrySetter()->SetVideoGeometry(
+          candidate.display_rect, candidate.transform,
+          VideoHoleDrawQuad::MaterialCast(*it)->overlay_plane_id);
 #endif
 
       render_pass->ReplaceExistingQuadWithOpaqueTransparentSolidColor(it);
@@ -290,12 +272,6 @@
   return OverlayStrategy::kUnderlayCast;
 }
 
-// static
-void OverlayStrategyUnderlayCast::SetOverlayCompositedCallback(
-    const OverlayCompositedCallback& cb) {
-  g_overlay_composited_callback.Get() = cb;
-}
-
 #if BUILDFLAG(IS_CHROMECAST)
 // static
 void OverlayStrategyUnderlayCast::ConnectVideoGeometrySetter(
diff --git a/components/viz/service/display/overlay_strategy_underlay_cast.h b/components/viz/service/display/overlay_strategy_underlay_cast.h
index 53b40ed..7277cba 100644
--- a/components/viz/service/display/overlay_strategy_underlay_cast.h
+++ b/components/viz/service/display/overlay_strategy_underlay_cast.h
@@ -8,12 +8,10 @@
 #include <memory>
 #include <vector>
 
-#include "base/callback.h"
 #include "base/macros.h"
 #include "build/chromecast_buildflags.h"
 #include "components/viz/service/display/overlay_strategy_underlay.h"
 #include "components/viz/service/viz_service_export.h"
-#include "ui/gfx/overlay_transform.h"
 
 #if BUILDFLAG(IS_CHROMECAST)
 #include "chromecast/media/service/mojom/video_geometry_setter.mojom.h"
@@ -61,13 +59,6 @@
       std::vector<gfx::Rect>* content_bounds,
       OverlayProposedCandidate* proposed_candidate) override;
 
-  // Callback that's made whenever an overlay quad is processed in the
-  // compositor. Used to allow hardware video plane to be positioned to match
-  // compositor hole.
-  using OverlayCompositedCallback =
-      base::RepeatingCallback<void(const gfx::RectF&, gfx::OverlayTransform)>;
-  static void SetOverlayCompositedCallback(const OverlayCompositedCallback& cb);
-
 #if BUILDFLAG(IS_CHROMECAST)
   // In Chromecast build, OverlayStrategyUnderlayCast needs a valid mojo
   // interface to VideoGeometrySetter Service (shared by all instances of
diff --git a/components/webapps/renderer/web_page_metadata_extraction.cc b/components/webapps/renderer/web_page_metadata_extraction.cc
index 154bca60..b07bdc18 100644
--- a/components/webapps/renderer/web_page_metadata_extraction.cc
+++ b/components/webapps/renderer/web_page_metadata_extraction.cc
@@ -41,11 +41,11 @@
 
   mojom::WebPageIconInfoPtr icon_info(mojom::WebPageIconInfo::New());
   if (link.HasAttribute("sizes")) {
-    blink::WebVector<blink::WebSize> icon_sizes =
+    blink::WebVector<gfx::Size> icon_sizes =
         blink::WebIconSizesParser::ParseIconSizes(link.GetAttribute("sizes"));
-    if (icon_sizes.size() == 1 && icon_sizes[0].width != 0 &&
-        icon_sizes[0].height == icon_sizes[0].width) {
-      icon_info->square_size_px = icon_sizes[0].width;
+    if (icon_sizes.size() == 1 && icon_sizes[0].width() != 0 &&
+        icon_sizes[0].height() == icon_sizes[0].width()) {
+      icon_info->square_size_px = icon_sizes[0].width();
     }
   }
   icon_info->url = url;
diff --git a/content/browser/accessibility/accessibility_tree_formatter_win.cc b/content/browser/accessibility/accessibility_tree_formatter_win.cc
index adb0fa07..69670fa9 100644
--- a/content/browser/accessibility/accessibility_tree_formatter_win.cc
+++ b/content/browser/accessibility/accessibility_tree_formatter_win.cc
@@ -203,9 +203,9 @@
   Microsoft::WRL::ComPtr<IAccessible> start_ia =
       ToBrowserAccessibilityComWin(start_internal);
 
-  base::DictionaryValue dict;
+  base::Value dict(base::Value::Type::DICTIONARY);
   RecursiveBuildTree(start_ia, &dict, root_x, root_y);
-  return std::move(dict);
+  return dict;
 }
 
 base::Value AccessibilityTreeFormatterWin::BuildTreeForWindow(
@@ -220,9 +220,9 @@
   if (FAILED(hr))
     return base::Value(base::Value::Type::DICTIONARY);
 
-  base::DictionaryValue dict;
+  base::Value dict(base::Value::Type::DICTIONARY);
   RecursiveBuildTree(start, &dict, 0, 0);
-  return std::move(dict);
+  return dict;
 }
 
 base::Value AccessibilityTreeFormatterWin::BuildTreeForSelector(
@@ -232,12 +232,12 @@
 
 void AccessibilityTreeFormatterWin::RecursiveBuildTree(
     const Microsoft::WRL::ComPtr<IAccessible> node,
-    base::DictionaryValue* dict,
+    base::Value* dict,
     LONG root_x,
     LONG root_y) const {
   AddProperties(node, dict, root_x, root_y);
 
-  auto children = std::make_unique<base::ListValue>();
+  base::Value child_list(base::Value::Type::LIST);
 
   LONG child_count;
   if (S_OK != node->get_accChildCount(&child_count))
@@ -254,16 +254,14 @@
     base::win::ScopedVariant child_variant;
     child_variant.Reset(
         children_array[index]);  // Sets without adding another reference.
-    std::unique_ptr<base::DictionaryValue> child_dict(
-        new base::DictionaryValue);
+    base::Value child_dict(base::Value::Type::DICTIONARY);
     Microsoft::WRL::ComPtr<IDispatch> dispatch;
     if (child_variant.type() == VT_DISPATCH) {
       dispatch = V_DISPATCH(child_variant.ptr());
     } else if (child_variant.type() == VT_I4) {
       hr = node->get_accChild(child_variant, &dispatch);
       if (FAILED(hr)) {
-        child_dict->SetString("error",
-                              base::ASCIIToUTF16("[Error retrieving child]"));
+        child_dict.SetStringPath("error", "[Error retrieving child]");
       } else if (!dispatch) {
         // Partial child does not have its own object.
         // Add minimal info -- role and name.
@@ -271,28 +269,27 @@
         if (SUCCEEDED(
                 node->get_accRole(child_variant, role_variant.Receive()))) {
           if (role_variant.type() == VT_I4) {
-            child_dict->SetString("role",
-                                  base::ASCIIToUTF16(" [partial child]"));
+            child_dict.SetStringPath("role", " [partial child]");
           }
         }
         base::win::ScopedBstr temp_bstr;
         if (S_OK == node->get_accName(child_variant, temp_bstr.Receive())) {
           std::wstring name(temp_bstr.Get(), temp_bstr.Length());
-          child_dict->SetString("name", base::WideToUTF16(name));
+          child_dict.SetStringPath("name", base::WideToUTF16(name));
         }
       }
     } else {
-      child_dict->SetString("error",
-                            base::ASCIIToUTF16("[Unknown child type]"));
+      child_dict.SetStringPath("error",
+                               base::ASCIIToUTF16("[Unknown child type]"));
     }
     if (dispatch) {
       Microsoft::WRL::ComPtr<IAccessible> accessible;
       if (SUCCEEDED(dispatch.As(&accessible)))
-        RecursiveBuildTree(accessible, child_dict.get(), root_x, root_y);
+        RecursiveBuildTree(accessible, &child_dict, root_x, root_y);
     }
-    children->Append(std::move(child_dict));
+    child_list.Append(std::move(child_dict));
   }
-  dict->Set(kChildrenDictAttr, std::move(children));
+  dict->SetPath(kChildrenDictAttr, std::move(child_list));
 }
 
 const char* const ALL_ATTRIBUTES[] = {
@@ -337,7 +334,7 @@
 
 void AccessibilityTreeFormatterWin::AddProperties(
     const Microsoft::WRL::ComPtr<IAccessible> node,
-    base::DictionaryValue* dict,
+    base::Value* dict,
     LONG root_x,
     LONG root_y) const {
   AddMSAAProperties(node, dict, root_x, root_y);
@@ -364,7 +361,7 @@
 
 void AccessibilityTreeFormatterWin::AddMSAAProperties(
     const Microsoft::WRL::ComPtr<IAccessible> node,
-    base::DictionaryValue* dict,
+    base::Value* dict,
     LONG root_x,
     LONG root_y) const {
   base::win::ScopedVariant variant_self(CHILDID_SELF);
@@ -372,14 +369,14 @@
   base::win::ScopedVariant ia_role_variant;
   LONG ia_role = 0;
   if (SUCCEEDED(node->get_accRole(variant_self, ia_role_variant.Receive()))) {
-    dict->SetString("role", RoleVariantToString(ia_role_variant));
+    dict->SetStringPath("role", RoleVariantToString(ia_role_variant));
     ia_role = V_I4(ia_role_variant.ptr());
   }
 
   // If S_FALSE it means there is no name
   if (S_OK == node->get_accName(variant_self, temp_bstr.Receive())) {
     std::wstring name(temp_bstr.Get(), temp_bstr.Length());
-    dict->SetString("name", base::WideToUTF16(name));
+    dict->SetStringPath("name", base::WideToUTF16(name));
   }
   temp_bstr.Reset();
 
@@ -387,33 +384,35 @@
   if (SUCCEEDED(node->get_accParent(&parent_dispatch))) {
     Microsoft::WRL::ComPtr<IAccessible> parent_accessible;
     if (!parent_dispatch) {
-      dict->SetString("parent", "[null]");
+      dict->SetStringPath("parent", "[null]");
     } else if (SUCCEEDED(parent_dispatch.As(&parent_accessible))) {
       base::win::ScopedVariant parent_ia_role_variant;
       if (SUCCEEDED(parent_accessible->get_accRole(
               variant_self, parent_ia_role_variant.Receive())))
-        dict->SetString("parent", RoleVariantToString(parent_ia_role_variant));
+        dict->SetStringPath("parent",
+                            RoleVariantToString(parent_ia_role_variant));
       else
-        dict->SetString("parent", "[Error retrieving role from parent]");
+        dict->SetStringPath("parent", "[Error retrieving role from parent]");
     } else {
-      dict->SetString("parent", "[Error getting IAccessible* for parent]");
+      dict->SetStringPath("parent", "[Error getting IAccessible* for parent]");
     }
   } else {
-    dict->SetString("parent", "[Error retrieving parent]");
+    dict->SetStringPath("parent", "[Error retrieving parent]");
   }
 
   HWND hwnd;
   if (SUCCEEDED(::WindowFromAccessibleObject(node.Get(), &hwnd)) && hwnd) {
-    dict->SetString("window_class", base::WideToUTF16(gfx::GetClassName(hwnd)));
+    dict->SetStringPath("window_class",
+                        base::WideToUTF16(gfx::GetClassName(hwnd)));
   } else {
     // This method is implemented by oleacc.dll and uses get_accParent,
     // therefore it Will fail if get_accParent from root fails.
-    dict->SetString("window_class", "[Error]");
+    dict->SetStringPath("window_class", "[Error]");
   }
 
   if (SUCCEEDED(node->get_accValue(variant_self, temp_bstr.Receive())))
-    dict->SetString("value",
-                    base::WideToUTF16({temp_bstr.Get(), temp_bstr.Length()}));
+    dict->SetStringPath(
+        "value", base::WideToUTF16({temp_bstr.Get(), temp_bstr.Length()}));
   temp_bstr.Reset();
 
   int32_t ia_state = 0;
@@ -428,53 +427,55 @@
     states.reserve(state_strings.size());
     for (const auto& str : state_strings)
       states.emplace_back(base::WideToUTF8(str));
-    dict->SetKey("states", base::Value(std::move(states)));
+    dict->SetPath("states", base::Value(std::move(states)));
   }
 
   if (SUCCEEDED(node->get_accDescription(variant_self, temp_bstr.Receive()))) {
-    dict->SetString("description",
-                    base::WideToUTF16({temp_bstr.Get(), temp_bstr.Length()}));
+    dict->SetStringPath("description", base::WideToUTF16({temp_bstr.Get(),
+                                                          temp_bstr.Length()}));
   }
   temp_bstr.Reset();
 
   // |get_accDefaultAction| returns a localized string.
   if (SUCCEEDED(
           node->get_accDefaultAction(variant_self, temp_bstr.Receive()))) {
-    dict->SetString("default_action",
-                    base::WideToUTF16({temp_bstr.Get(), temp_bstr.Length()}));
+    dict->SetStringPath(
+        "default_action",
+        base::WideToUTF16({temp_bstr.Get(), temp_bstr.Length()}));
   }
   temp_bstr.Reset();
 
   if (SUCCEEDED(
           node->get_accKeyboardShortcut(variant_self, temp_bstr.Receive()))) {
-    dict->SetString("keyboard_shortcut",
-                    base::WideToUTF16({temp_bstr.Get(), temp_bstr.Length()}));
+    dict->SetStringPath(
+        "keyboard_shortcut",
+        base::WideToUTF16({temp_bstr.Get(), temp_bstr.Length()}));
   }
   temp_bstr.Reset();
 
   if (SUCCEEDED(node->get_accHelp(variant_self, temp_bstr.Receive())))
-    dict->SetString("help",
-                    base::WideToUTF16({temp_bstr.Get(), temp_bstr.Length()}));
+    dict->SetStringPath(
+        "help", base::WideToUTF16({temp_bstr.Get(), temp_bstr.Length()}));
 
   temp_bstr.Reset();
 
   LONG x, y, width, height;
   if (SUCCEEDED(node->accLocation(&x, &y, &width, &height, variant_self))) {
-    auto location = std::make_unique<base::DictionaryValue>();
-    location->SetInteger("x", x - root_x);
-    location->SetInteger("y", y - root_y);
-    dict->Set("location", std::move(location));
+    base::Value location(base::Value::Type::DICTIONARY);
+    location.SetIntPath("x", x - root_x);
+    location.SetIntPath("y", y - root_y);
+    dict->SetPath("location", std::move(location));
 
-    auto size = std::make_unique<base::DictionaryValue>();
-    size->SetInteger("width", width);
-    size->SetInteger("height", height);
-    dict->Set("size", std::move(size));
+    base::Value size(base::Value::Type::DICTIONARY);
+    size.SetIntPath("width", width);
+    size.SetIntPath("height", height);
+    dict->SetPath("size", std::move(size));
   }
 }
 
 void AccessibilityTreeFormatterWin::AddSimpleDOMNodeProperties(
     const Microsoft::WRL::ComPtr<IAccessible> node,
-    base::DictionaryValue* dict) const {
+    base::Value* dict) const {
   Microsoft::WRL::ComPtr<ISimpleDOMNode> simple_dom_node;
 
   if (S_OK != QuerySimpleDOMNode(node.Get(), &simple_dom_node))
@@ -483,27 +484,27 @@
   base::win::ScopedBstr temp_bstr;
 
   if (SUCCEEDED(simple_dom_node->get_innerHTML(temp_bstr.Receive()))) {
-    dict->SetString("inner_html",
-                    base::WideToUTF16({temp_bstr.Get(), temp_bstr.Length()}));
+    dict->SetStringPath(
+        "inner_html", base::WideToUTF16({temp_bstr.Get(), temp_bstr.Length()}));
   }
   temp_bstr.Reset();
 }
 
 bool AccessibilityTreeFormatterWin::AddIA2Properties(
     const Microsoft::WRL::ComPtr<IAccessible> node,
-    base::DictionaryValue* dict) const {
+    base::Value* dict) const {
   Microsoft::WRL::ComPtr<IAccessible2> ia2;
   if (S_OK != QueryIAccessible2(node.Get(), &ia2))
     return false;  // No IA2, we are finished with this node.
 
   LONG ia2_role = 0;
   if (SUCCEEDED(ia2->role(&ia2_role))) {
-    std::string legacy_role;
-    dict->GetString("role", &legacy_role);
-    dict->SetString("msaa_legacy_role", legacy_role);
+    const std::string* legacy_role = dict->FindStringPath("role");
+    if (legacy_role)
+      dict->SetStringPath("msaa_legacy_role", *legacy_role);
     // Overwrite MSAA role which is more limited.
-    dict->SetString("role",
-                    base::WideToUTF8(IAccessible2RoleToString(ia2_role)));
+    dict->SetStringPath("role",
+                        base::WideToUTF8(IAccessible2RoleToString(ia2_role)));
   }
 
   std::vector<std::wstring> state_strings;
@@ -531,31 +532,32 @@
     attributes.reserve(ia2_attributes.size());
     for (const auto& str : ia2_attributes)
       attributes.push_back(base::Value(str));
-    dict->SetKey("attributes", base::Value(std::move(attributes)));
+    dict->SetPath("attributes", base::Value(std::move(attributes)));
   }
   temp_bstr.Reset();
 
   LONG index_in_parent;
   if (SUCCEEDED(ia2->get_indexInParent(&index_in_parent)))
-    dict->SetInteger("index_in_parent", index_in_parent);
+    dict->SetIntPath("index_in_parent", index_in_parent);
 
   LONG n_relations;
   if (SUCCEEDED(ia2->get_nRelations(&n_relations)))
-    dict->SetInteger("n_relations", n_relations);
+    dict->SetIntPath("n_relations", n_relations);
 
   LONG group_level, similar_items_in_group, position_in_group;
   // |GetGroupPosition| returns S_FALSE when no grouping information is
   // available so avoid using |SUCCEEDED|.
   if (ia2->get_groupPosition(&group_level, &similar_items_in_group,
                              &position_in_group) == S_OK) {
-    dict->SetInteger("group_level", group_level);
-    dict->SetInteger("similar_items_in_group", similar_items_in_group);
-    dict->SetInteger("position_in_group", position_in_group);
+    dict->SetIntPath("group_level", group_level);
+    dict->SetIntPath("similar_items_in_group", similar_items_in_group);
+    dict->SetIntPath("position_in_group", position_in_group);
   }
 
   if (SUCCEEDED(ia2->get_localizedExtendedRole(temp_bstr.Receive()))) {
-    dict->SetString("localized_extended_role",
-                    base::WideToUTF16({temp_bstr.Get(), temp_bstr.Length()}));
+    dict->SetStringPath(
+        "localized_extended_role",
+        base::WideToUTF16({temp_bstr.Get(), temp_bstr.Length()}));
   }
   temp_bstr.Reset();
 
@@ -564,7 +566,7 @@
 
 void AccessibilityTreeFormatterWin::AddIA2ActionProperties(
     const Microsoft::WRL::ComPtr<IAccessible> node,
-    base::DictionaryValue* dict) const {
+    base::Value* dict) const {
   Microsoft::WRL::ComPtr<IAccessibleAction> ia2action;
   if (S_OK != QueryIAccessibleAction(node.Get(), &ia2action))
     return;  // No IA2Value, we are finished with this node.
@@ -574,14 +576,14 @@
   // |IAccessibleAction::get_name| returns a localized string.
   if (SUCCEEDED(
           ia2action->get_name(0 /* action_index */, temp_bstr.Receive()))) {
-    dict->SetString("action_name",
-                    base::WideToUTF16({temp_bstr.Get(), temp_bstr.Length()}));
+    dict->SetStringPath("action_name", base::WideToUTF16({temp_bstr.Get(),
+                                                          temp_bstr.Length()}));
   }
 }
 
 void AccessibilityTreeFormatterWin::AddIA2HypertextProperties(
     Microsoft::WRL::ComPtr<IAccessible> node,
-    base::DictionaryValue* dict) const {
+    base::Value* dict) const {
   Microsoft::WRL::ComPtr<IAccessibleHypertext> ia2hyper;
   if (S_OK != QueryIAccessibleHypertext(node.Get(), &ia2hyper))
     return;  // No IA2, we are finished with this node
@@ -644,23 +646,23 @@
   }
   DCHECK_EQ(number_of_embeds, 0);
 
-  dict->SetString("ia2_hypertext", base::WideToUTF16(ia2_hypertext));
+  dict->SetStringPath("ia2_hypertext", base::WideToUTF16(ia2_hypertext));
 }
 
 void AccessibilityTreeFormatterWin::AddIA2TableProperties(
     const Microsoft::WRL::ComPtr<IAccessible> node,
-    base::DictionaryValue* dict) const {
+    base::Value* dict) const {
   Microsoft::WRL::ComPtr<IAccessibleTable> ia2table;
   if (S_OK != QueryIAccessibleTable(node.Get(), &ia2table))
     return;  // No IA2Text, we are finished with this node.
 
   LONG table_rows;
   if (SUCCEEDED(ia2table->get_nRows(&table_rows)))
-    dict->SetInteger("table_rows", table_rows);
+    dict->SetIntPath("table_rows", table_rows);
 
   LONG table_columns;
   if (SUCCEEDED(ia2table->get_nColumns(&table_columns)))
-    dict->SetInteger("table_columns", table_columns);
+    dict->SetIntPath("table_columns", table_columns);
 }
 
 static base::string16 ProcessAccessiblesArray(IUnknown** accessibles,
@@ -688,19 +690,19 @@
 
 void AccessibilityTreeFormatterWin::AddIA2TableCellProperties(
     const Microsoft::WRL::ComPtr<IAccessible> node,
-    base::DictionaryValue* dict) const {
+    base::Value* dict) const {
   Microsoft::WRL::ComPtr<IAccessibleTableCell> ia2cell;
   if (S_OK != QueryIAccessibleTableCell(node.Get(), &ia2cell))
     return;  // No IA2Text, we are finished with this node.
 
   LONG column_index;
   if (SUCCEEDED(ia2cell->get_columnIndex(&column_index))) {
-    dict->SetInteger("ia2_table_cell_column_index", column_index);
+    dict->SetIntPath("ia2_table_cell_column_index", column_index);
   }
 
   LONG row_index;
   if (SUCCEEDED(ia2cell->get_rowIndex(&row_index))) {
-    dict->SetInteger("ia2_table_cell_row_index", row_index);
+    dict->SetIntPath("ia2_table_cell_row_index", row_index);
   }
 
   LONG n_row_header_cells;
@@ -711,7 +713,7 @@
     base::string16 accessibles_desc =
         ProcessAccessiblesArray(row_headers, n_row_header_cells);
     CoTaskMemFree(row_headers);  // Free the array manually.
-    dict->SetString("row_headers", accessibles_desc);
+    dict->SetStringPath("row_headers", accessibles_desc);
   }
 
   LONG n_column_header_cells;
@@ -722,33 +724,33 @@
     base::string16 accessibles_desc =
         ProcessAccessiblesArray(column_headers, n_column_header_cells);
     CoTaskMemFree(column_headers);  // Free the array manually.
-    dict->SetString("column_headers", accessibles_desc);
+    dict->SetStringPath("column_headers", accessibles_desc);
   }
 }
 
 void AccessibilityTreeFormatterWin::AddIA2TextProperties(
     const Microsoft::WRL::ComPtr<IAccessible> node,
-    base::DictionaryValue* dict) const {
+    base::Value* dict) const {
   Microsoft::WRL::ComPtr<IAccessibleText> ia2text;
   if (S_OK != QueryIAccessibleText(node.Get(), &ia2text))
     return;  // No IA2Text, we are finished with this node.
 
   LONG n_characters;
   if (SUCCEEDED(ia2text->get_nCharacters(&n_characters)))
-    dict->SetInteger("n_characters", n_characters);
+    dict->SetIntPath("n_characters", n_characters);
 
   LONG caret_offset;
   if (ia2text->get_caretOffset(&caret_offset) == S_OK)
-    dict->SetInteger("caret_offset", caret_offset);
+    dict->SetIntPath("caret_offset", caret_offset);
 
   LONG n_selections;
   if (SUCCEEDED(ia2text->get_nSelections(&n_selections))) {
-    dict->SetInteger("n_selections", n_selections);
+    dict->SetIntPath("n_selections", n_selections);
     if (n_selections > 0) {
       LONG start, end;
       if (SUCCEEDED(ia2text->get_selection(0, &start, &end))) {
-        dict->SetInteger("selection_start", start);
-        dict->SetInteger("selection_end", end);
+        dict->SetIntPath("selection_start", start);
+        dict->SetIntPath("selection_end", end);
       }
     }
   }
@@ -756,7 +758,7 @@
   // Handle IA2 text attributes, adding them as a list.
   // IA2 text attributes comes formatted as a single string, as follows:
   // https://wiki.linuxfoundation.org/accessibility/iaccessible2/textattributes
-  std::unique_ptr<base::ListValue> text_attributes(new base::ListValue());
+  base::Value text_attributes(base::Value::Type::LIST);
   LONG current_offset = 0, start_offset, end_offset;
   while (current_offset < n_characters) {
     // TODO(aleventhal) n_characters is not actually useful for ending the
@@ -779,23 +781,23 @@
       // Append offset:<number>.
       base::string16 offset_str =
           base::ASCIIToUTF16("offset:") + base::NumberToString16(start_offset);
-      text_attributes->AppendString(offset_str);
+      text_attributes.Append(offset_str);
       // Append name:value pairs.
       std::vector<std::wstring> name_val_pairs =
           SplitString(std::wstring(temp_bstr.Get()), L";",
                       base::KEEP_WHITESPACE, base::SPLIT_WANT_ALL);
       for (const auto& name_val_pair : name_val_pairs)
-        text_attributes->Append(base::WideToUTF16(name_val_pair));
+        text_attributes.Append(base::WideToUTF16(name_val_pair));
     }
     current_offset = end_offset;
   }
 
-  dict->Set("text_attributes", std::move(text_attributes));
+  dict->SetPath("text_attributes", std::move(text_attributes));
 }
 
 void AccessibilityTreeFormatterWin::AddIA2ValueProperties(
     const Microsoft::WRL::ComPtr<IAccessible> node,
-    base::DictionaryValue* dict) const {
+    base::Value* dict) const {
   Microsoft::WRL::ComPtr<IAccessibleValue> ia2value;
   if (S_OK != QueryIAccessibleValue(node.Get(), &ia2value))
     return;  // No IA2Value, we are finished with this node.
@@ -803,19 +805,19 @@
   base::win::ScopedVariant current_value;
   if (ia2value->get_currentValue(current_value.Receive()) == S_OK &&
       isfinite(V_R8(current_value.ptr()))) {
-    dict->SetDouble("currentValue", V_R8(current_value.ptr()));
+    dict->SetDoublePath("currentValue", V_R8(current_value.ptr()));
   }
 
   base::win::ScopedVariant minimum_value;
   if (ia2value->get_minimumValue(minimum_value.Receive()) == S_OK &&
       isfinite(V_R8(minimum_value.ptr()))) {
-    dict->SetDouble("minimumValue", V_R8(minimum_value.ptr()));
+    dict->SetDoublePath("minimumValue", V_R8(minimum_value.ptr()));
   }
 
   base::win::ScopedVariant maximum_value;
   if (ia2value->get_maximumValue(maximum_value.Receive()) == S_OK &&
       isfinite(V_R8(maximum_value.ptr()))) {
-    dict->SetDouble("maximumValue", V_R8(maximum_value.ptr()));
+    dict->SetDoublePath("maximumValue", V_R8(maximum_value.ptr()));
   }
 }
 
diff --git a/content/browser/accessibility/accessibility_tree_formatter_win.h b/content/browser/accessibility/accessibility_tree_formatter_win.h
index 4f5bdcba..c501d51 100644
--- a/content/browser/accessibility/accessibility_tree_formatter_win.h
+++ b/content/browser/accessibility/accessibility_tree_formatter_win.h
@@ -30,34 +30,34 @@
 
  private:
   void RecursiveBuildTree(const Microsoft::WRL::ComPtr<IAccessible> node,
-                          base::DictionaryValue* dict,
+                          base::Value* dict,
                           LONG root_x,
                           LONG root_y) const;
 
   void AddProperties(const Microsoft::WRL::ComPtr<IAccessible>,
-                     base::DictionaryValue* dict,
+                     base::Value* dict,
                      LONG root_x,
                      LONG root_y) const;
   void AddMSAAProperties(const Microsoft::WRL::ComPtr<IAccessible>,
-                         base::DictionaryValue* dict,
+                         base::Value* dict,
                          LONG root_x,
                          LONG root_y) const;
   void AddSimpleDOMNodeProperties(const Microsoft::WRL::ComPtr<IAccessible>,
-                                  base::DictionaryValue* dict) const;
+                                  base::Value* dict) const;
   bool AddIA2Properties(const Microsoft::WRL::ComPtr<IAccessible>,
-                        base::DictionaryValue* dict) const;
+                        base::Value* dict) const;
   void AddIA2ActionProperties(const Microsoft::WRL::ComPtr<IAccessible>,
-                              base::DictionaryValue* dict) const;
+                              base::Value* dict) const;
   void AddIA2HypertextProperties(const Microsoft::WRL::ComPtr<IAccessible>,
-                                 base::DictionaryValue* dict) const;
+                                 base::Value* dict) const;
   void AddIA2TextProperties(const Microsoft::WRL::ComPtr<IAccessible>,
-                            base::DictionaryValue* dict) const;
+                            base::Value* dict) const;
   void AddIA2TableProperties(const Microsoft::WRL::ComPtr<IAccessible>,
-                             base::DictionaryValue* dict) const;
+                             base::Value* dict) const;
   void AddIA2TableCellProperties(const Microsoft::WRL::ComPtr<IAccessible>,
-                                 base::DictionaryValue* dict) const;
+                                 base::Value* dict) const;
   void AddIA2ValueProperties(const Microsoft::WRL::ComPtr<IAccessible>,
-                             base::DictionaryValue* dict) const;
+                             base::Value* dict) const;
   std::string ProcessTreeForOutput(
       const base::DictionaryValue& node) const override;
 };
diff --git a/content/browser/browser_context.cc b/content/browser/browser_context.cc
index f42f80d..73c482c 100644
--- a/content/browser/browser_context.cc
+++ b/content/browser/browser_context.cc
@@ -18,6 +18,7 @@
 #include "base/bind.h"
 #include "base/check_op.h"
 #include "base/command_line.h"
+#include "base/containers/contains.h"
 #include "base/debug/dump_without_crashing.h"
 #include "base/files/file_path.h"
 #include "base/lazy_instance.h"
@@ -113,9 +114,8 @@
   partition->GetSharedWorkerService()->Shutdown();
 }
 
-void SetDownloadManager(
-    BrowserContext* context,
-    std::unique_ptr<content::DownloadManager> download_manager) {
+void SetDownloadManager(BrowserContext* context,
+                        std::unique_ptr<DownloadManager> download_manager) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
   DCHECK(download_manager);
   context->SetUserData(kDownloadManagerKeyName, std::move(download_manager));
@@ -186,7 +186,7 @@
 }
 
 // static
-content::BrowsingDataRemover* content::BrowserContext::GetBrowsingDataRemover(
+BrowsingDataRemover* BrowserContext::GetBrowsingDataRemover(
     BrowserContext* context) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
 
@@ -202,7 +202,7 @@
 }
 
 // static
-content::PermissionController* content::BrowserContext::GetPermissionController(
+PermissionController* BrowserContext::GetPermissionController(
     BrowserContext* context) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
 
@@ -431,7 +431,7 @@
 // static
 void BrowserContext::SetDownloadManagerForTesting(
     BrowserContext* browser_context,
-    std::unique_ptr<content::DownloadManager> download_manager) {
+    std::unique_ptr<DownloadManager> download_manager) {
   SetDownloadManager(browser_context, std::move(download_manager));
 }
 
@@ -445,6 +445,27 @@
                                std::move(permission_controller));
 }
 
+// static
+SharedCorsOriginAccessList* BrowserContext::GetSharedCorsOriginAccessList(
+    BrowserContext* context) {
+  const char kSharedCorsOriginAccessListKeyName[] =
+      "BrowserContext -> SharedCorsOriginAccessList";
+  using UserDataAdapter = base::UserDataAdapter<SharedCorsOriginAccessList>;
+
+  // Return the existing UserData if possible.
+  if (SharedCorsOriginAccessList* result =
+          UserDataAdapter::Get(context, kSharedCorsOriginAccessListKeyName)) {
+    return result;
+  }
+
+  // Otherwise create and attach new UserData.
+  scoped_refptr<SharedCorsOriginAccessList> result =
+      SharedCorsOriginAccessList::Create();
+  context->SetUserData(kSharedCorsOriginAccessListKeyName,
+                       std::make_unique<UserDataAdapter>(result.get()));
+  return result.get();
+}
+
 BrowserContext::BrowserContext()
     : unique_id_(base::UnguessableToken::Create().ToString()) {
   TRACE_EVENT("shutdown", "BrowserContext::BrowserContext",
@@ -609,23 +630,6 @@
   return nullptr;
 }
 
-void BrowserContext::SetCorsOriginAccessListForOrigin(
-    TargetBrowserContexts target_mode,
-    const url::Origin& source_origin,
-    std::vector<network::mojom::CorsOriginPatternPtr> allow_patterns,
-    std::vector<network::mojom::CorsOriginPatternPtr> block_patterns,
-    base::OnceClosure closure) {
-  NOTREACHED() << "Sub-classes should implement this method to communicate "
-                  "with NetworkService to bypass CORS checks.";
-}
-
-SharedCorsOriginAccessList* BrowserContext::GetSharedCorsOriginAccessList() {
-  // Need to return a valid instance regardless of CORS bypass supports.
-  static const base::NoDestructor<scoped_refptr<SharedCorsOriginAccessList>>
-      empty_list(SharedCorsOriginAccessList::Create());
-  return empty_list->get();
-}
-
 FileSystemAccessPermissionContext*
 BrowserContext::GetFileSystemAccessPermissionContext() {
   return nullptr;
diff --git a/content/browser/client_hints/client_hints.cc b/content/browser/client_hints/client_hints.cc
index b467bab6..1b0e428b 100644
--- a/content/browser/client_hints/client_hints.cc
+++ b/content/browser/client_hints/client_hints.cc
@@ -382,7 +382,7 @@
       .value_or(std::string());
 }
 
-bool IsFeaturePolicyForClientHintsEnabled() {
+bool IsPermissionsPolicyForClientHintsEnabled() {
   return base::FeatureList::IsEnabled(features::kFeaturePolicyForClientHints);
 }
 
@@ -423,11 +423,12 @@
 
 bool IsClientHintAllowed(const ClientHintsExtendedData& data,
                          network::mojom::WebClientHintsType type) {
-  if (!IsFeaturePolicyForClientHintsEnabled() || data.is_main_frame)
+  if (!IsPermissionsPolicyForClientHintsEnabled() || data.is_main_frame)
     return data.is_1p_origin;
   return data.permissions_policy &&
          data.permissions_policy->IsFeatureEnabledForOrigin(
-             blink::kClientHintsFeaturePolicyMapping[static_cast<int>(type)],
+             blink::kClientHintsPermissionsPolicyMapping[static_cast<int>(
+                 type)],
              data.resource_origin);
 }
 
@@ -742,7 +743,7 @@
     return base::nullopt;
 
   base::TimeDelta persist_duration;
-  if (IsFeaturePolicyForClientHintsEnabled()) {
+  if (IsPermissionsPolicyForClientHintsEnabled()) {
     // JSON cannot store "non-finite" values (i.e. NaN or infinite) so
     // base::TimeDelta::Max cannot be used. As this will be removed once
     // the FeaturePolicyForClientHints feature is shipped, a reasonably
diff --git a/content/browser/conversions/conversion_registration_browsertest.cc b/content/browser/conversions/conversion_registration_browsertest.cc
index 5d24f45e..b6204f762 100644
--- a/content/browser/conversions/conversion_registration_browsertest.cc
+++ b/content/browser/conversions/conversion_registration_browsertest.cc
@@ -165,7 +165,7 @@
 }
 
 IN_PROC_BROWSER_TEST_F(ConversionRegistrationBrowserTest,
-                       FeaturePolicyDisabled_ConversionNotRegistered) {
+                       PermissionsPolicyDisabled_ConversionNotRegistered) {
   EXPECT_TRUE(NavigateToURL(
       shell(), embedded_test_server()->GetURL(
                    "/page_with_conversion_measurement_disabled.html")));
diff --git a/content/browser/conversions/impression_declaration_browsertest.cc b/content/browser/conversions/impression_declaration_browsertest.cc
index 609497c..302e2a9 100644
--- a/content/browser/conversions/impression_declaration_browsertest.cc
+++ b/content/browser/conversions/impression_declaration_browsertest.cc
@@ -378,7 +378,7 @@
 }
 
 IN_PROC_BROWSER_TEST_F(ImpressionDeclarationBrowserTest,
-                       ImpressionWithFeaturePolicyDisabled_NotRegistered) {
+                       ImpressionWithPermissionsPolicyDisabled_NotRegistered) {
   EXPECT_TRUE(NavigateToURL(
       web_contents(),
       https_server()->GetURL(
@@ -396,8 +396,9 @@
   EXPECT_TRUE(impression_observer.WaitForNavigationWithNoImpression());
 }
 
-IN_PROC_BROWSER_TEST_F(ImpressionDeclarationBrowserTest,
-                       ImpressionInSubframeWithoutFeaturePolicy_NotRegistered) {
+IN_PROC_BROWSER_TEST_F(
+    ImpressionDeclarationBrowserTest,
+    ImpressionInSubframeWithoutPermissionsPolicy_NotRegistered) {
   GURL page_url = https_server()->GetURL("b.test", "/page_with_iframe.html");
   EXPECT_TRUE(NavigateToURL(web_contents(), page_url));
 
@@ -419,7 +420,7 @@
 }
 
 IN_PROC_BROWSER_TEST_F(ImpressionDeclarationBrowserTest,
-                       ImpressionInSubframeWithFeaturePolicy_Registered) {
+                       ImpressionInSubframeWithPermissionsPolicy_Registered) {
   GURL page_url = https_server()->GetURL("b.test", "/page_with_iframe.html");
   EXPECT_TRUE(NavigateToURL(web_contents(), page_url));
   EXPECT_TRUE(ExecJs(shell(), R"(
diff --git a/content/browser/device_sensors/device_sensor_browsertest.cc b/content/browser/device_sensors/device_sensor_browsertest.cc
index 9c281ea..157123b 100644
--- a/content/browser/device_sensors/device_sensor_browsertest.cc
+++ b/content/browser/device_sensors/device_sensor_browsertest.cc
@@ -338,7 +338,7 @@
 }
 
 IN_PROC_BROWSER_TEST_F(DeviceSensorBrowserTest,
-                       DeviceOrientationFeaturePolicyWarning) {
+                       DeviceOrientationPermissionsPolicyWarning) {
   // Main frame is on a.com, iframe is on b.com.
   GURL main_frame_url =
       https_embedded_test_server_->GetURL("a.com", "/cross_origin_iframe.html");
diff --git a/content/browser/download/download_manager_impl.cc b/content/browser/download/download_manager_impl.cc
index 437b1d4..ddcce76c7 100644
--- a/content/browser/download/download_manager_impl.cc
+++ b/content/browser/download/download_manager_impl.cc
@@ -1290,7 +1290,7 @@
         std::make_unique<network::WrapperPendingSharedURLLoaderFactory>(
             FileURLLoaderFactory::Create(
                 browser_context_->GetPath(),
-                browser_context_->GetSharedCorsOriginAccessList(),
+                BrowserContext::GetSharedCorsOriginAccessList(browser_context_),
                 // USER_VISIBLE because download should progress
                 // even when there is high priority work to do.
                 base::TaskPriority::USER_VISIBLE));
diff --git a/content/browser/download/save_file_manager.cc b/content/browser/download/save_file_manager.cc
index b140be6..91786d976 100644
--- a/content/browser/download/save_file_manager.cc
+++ b/content/browser/download/save_file_manager.cc
@@ -265,7 +265,8 @@
       factory = factory_remote.get();
     } else if (url.SchemeIsFile()) {
       factory_remote.Bind(FileURLLoaderFactory::Create(
-          context->GetPath(), context->GetSharedCorsOriginAccessList(),
+          context->GetPath(),
+          BrowserContext::GetSharedCorsOriginAccessList(context),
           base::TaskPriority::USER_VISIBLE));
       factory = factory_remote.get();
     } else if (url.SchemeIsFileSystem() && rfh) {
diff --git a/chrome/browser/loader/cors_origin_access_list_browsertest.cc b/content/browser/loader/cors_origin_pattern_setter_browsertest.cc
similarity index 78%
rename from chrome/browser/loader/cors_origin_access_list_browsertest.cc
rename to content/browser/loader/cors_origin_pattern_setter_browsertest.cc
index 6f176bd7..d882edd7 100644
--- a/chrome/browser/loader/cors_origin_access_list_browsertest.cc
+++ b/content/browser/loader/cors_origin_pattern_setter_browsertest.cc
@@ -12,13 +12,12 @@
 #include "base/strings/string16.h"
 #include "base/strings/stringprintf.h"
 #include "base/strings/utf_string_conversions.h"
-#include "chrome/browser/profiles/profile.h"
-#include "chrome/browser/ui/browser.h"
-#include "chrome/test/base/in_process_browser_test.h"
-#include "chrome/test/base/ui_test_utils.h"
 #include "content/public/browser/browser_context.h"
+#include "content/public/browser/cors_origin_pattern_setter.h"
 #include "content/public/test/browser_test.h"
 #include "content/public/test/browser_test_utils.h"
+#include "content/public/test/content_browser_test.h"
+#include "content/shell/browser/shell.h"
 #include "net/base/host_port_pair.h"
 #include "net/dns/mock_host_resolver.h"
 #include "services/network/public/mojom/cors.mojom.h"
@@ -27,7 +26,7 @@
 #include "url/gurl.h"
 #include "url/origin.h"
 
-namespace {
+namespace content {
 
 const auto kAllowSubdomains =
     network::mojom::CorsDomainMatchMode::kAllowSubdomains;
@@ -41,14 +40,14 @@
 const char kTestSubdomainHost[] = "subdomain.crossorigin.example.com";
 
 // Tests end to end functionality of CORS access origin allow lists.
-class CorsOriginAccessListBrowserTest : public InProcessBrowserTest {
+class CorsOriginPatternSetterBrowserTest : public ContentBrowserTest {
  protected:
-  CorsOriginAccessListBrowserTest() = default;
+  CorsOriginPatternSetterBrowserTest() = default;
 
-  std::unique_ptr<content::TitleWatcher> CreateWatcher() {
+  std::unique_ptr<TitleWatcher> CreateWatcher() {
     // Register all possible result strings here.
-    std::unique_ptr<content::TitleWatcher> watcher =
-        std::make_unique<content::TitleWatcher>(web_contents(), pass_string());
+    std::unique_ptr<TitleWatcher> watcher =
+        std::make_unique<TitleWatcher>(web_contents(), pass_string());
     watcher->AlsoWaitForTitle(fail_string());
     return watcher;
   }
@@ -82,8 +81,8 @@
           network::mojom::CorsOriginAccessMatchPriority::kDefaultPriority));
 
       base::RunLoop run_loop;
-      browser()->profile()->SetCorsOriginAccessListForOrigin(
-          content::BrowserContext::TargetBrowserContexts::kSingleContext,
+      CorsOriginPatternSetter::Set(
+          web_contents()->GetBrowserContext(),
           url::Origin::Create(embedded_test_server()->base_url().GetOrigin()),
           std::move(list), std::vector<network::mojom::CorsOriginPatternPtr>(),
           run_loop.QuitClosure());
@@ -98,8 +97,8 @@
           network::mojom::CorsOriginAccessMatchPriority::kDefaultPriority));
 
       base::RunLoop run_loop;
-      browser()->profile()->SetCorsOriginAccessListForOrigin(
-          content::BrowserContext::TargetBrowserContexts::kSingleContext,
+      CorsOriginPatternSetter::Set(
+          web_contents()->GetBrowserContext(),
           url::Origin::Create(
               embedded_test_server()->GetURL(kTestHost, "/").GetOrigin()),
           std::move(list), std::vector<network::mojom::CorsOriginPatternPtr>(),
@@ -113,9 +112,7 @@
   const base::string16& pass_string() const { return pass_string_; }
   const base::string16& fail_string() const { return fail_string_; }
 
-  content::WebContents* web_contents() {
-    return browser()->tab_strip_model()->GetActiveWebContents();
-  }
+  WebContents* web_contents() { return shell()->web_contents(); }
 
  private:
   void SetUpOnMainThread() override {
@@ -135,14 +132,14 @@
   const base::string16 fail_string_ = base::ASCIIToUTF16("FAIL");
   const base::string16 script_ = base::ASCIIToUTF16("reason");
 
-  DISALLOW_COPY_AND_ASSIGN(CorsOriginAccessListBrowserTest);
+  DISALLOW_COPY_AND_ASSIGN(CorsOriginPatternSetterBrowserTest);
 };
 
 // Tests if specifying only protocol allows all hosts to pass.
-IN_PROC_BROWSER_TEST_F(CorsOriginAccessListBrowserTest, AllowAll) {
+IN_PROC_BROWSER_TEST_F(CorsOriginPatternSetterBrowserTest, AllowAll) {
   SetAllowList("http", "", kAllowSubdomains);
 
-  std::unique_ptr<content::TitleWatcher> watcher = CreateWatcher();
+  std::unique_ptr<TitleWatcher> watcher = CreateWatcher();
   EXPECT_TRUE(NavigateToURL(web_contents(),
                             embedded_test_server()->GetURL(base::StringPrintf(
                                 "%s?target=%s", kTestPath, kTestHost))));
@@ -150,10 +147,10 @@
 }
 
 // Tests if specifying only protocol allows all IP address based hosts to pass.
-IN_PROC_BROWSER_TEST_F(CorsOriginAccessListBrowserTest, AllowAllForIp) {
+IN_PROC_BROWSER_TEST_F(CorsOriginPatternSetterBrowserTest, AllowAllForIp) {
   SetAllowList("http", "", kAllowSubdomains);
 
-  std::unique_ptr<content::TitleWatcher> watcher = CreateWatcher();
+  std::unique_ptr<TitleWatcher> watcher = CreateWatcher();
   EXPECT_TRUE(NavigateToURL(
       web_contents(),
       embedded_test_server()->GetURL(
@@ -163,10 +160,10 @@
 }
 
 // Tests if complete allow list set allows only exactly matched host to pass.
-IN_PROC_BROWSER_TEST_F(CorsOriginAccessListBrowserTest, AllowExactHost) {
+IN_PROC_BROWSER_TEST_F(CorsOriginPatternSetterBrowserTest, AllowExactHost) {
   SetAllowList("http", kTestHost, kDisallowSubdomains);
 
-  std::unique_ptr<content::TitleWatcher> watcher = CreateWatcher();
+  std::unique_ptr<TitleWatcher> watcher = CreateWatcher();
   EXPECT_TRUE(NavigateToURL(web_contents(),
                             embedded_test_server()->GetURL(base::StringPrintf(
                                 "%s?target=%s", kTestPath, kTestHost))));
@@ -175,11 +172,11 @@
 
 // Tests if complete allow list set allows host that matches exactly, but in
 // case insensitive way to pass.
-IN_PROC_BROWSER_TEST_F(CorsOriginAccessListBrowserTest,
+IN_PROC_BROWSER_TEST_F(CorsOriginPatternSetterBrowserTest,
                        AllowExactHostInCaseInsensitive) {
   SetAllowList("http", kTestHost, kDisallowSubdomains);
 
-  std::unique_ptr<content::TitleWatcher> watcher = CreateWatcher();
+  std::unique_ptr<TitleWatcher> watcher = CreateWatcher();
   EXPECT_TRUE(
       NavigateToURL(web_contents(),
                     embedded_test_server()->GetURL(base::StringPrintf(
@@ -189,10 +186,10 @@
 
 // Tests if complete allow list set does not allow a host with a different port
 // to pass.
-IN_PROC_BROWSER_TEST_F(CorsOriginAccessListBrowserTest, BlockDifferentPort) {
+IN_PROC_BROWSER_TEST_F(CorsOriginPatternSetterBrowserTest, BlockDifferentPort) {
   SetAllowList("http", kTestHost, kDisallowSubdomains);
 
-  std::unique_ptr<content::TitleWatcher> watcher = CreateWatcher();
+  std::unique_ptr<TitleWatcher> watcher = CreateWatcher();
   EXPECT_TRUE(NavigateToURL(
       web_contents(), embedded_test_server()->GetURL(base::StringPrintf(
                           "%s?target=%s&port_diff=1", kTestPath, kTestHost))));
@@ -200,10 +197,10 @@
 }
 
 // Tests if complete allow list set allows a subdomain to pass if it is allowed.
-IN_PROC_BROWSER_TEST_F(CorsOriginAccessListBrowserTest, AllowSubdomain) {
+IN_PROC_BROWSER_TEST_F(CorsOriginPatternSetterBrowserTest, AllowSubdomain) {
   SetAllowList("http", kTestHost, kAllowSubdomains);
 
-  std::unique_ptr<content::TitleWatcher> watcher = CreateWatcher();
+  std::unique_ptr<TitleWatcher> watcher = CreateWatcher();
   EXPECT_TRUE(NavigateToURL(
       web_contents(), embedded_test_server()->GetURL(base::StringPrintf(
                           "%s?target=%s", kTestPath, kTestSubdomainHost))));
@@ -211,10 +208,10 @@
 }
 
 // Tests if complete allow list set does not allow a subdomain to pass.
-IN_PROC_BROWSER_TEST_F(CorsOriginAccessListBrowserTest, BlockSubdomain) {
+IN_PROC_BROWSER_TEST_F(CorsOriginPatternSetterBrowserTest, BlockSubdomain) {
   SetAllowList("http", kTestHost, kDisallowSubdomains);
 
-  std::unique_ptr<content::TitleWatcher> watcher = CreateWatcher();
+  std::unique_ptr<TitleWatcher> watcher = CreateWatcher();
   EXPECT_TRUE(NavigateToURL(
       web_contents(), embedded_test_server()->GetURL(base::StringPrintf(
                           "%s?target=%s", kTestPath, kTestSubdomainHost))));
@@ -223,11 +220,11 @@
 
 // Tests if complete allow list set does not allow a host with a different
 // protocol to pass.
-IN_PROC_BROWSER_TEST_F(CorsOriginAccessListBrowserTest,
+IN_PROC_BROWSER_TEST_F(CorsOriginPatternSetterBrowserTest,
                        BlockDifferentProtocol) {
   SetAllowList("https", kTestHost, kDisallowSubdomains);
 
-  std::unique_ptr<content::TitleWatcher> watcher = CreateWatcher();
+  std::unique_ptr<TitleWatcher> watcher = CreateWatcher();
   EXPECT_TRUE(NavigateToURL(web_contents(),
                             embedded_test_server()->GetURL(base::StringPrintf(
                                 "%s?target=%s", kTestPath, kTestHost))));
@@ -235,11 +232,11 @@
 }
 
 // Tests if IP address based hosts should not follow subdomain match rules.
-IN_PROC_BROWSER_TEST_F(CorsOriginAccessListBrowserTest,
+IN_PROC_BROWSER_TEST_F(CorsOriginPatternSetterBrowserTest,
                        SubdomainMatchShouldNotBeAppliedForIPAddress) {
   SetAllowList("http", "*.0.0.1", kAllowSubdomains);
 
-  std::unique_ptr<content::TitleWatcher> watcher = CreateWatcher();
+  std::unique_ptr<TitleWatcher> watcher = CreateWatcher();
   EXPECT_TRUE(NavigateToURL(
       web_contents(),
       embedded_test_server()->GetURL(
@@ -248,4 +245,4 @@
   EXPECT_EQ(fail_string(), watcher->WaitAndGetTitle()) << GetReason();
 }
 
-}  // namespace
+}  // namespace content
diff --git a/content/browser/loader/cors_origin_pattern_setter_unittest.cc b/content/browser/loader/cors_origin_pattern_setter_unittest.cc
new file mode 100644
index 0000000..343752c
--- /dev/null
+++ b/content/browser/loader/cors_origin_pattern_setter_unittest.cc
@@ -0,0 +1,139 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/public/browser/cors_origin_pattern_setter.h"
+
+#include <string>
+#include <vector>
+
+#include "base/run_loop.h"
+#include "content/public/browser/shared_cors_origin_access_list.h"
+#include "content/public/test/browser_task_environment.h"
+#include "content/public/test/test_browser_context.h"
+#include "mojo/public/cpp/bindings/clone_traits.h"
+#include "services/network/public/cpp/cors/origin_access_list.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "url/gurl.h"
+#include "url/origin.h"
+
+namespace content {
+
+namespace {
+
+network::mojom::CorsOriginPatternPtr CreateTestPattern(
+    std::string target_domain) {
+  std::string scheme = "chrome-extension";
+  uint16_t port = 123;
+  network::mojom::CorsDomainMatchMode domain_mode =
+      network::mojom::CorsDomainMatchMode::kAllowSubdomains;
+  network::mojom::CorsPortMatchMode port_mode =
+      network::mojom::CorsPortMatchMode::kAllowOnlySpecifiedPort;
+  network::mojom::CorsOriginAccessMatchPriority priority =
+      network::mojom::CorsOriginAccessMatchPriority::kDefaultPriority;
+
+  return network::mojom::CorsOriginPattern::New(
+      scheme, target_domain, port, domain_mode, port_mode, priority);
+}
+
+}  // namespace
+
+TEST(CorsOriginPatternSetter, InitialEmptyList) {
+  content::BrowserTaskEnvironment task_environment;
+  scoped_refptr<content::SharedCorsOriginAccessList> shared_list;
+
+  {
+    content::TestBrowserContext browser_context;
+    shared_list = content::BrowserContext::GetSharedCorsOriginAccessList(
+        &browser_context);
+    ASSERT_TRUE(shared_list);
+
+    // The list is empty (in absence of calls to CorsOriginPatternSetter::Set).
+    std::vector<network::mojom::CorsOriginAccessPatternsPtr> patterns =
+        shared_list->GetOriginAccessList().CreateCorsOriginAccessPatternsList();
+    EXPECT_EQ(0u, patterns.size());
+
+    // |shared_list| should own 1 ref-count + |browser_context|'s UserData
+    // should own 1 ref-count.
+    EXPECT_FALSE(shared_list->HasOneRef());
+  }
+
+  // |shared_list| should own the only remaining ref-count (i.e. the product
+  // code shouldn't hold any ref-counts at this point).
+  EXPECT_TRUE(shared_list->HasOneRef());
+}
+
+TEST(CorsOriginPatternSetter, ClonePatterns) {
+  content::BrowserTaskEnvironment task_environment;
+  const char kTestDomain[] = "example.com";
+  network::mojom::CorsOriginPatternPtr test_pattern =
+      CreateTestPattern(kTestDomain);
+
+  std::vector<network::mojom::CorsOriginPatternPtr> original_patterns;
+  original_patterns.push_back(CreateTestPattern(kTestDomain));
+  EXPECT_EQ(1u, original_patterns.size());
+  EXPECT_EQ(*test_pattern, *original_patterns[0]);
+
+  std::vector<network::mojom::CorsOriginPatternPtr> cloned_patterns =
+      mojo::Clone(original_patterns);
+  // `original_patterns` is not affected by the Clone method.
+  EXPECT_EQ(1u, original_patterns.size());
+  EXPECT_EQ(*test_pattern, *original_patterns[0]);
+  // Equivalent contents, but different pointers (i.e. separate objects).
+  EXPECT_EQ(1u, cloned_patterns.size());
+  EXPECT_EQ(*original_patterns[0], *cloned_patterns[0]);
+  EXPECT_NE(original_patterns[0].get(), cloned_patterns[0].get());
+}
+
+TEST(CorsOriginPatternSetter, Set) {
+  content::BrowserTaskEnvironment task_environment;
+  scoped_refptr<content::SharedCorsOriginAccessList> shared_list;
+
+  {
+    content::TestBrowserContext browser_context;
+
+    const char kTestDomain[] = "example.com";
+    network::mojom::CorsOriginPatternPtr test_pattern =
+        CreateTestPattern(kTestDomain);
+    url::Origin source_origin =
+        url::Origin::Create(GURL("https://initiator.com"));
+    std::vector<network::mojom::CorsOriginPatternPtr> allowlist;
+    allowlist.push_back(CreateTestPattern(kTestDomain));
+
+    // Call CorsOriginPatternSetter::Set and wait until it completes.
+    base::RunLoop run_loop;
+    CorsOriginPatternSetter::Set(&browser_context, source_origin,
+                                 std::move(allowlist), {},
+                                 run_loop.QuitClosure());
+    run_loop.Run();
+
+    // Verify that the results got properly stored.
+    shared_list = content::BrowserContext::GetSharedCorsOriginAccessList(
+        &browser_context);
+    ASSERT_TRUE(shared_list);
+    std::vector<network::mojom::CorsOriginAccessPatternsPtr> patterns =
+        shared_list->GetOriginAccessList().CreateCorsOriginAccessPatternsList();
+    ASSERT_EQ(1u, patterns.size());
+    ASSERT_TRUE(patterns[0]);
+    EXPECT_EQ(source_origin, patterns[0]->source_origin);
+    EXPECT_EQ(0u, patterns[0]->block_patterns.size());
+    ASSERT_EQ(1u, patterns[0]->allow_patterns.size());
+    EXPECT_EQ(*test_pattern, *patterns[0]->allow_patterns[0]);
+
+    // TODO(lukasza): Add verification that
+    // network::mojom::NetworkContext::SetCorsOriginAccessListsForOrigin got
+    // called.  The immediate problem is that TestBrowserContext has 0
+    // StoragePartition objects - we would need to find a way to add
+    // TestStoragePartition objects with test-controlled TestNetworkContext.
+
+    // |shared_list| should own 1 ref-count + |browser_context|'s UserData
+    // should own 1 ref-count.
+    EXPECT_FALSE(shared_list->HasOneRef());
+  }
+
+  // |shared_list| should own the only remaining ref-count (i.e. the product
+  // code shouldn't hold any ref-counts at this point).
+  EXPECT_TRUE(shared_list->HasOneRef());
+}
+
+}  // namespace content
diff --git a/content/browser/loader/navigation_url_loader_impl.cc b/content/browser/loader/navigation_url_loader_impl.cc
index de6d09b7..dba5134 100644
--- a/content/browser/loader/navigation_url_loader_impl.cc
+++ b/content/browser/loader/navigation_url_loader_impl.cc
@@ -1217,10 +1217,11 @@
   // Loading and rendering a web page after the user clicks a link.
   base::TaskPriority file_factory_priority = base::TaskPriority::USER_BLOCKING;
   non_network_url_loader_factories_.emplace(
-      url::kFileScheme, FileURLLoaderFactory::Create(
-                            browser_context_->GetPath(),
-                            browser_context_->GetSharedCorsOriginAccessList(),
-                            file_factory_priority));
+      url::kFileScheme,
+      FileURLLoaderFactory::Create(
+          browser_context_->GetPath(),
+          BrowserContext::GetSharedCorsOriginAccessList(browser_context_),
+          file_factory_priority));
 
 #if defined(OS_ANDROID)
   non_network_url_loader_factories_.emplace(url::kContentScheme,
diff --git a/content/browser/media/media_devices_permission_checker_unittest.cc b/content/browser/media/media_devices_permission_checker_unittest.cc
index a25d89d..c6a58e8 100644
--- a/content/browser/media/media_devices_permission_checker_unittest.cc
+++ b/content/browser/media/media_devices_permission_checker_unittest.cc
@@ -56,7 +56,8 @@
     std::vector<url::Origin> allowlist;
     if (enabled)
       allowlist.push_back(origin_);
-    navigation->SetFeaturePolicyHeader({{feature, allowlist, false, false}});
+    navigation->SetPermissionsPolicyHeader(
+        {{feature, allowlist, false, false}});
     navigation->Commit();
   }
 
@@ -95,7 +96,8 @@
 // case as the PermissionsPolicy class itself is tested thoroughly in
 // permissions_policy_unittest.cc and in
 // render_frame_host_permissions_policy_unittest.cc.
-TEST_F(MediaDevicesPermissionCheckerTest, CheckPermissionWithFeaturePolicy) {
+TEST_F(MediaDevicesPermissionCheckerTest,
+       CheckPermissionWithPermissionsPolicy) {
   // Mic and Camera should be enabled by default for a frame (if permission is
   // granted).
   EXPECT_TRUE(CheckPermission(MediaDeviceType::MEDIA_AUDIO_INPUT));
diff --git a/content/browser/net/trust_token_parameters_browsertest.cc b/content/browser/net/trust_token_parameters_browsertest.cc
index fb35653..62cb115 100644
--- a/content/browser/net/trust_token_parameters_browsertest.cc
+++ b/content/browser/net/trust_token_parameters_browsertest.cc
@@ -162,9 +162,9 @@
       expected_params_and_serialization.params));
 }
 
-class TrustTokenFeaturePolicyBrowsertest : public ContentBrowserTest {
+class TrustTokenPermissionsPolicyBrowsertest : public ContentBrowserTest {
  public:
-  TrustTokenFeaturePolicyBrowsertest() {
+  TrustTokenPermissionsPolicyBrowsertest() {
     features_.InitAndEnableFeature(network::features::kTrustTokens);
   }
 
@@ -176,7 +176,7 @@
   base::test::ScopedFeatureList features_;
 };
 
-IN_PROC_BROWSER_TEST_F(TrustTokenFeaturePolicyBrowsertest,
+IN_PROC_BROWSER_TEST_F(TrustTokenPermissionsPolicyBrowsertest,
                        PassesNegativeValueToFactoryParams) {
   // Since the trust-token-redemption Permissions Policy feature is disabled by
   // default in cross-site frames, the child's URLLoaderFactoryParams should be
@@ -205,7 +205,7 @@
   run_loop.Run();
 }
 
-IN_PROC_BROWSER_TEST_F(TrustTokenFeaturePolicyBrowsertest,
+IN_PROC_BROWSER_TEST_F(TrustTokenPermissionsPolicyBrowsertest,
                        PassesPositiveValueToFactoryParams) {
   // Even though the trust-token-redemption Permissions Policy feature is
   // disabled by default in cross-site frames, the allow attribute on the iframe
@@ -238,7 +238,7 @@
   run_loop.Run();
 }
 
-IN_PROC_BROWSER_TEST_F(TrustTokenFeaturePolicyBrowsertest,
+IN_PROC_BROWSER_TEST_F(TrustTokenPermissionsPolicyBrowsertest,
                        PassesNegativeValueToFactoryParamsAfterCrash) {
   // Since the trust-token-redemption Permissions Policy feature is disabled by
   // default in cross-site frames, the child's URLLoaderFactoryParams should be
@@ -274,7 +274,7 @@
   run_loop.Run();
 }
 
-IN_PROC_BROWSER_TEST_F(TrustTokenFeaturePolicyBrowsertest,
+IN_PROC_BROWSER_TEST_F(TrustTokenPermissionsPolicyBrowsertest,
                        PassesPositiveValueToFactoryParamsAfterCrash) {
   // Even though the trust-token-redemption Permissions Policy feature is
   // disabled by default in cross-site frames, the allow attribute on the iframe
diff --git a/content/browser/renderer_host/frame_tree_node.h b/content/browser/renderer_host/frame_tree_node.h
index 68dab52..fcb8b12 100644
--- a/content/browser/renderer_host/frame_tree_node.h
+++ b/content/browser/renderer_host/frame_tree_node.h
@@ -444,9 +444,9 @@
   }
 
  private:
-  FRIEND_TEST_ALL_PREFIXES(SitePerProcessFeaturePolicyBrowserTest,
+  FRIEND_TEST_ALL_PREFIXES(SitePerProcessPermissionsPolicyBrowserTest,
                            ContainerPolicyDynamic);
-  FRIEND_TEST_ALL_PREFIXES(SitePerProcessFeaturePolicyBrowserTest,
+  FRIEND_TEST_ALL_PREFIXES(SitePerProcessPermissionsPolicyBrowserTest,
                            ContainerPolicySandboxDynamic);
 
   class OpenerDestroyedObserver;
diff --git a/content/browser/renderer_host/media/media_stream_ui_proxy_unittest.cc b/content/browser/renderer_host/media/media_stream_ui_proxy_unittest.cc
index 548727f..65864104 100644
--- a/content/browser/renderer_host/media/media_stream_ui_proxy_unittest.cc
+++ b/content/browser/renderer_host/media/media_stream_ui_proxy_unittest.cc
@@ -390,7 +390,7 @@
 // These tests are not meant to cover every edge case as the PermissionsPolicy
 // class itself is tested thoroughly in permissions_policy_unittest.cc and in
 // render_frame_host_permissions_policy_unittest.cc.
-class MediaStreamUIProxyFeaturePolicyTest
+class MediaStreamUIProxyPermissionsPolicyTest
     : public RenderViewHostImplTestHarness {
  public:
   void SetUp() override {
@@ -405,7 +405,7 @@
       blink::mojom::PermissionsPolicyFeature feature) {
     auto navigation = NavigationSimulator::CreateRendererInitiated(
         main_rfh()->GetLastCommittedURL(), main_rfh());
-    navigation->SetFeaturePolicyHeader({{feature, {}, false, false}});
+    navigation->SetPermissionsPolicyHeader({{feature, {}, false, false}});
     navigation->Commit();
   }
 
@@ -416,10 +416,9 @@
     base::RunLoop run_loop;
     quit_closure_ = run_loop.QuitClosure();
     GetIOThreadTaskRunner({})->PostTask(
-        FROM_HERE,
-        base::BindOnce(
-            &MediaStreamUIProxyFeaturePolicyTest::GetResultForRequestOnIOThread,
-            base::Unretained(this), std::move(request)));
+        FROM_HERE, base::BindOnce(&MediaStreamUIProxyPermissionsPolicyTest::
+                                      GetResultForRequestOnIOThread,
+                                  base::Unretained(this), std::move(request)));
     run_loop.Run();
     *devices_out = devices_;
     *result_out = result_;
@@ -474,9 +473,9 @@
     proxy_ = MediaStreamUIProxy::CreateForTests(&delegate_);
     proxy_->RequestAccess(
         std::move(request),
-        base::BindOnce(
-            &MediaStreamUIProxyFeaturePolicyTest::FinishedGetResultOnIOThread,
-            base::Unretained(this)));
+        base::BindOnce(&MediaStreamUIProxyPermissionsPolicyTest::
+                           FinishedGetResultOnIOThread,
+                       base::Unretained(this)));
   }
 
   void FinishedGetResultOnIOThread(
@@ -486,8 +485,9 @@
     proxy_.reset();
     GetUIThreadTaskRunner({})->PostTask(
         FROM_HERE,
-        base::BindOnce(&MediaStreamUIProxyFeaturePolicyTest::FinishedGetResult,
-                       base::Unretained(this), devices, result));
+        base::BindOnce(
+            &MediaStreamUIProxyPermissionsPolicyTest::FinishedGetResult,
+            base::Unretained(this), devices, result));
   }
 
   void FinishedGetResult(const blink::MediaStreamDevices& devices,
@@ -508,7 +508,7 @@
   std::unique_ptr<MediaStreamUIProxy> proxy_;
 };
 
-TEST_F(MediaStreamUIProxyFeaturePolicyTest, PermissionsPolicy) {
+TEST_F(MediaStreamUIProxyPermissionsPolicyTest, PermissionsPolicy) {
   blink::MediaStreamDevices devices;
   blink::mojom::MediaStreamRequestResult result;
 
diff --git a/content/browser/renderer_host/navigator_unittest.cc b/content/browser/renderer_host/navigator_unittest.cc
index 0d10892..b122559da 100644
--- a/content/browser/renderer_host/navigator_unittest.cc
+++ b/content/browser/renderer_host/navigator_unittest.cc
@@ -1435,7 +1435,7 @@
 
 // Permissions Policy: Test that the permissions policy is reset when navigating
 // pages within a site.
-TEST_F(NavigatorTest, FeaturePolicySameSiteNavigation) {
+TEST_F(NavigatorTest, PermissionsPolicySameSiteNavigation) {
   const GURL kUrl1("http://www.chromium.org/");
   const GURL kUrl2("http://www.chromium.org/Home");
 
@@ -1458,7 +1458,7 @@
 
 // Permissions Policy: Test that the permissions policy is not reset when
 // navigating within a page.
-TEST_F(NavigatorTest, FeaturePolicyFragmentNavigation) {
+TEST_F(NavigatorTest, PermissionsPolicyFragmentNavigation) {
   const GURL kUrl1("http://www.chromium.org/");
   const GURL kUrl2("http://www.chromium.org/#Home");
 
@@ -1480,7 +1480,7 @@
 
 // Permissions Policy: Test that the permissions policy is set correctly when
 // inserting a new child frame.
-TEST_F(NavigatorTest, FeaturePolicyNewChild) {
+TEST_F(NavigatorTest, PermissionsPolicyNewChild) {
   const GURL kUrl1("http://www.chromium.org/");
   const GURL kUrl2("http://www.chromium.org/Home");
 
diff --git a/content/browser/renderer_host/render_frame_host_impl.cc b/content/browser/renderer_host/render_frame_host_impl.cc
index 6054172c..de602a1 100644
--- a/content/browser/renderer_host/render_frame_host_impl.cc
+++ b/content/browser/renderer_host/render_frame_host_impl.cc
@@ -684,12 +684,12 @@
 // (https://github.com/wicg/trust-token-api). If the operation's type is
 // "redemption" or "signing" (as opposed to "issuance"), the parent's frame
 // needs to have the trust-token-redemption Permissions Policy feature enabled.
-bool ParentNeedsTrustTokenFeaturePolicy(
+bool ParentNeedsTrustTokenPermissionsPolicy(
     const mojom::BeginNavigationParams& begin_params) {
   if (!begin_params.trust_token_params)
     return false;
 
-  return network::DoesTrustTokenOperationRequireFeaturePolicy(
+  return network::DoesTrustTokenOperationRequirePermissionsPolicy(
       begin_params.trust_token_params->type);
 }
 
@@ -1161,7 +1161,7 @@
   // Verify is_local_root() now indicates whether this frame is a local root or
   // not. It is safe to use this method anywhere beyond this point.
   DCHECK_EQ(setup_local_render_widget_host, is_local_root());
-  ResetFeaturePolicy();
+  ResetPermissionsPolicy();
 
   // New RenderFrameHostImpl are put in their own virtual browsing context
   // group. Then, they can inherit from:
@@ -2911,7 +2911,7 @@
   // permissions policy's state depends on the origin, so the PermissionsPolicy
   // object could be configured incorrectly if it were initialized before
   // knowing the value of |last_committed_origin_|. More at crbug.com/1112959.
-  ResetFeaturePolicy();
+  ResetPermissionsPolicy();
 }
 
 FrameTreeNode* RenderFrameHostImpl::AddChild(
@@ -5604,7 +5604,7 @@
     return;
   }
   if (begin_params->trust_token_params &&
-      ParentNeedsTrustTokenFeaturePolicy(*begin_params)) {
+      ParentNeedsTrustTokenPermissionsPolicy(*begin_params)) {
     RenderFrameHostImpl* parent = GetParent();
     if (!parent->IsFeatureEnabled(
             blink::mojom::PermissionsPolicyFeature::kTrustTokenRedemption)) {
@@ -6582,7 +6582,7 @@
           url::kFileScheme,
           FileURLLoaderFactory::Create(
               browser_context->GetPath(),
-              browser_context->GetSharedCorsOriginAccessList(),
+              BrowserContext::GetSharedCorsOriginAccessList(browser_context),
               file_factory_priority));
     }
 
@@ -7774,7 +7774,7 @@
   GetContentClient()->browser()->CreateWebUsbService(this, std::move(receiver));
 }
 
-void RenderFrameHostImpl::ResetFeaturePolicy() {
+void RenderFrameHostImpl::ResetPermissionsPolicy() {
   RenderFrameHostImpl* parent_frame_host = GetParent();
   const blink::PermissionsPolicy* parent_policy =
       parent_frame_host ? parent_frame_host->permissions_policy() : nullptr;
@@ -8947,7 +8947,7 @@
   // new ones.
   DCHECK(!navigation_request->IsServedFromBackForwardCache());
 
-  ResetFeaturePolicy();
+  ResetPermissionsPolicy();
   active_sandbox_flags_ = params.sandbox_flags;
   permissions_policy_header_ = params.permissions_policy_header;
   permissions_policy_->SetHeaderPolicy(params.permissions_policy_header);
diff --git a/content/browser/renderer_host/render_frame_host_impl.h b/content/browser/renderer_host/render_frame_host_impl.h
index b16e5f5..71fa9ff 100644
--- a/content/browser/renderer_host/render_frame_host_impl.h
+++ b/content/browser/renderer_host/render_frame_host_impl.h
@@ -2057,7 +2057,7 @@
                                 base::WeakPtr<RenderFrameHostImpl> impl);
 
  private:
-  friend class RenderFrameHostFeaturePolicyTest;
+  friend class RenderFrameHostPermissionsPolicyTest;
   friend class TestRenderFrameHost;
   friend class TestRenderViewHost;
   friend class TextInputTestLocalFrame;
@@ -2507,7 +2507,7 @@
 
   // Clears any existing policy and constructs a new policy for this frame,
   // based on its parent frame.
-  void ResetFeaturePolicy();
+  void ResetPermissionsPolicy();
 
   // TODO(ekaramad): One major purpose behind the API is to traverse the frame
   // tree top-down to visit the  RenderWidgetHostViews of interest in the most
diff --git a/content/browser/renderer_host/render_frame_host_permissions_policy_unittest.cc b/content/browser/renderer_host/render_frame_host_permissions_policy_unittest.cc
index 181e91f8..f7f98c6 100644
--- a/content/browser/renderer_host/render_frame_host_permissions_policy_unittest.cc
+++ b/content/browser/renderer_host/render_frame_host_permissions_policy_unittest.cc
@@ -21,7 +21,7 @@
 // class itself is tested thoroughly in permissions_policy_unittest.cc. Instead
 // they are meant to ensure that integration with RenderFrameHost works
 // correctly.
-class RenderFrameHostFeaturePolicyTest
+class RenderFrameHostPermissionsPolicyTest
     : public content::RenderViewHostTestHarness {
  protected:
   static constexpr const char* kOrigin1 = "https://google.com";
@@ -58,7 +58,7 @@
     RenderFrameHost* current = *rfh;
     auto navigation = NavigationSimulator::CreateRendererInitiated(
         current->GetLastCommittedURL(), current);
-    navigation->SetFeaturePolicyHeader(CreateFPHeader(feature, origins));
+    navigation->SetPermissionsPolicyHeader(CreateFPHeader(feature, origins));
     navigation->Commit();
     *rfh = navigation->GetFinalRenderFrameHost();
   }
@@ -92,7 +92,7 @@
   }
 };
 
-TEST_F(RenderFrameHostFeaturePolicyTest, DefaultPolicy) {
+TEST_F(RenderFrameHostPermissionsPolicyTest, DefaultPolicy) {
   RenderFrameHost* parent = GetMainRFH(kOrigin1);
   RenderFrameHost* child = AddChildRFH(parent, kOrigin2);
 
@@ -102,7 +102,7 @@
   EXPECT_FALSE(child->IsFeatureEnabled(kDefaultSelfFeature));
 }
 
-TEST_F(RenderFrameHostFeaturePolicyTest, HeaderPolicy) {
+TEST_F(RenderFrameHostPermissionsPolicyTest, HeaderPolicy) {
   RenderFrameHost* parent = GetMainRFH(kOrigin1);
 
   // Enable the feature for the child in the parent frame.
@@ -133,7 +133,7 @@
   EXPECT_FALSE(child->IsFeatureEnabled(kDefaultSelfFeature));
 }
 
-TEST_F(RenderFrameHostFeaturePolicyTest, ContainerPolicy) {
+TEST_F(RenderFrameHostPermissionsPolicyTest, ContainerPolicy) {
   RenderFrameHost* parent = GetMainRFH(kOrigin1);
   RenderFrameHost* child = AddChildRFH(parent, kOrigin2);
 
@@ -152,7 +152,7 @@
   EXPECT_FALSE(child->IsFeatureEnabled(kDefaultSelfFeature));
 }
 
-TEST_F(RenderFrameHostFeaturePolicyTest, HeaderAndContainerPolicy) {
+TEST_F(RenderFrameHostPermissionsPolicyTest, HeaderAndContainerPolicy) {
   RenderFrameHost* parent = GetMainRFH(kOrigin1);
 
   // Set a header policy and container policy. Check that they both take effect.
diff --git a/content/browser/renderer_host/render_process_host_impl.cc b/content/browser/renderer_host/render_process_host_impl.cc
index 45965fce..7a9a4e1 100644
--- a/content/browser/renderer_host/render_process_host_impl.cc
+++ b/content/browser/renderer_host/render_process_host_impl.cc
@@ -312,9 +312,6 @@
     GetShaderCacheFactorySingleton()->RemoveCacheInfo(id);
 }
 
-// Allow us to only run the trial in the first renderer.
-bool has_done_stun_trials = false;
-
 // the global list of all renderer processes
 base::IDMap<RenderProcessHost*>& GetAllHosts() {
   static base::NoDestructor<base::IDMap<RenderProcessHost*>> s_all_hosts;
@@ -3415,16 +3412,6 @@
   BrowserChildProcessHostImpl::CopyFeatureAndFieldTrialFlags(renderer_cmd);
   BrowserChildProcessHostImpl::CopyTraceStartupFlags(renderer_cmd);
 
-  // Only run the Stun trials in the first renderer.
-  if (!has_done_stun_trials &&
-      browser_cmd.HasSwitch(switches::kWebRtcStunProbeTrialParameter)) {
-    has_done_stun_trials = true;
-    renderer_cmd->AppendSwitchASCII(
-        switches::kWebRtcStunProbeTrialParameter,
-        browser_cmd.GetSwitchValueASCII(
-            switches::kWebRtcStunProbeTrialParameter));
-  }
-
   // Disable databases in incognito mode.
   if (GetBrowserContext()->IsOffTheRecord() &&
       !browser_cmd.HasSwitch(switches::kDisableDatabases)) {
diff --git a/content/browser/resources/gpu/vulkan_info.js b/content/browser/resources/gpu/vulkan_info.js
index 8bb02c0..149436a 100644
--- a/content/browser/resources/gpu/vulkan_info.js
+++ b/content/browser/resources/gpu/vulkan_info.js
@@ -9,6 +9,76 @@
     const array = Uint8Array.from(atob(base64Data), c => c.charCodeAt(0));
     const dataView = new DataView(array.buffer);
     this.vulkanInfo_ = VulkanInfo_Deserialize(dataView);
+    this.beautify(this.vulkanInfo_);
+  }
+
+  beautify(obj) {
+    for (const key of Object.keys(obj)) {
+      const value = obj[key];
+
+      if (key === 'specVersion') {
+        continue;
+      }
+
+      if (key.endsWith('Version')) {
+        obj[key] = this.beautifyVersion(value);
+        continue;
+      }
+
+      if (key === 'extensions' || key === 'instanceExtensions') {
+        obj[key] = this.beautifyExtensions(value);
+        continue;
+      }
+
+      if (key.endsWith('UUID')) {
+        obj[key] = this.beautifyUUID(value);
+        continue;
+      }
+
+      if (typeof value === 'bigint') {
+        // JSON.stringify() doesn't support bigint.
+        obj[key] = Number(value);
+        continue;
+      }
+
+      if (typeof value === 'object') {
+        this.beautify(value);
+        continue;
+      }
+    }
+  }
+
+  beautifyVersion(version) {
+    const major = version >> 22;
+    const minor = (version >> 12) & 0x3ff;
+    const patch = version & 0xfff;
+    return `${major}.${minor}.${patch}`;
+  }
+
+  beautifyUUID(uuid) {
+    // xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
+    let result = '';
+    for (let i = 0; i < 16; ++i) {
+      const value = uuid[i];
+      if (i == 4 || i == 6 || i == 8 || i == 10) {
+        result += '-';
+      }
+      if (value < 0x10) {
+        result += '0';
+      }
+      result += value.toString(16);
+    }
+    return result;
+  }
+
+  beautifyExtensions(extensions) {
+    const result = {};
+    for (const extension of extensions) {
+      const name = extension['extensionName'];
+      const version = extension['specVersion'];
+      result[name] = version;
+    }
+    return result;
   }
 
   toString() {
diff --git a/content/browser/security_exploit_browsertest.cc b/content/browser/security_exploit_browsertest.cc
index 120942a..71f687dd 100644
--- a/content/browser/security_exploit_browsertest.cc
+++ b/content/browser/security_exploit_browsertest.cc
@@ -1537,8 +1537,9 @@
 // attempts to navigate with a Trust Tokens redemption operation associated with
 // the navigation, but its parent lacks the trust-token-redemption Feature
 // Policy feature.
-IN_PROC_BROWSER_TEST_F(SecurityExploitBrowserTestWithTrustTokensEnabled,
-                       BrowserForbidsTrustTokenRedemptionWithoutFeaturePolicy) {
+IN_PROC_BROWSER_TEST_F(
+    SecurityExploitBrowserTestWithTrustTokensEnabled,
+    BrowserForbidsTrustTokenRedemptionWithoutPermissionsPolicy) {
   WebContents* web_contents = shell()->web_contents();
 
   // Prepare to intercept BeginNavigation mojo IPC. This has to be done before
@@ -1582,8 +1583,9 @@
 // attempts to navigate with a Trust Tokens signing operation associated with
 // the navigation, but its parent lacks the trust-token-redemption (sic) Feature
 // Policy feature.
-IN_PROC_BROWSER_TEST_F(SecurityExploitBrowserTestWithTrustTokensEnabled,
-                       BrowserForbidsTrustTokenSigningWithoutFeaturePolicy) {
+IN_PROC_BROWSER_TEST_F(
+    SecurityExploitBrowserTestWithTrustTokensEnabled,
+    BrowserForbidsTrustTokenSigningWithoutPermissionsPolicy) {
   WebContents* web_contents = shell()->web_contents();
 
   // Prepare to intercept BeginNavigation mojo IPC. This has to be done before
diff --git a/content/browser/site_per_process_browsertest.cc b/content/browser/site_per_process_browsertest.cc
index 496b8f8..79cacba7 100644
--- a/content/browser/site_per_process_browsertest.cc
+++ b/content/browser/site_per_process_browsertest.cc
@@ -9239,7 +9239,7 @@
 // Test that the replicated permissions policy header is correct in remote
 // proxies after the local frame has navigated.
 IN_PROC_BROWSER_TEST_P(SitePerProcessBrowserTest,
-                       TestFeaturePolicyReplicationToProxyOnNavigation) {
+                       TestPermissionsPolicyReplicationToProxyOnNavigation) {
   GURL main_url(embedded_test_server()->GetURL(
       "a.com", "/frame_tree/page_with_two_frames.html"));
   GURL first_nav_url(
@@ -9659,7 +9659,7 @@
 // results in the correct permissions policy in the RemoteSecurityContext.
 // https://crbug.com/852102
 IN_PROC_BROWSER_TEST_P(SitePerProcessBrowserTest,
-                       FeaturePolicyConstructionInExistingProxy) {
+                       PermissionsPolicyConstructionInExistingProxy) {
   WebContentsImpl* contents = web_contents();
   FrameTreeNode* root = contents->GetFrameTree()->root();
 
diff --git a/content/browser/webauth/webauth_browsertest.cc b/content/browser/webauth/webauth_browsertest.cc
index 35a071a..038bd22 100644
--- a/content/browser/webauth/webauth_browsertest.cc
+++ b/content/browser/webauth/webauth_browsertest.cc
@@ -113,7 +113,7 @@
 constexpr char kAbortErrorMessage[] =
     "webauth: AbortError: Request has been aborted.";
 
-constexpr char kGetFeaturePolicyMissingMessage[] =
+constexpr char kGetPermissionsPolicyMissingMessage[] =
     "webauth: NotAllowedError: The 'publickey-credentials-get' feature is "
     "not enabled in this document. Permissions Policy may be used to delegate "
     "Web Authentication capabilities to cross-origin child frames.";
@@ -1267,7 +1267,7 @@
     if (test.get_should_work) {
       EXPECT_EQ(std::string(kOkMessage), result);
     } else {
-      EXPECT_EQ(kGetFeaturePolicyMissingMessage, result);
+      EXPECT_EQ(kGetPermissionsPolicyMissingMessage, result);
     }
   }
 }
diff --git a/content/browser/worker_host/worker_script_fetch_initiator.cc b/content/browser/worker_host/worker_script_fetch_initiator.cc
index 483ca74..b4fea28b 100644
--- a/content/browser/worker_host/worker_script_fetch_initiator.cc
+++ b/content/browser/worker_host/worker_script_fetch_initiator.cc
@@ -237,8 +237,8 @@
     non_network_factories.emplace(
         url::kFileScheme, FileURLLoaderFactory::Create(
                               storage_partition->browser_context()->GetPath(),
-                              storage_partition->browser_context()
-                                  ->GetSharedCorsOriginAccessList(),
+                              BrowserContext::GetSharedCorsOriginAccessList(
+                                  storage_partition->browser_context()),
                               file_factory_priority));
   }
 
diff --git a/content/child/image_decoder_utils.cc b/content/child/image_decoder_utils.cc
index a9058b5..b5346b1 100644
--- a/content/child/image_decoder_utils.cc
+++ b/content/child/image_decoder_utils.cc
@@ -5,7 +5,6 @@
 #include "content/public/child/image_decoder_utils.h"
 
 #include "third_party/blink/public/platform/web_data.h"
-#include "third_party/blink/public/platform/web_size.h"
 #include "third_party/blink/public/web/web_image.h"
 #include "third_party/skia/include/core/SkBitmap.h"
 
diff --git a/content/common/cursors/webcursor_mac.mm b/content/common/cursors/webcursor_mac.mm
index 0fd7909..2d269dff 100644
--- a/content/common/cursors/webcursor_mac.mm
+++ b/content/common/cursors/webcursor_mac.mm
@@ -13,15 +13,12 @@
 #include "content/app/resources/grit/content_resources.h"
 #include "content/public/common/content_client.h"
 #include "skia/ext/skia_utils_mac.h"
-#include "third_party/blink/public/platform/web_size.h"
 #include "ui/base/cursor/cursor.h"
 #include "ui/base/cursor/mojom/cursor_type.mojom-shared.h"
 #include "ui/gfx/geometry/point_conversions.h"
 #include "ui/gfx/geometry/size_conversions.h"
 #include "ui/gfx/image/image.h"
 
-using blink::WebSize;
-
 // Private interface to CoreCursor, as of Mac OS X 10.7. This is essentially the
 // implementation of WKCursor in WebKitSystemInterface.
 
diff --git a/content/common/partition_alloc_support.cc b/content/common/partition_alloc_support.cc
index 49c39f4..3a27864 100644
--- a/content/common/partition_alloc_support.cc
+++ b/content/common/partition_alloc_support.cc
@@ -42,8 +42,7 @@
   }();
 
   if (name) {
-    base::internal::PCScan<base::internal::ThreadSafe>::Instance()
-        .SetProcessName(name);
+    base::internal::PCScan::Instance().SetProcessName(name);
   }
 }
 
diff --git a/content/public/browser/browser_context.h b/content/public/browser/browser_context.h
index c4adba4..be407422 100644
--- a/content/public/browser/browser_context.h
+++ b/content/public/browser/browser_context.h
@@ -21,7 +21,6 @@
 #include "content/common/content_export.h"
 #include "mojo/public/cpp/bindings/pending_receiver.h"
 #include "mojo/public/cpp/bindings/pending_remote.h"
-#include "services/network/public/mojom/cors_origin_pattern.mojom-forward.h"
 #include "services/network/public/mojom/network_context.mojom-forward.h"
 #include "third_party/blink/public/mojom/blob/blob.mojom-forward.h"
 #include "third_party/blink/public/mojom/push_messaging/push_messaging.mojom-forward.h"
@@ -45,10 +44,6 @@
 class ExternalMountPoints;
 }
 
-namespace url {
-class Origin;
-}
-
 namespace media {
 class VideoDecodePerfHistory;
 namespace learning {
@@ -219,12 +214,20 @@
 
   static void SetDownloadManagerForTesting(
       BrowserContext* browser_context,
-      std::unique_ptr<content::DownloadManager> download_manager);
+      std::unique_ptr<DownloadManager> download_manager);
 
   static void SetPermissionControllerForTesting(
       BrowserContext* browser_context,
       std::unique_ptr<PermissionController> permission_controller);
 
+  // The list of CORS exemptions.  This list needs to be 1) replicated when
+  // creating or re-creating new network::mojom::NetworkContexts (see
+  // network::mojom::NetworkContextParams::cors_origin_access_list) and 2)
+  // consulted by CORS-aware factories (e.g. passed when constructing
+  // FileURLLoaderFactory).
+  static SharedCorsOriginAccessList* GetSharedCorsOriginAccessList(
+      BrowserContext* context);
+
   BrowserContext();
 
   ~BrowserContext() override;
@@ -311,25 +314,6 @@
   // called once per context. It's valid to return nullptr.
   virtual BrowsingDataRemoverDelegate* GetBrowsingDataRemoverDelegate() = 0;
 
-  // Sets CORS origin access lists.
-  enum class TargetBrowserContexts {
-    // Only modify |this| BrowserContext.
-    kSingleContext,
-
-    // Modify |this| BrowserContext and all related regular/OffTheRecord
-    // BrowserContexts.
-    kAllRelatedContexts,
-  };
-  virtual void SetCorsOriginAccessListForOrigin(
-      TargetBrowserContexts target_mode,
-      const url::Origin& source_origin,
-      std::vector<network::mojom::CorsOriginPatternPtr> allow_patterns,
-      std::vector<network::mojom::CorsOriginPatternPtr> block_patterns,
-      base::OnceClosure closure);
-
-  // Returns a SharedCorsOriginAccessList instance.
-  virtual SharedCorsOriginAccessList* GetSharedCorsOriginAccessList();
-
   // Returns a unique string associated with this browser context.
   virtual const std::string& UniqueId();
 
diff --git a/content/public/browser/cors_origin_pattern_setter.cc b/content/public/browser/cors_origin_pattern_setter.cc
index 90560f6e..fc6ee92 100644
--- a/content/public/browser/cors_origin_pattern_setter.cc
+++ b/content/public/browser/cors_origin_pattern_setter.cc
@@ -3,13 +3,21 @@
 // found in the LICENSE file.
 
 #include "content/public/browser/cors_origin_pattern_setter.h"
+
+#include <memory>
+
+#include "base/barrier_closure.h"
+#include "base/memory/ref_counted.h"
 #include "content/public/browser/browser_context.h"
+#include "content/public/browser/shared_cors_origin_access_list.h"
 #include "content/public/browser/storage_partition.h"
+#include "mojo/public/cpp/bindings/clone_traits.h"
 #include "services/network/public/mojom/network_context.mojom.h"
 
 namespace content {
 
 CorsOriginPatternSetter::CorsOriginPatternSetter(
+    base::PassKey<CorsOriginPatternSetter> pass_key,
     const url::Origin& source_origin,
     std::vector<network::mojom::CorsOriginPatternPtr> allow_patterns,
     std::vector<network::mojom::CorsOriginPatternPtr> block_patterns,
@@ -23,30 +31,39 @@
   std::move(closure_).Run();
 }
 
-void CorsOriginPatternSetter::ApplyToEachStoragePartition(
-    BrowserContext* browser_context) {
-  BrowserContext::ForEachStoragePartition(
-      browser_context, base::BindRepeating(&CorsOriginPatternSetter::SetLists,
-                                           base::RetainedRef(this)));
-}
-
-void CorsOriginPatternSetter::SetLists(StoragePartition* partition) {
+void CorsOriginPatternSetter::SetForStoragePartition(
+    content::StoragePartition* partition) {
   partition->GetNetworkContext()->SetCorsOriginAccessListsForOrigin(
-      source_origin_, ClonePatterns(allow_patterns_),
-      ClonePatterns(block_patterns_),
+      source_origin_, mojo::Clone(allow_patterns_),
+      mojo::Clone(block_patterns_),
       base::BindOnce([](scoped_refptr<CorsOriginPatternSetter> setter) {},
                      base::RetainedRef(this)));
 }
 
 // static
-std::vector<network::mojom::CorsOriginPatternPtr>
-CorsOriginPatternSetter::ClonePatterns(
-    const std::vector<network::mojom::CorsOriginPatternPtr>& patterns) {
-  std::vector<network::mojom::CorsOriginPatternPtr> cloned_patterns;
-  cloned_patterns.reserve(patterns.size());
-  for (const auto& item : patterns)
-    cloned_patterns.push_back(item.Clone());
-  return cloned_patterns;
+void CorsOriginPatternSetter::Set(
+    content::BrowserContext* browser_context,
+    const url::Origin& source_origin,
+    std::vector<network::mojom::CorsOriginPatternPtr> allow_patterns,
+    std::vector<network::mojom::CorsOriginPatternPtr> block_patterns,
+    base::OnceClosure closure) {
+  auto barrier_closure = BarrierClosure(2, std::move(closure));
+
+  scoped_refptr<CorsOriginPatternSetter> setter =
+      base::MakeRefCounted<CorsOriginPatternSetter>(
+          PassKey(), source_origin, mojo::Clone(allow_patterns),
+          mojo::Clone(block_patterns), barrier_closure);
+  content::BrowserContext::ForEachStoragePartition(
+      browser_context,
+      base::BindRepeating(&CorsOriginPatternSetter::SetForStoragePartition,
+                          base::RetainedRef(setter)));
+
+  // Keep the per-profile access list up to date so that we can use this to
+  // restore NetworkContext settings at anytime, e.g. on restarting the
+  // network service.
+  content::BrowserContext::GetSharedCorsOriginAccessList(browser_context)
+      ->SetForOrigin(source_origin, std::move(allow_patterns),
+                     std::move(block_patterns), barrier_closure);
 }
 
 }  // namespace content
diff --git a/content/public/browser/cors_origin_pattern_setter.h b/content/public/browser/cors_origin_pattern_setter.h
index 6b33bcab..9a30e01b7 100644
--- a/content/public/browser/cors_origin_pattern_setter.h
+++ b/content/public/browser/cors_origin_pattern_setter.h
@@ -10,6 +10,8 @@
 
 #include "base/barrier_closure.h"
 #include "base/callback.h"
+#include "base/macros.h"
+#include "base/types/pass_key.h"
 #include "content/common/content_export.h"
 #include "services/network/public/mojom/cors_origin_pattern.mojom.h"
 #include "url/origin.h"
@@ -17,36 +19,47 @@
 namespace content {
 
 class BrowserContext;
+class SharedCorsOriginAccessList;
 class StoragePartition;
 
-// A class used to make an asynchronous Mojo call with cloned patterns for each
-// StoragePartition iteration. |this| instance will be destructed when all
-// existing asynchronous Mojo calls made in SetLists() are done, and |closure|
-// will be invoked on destructing |this|.
-//
-// Typically this would be used to implement
-// BrowserContext::SetCorsOriginAccessListForOrigin, and would use
-// ForEachStoragePartition with SetLists as the StoragePartitionCallback.
+// A class for mutating CORS examptions list associated with a BrowserContext:
+// 1. the in-process list in BrowserContext::shared_cors_origin_access_list
+// 2. the per-NetworkContext (i.e. per-StoragePartition) lists
 class CONTENT_EXPORT CorsOriginPatternSetter
     : public base::RefCounted<CorsOriginPatternSetter> {
  public:
-  CorsOriginPatternSetter(
+  // Sets |allow_patterns| and |block_patterns| for |source_origin| for the
+  // |browser_context|.
+  //
+  // The new settings will be 1) set in the SharedCorsOriginAccessList from
+  // |browser_context|'s GetSharedCorsOriginAccessList as well as 2) pushed to
+  // all network::mojom::NetworkContexts associated with all the current
+  // StoragePartitions of the |browser_context|.  |closure| will be called once
+  // all the stores/pushes have been acked.
+  static void Set(
+      content::BrowserContext* browser_context,
       const url::Origin& source_origin,
       std::vector<network::mojom::CorsOriginPatternPtr> allow_patterns,
       std::vector<network::mojom::CorsOriginPatternPtr> block_patterns,
       base::OnceClosure closure);
 
-  void ApplyToEachStoragePartition(BrowserContext* browser_context);
-
-  static std::vector<network::mojom::CorsOriginPatternPtr> ClonePatterns(
-      const std::vector<network::mojom::CorsOriginPatternPtr>& patterns);
+  // The constructor is semi-private (CorsOriginPatternSetter should only be
+  // constructed internally, within the implementation of the public Set
+  // method).
+  using PassKey = base::PassKey<CorsOriginPatternSetter>;
+  CorsOriginPatternSetter(
+      base::PassKey<CorsOriginPatternSetter> pass_key,
+      const url::Origin& source_origin,
+      std::vector<network::mojom::CorsOriginPatternPtr> allow_patterns,
+      std::vector<network::mojom::CorsOriginPatternPtr> block_patterns,
+      base::OnceClosure closure);
 
  private:
   friend class base::RefCounted<CorsOriginPatternSetter>;
-
-  void SetLists(StoragePartition* partition);
   ~CorsOriginPatternSetter();
 
+  void SetForStoragePartition(content::StoragePartition* partition);
+
   const url::Origin source_origin_;
   const std::vector<network::mojom::CorsOriginPatternPtr> allow_patterns_;
   const std::vector<network::mojom::CorsOriginPatternPtr> block_patterns_;
diff --git a/content/public/common/content_features.cc b/content/public/common/content_features.cc
index b1a5e598d..6cec4064 100644
--- a/content/public/common/content_features.cc
+++ b/content/public/common/content_features.cc
@@ -495,10 +495,6 @@
 const base::Feature kPeriodicBackgroundSync{"PeriodicBackgroundSync",
                                             base::FEATURE_DISABLED_BY_DEFAULT};
 
-// Enable permission policy for configuring and restricting feature behavior.
-const base::Feature kPermissionsPolicyHeader{"PermissionsPolicyHeader",
-                                             base::FEATURE_ENABLED_BY_DEFAULT};
-
 // If Pepper 3D Image Chromium is allowed, this feature controls whether it is
 // enabled.
 const base::Feature kPepper3DImageChromium {
diff --git a/content/public/common/content_features.h b/content/public/common/content_features.h
index 29da18f..cb66f6b6 100644
--- a/content/public/common/content_features.h
+++ b/content/public/common/content_features.h
@@ -126,7 +126,7 @@
 CONTENT_EXPORT extern const base::Feature kOpenXrExtendedFeatureSupport;
 CONTENT_EXPORT extern const base::Feature kOverscrollHistoryNavigation;
 CONTENT_EXPORT extern const base::Feature kPeriodicBackgroundSync;
-CONTENT_EXPORT extern const base::Feature kPermissionsPolicyHeader;
+CONTENT_EXPORT extern const base::Feature kFeaturePolicyHeader;
 CONTENT_EXPORT extern const base::Feature kPepper3DImageChromium;
 CONTENT_EXPORT extern const base::Feature kPepperCrossOriginRedirectRestriction;
 CONTENT_EXPORT extern const base::Feature kPlzServiceWorker;
diff --git a/content/public/common/content_switches.cc b/content/public/common/content_switches.cc
index 6067e36..71d2b75 100644
--- a/content/public/common/content_switches.cc
+++ b/content/public/common/content_switches.cc
@@ -879,11 +879,6 @@
 const char kWebRtcMaxCpuConsumptionPercentage[] =
     "webrtc-max-cpu-consumption-percentage";
 
-// Renderer process parameter for WebRTC Stun probe trial to determine the
-// interval. Please see SetupStunProbeTrial in
-// chrome_browser_field_trials_desktop.cc for more detail.
-const char kWebRtcStunProbeTrialParameter[] = "webrtc-stun-probe-trial";
-
 // Enable capture and local storage of WebRTC event logs without visiting
 // chrome://webrtc-internals. This is useful for automated testing. It accepts
 // the path to which the local logs would be stored. Disabling is not possible
diff --git a/content/public/common/content_switches.h b/content/public/common/content_switches.h
index 0a10e2d..f711444d 100644
--- a/content/public/common/content_switches.h
+++ b/content/public/common/content_switches.h
@@ -237,7 +237,6 @@
 CONTENT_EXPORT extern const char kWaitForDebuggerWebUI[];
 extern const char kWebRtcMaxCaptureFramerate[];
 extern const char kWebRtcMaxCpuConsumptionPercentage[];
-CONTENT_EXPORT extern const char kWebRtcStunProbeTrialParameter[];
 CONTENT_EXPORT extern const char kWebRtcLocalEventLogging[];
 CONTENT_EXPORT extern const char kDisableScrollToTextFragment[];
 
diff --git a/content/public/test/navigation_simulator.h b/content/public/test/navigation_simulator.h
index f2be8c7..4a6a143 100644
--- a/content/public/test/navigation_simulator.h
+++ b/content/public/test/navigation_simulator.h
@@ -274,7 +274,7 @@
       bool is_signed_exchange_inner_response) = 0;
 
   // Simulate receiving Permissions-Policy headers.
-  virtual void SetFeaturePolicyHeader(
+  virtual void SetPermissionsPolicyHeader(
       blink::ParsedPermissionsPolicy permissions_policy_header) = 0;
 
   // Provides the contents mime type to be set at commit. It should be
diff --git a/content/renderer/accessibility/blink_ax_tree_source.cc b/content/renderer/accessibility/blink_ax_tree_source.cc
index 5be9888..9bcbc3a 100644
--- a/content/renderer/accessibility/blink_ax_tree_source.cc
+++ b/content/renderer/accessibility/blink_ax_tree_source.cc
@@ -24,7 +24,6 @@
 #include "content/renderer/render_frame_impl.h"
 #include "content/renderer/render_frame_proxy.h"
 #include "content/renderer/render_view_impl.h"
-#include "third_party/blink/public/platform/web_size.h"
 #include "third_party/blink/public/platform/web_string.h"
 #include "third_party/blink/public/platform/web_vector.h"
 #include "third_party/blink/public/web/web_ax_enums.h"
diff --git a/content/renderer/accessibility/render_accessibility_impl_browsertest.cc b/content/renderer/accessibility/render_accessibility_impl_browsertest.cc
index 8488a92d8..b6efb23 100644
--- a/content/renderer/accessibility/render_accessibility_impl_browsertest.cc
+++ b/content/renderer/accessibility/render_accessibility_impl_browsertest.cc
@@ -42,7 +42,6 @@
 #include "testing/gtest/include/gtest/gtest.h"
 #include "third_party/blink/public/common/associated_interfaces/associated_interface_provider.h"
 #include "third_party/blink/public/platform/web_runtime_features.h"
-#include "third_party/blink/public/platform/web_size.h"
 #include "third_party/blink/public/web/web_ax_object.h"
 #include "third_party/blink/public/web/web_document.h"
 #include "third_party/blink/public/web/web_element.h"
diff --git a/content/renderer/gpu_benchmarking_extension.cc b/content/renderer/gpu_benchmarking_extension.cc
index 73785bd..cb2e0b1 100644
--- a/content/renderer/gpu_benchmarking_extension.cc
+++ b/content/renderer/gpu_benchmarking_extension.cc
@@ -120,7 +120,6 @@
 using blink::WebImageCache;
 using blink::WebLocalFrame;
 using blink::WebPrivatePtr;
-using blink::WebSize;
 using blink::WebView;
 
 namespace content {
@@ -491,7 +490,7 @@
   const float kMarginLeft = 29.0f;   // 0.40 inch
   const int kContentWidth = 555;     // 7.71 inch
   const int kContentHeight = 735;    // 10.21 inch
-  blink::WebPrintParams params(blink::WebSize(kContentWidth, kContentHeight));
+  blink::WebPrintParams params(gfx::Size(kContentWidth, kContentHeight));
   params.printer_dpi = 300;
   uint32_t page_count = frame->PrintBegin(params, blink::WebNode());
   for (uint32_t i = 0; i < page_count; ++i) {
diff --git a/content/renderer/media/renderer_webmediaplayer_delegate.cc b/content/renderer/media/renderer_webmediaplayer_delegate.cc
index 0b886f5a..207ac30 100644
--- a/content/renderer/media/renderer_webmediaplayer_delegate.cc
+++ b/content/renderer/media/renderer_webmediaplayer_delegate.cc
@@ -18,7 +18,6 @@
 #include "media/base/media_content_type.h"
 #include "third_party/blink/public/mojom/frame/user_activation_notification_type.mojom.h"
 #include "third_party/blink/public/platform/web_fullscreen_video_status.h"
-#include "third_party/blink/public/platform/web_size.h"
 #include "third_party/blink/public/web/web_local_frame.h"
 #include "ui/gfx/geometry/size.h"
 
diff --git a/content/renderer/pepper/pepper_plugin_instance_impl.cc b/content/renderer/pepper/pepper_plugin_instance_impl.cc
index e37682c..78210ada 100644
--- a/content/renderer/pepper/pepper_plugin_instance_impl.cc
+++ b/content/renderer/pepper/pepper_plugin_instance_impl.cc
@@ -1213,12 +1213,14 @@
   view_data_.css_scale *= viewport_to_dip_scale_;
   view_data_.device_scale /= viewport_to_dip_scale_;
 
-  gfx::Size scroll_offset = gfx::ScaleToRoundedSize(
-      container_->GetDocument().GetFrame()->GetScrollOffset(),
-      viewport_to_dip_scale_);
+  gfx::ScrollOffset scroll_offset =
+      container_->GetDocument().GetFrame()->GetScrollOffset();
+  scroll_offset.Scale(viewport_to_dip_scale_);
 
-  view_data_.scroll_offset = PP_MakePoint(scroll_offset.width(),
-                                          scroll_offset.height());
+  gfx::Vector2d floored_scroll_offset =
+      ScrollOffsetToFlooredVector2d(scroll_offset);
+  view_data_.scroll_offset =
+      PP_MakePoint(floored_scroll_offset.x(), floored_scroll_offset.y());
 
   // The view size may have changed and we might need to update
   // our registration of event listeners.
diff --git a/content/renderer/pepper/pepper_webplugin_impl.cc b/content/renderer/pepper/pepper_webplugin_impl.cc
index 5309f70..2d2ab46 100644
--- a/content/renderer/pepper/pepper_webplugin_impl.cc
+++ b/content/renderer/pepper/pepper_webplugin_impl.cc
@@ -29,7 +29,6 @@
 #include "third_party/blink/public/common/thread_safe_browser_interface_broker_proxy.h"
 #include "third_party/blink/public/mojom/input/focus_type.mojom.h"
 #include "third_party/blink/public/platform/platform.h"
-#include "third_party/blink/public/platform/web_size.h"
 #include "third_party/blink/public/web/web_associated_url_loader_client.h"
 #include "third_party/blink/public/web/web_document.h"
 #include "third_party/blink/public/web/web_element.h"
@@ -47,7 +46,6 @@
 using blink::WebPluginContainer;
 using blink::WebPluginParams;
 using blink::WebPrintParams;
-using blink::WebSize;
 using blink::WebString;
 using blink::WebURL;
 using blink::WebVector;
diff --git a/content/renderer/render_frame_proxy.cc b/content/renderer/render_frame_proxy.cc
index b5dff34..73b504ae 100644
--- a/content/renderer/render_frame_proxy.cc
+++ b/content/renderer/render_frame_proxy.cc
@@ -258,7 +258,7 @@
   web_frame_->SetReplicatedInsecureNavigationsSet(
       state->insecure_navigations_set);
   web_frame_->SetReplicatedAdFrameType(state->ad_frame_type);
-  web_frame_->SetReplicatedFeaturePolicyHeader(
+  web_frame_->SetReplicatedPermissionsPolicyHeader(
       state->permissions_policy_header);
   if (state->has_active_user_gesture) {
     // TODO(crbug.com/1087963): This should be hearing about sticky activations
diff --git a/content/renderer/renderer_blink_platform_impl.cc b/content/renderer/renderer_blink_platform_impl.cc
index ec57738..4ae0a21 100644
--- a/content/renderer/renderer_blink_platform_impl.cc
+++ b/content/renderer/renderer_blink_platform_impl.cc
@@ -118,7 +118,6 @@
 using blink::WebAudioDevice;
 using blink::WebAudioLatencyHint;
 using blink::WebMediaStreamTrack;
-using blink::WebSize;
 using blink::WebString;
 using blink::WebURL;
 using blink::WebVector;
@@ -631,16 +630,6 @@
       switches::kEnableWebRtcStunOrigin);
 }
 
-base::Optional<blink::WebString>
-RendererBlinkPlatformImpl::WebRtcStunProbeTrialParameter() {
-  const base::CommandLine* cmd_line = base::CommandLine::ForCurrentProcess();
-  if (!cmd_line->HasSwitch(switches::kWebRtcStunProbeTrialParameter))
-    return base::nullopt;
-
-  return blink::WebString::FromASCII(
-      cmd_line->GetSwitchValueASCII(switches::kWebRtcStunProbeTrialParameter));
-}
-
 media::MediaPermission* RendererBlinkPlatformImpl::GetWebRTCMediaPermission(
     blink::WebLocalFrame* web_frame) {
   DCHECK(ShouldEnforceWebRTCRoutingPreferences());
diff --git a/content/renderer/renderer_blink_platform_impl.h b/content/renderer/renderer_blink_platform_impl.h
index 7df00ecc..cebdd95 100644
--- a/content/renderer/renderer_blink_platform_impl.h
+++ b/content/renderer/renderer_blink_platform_impl.h
@@ -155,7 +155,6 @@
   bool UsesFakeCodecForPeerConnection() override;
   bool IsWebRtcEncryptionEnabled() override;
   bool IsWebRtcStunOriginEnabled() override;
-  base::Optional<blink::WebString> WebRtcStunProbeTrialParameter() override;
   media::MediaPermission* GetWebRTCMediaPermission(
       blink::WebLocalFrame* web_frame) override;
   void GetWebRTCRendererPreferences(blink::WebLocalFrame* web_frame,
diff --git a/content/test/BUILD.gn b/content/test/BUILD.gn
index ea508260..6695d630 100644
--- a/content/test/BUILD.gn
+++ b/content/test/BUILD.gn
@@ -369,8 +369,6 @@
     "test_web_contents_factory.cc",
     "web_contents_observer_consistency_checker.cc",
     "web_contents_observer_consistency_checker.h",
-    "web_gesture_curve_mock.cc",
-    "web_gesture_curve_mock.h",
   ]
 
   configs += [
@@ -1050,6 +1048,7 @@
     "../browser/keyboard_lock_browsertest.cc",
     "../browser/keyboard_lock_browsertest.h",
     "../browser/loader/cors_file_origin_browsertest.cc",
+    "../browser/loader/cors_origin_pattern_setter_browsertest.cc",
     "../browser/loader/cors_preflight_cache_browsertest.cc",
     "../browser/loader/cross_site_document_blocking_browsertest.cc",
     "../browser/loader/derived_origin_in_fetch_browsertest.cc",
@@ -1880,6 +1879,7 @@
     "../browser/indexed_db/mock_mojo_indexed_db_callbacks.h",
     "../browser/indexed_db/mock_mojo_indexed_db_database_callbacks.cc",
     "../browser/indexed_db/mock_mojo_indexed_db_database_callbacks.h",
+    "../browser/loader/cors_origin_pattern_setter_unittest.cc",
     "../browser/loader/file_url_loader_factory_unittest.cc",
     "../browser/loader/merkle_integrity_source_stream_unittest.cc",
     "../browser/loader/navigation_url_loader_impl_unittest.cc",
diff --git a/chrome/test/data/loader/cors_origin_access_list_test.html b/content/test/data/loader/cors_origin_access_list_test.html
similarity index 100%
rename from chrome/test/data/loader/cors_origin_access_list_test.html
rename to content/test/data/loader/cors_origin_access_list_test.html
diff --git a/content/test/navigation_simulator_impl.cc b/content/test/navigation_simulator_impl.cc
index d2450aa2..b8b9bc3 100644
--- a/content/test/navigation_simulator_impl.cc
+++ b/content/test/navigation_simulator_impl.cc
@@ -904,7 +904,7 @@
   is_signed_exchange_inner_response_ = is_signed_exchange_inner_response;
 }
 
-void NavigationSimulatorImpl::SetFeaturePolicyHeader(
+void NavigationSimulatorImpl::SetPermissionsPolicyHeader(
     blink::ParsedPermissionsPolicy permissions_policy_header) {
   CHECK_LE(state_, STARTED) << "The Feature-Policy headers cannot be set after "
                                "the navigation has committed or failed";
diff --git a/content/test/navigation_simulator_impl.h b/content/test/navigation_simulator_impl.h
index 08e51a2..3c499fe 100644
--- a/content/test/navigation_simulator_impl.h
+++ b/content/test/navigation_simulator_impl.h
@@ -87,7 +87,7 @@
   void SetWasFetchedViaCache(bool was_fetched_via_cache) override;
   void SetIsSignedExchangeInnerResponse(
       bool is_signed_exchange_inner_response) override;
-  void SetFeaturePolicyHeader(
+  void SetPermissionsPolicyHeader(
       blink::ParsedPermissionsPolicy permissions_policy_header) override;
   void SetContentsMimeType(const std::string& contents_mime_type) override;
   void SetResponseHeaders(
diff --git a/content/test/web_gesture_curve_mock.cc b/content/test/web_gesture_curve_mock.cc
deleted file mode 100644
index 87dc81a..0000000
--- a/content/test/web_gesture_curve_mock.cc
+++ /dev/null
@@ -1,25 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "content/test/web_gesture_curve_mock.h"
-
-WebGestureCurveMock::WebGestureCurveMock(
-    const gfx::Vector2dF& velocity,
-    const blink::WebSize& cumulative_scroll)
-    : velocity_(velocity), cumulative_scroll_(cumulative_scroll) {}
-
-WebGestureCurveMock::~WebGestureCurveMock() {
-}
-
-bool WebGestureCurveMock::Advance(double time,
-                                  gfx::Vector2dF& out_current_velocity,
-                                  gfx::Vector2dF& out_delta_to_scroll) {
-  blink::WebSize displacement(velocity_.x() * time, velocity_.y() * time);
-  out_delta_to_scroll =
-      gfx::Vector2dF(displacement.width - cumulative_scroll_.width,
-                     displacement.height - cumulative_scroll_.height);
-  cumulative_scroll_ = displacement;
-  out_current_velocity = velocity_;
-  return true;
-}
diff --git a/content/test/web_gesture_curve_mock.h b/content/test/web_gesture_curve_mock.h
deleted file mode 100644
index 9659349a9..0000000
--- a/content/test/web_gesture_curve_mock.h
+++ /dev/null
@@ -1,34 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CONTENT_TEST_WEB_GESTURE_CURVE_MOCK_H_
-#define CONTENT_TEST_WEB_GESTURE_CURVE_MOCK_H_
-
-#include <memory>
-
-#include "base/macros.h"
-#include "third_party/blink/public/platform/web_gesture_curve.h"
-#include "third_party/blink/public/platform/web_size.h"
-
-// A simple class for mocking a WebGestureCurve. The curve flings at velocity
-// indefinitely.
-class WebGestureCurveMock : public blink::WebGestureCurve {
- public:
-  WebGestureCurveMock(const gfx::Vector2dF& velocity,
-                      const blink::WebSize& cumulative_scroll);
-  ~WebGestureCurveMock() override;
-
-  // Returns false if curve has finished and can no longer advance.
-  bool Advance(double time,
-               gfx::Vector2dF& out_current_velocity,
-               gfx::Vector2dF& out_delta_to_scroll) override;
-
- private:
-  gfx::Vector2dF velocity_;
-  blink::WebSize cumulative_scroll_;
-
-  DISALLOW_COPY_AND_ASSIGN(WebGestureCurveMock);
-};
-
-#endif  // CONTENT_TEST_WEB_GESTURE_CURVE_MOCK_H_
diff --git a/content/web_test/renderer/layout_dump.cc b/content/web_test/renderer/layout_dump.cc
index 0e9d42b..7f87fb1 100644
--- a/content/web_test/renderer/layout_dump.cc
+++ b/content/web_test/renderer/layout_dump.cc
@@ -7,7 +7,6 @@
 #include "base/check.h"
 #include "base/strings/stringprintf.h"
 #include "content/web_test/renderer/web_frame_test_proxy.h"
-#include "third_party/blink/public/platform/web_size.h"
 #include "third_party/blink/public/platform/web_string.h"
 #include "third_party/blink/public/test/test_web_frame_content_dumper.h"
 #include "third_party/blink/public/web/web_document.h"
@@ -20,7 +19,6 @@
 using blink::TestWebFrameContentDumper;
 using blink::WebFrame;
 using blink::WebLocalFrame;
-using blink::WebSize;
 
 namespace {
 
@@ -40,15 +38,16 @@
 
 std::string DumpFrameScrollPosition(WebLocalFrame* frame) {
   std::string result;
-  WebSize offset = frame->GetScrollOffset();
-  if (offset.width > 0 || offset.height > 0) {
+  gfx::ScrollOffset offset = frame->GetScrollOffset();
+  if (offset.x() > 0 || offset.y() > 0) {
     if (frame->Parent()) {
       auto* frame_proxy = static_cast<WebFrameTestProxy*>(frame->Client());
       result = std::string("frame '") + frame_proxy->GetFrameNameForWebTests() +
                "' ";
     }
-    base::StringAppendF(&result, "scrolled to %d,%d\n", offset.width,
-                        offset.height);
+    base::StringAppendF(&result, "scrolled to %d,%d\n",
+                        base::ClampFloor(offset.x()),
+                        base::ClampFloor(offset.y()));
   }
 
   return result;
diff --git a/content/web_test/renderer/pixel_dump.cc b/content/web_test/renderer/pixel_dump.cc
index 387c511..31345a5 100644
--- a/content/web_test/renderer/pixel_dump.cc
+++ b/content/web_test/renderer/pixel_dump.cc
@@ -48,16 +48,16 @@
 
   uint32_t page_count =
       web_frame->PrintBegin(page_size_in_pixels, blink::WebNode());
-  blink::WebSize spool_size =
+  gfx::Size spool_size =
       web_frame->SpoolSizeInPixelsForTesting(page_size_in_pixels, page_count);
 
   bool is_opaque = false;
 
   SkBitmap bitmap;
-  if (!bitmap.tryAllocN32Pixels(spool_size.width, spool_size.height,
+  if (!bitmap.tryAllocN32Pixels(spool_size.width(), spool_size.height(),
                                 is_opaque)) {
-    LOG(ERROR) << "Failed to create bitmap width=" << spool_size.width
-               << " height=" << spool_size.height;
+    LOG(ERROR) << "Failed to create bitmap width=" << spool_size.width()
+               << " height=" << spool_size.height();
     return SkBitmap();
   }
 
diff --git a/content/web_test/renderer/web_frame_test_proxy.cc b/content/web_test/renderer/web_frame_test_proxy.cc
index 24f6951..9fda0c6d 100644
--- a/content/web_test/renderer/web_frame_test_proxy.cc
+++ b/content/web_test/renderer/web_frame_test_proxy.cc
@@ -215,7 +215,7 @@
   void ScriptedPrint(bool user_initiated) override {
     // This is using the main frame for the size, but maybe it should be using
     // the frame's size.
-    blink::WebSize page_size_in_pixels =
+    gfx::Size page_size_in_pixels =
         frame_proxy()->GetLocalRootWebFrameWidget()->Size();
     if (page_size_in_pixels.IsEmpty())
       return;
diff --git a/docs/google_play_services.md b/docs/google_play_services.md
index b9fa0ab7..16a4bfb 100644
--- a/docs/google_play_services.md
+++ b/docs/google_play_services.md
@@ -19,22 +19,23 @@
 containing only the APIs we currently need in Chrome, and in a single version.
 
 The up to date list of clients and version used can be seen in
-[//tools/android/roll/android_deps/build.gradle][build.gradle].
+[//third_party/android_deps/build.gradle][build.gradle].
 
 To update play services, change the gmsVersion variable in
-[//tools/android/roll/android_deps/build.gradle][build.gradle], then run
-[//tools/android/roll/android_deps/fetch_all.py][fetch_all.py].
+[//third_party/android_deps/build.gradle][build.gradle], then run
+[//third_party/android_deps/fetch_all.py][fetch_all.py].
 
 [play_store]: https://play.google.com/store/apps/details?id=com.google.android.gms
 [dev_doc]: https://developers.google.com/android/guides/overview
-[build.gradle]: ../tools/android/roll/android_deps/build.gradle
+[build.gradle]: ../third_party/android_deps/build.gradle
+[fetch_all.py]: ../third_party/android_deps/fetch_all.py
 
 ## Adding a dependency on new APIs
 
 As explained above, the default checkout has access to only a specific set of
 APIs during builds. If your CL depends on some APIs that are not included in the
 build, you will need to add an entry in
-[//tools/android/roll/android_deps/build.gradle][build.gradle].
+[//third_party/android_deps/build.gradle][build.gradle].
 
 Not doing so could make the CL fail on the trybots and commit queue. Even if it
 passes, it might fail on the internal bots and result in the CL getting
diff --git a/docs/threading_and_tasks.md b/docs/threading_and_tasks.md
index cf6335c..cd724674 100644
--- a/docs/threading_and_tasks.md
+++ b/docs/threading_and_tasks.md
@@ -921,10 +921,10 @@
 Unit tests can use [TaskEnvironment](https://cs.chromium.org/chromium/src/base/test/task_environment.h)
 which is highly configurable.
 
-## MessageLoop and CurrentThread
+## MessageLoop and MessageLoopCurrent
 
-You might come across references to MessageLoop or CurrentThread in the
+You might come across references to MessageLoop or MessageLoopCurrent in the
 code or documentation. These classes no longer exist and we are in the process
-or getting rid of all references to them. base::CurrentThread was replaced
+or getting rid of all references to them. base::MessageLoopCurrent was replaced
 by base::CurrentThread and the drop in replacements for base::MessageLoop are
 base::SingleThreadTaskExecutor and base::Test::TaskEnvironment.
diff --git a/extensions/browser/extension_util.cc b/extensions/browser/extension_util.cc
index 7faa2e4..f993a955 100644
--- a/extensions/browser/extension_util.cc
+++ b/extensions/browser/extension_util.cc
@@ -4,9 +4,11 @@
 
 #include "extensions/browser/extension_util.h"
 
+#include "base/barrier_closure.h"
 #include "base/no_destructor.h"
 #include "build/chromeos_buildflags.h"
 #include "content/public/browser/browser_context.h"
+#include "content/public/browser/cors_origin_pattern_setter.h"
 #include "content/public/browser/site_instance.h"
 #include "content/public/browser/storage_partition_config.h"
 #include "extensions/browser/extension_prefs.h"
@@ -22,6 +24,7 @@
 #include "extensions/common/manifest_handlers/incognito_info.h"
 #include "extensions/common/manifest_handlers/shared_module_info.h"
 #include "extensions/common/permissions/permissions_data.h"
+#include "mojo/public/cpp/bindings/clone_traits.h"
 
 #if BUILDFLAG(IS_CHROMEOS_ASH)
 #include "base/system/sys_info.h"
@@ -42,34 +45,30 @@
 #endif
 
 void SetCorsOriginAccessListForExtensionHelper(
-    content::BrowserContext* browser_context,
+    const std::vector<content::BrowserContext*>& browser_contexts,
     const Extension& extension,
-    base::Optional<content::BrowserContext::TargetBrowserContexts> target_mode,
     std::vector<network::mojom::CorsOriginPatternPtr> allow_patterns,
     std::vector<network::mojom::CorsOriginPatternPtr> block_patterns,
     base::OnceClosure closure) {
-  // SetCorsOriginAccessListForExtensionHelper should only affect an incognito
-  // profile if the extension is actually allowed to run in an incognito profile
-  // (not just by the extension manifest, but also by user preferences).
-  if (browser_context->IsOffTheRecord()) {
-    // TODO(lukasza): Change to util::IsIncognitoEnabled if possible.  This
-    // fails today in All/IncognitoCommandsApiTest.IncognitoMode/0 apparently
-    // because ExtensionPrefs::IsIncognitoEnabled return `false` and
-    // ExtensionPrefs::SetIsIncognitoEnabled(..., true) is never called.
-    DCHECK(IncognitoInfo::IsIncognitoAllowed(&extension));
-  }
+  auto barrier_closure =
+      BarrierClosure(browser_contexts.size(), std::move(closure));
+  for (content::BrowserContext* browser_context : browser_contexts) {
+    // SetCorsOriginAccessListForExtensionHelper should only affect an incognito
+    // profile if the extension is actually allowed to run in an incognito
+    // profile (not just by the extension manifest, but also by user
+    // preferences).
+    if (browser_context->IsOffTheRecord()) {
+      // TODO(lukasza): Change to util::IsIncognitoEnabled if possible.  This
+      // fails today in All/IncognitoCommandsApiTest.IncognitoMode/0 apparently
+      // because ExtensionPrefs::IsIncognitoEnabled return `false` and
+      // ExtensionPrefs::SetIsIncognitoEnabled(..., true) is never called.
+      DCHECK(IncognitoInfo::IsIncognitoAllowed(&extension));
+    }
 
-  if (!target_mode.has_value()) {
-    target_mode =
-        IncognitoInfo::IsSplitMode(&extension)
-            ? content::BrowserContext::TargetBrowserContexts::kSingleContext
-            : content::BrowserContext::TargetBrowserContexts::
-                  kAllRelatedContexts;
+    content::CorsOriginPatternSetter::Set(
+        browser_context, extension.origin(), mojo::Clone(allow_patterns),
+        mojo::Clone(block_patterns), barrier_closure);
   }
-
-  browser_context->SetCorsOriginAccessListForOrigin(
-      *target_mode, extension.origin(), std::move(allow_patterns),
-      std::move(block_patterns), std::move(closure));
 }
 
 }  // namespace
@@ -242,22 +241,19 @@
 }
 
 void SetCorsOriginAccessListForExtension(
-    content::BrowserContext* browser_context,
+    const std::vector<content::BrowserContext*>& browser_contexts,
     const Extension& extension,
-    base::Optional<content::BrowserContext::TargetBrowserContexts> target_mode,
     base::OnceClosure closure) {
   SetCorsOriginAccessListForExtensionHelper(
-      browser_context, extension, target_mode,
-      CreateCorsOriginAccessAllowList(extension),
+      browser_contexts, extension, CreateCorsOriginAccessAllowList(extension),
       CreateCorsOriginAccessBlockList(extension), std::move(closure));
 }
 
 void ResetCorsOriginAccessListForExtension(
     content::BrowserContext* browser_context,
-    const Extension& extension,
-    content::BrowserContext::TargetBrowserContexts target_mode) {
-  SetCorsOriginAccessListForExtensionHelper(
-      browser_context, extension, target_mode, {}, {}, base::DoNothing::Once());
+    const Extension& extension) {
+  SetCorsOriginAccessListForExtensionHelper({browser_context}, extension, {},
+                                            {}, base::DoNothing::Once());
 }
 
 }  // namespace util
diff --git a/extensions/browser/extension_util.h b/extensions/browser/extension_util.h
index 07ef11d..661d5410 100644
--- a/extensions/browser/extension_util.h
+++ b/extensions/browser/extension_util.h
@@ -6,10 +6,10 @@
 #define EXTENSIONS_BROWSER_EXTENSION_UTIL_H_
 
 #include <string>
+#include <vector>
 
 #include "base/callback.h"
 #include "base/optional.h"
-#include "content/public/browser/browser_context.h"
 #include "extensions/common/manifest.h"
 #include "url/gurl.h"
 
@@ -83,25 +83,17 @@
 int GetBrowserContextId(content::BrowserContext* context);
 
 // Calculates the allowlist and blocklist for |extension| and forwards the
-// request to |browser_context| (and possibly also for related incognito
-// contexts depending on |target_mode|).
-//
-// If the optional |target_mode| is not specified, then |target_mode| is
-// calculated based on whether |extension| operates in "split" or "spanning"
-// incognito mode.
+// request to |browser_contexts|.
 void SetCorsOriginAccessListForExtension(
-    content::BrowserContext* browser_context,
+    const std::vector<content::BrowserContext*>& browser_contexts,
     const Extension& extension,
-    base::Optional<content::BrowserContext::TargetBrowserContexts> target_mode,
     base::OnceClosure closure);
 
 // Resets the allowlist and blocklist for |extension| to empty lists for
-// |browser_context| (and possibly also for related incognito contexts depending
-// on |target_mode|).
+// |browser_context| and for all related regular+incognito contexts.
 void ResetCorsOriginAccessListForExtension(
     content::BrowserContext* browser_context,
-    const Extension& extension,
-    content::BrowserContext::TargetBrowserContexts target_mode);
+    const Extension& extension);
 
 }  // namespace util
 }  // namespace extensions
diff --git a/extensions/browser/extensions_test.cc b/extensions/browser/extensions_test.cc
index f01cf75..4b969e81 100644
--- a/extensions/browser/extensions_test.cc
+++ b/extensions/browser/extensions_test.cc
@@ -16,7 +16,6 @@
 #include "extensions/browser/extension_prefs_factory.h"
 #include "extensions/browser/test_extensions_browser_client.h"
 #include "extensions/test/test_content_utility_client.h"
-#include "services/network/public/mojom/cors_origin_pattern.mojom.h"
 
 namespace {
 
@@ -27,21 +26,6 @@
   return incognito_context;
 }
 
-class ExtensionTestBrowserContext : public content::TestBrowserContext {
- private:
-  void SetCorsOriginAccessListForOrigin(
-      TargetBrowserContexts target_mode,
-      const url::Origin& source_origin,
-      std::vector<network::mojom::CorsOriginPatternPtr> allow_patterns,
-      std::vector<network::mojom::CorsOriginPatternPtr> block_patterns,
-      base::OnceClosure closure) override {
-    // This method is called for setting up Extensions, but can be ignored
-    // unless actual network requests need to be handled.
-    base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE,
-                                                  std::move(closure));
-  }
-};
-
 }  // namespace
 
 namespace extensions {
@@ -70,7 +54,7 @@
 void ExtensionsTest::SetUp() {
   content::ForceInProcessNetworkService(true);
   content_utility_client_ = std::make_unique<TestContentUtilityClient>();
-  browser_context_ = std::make_unique<ExtensionTestBrowserContext>();
+  browser_context_ = std::make_unique<content::TestBrowserContext>();
   incognito_context_ = CreateTestIncognitoContext();
 
   if (!extensions_browser_client_) {
diff --git a/extensions/browser/renderer_startup_helper.cc b/extensions/browser/renderer_startup_helper.cc
index d788bd26..c2d925ec 100644
--- a/extensions/browser/renderer_startup_helper.cc
+++ b/extensions/browser/renderer_startup_helper.cc
@@ -132,7 +132,7 @@
   // Scripting allowlist. This is modified by tests and must be communicated
   // to renderers.
   renderer->SetScriptingAllowlist(
-      extensions::ExtensionsClient::Get()->GetScriptingAllowlist());
+      ExtensionsClient::Get()->GetScriptingAllowlist());
 
   // If the new render process is a WebView guest process, propagate the WebView
   // partition ID to it.
@@ -248,10 +248,8 @@
 
   // Registers the initial origin access lists to the BrowserContext
   // (and all related incognito contexts) asynchronously.
-  util::SetCorsOriginAccessListForExtension(
-      browser_context_, extension,
-      content::BrowserContext::TargetBrowserContexts::kSingleContext,
-      base::DoNothing::Once());
+  util::SetCorsOriginAccessListForExtension({browser_context_}, extension,
+                                            base::DoNothing::Once());
 
   // We don't need to include tab permisisons here, since the extension
   // was just loaded.
@@ -286,10 +284,7 @@
   }
 
   // Resets registered origin access lists in the BrowserContext asynchronously.
-  util::ResetCorsOriginAccessListForExtension(
-      browser_context_, extension,
-
-      content::BrowserContext::TargetBrowserContexts::kSingleContext);
+  util::ResetCorsOriginAccessListForExtension(browser_context_, extension);
 
   for (auto& process_extensions_pair : pending_active_extensions_)
     process_extensions_pair.second.erase(extension.id());
diff --git a/extensions/renderer/extension_frame_helper.cc b/extensions/renderer/extension_frame_helper.cc
index 64c9e170..7ff52b4 100644
--- a/extensions/renderer/extension_frame_helper.cc
+++ b/extensions/renderer/extension_frame_helper.cc
@@ -250,7 +250,7 @@
 
 void ExtensionFrameHelper::BindLocalFrame(
     mojo::PendingAssociatedReceiver<mojom::LocalFrame> pending_receiver) {
-  local_frame_receivers_.Add(this, std::move(pending_receiver));
+  local_frame_receiver_.Bind(std::move(pending_receiver));
 }
 
 void ExtensionFrameHelper::DidCreateDocumentElement() {
diff --git a/extensions/renderer/extension_frame_helper.h b/extensions/renderer/extension_frame_helper.h
index e7bd5bb..326e137 100644
--- a/extensions/renderer/extension_frame_helper.h
+++ b/extensions/renderer/extension_frame_helper.h
@@ -15,7 +15,7 @@
 #include "content/public/renderer/render_frame_observer_tracker.h"
 #include "extensions/common/mojom/frame.mojom.h"
 #include "extensions/common/mojom/view_type.mojom.h"
-#include "mojo/public/cpp/bindings/associated_receiver_set.h"
+#include "mojo/public/cpp/bindings/associated_receiver.h"
 #include "mojo/public/cpp/bindings/pending_associated_receiver.h"
 #include "third_party/blink/public/mojom/devtools/console_message.mojom.h"
 #include "v8/include/v8.h"
@@ -207,7 +207,7 @@
   // navigation happens, it is either the initial one or a reload.
   bool has_started_first_navigation_ = false;
 
-  mojo::AssociatedReceiverSet<mojom::LocalFrame> local_frame_receivers_;
+  mojo::AssociatedReceiver<mojom::LocalFrame> local_frame_receiver_{this};
 
   base::WeakPtrFactory<ExtensionFrameHelper> weak_ptr_factory_{this};
 
diff --git a/extensions/shell/browser/shell_browser_context.cc b/extensions/shell/browser/shell_browser_context.cc
index 98d02e6f..665bd9b 100644
--- a/extensions/shell/browser/shell_browser_context.cc
+++ b/extensions/shell/browser/shell_browser_context.cc
@@ -10,7 +10,6 @@
 #include "base/task/post_task.h"
 #include "components/guest_view/browser/guest_view_manager.h"
 #include "extensions/shell/browser/shell_special_storage_policy.h"
-#include "services/network/public/mojom/cors_origin_pattern.mojom.h"
 
 namespace extensions {
 
@@ -33,15 +32,4 @@
   return storage_policy_.get();
 }
 
-void ShellBrowserContext::SetCorsOriginAccessListForOrigin(
-    TargetBrowserContexts target_mode,
-    const url::Origin& source_origin,
-    std::vector<network::mojom::CorsOriginPatternPtr> allow_patterns,
-    std::vector<network::mojom::CorsOriginPatternPtr> block_patterns,
-    base::OnceClosure closure) {
-  // This method is called for Extension supports, but tests do not need to
-  // support exceptional CORS handling.
-  base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, std::move(closure));
-}
-
 }  // namespace extensions
diff --git a/extensions/shell/browser/shell_browser_context.h b/extensions/shell/browser/shell_browser_context.h
index 0e5c943..f75cf8c4 100644
--- a/extensions/shell/browser/shell_browser_context.h
+++ b/extensions/shell/browser/shell_browser_context.h
@@ -22,12 +22,6 @@
   // content::BrowserContext implementation.
   content::BrowserPluginGuestManager* GetGuestManager() override;
   storage::SpecialStoragePolicy* GetSpecialStoragePolicy() override;
-  void SetCorsOriginAccessListForOrigin(
-      TargetBrowserContexts target_mode,
-      const url::Origin& source_origin,
-      std::vector<network::mojom::CorsOriginPatternPtr> allow_patterns,
-      std::vector<network::mojom::CorsOriginPatternPtr> block_patterns,
-      base::OnceClosure closure) override;
 
  private:
   scoped_refptr<storage::SpecialStoragePolicy> storage_policy_;
diff --git a/google_apis/drive/base_requests.cc b/google_apis/drive/base_requests.cc
index 13f6382..5a5d328 100644
--- a/google_apis/drive/base_requests.cc
+++ b/google_apis/drive/base_requests.cc
@@ -446,7 +446,8 @@
                                          base::OnceClosure resume) {
   if (!download_data_->get_content_callback.is_null()) {
     download_data_->get_content_callback.Run(
-        HTTP_SUCCESS, std::make_unique<std::string>(string_piece));
+        HTTP_SUCCESS, std::make_unique<std::string>(string_piece),
+        download_data_->response_body.empty());
   }
 
   if (!download_data_->output_file_path.empty()) {
diff --git a/google_apis/drive/base_requests.h b/google_apis/drive/base_requests.h
index 3b815e5..491a34e 100644
--- a/google_apis/drive/base_requests.h
+++ b/google_apis/drive/base_requests.h
@@ -57,12 +57,16 @@
     FileResourceCallback;
 
 // Callback used for DownloadFileRequest and ResumeUploadRequestBase.
+// |first_chunk| indicates if |content| is from the very beginning of
+// the file being downloaded and helps consumers detect if download
+// was restarted, for example due to re-authentication.
 typedef base::RepeatingCallback<void(int64_t progress, int64_t total)>
     ProgressCallback;
 
 // Callback used to get the content from DownloadFileRequest.
 typedef base::RepeatingCallback<void(DriveApiErrorCode error,
-                                     std::unique_ptr<std::string> content)>
+                                     std::unique_ptr<std::string> content,
+                                     bool first_chunk)>
     GetContentCallback;
 
 // Parses JSON passed in |json|. Returns NULL on failure.
diff --git a/google_apis/drive/drive_api_requests_unittest.cc b/google_apis/drive/drive_api_requests_unittest.cc
index 093f09f..75295681 100644
--- a/google_apis/drive/drive_api_requests_unittest.cc
+++ b/google_apis/drive/drive_api_requests_unittest.cc
@@ -69,7 +69,8 @@
 // Used as a GetContentCallback.
 void AppendContent(std::string* out,
                    DriveApiErrorCode error,
-                   std::unique_ptr<std::string> content) {
+                   std::unique_ptr<std::string> content,
+                   bool first_chunk) {
   EXPECT_EQ(HTTP_SUCCESS, error);
   out->append(*content);
 }
diff --git a/google_apis/drive/test_util.cc b/google_apis/drive/test_util.cc
index 566c44e..e319e2b 100644
--- a/google_apis/drive/test_util.cc
+++ b/google_apis/drive/test_util.cc
@@ -172,7 +172,8 @@
 }
 
 void TestGetContentCallback::OnGetContent(google_apis::DriveApiErrorCode error,
-                                          std::unique_ptr<std::string> data) {
+                                          std::unique_ptr<std::string> data,
+                                          bool first_chunk) {
   data_.push_back(std::move(data));
 }
 
diff --git a/google_apis/drive/test_util.h b/google_apis/drive/test_util.h
index ee767ce6..73878681 100644
--- a/google_apis/drive/test_util.h
+++ b/google_apis/drive/test_util.h
@@ -294,7 +294,8 @@
 
  private:
   void OnGetContent(google_apis::DriveApiErrorCode error,
-                    std::unique_ptr<std::string> data);
+                    std::unique_ptr<std::string> data,
+                    bool first_chunk);
 
   const GetContentCallback callback_;
   std::vector<std::unique_ptr<std::string>> data_;
diff --git a/ios/chrome/app/strings/ios_strings.grd b/ios/chrome/app/strings/ios_strings.grd
index bc23930..f241c7e 100644
--- a/ios/chrome/app/strings/ios_strings.grd
+++ b/ios/chrome/app/strings/ios_strings.grd
@@ -1129,9 +1129,6 @@
       <message name="IDS_IOS_MANUAL_FALLBACK_USE_OTHER_PASSWORD" desc="The title for the manual fallback UI with all passwords without filter." meaning="The title for a list where the user is about to select a password or username to be filled in a form [Length: 10em]">
         Passwords
       </message>
-      <message name="IDS_IOS_MANUAL_FALLBACK_SUGGEST_PASSWORD_WITH_DOTS" desc="The title for the button in the manual fallback passwords UI that is used to trigger password generation on the active field. [30em]">
-        Suggest password...
-      </message>
       <message name="IDS_IOS_MANUAL_FALLBACK_USE_OTHER_PASSWORD_WITH_DOTS" desc="The title for the button in the manual fallback passwords UI that is used to open a list of all the user credentials where they can select one to fill a form. This button is showed at the same time as a different button with  IDS_IOS_MANUAL_FALLBACK_MANAGE_PASSWORDS as title. [30em]">
         Use Other Password...
       </message>
diff --git a/ios/chrome/app/strings/ios_strings_grd/IDS_IOS_MANUAL_FALLBACK_SUGGEST_PASSWORD_WITH_DOTS.png.sha1 b/ios/chrome/app/strings/ios_strings_grd/IDS_IOS_MANUAL_FALLBACK_SUGGEST_PASSWORD_WITH_DOTS.png.sha1
deleted file mode 100644
index 2dc074f..0000000
--- a/ios/chrome/app/strings/ios_strings_grd/IDS_IOS_MANUAL_FALLBACK_SUGGEST_PASSWORD_WITH_DOTS.png.sha1
+++ /dev/null
Binary files differ
diff --git a/ios/chrome/browser/autofill/form_structure_browsertest.mm b/ios/chrome/browser/autofill/form_structure_browsertest.mm
index a00f31ca..f558df0 100644
--- a/ios/chrome/browser/autofill/form_structure_browsertest.mm
+++ b/ios/chrome/browser/autofill/form_structure_browsertest.mm
@@ -148,7 +148,7 @@
        // TODO(crbug.com/1150895) Remove once launched.
        autofill::features::kAutofillParsingPatternsLanguageDetection},
       // Disabled
-      {autofill::features::kAutofillRestrictUnownedFieldsToFormlessCheckout});
+      {});
 }
 
 void FormStructureBrowserTest::SetUp() {
diff --git a/ios/chrome/browser/autofill/js_autofill_manager_unittest.mm b/ios/chrome/browser/autofill/js_autofill_manager_unittest.mm
index 4e519ff..06707a4 100644
--- a/ios/chrome/browser/autofill/js_autofill_manager_unittest.mm
+++ b/ios/chrome/browser/autofill/js_autofill_manager_unittest.mm
@@ -299,47 +299,10 @@
 
 // Tests forms extraction method
 // (fetchFormsWithRequirements:minimumRequiredFieldsCount:completionHandler:)
-// when formless forms are restricted to checkout flows. No form is expected to
-// be extracted here.
-TEST_F(JsAutofillManagerTest, ExtractFormlessForms_RestrictToFormlessCheckout) {
-  // Restrict formless forms to checkout flows.
-  base::test::ScopedFeatureList feature_list;
-  feature_list.InitAndEnableFeature(
-      autofill::features::kAutofillRestrictUnownedFieldsToFormlessCheckout);
-
-  LoadHtml(kUnownedUntitledFormHtml);
-
-  __block BOOL block_was_called = NO;
-  __block NSString* result;
-  [manager_ fetchFormsWithMinimumRequiredFieldsCount:
-                autofill::kMinRequiredFieldsForHeuristics
-                                             inFrame:main_web_frame()
-                                   completionHandler:^(NSString* actualResult) {
-                                     block_was_called = YES;
-                                     result = [actualResult copy];
-                                   }];
-  base::test::ios::WaitUntilCondition(^bool() {
-    return block_was_called;
-  });
-
-  // Verify that the form is empty.
-  NSArray* resultArray = [NSJSONSerialization
-      JSONObjectWithData:[result dataUsingEncoding:NSUTF8StringEncoding]
-                 options:0
-                   error:nil];
-  EXPECT_NSNE(nil, resultArray);
-  EXPECT_EQ(0u, resultArray.count);
-}
-
-// Tests forms extraction method
-// (fetchFormsWithRequirements:minimumRequiredFieldsCount:completionHandler:)
 // when all formless forms are extracted. A formless form is expected to be
 // extracted here.
 TEST_F(JsAutofillManagerTest, ExtractFormlessForms_AllFormlessForms) {
   // Allow all formless forms to be extracted.
-  base::test::ScopedFeatureList feature_list;
-  feature_list.InitAndDisableFeature(
-      autofill::features::kAutofillRestrictUnownedFieldsToFormlessCheckout);
 
   LoadHtml(kUnownedUntitledFormHtml);
 
@@ -437,11 +400,6 @@
 
 // Tests the generation of the name of the fields.
 TEST_F(JsAutofillManagerTest, TestExtractedFieldsIDs) {
-  // Allow all formless forms to be extracted.
-  base::test::ScopedFeatureList feature_list;
-  feature_list.InitAndDisableFeature(
-      autofill::features::kAutofillRestrictUnownedFieldsToFormlessCheckout);
-
   NSString* HTML =
       @"<html><body><form name='testform' method='post'>"
        // Field with name and id
diff --git a/ios/chrome/browser/flags/about_flags.mm b/ios/chrome/browser/flags/about_flags.mm
index d6a0e14..37c7b636 100644
--- a/ios/chrome/browser/flags/about_flags.mm
+++ b/ios/chrome/browser/flags/about_flags.mm
@@ -357,13 +357,6 @@
      flag_descriptions::kAutofillIOSDelayBetweenFieldsName,
      flag_descriptions::kAutofillIOSDelayBetweenFieldsDescription,
      flags_ui::kOsIos, MULTI_VALUE_TYPE(kAutofillIOSDelayBetweenFieldsChoices)},
-    {"autofill-restrict-formless-form-extraction",
-     flag_descriptions::kAutofillRestrictUnownedFieldsToFormlessCheckoutName,
-     flag_descriptions::
-         kAutofillRestrictUnownedFieldsToFormlessCheckoutDescription,
-     flags_ui::kOsIos,
-     FEATURE_VALUE_TYPE(
-         autofill::features::kAutofillRestrictUnownedFieldsToFormlessCheckout)},
     {"autofill-rich-metadata-queries",
      flag_descriptions::kAutofillRichMetadataQueriesName,
      flag_descriptions::kAutofillRichMetadataQueriesDescription,
@@ -687,6 +680,11 @@
      flag_descriptions::kInterestFeedNoticeCardAutoDismissDescription,
      flags_ui::kOsIos,
      FEATURE_VALUE_TYPE(feed::kInterestFeedNoticeCardAutoDismiss)},
+    {"autofill-address-save-prompt",
+     flag_descriptions::kEnableAutofillAddressSavePromptName,
+     flag_descriptions::kEnableAutofillAddressSavePromptDescription,
+     flags_ui::kOsIos,
+     FEATURE_VALUE_TYPE(autofill::features::kAutofillAddressProfileSavePrompt)},
 };
 
 bool SkipConditionalFeatureEntry(const flags_ui::FeatureEntry& entry) {
diff --git a/ios/chrome/browser/flags/ios_chrome_flag_descriptions.cc b/ios/chrome/browser/flags/ios_chrome_flag_descriptions.cc
index 57fee12..232c935 100644
--- a/ios/chrome/browser/flags/ios_chrome_flag_descriptions.cc
+++ b/ios/chrome/browser/flags/ios_chrome_flag_descriptions.cc
@@ -50,11 +50,6 @@
     "When enabled and saving a credit card to Google Payments, a dialog is "
     "displayed that allows editing the card info before confirming save.";
 
-const char kAutofillRestrictUnownedFieldsToFormlessCheckoutName[] =
-    "Restrict formless form extraction";
-const char kAutofillRestrictUnownedFieldsToFormlessCheckoutDescription[] =
-    "Restrict extraction of formless forms to checkout flows";
-
 const char kAutofillRichMetadataQueriesName[] =
     "Autofill - Rich metadata queries (Canary/Dev only)";
 const char kAutofillRichMetadataQueriesDescription[] =
@@ -171,6 +166,11 @@
 const char kEmbedderBlockRestoreUrlDescription[] =
     "Embedders can prevent URLs from restoring.";
 
+const char kEnableAutofillAddressSavePromptName[] =
+    "Autofill Address Save Prompts";
+const char kEnableAutofillAddressSavePromptDescription[] =
+    "Enable the Autofill address save prompts.";
+
 const char kEnableCloseAllTabsConfirmationName[] =
     "Enable Close All Tabs confirmation";
 const char kEnableCloseAllTabsConfirmationDescription[] =
diff --git a/ios/chrome/browser/flags/ios_chrome_flag_descriptions.h b/ios/chrome/browser/flags/ios_chrome_flag_descriptions.h
index e4df4d5..3733f3f 100644
--- a/ios/chrome/browser/flags/ios_chrome_flag_descriptions.h
+++ b/ios/chrome/browser/flags/ios_chrome_flag_descriptions.h
@@ -42,11 +42,6 @@
 extern const char kAutofillSaveCardInfobarEditSupportName[];
 extern const char kAutofillSaveCardInfobarEditSupportDescription[];
 
-// Title and description for the flag to restrict extraction of formless forms
-// to checkout flows.
-extern const char kAutofillRestrictUnownedFieldsToFormlessCheckoutName[];
-extern const char kAutofillRestrictUnownedFieldsToFormlessCheckoutDescription[];
-
 // Title and description for the flag to enable rich autofill queries on
 // Canary/Dev.
 extern const char kAutofillRichMetadataQueriesName[];
@@ -154,6 +149,10 @@
 extern const char kEmbedderBlockRestoreUrlName[];
 extern const char kEmbedderBlockRestoreUrlDescription[];
 
+// Title and description for the flag to enable autofill address save prompts.
+extern const char kEnableAutofillAddressSavePromptName[];
+extern const char kEnableAutofillAddressSavePromptDescription[];
+
 // Title and description for the flag to enable the confirmational action sheet
 // for the tab grid "Close All" action.
 extern const char kEnableCloseAllTabsConfirmationName[];
diff --git a/ios/chrome/browser/passwords/password_controller.h b/ios/chrome/browser/passwords/password_controller.h
index f954edb..110fbcf 100644
--- a/ios/chrome/browser/passwords/password_controller.h
+++ b/ios/chrome/browser/passwords/password_controller.h
@@ -11,7 +11,6 @@
 
 #import "components/autofill/ios/browser/form_suggestion_provider.h"
 #import "components/password_manager/ios/password_form_helper.h"
-#import "components/password_manager/ios/password_generation_provider.h"
 #import "components/password_manager/ios/password_manager_client_bridge.h"
 #import "components/password_manager/ios/password_manager_driver_bridge.h"
 #import "ios/chrome/browser/passwords/ios_chrome_password_manager_client.h"
@@ -50,10 +49,6 @@
 // An object that can provide suggestions from this PasswordController.
 @property(nonatomic, readonly) id<FormSuggestionProvider> suggestionProvider;
 
-// An object that can provide password generation from this PasswordController.
-@property(nonatomic, readonly) id<PasswordGenerationProvider>
-    generationProvider;
-
 // The PasswordManagerClient owned by this PasswordController.
 @property(nonatomic, readonly)
     password_manager::PasswordManagerClient* passwordManagerClient;
diff --git a/ios/chrome/browser/passwords/password_controller.mm b/ios/chrome/browser/passwords/password_controller.mm
index f66fce0..fe0ca7d 100644
--- a/ios/chrome/browser/passwords/password_controller.mm
+++ b/ios/chrome/browser/passwords/password_controller.mm
@@ -256,12 +256,6 @@
   return _sharedPasswordController;
 }
 
-#pragma mark - PasswordGenerationProvider
-
-- (id<PasswordGenerationProvider>)generationProvider {
-  return _sharedPasswordController;
-}
-
 #pragma mark - IOSChromePasswordManagerClientBridge
 
 - (WebState*)webState {
diff --git a/ios/chrome/browser/passwords/password_tab_helper.h b/ios/chrome/browser/passwords/password_tab_helper.h
index 8fd7d74..5df5d34 100644
--- a/ios/chrome/browser/passwords/password_tab_helper.h
+++ b/ios/chrome/browser/passwords/password_tab_helper.h
@@ -13,7 +13,6 @@
 @protocol FormSuggestionProvider;
 @class PasswordController;
 @protocol PasswordControllerDelegate;
-@protocol PasswordGenerationProvider;
 @protocol PasswordsUiDelegate;
 @class UIViewController;
 
@@ -50,10 +49,6 @@
   // Returns the PasswordManager owned by the PasswordController.
   password_manager::PasswordManager* GetPasswordManager();
 
-  // Returns an object that can provide password generation from the
-  // PasswordController. May return nil.
-  id<PasswordGenerationProvider> GetPasswordGenerationProvider();
-
  private:
   friend class web::WebStateUserData<PasswordTabHelper>;
 
diff --git a/ios/chrome/browser/passwords/password_tab_helper.mm b/ios/chrome/browser/passwords/password_tab_helper.mm
index 78a7c6ec..a923fb3 100644
--- a/ios/chrome/browser/passwords/password_tab_helper.mm
+++ b/ios/chrome/browser/passwords/password_tab_helper.mm
@@ -51,11 +51,6 @@
   return controller_.passwordManager;
 }
 
-id<PasswordGenerationProvider>
-PasswordTabHelper::GetPasswordGenerationProvider() {
-  return controller_.generationProvider;
-}
-
 PasswordTabHelper::PasswordTabHelper(web::WebState* web_state)
     : controller_([[PasswordController alloc] initWithWebState:web_state]) {
   web_state->AddObserver(this);
diff --git a/ios/chrome/browser/ui/authentication/signin/BUILD.gn b/ios/chrome/browser/ui/authentication/signin/BUILD.gn
index 45ce1333..419595a 100644
--- a/ios/chrome/browser/ui/authentication/signin/BUILD.gn
+++ b/ios/chrome/browser/ui/authentication/signin/BUILD.gn
@@ -109,6 +109,7 @@
   deps = [
     "//base",
     "//base/test:test_support",
+    "//components/signin/ios/browser:features",
     "//components/signin/public/base",
     "//ios/chrome/app/strings",
     "//ios/chrome/browser/ui/authentication:eg_test_support+eg2",
diff --git a/ios/chrome/browser/ui/authentication/signin/consistency_promo_signin/bottom_sheet/BUILD.gn b/ios/chrome/browser/ui/authentication/signin/consistency_promo_signin/bottom_sheet/BUILD.gn
index 0afb72b..c59de9f 100644
--- a/ios/chrome/browser/ui/authentication/signin/consistency_promo_signin/bottom_sheet/BUILD.gn
+++ b/ios/chrome/browser/ui/authentication/signin/consistency_promo_signin/bottom_sheet/BUILD.gn
@@ -13,6 +13,7 @@
     "bottom_sheet_presentation_controller.mm",
     "bottom_sheet_slide_transition_animator.h",
     "bottom_sheet_slide_transition_animator.mm",
+    "child_bottom_sheet_view_controller.h",
   ]
   deps = [
     "//ios/chrome/browser/browser_state",
diff --git a/ios/chrome/browser/ui/authentication/signin/consistency_promo_signin/bottom_sheet/bottom_sheet_navigation_controller.h b/ios/chrome/browser/ui/authentication/signin/consistency_promo_signin/bottom_sheet/bottom_sheet_navigation_controller.h
index be22714..a24a68a 100644
--- a/ios/chrome/browser/ui/authentication/signin/consistency_promo_signin/bottom_sheet/bottom_sheet_navigation_controller.h
+++ b/ios/chrome/browser/ui/authentication/signin/consistency_promo_signin/bottom_sheet/bottom_sheet_navigation_controller.h
@@ -17,12 +17,6 @@
 - (void)bottomSheetNavigationControllerDidDisappear:
     (BottomSheetNavigationController*)viewController;
 
-// Returns the desired height for |viewController| to fit. The height needs to
-// include safe area insets.
-- (CGFloat)layoutFittingHeightForViewController:
-               (UIViewController*)viewController
-                                          width:(CGFloat)width;
-
 @end
 
 // Navigation controller presented from the bottom. The pushed view controllers
@@ -31,6 +25,8 @@
 // The view is automatically sized according to the last child view controller.
 // This class works with BottomSheetPresentationController and
 // BottomSheetSlideTransitionAnimator.
+// Child view controller are required to implement
+// ChildBottomSheetViewController protocol.
 @interface BottomSheetNavigationController : UINavigationController
 
 // Presentation delegate.
diff --git a/ios/chrome/browser/ui/authentication/signin/consistency_promo_signin/bottom_sheet/bottom_sheet_navigation_controller.mm b/ios/chrome/browser/ui/authentication/signin/consistency_promo_signin/bottom_sheet/bottom_sheet_navigation_controller.mm
index 22a0c8f..da41196 100644
--- a/ios/chrome/browser/ui/authentication/signin/consistency_promo_signin/bottom_sheet/bottom_sheet_navigation_controller.mm
+++ b/ios/chrome/browser/ui/authentication/signin/consistency_promo_signin/bottom_sheet/bottom_sheet_navigation_controller.mm
@@ -7,6 +7,7 @@
 #import <algorithm>
 
 #import "base/check.h"
+#import "ios/chrome/browser/ui/authentication/signin/consistency_promo_signin/bottom_sheet/child_bottom_sheet_view_controller.h"
 #import "ios/chrome/common/ui/colors/semantic_color_names.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
@@ -37,14 +38,22 @@
                   animated:(BOOL)animated {
   // |viewController.view| has to be a UIScrollView.
   DCHECK([viewController.view isKindOfClass:[UIScrollView class]]);
+  DCHECK([viewController
+      conformsToProtocol:@protocol(ChildBottomSheetViewController)]);
   [super pushViewController:viewController animated:animated];
 }
 
 - (CGSize)layoutFittingSize {
   CGFloat width = self.view.frame.size.width;
-  CGFloat height = [self.presentationDelegate
-      layoutFittingHeightForViewController:self.childViewControllers.lastObject
-                                     width:width];
+  UINavigationController* navigationController =
+      self.childViewControllers.lastObject;
+  DCHECK([navigationController
+      conformsToProtocol:@protocol(ChildBottomSheetViewController)]);
+  UIViewController<ChildBottomSheetViewController>* childNavigationController =
+      static_cast<UIViewController<ChildBottomSheetViewController>*>(
+          navigationController);
+  CGFloat height =
+      [childNavigationController layoutFittingHeightForWidth:width];
   CGFloat maxViewHeight =
       self.view.window.frame.size.height * kMaxBottomSheetHeightRatioWithWindow;
   return CGSizeMake(width, std::min(height, maxViewHeight));
diff --git a/ios/chrome/browser/ui/authentication/signin/consistency_promo_signin/bottom_sheet/child_bottom_sheet_view_controller.h b/ios/chrome/browser/ui/authentication/signin/consistency_promo_signin/bottom_sheet/child_bottom_sheet_view_controller.h
new file mode 100644
index 0000000..3f41c86
--- /dev/null
+++ b/ios/chrome/browser/ui/authentication/signin/consistency_promo_signin/bottom_sheet/child_bottom_sheet_view_controller.h
@@ -0,0 +1,20 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef IOS_CHROME_BROWSER_UI_AUTHENTICATION_SIGNIN_CONSISTENCY_PROMO_SIGNIN_BOTTOM_SHEET_CHILD_BOTTOM_SHEET_VIEW_CONTROLLER_H_
+#define IOS_CHROME_BROWSER_UI_AUTHENTICATION_SIGNIN_CONSISTENCY_PROMO_SIGNIN_BOTTOM_SHEET_CHILD_BOTTOM_SHEET_VIEW_CONTROLLER_H_
+
+#import <UIKit/UIKit.h>
+
+// Protocol to implement for view controller pushed to
+// BottomSheetNavigationController.
+@protocol ChildBottomSheetViewController <NSObject>
+
+// Returns the desired height for |viewController| to fit. The height needs to
+// include safe area insets.
+- (CGFloat)layoutFittingHeightForWidth:(CGFloat)width;
+
+@end
+
+#endif  // IOS_CHROME_BROWSER_UI_AUTHENTICATION_SIGNIN_CONSISTENCY_PROMO_SIGNIN_BOTTOM_SHEET_CHILD_BOTTOM_SHEET_VIEW_CONTROLLER_H_
diff --git a/ios/chrome/browser/ui/authentication/signin/consistency_promo_signin/consistency_promo_signin_coordinator.mm b/ios/chrome/browser/ui/authentication/signin/consistency_promo_signin/consistency_promo_signin_coordinator.mm
index eccb973c..1a1b4ae 100644
--- a/ios/chrome/browser/ui/authentication/signin/consistency_promo_signin/consistency_promo_signin_coordinator.mm
+++ b/ios/chrome/browser/ui/authentication/signin/consistency_promo_signin/consistency_promo_signin_coordinator.mm
@@ -117,14 +117,6 @@
                    showAdvancedSettingsSignin:NO];
 }
 
-- (CGFloat)layoutFittingHeightForViewController:
-               (UIViewController*)viewController
-                                          width:(CGFloat)width {
-  // Needs implementation.
-  NOTIMPLEMENTED();
-  return 0;
-}
-
 #pragma mark - UIViewControllerAnimatedTransitioning
 
 - (id<UIViewControllerAnimatedTransitioning>)
diff --git a/ios/chrome/browser/ui/authentication/signin/signin_coordinator_egtest.mm b/ios/chrome/browser/ui/authentication/signin/signin_coordinator_egtest.mm
index 8408141..464215d 100644
--- a/ios/chrome/browser/ui/authentication/signin/signin_coordinator_egtest.mm
+++ b/ios/chrome/browser/ui/authentication/signin/signin_coordinator_egtest.mm
@@ -6,6 +6,7 @@
 #include "base/ios/ios_util.h"
 #include "base/strings/sys_string_conversions.h"
 #import "base/test/ios/wait_util.h"
+#import "components/signin/ios/browser/features.h"
 #include "components/signin/public/base/signin_pref_names.h"
 #import "ios/chrome/browser/ui/authentication/signin_earl_grey.h"
 #import "ios/chrome/browser/ui/authentication/signin_earl_grey_ui.h"
@@ -104,6 +105,7 @@
 - (AppLaunchConfiguration)appConfigurationForTestCase {
   AppLaunchConfiguration config;
   config.features_disabled.push_back(kDiscoverFeedInNtp);
+  config.features_enabled.push_back(signin::kSimplifySignOutIOS);
   return config;
 }
 
diff --git a/ios/chrome/browser/ui/authentication/signin_earl_grey_ui.h b/ios/chrome/browser/ui/authentication/signin_earl_grey_ui.h
index 54c67e9..4555e43 100644
--- a/ios/chrome/browser/ui/authentication/signin_earl_grey_ui.h
+++ b/ios/chrome/browser/ui/authentication/signin_earl_grey_ui.h
@@ -30,15 +30,26 @@
 + (void)signinWithFakeIdentity:(FakeChromeIdentity*)fakeIdentity
                     enableSync:(BOOL)enableSync;
 
-// DEPRECATED.
+// Signs the primary account out of Chrome through the accounts list screen.
+// Taps the "Sign Out" button to begin flow. Note that managed accounts cannot
+// go through this flow. There will be a GREYAssert if the tools menus is open
+// when calling this method or if the account is not successfully signed out.
+// This method should be used until SimplifySignOutIOS is turned on. Otherwise,
+// |signOutWithConfirmationChoice:| should be used.
 + (void)signOut;
 
-// DEPRECATED.
+// Signs the primary account out of Chrome through the accounts list screen.
+// Taps the "Sign out and clear data from this device" button to begin flow.
+// There will be a GREYAssert if the tools menus is open when calling this
+// method or if the account is not successfully signed out.
+// This method should be used until SimplifySignOutIOS is turned on. Otherwise,
+// |signOutWithConfirmationChoice:| should be used.
 + (void)signOutAndClearDataFromDevice;
 
 // Signs the primary account out of Chrome through the accounts list screen.
 // Taps the "Sign Out" button, and then validated the confirmation dialog
 // according to |confirmation|.
+// This method should be used only if SimplifySignOutIOS is turned on.
 + (void)signOutWithConfirmationChoice:(SignOutConfirmationChoice)confirmation;
 
 // Selects an identity when the identity chooser dialog is presented. The dialog
diff --git a/ios/chrome/browser/ui/authentication/signin_earl_grey_ui.mm b/ios/chrome/browser/ui/authentication/signin_earl_grey_ui.mm
index 82c3675..cb5baa1 100644
--- a/ios/chrome/browser/ui/authentication/signin_earl_grey_ui.mm
+++ b/ios/chrome/browser/ui/authentication/signin_earl_grey_ui.mm
@@ -85,11 +85,19 @@
 }
 
 + (void)signOut {
-  [self signOutWithConfirmationChoice:SignOutConfirmationChoiceKeepData];
+  NSString* primaryAccountEmail =
+      [SigninEarlGreyAppInterface primaryAccountEmail];
+  GREYAssert(![primaryAccountEmail hasSuffix:ios::kManagedIdentityEmailSuffix],
+             @"Managed account must clear data on signout");
+  [self signOutWithButton:SignOutAccountsButton()
+      confirmationLabelID:IDS_IOS_DISCONNECT_DIALOG_CONTINUE_BUTTON_MOBILE];
 }
 
 + (void)signOutAndClearDataFromDevice {
-  [self signOutWithConfirmationChoice:SignOutConfirmationChoiceClearData];
+  [self signOutWithButton:
+            grey_accessibilityID(
+                kSettingsAccountsTableViewSignoutAndClearDataCellId)
+      confirmationLabelID:IDS_IOS_DISCONNECT_DIALOG_CONTINUE_AND_CLEAR_MOBILE];
 }
 
 + (void)signOutWithConfirmationChoice:(SignOutConfirmationChoice)confirmation {
@@ -105,21 +113,8 @@
       confirmationLabelID = IDS_IOS_SIGNOUT_DIALOG_SIGN_OUT_BUTTON;
       break;
   }
-  id<GREYMatcher> buttonMatcher = SignOutAccountsButton();
-  [ChromeEarlGreyUI openSettingsMenu];
-  [ChromeEarlGreyUI tapSettingsMenuButton:SettingsAccountButton()];
-
-  [ChromeEarlGreyUI tapAccountsMenuButton:buttonMatcher];
-  id<GREYMatcher> confirmationButtonMatcher = [ChromeMatchersAppInterface
-      buttonWithAccessibilityLabelID:confirmationLabelID];
-  [[EarlGrey selectElementWithMatcher:grey_allOf(confirmationButtonMatcher,
-                                                 grey_not(buttonMatcher), nil)]
-      performAction:grey_tap()];
-  // Wait until the user is signed out.
-  [ChromeEarlGreyUI waitForAppToIdle];
-  [[EarlGrey selectElementWithMatcher:SettingsDoneButton()]
-      performAction:grey_tap()];
-  [SigninEarlGrey verifySignedOut];
+  [self signOutWithButton:SignOutAccountsButton()
+      confirmationLabelID:confirmationLabelID];
 }
 
 + (void)selectIdentityWithEmail:(NSString*)userEmail {
@@ -316,4 +311,24 @@
       performAction:grey_tap()];
 }
 
+#pragma mark - Private
+
++ (void)signOutWithButton:(id<GREYMatcher>)buttonMatcher
+      confirmationLabelID:(int)confirmationLabelID {
+  [ChromeEarlGreyUI openSettingsMenu];
+  [ChromeEarlGreyUI tapSettingsMenuButton:SettingsAccountButton()];
+
+  [ChromeEarlGreyUI tapAccountsMenuButton:buttonMatcher];
+  id<GREYMatcher> confirmationButtonMatcher = [ChromeMatchersAppInterface
+      buttonWithAccessibilityLabelID:confirmationLabelID];
+  [[EarlGrey selectElementWithMatcher:grey_allOf(confirmationButtonMatcher,
+                                                 grey_not(buttonMatcher), nil)]
+      performAction:grey_tap()];
+  // Wait until the user is signed out.
+  [ChromeEarlGreyUI waitForAppToIdle];
+  [[EarlGrey selectElementWithMatcher:SettingsDoneButton()]
+      performAction:grey_tap()];
+  [SigninEarlGrey verifySignedOut];
+}
+
 @end
diff --git a/ios/chrome/browser/ui/autofill/form_input_accessory/form_input_accessory_coordinator.mm b/ios/chrome/browser/ui/autofill/form_input_accessory/form_input_accessory_coordinator.mm
index 9b48638..751f9d9 100644
--- a/ios/chrome/browser/ui/autofill/form_input_accessory/form_input_accessory_coordinator.mm
+++ b/ios/chrome/browser/ui/autofill/form_input_accessory/form_input_accessory_coordinator.mm
@@ -158,8 +158,7 @@
   [self.childCoordinators removeAllObjects];
 }
 
-- (void)startPasswordsFromButton:(UIButton*)button
-          invokedOnPasswordField:(BOOL)invokedOnPasswordField {
+- (void)startPasswordsFromButton:(UIButton*)button {
   WebStateList* webStateList = self.browser->GetWebStateList();
   DCHECK(webStateList->GetActiveWebState());
   const GURL& URL = webStateList->GetActiveWebState()->GetLastCommittedURL();
@@ -168,8 +167,7 @@
           initWithBaseViewController:self.baseViewController
                              browser:self.browser
                                  URL:URL
-                    injectionHandler:self.injectionHandler
-              invokedOnPasswordField:invokedOnPasswordField];
+                    injectionHandler:self.injectionHandler];
   passwordCoordinator.delegate = self;
   if (IsIPadIdiom()) {
     [passwordCoordinator presentFromButton:button];
@@ -251,10 +249,7 @@
 
 - (void)passwordButtonPressed:(UIButton*)sender {
   [self stopChildren];
-  BOOL invokedOnPasswordField =
-      [self.formInputAccessoryMediator lastFocusedFieldWasPassword];
-  [self startPasswordsFromButton:sender
-          invokedOnPasswordField:invokedOnPasswordField];
+  [self startPasswordsFromButton:sender];
   [self.formInputAccessoryViewController lockManualFallbackView];
   [self.formInputAccessoryMediator disableSuggestions];
 }
diff --git a/ios/chrome/browser/ui/autofill/form_input_accessory/form_input_accessory_mediator.h b/ios/chrome/browser/ui/autofill/form_input_accessory/form_input_accessory_mediator.h
index d15786b..40d289a0 100644
--- a/ios/chrome/browser/ui/autofill/form_input_accessory/form_input_accessory_mediator.h
+++ b/ios/chrome/browser/ui/autofill/form_input_accessory/form_input_accessory_mediator.h
@@ -77,9 +77,6 @@
 // Stops observing all objects.
 - (void)disconnect;
 
-// Returns YES if the last focused field is of type 'password'.
-- (BOOL)lastFocusedFieldWasPassword;
-
 @end
 
 // Methods to allow injection in tests.
diff --git a/ios/chrome/browser/ui/autofill/form_input_accessory/form_input_accessory_mediator.mm b/ios/chrome/browser/ui/autofill/form_input_accessory/form_input_accessory_mediator.mm
index 085c7187..b69c619 100644
--- a/ios/chrome/browser/ui/autofill/form_input_accessory/form_input_accessory_mediator.mm
+++ b/ios/chrome/browser/ui/autofill/form_input_accessory/form_input_accessory_mediator.mm
@@ -272,10 +272,6 @@
   }
 }
 
-- (BOOL)lastFocusedFieldWasPassword {
-  return _lastSeenParams.field_type == autofill::kPasswordFieldType;
-}
-
 #pragma mark - KeyboardObserverHelperConsumer
 
 - (void)keyboardDidStayOnScreen {
diff --git a/ios/chrome/browser/ui/autofill/manual_fill/BUILD.gn b/ios/chrome/browser/ui/autofill/manual_fill/BUILD.gn
index e4eb9634..80933d3 100644
--- a/ios/chrome/browser/ui/autofill/manual_fill/BUILD.gn
+++ b/ios/chrome/browser/ui/autofill/manual_fill/BUILD.gn
@@ -42,8 +42,6 @@
     "//components/autofill/ios/form_util",
     "//components/keyed_service/core:core",
     "//components/password_manager/core/browser",
-    "//components/password_manager/core/common",
-    "//components/password_manager/ios",
     "//ios/chrome/app/strings:ios_strings_grit",
     "//ios/chrome/browser",
     "//ios/chrome/browser/autofill",
@@ -53,7 +51,6 @@
     "//ios/chrome/browser/favicon",
     "//ios/chrome/browser/main",
     "//ios/chrome/browser/passwords",
-    "//ios/chrome/browser/sync",
     "//ios/chrome/browser/ui:feature_flags",
     "//ios/chrome/browser/ui/autofill/manual_fill:manual_fill_ui",
     "//ios/chrome/browser/ui/commands",
@@ -231,10 +228,8 @@
     "//base/test:test_support",
     "//components/autofill/core/browser:test_support",
     "//components/password_manager/core/browser",
-    "//components/password_manager/core/common",
     "//components/strings",
     "//ios/chrome/app/strings:ios_strings_grit",
-    "//ios/chrome/browser/ui/authentication:eg_test_support+eg2",
     "//ios/chrome/browser/ui/autofill:eg_test_support+eg2",
     "//ios/chrome/browser/ui/util",
     "//ios/chrome/browser/ui/util:eg_test_support+eg2",
diff --git a/ios/chrome/browser/ui/autofill/manual_fill/manual_fill_all_password_coordinator.mm b/ios/chrome/browser/ui/autofill/manual_fill/manual_fill_all_password_coordinator.mm
index 9711881..df5486b 100644
--- a/ios/chrome/browser/ui/autofill/manual_fill/manual_fill_all_password_coordinator.mm
+++ b/ios/chrome/browser/ui/autofill/manual_fill/manual_fill_all_password_coordinator.mm
@@ -10,7 +10,6 @@
 #include "ios/chrome/browser/favicon/ios_chrome_favicon_loader_factory.h"
 #import "ios/chrome/browser/main/browser.h"
 #include "ios/chrome/browser/passwords/ios_chrome_password_store_factory.h"
-#include "ios/chrome/browser/sync/sync_setup_service_factory.h"
 #import "ios/chrome/browser/ui/autofill/manual_fill/manual_fill_injection_handler.h"
 #import "ios/chrome/browser/ui/autofill/manual_fill/manual_fill_password_mediator.h"
 #import "ios/chrome/browser/ui/autofill/manual_fill/password_list_navigator.h"
@@ -18,7 +17,6 @@
 #import "ios/chrome/browser/ui/table_view/table_view_animator.h"
 #import "ios/chrome/browser/ui/table_view/table_view_navigation_controller.h"
 #include "ios/chrome/browser/ui/util/ui_util.h"
-#import "ios/chrome/browser/web_state_list/web_state_list.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
 #error "This file requires ARC support."
@@ -53,16 +51,9 @@
   FaviconLoader* faviconLoader =
       IOSChromeFaviconLoaderFactory::GetForBrowserState(
           self.browser->GetBrowserState());
-  web::WebState* webState =
-      self.browser->GetWebStateList()->GetActiveWebState();
-  SyncSetupService* syncService = SyncSetupServiceFactory::GetForBrowserState(
-      self.browser->GetBrowserState());
   self.passwordMediator =
       [[ManualFillPasswordMediator alloc] initWithPasswordStore:passwordStore
-                                                  faviconLoader:faviconLoader
-                                                       webState:webState
-                                                    syncService:syncService
-                                         invokedOnPasswordField:NO];
+                                                  faviconLoader:faviconLoader];
   [self.passwordMediator fetchPasswordsForURL:GURL::EmptyGURL()];
   self.passwordMediator.actionSectionEnabled = NO;
   self.passwordMediator.consumer = self.passwordViewController;
diff --git a/ios/chrome/browser/ui/autofill/manual_fill/manual_fill_password_coordinator.h b/ios/chrome/browser/ui/autofill/manual_fill/manual_fill_password_coordinator.h
index 3c25c04..ad0550cf 100644
--- a/ios/chrome/browser/ui/autofill/manual_fill/manual_fill_password_coordinator.h
+++ b/ios/chrome/browser/ui/autofill/manual_fill/manual_fill_password_coordinator.h
@@ -36,7 +36,6 @@
                                        URL:(const GURL&)URL
                           injectionHandler:
                               (ManualFillInjectionHandler*)injectionHandler
-                    invokedOnPasswordField:(BOOL)invokedOnPasswordField
     NS_DESIGNATED_INITIALIZER;
 
 // Unavailable, use
diff --git a/ios/chrome/browser/ui/autofill/manual_fill/manual_fill_password_coordinator.mm b/ios/chrome/browser/ui/autofill/manual_fill/manual_fill_password_coordinator.mm
index 6fc5565b..326c85d5 100644
--- a/ios/chrome/browser/ui/autofill/manual_fill/manual_fill_password_coordinator.mm
+++ b/ios/chrome/browser/ui/autofill/manual_fill/manual_fill_password_coordinator.mm
@@ -11,13 +11,11 @@
 #include "ios/chrome/browser/favicon/ios_chrome_favicon_loader_factory.h"
 #import "ios/chrome/browser/main/browser.h"
 #include "ios/chrome/browser/passwords/ios_chrome_password_store_factory.h"
-#include "ios/chrome/browser/sync/sync_setup_service_factory.h"
 #import "ios/chrome/browser/ui/autofill/manual_fill/manual_fill_injection_handler.h"
 #import "ios/chrome/browser/ui/autofill/manual_fill/manual_fill_password_mediator.h"
 #import "ios/chrome/browser/ui/autofill/manual_fill/password_list_navigator.h"
 #import "ios/chrome/browser/ui/autofill/manual_fill/password_view_controller.h"
 #include "ios/chrome/browser/ui/util/ui_util.h"
-#import "ios/chrome/browser/web_state_list/web_state_list.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
 #error "This file requires ARC support."
@@ -49,8 +47,7 @@
                                    browser:(Browser*)browser
                                        URL:(const GURL&)URL
                           injectionHandler:
-                              (ManualFillInjectionHandler*)injectionHandler
-                    invokedOnPasswordField:(BOOL)invokedOnPasswordField {
+                              (ManualFillInjectionHandler*)injectionHandler {
   self = [super initWithBaseViewController:viewController
                                    browser:browser
                           injectionHandler:injectionHandler];
@@ -64,15 +61,10 @@
     FaviconLoader* faviconLoader =
         IOSChromeFaviconLoaderFactory::GetForBrowserState(
             browser->GetBrowserState());
-    SyncSetupService* syncService = SyncSetupServiceFactory::GetForBrowserState(
-        self.browser->GetBrowserState());
 
     _passwordMediator = [[ManualFillPasswordMediator alloc]
-         initWithPasswordStore:passwordStore
-                 faviconLoader:faviconLoader
-                      webState:browser->GetWebStateList()->GetActiveWebState()
-                   syncService:syncService
-        invokedOnPasswordField:invokedOnPasswordField];
+        initWithPasswordStore:passwordStore
+                faviconLoader:faviconLoader];
     [_passwordMediator fetchPasswordsForURL:URL];
     _passwordMediator.actionSectionEnabled = YES;
     _passwordMediator.consumer = _passwordViewController;
diff --git a/ios/chrome/browser/ui/autofill/manual_fill/manual_fill_password_mediator.h b/ios/chrome/browser/ui/autofill/manual_fill/manual_fill_password_mediator.h
index 38ac4b7..150255c 100644
--- a/ios/chrome/browser/ui/autofill/manual_fill/manual_fill_password_mediator.h
+++ b/ios/chrome/browser/ui/autofill/manual_fill/manual_fill_password_mediator.h
@@ -19,13 +19,8 @@
 class PasswordStore;
 }  // namespace password_manager
 
-namespace web {
-class WebState;
-}  // namespace web
-
 class FaviconLoader;
 class GURL;
-class SyncSetupService;
 
 namespace manual_fill {
 
@@ -67,9 +62,6 @@
                     (scoped_refptr<password_manager::PasswordStore>)
                         passwordStore
                         faviconLoader:(FaviconLoader*)faviconLoader
-                             webState:(web::WebState*)webState
-                          syncService:(SyncSetupService*)syncService
-               invokedOnPasswordField:(BOOL)invokedOnPasswordField
     NS_DESIGNATED_INITIALIZER;
 
 // Unavailable. Use |initWithPasswordStore:faviconLoader:|.
diff --git a/ios/chrome/browser/ui/autofill/manual_fill/manual_fill_password_mediator.mm b/ios/chrome/browser/ui/autofill/manual_fill/manual_fill_password_mediator.mm
index 1ab1eed0c..eb9626a 100644
--- a/ios/chrome/browser/ui/autofill/manual_fill/manual_fill_password_mediator.mm
+++ b/ios/chrome/browser/ui/autofill/manual_fill/manual_fill_password_mediator.mm
@@ -8,16 +8,9 @@
 
 #include "base/metrics/user_metrics.h"
 #include "base/strings/sys_string_conversions.h"
-#import "components/autofill/ios/browser/autofill_util.h"
-#import "components/autofill/ios/form_util/form_activity_observer_bridge.h"
-#include "components/autofill/ios/form_util/form_activity_params.h"
 #include "components/password_manager/core/browser/password_store.h"
-#include "components/password_manager/core/common/password_manager_features.h"
-#import "components/password_manager/ios/password_generation_provider.h"
 #import "ios/chrome/browser/autofill/manual_fill/passwords_fetcher.h"
 #import "ios/chrome/browser/favicon/favicon_loader.h"
-#import "ios/chrome/browser/passwords/password_tab_helper.h"
-#import "ios/chrome/browser/sync/sync_setup_service.h"
 #import "ios/chrome/browser/ui/autofill/manual_fill/manual_fill_action_cell.h"
 #import "ios/chrome/browser/ui/autofill/manual_fill/manual_fill_content_injector.h"
 #import "ios/chrome/browser/ui/autofill/manual_fill/manual_fill_credential+PasswordForm.h"
@@ -28,7 +21,6 @@
 #import "ios/chrome/browser/ui/list_model/list_model.h"
 #import "ios/chrome/browser/ui/table_view/table_view_model.h"
 #include "ios/chrome/grit/ios_strings.h"
-#import "ios/web/public/web_state_observer_bridge.h"
 #include "ui/base/l10n/l10n_util_mac.h"
 #include "ui/gfx/favicon_size.h"
 #include "url/gurl.h"
@@ -61,9 +53,7 @@
       isEqualToString:credentials[secondIndex].host];
 }
 
-@interface ManualFillPasswordMediator () <CRWWebStateObserver,
-                                          FormActivityObserver,
-                                          ManualFillContentInjector,
+@interface ManualFillPasswordMediator () <ManualFillContentInjector,
                                           PasswordFetcherDelegate> {
   // The interface for getting and manipulating a user's saved passwords.
   scoped_refptr<password_manager::PasswordStore> _passwordStore;
@@ -82,56 +72,23 @@
 // YES if the password fetcher has completed at least one fetch.
 @property(nonatomic, assign) BOOL passwordFetcherDidFetch;
 
-// YES if the active field is of type 'password'.
-@property(nonatomic, assign) BOOL activeFieldIsPassword;
-
-// The relevant active web state.
-@property(nonatomic, assign) web::WebState* webState;
-
-// Sync setup service.
-@property(nonatomic, assign) SyncSetupService* syncService;
-
 @end
 
-@implementation ManualFillPasswordMediator {
-  // Bridge to observe the web state from Objective-C.
-  std::unique_ptr<web::WebStateObserverBridge> _webStateObserverBridge;
-
-  // Bridge to observe form activity in |_webState|.
-  std::unique_ptr<autofill::FormActivityObserverBridge>
-      _formActivityObserverBridge;
-}
+@implementation ManualFillPasswordMediator
 
 - (instancetype)initWithPasswordStore:
                     (scoped_refptr<password_manager::PasswordStore>)
                         passwordStore
-                        faviconLoader:(FaviconLoader*)faviconLoader
-                             webState:(web::WebState*)webState
-                          syncService:(SyncSetupService*)syncService
-               invokedOnPasswordField:(BOOL)invokedOnPasswordField {
+                        faviconLoader:(FaviconLoader*)faviconLoader {
   self = [super init];
   if (self) {
     _credentials = @[];
     _passwordStore = passwordStore;
     _faviconLoader = faviconLoader;
-    _webState = webState;
-    _syncService = syncService;
-    _activeFieldIsPassword = invokedOnPasswordField;
-    _webStateObserverBridge =
-        std::make_unique<web::WebStateObserverBridge>(self);
-    _webState->AddObserver(_webStateObserverBridge.get());
-    _formActivityObserverBridge =
-        std::make_unique<autofill::FormActivityObserverBridge>(_webState, self);
   }
   return self;
 }
 
-- (void)dealloc {
-  if (_webState) {
-    [self webStateDestroyed:_webState];
-  }
-}
-
 - (void)fetchPasswordsForURL:(const GURL&)URL {
   self.credentials = @[];
   self.passwordFetcher =
@@ -244,23 +201,6 @@
         manual_fill::OtherPasswordsAccessibilityIdentifier;
     [actions addObject:otherPasswordsItem];
 
-    if (base::FeatureList::IsEnabled(
-            password_manager::features::kEnableManualPasswordGeneration) &&
-        _syncService->IsSyncEnabled() && _activeFieldIsPassword) {
-      NSString* suggestPasswordTitleString = l10n_util::GetNSString(
-          IDS_IOS_MANUAL_FALLBACK_SUGGEST_PASSWORD_WITH_DOTS);
-      auto suggestPasswordItem = [[ManualFillActionItem alloc]
-          initWithTitle:suggestPasswordTitleString
-                 action:^{
-                   base::RecordAction(base::UserMetricsAction(
-                       "ManualFallback_Password_OpenSuggestPassword"));
-                   [weakSelf suggestPassword];
-                 }];
-      suggestPasswordItem.accessibilityIdentifier =
-          manual_fill::SuggestPasswordAccessibilityIdentifier;
-      [actions addObject:suggestPasswordItem];
-    }
-
     NSString* managePasswordsTitle =
         l10n_util::GetNSString(IDS_IOS_MANUAL_FALLBACK_MANAGE_PASSWORDS);
     auto managePasswordsItem = [[ManualFillActionItem alloc]
@@ -278,17 +218,6 @@
   }
 }
 
-- (void)suggestPassword {
-  if ([self canUserInjectInPasswordField:YES requiresHTTPS:NO]) {
-    DCHECK(_webState);
-    id<PasswordGenerationProvider> generationProvider =
-        PasswordTabHelper::FromWebState(_webState)
-            ->GetPasswordGenerationProvider();
-    if (generationProvider)
-      [generationProvider triggerPasswordGeneration];
-  }
-}
-
 #pragma mark - Setters
 
 - (void)setConsumer:(id<ManualFillPasswordConsumer>)consumer {
@@ -325,29 +254,4 @@
                                               completion);
 }
 
-#pragma mark - FormActivityObserver
-
-- (void)webState:(web::WebState*)webState
-    didRegisterFormActivity:(const autofill::FormActivityParams&)params
-                    inFrame:(web::WebFrame*)frame {
-  DCHECK_EQ(_webState, webState);
-  if (_activeFieldIsPassword !=
-      (params.field_type == autofill::kPasswordFieldType)) {
-    _activeFieldIsPassword = params.field_type == autofill::kPasswordFieldType;
-    [self postActionsToConsumer];
-  }
-}
-
-#pragma mark - CRWWebStateObserver
-
-- (void)webStateDestroyed:(web::WebState*)webState {
-  DCHECK_EQ(_webState, webState);
-  if (_webState) {
-    _webState->RemoveObserver(_webStateObserverBridge.get());
-    _webState = nullptr;
-  }
-  _webStateObserverBridge.reset();
-  _formActivityObserverBridge.reset();
-}
-
 @end
diff --git a/ios/chrome/browser/ui/autofill/manual_fill/password_view_controller_egtest.mm b/ios/chrome/browser/ui/autofill/manual_fill/password_view_controller_egtest.mm
index 1499d69..fdcc7f33 100644
--- a/ios/chrome/browser/ui/autofill/manual_fill/password_view_controller_egtest.mm
+++ b/ios/chrome/browser/ui/autofill/manual_fill/password_view_controller_egtest.mm
@@ -7,10 +7,7 @@
 #include "base/strings/utf_string_conversions.h"
 #import "base/test/ios/wait_util.h"
 #include "components/password_manager/core/browser/password_ui_utils.h"
-#include "components/password_manager/core/common/password_manager_features.h"
 #include "components/strings/grit/components_strings.h"
-#import "ios/chrome/browser/ui/authentication/signin_earl_grey.h"
-#import "ios/chrome/browser/ui/authentication/signin_earl_grey_ui.h"
 #import "ios/chrome/browser/ui/autofill/autofill_app_interface.h"
 #include "ios/chrome/grit/ios_strings.h"
 #import "ios/chrome/test/earl_grey/chrome_actions.h"
@@ -38,7 +35,6 @@
 using chrome_test_util::ManualFallbackOtherPasswordsDismissMatcher;
 using chrome_test_util::ManualFallbackPasswordButtonMatcher;
 using chrome_test_util::ManualFallbackPasswordTableViewWindowMatcher;
-using chrome_test_util::ManualFallbackSuggestPasswordMatcher;
 using chrome_test_util::NavigationBarDoneButton;
 using chrome_test_util::NavigationBarCancelButton;
 using chrome_test_util::SettingsPasswordMatcher;
@@ -46,7 +42,6 @@
 using chrome_test_util::StaticTextWithAccessibilityLabelId;
 using chrome_test_util::TapWebElementWithId;
 using chrome_test_util::TapWebElementWithIdInFrame;
-using chrome_test_util::UseSuggestedPasswordMatcher;
 
 namespace {
 
@@ -109,19 +104,6 @@
 
 @implementation PasswordViewControllerTestCase
 
-- (AppLaunchConfiguration)appConfigurationForTestCase {
-  AppLaunchConfiguration config;
-  if ([self isRunningTest:@selector(testPasswordGenerationOnManualFallback)]) {
-    config.features_enabled.push_back(
-        password_manager::features::kEnableManualPasswordGeneration);
-  }
-  if ([self isRunningTest:@selector(testPasswordControllerKeepsRightSize)]) {
-    config.features_disabled.push_back(
-        password_manager::features::kEnableManualPasswordGeneration);
-  }
-  return config;
-}
-
 - (void)setUp {
   [super setUp];
   GREYAssertTrue(self.testServer->Start(), @"Test server failed to start.");
@@ -658,44 +640,4 @@
       assertWithMatcher:grey_notVisible()];
 }
 
-// Tests password generation on manual fallback.
-- (void)testPasswordGenerationOnManualFallback {
-  [SigninEarlGreyUI signinWithFakeIdentity:[SigninEarlGrey fakeIdentity1]];
-  [ChromeEarlGrey waitForSyncInitialized:YES syncTimeout:10.0];
-
-  const GURL URL = self.testServer->GetURL(kFormHTMLFile);
-  [ChromeEarlGrey loadURL:URL];
-  [ChromeEarlGrey waitForWebStateContainingText:"hello!"];
-
-  // Bring up the keyboard.
-  [[EarlGrey selectElementWithMatcher:chrome_test_util::WebViewMatcher()]
-      performAction:TapWebElementWithId(kFormElementPassword)];
-
-  // Wait for the accessory icon to appear.
-  GREYAssertTrue([EarlGrey isKeyboardShownWithError:nil],
-                 @"Keyboard Should be Shown");
-
-  // Tap on the passwords icon.
-  [[EarlGrey selectElementWithMatcher:ManualFallbackPasswordIconMatcher()]
-      performAction:grey_tap()];
-
-  // Verify the password controller table view is visible.
-  [[EarlGrey selectElementWithMatcher:ManualFallbackPasswordTableViewMatcher()]
-      assertWithMatcher:grey_sufficientlyVisible()];
-
-  // Select a 'Suggest Password...' option.
-  [[EarlGrey selectElementWithMatcher:ManualFallbackSuggestPasswordMatcher()]
-      performAction:grey_tap()];
-
-  // Confirm by tapping on the 'Use Suggested Password' button.
-  [[EarlGrey selectElementWithMatcher:UseSuggestedPasswordMatcher()]
-      performAction:grey_tap()];
-
-  // Verify Web Content.
-  NSString* javaScriptCondition =
-      [NSString stringWithFormat:@"document.getElementById('%s').value !== ''",
-                                 kFormElementPassword];
-  XCTAssertTrue(WaitForJavaScriptCondition(javaScriptCondition));
-}
-
 @end
diff --git a/ios/chrome/browser/ui/settings/google_services/accounts_table_egtest.mm b/ios/chrome/browser/ui/settings/google_services/accounts_table_egtest.mm
index 99c7d49c..89cd0dd9c 100644
--- a/ios/chrome/browser/ui/settings/google_services/accounts_table_egtest.mm
+++ b/ios/chrome/browser/ui/settings/google_services/accounts_table_egtest.mm
@@ -4,6 +4,7 @@
 
 #import <UIKit/UIKit.h>
 
+#import "components/signin/ios/browser/features.h"
 #import "components/signin/public/base/account_consistency_method.h"
 #import "ios/chrome/browser/ui/authentication/signin_earl_grey.h"
 #import "ios/chrome/browser/ui/authentication/signin_earl_grey_ui.h"
@@ -64,6 +65,12 @@
       @"No bookmarks should exist before tests start.");
 }
 
+- (AppLaunchConfiguration)appConfigurationForTestCase {
+  AppLaunchConfiguration config;
+  config.features_disabled.push_back(signin::kSimplifySignOutIOS);
+  return config;
+}
+
 // Tests that the Sync and Account Settings screen are correctly popped if the
 // signed in account is removed.
 - (void)testSignInPopUpAccountOnSyncSettings {
@@ -201,8 +208,7 @@
   [BookmarkEarlGrey setupStandardBookmarks];
 
   // Sign out.
-  [SigninEarlGreyUI
-      signOutWithConfirmationChoice:SignOutConfirmationChoiceKeepData];
+  [SigninEarlGreyUI signOut];
 
   // Open the Bookmarks screen on the Tools menu.
   [BookmarkEarlGreyUI openBookmarks];
@@ -227,8 +233,7 @@
   [BookmarkEarlGrey setupStandardBookmarks];
 
   // Sign out.
-  [SigninEarlGreyUI
-      signOutWithConfirmationChoice:SignOutConfirmationChoiceClearData];
+  [SigninEarlGreyUI signOutAndClearDataFromDevice];
 
   // Open the Bookmarks screen on the Tools menu.
   [BookmarkEarlGreyUI openBookmarks];
@@ -257,8 +262,7 @@
   [BookmarkEarlGrey setupStandardBookmarks];
 
   // Sign out.
-  [SigninEarlGreyUI
-      signOutWithConfirmationChoice:SignOutConfirmationChoiceClearData];
+  [SigninEarlGreyUI signOutAndClearDataFromDevice];
 
   // Open the Bookmarks screen on the Tools menu.
   [BookmarkEarlGreyUI openBookmarks];
@@ -286,8 +290,7 @@
 
   [SigninEarlGreyUI signinWithFakeIdentity:fakeIdentity1];
   [SigninEarlGrey verifySignedInWithFakeIdentity:fakeIdentity1];
-  [SigninEarlGreyUI
-      signOutWithConfirmationChoice:SignOutConfirmationChoiceClearData];
+  [SigninEarlGreyUI signOutAndClearDataFromDevice];
 
   [SigninEarlGreyUI signinWithFakeIdentity:fakeIdentity2];
   [SigninEarlGrey verifySignedInWithFakeIdentity:fakeIdentity2];
diff --git a/ios/chrome/test/earl_grey/chrome_matchers.h b/ios/chrome/test/earl_grey/chrome_matchers.h
index 31079cb..bce4ad88 100644
--- a/ios/chrome/test/earl_grey/chrome_matchers.h
+++ b/ios/chrome/test/earl_grey/chrome_matchers.h
@@ -546,13 +546,6 @@
 // Returns the matcher for the iOS 13+ Activity View header.
 id<GREYMatcher> ActivityViewHeader(NSString* page_title);
 
-// Returns a matcher for the button to trigger password generation on manual
-// fallback.
-id<GREYMatcher> ManualFallbackSuggestPasswordMatcher();
-
-// Returns a matcher for the button to accept the generated password.
-id<GREYMatcher> UseSuggestedPasswordMatcher();
-
 }  // namespace chrome_test_util
 
 #endif  // IOS_CHROME_TEST_EARL_GREY_CHROME_MATCHERS_H_
diff --git a/ios/chrome/test/earl_grey/chrome_matchers.mm b/ios/chrome/test/earl_grey/chrome_matchers.mm
index 2e91c8e..ac0bc3f2 100644
--- a/ios/chrome/test/earl_grey/chrome_matchers.mm
+++ b/ios/chrome/test/earl_grey/chrome_matchers.mm
@@ -687,12 +687,4 @@
   return [ChromeMatchersAppInterface activityViewHeaderWithTitle:page_title];
 }
 
-id<GREYMatcher> ManualFallbackSuggestPasswordMatcher() {
-  return [ChromeMatchersAppInterface manualFallbackSuggestPasswordMatcher];
-}
-
-id<GREYMatcher> UseSuggestedPasswordMatcher() {
-  return [ChromeMatchersAppInterface useSuggestedPasswordMatcher];
-}
-
 }  // namespace chrome_test_util
diff --git a/ios/chrome/test/earl_grey/chrome_matchers_app_interface.h b/ios/chrome/test/earl_grey/chrome_matchers_app_interface.h
index 49c2216..1782151 100644
--- a/ios/chrome/test/earl_grey/chrome_matchers_app_interface.h
+++ b/ios/chrome/test/earl_grey/chrome_matchers_app_interface.h
@@ -537,13 +537,6 @@
 // Returns the matcher for the Activity View header.
 + (id<GREYMatcher>)activityViewHeaderWithTitle:(NSString*)pageTitle;
 
-// Returns a matcher for the button to trigger password generation on manual
-// fallback.
-+ (id<GREYMatcher>)manualFallbackSuggestPasswordMatcher;
-
-// Returns a matcher for the button to accept the generated password.
-+ (id<GREYMatcher>)useSuggestedPasswordMatcher;
-
 @end
 
 #endif  // IOS_CHROME_TEST_EARL_GREY_CHROME_MATCHERS_APP_INTERFACE_H_
diff --git a/ios/chrome/test/earl_grey/chrome_matchers_app_interface.mm b/ios/chrome/test/earl_grey/chrome_matchers_app_interface.mm
index 65e4bb4..b31f0d97 100644
--- a/ios/chrome/test/earl_grey/chrome_matchers_app_interface.mm
+++ b/ios/chrome/test/earl_grey/chrome_matchers_app_interface.mm
@@ -1040,15 +1040,4 @@
                     nil);
 }
 
-+ (id<GREYMatcher>)manualFallbackSuggestPasswordMatcher {
-  return grey_accessibilityID(
-      manual_fill::SuggestPasswordAccessibilityIdentifier);
-}
-
-+ (id<GREYMatcher>)useSuggestedPasswordMatcher {
-  return grey_allOf(
-      [self buttonWithAccessibilityLabelID:IDS_IOS_USE_SUGGESTED_PASSWORD],
-      grey_interactable(), nullptr);
-}
-
 @end
diff --git a/media/blink/webmediaplayer_impl.cc b/media/blink/webmediaplayer_impl.cc
index f4c4e00..3ddeffa 100644
--- a/media/blink/webmediaplayer_impl.cc
+++ b/media/blink/webmediaplayer_impl.cc
@@ -67,7 +67,6 @@
 #include "third_party/blink/public/platform/web_media_source.h"
 #include "third_party/blink/public/platform/web_runtime_features.h"
 #include "third_party/blink/public/platform/web_security_origin.h"
-#include "third_party/blink/public/platform/web_size.h"
 #include "third_party/blink/public/platform/web_string.h"
 #include "third_party/blink/public/platform/web_surface_layer_bridge.h"
 #include "third_party/blink/public/platform/web_texttrack_metadata.h"
diff --git a/media/blink/webmediaplayer_impl_unittest.cc b/media/blink/webmediaplayer_impl_unittest.cc
index 2dd3041..9363060 100644
--- a/media/blink/webmediaplayer_impl_unittest.cc
+++ b/media/blink/webmediaplayer_impl_unittest.cc
@@ -63,7 +63,6 @@
 #include "third_party/blink/public/platform/web_media_player_encrypted_media_client.h"
 #include "third_party/blink/public/platform/web_media_player_source.h"
 #include "third_party/blink/public/platform/web_security_origin.h"
-#include "third_party/blink/public/platform/web_size.h"
 #include "third_party/blink/public/platform/web_surface_layer_bridge.h"
 #include "third_party/blink/public/platform/web_url_response.h"
 #include "third_party/blink/public/web/web_local_frame.h"
diff --git a/media/filters/offloading_video_decoder.cc b/media/filters/offloading_video_decoder.cc
index 4c3b701..4719780c 100644
--- a/media/filters/offloading_video_decoder.cc
+++ b/media/filters/offloading_video_decoder.cc
@@ -75,6 +75,10 @@
     offload_task_runner_->DeleteSoon(FROM_HERE, std::move(helper_));
 }
 
+bool OffloadingVideoDecoder::IsOptimizedForRTC() const {
+  return helper_->decoder()->IsOptimizedForRTC();
+}
+
 VideoDecoderType OffloadingVideoDecoder::GetDecoderType() const {
   // This call is expected to be static and safe to call from any thread.
   return helper_->decoder()->GetDecoderType();
diff --git a/media/filters/offloading_video_decoder.h b/media/filters/offloading_video_decoder.h
index 8ef2d67..06016c2 100644
--- a/media/filters/offloading_video_decoder.h
+++ b/media/filters/offloading_video_decoder.h
@@ -88,6 +88,7 @@
   ~OffloadingVideoDecoder() override;
 
   // VideoDecoder implementation.
+  bool IsOptimizedForRTC() const override;
   VideoDecoderType GetDecoderType() const override;
   void Initialize(const VideoDecoderConfig& config,
                   bool low_delay,
diff --git a/media/gpu/v4l2/v4l2_video_decoder.cc b/media/gpu/v4l2/v4l2_video_decoder.cc
index 0f95090..34c2fc6 100644
--- a/media/gpu/v4l2/v4l2_video_decoder.cc
+++ b/media/gpu/v4l2/v4l2_video_decoder.cc
@@ -83,7 +83,6 @@
     base::WeakPtr<DecoderInterface::Client> client,
     scoped_refptr<V4L2Device> device)
     : DecoderInterface(std::move(decoder_task_runner), std::move(client)),
-      can_use_decoder_(num_instances_.Increment() < kMaxNumOfInstances),
       device_(std::move(device)),
       weak_this_factory_(this) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(decoder_sequence_checker_);
@@ -114,7 +113,9 @@
   }
 
   weak_this_factory_.InvalidateWeakPtrs();
-  num_instances_.Decrement();
+
+  if (can_use_decoder_)
+    num_instances_.Decrement();
 }
 
 void V4L2VideoDecoder::Initialize(const VideoDecoderConfig& config,
@@ -124,24 +125,21 @@
                                   const WaitingCB& /*waiting_cb*/) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(decoder_sequence_checker_);
   DCHECK(config.IsValidConfig());
-  DCHECK(state_ == State::kUninitialized || state_ == State::kDecoding);
+  DCHECK(state_ == State::kUninitialized || state_ == State::kInitialized ||
+         state_ == State::kDecoding);
   DVLOGF(3);
 
-  if (!can_use_decoder_) {
-    VLOGF(1) << "Reached maximum number of decoder instances ("
-             << kMaxNumOfInstances << ")";
-    std::move(init_cb).Run(StatusCode::kDecoderCreationFailed);
-    return;
-  }
-
   if (cdm_context || config.is_encrypted()) {
     VLOGF(1) << "V4L2 decoder does not support encrypted stream";
     std::move(init_cb).Run(StatusCode::kEncryptedContentUnsupported);
     return;
   }
 
-  // Reset V4L2 device and queue if reinitializing decoder.
-  if (state_ != State::kUninitialized) {
+  // Stop and reset the queues if we're currently decoding but want to
+  // re-initialize the decoder. This is not needed if the decoder is in the
+  // |kInitialized| state because the queues should still be stopped in that
+  // case.
+  if (state_ == State::kDecoding) {
     if (!StopStreamV4L2Queue(true)) {
       std::move(init_cb).Run(StatusCode::kV4l2FailedToStopStreamQueue);
       return;
@@ -152,27 +150,64 @@
     input_queue_ = nullptr;
     output_queue_ = nullptr;
 
+    if (can_use_decoder_) {
+      num_instances_.Decrement();
+      can_use_decoder_ = false;
+    }
+
+    continue_change_resolution_cb_.Reset();
+
     device_ = V4L2Device::Create();
     if (!device_) {
       VLOGF(1) << "Failed to create V4L2 device.";
+      SetState(State::kError);
       std::move(init_cb).Run(StatusCode::kV4l2NoDevice);
       return;
     }
 
     if (backend_)
       backend_ = nullptr;
-
-    SetState(State::kUninitialized);
   }
 
-  const VideoCodecProfile profile = config.profile();
+  DCHECK(!input_queue_);
+  DCHECK(!output_queue_);
+
+  profile_ = config.profile();
+  pixel_aspect_ratio_ = config.GetPixelAspectRatio();
+
+  if (profile_ == VIDEO_CODEC_PROFILE_UNKNOWN) {
+    VLOGF(1) << "Unknown profile.";
+    SetState(State::kError);
+    std::move(init_cb).Run(StatusCode::kV4l2NoDecoder);
+    return;
+  }
+
+  // Call init_cb
+  output_cb_ = std::move(output_cb);
+  SetState(State::kInitialized);
+  std::move(init_cb).Run(::media::OkStatus());
+}
+
+StatusCode V4L2VideoDecoder::InitializeBackend() {
+  DVLOGF(3);
+  DCHECK_CALLED_ON_VALID_SEQUENCE(decoder_sequence_checker_);
+  DCHECK(state_ == State::kInitialized);
+
+  can_use_decoder_ = num_instances_.Increment() < kMaxNumOfInstances;
+  if (!can_use_decoder_) {
+    VLOGF(1) << "Reached maximum number of decoder instances ("
+             << kMaxNumOfInstances << ")";
+    return StatusCode::kDecoderCreationFailed;
+  }
+
   constexpr bool kStateful = false;
   constexpr bool kStateless = true;
   base::Optional<std::pair<bool, uint32_t>> api_and_format;
   // Try both kStateful and kStateless APIs via |fourcc| and select the first
   // combination where Open()ing the |device_| works.
   for (const auto api : {kStateful, kStateless}) {
-    const auto fourcc = V4L2Device::VideoCodecProfileToV4L2PixFmt(profile, api);
+    const auto fourcc =
+        V4L2Device::VideoCodecProfileToV4L2PixFmt(profile_, api);
     constexpr uint32_t kInvalidV4L2PixFmt = 0;
     if (fourcc == kInvalidV4L2PixFmt ||
         !device_->Open(V4L2Device::Type::kDecoder, fourcc)) {
@@ -183,9 +218,10 @@
   }
 
   if (!api_and_format.has_value()) {
-    VLOGF(1) << "No V4L2 API found for profile: " << GetProfileName(profile);
-    std::move(init_cb).Run(StatusCode::kV4l2NoDecoder);
-    return;
+    num_instances_.Decrement();
+    can_use_decoder_ = false;
+    VLOGF(1) << "No V4L2 API found for profile: " << GetProfileName(profile_);
+    return StatusCode::kV4l2NoDecoder;
   }
 
   struct v4l2_capability caps;
@@ -194,71 +230,62 @@
       (caps.capabilities & kCapsRequired) != kCapsRequired) {
     VLOGF(1) << "ioctl() failed: VIDIOC_QUERYCAP, "
              << "caps check failed: 0x" << std::hex << caps.capabilities;
-    std::move(init_cb).Run(StatusCode::kV4l2FailedFileCapabilitiesCheck);
-    return;
+    return StatusCode::kV4l2FailedFileCapabilitiesCheck;
   }
 
-  pixel_aspect_ratio_ = config.GetPixelAspectRatio();
-
   // Create Input/Output V4L2Queue
   input_queue_ = device_->GetQueue(V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE);
   output_queue_ = device_->GetQueue(V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE);
   if (!input_queue_ || !output_queue_) {
     VLOGF(1) << "Failed to create V4L2 queue.";
-    std::move(init_cb).Run(StatusCode::kV4l2FailedResourceAllocation);
-    return;
+    return StatusCode::kV4l2FailedResourceAllocation;
   }
 
   const auto preferred_api_and_format = api_and_format.value();
   const uint32_t input_format_fourcc = preferred_api_and_format.second;
   if (preferred_api_and_format.first == kStateful) {
-    VLOGF(1) << "Using a stateful API for profile: " << GetProfileName(profile)
+    VLOGF(1) << "Using a stateful API for profile: " << GetProfileName(profile_)
              << " and fourcc: " << FourccToString(input_format_fourcc);
     backend_ = std::make_unique<V4L2StatefulVideoDecoderBackend>(
-        this, device_, profile, decoder_task_runner_);
+        this, device_, profile_, decoder_task_runner_);
   } else {
     DCHECK_EQ(preferred_api_and_format.first, kStateless);
-    VLOGF(1) << "Using a stateless API for profile: " << GetProfileName(profile)
+    VLOGF(1) << "Using a stateless API for profile: "
+             << GetProfileName(profile_)
              << " and fourcc: " << FourccToString(input_format_fourcc);
     backend_ = std::make_unique<V4L2StatelessVideoDecoderBackend>(
-        this, device_, profile, decoder_task_runner_);
+        this, device_, profile_, decoder_task_runner_);
   }
 
   if (!backend_->Initialize()) {
     VLOGF(1) << "Failed to initialize backend.";
-    std::move(init_cb).Run(StatusCode::kV4l2FailedResourceAllocation);
-    return;
+    return StatusCode::kV4l2FailedResourceAllocation;
   }
 
   if (!SetupInputFormat(input_format_fourcc)) {
     VLOGF(1) << "Failed to setup input format.";
-    std::move(init_cb).Run(StatusCode::kV4l2BadFormat);
-    return;
+    return StatusCode::kV4l2BadFormat;
   }
 
   if (input_queue_->AllocateBuffers(kNumInputBuffers, V4L2_MEMORY_MMAP) == 0) {
     VLOGF(1) << "Failed to allocate input buffer.";
-    std::move(init_cb).Run(StatusCode::kV4l2FailedResourceAllocation);
-    return;
+    return StatusCode::kV4l2FailedResourceAllocation;
   }
 
   // Start streaming input queue and polling. This is required for the stateful
   // decoder, and doesn't hurt for the stateless one.
   if (!StartStreamV4L2Queue(false)) {
     VLOGF(1) << "Failed to start streaming.";
-    std::move(init_cb).Run(StatusCode::kV4L2FailedToStartStreamQueue);
-    return;
+    return StatusCode::kV4L2FailedToStartStreamQueue;
   }
 
-  // Call init_cb
-  output_cb_ = output_cb;
   SetState(State::kDecoding);
-  std::move(init_cb).Run(::media::OkStatus());
+  return StatusCode::kOk;
 }
 
 bool V4L2VideoDecoder::SetupInputFormat(uint32_t input_format_fourcc) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(decoder_sequence_checker_);
-  DCHECK_EQ(state_, State::kUninitialized);
+  DCHECK_EQ(state_, State::kInitialized);
 
   // Check if the format is supported.
   std::vector<uint32_t> formats = device_->EnumerateSupportedPixelformats(
@@ -394,6 +421,11 @@
   // flushed after reset.
   continue_change_resolution_cb_.Reset();
 
+  if (state_ == State::kInitialized) {
+    std::move(closure).Run();
+    return;
+  }
+
   // Call all pending decode callback.
   backend_->ClearPendingRequests(DecodeStatus::ABORTED);
 
@@ -427,6 +459,15 @@
     return;
   }
 
+  if (state_ == State::kInitialized) {
+    const StatusCode status = InitializeBackend();
+    if (status != StatusCode::kOk) {
+      SetState(State::kError);
+      std::move(decode_cb).Run(status);
+      return;
+    }
+  }
+
   const int32_t bitstream_id = bitstream_id_generator_.GetNextBitstreamId();
   backend_->EnqueueDecodeTask(std::move(buffer), std::move(decode_cb),
                               bitstream_id);
@@ -585,16 +626,20 @@
 
 void V4L2VideoDecoder::ServiceDeviceTask(bool event) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(decoder_sequence_checker_);
-  DVLOGF(3) << "Number of queued input buffers: "
-            << input_queue_->QueuedBuffersCount()
-            << ", Number of queued output buffers: "
-            << output_queue_->QueuedBuffersCount();
 
-  backend_->OnServiceDeviceTask(event);
+  if (input_queue_ && output_queue_) {
+    DVLOGF(3) << "Number of queued input buffers: "
+              << input_queue_->QueuedBuffersCount()
+              << ", Number of queued output buffers: "
+              << output_queue_->QueuedBuffersCount();
+  }
+
+  if (backend_)
+    backend_->OnServiceDeviceTask(event);
 
   // Dequeue V4L2 output buffer first to reduce output latency.
   bool success;
-  while (output_queue_->QueuedBuffersCount() > 0) {
+  while (output_queue_ && output_queue_->QueuedBuffersCount() > 0) {
     V4L2ReadableBufferRef dequeued_buffer;
 
     std::tie(success, dequeued_buffer) = output_queue_->DequeueBuffer();
@@ -609,7 +654,7 @@
   }
 
   // Dequeue V4L2 input buffer.
-  while (input_queue_->QueuedBuffersCount() > 0) {
+  while (input_queue_ && input_queue_->QueuedBuffersCount() > 0) {
     V4L2ReadableBufferRef dequeued_buffer;
 
     std::tie(success, dequeued_buffer) = input_queue_->DequeueBuffer();
@@ -671,8 +716,14 @@
   // Check if the state transition is valid.
   switch (new_state) {
     case State::kUninitialized:
-      if (state_ != State::kDecoding) {
-        VLOGF(1) << "Should not set to kUninitialized.";
+      VLOGF(1) << "Should not set to kUninitialized.";
+      new_state = State::kError;
+      break;
+
+    case State::kInitialized:
+      if ((state_ != State::kUninitialized) && (state_ != State::kDecoding)) {
+        VLOGF(1) << "Can only transition to kInitialized from kUninitialized "
+                    "or kDecoding";
         new_state = State::kError;
       }
       break;
diff --git a/media/gpu/v4l2/v4l2_video_decoder.h b/media/gpu/v4l2/v4l2_video_decoder.h
index 37d1291..094465c 100644
--- a/media/gpu/v4l2/v4l2_video_decoder.h
+++ b/media/gpu/v4l2/v4l2_video_decoder.h
@@ -82,9 +82,13 @@
   ~V4L2VideoDecoder() override;
 
   enum class State {
-    // Initial state. Transitions to |kDecoding| if Initialize() is successful,
+    // Initial state. Transitions to |kInitialized| if Initialize() is
+    // successful,
     // |kError| otherwise.
     kUninitialized,
+    // Transitions to |kDecoding| when an input buffer has arrived that
+    // allows creation of hardware contexts. |kError| on error.
+    kInitialized,
     // Transitions to |kFlushing| when flushing or changing resolution,
     // |kError| if any unexpected error occurs.
     kDecoding,
@@ -136,6 +140,10 @@
   // Change the state and check the state transition is valid.
   void SetState(State new_state);
 
+  // Continue backend initialization. Decoder will not take a hardware context
+  // until InitializeBackend() is called.
+  StatusCode InitializeBackend();
+
   // Pages with multiple V4L2VideoDecoder instances might run out of memory
   // (e.g. b/170870476) or crash (e.g. crbug.com/1109312). To avoid that and
   // while the investigation goes on, limit the maximum number of simultaneous
@@ -144,7 +152,7 @@
   // the maximum number of instances at the time this decoder is created.
   static constexpr int kMaxNumOfInstances = 32;
   static base::AtomicRefCount num_instances_;
-  const bool can_use_decoder_;
+  bool can_use_decoder_ = false;
 
   // The V4L2 backend, i.e. the part of the decoder that sends
   // decoding jobs to the kernel.
@@ -169,6 +177,10 @@
   // Callbacks passed from Initialize().
   OutputCB output_cb_;
 
+  // Hold onto profile passed in from Initialize() so that
+  // it is available for InitializeBackend().
+  VideoCodecProfile profile_ = VIDEO_CODEC_PROFILE_UNKNOWN;
+
   // V4L2 input and output queue.
   scoped_refptr<V4L2Queue> input_queue_;
   scoped_refptr<V4L2Queue> output_queue_;
diff --git a/mojo/public/cpp/bindings/lib/validation_errors.cc b/mojo/public/cpp/bindings/lib/validation_errors.cc
index e942182..31e037bf 100644
--- a/mojo/public/cpp/bindings/lib/validation_errors.cc
+++ b/mojo/public/cpp/bindings/lib/validation_errors.cc
@@ -90,7 +90,7 @@
                            ValidationError error,
                            const char* description) {
 #if !defined(OS_NACL)
-  SCOPED_CRASH_KEY_STRING32("mojo-message", "header-bytes",
+  SCOPED_CRASH_KEY_STRING64("mojo-message", "header-bytes",
                             MessageHeaderAsHexString(context->message()));
 #endif  // !defined (OS_NACL)
 
diff --git a/pdf/out_of_process_instance.cc b/pdf/out_of_process_instance.cc
index 83852be..f113ebbc 100644
--- a/pdf/out_of_process_instance.cc
+++ b/pdf/out_of_process_instance.cc
@@ -45,7 +45,6 @@
 #include "pdf/ppapi_migration/url_loader.h"
 #include "pdf/ppapi_migration/value_conversions.h"
 #include "pdf/thumbnail.h"
-#include "pdf/ui/file_name.h"
 #include "pdf/ui/format_page_size.h"
 #include "ppapi/c/dev/ppb_cursor_control_dev.h"
 #include "ppapi/c/pp_errors.h"
@@ -118,10 +117,6 @@
 constexpr char kJSSaveType[] = "save";
 constexpr char kJSToken[] = "token";
 constexpr char kJSSaveRequestType[] = "saveRequestType";
-// Save data (Plugin -> Page)
-constexpr char kJSSaveDataType[] = "saveData";
-constexpr char kJSFileName[] = "fileName";
-constexpr char kJSDataToSave[] = "dataToSave";
 // Reset print preview mode (Page -> Plugin)
 constexpr char kJSResetPrintPreviewModeType[] = "resetPrintPreviewMode";
 constexpr char kJSPrintPreviewUrl[] = "url";
@@ -1035,41 +1030,6 @@
   SelectedFindResultChanged(current_find_index);
 }
 
-void OutOfProcessInstance::SaveToBuffer(const std::string& token) {
-  engine()->KillFormFocus();
-
-  pp::VarDictionary message;
-  message.Set(kType, kJSSaveDataType);
-  message.Set(kJSToken, pp::Var(token));
-  message.Set(kJSFileName, pp::Var(GetFileNameForSaveFromUrl(GetURL())));
-  // This will be overwritten if the save is successful.
-  message.Set(kJSDataToSave, pp::Var(pp::Var::Null()));
-
-  if (edit_mode()) {
-    std::vector<uint8_t> data = engine()->GetSaveData();
-    if (IsSaveDataSizeValid(data.size())) {
-      pp::VarArrayBuffer buffer(data.size());
-      std::copy(data.begin(), data.end(),
-                reinterpret_cast<char*>(buffer.Map()));
-      message.Set(kJSDataToSave, buffer);
-    }
-  } else {
-#if BUILDFLAG(IS_CHROMEOS_ASH)
-    uint32_t length = engine()->GetLoadedByteSize();
-    if (IsSaveDataSizeValid(length)) {
-      pp::VarArrayBuffer buffer(length);
-      if (engine()->ReadLoadedBytes(length, buffer.Map())) {
-        message.Set(kJSDataToSave, buffer);
-      }
-    }
-#else
-    NOTREACHED();
-#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
-  }
-
-  PostMessage(message);
-}
-
 void OutOfProcessInstance::SaveToFile(const std::string& token) {
   engine()->KillFormFocus();
   ConsumeSaveToken(token);
diff --git a/pdf/out_of_process_instance.h b/pdf/out_of_process_instance.h
index 3a86244..50d6dda8 100644
--- a/pdf/out_of_process_instance.h
+++ b/pdf/out_of_process_instance.h
@@ -172,7 +172,6 @@
 
   bool CanSaveEdits() const;
   void SaveToFile(const std::string& token);
-  void SaveToBuffer(const std::string& token);
 
   void FormDidOpen(int32_t result);
 
diff --git a/pdf/pdf_view_plugin_base.cc b/pdf/pdf_view_plugin_base.cc
index 075d85f..4f9cd172 100644
--- a/pdf/pdf_view_plugin_base.cc
+++ b/pdf/pdf_view_plugin_base.cc
@@ -27,6 +27,7 @@
 #include "base/strings/string_util.h"
 #include "base/time/time.h"
 #include "base/values.h"
+#include "build/chromeos_buildflags.h"
 #include "net/base/escape.h"
 #include "pdf/accessibility.h"
 #include "pdf/accessibility_structs.h"
@@ -36,6 +37,7 @@
 #include "pdf/pdfium/pdfium_engine.h"
 #include "pdf/ppapi_migration/image.h"
 #include "pdf/ppapi_migration/url_loader.h"
+#include "pdf/ui/file_name.h"
 #include "third_party/skia/include/core/SkBitmap.h"
 #include "third_party/skia/include/core/SkColor.h"
 #include "ui/gfx/geometry/point_f.h"
@@ -286,6 +288,36 @@
   (this->*handler)(message);
 }
 
+void PdfViewPluginBase::SaveToBuffer(const std::string& token) {
+  engine()->KillFormFocus();
+
+  base::Value message(base::Value::Type::DICTIONARY);
+  message.SetStringKey("type", "saveData");
+  message.SetStringKey("token", token);
+  message.SetStringKey("fileName", GetFileNameForSaveFromUrl(url_));
+
+  base::Value data_to_save;
+  if (edit_mode_) {
+    base::Value::BlobStorage data = engine()->GetSaveData();
+    if (IsSaveDataSizeValid(data.size()))
+      data_to_save = base::Value(std::move(data));
+  } else {
+#if BUILDFLAG(IS_CHROMEOS_ASH)
+    uint32_t length = engine()->GetLoadedByteSize();
+    if (IsSaveDataSizeValid(length)) {
+      base::Value::BlobStorage data(length);
+      if (engine()->ReadLoadedBytes(length, data.data()))
+        data_to_save = base::Value(std::move(data));
+    }
+#else
+    NOTREACHED();
+#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
+  }
+
+  message.SetKey("dataToSave", std::move(data_to_save));
+  SendMessage(std::move(message));
+}
+
 void PdfViewPluginBase::ConsumeSaveToken(const std::string& token) {
   base::Value message(base::Value::Type::DICTIONARY);
   message.SetStringKey("type", "consumeSaveToken");
diff --git a/pdf/pdf_view_plugin_base.h b/pdf/pdf_view_plugin_base.h
index 82466a4..300eacd 100644
--- a/pdf/pdf_view_plugin_base.h
+++ b/pdf/pdf_view_plugin_base.h
@@ -149,6 +149,8 @@
   // non-blocking.
   virtual void SendMessage(base::Value message) = 0;
 
+  void SaveToBuffer(const std::string& token);
+
   // Consumes a token for saving the document.
   void ConsumeSaveToken(const std::string& token);
 
diff --git a/services/data_decoder/image_decoder_impl.cc b/services/data_decoder/image_decoder_impl.cc
index f0546286..b64188b 100644
--- a/services/data_decoder/image_decoder_impl.cc
+++ b/services/data_decoder/image_decoder_impl.cc
@@ -11,7 +11,6 @@
 
 #include "skia/ext/image_operations.h"
 #include "third_party/blink/public/platform/web_data.h"
-#include "third_party/blink/public/platform/web_size.h"
 #include "third_party/blink/public/web/web_image.h"
 #include "third_party/skia/include/core/SkBitmap.h"
 
diff --git a/services/network/cors/cors_url_loader_factory.cc b/services/network/cors/cors_url_loader_factory.cc
index f376305..ae5daab0 100644
--- a/services/network/cors/cors_url_loader_factory.cc
+++ b/services/network/cors/cors_url_loader_factory.cc
@@ -76,7 +76,7 @@
 
   if (trust_token_redemption_policy ==
           mojom::TrustTokenRedemptionPolicy::kForbid &&
-      DoesTrustTokenOperationRequireFeaturePolicy(
+      DoesTrustTokenOperationRequirePermissionsPolicy(
           url_request.trust_token_params->type)) {
     // Got a request configured for Trust Tokens redemption or signing from
     // a context in which this operation is prohibited.
diff --git a/services/network/public/cpp/not_implemented_url_loader_factory.cc b/services/network/public/cpp/not_implemented_url_loader_factory.cc
index 56516cb..aef437b8 100644
--- a/services/network/public/cpp/not_implemented_url_loader_factory.cc
+++ b/services/network/public/cpp/not_implemented_url_loader_factory.cc
@@ -24,7 +24,9 @@
     const network::ResourceRequest& url_request,
     mojo::PendingRemote<network::mojom::URLLoaderClient> client,
     const net::MutableNetworkTrafficAnnotationTag& traffic_annotation) {
-  NOTREACHED();
+  // TODO(https://crbug.com/1184292): Add a NOTREACHED assertion here once we
+  // know of no more cases when the assertion may fire.
+
   network::URLLoaderCompletionStatus status;
   status.error_code = net::ERR_NOT_IMPLEMENTED;
   mojo::Remote<network::mojom::URLLoaderClient>(std::move(client))
diff --git a/services/network/public/cpp/trust_token_operation_authorization.h b/services/network/public/cpp/trust_token_operation_authorization.h
index 03c21b8..c64eb41 100644
--- a/services/network/public/cpp/trust_token_operation_authorization.h
+++ b/services/network/public/cpp/trust_token_operation_authorization.h
@@ -26,7 +26,7 @@
 //  side of a privacy boundary, we’d like to prohibit these third-party frames
 //  from having access to the redeeming-context RRs without the top-level
 //  frame's explicit consent.
-constexpr bool DoesTrustTokenOperationRequireFeaturePolicy(
+constexpr bool DoesTrustTokenOperationRequirePermissionsPolicy(
     mojom::TrustTokenOperationType type) {
   switch (type) {
     case mojom::TrustTokenOperationType::kRedemption:
diff --git a/services/network/test/test_url_loader_factory.cc b/services/network/test/test_url_loader_factory.cc
index afc46ed..8dd112b7 100644
--- a/services/network/test/test_url_loader_factory.cc
+++ b/services/network/test/test_url_loader_factory.cc
@@ -81,7 +81,8 @@
     if (candidate.request.url == url) {
       if (request_out)
         *request_out = &candidate.request;
-      return candidate.client.is_connected();
+      if (candidate.client.is_connected())
+        return true;
     }
   }
   return false;
diff --git a/services/network/test/test_url_loader_factory_unittest.cc b/services/network/test/test_url_loader_factory_unittest.cc
index 57f5f18b..c95a1f52 100644
--- a/services/network/test/test_url_loader_factory_unittest.cc
+++ b/services/network/test/test_url_loader_factory_unittest.cc
@@ -172,6 +172,17 @@
   EXPECT_TRUE(factory()->IsPending(url));
   client()->Unbind();
   EXPECT_FALSE(factory()->IsPending(url));
+
+  // Cleanup between tests.
+  client()->Unbind();
+  factory()->ClearResponses();
+
+  // Now with multiple requests
+  StartRequest(url);
+  client()->Unbind();
+  EXPECT_FALSE(factory()->IsPending(url));
+  StartRequest(url);
+  EXPECT_TRUE(factory()->IsPending(url));
 }
 
 TEST_F(TestURLLoaderFactoryTest, IsPendingLoadFlags) {
diff --git a/testing/buildbot/OWNERS b/testing/buildbot/OWNERS
index 6a7da71b..7e05bb5b 100644
--- a/testing/buildbot/OWNERS
+++ b/testing/buildbot/OWNERS
@@ -12,6 +12,8 @@
 
 # For Weblayer skew tests related reviews
 rmhasan@google.com
+per-file chromium.android.*=chrome-weblayer-builder@chops-service-accounts.iam.gserviceaccount.com
+per-file variants.pyl=chrome-weblayer-builder@chops-service-accounts.iam.gserviceaccount.com
 
 # For V8 and DevTools related reviews.
 machenbach@chromium.org
@@ -24,8 +26,3 @@
 
 # For OOBE-related test filters.
 per-file *oobe*=file://chrome/browser/ui/webui/chromeos/login/OWNERS
-
-# Owners of variants.pyl will be added as reviewers to CL's generated
-# by the build_weblayer_version_tests_apk_cipd_pkg infra recipe. See
-# crbug.com/1041619.
-per-file variants.pyl=rmhasan@google.com
diff --git a/testing/buildbot/chromium.android.fyi.json b/testing/buildbot/chromium.android.fyi.json
index a6ba937..fd8d73d3 100644
--- a/testing/buildbot/chromium.android.fyi.json
+++ b/testing/buildbot/chromium.android.fyi.json
@@ -352,11 +352,11 @@
             "--bucket",
             "chromium-result-details",
             "--test-name",
-            "weblayer_instrumentation_test_versions_apk_Client Library Skew Tests For 90.0.4430.17"
+            "weblayer_instrumentation_test_versions_apk_Client Library Skew Tests For 90.0.4430.19"
           ],
           "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
         },
-        "name": "weblayer_instrumentation_test_versions_apk_Client Library Skew Tests For 90.0.4430.17",
+        "name": "weblayer_instrumentation_test_versions_apk_Client Library Skew Tests For 90.0.4430.19",
         "resultdb": {
           "enable": true
         },
@@ -366,7 +366,7 @@
             {
               "cipd_package": "chromium/testing/weblayer-x86",
               "location": "weblayer_instrumentation_test_M90",
-              "revision": "version:90.0.4430.17"
+              "revision": "version:90.0.4430.19"
             },
             {
               "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
@@ -589,11 +589,11 @@
             "--bucket",
             "chromium-result-details",
             "--test-name",
-            "weblayer_instrumentation_test_versions_apk_Implementation Library Skew Tests For 90.0.4430.17"
+            "weblayer_instrumentation_test_versions_apk_Implementation Library Skew Tests For 90.0.4430.19"
           ],
           "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
         },
-        "name": "weblayer_instrumentation_test_versions_apk_Implementation Library Skew Tests For 90.0.4430.17",
+        "name": "weblayer_instrumentation_test_versions_apk_Implementation Library Skew Tests For 90.0.4430.19",
         "resultdb": {
           "enable": true
         },
@@ -603,7 +603,7 @@
             {
               "cipd_package": "chromium/testing/weblayer-x86",
               "location": "weblayer_instrumentation_test_M90",
-              "revision": "version:90.0.4430.17"
+              "revision": "version:90.0.4430.19"
             },
             {
               "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
@@ -894,11 +894,11 @@
             "--bucket",
             "chromium-result-details",
             "--test-name",
-            "weblayer_instrumentation_test_versions_apk_Client Library Skew Tests For 90.0.4430.17"
+            "weblayer_instrumentation_test_versions_apk_Client Library Skew Tests For 90.0.4430.19"
           ],
           "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
         },
-        "name": "weblayer_instrumentation_test_versions_apk_Client Library Skew Tests For 90.0.4430.17",
+        "name": "weblayer_instrumentation_test_versions_apk_Client Library Skew Tests For 90.0.4430.19",
         "resultdb": {
           "enable": true
         },
@@ -908,7 +908,7 @@
             {
               "cipd_package": "chromium/testing/weblayer-x86",
               "location": "weblayer_instrumentation_test_M90",
-              "revision": "version:90.0.4430.17"
+              "revision": "version:90.0.4430.19"
             },
             {
               "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
@@ -1131,11 +1131,11 @@
             "--bucket",
             "chromium-result-details",
             "--test-name",
-            "weblayer_instrumentation_test_versions_apk_Implementation Library Skew Tests For 90.0.4430.17"
+            "weblayer_instrumentation_test_versions_apk_Implementation Library Skew Tests For 90.0.4430.19"
           ],
           "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
         },
-        "name": "weblayer_instrumentation_test_versions_apk_Implementation Library Skew Tests For 90.0.4430.17",
+        "name": "weblayer_instrumentation_test_versions_apk_Implementation Library Skew Tests For 90.0.4430.19",
         "resultdb": {
           "enable": true
         },
@@ -1145,7 +1145,7 @@
             {
               "cipd_package": "chromium/testing/weblayer-x86",
               "location": "weblayer_instrumentation_test_M90",
-              "revision": "version:90.0.4430.17"
+              "revision": "version:90.0.4430.19"
             },
             {
               "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
diff --git a/testing/buildbot/chromium.android.json b/testing/buildbot/chromium.android.json
index b1d6836..c52b355 100644
--- a/testing/buildbot/chromium.android.json
+++ b/testing/buildbot/chromium.android.json
@@ -46646,11 +46646,11 @@
             "--bucket",
             "chromium-result-details",
             "--test-name",
-            "weblayer_instrumentation_test_versions_apk_Client Library Skew Tests For 90.0.4430.17"
+            "weblayer_instrumentation_test_versions_apk_Client Library Skew Tests For 90.0.4430.19"
           ],
           "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
         },
-        "name": "weblayer_instrumentation_test_versions_apk_Client Library Skew Tests For 90.0.4430.17",
+        "name": "weblayer_instrumentation_test_versions_apk_Client Library Skew Tests For 90.0.4430.19",
         "resultdb": {
           "enable": true
         },
@@ -46660,7 +46660,7 @@
             {
               "cipd_package": "chromium/testing/weblayer-x86",
               "location": "weblayer_instrumentation_test_M90",
-              "revision": "version:90.0.4430.17"
+              "revision": "version:90.0.4430.19"
             },
             {
               "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
@@ -46883,11 +46883,11 @@
             "--bucket",
             "chromium-result-details",
             "--test-name",
-            "weblayer_instrumentation_test_versions_apk_Implementation Library Skew Tests For 90.0.4430.17"
+            "weblayer_instrumentation_test_versions_apk_Implementation Library Skew Tests For 90.0.4430.19"
           ],
           "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
         },
-        "name": "weblayer_instrumentation_test_versions_apk_Implementation Library Skew Tests For 90.0.4430.17",
+        "name": "weblayer_instrumentation_test_versions_apk_Implementation Library Skew Tests For 90.0.4430.19",
         "resultdb": {
           "enable": true
         },
@@ -46897,7 +46897,7 @@
             {
               "cipd_package": "chromium/testing/weblayer-x86",
               "location": "weblayer_instrumentation_test_M90",
-              "revision": "version:90.0.4430.17"
+              "revision": "version:90.0.4430.19"
             },
             {
               "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
@@ -47187,11 +47187,11 @@
             "--bucket",
             "chromium-result-details",
             "--test-name",
-            "weblayer_instrumentation_test_versions_apk_Client Library Skew Tests For 90.0.4430.17"
+            "weblayer_instrumentation_test_versions_apk_Client Library Skew Tests For 90.0.4430.19"
           ],
           "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
         },
-        "name": "weblayer_instrumentation_test_versions_apk_Client Library Skew Tests For 90.0.4430.17",
+        "name": "weblayer_instrumentation_test_versions_apk_Client Library Skew Tests For 90.0.4430.19",
         "resultdb": {
           "enable": true
         },
@@ -47201,7 +47201,7 @@
             {
               "cipd_package": "chromium/testing/weblayer-x86",
               "location": "weblayer_instrumentation_test_M90",
-              "revision": "version:90.0.4430.17"
+              "revision": "version:90.0.4430.19"
             },
             {
               "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
@@ -47424,11 +47424,11 @@
             "--bucket",
             "chromium-result-details",
             "--test-name",
-            "weblayer_instrumentation_test_versions_apk_Implementation Library Skew Tests For 90.0.4430.17"
+            "weblayer_instrumentation_test_versions_apk_Implementation Library Skew Tests For 90.0.4430.19"
           ],
           "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
         },
-        "name": "weblayer_instrumentation_test_versions_apk_Implementation Library Skew Tests For 90.0.4430.17",
+        "name": "weblayer_instrumentation_test_versions_apk_Implementation Library Skew Tests For 90.0.4430.19",
         "resultdb": {
           "enable": true
         },
@@ -47438,7 +47438,7 @@
             {
               "cipd_package": "chromium/testing/weblayer-x86",
               "location": "weblayer_instrumentation_test_M90",
-              "revision": "version:90.0.4430.17"
+              "revision": "version:90.0.4430.19"
             },
             {
               "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
diff --git a/testing/buildbot/chromium.linux.json b/testing/buildbot/chromium.linux.json
index 32c1c889..445575e 100644
--- a/testing/buildbot/chromium.linux.json
+++ b/testing/buildbot/chromium.linux.json
@@ -7307,8 +7307,7 @@
           "--no-xvfb",
           "--use-weston",
           "--ozone-platform=wayland",
-          "--enable-features=UseOzonePlatform",
-          "--test-launcher-filter-file=../../testing/buildbot/filters/ozone-linux.sync_integration_tests_wayland.filter"
+          "--enable-features=UseOzonePlatform"
         ],
         "merge": {
           "args": [],
diff --git a/testing/buildbot/filters/BUILD.gn b/testing/buildbot/filters/BUILD.gn
index 0988f2a..058a6298 100644
--- a/testing/buildbot/filters/BUILD.gn
+++ b/testing/buildbot/filters/BUILD.gn
@@ -127,10 +127,7 @@
 source_set("sync_integration_tests_filters") {
   testonly = true
 
-  data = [
-    "//testing/buildbot/filters/e2e.sync_integration_tests.filter",
-    "//testing/buildbot/filters/ozone-linux.sync_integration_tests_wayland.filter",
-  ]
+  data = [ "//testing/buildbot/filters/e2e.sync_integration_tests.filter" ]
 }
 
 source_set("fuchsia_filters") {
diff --git a/testing/buildbot/filters/ozone-linux.sync_integration_tests_wayland.filter b/testing/buildbot/filters/ozone-linux.sync_integration_tests_wayland.filter
deleted file mode 100644
index c1e58db3..0000000
--- a/testing/buildbot/filters/ozone-linux.sync_integration_tests_wayland.filter
+++ /dev/null
@@ -1,3 +0,0 @@
-# TODO(https://crbug.com/1184124): this fails because of non-existing xdg_toplevel that
-# should be a parent of a newly created xdg_popup child.
--SingleClientSessionsSyncTestWithFaviconTestServer.ShouldDeleteOnDemandIconsOnSessionsDisabled
diff --git a/testing/buildbot/filters/ozone-linux.wayland_browser_tests.filter b/testing/buildbot/filters/ozone-linux.wayland_browser_tests.filter
index 849ca982e..ba0f275 100644
--- a/testing/buildbot/filters/ozone-linux.wayland_browser_tests.filter
+++ b/testing/buildbot/filters/ozone-linux.wayland_browser_tests.filter
@@ -42,28 +42,14 @@
 # are created.
 # TODO(https://crbug.com/1176174): figure out what exactly is wrong and fix
 # the problems.
--All/HostedAppProcessModelTest.BackgroundPageWithAppCoveringDifferentSites/0
 -All/HostedOrWebAppTest.CtrlClickLink/HostedApp
 -All/HostedOrWebAppTest.CtrlClickLink/WebApp
 -All/HostedOrWebAppTest.OpenLinkInNewTab/HostedApp
 -All/HostedOrWebAppTest.OpenLinkInNewTab/WebApp
--AppBackgroundPageApiTest.OpenPopupFromBGPage
 -AudioFocusWebContentsObserverBrowserTest.PlatformAppHasDifferentAudioFocus
 -CustomTabBarViewBrowserTest.RightClickMenuShowsCopyUrl
--PopupTrackerBrowserTest.ShiftClick_HasTracker
 -RemoteCopyBrowserTest.ImageUrl
 -RemoteCopyBrowserTest.Text
 -RemoteCopyBrowserTest.TextThenImageUrl
 -WebAppBrowserTest.CopyURL
 -BrowserNavigatorTest.SwitchToTabLatestWindow
--All/IntentPickerBubbleViewBrowserTest.NavigationInAppWindowToInScopeLinkDoesNotShowIntentPicker/0
--All/IntentPickerBubbleViewBrowserTest.NavigationInAppWindowToInScopeLinkDoesNotShowIntentPicker/1
--All/IntentPickerBubbleViewBrowserTest.NavigationInAppWindowToInScopeLinkDoesNotShowIntentPicker/2
--All/IntentPickerBubbleViewBrowserTest.NavigationInAppWindowToInScopeLinkDoesNotShowIntentPicker/3
--All/SystemWebAppLinkCaptureBrowserTest.WindowOpenFromOtherSWA/_Default
--CustomTabBarViewBrowserTest.IsNotCreatedInPopup
--OnDiskAppWithIncognitoProfile/NetworkContextConfigurationBrowserTest.CacheIsolation/0
--PopupTrackerBrowserTest.PopupInWindow_IsWindowTrue
--PopupTrackerBrowserTest.PopupNoRedirect_RedirectCountZero
--PopupTrackerBrowserTest.PopupRedirectsTwice_RedirectCountTwo
--SSLUITest.TestCloseTabWithUnsafePopup
diff --git a/testing/buildbot/test_suite_exceptions.pyl b/testing/buildbot/test_suite_exceptions.pyl
index bcd3087..dcc7e2a4 100644
--- a/testing/buildbot/test_suite_exceptions.pyl
+++ b/testing/buildbot/test_suite_exceptions.pyl
@@ -2487,16 +2487,6 @@
       },
     },
   },
-  'sync_integration_tests_wayland': {
-    'modifications': {
-      # CI Ozone/Wayland tester.
-      'Linux Tester (Ozone Wayland)': {
-        'args': [
-          '--test-launcher-filter-file=../../testing/buildbot/filters/ozone-linux.sync_integration_tests_wayland.filter',
-        ],
-      },
-    }
-  },
   'tab_capture_end2end_tests': {
     # Run these only on Release bots.
     'remove_from': [
diff --git a/testing/buildbot/variants.pyl b/testing/buildbot/variants.pyl
index 7bbbc42..d077b15 100644
--- a/testing/buildbot/variants.pyl
+++ b/testing/buildbot/variants.pyl
@@ -311,13 +311,13 @@
       '../../weblayer/browser/android/javatests/skew/expectations.txt',
       '--impl-version=90',
     ],
-    'identifier': 'Implementation Library Skew Tests For 90.0.4430.17',
+    'identifier': 'Implementation Library Skew Tests For 90.0.4430.19',
     'swarming': {
       'cipd_packages': [
         {
           'cipd_package': 'chromium/testing/weblayer-x86',
           'location': 'weblayer_instrumentation_test_M90',
-          'revision': 'version:90.0.4430.17',
+          'revision': 'version:90.0.4430.19',
         }
       ],
     },
@@ -383,13 +383,13 @@
       '../../weblayer/browser/android/javatests/skew/expectations.txt',
       '--impl-version=90',
     ],
-    'identifier': 'Implementation Library Skew Tests For 90.0.4430.17',
+    'identifier': 'Implementation Library Skew Tests For 90.0.4430.19',
     'swarming': {
       'cipd_packages': [
         {
           'cipd_package': 'chromium/testing/weblayer-x86',
           'location': 'weblayer_instrumentation_test_M90',
-          'revision': 'version:90.0.4430.17',
+          'revision': 'version:90.0.4430.19',
         }
       ],
     },
@@ -455,13 +455,13 @@
       '../../weblayer/browser/android/javatests/skew/expectations.txt',
       '--client-version=90',
     ],
-    'identifier': 'Client Library Skew Tests For 90.0.4430.17',
+    'identifier': 'Client Library Skew Tests For 90.0.4430.19',
     'swarming': {
       'cipd_packages': [
         {
           'cipd_package': 'chromium/testing/weblayer-x86',
           'location': 'weblayer_instrumentation_test_M90',
-          'revision': 'version:90.0.4430.17',
+          'revision': 'version:90.0.4430.19',
         }
       ],
     },
@@ -528,4 +528,4 @@
     },
     'identifier': 'OCTOPUS_TOT-1',
   },
-}
\ No newline at end of file
+}
diff --git a/testing/scripts/wpt_common.py b/testing/scripts/wpt_common.py
index a39e749a..4f257dc 100644
--- a/testing/scripts/wpt_common.py
+++ b/testing/scripts/wpt_common.py
@@ -152,6 +152,12 @@
             expected_text = expected_text.encode('utf8')
             actual_text = actual_text.encode('utf8')
         html_diff_content = html_diff(expected_text, actual_text)
+        if six.PY2:
+            # Ensure the diff itself is properly decoded, to avoid
+            # UnicodeDecodeErrors when writing to file. This can happen if
+            # the diff contains unicode characters but the file is written
+            # as ascii because of the default system-level encoding.
+            html_diff_content = unicode(html_diff_content, 'utf8')
         html_diff_subpath = self._write_text_artifact(
             test_failures.FILENAME_SUFFIX_HTML_DIFF, results_dir,
             path_so_far, html_diff_content, extension=".html")
diff --git a/third_party/android_deps/BUILD.gn b/third_party/android_deps/BUILD.gn
index b5cb2eb..6fce674 100644
--- a/third_party/android_deps/BUILD.gn
+++ b/third_party/android_deps/BUILD.gn
@@ -469,7 +469,7 @@
     # Omit the file since we use our own copy.
     jar_excluded_patterns +=
         [ "com/google/android/gms/common/internal/Preconditions.class" ]
-    deps += [ "//third_party/android_deps/local_modifications/preconditions:preconditions_gms_stub_java" ]
+    deps += [ "//third_party/android_deps/local_modifications/preconditions:preconditions_stub_java" ]
   }
 
   # https://crbug.com/989505
@@ -848,7 +848,7 @@
   if (!is_java_debug && !dcheck_always_on) {
     # Omit the file since we use our own copy.
     jar_excluded_patterns += [ "com/google/common/base/Preconditions.class" ]
-    deps += [ "//third_party/android_deps/local_modifications/preconditions:preconditions_guava_stub_java" ]
+    deps += [ "//third_party/android_deps/local_modifications/preconditions:preconditions_stub_java" ]
   }
 
   # Add a dep to com_google_guava_listenablefuture_java
diff --git a/third_party/android_deps/buildSrc/src/main/groovy/BuildConfigGenerator.groovy b/third_party/android_deps/buildSrc/src/main/groovy/BuildConfigGenerator.groovy
index 97a555e..07877050 100644
--- a/third_party/android_deps/buildSrc/src/main/groovy/BuildConfigGenerator.groovy
+++ b/third_party/android_deps/buildSrc/src/main/groovy/BuildConfigGenerator.groovy
@@ -611,16 +611,7 @@
           case "androidx_core_core":
           case "com_google_guava_guava_android":
           case "google_play_services_basement":
-              def preconditionsTarget = null
-              if (targetName == "androidx_core_core") {
-                  preconditionsTarget = "preconditions_androidx_stub_java"
-              }
-              if (targetName == "google_play_services_basement") {
-                  preconditionsTarget = "preconditions_gms_stub_java"
-              }
               if (targetName == "com_google_guava_guava_android") {
-                  preconditionsTarget = "preconditions_guava_stub_java"
-
                   // com_google_guava_guava_android is java_prebuilt().
                   sb.append("bypass_platform_checks = true")
               }
@@ -633,7 +624,7 @@
                 |     "${computePreconditionsClassForDep(dependencyId)}",
                 |   ]
                 |   deps += [
-                |     "//third_party/android_deps/local_modifications/preconditions:${preconditionsTarget}",
+                |     "//third_party/android_deps/local_modifications/preconditions:preconditions_stub_java",
                 |   ]
                 | }
                 |""".stripMargin())
diff --git a/third_party/android_deps/local_modifications/preconditions/BUILD.gn b/third_party/android_deps/local_modifications/preconditions/BUILD.gn
index 7670564..ffdf7037 100644
--- a/third_party/android_deps/local_modifications/preconditions/BUILD.gn
+++ b/third_party/android_deps/local_modifications/preconditions/BUILD.gn
@@ -7,23 +7,12 @@
 # Stub versions of Preconditions classes used when dchecks are off.
 # TODO(pkotwicz): Remove separate libraries once internal Chrome
 # uses :preconditions_stub_java
-java_group("preconditions_stub_java") {
-  deps = [
-    ":preconditions_gms_stub_java",
-    ":preconditions_guava_stub_java",
-  ]
-}
-
-android_library("preconditions_guava_stub_java") {
-  sources = [
-    "java/com/google/common/base/Preconditions.java",
-  ]
-}
-
-android_library("preconditions_gms_stub_java") {
+android_library("preconditions_stub_java") {
   sources = [
     "java/com/google/android/gms/common/internal/Preconditions.java",
+    "java/com/google/common/base/Preconditions.java",
   ]
+  deps = [ ":preconditions_androidx_stub_java" ]
 }
 
 android_library("preconditions_androidx_stub_java") {
diff --git a/third_party/blink/common/client_hints/client_hints.cc b/third_party/blink/common/client_hints/client_hints.cc
index 833602b..06b3138b 100644
--- a/third_party/blink/common/client_hints/client_hints.cc
+++ b/third_party/blink/common/client_hints/client_hints.cc
@@ -38,7 +38,7 @@
 
 const unsigned kClientHintsNumberOfLegacyHints = 4;
 
-const mojom::PermissionsPolicyFeature kClientHintsFeaturePolicyMapping[] = {
+const mojom::PermissionsPolicyFeature kClientHintsPermissionsPolicyMapping[] = {
     // Legacy Hints that are sent cross-origin regardless of Permissions Policy
     // when kAllowClientHintsToThirdParty is enabled.
     mojom::PermissionsPolicyFeature::kClientHintDeviceMemory,
@@ -67,7 +67,7 @@
     "Client Hint name table size must match network::mojom::WebClientHintsType "
     "range");
 
-static_assert(base::size(kClientHintsFeaturePolicyMapping) ==
+static_assert(base::size(kClientHintsPermissionsPolicyMapping) ==
                   kClientHintsMappingsCount,
               "Client Hint table sizes must be identical between names and "
               "feature policies");
@@ -153,7 +153,7 @@
              static_cast<network::mojom::WebClientHintsType>(i))) ||
         (permissions_policy &&
          !permissions_policy->IsFeatureEnabledForOrigin(
-             blink::kClientHintsFeaturePolicyMapping[i], origin))) {
+             blink::kClientHintsPermissionsPolicyMapping[i], origin))) {
       removed_headers->push_back(blink::kClientHintsHeaderMapping[i]);
     }
   }
diff --git a/third_party/blink/common/permissions_policy/permissions_policy_unittest.cc b/third_party/blink/common/permissions_policy/permissions_policy_unittest.cc
index de32c024..a382529 100644
--- a/third_party/blink/common/permissions_policy/permissions_policy_unittest.cc
+++ b/third_party/blink/common/permissions_policy/permissions_policy_unittest.cc
@@ -28,9 +28,9 @@
 
 }  // namespace
 
-class FeaturePolicyTest : public testing::Test {
+class PermissionsPolicyTest : public testing::Test {
  protected:
-  FeaturePolicyTest()
+  PermissionsPolicyTest()
       : feature_list_({{kDefaultOnFeature,
                         PermissionsPolicyFeatureDefault(
                             PermissionsPolicyFeatureDefault::EnableForAll)},
@@ -39,7 +39,7 @@
                             PermissionsPolicyFeatureDefault::EnableForSelf)}}) {
   }
 
-  ~FeaturePolicyTest() override = default;
+  ~PermissionsPolicyTest() override = default;
 
   std::unique_ptr<PermissionsPolicy> CreateFromParentPolicy(
       const PermissionsPolicy* parent,
@@ -73,7 +73,7 @@
   PermissionsPolicyFeatureList feature_list_;
 };
 
-TEST_F(FeaturePolicyTest, TestInitialPolicy) {
+TEST_F(PermissionsPolicyTest, TestInitialPolicy) {
   // +-------------+
   // |(1)Origin A  |
   // |No Policy    |
@@ -86,7 +86,7 @@
   EXPECT_TRUE(policy1->IsFeatureEnabled(kDefaultSelfFeature));
 }
 
-TEST_F(FeaturePolicyTest, TestInitialSameOriginChildPolicy) {
+TEST_F(PermissionsPolicyTest, TestInitialSameOriginChildPolicy) {
   // +-----------------+
   // |(1)Origin A      |
   // |No Policy        |
@@ -105,7 +105,7 @@
   EXPECT_TRUE(policy2->IsFeatureEnabled(kDefaultSelfFeature));
 }
 
-TEST_F(FeaturePolicyTest, TestInitialCrossOriginChildPolicy) {
+TEST_F(PermissionsPolicyTest, TestInitialCrossOriginChildPolicy) {
   // +-----------------+
   // |(1)Origin A      |
   // |No Policy        |
@@ -124,7 +124,7 @@
   EXPECT_FALSE(policy2->IsFeatureEnabled(kDefaultSelfFeature));
 }
 
-TEST_F(FeaturePolicyTest, TestCrossOriginChildCannotEnableFeature) {
+TEST_F(PermissionsPolicyTest, TestCrossOriginChildCannotEnableFeature) {
   // +----------------------------------------+
   // |(1) Origin A                            |
   // |No Policy                               |
@@ -145,7 +145,7 @@
   EXPECT_FALSE(policy2->IsFeatureEnabled(kDefaultSelfFeature));
 }
 
-TEST_F(FeaturePolicyTest, TestFrameSelfInheritance) {
+TEST_F(PermissionsPolicyTest, TestFrameSelfInheritance) {
   // +------------------------------------------+
   // |(1) Origin A                              |
   // |Feature-Policy: default-self 'self'       |
@@ -180,7 +180,7 @@
   EXPECT_FALSE(policy5->IsFeatureEnabled(kDefaultSelfFeature));
 }
 
-TEST_F(FeaturePolicyTest, TestReflexiveFrameSelfInheritance) {
+TEST_F(PermissionsPolicyTest, TestReflexiveFrameSelfInheritance) {
   // +------------------------------------+
   // |(1) Origin A                        |
   // |Feature-Policy: default-self 'self' |
@@ -208,7 +208,7 @@
   EXPECT_FALSE(policy3->IsFeatureEnabled(kDefaultSelfFeature));
 }
 
-TEST_F(FeaturePolicyTest, TestSelectiveFrameInheritance) {
+TEST_F(PermissionsPolicyTest, TestSelectiveFrameInheritance) {
   // +------------------------------------------+
   // |(1) Origin A                              |
   // |Feature-Policy: default-self OriginB      |
@@ -241,7 +241,7 @@
   EXPECT_FALSE(policy4->IsFeatureEnabled(kDefaultSelfFeature));
 }
 
-TEST_F(FeaturePolicyTest, TestSelectiveFrameInheritance2) {
+TEST_F(PermissionsPolicyTest, TestSelectiveFrameInheritance2) {
   // +------------------------------------------+
   // |(1) Origin A                              |
   // |Feature-Policy: default-self OriginB      |
@@ -276,7 +276,7 @@
   EXPECT_FALSE(policy4->IsFeatureEnabled(kDefaultSelfFeature));
 }
 
-TEST_F(FeaturePolicyTest, TestPolicyCanBlockSelf) {
+TEST_F(PermissionsPolicyTest, TestPolicyCanBlockSelf) {
   // +----------------------------------+
   // |(1)Origin A                       |
   // |Feature-Policy: default-on 'none' |
@@ -289,7 +289,7 @@
   EXPECT_FALSE(policy1->IsFeatureEnabled(kDefaultOnFeature));
 }
 
-TEST_F(FeaturePolicyTest, TestParentPolicyBlocksSameOriginChildPolicy) {
+TEST_F(PermissionsPolicyTest, TestParentPolicyBlocksSameOriginChildPolicy) {
   // +----------------------------------+
   // |(1)Origin A                       |
   // |Feature-Policy: default-on 'none' |
@@ -308,7 +308,7 @@
   EXPECT_FALSE(policy2->IsFeatureEnabled(kDefaultOnFeature));
 }
 
-TEST_F(FeaturePolicyTest, TestChildPolicyCanBlockSelf) {
+TEST_F(PermissionsPolicyTest, TestChildPolicyCanBlockSelf) {
   // +--------------------------------------+
   // |(1)Origin A                           |
   // |No Policy                             |
@@ -327,7 +327,7 @@
   EXPECT_FALSE(policy2->IsFeatureEnabled(kDefaultOnFeature));
 }
 
-TEST_F(FeaturePolicyTest, TestChildPolicyCanBlockChildren) {
+TEST_F(PermissionsPolicyTest, TestChildPolicyCanBlockChildren) {
   // +--------------------------------------+
   // |(1)Origin A                           |
   // |No Policy                             |
@@ -354,7 +354,7 @@
   EXPECT_FALSE(policy3->IsFeatureEnabled(kDefaultOnFeature));
 }
 
-TEST_F(FeaturePolicyTest, TestParentPolicyBlocksCrossOriginChildPolicy) {
+TEST_F(PermissionsPolicyTest, TestParentPolicyBlocksCrossOriginChildPolicy) {
   // +----------------------------------+
   // |(1)Origin A                       |
   // |Feature-Policy: default-on 'none' |
@@ -373,7 +373,7 @@
   EXPECT_FALSE(policy2->IsFeatureEnabled(kDefaultOnFeature));
 }
 
-TEST_F(FeaturePolicyTest, TestEnableForAllOrigins) {
+TEST_F(PermissionsPolicyTest, TestEnableForAllOrigins) {
   // +--------------------------------+
   // |(1) Origin A                    |
   // |Feature-Policy: default-self *  |
@@ -400,7 +400,7 @@
   EXPECT_FALSE(policy3->IsFeatureEnabled(kDefaultSelfFeature));
 }
 
-TEST_F(FeaturePolicyTest, TestEnableForAllOriginsAndDelegate) {
+TEST_F(PermissionsPolicyTest, TestEnableForAllOriginsAndDelegate) {
   // +--------------------------------------+
   // |(1) Origin A                          |
   // |Feature-Policy: default-self *        |
@@ -430,7 +430,7 @@
   EXPECT_FALSE(policy3->IsFeatureEnabled(kDefaultSelfFeature));
 }
 
-TEST_F(FeaturePolicyTest, TestDefaultOnStillNeedsSelf) {
+TEST_F(PermissionsPolicyTest, TestDefaultOnStillNeedsSelf) {
   // +---------------------------------------+
   // |(1) Origin A                           |
   // |Feature-Policy: default-on OriginB     |
@@ -460,7 +460,7 @@
   EXPECT_FALSE(policy4->IsFeatureEnabled(kDefaultOnFeature));
 }
 
-TEST_F(FeaturePolicyTest, TestDefaultOnEnablesForAllDescendants) {
+TEST_F(PermissionsPolicyTest, TestDefaultOnEnablesForAllDescendants) {
   // +----------------------------------------+
   // |(1) Origin A                            |
   // |Feature-Policy: default-on self OriginB |
@@ -491,7 +491,7 @@
   EXPECT_TRUE(policy4->IsFeatureEnabled(kDefaultOnFeature));
 }
 
-TEST_F(FeaturePolicyTest, TestDefaultSelfRequiresDelegation) {
+TEST_F(PermissionsPolicyTest, TestDefaultSelfRequiresDelegation) {
   // +---------------------------------------+
   // |(1) Origin A                           |
   // |Feature-Policy: default-self OriginB   |
@@ -522,7 +522,7 @@
   EXPECT_FALSE(policy4->IsFeatureEnabled(kDefaultSelfFeature));
 }
 
-TEST_F(FeaturePolicyTest, TestDefaultSelfRespectsSameOriginEmbedding) {
+TEST_F(PermissionsPolicyTest, TestDefaultSelfRespectsSameOriginEmbedding) {
   // +------------------------------------------+
   // |(1) Origin A                              |
   // |Feature-Policy: default-self self OriginB |
@@ -556,7 +556,7 @@
   EXPECT_FALSE(policy4->IsFeatureEnabled(kDefaultSelfFeature));
 }
 
-TEST_F(FeaturePolicyTest, TestDelegationRequiredAtAllLevels) {
+TEST_F(PermissionsPolicyTest, TestDelegationRequiredAtAllLevels) {
   // +------------------------------------+
   // |(1) Origin A                        |
   // |<iframe allow="default-self *">     |
@@ -587,7 +587,7 @@
   EXPECT_FALSE(policy3->IsFeatureEnabled(kDefaultSelfFeature));
 }
 
-TEST_F(FeaturePolicyTest, TestBlockedFrameCannotReenable) {
+TEST_F(PermissionsPolicyTest, TestBlockedFrameCannotReenable) {
   // +--------------------------------------+
   // |(1)Origin A                           |
   // |Feature-Policy: default-self 'self'   |
@@ -620,7 +620,7 @@
   EXPECT_FALSE(policy4->IsFeatureEnabled(kDefaultSelfFeature));
 }
 
-TEST_F(FeaturePolicyTest, TestEnabledFrameCanDelegate) {
+TEST_F(PermissionsPolicyTest, TestEnabledFrameCanDelegate) {
   // +---------------------------------------------------+
   // |(1) Origin A                                       |
   // |No Policy                                          |
@@ -651,7 +651,7 @@
   EXPECT_TRUE(policy3->IsFeatureEnabled(kDefaultSelfFeature));
 }
 
-TEST_F(FeaturePolicyTest, TestEnabledFrameCanDelegateByDefault) {
+TEST_F(PermissionsPolicyTest, TestEnabledFrameCanDelegateByDefault) {
   // +-----------------------------------------------+
   // |(1) Origin A                                   |
   // |Feature-Policy: default-on 'self' OriginB      |
@@ -683,7 +683,7 @@
   EXPECT_FALSE(policy4->IsFeatureEnabled(kDefaultOnFeature));
 }
 
-TEST_F(FeaturePolicyTest, TestFeaturesDontDelegateByDefault) {
+TEST_F(PermissionsPolicyTest, TestFeaturesDontDelegateByDefault) {
   // +-----------------------------------------------+
   // |(1) Origin A                                   |
   // |Feature-Policy: default-self 'self' OriginB    |
@@ -715,7 +715,7 @@
   EXPECT_FALSE(policy4->IsFeatureEnabled(kDefaultSelfFeature));
 }
 
-TEST_F(FeaturePolicyTest, TestFeaturesAreIndependent) {
+TEST_F(PermissionsPolicyTest, TestFeaturesAreIndependent) {
   // +-----------------------------------------------+
   // |(1) Origin A                                   |
   // |No Policy                                      |
@@ -762,7 +762,7 @@
 
 // Test frame policies
 
-TEST_F(FeaturePolicyTest, TestSimpleFramePolicy) {
+TEST_F(PermissionsPolicyTest, TestSimpleFramePolicy) {
   // +--------------------------------------+
   // |(1)Origin A                           |
   // |No Policy                             |
@@ -789,7 +789,7 @@
       policy2->IsFeatureEnabledForOrigin(kDefaultSelfFeature, origin_b_));
 }
 
-TEST_F(FeaturePolicyTest, TestAllOriginFramePolicy) {
+TEST_F(PermissionsPolicyTest, TestAllOriginFramePolicy) {
   // +--------------------------------+
   // |(1)Origin A                     |
   // |No Policy                       |
@@ -816,7 +816,7 @@
       policy2->IsFeatureEnabledForOrigin(kDefaultSelfFeature, origin_b_));
 }
 
-TEST_F(FeaturePolicyTest, TestFramePolicyCanBeFurtherDelegated) {
+TEST_F(PermissionsPolicyTest, TestFramePolicyCanBeFurtherDelegated) {
   // +------------------------------------------+
   // |(1)Origin A                               |
   // |No Policy                                 |
@@ -866,7 +866,7 @@
       policy4->IsFeatureEnabledForOrigin(kDefaultSelfFeature, origin_c_));
 }
 
-TEST_F(FeaturePolicyTest, TestDefaultOnCanBeDisabledByFramePolicy) {
+TEST_F(PermissionsPolicyTest, TestDefaultOnCanBeDisabledByFramePolicy) {
   // +-----------------------------------+
   // |(1)Origin A                        |
   // |No Policy                          |
@@ -912,7 +912,7 @@
       policy3->IsFeatureEnabledForOrigin(kDefaultOnFeature, origin_c_));
 }
 
-TEST_F(FeaturePolicyTest, TestFramePolicyModifiesHeaderPolicy) {
+TEST_F(PermissionsPolicyTest, TestFramePolicyModifiesHeaderPolicy) {
   // +---------------------------------------------+
   // |(1)Origin A                                  |
   // |Feature-Policy: default-self 'self' OriginB  |
@@ -957,7 +957,7 @@
       policy3->IsFeatureEnabledForOrigin(kDefaultSelfFeature, origin_b_));
 }
 
-TEST_F(FeaturePolicyTest, TestCombineFrameAndHeaderPolicies) {
+TEST_F(PermissionsPolicyTest, TestCombineFrameAndHeaderPolicies) {
   // +-----------------------------------------+
   // |(1)Origin A                              |
   // |No Policy                                |
@@ -1004,7 +1004,7 @@
       policy3->IsFeatureEnabledForOrigin(kDefaultSelfFeature, origin_c_));
 }
 
-TEST_F(FeaturePolicyTest, TestFeatureDeclinedAtTopLevel) {
+TEST_F(PermissionsPolicyTest, TestFeatureDeclinedAtTopLevel) {
   // +-----------------------------------------+
   // |(1)Origin A                              |
   // |Feature-Policy: default-self 'none'      |
@@ -1044,7 +1044,7 @@
       policy3->IsFeatureEnabledForOrigin(kDefaultSelfFeature, origin_a_));
 }
 
-TEST_F(FeaturePolicyTest, TestFeatureDelegatedAndAllowed) {
+TEST_F(PermissionsPolicyTest, TestFeatureDelegatedAndAllowed) {
   // +--------------------------------------------+
   // |(1)Origin A                                 |
   // |Feature-Policy: default-self 'self' OriginB |
@@ -1100,7 +1100,7 @@
       policy4->IsFeatureEnabledForOrigin(kDefaultSelfFeature, origin_b_));
 }
 
-TEST_F(FeaturePolicyTest, TestDefaultSandboxedFramePolicy) {
+TEST_F(PermissionsPolicyTest, TestDefaultSandboxedFramePolicy) {
   // +------------------+
   // |(1)Origin A       |
   // |No Policy         |
@@ -1127,7 +1127,7 @@
                                                   sandboxed_origin));
 }
 
-TEST_F(FeaturePolicyTest, TestSandboxedFramePolicyForAllOrigins) {
+TEST_F(PermissionsPolicyTest, TestSandboxedFramePolicyForAllOrigins) {
   // +----------------------------------------+
   // |(1)Origin A                             |
   // |No Policy                               |
@@ -1156,7 +1156,7 @@
                                                  sandboxed_origin));
 }
 
-TEST_F(FeaturePolicyTest, TestSandboxedFramePolicyForOpaqueSrcOrigin) {
+TEST_F(PermissionsPolicyTest, TestSandboxedFramePolicyForOpaqueSrcOrigin) {
   // +--------------------------------------+
   // |(1)Origin A                           |
   // |No Policy                             |
@@ -1185,7 +1185,7 @@
                                                  sandboxed_origin));
 }
 
-TEST_F(FeaturePolicyTest, TestSandboxedFrameFromHeaderPolicy) {
+TEST_F(PermissionsPolicyTest, TestSandboxedFrameFromHeaderPolicy) {
   // +--------------------------------------+
   // |(1)Origin A                           |
   // |Feature-Policy: default-self *        |
@@ -1212,7 +1212,7 @@
                                                   sandboxed_origin));
 }
 
-TEST_F(FeaturePolicyTest, TestSandboxedPolicyIsNotInherited) {
+TEST_F(PermissionsPolicyTest, TestSandboxedPolicyIsNotInherited) {
   // +----------------------------------------+
   // |(1)Origin A                             |
   // |No Policy                               |
@@ -1254,7 +1254,7 @@
                                                   sandboxed_origin_2));
 }
 
-TEST_F(FeaturePolicyTest, TestSandboxedPolicyCanBePropagated) {
+TEST_F(PermissionsPolicyTest, TestSandboxedPolicyCanBePropagated) {
   // +--------------------------------------------+
   // |(1)Origin A                                 |
   // |No Policy                                   |
@@ -1294,7 +1294,7 @@
                                                  sandboxed_origin_2));
 }
 
-TEST_F(FeaturePolicyTest, TestUndefinedFeaturesInFramePolicy) {
+TEST_F(PermissionsPolicyTest, TestUndefinedFeaturesInFramePolicy) {
   // +---------------------------------------------------+
   // |(1)Origin A                                        |
   // |No Policy                                          |
@@ -1331,7 +1331,7 @@
 // where this differs from the current feature policy algorithm are called
 // out specifically. See https://crbug.com/937131 for additional context.
 
-TEST_F(FeaturePolicyTest, ProposedTestImplicitPolicy) {
+TEST_F(PermissionsPolicyTest, ProposedTestImplicitPolicy) {
   // +-----------------+
   // |(1)Origin A      |
   // |No Policy        |
@@ -1363,7 +1363,7 @@
   EXPECT_FALSE(policy3->IsFeatureEnabled(kDefaultSelfFeature));
 }
 
-TEST_F(FeaturePolicyTest, ProposedTestCompletelyBlockedPolicy) {
+TEST_F(PermissionsPolicyTest, ProposedTestCompletelyBlockedPolicy) {
   // +------------------------------------+
   // |(1)Origin A                         |
   // |Feature-Policy: default-self 'none' |
@@ -1420,7 +1420,7 @@
   EXPECT_FALSE(policy6->IsFeatureEnabled(kDefaultSelfFeature));
 }
 
-TEST_F(FeaturePolicyTest, ProposedTestDisallowedCrossOriginChildPolicy) {
+TEST_F(PermissionsPolicyTest, ProposedTestDisallowedCrossOriginChildPolicy) {
   // +------------------------------------+
   // |(1)Origin A                         |
   // |Feature-Policy: default-self 'self' |
@@ -1483,7 +1483,7 @@
   EXPECT_FALSE(policy6->IsFeatureEnabled(kDefaultSelfFeature));
 }
 
-TEST_F(FeaturePolicyTest, ProposedTestAllowedCrossOriginChildPolicy) {
+TEST_F(PermissionsPolicyTest, ProposedTestAllowedCrossOriginChildPolicy) {
   // +-----------------------------------------------+
   // |(1)Origin A                                    |
   // |Feature-Policy: default-self 'self' OriginB;   |
@@ -1546,7 +1546,7 @@
   EXPECT_FALSE(policy6->IsFeatureEnabled(kDefaultSelfFeature));
 }
 
-TEST_F(FeaturePolicyTest, ProposedTestAllAllowedCrossOriginChildPolicy) {
+TEST_F(PermissionsPolicyTest, ProposedTestAllAllowedCrossOriginChildPolicy) {
   // +------------------------------------+
   // |(1)Origin A                         |
   // |Feature-Policy: default-self *      |
@@ -1608,7 +1608,7 @@
   EXPECT_FALSE(policy6->IsFeatureEnabled(kDefaultSelfFeature));
 }
 
-TEST_F(FeaturePolicyTest, ProposedTestNestedPolicyPropagates) {
+TEST_F(PermissionsPolicyTest, ProposedTestNestedPolicyPropagates) {
   // +-----------------------------------------------+
   // |(1)Origin A                                    |
   // |Feature-Policy: default-self 'self' OriginB;   |
diff --git a/third_party/blink/public/BUILD.gn b/third_party/blink/public/BUILD.gn
index caf809e..f5fb50c 100644
--- a/third_party/blink/public/BUILD.gn
+++ b/third_party/blink/public/BUILD.gn
@@ -241,7 +241,6 @@
     "platform/web_scrollbar_overlay_color_theme.h",
     "platform/web_security_origin.h",
     "platform/web_set_sink_id_callbacks.h",
-    "platform/web_size.h",
     "platform/web_source_buffer.h",
     "platform/web_source_buffer_client.h",
     "platform/web_spell_check_panel_host_client.h",
diff --git a/third_party/blink/public/common/client_hints/client_hints.h b/third_party/blink/public/common/client_hints/client_hints.h
index 7e81fdc..3b6844a 100644
--- a/third_party/blink/public/common/client_hints/client_hints.h
+++ b/third_party/blink/public/common/client_hints/client_hints.h
@@ -28,7 +28,7 @@
 // kDpr => kClientHintsDPR). The order matches the header mapping and the enum
 // order in services/network/public/mojom/web_client_hints_types.mojom
 BLINK_COMMON_EXPORT extern const mojom::PermissionsPolicyFeature
-    kClientHintsFeaturePolicyMapping[];
+    kClientHintsPermissionsPolicyMapping[];
 
 // The size of the mapping arrays.
 BLINK_COMMON_EXPORT extern const size_t kClientHintsMappingsCount;
diff --git a/third_party/blink/public/common/permissions_policy/permissions_policy.h b/third_party/blink/public/common/permissions_policy/permissions_policy.h
index 9e5c24a..05daf7fe 100644
--- a/third_party/blink/public/common/permissions_policy/permissions_policy.h
+++ b/third_party/blink/public/common/permissions_policy/permissions_policy.h
@@ -213,7 +213,7 @@
       mojom::PermissionsPolicyFeature feature) const;
 
  private:
-  friend class FeaturePolicyTest;
+  friend class PermissionsPolicyTest;
 
   PermissionsPolicy(url::Origin origin,
                     const PermissionsPolicyFeatureList& feature_list);
diff --git a/third_party/blink/public/platform/platform.h b/third_party/blink/public/platform/platform.h
index c70dd50..52cb54d 100644
--- a/third_party/blink/public/platform/platform.h
+++ b/third_party/blink/public/platform/platform.h
@@ -64,7 +64,6 @@
 #include "third_party/blink/public/platform/web_common.h"
 #include "third_party/blink/public/platform/web_data.h"
 #include "third_party/blink/public/platform/web_dedicated_worker_host_factory_client.h"
-#include "third_party/blink/public/platform/web_size.h"
 #include "third_party/blink/public/platform/web_string.h"
 #include "third_party/blink/public/platform/web_url_error.h"
 #include "third_party/blink/public/platform/web_url_loader.h"
@@ -644,10 +643,6 @@
 
   virtual bool IsWebRtcSrtpEncryptedHeadersEnabled() { return false; }
 
-  virtual base::Optional<WebString> WebRtcStunProbeTrialParameter() {
-    return base::nullopt;
-  }
-
   // TODO(qingsi): Consolidate the legacy |ip_handling_policy| with
   // |allow_mdns_obfuscation| following the latest spec on IP handling modes
   // with mDNS introduced
diff --git a/third_party/blink/public/platform/web_size.h b/third_party/blink/public/platform/web_size.h
deleted file mode 100644
index d8aac052b..0000000
--- a/third_party/blink/public/platform/web_size.h
+++ /dev/null
@@ -1,110 +0,0 @@
-/*
- * Copyright (C) 2009 Google Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- *     * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *     * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *     * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#ifndef THIRD_PARTY_BLINK_PUBLIC_PLATFORM_WEB_SIZE_H_
-#define THIRD_PARTY_BLINK_PUBLIC_PLATFORM_WEB_SIZE_H_
-
-#include "third_party/blink/public/platform/web_common.h"
-#include "ui/gfx/geometry/size.h"
-#include "ui/gfx/geometry/vector2d.h"
-
-#if INSIDE_BLINK
-#include "third_party/blink/renderer/platform/geometry/int_size.h"  // nogncheck
-#else
-#include <algorithm>
-#include <cmath>
-#endif
-
-namespace blink {
-
-struct WebSize {
-  int width;
-  int height;
-
-  bool IsEmpty() const { return width <= 0 || height <= 0; }
-
-  WebSize() : width(0), height(0) {}
-
-  WebSize(int width, int height) : width(width), height(height) {}
-
-#if INSIDE_BLINK
-  WebSize(const IntSize& s) : width(s.Width()), height(s.Height()) {}
-
-  WebSize& operator=(const IntSize& s) {
-    width = s.Width();
-    height = s.Height();
-    return *this;
-  }
-
-  operator IntSize() const { return IntSize(width, height); }
-
-  explicit WebSize(const gfx::Size& s) : width(s.width()), height(s.height()) {}
-  explicit WebSize(const gfx::Vector2d& v) : width(v.x()), height(v.y()) {}
-
-  // Note that this conversion clamps to non-negative values.
-  explicit operator gfx::Size() const { return gfx::Size(width, height); }
-
-  explicit operator gfx::Vector2d() const {
-    return gfx::Vector2d(width, height);
-  }
-#else
-  WebSize(const gfx::Size& s) : width(s.width()), height(s.height()) {}
-  WebSize(const gfx::Vector2d& v) : width(v.x()), height(v.y()) {}
-
-  WebSize& operator=(const gfx::Size& s) {
-    width = s.width();
-    height = s.height();
-    return *this;
-  }
-
-  WebSize& operator=(const gfx::Vector2d& v) {
-    width = v.x();
-    height = v.y();
-    return *this;
-  }
-
-  // Note that this conversion clamps to non-negative values.
-  operator gfx::Size() const { return gfx::Size(width, height); }
-
-  operator gfx::Vector2d() const { return gfx::Vector2d(width, height); }
-#endif
-};
-
-inline bool operator==(const WebSize& a, const WebSize& b) {
-  return a.width == b.width && a.height == b.height;
-}
-
-inline bool operator!=(const WebSize& a, const WebSize& b) {
-  return !(a == b);
-}
-
-}  // namespace blink
-
-#endif
diff --git a/third_party/blink/public/web/web_local_frame.h b/third_party/blink/public/web/web_local_frame.h
index 5d67e49..ee414a8b 100644
--- a/third_party/blink/public/web/web_local_frame.h
+++ b/third_party/blink/public/web/web_local_frame.h
@@ -37,7 +37,6 @@
 #include "third_party/blink/public/mojom/web_feature/web_feature.mojom-shared.h"
 #include "third_party/blink/public/platform/cross_variant_mojo_util.h"
 #include "third_party/blink/public/platform/task_type.h"
-#include "third_party/blink/public/platform/web_size.h"
 #include "third_party/blink/public/platform/web_url_error.h"
 #include "third_party/blink/public/platform/web_url_request.h"
 #include "third_party/blink/public/web/web_document_loader.h"
@@ -53,6 +52,7 @@
 
 namespace gfx {
 class Point;
+class ScrollOffset;
 }  // namespace gfx
 
 namespace ui {
@@ -677,8 +677,8 @@
   // not be accurate if the page layout is out-of-date.
 
   // The scroll offset from the top-left corner of the frame in pixels.
-  virtual WebSize GetScrollOffset() const = 0;
-  virtual void SetScrollOffset(const WebSize&) = 0;
+  virtual gfx::ScrollOffset GetScrollOffset() const = 0;
+  virtual void SetScrollOffset(const gfx::ScrollOffset&) = 0;
 
   // The size of the document in this frame.
   virtual gfx::Size DocumentSize() const = 0;
diff --git a/third_party/blink/public/web/web_remote_frame.h b/third_party/blink/public/web/web_remote_frame.h
index 68d2832..67a539f6 100644
--- a/third_party/blink/public/web/web_remote_frame.h
+++ b/third_party/blink/public/web/web_remote_frame.h
@@ -105,7 +105,7 @@
                                  const WebString& unique_name) = 0;
 
   // Sets the Permissions Policy header for the main frame.
-  virtual void SetReplicatedFeaturePolicyHeader(
+  virtual void SetReplicatedPermissionsPolicyHeader(
       const ParsedPermissionsPolicy& parsed_header) = 0;
 
   // Set frame enforcement of insecure request policy replicated from another
diff --git a/third_party/blink/public/web/web_settings.h b/third_party/blink/public/web/web_settings.h
index c72bddb..21070c1 100644
--- a/third_party/blink/public/web/web_settings.h
+++ b/third_party/blink/public/web/web_settings.h
@@ -39,7 +39,6 @@
 #include "third_party/blink/public/mojom/webpreferences/web_preferences.mojom-forward.h"
 #include "third_party/blink/public/platform/web_common.h"
 #include "third_party/blink/public/platform/web_effective_connection_type.h"
-#include "third_party/blink/public/platform/web_size.h"
 
 namespace blink {
 
diff --git a/third_party/blink/renderer/core/OWNERS b/third_party/blink/renderer/core/OWNERS
index 393b9d2..c9bdfac 100644
--- a/third_party/blink/renderer/core/OWNERS
+++ b/third_party/blink/renderer/core/OWNERS
@@ -42,6 +42,7 @@
 jfernandez@igalia.com
 jianli@chromium.org
 jochen@chromium.org
+junov@chromium.org
 kbr@chromium.org
 keishi@chromium.org
 kenneth.r.christiansen@intel.com
diff --git a/third_party/blink/renderer/core/animation/animation.cc b/third_party/blink/renderer/core/animation/animation.cc
index d8be49a4..e009476 100644
--- a/third_party/blink/renderer/core/animation/animation.cc
+++ b/third_party/blink/renderer/core/animation/animation.cc
@@ -2061,6 +2061,11 @@
   // time of an animation also involves:
   //   * Running the update an animation’s finished state procedure.
   //   * Queueing animation events.
+
+  if (!Outdated() && reason == kTimingUpdateForAnimationFrame &&
+      IsInDisplayLockedSubtree())
+    return true;
+
   ClearOutdated();
   bool idle = CalculateAnimationPlayState() == kIdle;
   if (!idle)
diff --git a/third_party/blink/renderer/core/animation/animation_test_helpers.cc b/third_party/blink/renderer/core/animation/animation_test_helpers.cc
index 081cd301..e804426 100644
--- a/third_party/blink/renderer/core/animation/animation_test_helpers.cc
+++ b/third_party/blink/renderer/core/animation/animation_test_helpers.cc
@@ -73,7 +73,7 @@
   // require our callers to properly register every animation they pass in
   // here, which the current tests do not do.
   auto style = ComputedStyle::Create();
-  StyleResolverState state(document, *element, style.get(), style.get());
+  StyleResolverState state(document, *element, StyleRequest(style.get()));
   state.SetStyle(style);
 
   ActiveInterpolationsMap map;
diff --git a/third_party/blink/renderer/core/animation/css/css_animations.cc b/third_party/blink/renderer/core/animation/css/css_animations.cc
index 18dcabd..c29ba00 100644
--- a/third_party/blink/renderer/core/animation/css/css_animations.cc
+++ b/third_party/blink/renderer/core/animation/css/css_animations.cc
@@ -676,7 +676,7 @@
       if (name == CSSAnimationData::InitialName())
         continue;
 
-      // Find n where this is the nth occurence of this animation name.
+      // Find n where this is the nth occurrence of this animation name.
       wtf_size_t name_index = 0;
       for (wtf_size_t j = 0; j < i; j++) {
         if (name_list[j] == name)
@@ -722,7 +722,6 @@
 
       if (existing_animation) {
         cancel_running_animation_flags[existing_animation_index] = false;
-
         CSSAnimation* animation =
             DynamicTo<CSSAnimation>(existing_animation->animation.Get());
         animation->SetAnimationIndex(i);
diff --git a/third_party/blink/renderer/core/css/counter_style_map_test.cc b/third_party/blink/renderer/core/css/counter_style_map_test.cc
index 8bd6373..99dbdff 100644
--- a/third_party/blink/renderer/core/css/counter_style_map_test.cc
+++ b/third_party/blink/renderer/core/css/counter_style_map_test.cc
@@ -205,12 +205,4 @@
   EXPECT_EQ("decimal", new_bar.GetExtendedStyle().GetName());
 }
 
-class CounterStyleInitiallyDisabledTest
-    : private ScopedCSSAtRuleCounterStyleForTest,
-      public PageTestBase {
- public:
-  CounterStyleInitiallyDisabledTest()
-      : ScopedCSSAtRuleCounterStyleForTest(false) {}
-};
-
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/css/resolver/matched_properties_cache_test.cc b/third_party/blink/renderer/core/css/resolver/matched_properties_cache_test.cc
index 0803cfc..8c922020 100644
--- a/third_party/blink/renderer/core/css/resolver/matched_properties_cache_test.cc
+++ b/third_party/blink/renderer/core/css/resolver/matched_properties_cache_test.cc
@@ -64,8 +64,8 @@
   const CachedMatchedProperties* Find(const TestKey& key,
                                       const ComputedStyle& style,
                                       const ComputedStyle& parent_style) {
-    StyleResolverState state(document_, *document_.body(), &parent_style,
-                             &parent_style);
+    StyleResolverState state(document_, *document_.body(),
+                             StyleRequest(&parent_style));
     state.SetStyle(ComputedStyle::Clone(style));
     return cache_.Find(key.InnerKey(), state);
   }
diff --git a/third_party/blink/renderer/core/css/resolver/style_builder_test.cc b/third_party/blink/renderer/core/css/resolver/style_builder_test.cc
index 323666b..cee6060d 100644
--- a/third_party/blink/renderer/core/css/resolver/style_builder_test.cc
+++ b/third_party/blink/renderer/core/css/resolver/style_builder_test.cc
@@ -38,7 +38,7 @@
       style->SetWritingMode(WritingMode::kVerticalLr);
 
       StyleResolverState state(GetDocument(), *GetDocument().body(),
-                               parent_style.get(), parent_style.get());
+                               StyleRequest(parent_style.get()));
       state.SetStyle(style);
 
       ASSERT_FALSE(state.GetFontBuilder().FontDirty());
@@ -70,7 +70,7 @@
       style->SetTextOrientation(ETextOrientation::kUpright);
 
       StyleResolverState state(GetDocument(), *GetDocument().body(),
-                               parent_style.get(), parent_style.get());
+                               StyleRequest(parent_style.get()));
       state.SetStyle(style);
 
       ASSERT_FALSE(state.GetFontBuilder().FontDirty());
@@ -85,7 +85,7 @@
   auto parent_style = ComputedStyle::Create();
   auto style = ComputedStyle::Create();
   StyleResolverState state(GetDocument(), *GetDocument().body(),
-                           parent_style.get(), parent_style.get());
+                           StyleRequest(parent_style.get()));
   state.SetStyle(style);
   EXPECT_FALSE(style->HasExplicitInheritance());
 
diff --git a/third_party/blink/renderer/core/css/resolver/style_resolver.cc b/third_party/blink/renderer/core/css/resolver/style_resolver.cc
index ab4d7286..448804d 100644
--- a/third_party/blink/renderer/core/css/resolver/style_resolver.cc
+++ b/third_party/blink/renderer/core/css/resolver/style_resolver.cc
@@ -988,8 +988,8 @@
     double offset) {
   // TODO(alancutter): Avoid creating a StyleResolverState just to apply a
   // single value on a ComputedStyle.
-  StyleResolverState state(element.GetDocument(), element, parent_style,
-                           parent_style);
+  StyleResolverState state(element.GetDocument(), element,
+                           StyleRequest(parent_style));
   state.SetStyle(ComputedStyle::Clone(base_style));
   if (value) {
     STACK_UNINITIALIZED StyleCascade cascade(state);
@@ -1016,7 +1016,7 @@
     return initial_style;
 
   StyleResolverState state(GetDocument(), *GetDocument().documentElement(),
-                           initial_style.get(), initial_style.get());
+                           StyleRequest(initial_style.get()));
 
   scoped_refptr<ComputedStyle> style = ComputedStyle::Create();
   const ComputedStyle* root_element_style =
@@ -1603,7 +1603,7 @@
   };
 
   // TODO(timloh): This is weird, the style is being used as its own parent
-  StyleResolverState state(GetDocument(), element, style, style);
+  StyleResolverState state(GetDocument(), element, StyleRequest(style));
   state.SetStyle(style);
 
   for (const CSSProperty* property : properties) {
diff --git a/third_party/blink/renderer/core/css/resolver/style_resolver_state.cc b/third_party/blink/renderer/core/css/resolver/style_resolver_state.cc
index 09010d2..01ec7c62 100644
--- a/third_party/blink/renderer/core/css/resolver/style_resolver_state.cc
+++ b/third_party/blink/renderer/core/css/resolver/style_resolver_state.cc
@@ -34,25 +34,22 @@
 
 namespace blink {
 
-StyleResolverState::StyleResolverState(
-    Document& document,
-    Element& element,
-    PseudoElement* pseudo_element,
-    StyleRequest::RequestType pseudo_request_type,
-    ElementType element_type,
-    const ComputedStyle* parent_style,
-    const ComputedStyle* layout_parent_style)
+StyleResolverState::StyleResolverState(Document& document,
+                                       Element& element,
+                                       const StyleRequest& style_request)
     : element_context_(element),
       document_(&document),
-      parent_style_(parent_style),
-      layout_parent_style_(layout_parent_style),
-      pseudo_request_type_(pseudo_request_type),
+      parent_style_(style_request.parent_override),
+      layout_parent_style_(style_request.layout_parent_override),
+      pseudo_request_type_(style_request.type),
       font_builder_(&document),
+      pseudo_element_(element.GetPseudoElement(style_request.pseudo_id)),
       element_style_resources_(GetElement(),
                                document.DevicePixelRatio(),
-                               pseudo_element),
-      pseudo_element_(pseudo_element),
-      element_type_(element_type) {
+                               pseudo_element_),
+      element_type_(style_request.IsPseudoStyleRequest()
+                        ? ElementType::kPseudoElement
+                        : ElementType::kElement) {
   DCHECK(!!parent_style_ == !!layout_parent_style_);
 
   if (!parent_style_) {
@@ -68,46 +65,6 @@
   DCHECK(document.IsActive());
 }
 
-StyleResolverState::StyleResolverState(Document& document,
-                                       Element& element,
-                                       const ComputedStyle* parent_style,
-                                       const ComputedStyle* layout_parent_style)
-    : StyleResolverState(document,
-                         element,
-                         nullptr /* pseudo_element */,
-                         StyleRequest::kForRenderer,
-                         ElementType::kElement,
-                         parent_style,
-                         layout_parent_style) {}
-
-StyleResolverState::StyleResolverState(
-    Document& document,
-    Element& element,
-    PseudoId pseudo_id,
-    StyleRequest::RequestType pseudo_request_type,
-    const ComputedStyle* parent_style,
-    const ComputedStyle* layout_parent_style)
-    : StyleResolverState(document,
-                         element,
-                         element.GetPseudoElement(pseudo_id),
-                         pseudo_request_type,
-                         ElementType::kPseudoElement,
-                         parent_style,
-                         layout_parent_style) {}
-
-StyleResolverState::StyleResolverState(Document& document,
-                                       Element& element,
-                                       const StyleRequest& style_request)
-    : StyleResolverState(document,
-                         element,
-                         element.GetPseudoElement(style_request.pseudo_id),
-                         style_request.type,
-                         style_request.IsPseudoStyleRequest()
-                             ? ElementType::kPseudoElement
-                             : ElementType::kElement,
-                         style_request.parent_override,
-                         style_request.layout_parent_override) {}
-
 StyleResolverState::~StyleResolverState() {
   // For performance reasons, explicitly clear HeapVectors and
   // HeapHashMaps to avoid giving a pressure on Oilpan's GC.
diff --git a/third_party/blink/renderer/core/css/resolver/style_resolver_state.h b/third_party/blink/renderer/core/css/resolver/style_resolver_state.h
index b7b2db29..8f9278d8 100644
--- a/third_party/blink/renderer/core/css/resolver/style_resolver_state.h
+++ b/third_party/blink/renderer/core/css/resolver/style_resolver_state.h
@@ -53,17 +53,7 @@
   enum class ElementType { kElement, kPseudoElement };
 
  public:
-  StyleResolverState(Document&,
-                     Element&,
-                     const ComputedStyle* parent_style = nullptr,
-                     const ComputedStyle* layout_parent_style = nullptr);
-  StyleResolverState(Document&,
-                     Element&,
-                     PseudoId,
-                     StyleRequest::RequestType,
-                     const ComputedStyle* parent_style,
-                     const ComputedStyle* layout_parent_style);
-  StyleResolverState(Document&, Element&, const StyleRequest&);
+  StyleResolverState(Document&, Element&, const StyleRequest& = StyleRequest());
   StyleResolverState(const StyleResolverState&) = delete;
   StyleResolverState& operator=(const StyleResolverState&) = delete;
   ~StyleResolverState();
@@ -182,14 +172,6 @@
   void SetHadNoMatchedProperties() { had_no_matched_properties_ = true; }
 
  private:
-  StyleResolverState(Document&,
-                     Element&,
-                     PseudoElement*,
-                     StyleRequest::RequestType,
-                     ElementType,
-                     const ComputedStyle* parent_style,
-                     const ComputedStyle* layout_parent_style);
-
   CSSToLengthConversionData UnzoomedLengthConversionData(
       const ComputedStyle* font_style) const;
 
@@ -215,8 +197,8 @@
 
   FontBuilder font_builder_;
 
+  PseudoElement* pseudo_element_;
   ElementStyleResources element_style_resources_;
-  Element* pseudo_element_;
   ElementType element_type_;
 
   // True if the base style can be cached to optimize style recalculations for
diff --git a/third_party/blink/renderer/core/css/style_request.h b/third_party/blink/renderer/core/css/style_request.h
index c2e702d1..394f6e2 100644
--- a/third_party/blink/renderer/core/css/style_request.h
+++ b/third_party/blink/renderer/core/css/style_request.h
@@ -52,6 +52,10 @@
   ScrollbarPart scrollbar_part{kNoPart};
   CustomScrollbar* scrollbar{nullptr};
 
+  explicit StyleRequest(const ComputedStyle* parent_override)
+      : parent_override(parent_override),
+        layout_parent_override(parent_override) {}
+
   StyleRequest(PseudoId pseudo_id, const ComputedStyle* parent_override)
       : parent_override(parent_override),
         layout_parent_override(parent_override),
diff --git a/third_party/blink/renderer/core/document_transition/document_transition_test.cc b/third_party/blink/renderer/core/document_transition/document_transition_test.cc
index eed1d27..38b6fcb 100644
--- a/third_party/blink/renderer/core/document_transition/document_transition_test.cc
+++ b/third_party/blink/renderer/core/document_transition/document_transition_test.cc
@@ -133,17 +133,6 @@
 
   directive = request->ConstructDirective();
   EXPECT_EQ(directive.effect(), DocumentTransition::Request::Effect::kExplode);
-
-  // Test invalid effect parsing.
-  DocumentTransitionInit invalid_init;
-  invalid_init.setRootTransition("invalid effect");
-  transition->prepare(script_state, &invalid_init, exception_state);
-
-  request = transition->TakePendingRequest();
-  ASSERT_TRUE(request);
-
-  directive = request->ConstructDirective();
-  EXPECT_EQ(directive.effect(), DocumentTransition::Request::Effect::kNone);
 }
 
 TEST_F(DocumentTransitionTest, AdditionalPrepareAfterPreparedSucceeds) {
diff --git a/third_party/blink/renderer/core/execution_context/remote_security_context.cc b/third_party/blink/renderer/core/execution_context/remote_security_context.cc
index da11092..a9a7a380 100644
--- a/third_party/blink/renderer/core/execution_context/remote_security_context.cc
+++ b/third_party/blink/renderer/core/execution_context/remote_security_context.cc
@@ -38,7 +38,7 @@
   }
 }
 
-void RemoteSecurityContext::InitializeFeaturePolicy(
+void RemoteSecurityContext::InitializePermissionsPolicy(
     const ParsedPermissionsPolicy& parsed_header,
     const ParsedPermissionsPolicy& container_policy,
     const PermissionsPolicy* parent_permissions_policy) {
diff --git a/third_party/blink/renderer/core/execution_context/remote_security_context.h b/third_party/blink/renderer/core/execution_context/remote_security_context.h
index cf40400..35f3dcb 100644
--- a/third_party/blink/renderer/core/execution_context/remote_security_context.h
+++ b/third_party/blink/renderer/core/execution_context/remote_security_context.h
@@ -31,7 +31,7 @@
   //   policies in a parent browsing context (frame).
   // Note that |parent_permissions_policy| is null, and |container_policy| is
   // empty for a top-level security context.
-  void InitializeFeaturePolicy(
+  void InitializePermissionsPolicy(
       const ParsedPermissionsPolicy& parsed_header,
       const ParsedPermissionsPolicy& container_policy,
       const PermissionsPolicy* parent_permissions_policy);
diff --git a/third_party/blink/renderer/core/execution_context/security_context.cc b/third_party/blink/renderer/core/execution_context/security_context.cc
index 6d280bf..d39b261 100644
--- a/third_party/blink/renderer/core/execution_context/security_context.cc
+++ b/third_party/blink/renderer/core/execution_context/security_context.cc
@@ -142,12 +142,12 @@
   sandbox_flags_ = flags;
 }
 
-void SecurityContext::SetFeaturePolicy(
+void SecurityContext::SetPermissionsPolicy(
     std::unique_ptr<PermissionsPolicy> permissions_policy) {
   permissions_policy_ = std::move(permissions_policy);
 }
 
-void SecurityContext::SetReportOnlyFeaturePolicy(
+void SecurityContext::SetReportOnlyPermissionsPolicy(
     std::unique_ptr<PermissionsPolicy> permissions_policy) {
   report_only_permissions_policy_ = std::move(permissions_policy);
 }
diff --git a/third_party/blink/renderer/core/execution_context/security_context.h b/third_party/blink/renderer/core/execution_context/security_context.h
index 759d59fc..a33d82a 100644
--- a/third_party/blink/renderer/core/execution_context/security_context.h
+++ b/third_party/blink/renderer/core/execution_context/security_context.h
@@ -133,14 +133,14 @@
     return insecure_request_policy_;
   }
 
-  const PermissionsPolicy* GetFeaturePolicy() const {
+  const PermissionsPolicy* GetPermissionsPolicy() const {
     return permissions_policy_.get();
   }
-  const PermissionsPolicy* GetReportOnlyFeaturePolicy() const {
+  const PermissionsPolicy* GetReportOnlyPermissionsPolicy() const {
     return report_only_permissions_policy_.get();
   }
-  void SetFeaturePolicy(std::unique_ptr<PermissionsPolicy>);
-  void SetReportOnlyFeaturePolicy(std::unique_ptr<PermissionsPolicy>);
+  void SetPermissionsPolicy(std::unique_ptr<PermissionsPolicy>);
+  void SetReportOnlyPermissionsPolicy(std::unique_ptr<PermissionsPolicy>);
 
   const DocumentPolicy* GetDocumentPolicy() const {
     return document_policy_.get();
diff --git a/third_party/blink/renderer/core/execution_context/security_context_init.cc b/third_party/blink/renderer/core/execution_context/security_context_init.cc
index 342f0f2..f3ea66e 100644
--- a/third_party/blink/renderer/core/execution_context/security_context_init.cc
+++ b/third_party/blink/renderer/core/execution_context/security_context_init.cc
@@ -119,7 +119,7 @@
   }
 }
 
-void SecurityContextInit::ApplyFeaturePolicy(
+void SecurityContextInit::ApplyPermissionsPolicy(
     LocalFrame* frame,
     const ResourceResponse& response,
     const base::Optional<WebOriginPolicy>& origin_policy,
@@ -127,7 +127,7 @@
   // If we are a HTMLViewSourceDocument we use container, header or
   // inherited policies. https://crbug.com/898688.
   if (frame->InViewSourceMode()) {
-    execution_context_->GetSecurityContext().SetFeaturePolicy(
+    execution_context_->GetSecurityContext().SetPermissionsPolicy(
         PermissionsPolicy::CreateFromParentPolicy(
             nullptr, {},
             execution_context_->GetSecurityOrigin()->ToUrlOrigin()));
@@ -214,13 +214,13 @@
   std::unique_ptr<PermissionsPolicy> permissions_policy;
   auto* parent_permissions_policy =
       frame->Tree().Parent()
-          ? frame->Tree().Parent()->GetSecurityContext()->GetFeaturePolicy()
+          ? frame->Tree().Parent()->GetSecurityContext()->GetPermissionsPolicy()
           : nullptr;
   permissions_policy = PermissionsPolicy::CreateFromParentPolicy(
       parent_permissions_policy, container_policy,
       execution_context_->GetSecurityOrigin()->ToUrlOrigin());
   permissions_policy->SetHeaderPolicy(permissions_policy_header_);
-  execution_context_->GetSecurityContext().SetFeaturePolicy(
+  execution_context_->GetSecurityContext().SetPermissionsPolicy(
       std::move(permissions_policy));
 
   // Report-only permissions policy only takes effect when it is stricter than
@@ -238,17 +238,18 @@
             execution_context_->GetSecurityOrigin()->ToUrlOrigin());
     report_only_policy->SetHeaderPolicy(
         parsed_report_only_permissions_policy_header);
-    execution_context_->GetSecurityContext().SetReportOnlyFeaturePolicy(
+    execution_context_->GetSecurityContext().SetReportOnlyPermissionsPolicy(
         std::move(report_only_policy));
   }
 }
 
-void SecurityContextInit::InitFeaturePolicyFrom(const SecurityContext& other) {
+void SecurityContextInit::InitPermissionsPolicyFrom(
+    const SecurityContext& other) {
   auto& security_context = execution_context_->GetSecurityContext();
-  security_context.SetFeaturePolicy(
-      PermissionsPolicy::CopyStateFrom(other.GetFeaturePolicy()));
-  security_context.SetReportOnlyFeaturePolicy(
-      PermissionsPolicy::CopyStateFrom(other.GetReportOnlyFeaturePolicy()));
+  security_context.SetPermissionsPolicy(
+      PermissionsPolicy::CopyStateFrom(other.GetPermissionsPolicy()));
+  security_context.SetReportOnlyPermissionsPolicy(
+      PermissionsPolicy::CopyStateFrom(other.GetReportOnlyPermissionsPolicy()));
 }
 
 void SecurityContextInit::InitDocumentPolicyFrom(const SecurityContext& other) {
diff --git a/third_party/blink/renderer/core/execution_context/security_context_init.h b/third_party/blink/renderer/core/execution_context/security_context_init.h
index 2ca7353d..21bc6d2d 100644
--- a/third_party/blink/renderer/core/execution_context/security_context_init.h
+++ b/third_party/blink/renderer/core/execution_context/security_context_init.h
@@ -34,7 +34,7 @@
   // Used to carry permissions policy information from previous document
   // to current document during XSLT navigation, because XSLT navigation
   // does not have header information available.
-  void InitFeaturePolicyFrom(const SecurityContext& other);
+  void InitPermissionsPolicyFrom(const SecurityContext& other);
 
   // Init |document_policy_| and |report_only_document_policy_| by copying
   // state from another security context instance.
@@ -43,15 +43,16 @@
   // does not have header information available.
   void InitDocumentPolicyFrom(const SecurityContext& other);
 
-  void ApplyFeaturePolicy(LocalFrame* frame,
-                          const ResourceResponse& response,
-                          const base::Optional<WebOriginPolicy>& origin_policy,
-                          const FramePolicy& frame_policy);
+  void ApplyPermissionsPolicy(
+      LocalFrame* frame,
+      const ResourceResponse& response,
+      const base::Optional<WebOriginPolicy>& origin_policy,
+      const FramePolicy& frame_policy);
   void ApplyDocumentPolicy(
       DocumentPolicy::ParsedDocumentPolicy& document_policy,
       const String& report_only_document_policy_header);
 
-  const ParsedPermissionsPolicy& FeaturePolicyHeader() const {
+  const ParsedPermissionsPolicy& PermissionsPolicyHeader() const {
     return permissions_policy_header_;
   }
 
diff --git a/third_party/blink/renderer/core/exported/web_dev_tools_agent_impl.h b/third_party/blink/renderer/core/exported/web_dev_tools_agent_impl.h
index e6a27b7..4f52bc8 100644
--- a/third_party/blink/renderer/core/exported/web_dev_tools_agent_impl.h
+++ b/third_party/blink/renderer/core/exported/web_dev_tools_agent_impl.h
@@ -36,7 +36,6 @@
 #include "mojo/public/cpp/bindings/pending_associated_receiver.h"
 #include "mojo/public/cpp/bindings/pending_associated_remote.h"
 #include "third_party/blink/public/platform/web_input_event_result.h"
-#include "third_party/blink/public/platform/web_size.h"
 #include "third_party/blink/renderer/core/core_export.h"
 #include "third_party/blink/renderer/core/inspector/devtools_agent.h"
 #include "third_party/blink/renderer/core/inspector/inspector_layer_tree_agent.h"
diff --git a/third_party/blink/renderer/core/exported/web_page_popup_impl.cc b/third_party/blink/renderer/core/exported/web_page_popup_impl.cc
index b7fd7ea2..b1e37032 100644
--- a/third_party/blink/renderer/core/exported/web_page_popup_impl.cc
+++ b/third_party/blink/renderer/core/exported/web_page_popup_impl.cc
@@ -684,8 +684,8 @@
   SetWindowRect(IntRect(window_rect_in_dips));
 
   if (page_) {
-    MainFrame().View()->Resize(WebSize(new_size_in_viewport));
-    page_->GetVisualViewport().SetSize(WebSize(new_size_in_viewport));
+    MainFrame().View()->Resize(IntSize(new_size_in_viewport));
+    page_->GetVisualViewport().SetSize(IntSize(new_size_in_viewport));
   }
 }
 
diff --git a/third_party/blink/renderer/core/exported/web_plugin_container_test.cc b/third_party/blink/renderer/core/exported/web_plugin_container_test.cc
index 3c6feb6a..a93b9e0c 100644
--- a/third_party/blink/renderer/core/exported/web_plugin_container_test.cc
+++ b/third_party/blink/renderer/core/exported/web_plugin_container_test.cc
@@ -1325,7 +1325,8 @@
       web_view->SmoothScroll(root_document_scroll_to.Width(),
                              root_document_scroll_to.Height(),
                              base::TimeDelta());
-      iframe->SetScrollOffset(iframe_scroll_to);
+      iframe->SetScrollOffset(gfx::ScrollOffset(iframe_scroll_to.Width(),
+                                                iframe_scroll_to.Height()));
       UpdateAllLifecyclePhases(web_view);
       RunPendingTasks();
 
diff --git a/third_party/blink/renderer/core/exported/web_view_impl.cc b/third_party/blink/renderer/core/exported/web_view_impl.cc
index 0a3218e..2b87dde5 100644
--- a/third_party/blink/renderer/core/exported/web_view_impl.cc
+++ b/third_party/blink/renderer/core/exported/web_view_impl.cc
@@ -658,12 +658,13 @@
   DCHECK(MainFrame());
   DCHECK(MainFrame()->IsWebLocalFrame());
   gfx::Size max_size = MainFrame()->ToWebLocalFrame()->DocumentSize();
-  IntSize scroll_offset = MainFrame()->ToWebLocalFrame()->GetScrollOffset();
+  gfx::ScrollOffset scroll_offset =
+      MainFrame()->ToWebLocalFrame()->GetScrollOffset();
 
   int left_margin = target_margin;
   int right_margin = target_margin;
 
-  const int absolute_source_x = source.x() + scroll_offset.Width();
+  const int absolute_source_x = source.x() + scroll_offset.x();
   if (left_margin > absolute_source_x) {
     left_margin = absolute_source_x;
     right_margin = std::max(left_margin, minimum_margin);
@@ -680,7 +681,7 @@
   const int new_x = source.x() - left_margin;
 
   DCHECK_GE(new_width, 0);
-  DCHECK_LE(scroll_offset.Width() + new_x + new_width, max_size.width());
+  DCHECK_LE(scroll_offset.x() + new_x + new_width, max_size.width());
 
   return gfx::Rect(new_x, source.y(), new_width, source.height());
 }
@@ -1076,7 +1077,7 @@
 }
 
 void WebViewImpl::ResizeVisualViewport(const gfx::Size& new_size) {
-  GetPage()->GetVisualViewport().SetSize(WebSize(new_size));
+  GetPage()->GetVisualViewport().SetSize(IntSize(new_size));
   GetPage()->GetVisualViewport().ClampToBoundaries();
 }
 
diff --git a/third_party/blink/renderer/core/exported/web_view_test.cc b/third_party/blink/renderer/core/exported/web_view_test.cc
index bfb7c7c..605cee4 100644
--- a/third_party/blink/renderer/core/exported/web_view_test.cc
+++ b/third_party/blink/renderer/core/exported/web_view_test.cc
@@ -65,7 +65,6 @@
 #include "third_party/blink/public/mojom/manifest/display_mode.mojom-shared.h"
 #include "third_party/blink/public/platform/scheduler/test/renderer_scheduler_test_support.h"
 #include "third_party/blink/public/platform/web_drag_data.h"
-#include "third_party/blink/public/platform/web_size.h"
 #include "third_party/blink/public/platform/web_url_loader_mock_factory.h"
 #include "third_party/blink/public/public_buildflags.h"
 #include "third_party/blink/public/test/test_web_frame_content_dumper.h"
@@ -1568,8 +1567,7 @@
       web_view_helper_.InitializeAndLoad(base_url_ + "form_with_input.html");
   web_view->MainFrameViewWidget()->Resize(gfx::Size(800, 600));
   web_view->MainFrameImpl()->GetFrame()->SetInitialFocus(false);
-  EXPECT_EQ(0, web_view->MainFrameImpl()->GetScrollOffset().width);
-  EXPECT_EQ(0, web_view->MainFrameImpl()->GetScrollOffset().height);
+  EXPECT_EQ(gfx::ScrollOffset(), web_view->MainFrameImpl()->GetScrollOffset());
 
   // Set up a composition from existing text that needs to be committed.
   Vector<ImeTextSpan> empty_ime_text_spans;
@@ -1581,8 +1579,8 @@
   Element* element = static_cast<Element*>(
       web_view->MainFrameImpl()->GetDocument().GetElementById("btn"));
   element->scrollIntoView();
-  float offset_height = web_view->MainFrameImpl()->GetScrollOffset().height;
-  EXPECT_EQ(0, web_view->MainFrameImpl()->GetScrollOffset().width);
+  float offset_height = web_view->MainFrameImpl()->GetScrollOffset().y();
+  EXPECT_EQ(0, web_view->MainFrameImpl()->GetScrollOffset().x());
   EXPECT_LT(0, offset_height);
 
   WebTextInputInfo info = frame->GetInputMethodController()->TextInputInfo();
@@ -1592,8 +1590,8 @@
   frame->FrameWidget()
       ->GetActiveWebInputMethodController()
       ->FinishComposingText(WebInputMethodController::kDoNotKeepSelection);
-  EXPECT_EQ(0, web_view->MainFrameImpl()->GetScrollOffset().width);
-  EXPECT_EQ(offset_height, web_view->MainFrameImpl()->GetScrollOffset().height);
+  EXPECT_EQ(0, web_view->MainFrameImpl()->GetScrollOffset().x());
+  EXPECT_EQ(offset_height, web_view->MainFrameImpl()->GetScrollOffset().y());
 }
 
 TEST_F(WebViewTest, InsertNewLinePlacementAfterFinishComposingText) {
@@ -2426,15 +2424,15 @@
       web_view_helper_.InitializeAndLoad(base_url_ + "200-by-300.html");
   web_view_impl->MainFrameViewWidget()->Resize(gfx::Size(100, 150));
   UpdateAllLifecyclePhases();
-  EXPECT_EQ(0, web_view_impl->MainFrameImpl()->GetScrollOffset().width);
-  EXPECT_EQ(0, web_view_impl->MainFrameImpl()->GetScrollOffset().height);
+  EXPECT_EQ(gfx::ScrollOffset(),
+            web_view_impl->MainFrameImpl()->GetScrollOffset());
 
   // Make the page scale and scroll with the given paremeters.
   web_view_impl->SetPageScaleFactor(2.0f);
-  web_view_impl->MainFrameImpl()->SetScrollOffset(WebSize(94, 111));
+  web_view_impl->MainFrameImpl()->SetScrollOffset(gfx::ScrollOffset(94, 111));
   EXPECT_EQ(2.0f, web_view_impl->PageScaleFactor());
-  EXPECT_EQ(94, web_view_impl->MainFrameImpl()->GetScrollOffset().width);
-  EXPECT_EQ(111, web_view_impl->MainFrameImpl()->GetScrollOffset().height);
+  EXPECT_EQ(94, web_view_impl->MainFrameImpl()->GetScrollOffset().x());
+  EXPECT_EQ(111, web_view_impl->MainFrameImpl()->GetScrollOffset().y());
   auto* main_frame_local =
       To<LocalFrame>(web_view_impl->GetPage()->MainFrame());
   main_frame_local->Loader().SaveScrollState();
@@ -2457,8 +2455,8 @@
   // Confirm that resetting the page state resets the saved scroll position.
   web_view_impl->ResetScrollAndScaleState();
   EXPECT_EQ(1.0f, web_view_impl->PageScaleFactor());
-  EXPECT_EQ(0, web_view_impl->MainFrameImpl()->GetScrollOffset().width);
-  EXPECT_EQ(0, web_view_impl->MainFrameImpl()->GetScrollOffset().height);
+  EXPECT_EQ(gfx::ScrollOffset(),
+            web_view_impl->MainFrameImpl()->GetScrollOffset());
   EXPECT_FALSE(main_frame_local->Loader()
                    .GetDocumentLoader()
                    ->GetHistoryItem()
@@ -2475,7 +2473,7 @@
       DocumentUpdateReason::kTest);
 
   // Emulate a user scroll
-  web_view_impl->MainFrameImpl()->SetScrollOffset(WebSize(0, 900));
+  web_view_impl->MainFrameImpl()->SetScrollOffset(gfx::ScrollOffset(0, 900));
   auto* main_frame_local =
       To<LocalFrame>(web_view_impl->GetPage()->MainFrame());
   Persistent<HistoryItem> item1 =
@@ -2536,8 +2534,8 @@
   // TODO(chrishtr): At the moment, WebLocalFrameImpl::GetScrollOffset() does
   // not force a layout. Script-exposed scroll offset-reading methods do,
   // however. It seems wrong not to force a layout.
-  EXPECT_EQ(0, web_view_impl->MainFrameImpl()->GetScrollOffset().width);
-  EXPECT_GT(web_view_impl->MainFrameImpl()->GetScrollOffset().height, 2000);
+  EXPECT_EQ(0, web_view_impl->MainFrameImpl()->GetScrollOffset().x());
+  EXPECT_GT(web_view_impl->MainFrameImpl()->GetScrollOffset().y(), 2000);
 }
 
 // Tests that scroll offset modified during fullscreen is preserved when
@@ -2550,8 +2548,8 @@
   UpdateAllLifecyclePhases();
 
   // Scroll the page down.
-  web_view_impl->MainFrameImpl()->SetScrollOffset(WebSize(0, 2000));
-  ASSERT_EQ(2000, web_view_impl->MainFrameImpl()->GetScrollOffset().height);
+  web_view_impl->MainFrameImpl()->SetScrollOffset(gfx::ScrollOffset(0, 2000));
+  ASSERT_EQ(2000, web_view_impl->MainFrameImpl()->GetScrollOffset().y());
 
   // Enter fullscreen.
   LocalFrame* frame = web_view_impl->MainFrameImpl()->GetFrame();
@@ -2563,14 +2561,14 @@
   UpdateAllLifecyclePhases();
 
   // Assert the scroll position on the document element doesn't change.
-  ASSERT_EQ(2000, web_view_impl->MainFrameImpl()->GetScrollOffset().height);
+  ASSERT_EQ(2000, web_view_impl->MainFrameImpl()->GetScrollOffset().y());
 
-  web_view_impl->MainFrameImpl()->SetScrollOffset(WebSize(0, 2100));
+  web_view_impl->MainFrameImpl()->SetScrollOffset(gfx::ScrollOffset(0, 2100));
 
   web_view_impl->DidExitFullscreen();
   UpdateAllLifecyclePhases();
 
-  EXPECT_EQ(2100, web_view_impl->MainFrameImpl()->GetScrollOffset().height);
+  EXPECT_EQ(2100, web_view_impl->MainFrameImpl()->GetScrollOffset().y());
 }
 
 // Tests that background color is read from the backdrop on fullscreen.
diff --git a/third_party/blink/renderer/core/frame/browser_controls_test.cc b/third_party/blink/renderer/core/frame/browser_controls_test.cc
index 244c086f..2313b9654 100644
--- a/third_party/blink/renderer/core/frame/browser_controls_test.cc
+++ b/third_party/blink/renderer/core/frame/browser_controls_test.cc
@@ -725,7 +725,7 @@
   web_view->SetPageScaleFactor(2.0);
 
   // Fully scroll frameview but visualviewport remains scrollable
-  web_view->MainFrameImpl()->SetScrollOffset(WebSize(0, 10000));
+  web_view->MainFrameImpl()->SetScrollOffset(gfx::ScrollOffset(0, 10000));
   GetVisualViewport().SetLocation(FloatPoint(0, 0));
   GetWebView()->MainFrameViewWidget()->HandleInputEvent(
       GenerateEvent(WebInputEvent::Type::kGestureScrollBegin, 0, -10.f));
@@ -739,7 +739,7 @@
 
   web_view->GetBrowserControls().SetShownRatio(1, 1);
   // Fully scroll visual veiwport but frameview remains scrollable
-  web_view->MainFrameImpl()->SetScrollOffset(WebSize(0, 0));
+  web_view->MainFrameImpl()->SetScrollOffset(gfx::ScrollOffset(0, 0));
   GetVisualViewport().SetLocation(FloatPoint(0, 10000));
   GetWebView()->MainFrameViewWidget()->HandleInputEvent(
       GenerateEvent(WebInputEvent::Type::kGestureScrollBegin, 0, -20.f));
@@ -753,7 +753,7 @@
 
   web_view->GetBrowserControls().SetShownRatio(1, 1);
   // Fully scroll both frameview and visual viewport
-  web_view->MainFrameImpl()->SetScrollOffset(WebSize(0, 10000));
+  web_view->MainFrameImpl()->SetScrollOffset(gfx::ScrollOffset(0, 10000));
   GetVisualViewport().SetLocation(FloatPoint(0, 10000));
   VerticalScroll(-30.f);
   // Browser controls should not move because neither frameview nor visual
diff --git a/third_party/blink/renderer/core/frame/local_frame.cc b/third_party/blink/renderer/core/frame/local_frame.cc
index 4c931022..a617b0c 100644
--- a/third_party/blink/renderer/core/frame/local_frame.cc
+++ b/third_party/blink/renderer/core/frame/local_frame.cc
@@ -2554,7 +2554,7 @@
     UseCounter::Count(GetDocument(), WebFeature::kAdClickNavigation);
 }
 
-void LocalFrame::CountUseIfFeatureWouldBeBlockedByFeaturePolicy(
+void LocalFrame::CountUseIfFeatureWouldBeBlockedByPermissionsPolicy(
     mojom::WebFeature blocked_cross_origin,
     mojom::WebFeature blocked_same_origin) {
   // Get the origin of the top-level document
diff --git a/third_party/blink/renderer/core/frame/local_frame.h b/third_party/blink/renderer/core/frame/local_frame.h
index 1771870..2e3153d 100644
--- a/third_party/blink/renderer/core/frame/local_frame.h
+++ b/third_party/blink/renderer/core/frame/local_frame.h
@@ -583,7 +583,7 @@
   // document, and triggers |blockedSameOrigin| if it is same-origin with the
   // top level, but is embedded in any way through a cross-origin frame.
   // (A->B->A embedding)
-  void CountUseIfFeatureWouldBeBlockedByFeaturePolicy(
+  void CountUseIfFeatureWouldBeBlockedByPermissionsPolicy(
       mojom::WebFeature blocked_cross_origin,
       mojom::WebFeature blocked_same_origin);
 
diff --git a/third_party/blink/renderer/core/frame/picture_in_picture_controller.h b/third_party/blink/renderer/core/frame/picture_in_picture_controller.h
index 6593111..fe83d0b 100644
--- a/third_party/blink/renderer/core/frame/picture_in_picture_controller.h
+++ b/third_party/blink/renderer/core/frame/picture_in_picture_controller.h
@@ -44,7 +44,7 @@
     kMetadataNotLoaded,
     kVideoTrackNotAvailable,
     kDisabledBySystem,
-    kDisabledByFeaturePolicy,
+    kDisabledByPermissionsPolicy,
     kDisabledByAttribute,
     kInvalidWidthOrHeightOption,
   };
diff --git a/third_party/blink/renderer/core/frame/remote_frame.cc b/third_party/blink/renderer/core/frame/remote_frame.cc
index 2b4536e..3540d99 100644
--- a/third_party/blink/renderer/core/frame/remote_frame.cc
+++ b/third_party/blink/renderer/core/frame/remote_frame.cc
@@ -471,10 +471,10 @@
       .SetHasPointerEventsNone(IsIgnoredForHitTest());
 }
 
-void RemoteFrame::SetReplicatedFeaturePolicyHeader(
+void RemoteFrame::SetReplicatedPermissionsPolicyHeader(
     const ParsedPermissionsPolicy& parsed_header) {
   permissions_policy_header_ = parsed_header;
-  ApplyReplicatedFeaturePolicyHeader();
+  ApplyReplicatedPermissionsPolicyHeader();
 }
 
 void RemoteFrame::SetReplicatedSandboxFlags(
@@ -551,7 +551,7 @@
   security_origin->SetOpaqueOriginIsPotentiallyTrustworthy(
       is_potentially_trustworthy_unique_origin);
   security_context_.SetReplicatedOrigin(security_origin);
-  ApplyReplicatedFeaturePolicyHeader();
+  ApplyReplicatedPermissionsPolicyHeader();
 
   // If the origin of a remote frame changed, the accessibility object for the
   // owner element now points to a different child.
@@ -747,7 +747,7 @@
       parsed_permissions_policy.size());
   for (size_t i = 0; i < parsed_permissions_policy.size(); ++i)
     parsed_permissions_policy_copy[i] = parsed_permissions_policy[i];
-  SetReplicatedFeaturePolicyHeader(parsed_permissions_policy_copy);
+  SetReplicatedPermissionsPolicyHeader(parsed_permissions_policy_copy);
 }
 
 // Update the proxy's FrameOwner with new sandbox flags and container policy
@@ -893,16 +893,16 @@
   return !!Client();
 }
 
-void RemoteFrame::ApplyReplicatedFeaturePolicyHeader() {
+void RemoteFrame::ApplyReplicatedPermissionsPolicyHeader() {
   const PermissionsPolicy* parent_permissions_policy = nullptr;
   if (Frame* parent_frame = Parent()) {
     parent_permissions_policy =
-        parent_frame->GetSecurityContext()->GetFeaturePolicy();
+        parent_frame->GetSecurityContext()->GetPermissionsPolicy();
   }
   ParsedPermissionsPolicy container_policy;
   if (Owner())
     container_policy = Owner()->GetFramePolicy().container_policy;
-  security_context_.InitializeFeaturePolicy(
+  security_context_.InitializePermissionsPolicy(
       permissions_policy_header_, container_policy, parent_permissions_policy);
 }
 
diff --git a/third_party/blink/renderer/core/frame/remote_frame.h b/third_party/blink/renderer/core/frame/remote_frame.h
index f008c109..19276c6 100644
--- a/third_party/blink/renderer/core/frame/remote_frame.h
+++ b/third_party/blink/renderer/core/frame/remote_frame.h
@@ -111,7 +111,7 @@
 
   void DidChangeVisibleToHitTesting() override;
 
-  void SetReplicatedFeaturePolicyHeader(
+  void SetReplicatedPermissionsPolicyHeader(
       const ParsedPermissionsPolicy& parsed_header);
 
   void SetReplicatedSandboxFlags(network::mojom::blink::WebSandboxFlags);
@@ -242,7 +242,7 @@
 
   // Returns false if detaching child frames reentrantly detached `this`.
   bool DetachChildren();
-  void ApplyReplicatedFeaturePolicyHeader();
+  void ApplyReplicatedPermissionsPolicyHeader();
   void RecordSentVisualProperties();
 
   static void BindToReceiver(
diff --git a/third_party/blink/renderer/core/frame/visual_viewport.h b/third_party/blink/renderer/core/frame/visual_viewport.h
index 4dc38ebe..9b01e8a 100644
--- a/third_party/blink/renderer/core/frame/visual_viewport.h
+++ b/third_party/blink/renderer/core/frame/visual_viewport.h
@@ -35,7 +35,6 @@
 
 #include "base/single_thread_task_runner.h"
 #include "third_party/blink/public/mojom/scroll/scroll_into_view_params.mojom-blink-forward.h"
-#include "third_party/blink/public/platform/web_size.h"
 #include "third_party/blink/renderer/core/core_export.h"
 #include "third_party/blink/renderer/core/dom/document.h"
 #include "third_party/blink/renderer/core/dom/events/event.h"
diff --git a/third_party/blink/renderer/core/frame/visual_viewport_test.cc b/third_party/blink/renderer/core/frame/visual_viewport_test.cc
index 0642a3dd..23fce2f 100644
--- a/third_party/blink/renderer/core/frame/visual_viewport_test.cc
+++ b/third_party/blink/renderer/core/frame/visual_viewport_test.cc
@@ -287,7 +287,7 @@
       WebView()->GetBrowserControls().Params());
 
   // Scroll layout viewport and verify visibleContentRect.
-  WebView()->MainFrameImpl()->SetScrollOffset(WebSize(0, 50));
+  WebView()->MainFrameImpl()->SetScrollOffset(gfx::ScrollOffset(0, 50));
 
   VisualViewport& visual_viewport = GetFrame()->GetPage()->GetVisualViewport();
   EXPECT_EQ(IntRect(IntPoint(0, 0), size - scrollbar_size),
@@ -392,7 +392,7 @@
   WebView()->MainFrameViewWidget()->Resize(gfx::Size(100, 200));
 
   // Scroll main frame to the bottom of the document
-  WebView()->MainFrameImpl()->SetScrollOffset(WebSize(0, 400));
+  WebView()->MainFrameImpl()->SetScrollOffset(gfx::ScrollOffset(0, 400));
   EXPECT_EQ(ScrollOffset(0, 400),
             GetFrame()->View()->LayoutViewport()->GetScrollOffset());
 
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 8b533e1..428e0eb 100644
--- a/third_party/blink/renderer/core/frame/web_frame_test.cc
+++ b/third_party/blink/renderer/core/frame/web_frame_test.cc
@@ -2956,13 +2956,13 @@
   void TestResizeYieldsCorrectScrollAndScale(
       const char* url,
       const float initial_page_scale_factor,
-      const WebSize scroll_offset,
-      const WebSize viewport_size,
+      const gfx::ScrollOffset& scroll_offset,
+      const gfx::Size& viewport_size,
       const bool should_scale_relative_to_viewport_width) {
     RegisterMockedHttpURLLoad(url);
 
     const float aspect_ratio =
-        static_cast<float>(viewport_size.width) / viewport_size.height;
+        static_cast<float>(viewport_size.width()) / viewport_size.height();
 
     frame_test_helpers::WebViewHelper web_view_helper;
     web_view_helper.InitializeAndLoad(base_url_ + url, nullptr, nullptr,
@@ -2971,8 +2971,7 @@
 
     // Origin scrollOffsets preserved under resize.
     {
-      web_view_helper.Resize(
-          gfx::Size(viewport_size.width, viewport_size.height));
+      web_view_helper.Resize(viewport_size);
       web_view_helper.GetWebView()->SetPageScaleFactor(
           initial_page_scale_factor);
       ASSERT_EQ(gfx::Size(viewport_size),
@@ -2980,34 +2979,34 @@
       ASSERT_EQ(initial_page_scale_factor,
                 web_view_helper.GetWebView()->PageScaleFactor());
       web_view_helper.Resize(
-          gfx::Size(viewport_size.height, viewport_size.width));
+          gfx::Size(viewport_size.height(), viewport_size.width()));
       float expected_page_scale_factor =
           initial_page_scale_factor *
           (should_scale_relative_to_viewport_width ? 1 / aspect_ratio : 1);
       EXPECT_NEAR(expected_page_scale_factor,
                   web_view_helper.GetWebView()->PageScaleFactor(), 0.05f);
-      EXPECT_EQ(WebSize(), web_view_helper.LocalMainFrame()->GetScrollOffset());
+      EXPECT_EQ(gfx::ScrollOffset(),
+                web_view_helper.LocalMainFrame()->GetScrollOffset());
     }
 
     // Resizing just the height should not affect pageScaleFactor or
     // scrollOffset.
     {
-      web_view_helper.Resize(
-          gfx::Size(viewport_size.width, viewport_size.height));
+      web_view_helper.Resize(viewport_size);
       web_view_helper.GetWebView()->SetPageScaleFactor(
           initial_page_scale_factor);
       web_view_helper.LocalMainFrame()->SetScrollOffset(scroll_offset);
       UpdateAllLifecyclePhases(web_view_helper.GetWebView());
-      const WebSize expected_scroll_offset =
+      const gfx::ScrollOffset expected_scroll_offset =
           web_view_helper.LocalMainFrame()->GetScrollOffset();
       web_view_helper.Resize(
-          gfx::Size(viewport_size.width, viewport_size.height * 0.8f));
+          gfx::Size(viewport_size.width(), viewport_size.height() * 0.8f));
       EXPECT_EQ(initial_page_scale_factor,
                 web_view_helper.GetWebView()->PageScaleFactor());
       EXPECT_EQ(expected_scroll_offset,
                 web_view_helper.LocalMainFrame()->GetScrollOffset());
       web_view_helper.Resize(
-          gfx::Size(viewport_size.width, viewport_size.height * 0.8f));
+          gfx::Size(viewport_size.width(), viewport_size.height() * 0.8f));
       EXPECT_EQ(initial_page_scale_factor,
                 web_view_helper.GetWebView()->PageScaleFactor());
       EXPECT_EQ(expected_scroll_offset,
@@ -3022,8 +3021,8 @@
   // long as the content adjusts according to the device-width.
   const char* url = "resize_scroll_mobile.html";
   const float kInitialPageScaleFactor = 1;
-  const WebSize scroll_offset(0, 50);
-  const WebSize viewport_size(120, 160);
+  const gfx::ScrollOffset scroll_offset(0, 50);
+  const gfx::Size viewport_size(120, 160);
   const bool kShouldScaleRelativeToViewportWidth = true;
 
   TestResizeYieldsCorrectScrollAndScale(url, kInitialPageScaleFactor,
@@ -3038,8 +3037,8 @@
   // on rotation and not do anything strange.
   const char* url = "resize_scroll_minimum_scale.html";
   const float kInitialPageScaleFactor = 1;
-  const WebSize scroll_offset(0, 0);
-  const WebSize viewport_size(240, 320);
+  const gfx::ScrollOffset scroll_offset(0, 0);
+  const gfx::Size viewport_size(240, 320);
   const bool kShouldScaleRelativeToViewportWidth = false;
 
   TestResizeYieldsCorrectScrollAndScale(url, kInitialPageScaleFactor,
@@ -3052,8 +3051,8 @@
   // viewport width.
   const char* url = "resize_scroll_fixed_width.html";
   const float kInitialPageScaleFactor = 2;
-  const WebSize scroll_offset(0, 200);
-  const WebSize viewport_size(240, 320);
+  const gfx::ScrollOffset scroll_offset(0, 200);
+  const gfx::Size viewport_size(240, 320);
   const bool kShouldScaleRelativeToViewportWidth = true;
 
   TestResizeYieldsCorrectScrollAndScale(url, kInitialPageScaleFactor,
@@ -3066,8 +3065,8 @@
   // viewport width.
   const char* url = "resize_scroll_fixed_layout.html";
   const float kInitialPageScaleFactor = 2;
-  const WebSize scroll_offset(200, 400);
-  const WebSize viewport_size(320, 240);
+  const gfx::ScrollOffset scroll_offset(200, 400);
+  const gfx::Size viewport_size(320, 240);
   const bool kShouldScaleRelativeToViewportWidth = true;
 
   TestResizeYieldsCorrectScrollAndScale(url, kInitialPageScaleFactor,
@@ -3162,7 +3161,8 @@
                                 const gfx::Point& scroll,
                                 float scale) {
   web_view->SetPageScaleFactor(scale);
-  web_view->MainFrameImpl()->SetScrollOffset(WebSize(scroll.x(), scroll.y()));
+  web_view->MainFrameImpl()->SetScrollOffset(
+      gfx::ScrollOffset(scroll.x(), scroll.y()));
   web_view->MainFrameWidget()->UpdateAllLifecyclePhases(
       DocumentUpdateReason::kTest);
 }
@@ -4254,7 +4254,7 @@
   web_view_helper.InitializeAndLoad(base_url_ + url, &client);
   web_view_helper.Resize(gfx::Size(kPageWidth, kPageHeight));
   web_view_helper.LocalMainFrame()->SetScrollOffset(
-      WebSize(kPageWidth / 4, kPageHeight / 4));
+      gfx::ScrollOffset(kPageWidth / 4, kPageHeight / 4));
   web_view_helper.GetWebView()->SetPageScaleFactor(kPageScaleFactor);
 
   // Reload the page and end up at the same url. State should not be propagated.
@@ -4262,8 +4262,8 @@
       WebFrameLoadType::kReload);
   frame_test_helpers::PumpPendingRequestsForFrameToLoad(
       web_view_helper.LocalMainFrame());
-  EXPECT_EQ(0, web_view_helper.LocalMainFrame()->GetScrollOffset().width);
-  EXPECT_EQ(0, web_view_helper.LocalMainFrame()->GetScrollOffset().height);
+  EXPECT_EQ(gfx::ScrollOffset(),
+            web_view_helper.LocalMainFrame()->GetScrollOffset());
   EXPECT_EQ(1.0f, web_view_helper.GetWebView()->PageScaleFactor());
 }
 
@@ -7902,7 +7902,7 @@
   web_view->SetPageScaleFactor(2.0f);
   UpdateAllLifecyclePhases(web_view_helper.GetWebView());
 
-  web_view->MainFrameImpl()->SetScrollOffset(WebSize(0, 2000));
+  web_view->MainFrameImpl()->SetScrollOffset(gfx::ScrollOffset(0, 2000));
   EXPECT_EQ(ScrollOffset(0, 1900),
             frame_view->LayoutViewport()->GetScrollOffset());
 
@@ -7918,7 +7918,7 @@
   web_view->MainFrameWidget()->ApplyViewportChangesForTesting(
       {gfx::ScrollOffset(), gfx::Vector2dF(), 1.0f, false,
        20.0f / browser_controls_height, 0, cc::BrowserControlsState::kBoth});
-  web_view->MainFrameImpl()->SetScrollOffset(WebSize(0, 2000));
+  web_view->MainFrameImpl()->SetScrollOffset(gfx::ScrollOffset(0, 2000));
   EXPECT_EQ(ScrollOffset(0, 1940),
             frame_view->LayoutViewport()->GetScrollOffset());
 
@@ -8322,9 +8322,9 @@
   // resize and switching fullscreen state operations on WebView, with the
   // interference from Android status bars like a real device does.
   // This verifies we handle the transition and restore states correctly.
-  WebSize screen_size_minus_status_bars_minus_url_bar(598, 303);
-  WebSize screen_size_minus_status_bars(598, 359);
-  WebSize screen_size(640, 384);
+  gfx::Size screen_size_minus_status_bars_minus_url_bar(598, 303);
+  gfx::Size screen_size_minus_status_bars(598, 359);
+  gfx::Size screen_size(640, 384);
 
   RegisterMockedHttpURLLoad("fullscreen_restore_scale_factor.html");
   frame_test_helpers::WebViewHelper web_view_helper;
@@ -8332,15 +8332,15 @@
       base_url_ + "fullscreen_restore_scale_factor.html", nullptr, nullptr,
       &ConfigureAndroid);
   UpdateScreenInfoAndResizeView(
-      &web_view_helper, screen_size_minus_status_bars_minus_url_bar.width,
-      screen_size_minus_status_bars_minus_url_bar.height);
+      &web_view_helper, screen_size_minus_status_bars_minus_url_bar.width(),
+      screen_size_minus_status_bars_minus_url_bar.height());
   auto* layout_view = web_view_helper.GetWebView()
                           ->MainFrameImpl()
                           ->GetFrameView()
                           ->GetLayoutView();
-  EXPECT_EQ(screen_size_minus_status_bars_minus_url_bar.width,
+  EXPECT_EQ(screen_size_minus_status_bars_minus_url_bar.width(),
             layout_view->LogicalWidth().Floor());
-  EXPECT_EQ(screen_size_minus_status_bars_minus_url_bar.height,
+  EXPECT_EQ(screen_size_minus_status_bars_minus_url_bar.height(),
             layout_view->LogicalHeight().Floor());
   EXPECT_FLOAT_EQ(1.0, web_view_impl->PageScaleFactor());
   EXPECT_FLOAT_EQ(1.0, web_view_impl->MinimumPageScaleFactor());
@@ -8356,12 +8356,12 @@
   web_view_impl->DidEnterFullscreen();
   UpdateAllLifecyclePhases(web_view_impl);
   UpdateScreenInfoAndResizeView(&web_view_helper,
-                                screen_size_minus_status_bars.width,
-                                screen_size_minus_status_bars.height);
-  UpdateScreenInfoAndResizeView(&web_view_helper, screen_size.width,
-                                screen_size.height);
-  EXPECT_EQ(screen_size.width, layout_view->LogicalWidth().Floor());
-  EXPECT_EQ(screen_size.height, layout_view->LogicalHeight().Floor());
+                                screen_size_minus_status_bars.width(),
+                                screen_size_minus_status_bars.height());
+  UpdateScreenInfoAndResizeView(&web_view_helper, screen_size.width(),
+                                screen_size.height());
+  EXPECT_EQ(screen_size.width(), layout_view->LogicalWidth().Floor());
+  EXPECT_EQ(screen_size.height(), layout_view->LogicalHeight().Floor());
   EXPECT_FLOAT_EQ(1.0, web_view_impl->PageScaleFactor());
   EXPECT_FLOAT_EQ(1.0, web_view_impl->MinimumPageScaleFactor());
   EXPECT_FLOAT_EQ(1.0, web_view_impl->MaximumPageScaleFactor());
@@ -8369,14 +8369,14 @@
   web_view_impl->DidExitFullscreen();
   UpdateAllLifecyclePhases(web_view_impl);
   UpdateScreenInfoAndResizeView(&web_view_helper,
-                                screen_size_minus_status_bars.width,
-                                screen_size_minus_status_bars.height);
+                                screen_size_minus_status_bars.width(),
+                                screen_size_minus_status_bars.height());
   UpdateScreenInfoAndResizeView(
-      &web_view_helper, screen_size_minus_status_bars_minus_url_bar.width,
-      screen_size_minus_status_bars_minus_url_bar.height);
-  EXPECT_EQ(screen_size_minus_status_bars_minus_url_bar.width,
+      &web_view_helper, screen_size_minus_status_bars_minus_url_bar.width(),
+      screen_size_minus_status_bars_minus_url_bar.height());
+  EXPECT_EQ(screen_size_minus_status_bars_minus_url_bar.width(),
             layout_view->LogicalWidth().Floor());
-  EXPECT_EQ(screen_size_minus_status_bars_minus_url_bar.height,
+  EXPECT_EQ(screen_size_minus_status_bars_minus_url_bar.height(),
             layout_view->LogicalHeight().Floor());
   EXPECT_FLOAT_EQ(1.0, web_view_impl->PageScaleFactor());
   EXPECT_FLOAT_EQ(1.0, web_view_impl->MinimumPageScaleFactor());
@@ -13468,11 +13468,11 @@
   // Make the page scale and scroll with the given parameters.
   EXPECT_EQ(0.5f, WebView().PageScaleFactor());
   WebView().SetPageScaleFactor(2.0f);
-  WebView().MainFrameImpl()->SetScrollOffset(WebSize(94, 111));
+  WebView().MainFrameImpl()->SetScrollOffset(gfx::ScrollOffset(94, 111));
   WebView().SetVisualViewportOffset(gfx::PointF(12, 20));
   EXPECT_EQ(2.0f, WebView().PageScaleFactor());
-  EXPECT_EQ(94, WebView().MainFrameImpl()->GetScrollOffset().width);
-  EXPECT_EQ(111, WebView().MainFrameImpl()->GetScrollOffset().height);
+  EXPECT_EQ(94, WebView().MainFrameImpl()->GetScrollOffset().x());
+  EXPECT_EQ(111, WebView().MainFrameImpl()->GetScrollOffset().y());
   EXPECT_EQ(12, WebView().VisualViewportOffset().x());
   EXPECT_EQ(20, WebView().VisualViewportOffset().y());
 
@@ -13493,8 +13493,8 @@
       DocumentUpdateReason::kTest);
 
   EXPECT_EQ(0.5f, WebView().PageScaleFactor());
-  EXPECT_EQ(94, WebView().MainFrameImpl()->GetScrollOffset().width);
-  EXPECT_EQ(111, WebView().MainFrameImpl()->GetScrollOffset().height);
+  EXPECT_EQ(94, WebView().MainFrameImpl()->GetScrollOffset().x());
+  EXPECT_EQ(111, WebView().MainFrameImpl()->GetScrollOffset().y());
   EXPECT_EQ(0, WebView().VisualViewportOffset().x());
   EXPECT_EQ(0, WebView().VisualViewportOffset().y());
 }
diff --git a/third_party/blink/renderer/core/frame/web_local_frame_impl.cc b/third_party/blink/renderer/core/frame/web_local_frame_impl.cc
index 4d7f47f..eeb2ef4 100644
--- a/third_party/blink/renderer/core/frame/web_local_frame_impl.cc
+++ b/third_party/blink/renderer/core/frame/web_local_frame_impl.cc
@@ -109,7 +109,6 @@
 #include "third_party/blink/public/platform/web_double_size.h"
 #include "third_party/blink/public/platform/web_isolated_world_info.h"
 #include "third_party/blink/public/platform/web_security_origin.h"
-#include "third_party/blink/public/platform/web_size.h"
 #include "third_party/blink/public/platform/web_url_error.h"
 #include "third_party/blink/public/platform/web_url_loader_factory.h"
 #include "third_party/blink/public/platform/web_vector.h"
@@ -783,15 +782,16 @@
     GetFrame()->GetSystemClipboard()->CopyToFindPboard(SelectionAsText());
 }
 
-WebSize WebLocalFrameImpl::GetScrollOffset() const {
-  if (ScrollableArea* scrollable_area = LayoutViewport())
-    return scrollable_area->ScrollOffsetInt();
-  return WebSize();
+gfx::ScrollOffset WebLocalFrameImpl::GetScrollOffset() const {
+  if (ScrollableArea* scrollable_area = LayoutViewport()) {
+    return gfx::ScrollOffset(scrollable_area->GetScrollOffset());
+  }
+  return gfx::ScrollOffset();
 }
 
-void WebLocalFrameImpl::SetScrollOffset(const WebSize& offset) {
+void WebLocalFrameImpl::SetScrollOffset(const gfx::ScrollOffset& offset) {
   if (ScrollableArea* scrollable_area = LayoutViewport()) {
-    scrollable_area->SetScrollOffset(ScrollOffset(offset.width, offset.height),
+    scrollable_area->SetScrollOffset(ScrollOffset(offset.x(), offset.y()),
                                      mojom::blink::ScrollType::kProgrammatic);
   }
 }
diff --git a/third_party/blink/renderer/core/frame/web_local_frame_impl.h b/third_party/blink/renderer/core/frame/web_local_frame_impl.h
index 74c9b26..a41ba59 100644
--- a/third_party/blink/renderer/core/frame/web_local_frame_impl.h
+++ b/third_party/blink/renderer/core/frame/web_local_frame_impl.h
@@ -283,8 +283,8 @@
   std::unique_ptr<WebAssociatedURLLoader> CreateAssociatedURLLoader(
       const WebAssociatedURLLoaderOptions&) override;
   void DeprecatedStopLoading() override;
-  WebSize GetScrollOffset() const override;
-  void SetScrollOffset(const WebSize&) override;
+  gfx::ScrollOffset GetScrollOffset() const override;
+  void SetScrollOffset(const gfx::ScrollOffset&) override;
   gfx::Size DocumentSize() const override;
   bool HasVisibleContent() const override;
   gfx::Rect VisibleContentRect() const override;
diff --git a/third_party/blink/renderer/core/frame/web_remote_frame_impl.cc b/third_party/blink/renderer/core/frame/web_remote_frame_impl.cc
index 24775af..ca5ea237 100644
--- a/third_party/blink/renderer/core/frame/web_remote_frame_impl.cc
+++ b/third_party/blink/renderer/core/frame/web_remote_frame_impl.cc
@@ -326,10 +326,10 @@
   GetFrame()->SetReplicatedName(name, unique_name);
 }
 
-void WebRemoteFrameImpl::SetReplicatedFeaturePolicyHeader(
+void WebRemoteFrameImpl::SetReplicatedPermissionsPolicyHeader(
     const ParsedPermissionsPolicy& parsed_header) {
   DCHECK(GetFrame());
-  GetFrame()->SetReplicatedFeaturePolicyHeader(parsed_header);
+  GetFrame()->SetReplicatedPermissionsPolicyHeader(parsed_header);
 }
 
 void WebRemoteFrameImpl::SetReplicatedInsecureRequestPolicy(
diff --git a/third_party/blink/renderer/core/frame/web_remote_frame_impl.h b/third_party/blink/renderer/core/frame/web_remote_frame_impl.h
index cec8a7d..910c14a7 100644
--- a/third_party/blink/renderer/core/frame/web_remote_frame_impl.h
+++ b/third_party/blink/renderer/core/frame/web_remote_frame_impl.h
@@ -86,7 +86,7 @@
       network::mojom::blink::WebSandboxFlags) override;
   void SetReplicatedName(const WebString& name,
                          const WebString& unique_name) override;
-  void SetReplicatedFeaturePolicyHeader(
+  void SetReplicatedPermissionsPolicyHeader(
       const ParsedPermissionsPolicy& parsed_header) override;
   void SetReplicatedInsecureRequestPolicy(
       mojom::blink::InsecureRequestPolicy) override;
diff --git a/third_party/blink/renderer/core/html/canvas/OWNERS b/third_party/blink/renderer/core/html/canvas/OWNERS
index 1e56363..9a1d5cc 100644
--- a/third_party/blink/renderer/core/html/canvas/OWNERS
+++ b/third_party/blink/renderer/core/html/canvas/OWNERS
@@ -1 +1,2 @@
 fserb@chromium.org
+junov@chromium.org
diff --git a/third_party/blink/renderer/core/html/html_frame_element_base.cc b/third_party/blink/renderer/core/html/html_frame_element_base.cc
index be6f21a..abbe350 100644
--- a/third_party/blink/renderer/core/html/html_frame_element_base.cc
+++ b/third_party/blink/renderer/core/html/html_frame_element_base.cc
@@ -158,7 +158,7 @@
 }
 
 scoped_refptr<const SecurityOrigin>
-HTMLFrameElementBase::GetOriginForFeaturePolicy() const {
+HTMLFrameElementBase::GetOriginForPermissionsPolicy() const {
   // Sandboxed frames have a unique origin.
   if ((GetFramePolicy().sandbox_flags &
        network::mojom::blink::WebSandboxFlags::kOrigin) !=
diff --git a/third_party/blink/renderer/core/html/html_frame_element_base.h b/third_party/blink/renderer/core/html/html_frame_element_base.h
index 37d4bba..e5248df 100644
--- a/third_party/blink/renderer/core/html/html_frame_element_base.h
+++ b/third_party/blink/renderer/core/html/html_frame_element_base.h
@@ -64,7 +64,7 @@
   // feature on the origin which is specified by the frame's "src" attribute. It
   // also takes into account details such as the frame's sandbox status, and
   // whether the frame should inherit its parent's origin.
-  scoped_refptr<const SecurityOrigin> GetOriginForFeaturePolicy()
+  scoped_refptr<const SecurityOrigin> GetOriginForPermissionsPolicy()
       const override;
 
  private:
diff --git a/third_party/blink/renderer/core/html/html_frame_owner_element.h b/third_party/blink/renderer/core/html/html_frame_owner_element.h
index 76347fe..659850e 100644
--- a/third_party/blink/renderer/core/html/html_frame_owner_element.h
+++ b/third_party/blink/renderer/core/html/html_frame_owner_element.h
@@ -153,7 +153,7 @@
   // policies, as "the origin of the URL in the frame's src attribute" (see
   // https://w3c.github.io/webappsec-permissions-policy/#iframe-allow-attribute).
   // This method is intended to be overridden by specific frame classes.
-  virtual scoped_refptr<const SecurityOrigin> GetOriginForFeaturePolicy()
+  virtual scoped_refptr<const SecurityOrigin> GetOriginForPermissionsPolicy()
       const {
     return SecurityOrigin::CreateUniqueOpaque();
   }
diff --git a/third_party/blink/renderer/core/html/html_iframe_element.cc b/third_party/blink/renderer/core/html/html_iframe_element.cc
index c2b2a51..751713b 100644
--- a/third_party/blink/renderer/core/html/html_iframe_element.cc
+++ b/third_party/blink/renderer/core/html/html_iframe_element.cc
@@ -97,7 +97,7 @@
   if (!policy_ && GetExecutionContext()) {
     policy_ = MakeGarbageCollected<IFramePolicy>(
         GetExecutionContext(), GetFramePolicy().container_policy,
-        GetOriginForFeaturePolicy());
+        GetOriginForPermissionsPolicy());
   }
   return policy_.Get();
 }
@@ -313,7 +313,8 @@
   if (!GetExecutionContext())
     return ParsedPermissionsPolicy();
 
-  scoped_refptr<const SecurityOrigin> src_origin = GetOriginForFeaturePolicy();
+  scoped_refptr<const SecurityOrigin> src_origin =
+      GetOriginForPermissionsPolicy();
   scoped_refptr<const SecurityOrigin> self_origin =
       GetExecutionContext()->GetSecurityOrigin();
 
diff --git a/third_party/blink/renderer/core/html/html_iframe_element_test.cc b/third_party/blink/renderer/core/html/html_iframe_element_test.cc
index d8f8f1b8..f1a47cf 100644
--- a/third_party/blink/renderer/core/html/html_iframe_element_test.cc
+++ b/third_party/blink/renderer/core/html/html_iframe_element_test.cc
@@ -19,9 +19,9 @@
 
 class HTMLIFrameElementTest : public testing::Test {
  public:
-  scoped_refptr<const SecurityOrigin> GetOriginForFeaturePolicy(
+  scoped_refptr<const SecurityOrigin> GetOriginForPermissionsPolicy(
       HTMLIFrameElement* element) {
-    return element->GetOriginForFeaturePolicy();
+    return element->GetOriginForPermissionsPolicy();
   }
 
   void SetUp() final {
@@ -52,18 +52,18 @@
 TEST_F(HTMLIFrameElementTest, FramesUseCorrectOrigin) {
   frame_element_->setAttribute(html_names::kSrcAttr, "about:blank");
   scoped_refptr<const SecurityOrigin> effective_origin =
-      GetOriginForFeaturePolicy(frame_element_);
+      GetOriginForPermissionsPolicy(frame_element_);
   EXPECT_TRUE(effective_origin->IsSameOriginWith(window_->GetSecurityOrigin()));
 
   frame_element_->setAttribute(
       html_names::kSrcAttr, "data:text/html;base64,PHRpdGxlPkFCQzwvdGl0bGU+");
-  effective_origin = GetOriginForFeaturePolicy(frame_element_);
+  effective_origin = GetOriginForPermissionsPolicy(frame_element_);
   EXPECT_FALSE(
       effective_origin->IsSameOriginWith(window_->GetSecurityOrigin()));
   EXPECT_TRUE(effective_origin->IsOpaque());
 
   frame_element_->setAttribute(html_names::kSrcAttr, "http://example.net/");
-  effective_origin = GetOriginForFeaturePolicy(frame_element_);
+  effective_origin = GetOriginForPermissionsPolicy(frame_element_);
   EXPECT_FALSE(
       effective_origin->IsSameOriginWith(window_->GetSecurityOrigin()));
   EXPECT_FALSE(effective_origin->IsOpaque());
@@ -75,13 +75,13 @@
   frame_element_->setAttribute(html_names::kSandboxAttr, "");
   frame_element_->setAttribute(html_names::kSrcAttr, "http://example.com/");
   scoped_refptr<const SecurityOrigin> effective_origin =
-      GetOriginForFeaturePolicy(frame_element_);
+      GetOriginForPermissionsPolicy(frame_element_);
   EXPECT_FALSE(
       effective_origin->IsSameOriginWith(window_->GetSecurityOrigin()));
   EXPECT_TRUE(effective_origin->IsOpaque());
 
   frame_element_->setAttribute(html_names::kSrcAttr, "http://example.net/");
-  effective_origin = GetOriginForFeaturePolicy(frame_element_);
+  effective_origin = GetOriginForPermissionsPolicy(frame_element_);
   EXPECT_FALSE(
       effective_origin->IsSameOriginWith(window_->GetSecurityOrigin()));
   EXPECT_TRUE(effective_origin->IsOpaque());
@@ -93,7 +93,7 @@
   frame_element_->setAttribute(html_names::kSandboxAttr, "allow-same-origin");
   frame_element_->setAttribute(html_names::kSrcAttr, "http://example.com/");
   scoped_refptr<const SecurityOrigin> effective_origin =
-      GetOriginForFeaturePolicy(frame_element_);
+      GetOriginForPermissionsPolicy(frame_element_);
   EXPECT_TRUE(effective_origin->IsSameOriginWith(window_->GetSecurityOrigin()));
   EXPECT_FALSE(effective_origin->IsOpaque());
 }
@@ -103,7 +103,7 @@
 TEST_F(HTMLIFrameElementTest, SrcdocFramesUseCorrectOrigin) {
   frame_element_->setAttribute(html_names::kSrcdocAttr, "<title>title</title>");
   scoped_refptr<const SecurityOrigin> effective_origin =
-      GetOriginForFeaturePolicy(frame_element_);
+      GetOriginForPermissionsPolicy(frame_element_);
   EXPECT_TRUE(effective_origin->IsSameOriginWith(window_->GetSecurityOrigin()));
 }
 
@@ -113,7 +113,7 @@
   frame_element_->setAttribute(html_names::kSandboxAttr, "");
   frame_element_->setAttribute(html_names::kSrcdocAttr, "<title>title</title>");
   scoped_refptr<const SecurityOrigin> effective_origin =
-      GetOriginForFeaturePolicy(frame_element_);
+      GetOriginForPermissionsPolicy(frame_element_);
   EXPECT_FALSE(
       effective_origin->IsSameOriginWith(window_->GetSecurityOrigin()));
   EXPECT_TRUE(effective_origin->IsOpaque());
@@ -125,13 +125,13 @@
   // Host-relative URLs should resolve to the same domain as the parent.
   frame_element_->setAttribute(html_names::kSrcAttr, "index2.html");
   scoped_refptr<const SecurityOrigin> effective_origin =
-      GetOriginForFeaturePolicy(frame_element_);
+      GetOriginForPermissionsPolicy(frame_element_);
   EXPECT_TRUE(effective_origin->IsSameOriginWith(window_->GetSecurityOrigin()));
 
   // Scheme-relative URLs should not resolve to the same domain as the parent.
   frame_element_->setAttribute(html_names::kSrcAttr,
                                "//example.net/index2.html");
-  effective_origin = GetOriginForFeaturePolicy(frame_element_);
+  effective_origin = GetOriginForPermissionsPolicy(frame_element_);
   EXPECT_FALSE(
       effective_origin->IsSameOriginWith(window_->GetSecurityOrigin()));
 }
@@ -210,12 +210,12 @@
   EXPECT_FALSE(container_policy[0].matches_all_origins);
   EXPECT_EQ(1UL, container_policy[0].allowed_origins.size());
   EXPECT_TRUE(container_policy[0].allowed_origins.begin()->IsSameOriginWith(
-      GetOriginForFeaturePolicy(frame_element_)->ToUrlOrigin()));
+      GetOriginForPermissionsPolicy(frame_element_)->ToUrlOrigin()));
   EXPECT_EQ(mojom::blink::PermissionsPolicyFeature::kUsb,
             container_policy[1].feature);
   EXPECT_EQ(1UL, container_policy[1].allowed_origins.size());
   EXPECT_TRUE(container_policy[1].allowed_origins.begin()->IsSameOriginWith(
-      GetOriginForFeaturePolicy(frame_element_)->ToUrlOrigin()));
+      GetOriginForPermissionsPolicy(frame_element_)->ToUrlOrigin()));
 }
 
 // Test the ConstructContainerPolicy method when the "allowfullscreen" attribute
@@ -246,7 +246,7 @@
   EXPECT_FALSE(container_policy[0].matches_all_origins);
   EXPECT_EQ(1UL, container_policy[0].allowed_origins.size());
   EXPECT_TRUE(container_policy[0].allowed_origins.begin()->IsSameOriginWith(
-      GetOriginForFeaturePolicy(frame_element_)->ToUrlOrigin()));
+      GetOriginForPermissionsPolicy(frame_element_)->ToUrlOrigin()));
   EXPECT_EQ(mojom::blink::PermissionsPolicyFeature::kPayment,
             container_policy[1].feature);
 }
@@ -271,12 +271,12 @@
   EXPECT_FALSE(container_policy[0].matches_all_origins);
   EXPECT_EQ(1UL, container_policy[0].allowed_origins.size());
   EXPECT_TRUE(container_policy[0].allowed_origins.begin()->IsSameOriginWith(
-      GetOriginForFeaturePolicy(frame_element_)->ToUrlOrigin()));
+      GetOriginForPermissionsPolicy(frame_element_)->ToUrlOrigin()));
   EXPECT_EQ(mojom::blink::PermissionsPolicyFeature::kUsb,
             container_policy[1].feature);
   EXPECT_EQ(1UL, container_policy[1].allowed_origins.size());
   EXPECT_TRUE(container_policy[1].allowed_origins.begin()->IsSameOriginWith(
-      GetOriginForFeaturePolicy(frame_element_)->ToUrlOrigin()));
+      GetOriginForPermissionsPolicy(frame_element_)->ToUrlOrigin()));
   EXPECT_EQ(mojom::blink::PermissionsPolicyFeature::kFullscreen,
             container_policy[2].feature);
 }
diff --git a/third_party/blink/renderer/core/html/html_link_element.cc b/third_party/blink/renderer/core/html/html_link_element.cc
index 9b0606b..3d54337 100644
--- a/third_party/blink/renderer/core/html/html_link_element.cc
+++ b/third_party/blink/renderer/core/html/html_link_element.cc
@@ -30,7 +30,6 @@
 #include "third_party/blink/public/platform/task_type.h"
 #include "third_party/blink/public/platform/web_icon_sizes_parser.h"
 #include "third_party/blink/public/platform/web_prescient_networking.h"
-#include "third_party/blink/public/platform/web_size.h"
 #include "third_party/blink/renderer/core/core_initializer.h"
 #include "third_party/blink/renderer/core/dom/attribute.h"
 #include "third_party/blink/renderer/core/dom/document.h"
diff --git a/third_party/blink/renderer/core/imagebitmap/OWNERS b/third_party/blink/renderer/core/imagebitmap/OWNERS
index 1e56363..9a1d5cc 100644
--- a/third_party/blink/renderer/core/imagebitmap/OWNERS
+++ b/third_party/blink/renderer/core/imagebitmap/OWNERS
@@ -1 +1,2 @@
 fserb@chromium.org
+junov@chromium.org
diff --git a/third_party/blink/renderer/core/inspector/dev_tools_emulator.cc b/third_party/blink/renderer/core/inspector/dev_tools_emulator.cc
index 2a4756e..1734647 100644
--- a/third_party/blink/renderer/core/inspector/dev_tools_emulator.cc
+++ b/third_party/blink/renderer/core/inspector/dev_tools_emulator.cc
@@ -443,13 +443,13 @@
 
   // Translate while taking into account current scroll offset.
   // TODO(lukasza): https://crbug.com/734201: Add OOPIF support.
-  WebSize scroll_offset =
+  gfx::ScrollOffset scroll_offset =
       web_view_->MainFrame()->IsWebLocalFrame()
           ? web_view_->MainFrame()->ToWebLocalFrame()->GetScrollOffset()
-          : WebSize();
+          : gfx::ScrollOffset();
   gfx::PointF visual_offset = web_view_->VisualViewportOffset();
-  float scroll_x = scroll_offset.width + visual_offset.x();
-  float scroll_y = scroll_offset.height + visual_offset.y();
+  float scroll_x = scroll_offset.x() + visual_offset.x();
+  float scroll_y = scroll_offset.y() + visual_offset.y();
   transform->Translate(-viewport_override_->position.X() + scroll_x,
                        -viewport_override_->position.Y() + scroll_y);
 
diff --git a/third_party/blink/renderer/core/inspector/inspector_page_agent.cc b/third_party/blink/renderer/core/inspector/inspector_page_agent.cc
index e4b9bb36..6dc1674b 100644
--- a/third_party/blink/renderer/core/inspector/inspector_page_agent.cc
+++ b/third_party/blink/renderer/core/inspector/inspector_page_agent.cc
@@ -842,13 +842,13 @@
 
 std::unique_ptr<protocol::Page::PermissionsPolicyBlockLocator>
 CreatePermissionsPolicyBlockLocator(
-    const blink::FeaturePolicyBlockLocator& locator) {
+    const blink::PermissionsPolicyBlockLocator& locator) {
   protocol::Page::PermissionsPolicyBlockReason reason;
   switch (locator.reason) {
-    case blink::FeaturePolicyBlockReason::kHeader:
+    case blink::PermissionsPolicyBlockReason::kHeader:
       reason = protocol::Page::PermissionsPolicyBlockReasonEnum::Header;
       break;
-    case blink::FeaturePolicyBlockReason::kIframeAttribute:
+    case blink::PermissionsPolicyBlockReason::kIframeAttribute:
       reason =
           protocol::Page::PermissionsPolicyBlockReasonEnum::IframeAttribute;
       break;
@@ -873,7 +873,7 @@
     return Response::ServerError("No frame for given id found in this target");
 
   const blink::PermissionsPolicy* permissions_policy =
-      frame->GetSecurityContext()->GetFeaturePolicy();
+      frame->GetSecurityContext()->GetPermissionsPolicy();
 
   if (!permissions_policy)
     return Response::ServerError("Frame not ready");
@@ -888,8 +888,8 @@
     if (blink::DisabledByOriginTrial(feature_name, frame->DomWindow()))
       continue;
 
-    base::Optional<blink::FeaturePolicyBlockLocator> locator =
-        blink::TraceFeaturePolicyBlockSource(frame, feature);
+    base::Optional<blink::PermissionsPolicyBlockLocator> locator =
+        blink::TracePermissionsPolicyBlockSource(frame, feature);
 
     std::unique_ptr<protocol::Page::PermissionsPolicyFeatureState>
         feature_state =
diff --git a/third_party/blink/renderer/core/layout/layout_video.cc b/third_party/blink/renderer/core/layout/layout_video.cc
index 733580f5..10ad975 100644
--- a/third_party/blink/renderer/core/layout/layout_video.cc
+++ b/third_party/blink/renderer/core/layout/layout_video.cc
@@ -25,7 +25,6 @@
 
 #include "third_party/blink/renderer/core/layout/layout_video.h"
 
-#include "third_party/blink/public/platform/web_size.h"
 #include "third_party/blink/renderer/core/dom/document.h"
 #include "third_party/blink/renderer/core/html/media/html_video_element.h"
 #include "third_party/blink/renderer/core/paint/video_painter.h"
diff --git a/third_party/blink/renderer/core/layout/ng/table/ng_table_layout_algorithm_helpers.cc b/third_party/blink/renderer/core/layout/ng/table/ng_table_layout_algorithm_helpers.cc
index d7e735e..58ce313 100644
--- a/third_party/blink/renderer/core/layout/ng/table/ng_table_layout_algorithm_helpers.cc
+++ b/third_party/blink/renderer/core/layout/ng/table/ng_table_layout_algorithm_helpers.cc
@@ -329,8 +329,18 @@
   unsigned all_columns_count = 0;
   unsigned percent_columns_count = 0;
   unsigned auto_columns_count = 0;
-  unsigned auto_empty_columns_count = 0;
   unsigned fixed_columns_count = 0;
+  unsigned zero_inline_size_constrained_colums_count = 0;
+
+  auto TreatAsFixed = [](const NGTableTypes::Column& column) {
+    // Columns of width 0 are treated as auto by all browsers.
+    return column.IsFixed() && column.max_inline_size != LayoutUnit();
+  };
+
+  auto IsZeroInlineSizeConstrained = [](const NGTableTypes::Column& column) {
+    // Columns of width 0 are treated as auto by all browsers.
+    return column.is_constrained && column.max_inline_size == LayoutUnit();
+  };
 
   float total_percent = 0.0f;
   LayoutUnit total_percent_inline_size;
@@ -346,13 +356,13 @@
       total_percent += *column.percent;
       total_percent_inline_size +=
           column.ResolvePercentInlineSize(target_inline_size);
-    } else if (column.is_constrained) {  // Fixed column
+    } else if (TreatAsFixed(column)) {
       fixed_columns_count++;
       total_fixed_inline_size += column.max_inline_size.value_or(LayoutUnit());
+    } else if (IsZeroInlineSizeConstrained(column)) {
+      zero_inline_size_constrained_colums_count++;
     } else {
       auto_columns_count++;
-      if (*column.max_inline_size == LayoutUnit())
-        auto_empty_columns_count++;
       total_auto_max_inline_size +=
           column.max_inline_size.value_or(LayoutUnit());
     }
@@ -380,7 +390,7 @@
     LayoutUnit* column_size = column_sizes.begin();
     for (const NGTableTypes::Column* column = column_constraints.data.begin();
          column != column_constraints.data.end(); ++column, ++column_size) {
-      if (!column->IsFixed())
+      if (!TreatAsFixed(*column))
         continue;
       last_column_size = column_size;
       if (scale_available) {
@@ -431,21 +441,32 @@
       assigned_inline_size += *column_size;
     }
   }
-  // Distribute to auto columns.
+  // Distribute to auto, and zero inline size columns.
   LayoutUnit distributing_inline_size =
       target_inline_size - assigned_inline_size;
   LayoutUnit* column_size = column_sizes.begin();
 
+  bool distribute_zero_inline_size =
+      zero_inline_size_constrained_colums_count == all_columns_count;
+
   for (const NGTableTypes::Column* column = column_constraints.data.begin();
        column != column_constraints.data.end(); ++column, ++column_size) {
-    if (column->percent || column->is_constrained)
+    if (column->percent || TreatAsFixed(*column))
       continue;
+    // Zero-width columns only grow if all columns are zero-width.
+    if (IsZeroInlineSizeConstrained(*column) && !distribute_zero_inline_size)
+      continue;
+
     last_column_size = column_size;
     *column_size =
-        LayoutUnit(distributing_inline_size / float(auto_columns_count));
+        LayoutUnit(distributing_inline_size /
+                   float(distribute_zero_inline_size
+                             ? zero_inline_size_constrained_colums_count
+                             : auto_columns_count));
     assigned_inline_size += *column_size;
   }
   LayoutUnit delta = target_inline_size - assigned_inline_size;
+  DCHECK(last_column_size);
   *last_column_size += delta;
 
   return column_sizes;
diff --git a/third_party/blink/renderer/core/loader/base_fetch_context.cc b/third_party/blink/renderer/core/loader/base_fetch_context.cc
index d1ee804a..8d86029 100644
--- a/third_party/blink/renderer/core/loader/base_fetch_context.cc
+++ b/third_party/blink/renderer/core/loader/base_fetch_context.cc
@@ -552,9 +552,10 @@
     origin_ok = true;
   } else if (RuntimeEnabledFeatures::FeaturePolicyForClientHintsEnabled()) {
     origin_ok =
-        (policy && policy->IsFeatureEnabledForOrigin(
-                       kClientHintsFeaturePolicyMapping[static_cast<int>(type)],
-                       resource_origin));
+        (policy &&
+         policy->IsFeatureEnabledForOrigin(
+             kClientHintsPermissionsPolicyMapping[static_cast<int>(type)],
+             resource_origin));
   } else {
     origin_ok = is_1p_origin;
   }
diff --git a/third_party/blink/renderer/core/loader/document_loader.cc b/third_party/blink/renderer/core/loader/document_loader.cc
index 78a961d..cf7d7af 100644
--- a/third_party/blink/renderer/core/loader/document_loader.cc
+++ b/third_party/blink/renderer/core/loader/document_loader.cc
@@ -2065,14 +2065,15 @@
     DCHECK(response_.HttpHeaderField(http_names::kFeaturePolicy).IsEmpty());
     DCHECK(response_.HttpHeaderField(http_names::kPermissionsPolicy).IsEmpty());
     DCHECK(response_.HttpHeaderField(http_names::kDocumentPolicy).IsEmpty());
-    security_init.InitFeaturePolicyFrom(previous_window->GetSecurityContext());
+    security_init.InitPermissionsPolicyFrom(
+        previous_window->GetSecurityContext());
     security_init.InitDocumentPolicyFrom(previous_window->GetSecurityContext());
   } else {
     // PermissionsPolicy and DocumentPolicy require SecurityOrigin and origin
     // trials to be initialized.
     // TODO(iclelland): Add Permissions-Policy-Report-Only to Origin Policy.
-    security_init.ApplyFeaturePolicy(frame_.Get(), response_, origin_policy_,
-                                     frame_policy_);
+    security_init.ApplyPermissionsPolicy(frame_.Get(), response_,
+                                         origin_policy_, frame_policy_);
     // |document_policy_| is parsed in document loader because it is
     // compared with |frame_policy.required_document_policy| to decide
     // whether to block the document load or not.
@@ -2212,7 +2213,8 @@
           history_item_.Get(), LoadTypeToCommitType(load_type_),
           previous_window != frame_->DomWindow(),
           frame_->DomWindow()->GetSandboxFlags(),
-          security_init.FeaturePolicyHeader(), document_policy_.feature_state);
+          security_init.PermissionsPolicyHeader(),
+          document_policy_.feature_state);
     }
     // TODO(dgozman): make DidCreateScriptContext notification call currently
     // triggered by installing new document happen here, after commit.
diff --git a/third_party/blink/renderer/core/loader/frame_fetch_context.cc b/third_party/blink/renderer/core/loader/frame_fetch_context.cc
index 3adbb0b..39aa68da 100644
--- a/third_party/blink/renderer/core/loader/frame_fetch_context.cc
+++ b/third_party/blink/renderer/core/loader/frame_fetch_context.cc
@@ -449,7 +449,7 @@
   // the requesting document, and the origin of the resource.
   const PermissionsPolicy* policy =
       document_
-          ? document_->domWindow()->GetSecurityContext().GetFeaturePolicy()
+          ? document_->domWindow()->GetSecurityContext().GetPermissionsPolicy()
           : nullptr;
 
   url::Origin resource_origin =
@@ -735,10 +735,11 @@
   return GetLocalFrameClient()->UserAgentMetadata();
 }
 
-const PermissionsPolicy* FrameFetchContext::GetFeaturePolicy() const {
-  return document_
-             ? document_->domWindow()->GetSecurityContext().GetFeaturePolicy()
-             : nullptr;
+const PermissionsPolicy* FrameFetchContext::GetPermissionsPolicy() const {
+  return document_ ? document_->domWindow()
+                         ->GetSecurityContext()
+                         .GetPermissionsPolicy()
+                   : nullptr;
 }
 
 const ClientHintsPreferences FrameFetchContext::GetClientHintsPreferences()
diff --git a/third_party/blink/renderer/core/loader/frame_fetch_context.h b/third_party/blink/renderer/core/loader/frame_fetch_context.h
index fd0841be..a7e53040 100644
--- a/third_party/blink/renderer/core/loader/frame_fetch_context.h
+++ b/third_party/blink/renderer/core/loader/frame_fetch_context.h
@@ -182,7 +182,7 @@
   Settings* GetSettings() const;
   String GetUserAgent() const;
   base::Optional<UserAgentMetadata> GetUserAgentMetadata() const;
-  const PermissionsPolicy* GetFeaturePolicy() const override;
+  const PermissionsPolicy* GetPermissionsPolicy() const override;
   const ClientHintsPreferences GetClientHintsPreferences() const;
   float GetDevicePixelRatio() const;
 
diff --git a/third_party/blink/renderer/core/loader/frame_fetch_context_test.cc b/third_party/blink/renderer/core/loader/frame_fetch_context_test.cc
index 0a84a2e..2485dbb 100644
--- a/third_party/blink/renderer/core/loader/frame_fetch_context_test.cc
+++ b/third_party/blink/renderer/core/loader/frame_fetch_context_test.cc
@@ -911,7 +911,7 @@
 // Verify that the client hints should be attached for third-party subresources
 // fetched over secure transport, when specifically allowed by permissions
 // policy.
-TEST_F(FrameFetchContextHintsTest, MonitorAllHintsFeaturePolicy) {
+TEST_F(FrameFetchContextHintsTest, MonitorAllHintsPermissionsPolicy) {
   RecreateFetchContext(
       KURL("https://www.example.com/"),
       "ch-dpr *; ch-device-memory *; ch-downlink *; ch-ect *; ch-lang *;"
@@ -977,7 +977,7 @@
 
 // Verify that only the specifically allowed client hints are attached for
 // third-party subresources fetched over secure transport.
-TEST_F(FrameFetchContextHintsTest, MonitorSomeHintsFeaturePolicy) {
+TEST_F(FrameFetchContextHintsTest, MonitorSomeHintsPermissionsPolicy) {
   RecreateFetchContext(KURL("https://www.example.com/"),
                        "ch-device-memory 'self' https://www.example.net");
   document->GetSettings()->SetScriptEnabled(true);
@@ -1025,7 +1025,8 @@
 // Verify that the client hints are not attached for third-party subresources
 // fetched over insecure transport, even when specifically allowed by
 // permissions policy.
-TEST_F(FrameFetchContextHintsTest, MonitorHintsFeaturePolicyInsecureContext) {
+TEST_F(FrameFetchContextHintsTest,
+       MonitorHintsPermissionsPolicyInsecureContext) {
   RecreateFetchContext(KURL("https://www.example.com/"), "ch-device-memory *");
   document->GetSettings()->SetScriptEnabled(true);
   ExpectHeader("https://www.example.com/1.gif", "Device-Memory", false, "");
diff --git a/third_party/blink/renderer/core/loader/programmatic_scroll_test.cc b/third_party/blink/renderer/core/loader/programmatic_scroll_test.cc
index b7ae037..0338a74 100644
--- a/third_party/blink/renderer/core/loader/programmatic_scroll_test.cc
+++ b/third_party/blink/renderer/core/loader/programmatic_scroll_test.cc
@@ -58,7 +58,7 @@
   loader.GetDocumentLoader()->SetLoadType(WebFrameLoadType::kBackForward);
 
   web_view->SetPageScaleFactor(3.0f);
-  web_view->MainFrameImpl()->SetScrollOffset(WebSize(0, 500));
+  web_view->MainFrameImpl()->SetScrollOffset(gfx::ScrollOffset(0, 500));
   loader.GetDocumentLoader()->GetInitialScrollState().was_scrolled_by_user =
       false;
   loader.GetDocumentLoader()->GetHistoryItem()->SetPageScaleFactor(2);
@@ -76,7 +76,7 @@
 
   // Expect that both scroll and scale were restored.
   EXPECT_EQ(2.0f, web_view->PageScaleFactor());
-  EXPECT_EQ(200, web_view->MainFrameImpl()->GetScrollOffset().height);
+  EXPECT_EQ(200, web_view->MainFrameImpl()->GetScrollOffset().y());
 }
 
 TEST_F(ProgrammaticScrollTest, RestoreScrollPositionAndViewStateWithoutScale) {
@@ -93,7 +93,7 @@
   loader.GetDocumentLoader()->SetLoadType(WebFrameLoadType::kBackForward);
 
   web_view->SetPageScaleFactor(3.0f);
-  web_view->MainFrameImpl()->SetScrollOffset(WebSize(0, 500));
+  web_view->MainFrameImpl()->SetScrollOffset(gfx::ScrollOffset(0, 500));
   loader.GetDocumentLoader()->GetInitialScrollState().was_scrolled_by_user =
       false;
   loader.GetDocumentLoader()->GetHistoryItem()->SetPageScaleFactor(0);
@@ -108,7 +108,7 @@
 
   // Expect that only the scroll position was restored.
   EXPECT_EQ(3.0f, web_view->PageScaleFactor());
-  EXPECT_EQ(400, web_view->MainFrameImpl()->GetScrollOffset().height);
+  EXPECT_EQ(400, web_view->MainFrameImpl()->GetScrollOffset().y());
 }
 
 TEST_F(ProgrammaticScrollTest, SaveScrollStateClearsAnchor) {
@@ -124,20 +124,20 @@
   FrameLoader& loader = web_view->MainFrameImpl()->GetFrame()->Loader();
   loader.GetDocumentLoader()->SetLoadType(WebFrameLoadType::kBackForward);
 
-  web_view->MainFrameImpl()->SetScrollOffset(WebSize(0, 500));
+  web_view->MainFrameImpl()->SetScrollOffset(gfx::ScrollOffset(0, 500));
   loader.GetDocumentLoader()->GetInitialScrollState().was_scrolled_by_user =
       true;
   loader.SaveScrollState();
   loader.SaveScrollAnchor();
 
-  web_view->MainFrameImpl()->SetScrollOffset(WebSize(0, 0));
+  web_view->MainFrameImpl()->SetScrollOffset(gfx::ScrollOffset(0, 0));
   loader.SaveScrollState();
   loader.GetDocumentLoader()->GetInitialScrollState().was_scrolled_by_user =
       false;
 
   loader.RestoreScrollPositionAndViewState();
 
-  EXPECT_EQ(0, web_view->MainFrameImpl()->GetScrollOffset().height);
+  EXPECT_EQ(0, web_view->MainFrameImpl()->GetScrollOffset().y());
 }
 
 class ProgrammaticScrollSimTest : public SimTest {};
diff --git a/third_party/blink/renderer/core/loader/threaded_icon_loader.h b/third_party/blink/renderer/core/loader/threaded_icon_loader.h
index 1df49f8..4497f32 100644
--- a/third_party/blink/renderer/core/loader/threaded_icon_loader.h
+++ b/third_party/blink/renderer/core/loader/threaded_icon_loader.h
@@ -8,12 +8,12 @@
 #include "base/memory/scoped_refptr.h"
 #include "base/optional.h"
 #include "base/time/time.h"
-#include "third_party/blink/public/platform/web_size.h"
 #include "third_party/blink/renderer/core/core_export.h"
 #include "third_party/blink/renderer/core/loader/threadable_loader.h"
 #include "third_party/blink/renderer/core/loader/threadable_loader_client.h"
 #include "third_party/blink/renderer/platform/heap/garbage_collected.h"
 #include "third_party/skia/include/core/SkBitmap.h"
+#include "ui/gfx/geometry/size.h"
 
 namespace blink {
 
diff --git a/third_party/blink/renderer/core/loader/threaded_icon_loader_test.cc b/third_party/blink/renderer/core/loader/threaded_icon_loader_test.cc
index 8e912ed..39d8452 100644
--- a/third_party/blink/renderer/core/loader/threaded_icon_loader_test.cc
+++ b/third_party/blink/renderer/core/loader/threaded_icon_loader_test.cc
@@ -7,7 +7,6 @@
 #include "base/optional.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "third_party/blink/public/mojom/fetch/fetch_api_request.mojom-blink.h"
-#include "third_party/blink/public/platform/web_size.h"
 #include "third_party/blink/public/platform/web_url.h"
 #include "third_party/blink/public/platform/web_url_loader_mock_factory.h"
 #include "third_party/blink/renderer/core/dom/document.h"
diff --git a/third_party/blink/renderer/core/offscreencanvas/OWNERS b/third_party/blink/renderer/core/offscreencanvas/OWNERS
index 1e56363..9a1d5cc 100644
--- a/third_party/blink/renderer/core/offscreencanvas/OWNERS
+++ b/third_party/blink/renderer/core/offscreencanvas/OWNERS
@@ -1 +1,2 @@
 fserb@chromium.org
+junov@chromium.org
diff --git a/third_party/blink/renderer/core/origin_trials/origin_trial_context_test.cc b/third_party/blink/renderer/core/origin_trials/origin_trial_context_test.cc
index 7e4395f..47a20ed 100644
--- a/third_party/blink/renderer/core/origin_trials/origin_trial_context_test.cc
+++ b/third_party/blink/renderer/core/origin_trials/origin_trial_context_test.cc
@@ -430,8 +430,8 @@
 
   PolicyParserMessageBuffer logger;
   ParsedPermissionsPolicy result;
-  result = PermissionsPolicyParser::ParseFeaturePolicyForTest(
-      "frobulate", security_origin, nullptr, logger, feature_map, window);
+  result = PermissionsPolicyParser::ParsePermissionsPolicyForTest(
+      "frobulate=*", security_origin, nullptr, logger, feature_map, window);
   EXPECT_TRUE(logger.GetMessages().IsEmpty());
   ASSERT_EQ(1u, result.size());
   EXPECT_EQ(mojom::blink::PermissionsPolicyFeature::kFrobulate,
diff --git a/third_party/blink/renderer/core/paint/html_canvas_painter_test.cc b/third_party/blink/renderer/core/paint/html_canvas_painter_test.cc
index 89854cb..45f16213 100644
--- a/third_party/blink/renderer/core/paint/html_canvas_painter_test.cc
+++ b/third_party/blink/renderer/core/paint/html_canvas_painter_test.cc
@@ -9,7 +9,6 @@
 
 #include "cc/layers/layer.h"
 #include "components/viz/test/test_context_provider.h"
-#include "third_party/blink/public/platform/web_size.h"
 #include "third_party/blink/renderer/core/frame/local_frame_view.h"
 #include "third_party/blink/renderer/core/html/canvas/canvas_context_creation_attributes_core.h"
 #include "third_party/blink/renderer/core/html/canvas/canvas_rendering_context.h"
diff --git a/third_party/blink/renderer/core/paint/link_highlight_impl.cc b/third_party/blink/renderer/core/paint/link_highlight_impl.cc
index 1e51831..402ceb9 100644
--- a/third_party/blink/renderer/core/paint/link_highlight_impl.cc
+++ b/third_party/blink/renderer/core/paint/link_highlight_impl.cc
@@ -33,7 +33,6 @@
 #include "cc/layers/picture_layer.h"
 #include "cc/paint/display_item_list.h"
 #include "third_party/blink/public/platform/platform.h"
-#include "third_party/blink/public/platform/web_size.h"
 #include "third_party/blink/public/web/blink.h"
 #include "third_party/blink/renderer/core/dom/layout_tree_builder_traversal.h"
 #include "third_party/blink/renderer/core/dom/node.h"
diff --git a/third_party/blink/renderer/core/paint/link_highlight_impl_test.cc b/third_party/blink/renderer/core/paint/link_highlight_impl_test.cc
index 6883719..bc6d174 100644
--- a/third_party/blink/renderer/core/paint/link_highlight_impl_test.cc
+++ b/third_party/blink/renderer/core/paint/link_highlight_impl_test.cc
@@ -31,7 +31,6 @@
 #include "cc/trees/layer_tree_host.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "third_party/blink/public/common/input/web_input_event.h"
-#include "third_party/blink/public/platform/web_size.h"
 #include "third_party/blink/public/platform/web_url_loader_mock_factory.h"
 #include "third_party/blink/public/web/web_frame.h"
 #include "third_party/blink/public/web/web_local_frame_client.h"
diff --git a/third_party/blink/renderer/core/paint/paint_and_raster_invalidation_test.cc b/third_party/blink/renderer/core/paint/paint_and_raster_invalidation_test.cc
index fb7cf47..ac288ecb 100644
--- a/third_party/blink/renderer/core/paint/paint_and_raster_invalidation_test.cc
+++ b/third_party/blink/renderer/core/paint/paint_and_raster_invalidation_test.cc
@@ -454,7 +454,7 @@
   UpdateAllLifecyclePhasesForTest();
 
   GetDocument().View()->SetTracksRasterInvalidations(true);
-  GetDocument().View()->Resize(WebSize(500, 500));
+  GetDocument().View()->Resize(IntSize(500, 500));
   UpdateAllLifecyclePhasesForTest();
 
   EXPECT_THAT(GetRasterInvalidationTracking()->Invalidations(),
diff --git a/third_party/blink/renderer/core/paint/paint_property_tree_builder.cc b/third_party/blink/renderer/core/paint/paint_property_tree_builder.cc
index 8c481bd..9a66acc 100644
--- a/third_party/blink/renderer/core/paint/paint_property_tree_builder.cc
+++ b/third_party/blink/renderer/core/paint/paint_property_tree_builder.cc
@@ -38,7 +38,6 @@
 #include "third_party/blink/renderer/core/page/scrolling/snap_coordinator.h"
 #include "third_party/blink/renderer/core/page/scrolling/top_document_root_scroller_controller.h"
 #include "third_party/blink/renderer/core/paint/clip_path_clipper.h"
-#include "third_party/blink/renderer/core/paint/compositing/composited_layer_mapping.h"
 #include "third_party/blink/renderer/core/paint/compositing/compositing_reason_finder.h"
 #include "third_party/blink/renderer/core/paint/css_mask_painter.h"
 #include "third_party/blink/renderer/core/paint/find_paint_offset_needing_update.h"
@@ -49,8 +48,8 @@
 #include "third_party/blink/renderer/core/paint/paint_property_tree_printer.h"
 #include "third_party/blink/renderer/core/paint/rounded_border_geometry.h"
 #include "third_party/blink/renderer/core/paint/svg_root_painter.h"
-#include "third_party/blink/renderer/platform/graphics/bitmap_image.h"
 #include "third_party/blink/renderer/platform/graphics/compositing/paint_artifact_compositor.h"
+#include "third_party/blink/renderer/platform/graphics/skia/skia_utils.h"
 #include "third_party/blink/renderer/platform/transforms/transformation_matrix.h"
 
 namespace blink {
diff --git a/third_party/blink/renderer/core/paint/video_painter_test.cc b/third_party/blink/renderer/core/paint/video_painter_test.cc
index 3b37ce2..5dcc626 100644
--- a/third_party/blink/renderer/core/paint/video_painter_test.cc
+++ b/third_party/blink/renderer/core/paint/video_painter_test.cc
@@ -8,7 +8,6 @@
 #include "cc/layers/layer.h"
 #include "components/paint_preview/common/paint_preview_tracker.h"
 #include "third_party/blink/public/platform/platform.h"
-#include "third_party/blink/public/platform/web_size.h"
 #include "third_party/blink/renderer/core/frame/frame_test_helpers.h"
 #include "third_party/blink/renderer/core/frame/web_local_frame_impl.h"
 #include "third_party/blink/renderer/core/html/media/html_media_element.h"
diff --git a/third_party/blink/renderer/core/permissions_policy/dom_feature_policy.h b/third_party/blink/renderer/core/permissions_policy/dom_feature_policy.h
index bc4c488..497c274 100644
--- a/third_party/blink/renderer/core/permissions_policy/dom_feature_policy.h
+++ b/third_party/blink/renderer/core/permissions_policy/dom_feature_policy.h
@@ -54,7 +54,7 @@
 
  protected:
   virtual const PermissionsPolicy* GetPolicy() const {
-    return context_->GetSecurityContext().GetFeaturePolicy();
+    return context_->GetSecurityContext().GetPermissionsPolicy();
   }
 
   virtual bool IsIFramePolicy() const { return false; }
diff --git a/third_party/blink/renderer/core/permissions_policy/iframe_policy.h b/third_party/blink/renderer/core/permissions_policy/iframe_policy.h
index 560d125..0faa073 100644
--- a/third_party/blink/renderer/core/permissions_policy/iframe_policy.h
+++ b/third_party/blink/renderer/core/permissions_policy/iframe_policy.h
@@ -34,7 +34,7 @@
       const ParsedPermissionsPolicy& container_policy,
       scoped_refptr<const SecurityOrigin> src_origin) override {
     policy_ = PermissionsPolicy::CreateFromParentPolicy(
-        context_->GetSecurityContext().GetFeaturePolicy(), container_policy,
+        context_->GetSecurityContext().GetPermissionsPolicy(), container_policy,
         src_origin->ToUrlOrigin());
   }
 
diff --git a/third_party/blink/renderer/core/permissions_policy/permissions_policy_devtools_support.cc b/third_party/blink/renderer/core/permissions_policy/permissions_policy_devtools_support.cc
index fbf1cef..f5fa39dd 100644
--- a/third_party/blink/renderer/core/permissions_policy/permissions_policy_devtools_support.cc
+++ b/third_party/blink/renderer/core/permissions_policy/permissions_policy_devtools_support.cc
@@ -12,11 +12,11 @@
 
 namespace blink {
 
-base::Optional<FeaturePolicyBlockLocator> TraceFeaturePolicyBlockSource(
+base::Optional<PermissionsPolicyBlockLocator> TracePermissionsPolicyBlockSource(
     Frame* frame,
     mojom::PermissionsPolicyFeature feature) {
   const PermissionsPolicy* current_policy =
-      frame->GetSecurityContext()->GetFeaturePolicy();
+      frame->GetSecurityContext()->GetPermissionsPolicy();
   DCHECK(current_policy);
   if (current_policy->IsFeatureEnabled(feature))
     return base::nullopt;
@@ -32,7 +32,8 @@
   // - The iframe attribute on |child_frame|'s html frame owner element.
   while (true) {
     DCHECK(current_frame);
-    current_policy = current_frame->GetSecurityContext()->GetFeaturePolicy();
+    current_policy =
+        current_frame->GetSecurityContext()->GetPermissionsPolicy();
     DCHECK(current_policy);
 
     if (current_policy->IsFeatureEnabledByInheritedPolicy(feature))
@@ -55,9 +56,9 @@
 
   if (!allowed_by_current_frame || !allowed_by_child_frame) {
     // Feature disabled by allowlist, i.e. value in HTTP header.
-    return FeaturePolicyBlockLocator{
+    return PermissionsPolicyBlockLocator{
         IdentifiersFactory::FrameId(current_frame),
-        FeaturePolicyBlockReason::kHeader,
+        PermissionsPolicyBlockReason::kHeader,
     };
   } else {
     // Otherwise, feature must be disabled by iframe attribute.
@@ -69,9 +70,9 @@
     // Along with (2), we can conclude feature is enabled by container policy
     // (iframe attribute) which contradicts with the else branch condition.
     DCHECK(child_frame);
-    return FeaturePolicyBlockLocator{
+    return PermissionsPolicyBlockLocator{
         IdentifiersFactory::FrameId(child_frame),
-        FeaturePolicyBlockReason::kIframeAttribute,
+        PermissionsPolicyBlockReason::kIframeAttribute,
     };
   }
 }
diff --git a/third_party/blink/renderer/core/permissions_policy/permissions_policy_devtools_support.h b/third_party/blink/renderer/core/permissions_policy/permissions_policy_devtools_support.h
index ac9043ff..553859f 100644
--- a/third_party/blink/renderer/core/permissions_policy/permissions_policy_devtools_support.h
+++ b/third_party/blink/renderer/core/permissions_policy/permissions_policy_devtools_support.h
@@ -15,25 +15,25 @@
 class Frame;
 
 // The reason for a feature to be disallowed.
-enum class FeaturePolicyBlockReason {
+enum class PermissionsPolicyBlockReason {
   // Feature's allowlist declaration can be overridden either in HTTP header,
   // or in iframe attribute.
   kHeader,
   kIframeAttribute,
 };
 
-struct FeaturePolicyBlockLocator {
+struct PermissionsPolicyBlockLocator {
   // FrameId used in devtools protocol.
   String frame_id;
   // Note: Attribute declaration is on frame's owner element, which is
   // technically above 1 level in the frame tree.
-  FeaturePolicyBlockReason reason;
+  PermissionsPolicyBlockReason reason;
 };
 
 // Traces the root reason for a feature to be disabled in a frame.
 // Returns base::nullopt when the feature is enabled in the frame.
-CORE_EXPORT base::Optional<FeaturePolicyBlockLocator>
-TraceFeaturePolicyBlockSource(Frame*, mojom::PermissionsPolicyFeature);
+CORE_EXPORT base::Optional<PermissionsPolicyBlockLocator>
+TracePermissionsPolicyBlockSource(Frame*, mojom::PermissionsPolicyFeature);
 
 }  // namespace blink
 
diff --git a/third_party/blink/renderer/core/permissions_policy/permissions_policy_devtools_support_test.cc b/third_party/blink/renderer/core/permissions_policy/permissions_policy_devtools_support_test.cc
index a21c6f7d..d37abb9 100644
--- a/third_party/blink/renderer/core/permissions_policy/permissions_policy_devtools_support_test.cc
+++ b/third_party/blink/renderer/core/permissions_policy/permissions_policy_devtools_support_test.cc
@@ -12,11 +12,11 @@
 #include "third_party/blink/renderer/core/testing/sim/sim_test.h"
 
 namespace blink {
-using FeaturePolicyDevtoolsSupportSimTest = SimTest;
+using PermissionsPolicyDevtoolsSupportSimTest = SimTest;
 
 // Note: fullscreen has default allowlist 'EnableForSelf'.
 
-TEST_F(FeaturePolicyDevtoolsSupportSimTest, DetectIframeAttributeBlockage) {
+TEST_F(PermissionsPolicyDevtoolsSupportSimTest, DetectIframeAttributeBlockage) {
   SimRequest main_resource("https://example.com", "text/html");
   SimRequest iframe_resource("https://example.com/foo.html", "text/html");
 
@@ -26,18 +26,18 @@
     )");
   iframe_resource.Finish();
 
-  base::Optional<FeaturePolicyBlockLocator> locator =
-      TraceFeaturePolicyBlockSource(
+  base::Optional<PermissionsPolicyBlockLocator> locator =
+      TracePermissionsPolicyBlockSource(
           MainFrame().GetFrame()->FirstChild(),
           mojom::blink::PermissionsPolicyFeature::kFullscreen);
 
   ASSERT_NE(locator, base::nullopt);
   EXPECT_EQ(locator->frame_id,
             IdentifiersFactory::FrameId(MainFrame().GetFrame()->FirstChild()));
-  EXPECT_EQ(locator->reason, FeaturePolicyBlockReason::kIframeAttribute);
+  EXPECT_EQ(locator->reason, PermissionsPolicyBlockReason::kIframeAttribute);
 }
 
-TEST_F(FeaturePolicyDevtoolsSupportSimTest,
+TEST_F(PermissionsPolicyDevtoolsSupportSimTest,
        DetectNestedIframeAttributeBlockage) {
   SimRequest main_resource("https://example.com", "text/html");
   SimRequest iframe_resource1("https://example.com/foo.html", "text/html");
@@ -52,18 +52,18 @@
     )");
   iframe_resource2.Finish();
 
-  base::Optional<FeaturePolicyBlockLocator> locator =
-      TraceFeaturePolicyBlockSource(
+  base::Optional<PermissionsPolicyBlockLocator> locator =
+      TracePermissionsPolicyBlockSource(
           MainFrame().GetFrame()->FirstChild()->FirstChild(),
           mojom::blink::PermissionsPolicyFeature::kFullscreen);
 
   ASSERT_NE(locator, base::nullopt);
   EXPECT_EQ(locator->frame_id,
             IdentifiersFactory::FrameId(MainFrame().GetFrame()->FirstChild()));
-  EXPECT_EQ(locator->reason, FeaturePolicyBlockReason::kIframeAttribute);
+  EXPECT_EQ(locator->reason, PermissionsPolicyBlockReason::kIframeAttribute);
 }
 
-TEST_F(FeaturePolicyDevtoolsSupportSimTest, DetectHeaderBlockage) {
+TEST_F(PermissionsPolicyDevtoolsSupportSimTest, DetectHeaderBlockage) {
   SimRequest::Params main_params;
   main_params.response_http_headers = {
       {"Permissions-Policy", "fullscreen=()"},
@@ -73,18 +73,18 @@
   LoadURL("https://example.com");
   main_resource.Finish();
 
-  base::Optional<FeaturePolicyBlockLocator> locator =
-      TraceFeaturePolicyBlockSource(
+  base::Optional<PermissionsPolicyBlockLocator> locator =
+      TracePermissionsPolicyBlockSource(
           MainFrame().GetFrame(),
           mojom::blink::PermissionsPolicyFeature::kFullscreen);
 
   ASSERT_NE(locator, base::nullopt);
   EXPECT_EQ(locator->frame_id,
             IdentifiersFactory::FrameId(MainFrame().GetFrame()));
-  EXPECT_EQ(locator->reason, FeaturePolicyBlockReason::kHeader);
+  EXPECT_EQ(locator->reason, PermissionsPolicyBlockReason::kHeader);
 }
 
-TEST_F(FeaturePolicyDevtoolsSupportSimTest, DetectNestedHeaderBlockage) {
+TEST_F(PermissionsPolicyDevtoolsSupportSimTest, DetectNestedHeaderBlockage) {
   SimRequest::Params main_params;
   main_params.response_http_headers = {
       {"Permissions-Policy", "fullscreen=()"},
@@ -99,20 +99,20 @@
     )");
   iframe_resource.Finish();
 
-  base::Optional<FeaturePolicyBlockLocator> locator =
-      TraceFeaturePolicyBlockSource(
+  base::Optional<PermissionsPolicyBlockLocator> locator =
+      TracePermissionsPolicyBlockSource(
           MainFrame().GetFrame()->FirstChild(),
           mojom::blink::PermissionsPolicyFeature::kFullscreen);
 
   ASSERT_NE(locator, base::nullopt);
   EXPECT_EQ(locator->frame_id,
             IdentifiersFactory::FrameId(MainFrame().GetFrame()));
-  EXPECT_EQ(locator->reason, FeaturePolicyBlockReason::kHeader);
+  EXPECT_EQ(locator->reason, PermissionsPolicyBlockReason::kHeader);
 }
 
 // When feature is disabled at multiple level of frames, report blockage
 // closest to the root of frame tree.
-TEST_F(FeaturePolicyDevtoolsSupportSimTest, DetectRootHeaderBlockage) {
+TEST_F(PermissionsPolicyDevtoolsSupportSimTest, DetectRootHeaderBlockage) {
   SimRequest::Params main_params;
   main_params.response_http_headers = {
       {"Permissions-Policy", "fullscreen=()"},
@@ -132,18 +132,19 @@
     )");
   iframe_resource.Finish();
 
-  base::Optional<FeaturePolicyBlockLocator> locator =
-      TraceFeaturePolicyBlockSource(
+  base::Optional<PermissionsPolicyBlockLocator> locator =
+      TracePermissionsPolicyBlockSource(
           MainFrame().GetFrame()->FirstChild(),
           mojom::blink::PermissionsPolicyFeature::kFullscreen);
 
   ASSERT_NE(locator, base::nullopt);
   EXPECT_EQ(locator->frame_id,
             IdentifiersFactory::FrameId(MainFrame().GetFrame()));
-  EXPECT_EQ(locator->reason, FeaturePolicyBlockReason::kHeader);
+  EXPECT_EQ(locator->reason, PermissionsPolicyBlockReason::kHeader);
 }
 
-TEST_F(FeaturePolicyDevtoolsSupportSimTest, DetectCrossOriginHeaderBlockage) {
+TEST_F(PermissionsPolicyDevtoolsSupportSimTest,
+       DetectCrossOriginHeaderBlockage) {
   SimRequest::Params main_params;
   main_params.response_http_headers = {
       {"Permissions-Policy", "fullscreen=self"},
@@ -162,18 +163,18 @@
     )");
   iframe_resource.Finish();
 
-  base::Optional<FeaturePolicyBlockLocator> locator =
-      TraceFeaturePolicyBlockSource(
+  base::Optional<PermissionsPolicyBlockLocator> locator =
+      TracePermissionsPolicyBlockSource(
           MainFrame().GetFrame()->FirstChild(),
           mojom::blink::PermissionsPolicyFeature::kFullscreen);
 
   ASSERT_NE(locator, base::nullopt);
   EXPECT_EQ(locator->frame_id,
             IdentifiersFactory::FrameId(MainFrame().GetFrame()));
-  EXPECT_EQ(locator->reason, FeaturePolicyBlockReason::kHeader);
+  EXPECT_EQ(locator->reason, PermissionsPolicyBlockReason::kHeader);
 }
 
-TEST_F(FeaturePolicyDevtoolsSupportSimTest,
+TEST_F(PermissionsPolicyDevtoolsSupportSimTest,
        DetectCrossOriginDefaultAllowlistBlockage) {
   SimRequest main_resource("https://example.com", "text/html");
   SimRequest iframe_resource("https://foo.com", "text/html");
@@ -184,18 +185,18 @@
     )");
   iframe_resource.Finish();
 
-  base::Optional<FeaturePolicyBlockLocator> locator =
-      TraceFeaturePolicyBlockSource(
+  base::Optional<PermissionsPolicyBlockLocator> locator =
+      TracePermissionsPolicyBlockSource(
           MainFrame().GetFrame()->FirstChild(),
           mojom::blink::PermissionsPolicyFeature::kFullscreen);
 
   ASSERT_NE(locator, base::nullopt);
   EXPECT_EQ(locator->frame_id,
             IdentifiersFactory::FrameId(MainFrame().GetFrame()->FirstChild()));
-  EXPECT_EQ(locator->reason, FeaturePolicyBlockReason::kIframeAttribute);
+  EXPECT_EQ(locator->reason, PermissionsPolicyBlockReason::kIframeAttribute);
 }
 
-TEST_F(FeaturePolicyDevtoolsSupportSimTest,
+TEST_F(PermissionsPolicyDevtoolsSupportSimTest,
        DetectCrossOriginIframeAttributeBlockage) {
   SimRequest::Params main_params;
   main_params.response_http_headers = {
@@ -215,18 +216,19 @@
     )");
   iframe_resource.Finish();
 
-  base::Optional<FeaturePolicyBlockLocator> locator =
-      TraceFeaturePolicyBlockSource(
+  base::Optional<PermissionsPolicyBlockLocator> locator =
+      TracePermissionsPolicyBlockSource(
           MainFrame().GetFrame()->FirstChild(),
           mojom::blink::PermissionsPolicyFeature::kFullscreen);
 
   ASSERT_NE(locator, base::nullopt);
   EXPECT_EQ(locator->frame_id,
             IdentifiersFactory::FrameId(MainFrame().GetFrame()->FirstChild()));
-  EXPECT_EQ(locator->reason, FeaturePolicyBlockReason::kIframeAttribute);
+  EXPECT_EQ(locator->reason, PermissionsPolicyBlockReason::kIframeAttribute);
 }
 
-TEST_F(FeaturePolicyDevtoolsSupportSimTest, DetectNestedCrossOriginNoBlockage) {
+TEST_F(PermissionsPolicyDevtoolsSupportSimTest,
+       DetectNestedCrossOriginNoBlockage) {
   SimRequest::Params main_params;
   main_params.response_http_headers = {
       {"Permissions-Policy", "fullscreen=(self \"https://foo.com)\""},
@@ -254,8 +256,8 @@
     )");
   bar_resource.Finish();
 
-  base::Optional<FeaturePolicyBlockLocator> locator =
-      TraceFeaturePolicyBlockSource(
+  base::Optional<PermissionsPolicyBlockLocator> locator =
+      TracePermissionsPolicyBlockSource(
           MainFrame().GetFrame()->FirstChild()->FirstChild(),
           mojom::blink::PermissionsPolicyFeature::kFullscreen);
 
@@ -277,7 +279,7 @@
   EXPECT_EQ(locator, base::nullopt);
 }
 
-TEST_F(FeaturePolicyDevtoolsSupportSimTest, DetectNoBlockage) {
+TEST_F(PermissionsPolicyDevtoolsSupportSimTest, DetectNoBlockage) {
   SimRequest::Params main_params;
   main_params.response_http_headers = {
       {"Permissions-Policy", "fullscreen=*"},
@@ -287,8 +289,8 @@
   LoadURL("https://example.com");
   main_resource.Finish();
 
-  base::Optional<FeaturePolicyBlockLocator> locator =
-      TraceFeaturePolicyBlockSource(
+  base::Optional<PermissionsPolicyBlockLocator> locator =
+      TracePermissionsPolicyBlockSource(
           MainFrame().GetFrame(),
           mojom::blink::PermissionsPolicyFeature::kFullscreen);
 
diff --git a/third_party/blink/renderer/core/permissions_policy/policy_test.cc b/third_party/blink/renderer/core/permissions_policy/policy_test.cc
index fbbc3d5..295d2ed 100644
--- a/third_party/blink/renderer/core/permissions_policy/policy_test.cc
+++ b/third_party/blink/renderer/core/permissions_policy/policy_test.cc
@@ -41,7 +41,7 @@
     auto& security_context =
         page_holder_->GetFrame().DomWindow()->GetSecurityContext();
     security_context.SetSecurityOriginForTesting(origin);
-    security_context.SetFeaturePolicy(std::move(permissions_policy));
+    security_context.SetPermissionsPolicy(std::move(permissions_policy));
   }
 
   DOMFeaturePolicy* GetPolicy() const { return policy_; }
diff --git a/third_party/blink/renderer/core/style/computed_style_test.cc b/third_party/blink/renderer/core/style/computed_style_test.cc
index c066f289..76b1bc1 100644
--- a/third_party/blink/renderer/core/style/computed_style_test.cc
+++ b/third_party/blink/renderer/core/style/computed_style_test.cc
@@ -676,7 +676,7 @@
       mojom::blink::PreferredColorScheme::kDark);
   StyleResolverState state(dummy_page_holder_->GetDocument(),
                            *dummy_page_holder_->GetDocument().documentElement(),
-                           initial, initial);
+                           StyleRequest(initial));
 
   scoped_refptr<ComputedStyle> style = ComputedStyle::Create();
   state.SetStyle(style);
@@ -710,7 +710,7 @@
       mojom::blink::PreferredColorScheme::kDark);
   StyleResolverState state(dummy_page_holder_->GetDocument(),
                            *dummy_page_holder_->GetDocument().documentElement(),
-                           initial, initial);
+                           StyleRequest(initial));
 
   scoped_refptr<ComputedStyle> style = ComputedStyle::Create();
   state.SetStyle(style);
@@ -753,7 +753,7 @@
       mojom::blink::PreferredColorScheme::kDark);
   StyleResolverState state(dummy_page_holder_->GetDocument(),
                            *dummy_page_holder_->GetDocument().documentElement(),
-                           initial, initial);
+                           StyleRequest(initial));
 
   scoped_refptr<ComputedStyle> style = ComputedStyle::Create();
   state.SetStyle(style);
@@ -792,7 +792,7 @@
 
   StyleResolverState state(dummy_page_holder_->GetDocument(),
                            *dummy_page_holder_->GetDocument().documentElement(),
-                           initial, initial);
+                           StyleRequest(initial));
 
   scoped_refptr<ComputedStyle> style = ComputedStyle::Create();
   style->SetEffectiveZoom(1.5);
@@ -915,7 +915,7 @@
 
   StyleResolverState state(dummy_page_holder_->GetDocument(),
                            *dummy_page_holder_->GetDocument().documentElement(),
-                           initial, initial);
+                           StyleRequest(initial));
 
   scoped_refptr<ComputedStyle> style = ComputedStyle::Create();
   style->SetEffectiveZoom(2);
@@ -961,7 +961,7 @@
 
   StyleResolverState state(dummy_page_holder_->GetDocument(),
                            *dummy_page_holder_->GetDocument().documentElement(),
-                           initial, initial);
+                           StyleRequest(initial));
 
   scoped_refptr<ComputedStyle> style = ComputedStyle::Create();
 
@@ -1000,7 +1000,7 @@
 
   StyleResolverState state(dummy_page_holder_->GetDocument(),
                            *dummy_page_holder_->GetDocument().documentElement(),
-                           initial, initial);
+                           StyleRequest(initial));
 
   scoped_refptr<ComputedStyle> style = ComputedStyle::Create();
 
@@ -1107,7 +1107,7 @@
   const ComputedStyle* initial = &ComputedStyle::InitialStyle();
   StyleResolverState state(dummy_page_holder_->GetDocument(),
                            *dummy_page_holder_->GetDocument().documentElement(),
-                           initial, initial);
+                           StyleRequest(initial));
 
   scoped_refptr<ComputedStyle> style = ComputedStyle::Create();
   state.SetStyle(style);
diff --git a/third_party/blink/renderer/core/workers/dedicated_worker.cc b/third_party/blink/renderer/core/workers/dedicated_worker.cc
index 39ebcef3..b263f3c1a 100644
--- a/third_party/blink/renderer/core/workers/dedicated_worker.cc
+++ b/third_party/blink/renderer/core/workers/dedicated_worker.cc
@@ -461,7 +461,7 @@
       mojom::blink::V8CacheOptions::kDefault,
       nullptr /* worklet_module_responses_map */,
       std::move(browser_interface_broker_), CreateBeginFrameProviderParams(),
-      GetExecutionContext()->GetSecurityContext().GetFeaturePolicy(),
+      GetExecutionContext()->GetSecurityContext().GetPermissionsPolicy(),
       GetExecutionContext()->GetAgentClusterID(),
       GetExecutionContext()->UkmSourceID(),
       GetExecutionContext()->GetExecutionContextToken(),
diff --git a/third_party/blink/renderer/core/workers/worker_global_scope.cc b/third_party/blink/renderer/core/workers/worker_global_scope.cc
index 56fe4112..096a9d1 100644
--- a/third_party/blink/renderer/core/workers/worker_global_scope.cc
+++ b/third_party/blink/renderer/core/workers/worker_global_scope.cc
@@ -588,7 +588,7 @@
   // PermissionsPolicy::CreateFromParentPolicy, even if the parent policy is
   // null.
   DCHECK(creation_params->worker_permissions_policy);
-  GetSecurityContext().SetFeaturePolicy(
+  GetSecurityContext().SetPermissionsPolicy(
       std::move(creation_params->worker_permissions_policy));
 }
 
diff --git a/third_party/blink/renderer/modules/background_fetch/background_fetch_icon_loader.cc b/third_party/blink/renderer/modules/background_fetch/background_fetch_icon_loader.cc
index c8eebd2..e7f19be0 100644
--- a/third_party/blink/renderer/modules/background_fetch/background_fetch_icon_loader.cc
+++ b/third_party/blink/renderer/modules/background_fetch/background_fetch_icon_loader.cc
@@ -7,7 +7,6 @@
 #include "base/time/time.h"
 #include "third_party/blink/public/common/manifest/manifest_icon_selector.h"
 #include "third_party/blink/public/mojom/fetch/fetch_api_request.mojom-blink.h"
-#include "third_party/blink/public/platform/web_size.h"
 #include "third_party/blink/public/platform/web_url_request.h"
 #include "third_party/blink/renderer/bindings/modules/v8/v8_image_resource.h"
 #include "third_party/blink/renderer/core/execution_context/execution_context.h"
diff --git a/third_party/blink/renderer/modules/background_fetch/background_fetch_icon_loader_test.cc b/third_party/blink/renderer/modules/background_fetch/background_fetch_icon_loader_test.cc
index e7b57c7..acd74a3 100644
--- a/third_party/blink/renderer/modules/background_fetch/background_fetch_icon_loader_test.cc
+++ b/third_party/blink/renderer/modules/background_fetch/background_fetch_icon_loader_test.cc
@@ -7,7 +7,6 @@
 #include <utility>
 
 #include "testing/gtest/include/gtest/gtest.h"
-#include "third_party/blink/public/platform/web_size.h"
 #include "third_party/blink/public/platform/web_url.h"
 #include "third_party/blink/public/platform/web_url_loader_mock_factory.h"
 #include "third_party/blink/renderer/bindings/modules/v8/v8_image_resource.h"
diff --git a/third_party/blink/renderer/modules/battery/battery_manager.cc b/third_party/blink/renderer/modules/battery/battery_manager.cc
index bb1e4d422..b4dbe25 100644
--- a/third_party/blink/renderer/modules/battery/battery_manager.cc
+++ b/third_party/blink/renderer/modules/battery/battery_manager.cc
@@ -28,7 +28,7 @@
   LocalDOMWindow* window = navigator.DomWindow();
   if (!window->IsSecureContext())
     UseCounter::Count(window, WebFeature::kBatteryStatusInsecureOrigin);
-  window->GetFrame()->CountUseIfFeatureWouldBeBlockedByFeaturePolicy(
+  window->GetFrame()->CountUseIfFeatureWouldBeBlockedByPermissionsPolicy(
       WebFeature::kBatteryStatusCrossOrigin,
       WebFeature::kBatteryStatusSameOriginABA);
 
diff --git a/third_party/blink/renderer/modules/canvas/OWNERS b/third_party/blink/renderer/modules/canvas/OWNERS
index 3191493..492fe380 100644
--- a/third_party/blink/renderer/modules/canvas/OWNERS
+++ b/third_party/blink/renderer/modules/canvas/OWNERS
@@ -1,6 +1,7 @@
 fserb@chromium.org
 aaronhk@chromium.org
 juanmihd@chromium.org
+junov@chromium.org
 yiyix@chromium.org
 # canvas, imagebitmap
 senorblanco@chromium.org
diff --git a/third_party/blink/renderer/modules/canvas/canvas2d/canvas_rendering_context_2d_state.cc b/third_party/blink/renderer/modules/canvas/canvas2d/canvas_rendering_context_2d_state.cc
index d030aba..ecc903f 100644
--- a/third_party/blink/renderer/modules/canvas/canvas2d/canvas_rendering_context_2d_state.cc
+++ b/third_party/blink/renderer/modules/canvas/canvas2d/canvas_rendering_context_2d_state.cc
@@ -403,7 +403,7 @@
     }
     StyleResolverState resolver_state(style_resolution_host->GetDocument(),
                                       *style_resolution_host,
-                                      filter_style.get(), filter_style.get());
+                                      StyleRequest(filter_style.get()));
     resolver_state.SetStyle(filter_style);
 
     StyleBuilder::ApplyProperty(
diff --git a/third_party/blink/renderer/modules/content_index/content_index.cc b/third_party/blink/renderer/modules/content_index/content_index.cc
index ef52fa5..d0bd34c 100644
--- a/third_party/blink/renderer/modules/content_index/content_index.cc
+++ b/third_party/blink/renderer/modules/content_index/content_index.cc
@@ -7,7 +7,6 @@
 #include "base/feature_list.h"
 #include "base/optional.h"
 #include "third_party/blink/public/common/browser_interface_broker_proxy.h"
-#include "third_party/blink/public/platform/web_size.h"
 #include "third_party/blink/renderer/bindings/core/v8/script_promise_resolver.h"
 #include "third_party/blink/renderer/bindings/modules/v8/v8_content_icon_definition.h"
 #include "third_party/blink/renderer/core/dom/dom_exception.h"
diff --git a/third_party/blink/renderer/modules/credentialmanager/credentials_container.cc b/third_party/blink/renderer/modules/credentialmanager/credentials_container.cc
index c827b42..41d98d4 100644
--- a/third_party/blink/renderer/modules/credentialmanager/credentials_container.cc
+++ b/third_party/blink/renderer/modules/credentialmanager/credentials_container.cc
@@ -104,7 +104,7 @@
   kSecure,
   // Must be a secure origin and be same-origin with all ancestor frames.
   kSecureAndSameWithAncestors,
-  // Must be a secure origin and the "publickey-credentials-get" feature
+  // Must be a secure origin and the "publickey-credentials-get" permissions
   // policy must be enabled. By default "publickey-credentials-get" is not
   // inherited by cross-origin child frames, so if that policy is not
   // explicitly enabled, behavior is the same as that of
@@ -112,9 +112,9 @@
   // expressed in various ways, e.g.: |allow| iframe attribute and/or
   // permissions-policy header, and may be inherited from parent browsing
   // contexts. See Permissions Policy spec.
-  kSecureAndPermittedByWebAuthGetAssertionFeaturePolicy,
+  kSecureAndPermittedByWebAuthGetAssertionPermissionsPolicy,
   // Similar to the enum above, checks the "otp-credentials" permissions policy.
-  kSecureAndPermittedByWebOTPAssertionFeaturePolicy,
+  kSecureAndPermittedByWebOTPAssertionPermissionsPolicy,
 };
 
 bool IsSameOriginWithAncestors(const Frame* frame) {
@@ -198,7 +198,7 @@
       break;
 
     case RequiredOriginType::
-        kSecureAndPermittedByWebAuthGetAssertionFeaturePolicy:
+        kSecureAndPermittedByWebAuthGetAssertionPermissionsPolicy:
       // The 'publickey-credentials-get' feature's "default allowlist" is
       // "self", which means the webauthn feature is allowed by default in
       // same-origin child browsing contexts.
@@ -218,7 +218,8 @@
       }
       break;
 
-    case RequiredOriginType::kSecureAndPermittedByWebOTPAssertionFeaturePolicy:
+    case RequiredOriginType::
+        kSecureAndPermittedByWebOTPAssertionPermissionsPolicy:
       if (!resolver->GetExecutionContext()->IsFeatureEnabled(
               mojom::blink::PermissionsPolicyFeature::kOTPCredentials)) {
         resolver->Reject(MakeGarbageCollected<DOMException>(
@@ -261,12 +262,13 @@
       break;
 
     case RequiredOriginType::
-        kSecureAndPermittedByWebAuthGetAssertionFeaturePolicy:
+        kSecureAndPermittedByWebAuthGetAssertionPermissionsPolicy:
       SECURITY_CHECK(resolver->GetExecutionContext()->IsFeatureEnabled(
           mojom::blink::PermissionsPolicyFeature::kPublicKeyCredentialsGet));
       break;
 
-    case RequiredOriginType::kSecureAndPermittedByWebOTPAssertionFeaturePolicy:
+    case RequiredOriginType::
+        kSecureAndPermittedByWebOTPAssertionPermissionsPolicy:
       SECURITY_CHECK(
           resolver->GetExecutionContext()->IsFeatureEnabled(
               mojom::blink::PermissionsPolicyFeature::kOTPCredentials) &&
@@ -642,7 +644,7 @@
       resolver, resolver->GetExecutionContext()->IsFeatureEnabled(
                     mojom::blink::PermissionsPolicyFeature::kOTPCredentials)
                     ? RequiredOriginType::
-                          kSecureAndPermittedByWebOTPAssertionFeaturePolicy
+                          kSecureAndPermittedByWebOTPAssertionPermissionsPolicy
                     : RequiredOriginType::kSecureAndSameWithAncestors);
   if (status == mojom::blink::SmsStatus::kUnhandledRequest) {
     resolver->Reject(MakeGarbageCollected<DOMException>(
@@ -939,11 +941,11 @@
       RuntimeEnabledFeatures::
           WebAuthenticationGetAssertionFeaturePolicyEnabled()) {
     required_origin_type = RequiredOriginType::
-        kSecureAndPermittedByWebAuthGetAssertionFeaturePolicy;
+        kSecureAndPermittedByWebAuthGetAssertionPermissionsPolicy;
   } else if (options->hasOtp() &&
              RuntimeEnabledFeatures::WebOTPAssertionFeaturePolicyEnabled()) {
-    required_origin_type =
-        RequiredOriginType::kSecureAndPermittedByWebOTPAssertionFeaturePolicy;
+    required_origin_type = RequiredOriginType::
+        kSecureAndPermittedByWebOTPAssertionPermissionsPolicy;
   }
   if (!CheckSecurityRequirementsBeforeRequest(resolver, required_origin_type)) {
     return promise;
diff --git a/third_party/blink/renderer/modules/encryptedmedia/encrypted_media_utils.h b/third_party/blink/renderer/modules/encryptedmedia/encrypted_media_utils.h
index 3162ba2..ac0e651 100644
--- a/third_party/blink/renderer/modules/encryptedmedia/encrypted_media_utils.h
+++ b/third_party/blink/renderer/modules/encryptedmedia/encrypted_media_utils.h
@@ -38,7 +38,7 @@
   kRemove = 8,
 };
 
-constexpr const char* kEncryptedMediaFeaturePolicyConsoleWarning =
+constexpr const char* kEncryptedMediaPermissionsPolicyConsoleWarning =
     "Encrypted Media access has been blocked because of a Feature Policy "
     "applied to the current document. See https://goo.gl/EuHzyv for more "
     "details.";
diff --git a/third_party/blink/renderer/modules/encryptedmedia/navigator_request_media_key_system_access.cc b/third_party/blink/renderer/modules/encryptedmedia/navigator_request_media_key_system_access.cc
index fbe67385..6780654 100644
--- a/third_party/blink/renderer/modules/encryptedmedia/navigator_request_media_key_system_access.cc
+++ b/third_party/blink/renderer/modules/encryptedmedia/navigator_request_media_key_system_access.cc
@@ -120,7 +120,7 @@
     window->AddConsoleMessage(MakeGarbageCollected<ConsoleMessage>(
         mojom::ConsoleMessageSource::kJavaScript,
         mojom::ConsoleMessageLevel::kWarning,
-        kEncryptedMediaFeaturePolicyConsoleWarning));
+        kEncryptedMediaPermissionsPolicyConsoleWarning));
     exception_state.ThrowSecurityError(
         "requestMediaKeySystemAccess is disabled by permissions policy.");
     return ScriptPromise();
diff --git a/third_party/blink/renderer/modules/image_downloader/image_downloader_impl.cc b/third_party/blink/renderer/modules/image_downloader/image_downloader_impl.cc
index 28e60f2..ec53c82 100644
--- a/third_party/blink/renderer/modules/image_downloader/image_downloader_impl.cc
+++ b/third_party/blink/renderer/modules/image_downloader/image_downloader_impl.cc
@@ -12,7 +12,6 @@
 #include "third_party/blink/public/mojom/fetch/fetch_api_request.mojom-blink.h"
 #include "third_party/blink/public/platform/interface_registry.h"
 #include "third_party/blink/public/platform/web_data.h"
-#include "third_party/blink/public/platform/web_size.h"
 #include "third_party/blink/public/platform/web_string.h"
 #include "third_party/blink/public/platform/web_vector.h"
 #include "third_party/blink/public/web/web_image.h"
diff --git a/third_party/blink/renderer/modules/manifest/image_resource_type_converters_test.cc b/third_party/blink/renderer/modules/manifest/image_resource_type_converters_test.cc
index c639c74..01d050d05 100644
--- a/third_party/blink/renderer/modules/manifest/image_resource_type_converters_test.cc
+++ b/third_party/blink/renderer/modules/manifest/image_resource_type_converters_test.cc
@@ -6,7 +6,6 @@
 
 #include "testing/gtest/include/gtest/gtest.h"
 #include "third_party/blink/public/mojom/manifest/manifest.mojom-blink.h"
-#include "third_party/blink/public/platform/web_size.h"
 #include "third_party/blink/public/platform/web_string.h"
 #include "third_party/blink/renderer/bindings/modules/v8/v8_image_resource.h"
 #include "third_party/blink/renderer/platform/weborigin/kurl.h"
diff --git a/third_party/blink/renderer/modules/manifest/manifest_parser.cc b/third_party/blink/renderer/modules/manifest/manifest_parser.cc
index e165ff6..24a0da7 100644
--- a/third_party/blink/renderer/modules/manifest/manifest_parser.cc
+++ b/third_party/blink/renderer/modules/manifest/manifest_parser.cc
@@ -14,7 +14,6 @@
 #include "third_party/blink/public/common/mime_util/mime_util.h"
 #include "third_party/blink/public/common/security/protocol_handler_security_level.h"
 #include "third_party/blink/public/platform/web_icon_sizes_parser.h"
-#include "third_party/blink/public/platform/web_size.h"
 #include "third_party/blink/public/platform/web_string.h"
 #include "third_party/blink/renderer/core/css/parser/css_parser.h"
 #include "third_party/blink/renderer/modules/manifest/manifest_uma_util.h"
diff --git a/third_party/blink/renderer/modules/media_capabilities/media_capabilities.cc b/third_party/blink/renderer/modules/media_capabilities/media_capabilities.cc
index eff0956..8c1d6518 100644
--- a/third_party/blink/renderer/modules/media_capabilities/media_capabilities.cc
+++ b/third_party/blink/renderer/modules/media_capabilities/media_capabilities.cc
@@ -961,7 +961,7 @@
     execution_context->AddConsoleMessage(MakeGarbageCollected<ConsoleMessage>(
         mojom::ConsoleMessageSource::kJavaScript,
         mojom::ConsoleMessageLevel::kWarning,
-        kEncryptedMediaFeaturePolicyConsoleWarning));
+        kEncryptedMediaPermissionsPolicyConsoleWarning));
     exception_state.ThrowSecurityError(
         "decodingInfo(): Creating MediaKeySystemAccess is disabled by feature "
         "policy.");
diff --git a/third_party/blink/renderer/modules/media_capabilities/media_capabilities_test.cc b/third_party/blink/renderer/modules/media_capabilities/media_capabilities_test.cc
index b7ac9a6..e254f7e 100644
--- a/third_party/blink/renderer/modules/media_capabilities/media_capabilities_test.cc
+++ b/third_party/blink/renderer/modules/media_capabilities/media_capabilities_test.cc
@@ -26,7 +26,6 @@
 #include "mojo/public/cpp/bindings/receiver.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "third_party/blink/public/common/browser_interface_broker_proxy.h"
-#include "third_party/blink/public/platform/web_size.h"
 #include "third_party/blink/renderer/bindings/core/v8/native_value_traits_impl.h"
 #include "third_party/blink/renderer/bindings/core/v8/script_promise_tester.h"
 #include "third_party/blink/renderer/bindings/core/v8/v8_binding_for_testing.h"
diff --git a/third_party/blink/renderer/modules/media_controls/media_controls_impl_test.cc b/third_party/blink/renderer/modules/media_controls/media_controls_impl_test.cc
index d5e76d1..bfc820c 100644
--- a/third_party/blink/renderer/modules/media_controls/media_controls_impl_test.cc
+++ b/third_party/blink/renderer/modules/media_controls/media_controls_impl_test.cc
@@ -14,7 +14,6 @@
 #include "third_party/blink/public/mojom/input/focus_type.mojom-blink.h"
 #include "third_party/blink/public/mojom/widget/screen_orientation.mojom-blink.h"
 #include "third_party/blink/public/platform/modules/remoteplayback/web_remote_playback_client.h"
-#include "third_party/blink/public/platform/web_size.h"
 #include "third_party/blink/renderer/bindings/core/v8/v8_gc_controller.h"
 #include "third_party/blink/renderer/core/css/css_property_value_set.h"
 #include "third_party/blink/renderer/core/css/document_style_environment_variables.h"
diff --git a/third_party/blink/renderer/modules/media_controls/media_controls_orientation_lock_delegate_test.cc b/third_party/blink/renderer/modules/media_controls/media_controls_orientation_lock_delegate_test.cc
index ffe580a..35571f0 100644
--- a/third_party/blink/renderer/modules/media_controls/media_controls_orientation_lock_delegate_test.cc
+++ b/third_party/blink/renderer/modules/media_controls/media_controls_orientation_lock_delegate_test.cc
@@ -13,7 +13,6 @@
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "third_party/blink/public/mojom/widget/screen_orientation.mojom-blink.h"
-#include "third_party/blink/public/platform/web_size.h"
 #include "third_party/blink/renderer/core/dom/document.h"
 #include "third_party/blink/renderer/core/frame/frame_view.h"
 #include "third_party/blink/renderer/core/frame/local_dom_window.h"
diff --git a/third_party/blink/renderer/modules/media_controls/media_controls_rotate_to_fullscreen_delegate_test.cc b/third_party/blink/renderer/modules/media_controls/media_controls_rotate_to_fullscreen_delegate_test.cc
index 56ca634..17ba86c 100644
--- a/third_party/blink/renderer/modules/media_controls/media_controls_rotate_to_fullscreen_delegate_test.cc
+++ b/third_party/blink/renderer/modules/media_controls/media_controls_rotate_to_fullscreen_delegate_test.cc
@@ -8,7 +8,6 @@
 #include "services/device/public/mojom/screen_orientation.mojom-blink.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "third_party/blink/public/mojom/widget/screen_orientation.mojom-blink.h"
-#include "third_party/blink/public/platform/web_size.h"
 #include "third_party/blink/renderer/core/css/css_style_declaration.h"
 #include "third_party/blink/renderer/core/dom/document.h"
 #include "third_party/blink/renderer/core/dom/events/event.h"
diff --git a/third_party/blink/renderer/modules/mediacapturefromelement/html_video_element_capturer_source.cc b/third_party/blink/renderer/modules/mediacapturefromelement/html_video_element_capturer_source.cc
index 7c0801e25..9d34eb8 100644
--- a/third_party/blink/renderer/modules/mediacapturefromelement/html_video_element_capturer_source.cc
+++ b/third_party/blink/renderer/modules/mediacapturefromelement/html_video_element_capturer_source.cc
@@ -11,7 +11,6 @@
 #include "base/trace_event/trace_event.h"
 #include "media/base/limits.h"
 #include "third_party/blink/public/platform/web_media_player.h"
-#include "third_party/blink/public/platform/web_size.h"
 #include "third_party/blink/public/web/modules/mediastream/media_stream_video_source.h"
 #include "third_party/blink/renderer/platform/mediastream/webrtc_uma_histograms.h"
 #include "third_party/blink/renderer/platform/scheduler/public/post_cross_thread_task.h"
diff --git a/third_party/blink/renderer/modules/mediacapturefromelement/html_video_element_capturer_source.h b/third_party/blink/renderer/modules/mediacapturefromelement/html_video_element_capturer_source.h
index 07ec4f41..196b1da0 100644
--- a/third_party/blink/renderer/modules/mediacapturefromelement/html_video_element_capturer_source.h
+++ b/third_party/blink/renderer/modules/mediacapturefromelement/html_video_element_capturer_source.h
@@ -11,7 +11,6 @@
 #include "base/time/time.h"
 #include "media/base/video_types.h"
 #include "media/capture/video_capturer_source.h"
-#include "third_party/blink/public/platform/web_size.h"
 #include "third_party/blink/renderer/modules/modules_export.h"
 
 namespace base {
diff --git a/third_party/blink/renderer/modules/mediasession/media_metadata_sanitizer.cc b/third_party/blink/renderer/modules/mediasession/media_metadata_sanitizer.cc
index e267462..9764803 100644
--- a/third_party/blink/renderer/modules/mediasession/media_metadata_sanitizer.cc
+++ b/third_party/blink/renderer/modules/mediasession/media_metadata_sanitizer.cc
@@ -6,7 +6,6 @@
 
 #include "third_party/blink/public/mojom/mediasession/media_session.mojom-blink.h"
 #include "third_party/blink/public/platform/web_icon_sizes_parser.h"
-#include "third_party/blink/public/platform/web_size.h"
 #include "third_party/blink/public/platform/web_string.h"
 #include "third_party/blink/renderer/bindings/modules/v8/v8_media_image.h"
 #include "third_party/blink/renderer/core/execution_context/execution_context.h"
diff --git a/third_party/blink/renderer/modules/mediastream/webmediaplayer_ms.cc b/third_party/blink/renderer/modules/mediastream/webmediaplayer_ms.cc
index 5ba23d83..a7a6cf7 100644
--- a/third_party/blink/renderer/modules/mediastream/webmediaplayer_ms.cc
+++ b/third_party/blink/renderer/modules/mediastream/webmediaplayer_ms.cc
@@ -33,7 +33,6 @@
 #include "third_party/blink/public/platform/url_conversion.h"
 #include "third_party/blink/public/platform/web_media_player_client.h"
 #include "third_party/blink/public/platform/web_media_player_source.h"
-#include "third_party/blink/public/platform/web_size.h"
 #include "third_party/blink/public/platform/web_surface_layer_bridge.h"
 #include "third_party/blink/public/web/modules/media/webmediaplayer_util.h"
 #include "third_party/blink/public/web/web_local_frame.h"
diff --git a/third_party/blink/renderer/modules/notifications/notification_resources_loader.cc b/third_party/blink/renderer/modules/notifications/notification_resources_loader.cc
index 3468197..6dd454c 100644
--- a/third_party/blink/renderer/modules/notifications/notification_resources_loader.cc
+++ b/third_party/blink/renderer/modules/notifications/notification_resources_loader.cc
@@ -11,7 +11,6 @@
 #include "third_party/blink/public/common/notifications/notification_constants.h"
 #include "third_party/blink/public/mojom/fetch/fetch_api_request.mojom-blink.h"
 #include "third_party/blink/public/mojom/notifications/notification.mojom-blink.h"
-#include "third_party/blink/public/platform/web_size.h"
 #include "third_party/blink/renderer/platform/heap/persistent.h"
 #include "third_party/blink/renderer/platform/weborigin/kurl.h"
 #include "third_party/blink/renderer/platform/wtf/threading.h"
diff --git a/third_party/blink/renderer/modules/payments/payment_instruments.cc b/third_party/blink/renderer/modules/payments/payment_instruments.cc
index 27d80010..58e64f7 100644
--- a/third_party/blink/renderer/modules/payments/payment_instruments.cc
+++ b/third_party/blink/renderer/modules/payments/payment_instruments.cc
@@ -81,7 +81,7 @@
     return false;
   return ExecutionContext::From(script_state)
       ->GetSecurityContext()
-      .GetFeaturePolicy()
+      .GetPermissionsPolicy()
       ->IsFeatureEnabled(mojom::blink::PermissionsPolicyFeature::kPayment);
 }
 
diff --git a/third_party/blink/renderer/modules/peerconnection/peer_connection_dependency_factory.cc b/third_party/blink/renderer/modules/peerconnection/peer_connection_dependency_factory.cc
index d48644555..82e9493 100644
--- a/third_party/blink/renderer/modules/peerconnection/peer_connection_dependency_factory.cc
+++ b/third_party/blink/renderer/modules/peerconnection/peer_connection_dependency_factory.cc
@@ -46,7 +46,6 @@
 #include "third_party/blink/renderer/platform/p2p/port_allocator.h"
 #include "third_party/blink/renderer/platform/p2p/socket_dispatcher.h"
 #include "third_party/blink/renderer/platform/peerconnection/audio_codec_factory.h"
-#include "third_party/blink/renderer/platform/peerconnection/stun_field_trial.h"
 #include "third_party/blink/renderer/platform/peerconnection/video_codec_factory.h"
 #include "third_party/blink/renderer/platform/scheduler/public/post_cross_thread_task.h"
 #include "third_party/blink/renderer/platform/wtf/cross_thread_copier.h"
@@ -121,7 +120,6 @@
   if (base::FeatureList::IsEnabled(features::kWebRtcDistinctWorkerThread)) {
     chrome_worker_thread_.emplace("WebRTC_Worker");
   }
-  TryScheduleStunProbeTrial();
 }
 
 PeerConnectionDependencyFactory::~PeerConnectionDependencyFactory() {
@@ -568,32 +566,6 @@
   event->Signal();
 }
 
-void PeerConnectionDependencyFactory::TryScheduleStunProbeTrial() {
-  base::Optional<WebString> params =
-      Platform::Current()->WebRtcStunProbeTrialParameter();
-  if (!params)
-    return;
-
-  GetPcFactory();
-
-  PostDelayedCrossThreadTask(
-      *chrome_network_thread_.task_runner().get(), FROM_HERE,
-      CrossThreadBindOnce(
-          &PeerConnectionDependencyFactory::StartStunProbeTrialOnNetworkThread,
-          CrossThreadUnretained(this), String(*params)),
-      base::TimeDelta::FromMilliseconds(blink::kExperimentStartDelayMs));
-}
-
-void PeerConnectionDependencyFactory::StartStunProbeTrialOnNetworkThread(
-    const String& params) {
-  DCHECK(network_manager_);
-  DCHECK(chrome_network_thread_.task_runner()->BelongsToCurrentThread());
-  // TODO(crbug.com/787254): Remove the UTF8 conversion when StunProberTrial
-  // operates over WTF::String.
-  stun_trial_.reset(new StunProberTrial(network_manager_.get(), params.Utf8(),
-                                        socket_factory_.get()));
-}
-
 void PeerConnectionDependencyFactory::CreateIpcNetworkManagerOnNetworkThread(
     base::WaitableEvent* event,
     std::unique_ptr<MdnsResponderAdapter> mdns_responder,
diff --git a/third_party/blink/renderer/modules/peerconnection/peer_connection_dependency_factory.h b/third_party/blink/renderer/modules/peerconnection/peer_connection_dependency_factory.h
index 14af4c37..a8806c8 100644
--- a/third_party/blink/renderer/modules/peerconnection/peer_connection_dependency_factory.h
+++ b/third_party/blink/renderer/modules/peerconnection/peer_connection_dependency_factory.h
@@ -14,7 +14,6 @@
 #include "third_party/blink/renderer/platform/bindings/exception_state.h"
 #include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
 #include "third_party/webrtc/api/peer_connection_interface.h"
-#include "third_party/webrtc/p2p/stunprober/stun_prober.h"
 
 namespace base {
 class WaitableEvent;
@@ -45,7 +44,6 @@
 class P2PSocketDispatcher;
 class RTCPeerConnectionHandlerClient;
 class RTCPeerConnectionHandler;
-class StunProberTrial;
 class WebLocalFrame;
 class WebRtcAudioDeviceImpl;
 
@@ -141,7 +139,6 @@
   // Functions related to Stun probing trial to determine how fast we could send
   // Stun request without being dropped by NAT.
   void TryScheduleStunProbeTrial();
-  void StartStunProbeTrialOnNetworkThread(const String& params);
 
   // Creates |pc_factory_|, which in turn is used for
   // creating PeerConnection objects.
@@ -175,8 +172,6 @@
 
   scoped_refptr<blink::WebRtcAudioDeviceImpl> audio_device_;
 
-  std::unique_ptr<blink::StunProberTrial> stun_trial_;
-
   media::GpuVideoAcceleratorFactories* gpu_factories_;
 
   // PeerConnection threads. signaling_thread_ is created from the
diff --git a/third_party/blink/renderer/modules/picture_in_picture/html_element_picture_in_picture.cc b/third_party/blink/renderer/modules/picture_in_picture/html_element_picture_in_picture.cc
index e189951..02c2760 100644
--- a/third_party/blink/renderer/modules/picture_in_picture/html_element_picture_in_picture.cc
+++ b/third_party/blink/renderer/modules/picture_in_picture/html_element_picture_in_picture.cc
@@ -81,7 +81,7 @@
       exception_state.ThrowDOMException(DOMExceptionCode::kInvalidStateError,
                                         kVideoTrackNotAvailableError);
       return;
-    case Status::kDisabledByFeaturePolicy:
+    case Status::kDisabledByPermissionsPolicy:
       exception_state.ThrowSecurityError(kFeaturePolicyBlocked);
       return;
     case Status::kDisabledByAttribute:
diff --git a/third_party/blink/renderer/modules/picture_in_picture/picture_in_picture_controller_impl.cc b/third_party/blink/renderer/modules/picture_in_picture/picture_in_picture_controller_impl.cc
index 768ab36..711ee16d 100644
--- a/third_party/blink/renderer/modules/picture_in_picture/picture_in_picture_controller_impl.cc
+++ b/third_party/blink/renderer/modules/picture_in_picture/picture_in_picture_controller_impl.cc
@@ -75,13 +75,13 @@
     return Status::kDisabledBySystem;
 
   // If document is not allowed to use the policy-controlled feature named
-  // "picture-in-picture", return kDisabledByFeaturePolicy status.
+  // "picture-in-picture", return kDisabledByPermissionsPolicy status.
   if (RuntimeEnabledFeatures::PictureInPictureAPIEnabled() &&
       !GetSupplementable()->GetExecutionContext()->IsFeatureEnabled(
           blink::mojom::blink::PermissionsPolicyFeature::kPictureInPicture,
           report_failure ? ReportOptions::kReportOnFailure
                          : ReportOptions::kDoNotReport)) {
-    return Status::kDisabledByFeaturePolicy;
+    return Status::kDisabledByPermissionsPolicy;
   }
 
   return Status::kEnabled;
diff --git a/third_party/blink/renderer/modules/webaudio/audio_param.cc b/third_party/blink/renderer/modules/webaudio/audio_param.cc
index cf4e828..5854609 100644
--- a/third_party/blink/renderer/modules/webaudio/audio_param.cc
+++ b/third_party/blink/renderer/modules/webaudio/audio_param.cc
@@ -166,7 +166,8 @@
     bool has_value;
     float timeline_value;
     std::tie(has_value, timeline_value) = timeline_.ValueForContextTime(
-        DestinationHandler(), v, MinValue(), MaxValue());
+        DestinationHandler(), v, MinValue(), MaxValue(),
+        GetDeferredTaskHandler().RenderQuantumFrames());
 
     if (has_value)
       v = timeline_value;
@@ -195,7 +196,8 @@
   bool use_timeline_value = false;
   float value;
   std::tie(use_timeline_value, value) = timeline_.ValueForContextTime(
-      DestinationHandler(), IntrinsicValue(), MinValue(), MaxValue());
+      DestinationHandler(), IntrinsicValue(), MinValue(), MaxValue(),
+      GetDeferredTaskHandler().RenderQuantumFrames());
 
   float smoothed_value = timeline_.SmoothedValue();
   if (smoothed_value == value) {
@@ -300,7 +302,8 @@
     float value = IntrinsicValue();
     float timeline_value;
     std::tie(has_value, timeline_value) = timeline_.ValueForContextTime(
-        DestinationHandler(), value, MinValue(), MaxValue());
+        DestinationHandler(), value, MinValue(), MaxValue(),
+        GetDeferredTaskHandler().RenderQuantumFrames());
 
     if (has_value)
       value = timeline_value;
@@ -376,7 +379,8 @@
   // Pass in the current value as default value.
   SetIntrinsicValue(timeline_.ValuesForFrameRange(
       start_frame, end_frame, IntrinsicValue(), values, number_of_values,
-      sample_rate, sample_rate, MinValue(), MaxValue()));
+      sample_rate, sample_rate, MinValue(), MaxValue(),
+      GetDeferredTaskHandler().RenderQuantumFrames()));
 }
 
 // ----------------------------------------------------------------
diff --git a/third_party/blink/renderer/modules/webaudio/audio_param.h b/third_party/blink/renderer/modules/webaudio/audio_param.h
index 6bd9a38..cdfd3a7 100644
--- a/third_party/blink/renderer/modules/webaudio/audio_param.h
+++ b/third_party/blink/renderer/modules/webaudio/audio_param.h
@@ -184,7 +184,8 @@
   bool HasSampleAccurateValues() {
     bool has_values =
         timeline_.HasValues(destination_handler_->CurrentSampleFrame(),
-                            destination_handler_->SampleRate());
+                            destination_handler_->SampleRate(),
+                            GetDeferredTaskHandler().RenderQuantumFrames());
 
     return has_values || NumberOfRenderingConnections();
   }
diff --git a/third_party/blink/renderer/modules/webaudio/audio_param_timeline.cc b/third_party/blink/renderer/modules/webaudio/audio_param_timeline.cc
index db3c5c2..cf863b3 100644
--- a/third_party/blink/renderer/modules/webaudio/audio_param_timeline.cc
+++ b/third_party/blink/renderer/modules/webaudio/audio_param_timeline.cc
@@ -612,7 +612,8 @@
 }
 
 bool AudioParamTimeline::HasValues(size_t current_frame,
-                                   double sample_rate) const {
+                                   double sample_rate,
+                                   unsigned render_quantum_frames) const {
   MutexTryLocker try_locker(events_lock_);
 
   if (try_locker.Locked()) {
@@ -626,7 +627,7 @@
     // future.  Then, no sample-accurate processing is needed because the event
     // hasn't started.
     if (events_[0]->Time() >
-        (current_frame + audio_utilities::kRenderQuantumFrames) / sample_rate) {
+        (current_frame + render_quantum_frames) / sample_rate) {
       switch (events_[0]->GetType()) {
         case ParamEvent::kSetTarget:
         case ParamEvent::kSetValue:
@@ -655,8 +656,7 @@
         // Need automation if the event starts somewhere before the
         // end of the current render quantum.
         return events_[0]->Time() <=
-               (current_frame + audio_utilities::kRenderQuantumFrames) /
-                   sample_rate;
+               (current_frame + render_quantum_frames) / sample_rate;
       case ParamEvent::kSetValue:
       case ParamEvent::kLinearRampToValue:
       case ParamEvent::kExponentialRampToValue:
@@ -853,7 +853,8 @@
     AudioDestinationHandler& audio_destination,
     float default_value,
     float min_value,
-    float max_value) {
+    float max_value,
+    unsigned render_quantum_frames) {
   {
     MutexTryLocker try_locker(events_lock_);
     if (!try_locker.Locked() || !events_.size() ||
@@ -867,10 +868,10 @@
   double sample_rate = audio_destination.SampleRate();
   size_t start_frame = audio_destination.CurrentSampleFrame();
   // One parameter change per render quantum.
-  double control_rate = sample_rate / audio_utilities::kRenderQuantumFrames;
-  value =
-      ValuesForFrameRange(start_frame, start_frame + 1, default_value, &value,
-                          1, sample_rate, control_rate, min_value, max_value);
+  double control_rate = sample_rate / render_quantum_frames;
+  value = ValuesForFrameRange(start_frame, start_frame + 1, default_value,
+                              &value, 1, sample_rate, control_rate, min_value,
+                              max_value, render_quantum_frames);
 
   return std::make_tuple(true, value);
 }
@@ -883,7 +884,8 @@
                                               double sample_rate,
                                               double control_rate,
                                               float min_value,
-                                              float max_value) {
+                                              float max_value,
+                                              unsigned render_quantum_frames) {
   // We can't contend the lock in the realtime audio thread.
   MutexTryLocker try_locker(events_lock_);
   if (!try_locker.Locked()) {
@@ -894,9 +896,9 @@
     return default_value;
   }
 
-  float last_value =
-      ValuesForFrameRangeImpl(start_frame, end_frame, default_value, values,
-                              number_of_values, sample_rate, control_rate);
+  float last_value = ValuesForFrameRangeImpl(
+      start_frame, end_frame, default_value, values, number_of_values,
+      sample_rate, control_rate, render_quantum_frames);
 
   // Clamp the values now to the nominal range
   vector_math::Vclip(values, 1, &min_value, &max_value, values, 1,
@@ -905,13 +907,15 @@
   return last_value;
 }
 
-float AudioParamTimeline::ValuesForFrameRangeImpl(size_t start_frame,
-                                                  size_t end_frame,
-                                                  float default_value,
-                                                  float* values,
-                                                  unsigned number_of_values,
-                                                  double sample_rate,
-                                                  double control_rate) {
+float AudioParamTimeline::ValuesForFrameRangeImpl(
+    size_t start_frame,
+    size_t end_frame,
+    float default_value,
+    float* values,
+    unsigned number_of_values,
+    double sample_rate,
+    double control_rate,
+    unsigned render_quantum_frames) {
   DCHECK(values);
   DCHECK_GE(number_of_values, 1u);
 
@@ -940,7 +944,8 @@
     double current_time = start_frame / sample_rate;
 
     if (HandleAllEventsInThePast(current_time, sample_rate, default_value,
-                                 number_of_values, values))
+                                 number_of_values, values,
+                                 render_quantum_frames))
       return default_value;
   }
 
@@ -1233,11 +1238,13 @@
   return false;
 }
 
-bool AudioParamTimeline::HandleAllEventsInThePast(double current_time,
-                                                  double sample_rate,
-                                                  float& default_value,
-                                                  unsigned number_of_values,
-                                                  float* values) {
+bool AudioParamTimeline::HandleAllEventsInThePast(
+    double current_time,
+    double sample_rate,
+    float& default_value,
+    unsigned number_of_values,
+    float* values,
+    unsigned render_quantum_frames) {
   // Optimize the case where the last event is in the past.
   ParamEvent* last_event = events_[events_.size() - 1].get();
   ParamEvent::Type last_event_type = last_event->GetType();
@@ -1248,8 +1255,7 @@
   // "forever".  SetValueCurve also has an explicit SetValue at the end of
   // the curve, so we don't need to worry that SetValueCurve time is a
   // start time, not an end time.
-  if (last_event_time +
-          1.5 * audio_utilities::kRenderQuantumFrames / sample_rate <
+  if (last_event_time + 1.5 * render_quantum_frames / sample_rate <
       current_time) {
     // If the last event is SetTarget, make sure we've converged and, that
     // we're at least 5 time constants past the start of the event.  If not, we
diff --git a/third_party/blink/renderer/modules/webaudio/audio_param_timeline.h b/third_party/blink/renderer/modules/webaudio/audio_param_timeline.h
index 1ff9e359..9a83db6 100644
--- a/third_party/blink/renderer/modules/webaudio/audio_param_timeline.h
+++ b/third_party/blink/renderer/modules/webaudio/audio_param_timeline.h
@@ -78,7 +78,8 @@
   std::tuple<bool, float> ValueForContextTime(AudioDestinationHandler&,
                                               float default_value,
                                               float min_value,
-                                              float max_value);
+                                              float max_value,
+                                              unsigned render_quantum_frames);
 
   // Given the time range in frames, calculates parameter values into the values
   // buffer and returns the last parameter value calculated for "values" or the
@@ -95,12 +96,15 @@
                             double sample_rate,
                             double control_rate,
                             float min_value,
-                            float max_value);
+                            float max_value,
+                            unsigned render_quantum_frames);
 
   // Returns true if the AudioParam timeline needs to run in this
   // rendering quantum.  This means some automation is already running
   // or is scheduled to run in the current rendering quantuym.
-  bool HasValues(size_t current_frame, double sample_rate) const;
+  bool HasValues(size_t current_frame,
+                 double sample_rate,
+                 unsigned render_quantum_frames) const;
 
   float SmoothedValue() { return smoothed_value_; }
   void SetSmoothedValue(float v) { smoothed_value_ = v; }
@@ -306,7 +310,8 @@
                                 float* values,
                                 unsigned number_of_values,
                                 double sample_rate,
-                                double control_rate);
+                                double control_rate,
+                                unsigned render_quantum_frames);
 
   // Produce a nice string describing the event in human-readable form.
   String EventToString(const ParamEvent&) const;
@@ -367,7 +372,8 @@
                                 double sample_rate,
                                 float& default_value,
                                 unsigned number_of_values,
-                                float* values);
+                                float* values,
+                                unsigned render_quantum_frames);
 
   // Handle processing of CancelValue event. If cancellation happens, value2,
   // time2, and nextEventType will be updated with the new value due to
diff --git a/third_party/blink/renderer/modules/xr/xr_system.cc b/third_party/blink/renderer/modules/xr/xr_system.cc
index e6c37a8..99e2c74 100644
--- a/third_party/blink/renderer/modules/xr/xr_system.cc
+++ b/third_party/blink/renderer/modules/xr/xr_system.cc
@@ -311,8 +311,8 @@
   }
 }
 
-bool HasRequiredFeaturePolicy(const ExecutionContext* context,
-                              device::mojom::XRSessionFeature feature) {
+bool HasRequiredPermissionsPolicy(const ExecutionContext* context,
+                                  device::mojom::XRSessionFeature feature) {
   if (!context)
     return false;
 
@@ -1335,8 +1335,8 @@
                                            "' is not supported for mode: " +
                                            SessionModeToString(session_mode));
         result.invalid_features = true;
-      } else if (!HasRequiredFeaturePolicy(GetExecutionContext(),
-                                           feature_enum.value())) {
+      } else if (!HasRequiredPermissionsPolicy(GetExecutionContext(),
+                                               feature_enum.value())) {
         AddConsoleMessage(error_level,
                           "Feature '" + feature_string +
                               "' is not permitted by permissions policy");
@@ -1425,7 +1425,7 @@
   }
 
   for (const auto& feature : default_features) {
-    if (HasRequiredFeaturePolicy(GetExecutionContext(), feature)) {
+    if (HasRequiredPermissionsPolicy(GetExecutionContext(), feature)) {
       required_features.valid_features.insert(feature);
     } else {
       DVLOG(2) << __func__
diff --git a/third_party/blink/renderer/platform/BUILD.gn b/third_party/blink/renderer/platform/BUILD.gn
index 84461f5..27e94bd 100644
--- a/third_party/blink/renderer/platform/BUILD.gn
+++ b/third_party/blink/renderer/platform/BUILD.gn
@@ -1343,8 +1343,6 @@
     "peerconnection/rtc_video_encoder_factory.cc",
     "peerconnection/rtc_video_encoder_factory.h",
     "peerconnection/rtc_void_request.h",
-    "peerconnection/stun_field_trial.cc",
-    "peerconnection/stun_field_trial.h",
     "peerconnection/transmission_encoding_info_handler.cc",
     "peerconnection/transmission_encoding_info_handler.h",
     "peerconnection/two_keys_adapter_map.h",
@@ -2109,7 +2107,6 @@
     "peerconnection/rtc_video_decoder_adapter_test.cc",
     "peerconnection/rtc_video_decoder_stream_adapter_test.cc",
     "peerconnection/rtc_video_encoder_test.cc",
-    "peerconnection/stun_field_trial_test.cc",
     "peerconnection/task_queue_factory_test.cc",
     "peerconnection/transmission_encoding_info_handler_test.cc",
     "peerconnection/two_keys_adapter_map_unittest.cc",
diff --git a/third_party/blink/renderer/platform/OWNERS b/third_party/blink/renderer/platform/OWNERS
index 3b41257..549b981e 100644
--- a/third_party/blink/renderer/platform/OWNERS
+++ b/third_party/blink/renderer/platform/OWNERS
@@ -8,6 +8,7 @@
 ikilpatrick@chromium.org
 jbroman@chromium.org
 jochen@chromium.org
+junov@chromium.org
 kbr@chromium.org
 kinuko@chromium.org
 kojii@chromium.org
diff --git a/third_party/blink/renderer/platform/exported/web_icon_sizes_fuzzer.cc b/third_party/blink/renderer/platform/exported/web_icon_sizes_fuzzer.cc
index 5c53f27..4664bf1e 100644
--- a/third_party/blink/renderer/platform/exported/web_icon_sizes_fuzzer.cc
+++ b/third_party/blink/renderer/platform/exported/web_icon_sizes_fuzzer.cc
@@ -3,9 +3,9 @@
 // found in the LICENSE file.
 
 #include "third_party/blink/public/platform/web_icon_sizes_parser.h"
-#include "third_party/blink/public/platform/web_size.h"
 #include "third_party/blink/public/platform/web_string.h"
 #include "third_party/blink/renderer/platform/testing/blink_fuzzer_test_support.h"
+#include "ui/gfx/geometry/size.h"
 
 namespace blink {
 
diff --git a/third_party/blink/renderer/platform/exported/web_icon_sizes_parser.cc b/third_party/blink/renderer/platform/exported/web_icon_sizes_parser.cc
index ec882242..4f481be 100644
--- a/third_party/blink/renderer/platform/exported/web_icon_sizes_parser.cc
+++ b/third_party/blink/renderer/platform/exported/web_icon_sizes_parser.cc
@@ -5,10 +5,10 @@
 #include "third_party/blink/public/platform/web_icon_sizes_parser.h"
 
 #include <algorithm>
-#include "third_party/blink/public/platform/web_size.h"
 #include "third_party/blink/public/platform/web_string.h"
 #include "third_party/blink/renderer/platform/wtf/text/string_to_number.h"
 #include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
+#include "ui/gfx/geometry/size.h"
 
 namespace blink {
 
diff --git a/third_party/blink/renderer/platform/geometry/float_size.h b/third_party/blink/renderer/platform/geometry/float_size.h
index 67da722..68bbda5 100644
--- a/third_party/blink/renderer/platform/geometry/float_size.h
+++ b/third_party/blink/renderer/platform/geometry/float_size.h
@@ -38,6 +38,7 @@
 #include "third_party/blink/renderer/platform/wtf/hash_traits.h"
 #include "third_party/blink/renderer/platform/wtf/math_extras.h"
 #include "third_party/skia/include/core/SkSize.h"
+#include "ui/gfx/geometry/scroll_offset.h"
 #include "ui/gfx/geometry/size.h"
 #include "ui/gfx/geometry/size_f.h"
 #include "ui/gfx/geometry/vector2d_f.h"
@@ -154,6 +155,13 @@
     return gfx::Vector2dF(width_, height_);
   }
 
+  // blink::ScrollOffset is typedef'd as FloatSize. When exposing outside blink
+  // it should probably be exposed as a gfx::ScrollOffset (as opposed to a
+  // Vector2dF).
+  constexpr explicit operator gfx::ScrollOffset() const {
+    return gfx::ScrollOffset(width_, height_);
+  }
+
   String ToString() const;
 
  private:
diff --git a/third_party/blink/renderer/platform/graphics/graphics_layer.cc b/third_party/blink/renderer/platform/graphics/graphics_layer.cc
index 37d8f1d..1cca77e 100644
--- a/third_party/blink/renderer/platform/graphics/graphics_layer.cc
+++ b/third_party/blink/renderer/platform/graphics/graphics_layer.cc
@@ -36,7 +36,6 @@
 #include "cc/layers/picture_layer.h"
 #include "cc/paint/display_item_list.h"
 #include "third_party/blink/public/platform/platform.h"
-#include "third_party/blink/public/platform/web_size.h"
 #include "third_party/blink/renderer/platform/geometry/float_rect.h"
 #include "third_party/blink/renderer/platform/geometry/geometry_as_json.h"
 #include "third_party/blink/renderer/platform/geometry/layout_rect.h"
diff --git a/third_party/blink/renderer/platform/image-decoders/gif/gif_image_decoder_test.cc b/third_party/blink/renderer/platform/image-decoders/gif/gif_image_decoder_test.cc
index 15eee95..ddf593ef 100644
--- a/third_party/blink/renderer/platform/image-decoders/gif/gif_image_decoder_test.cc
+++ b/third_party/blink/renderer/platform/image-decoders/gif/gif_image_decoder_test.cc
@@ -33,7 +33,6 @@
 #include <memory>
 #include "testing/gtest/include/gtest/gtest.h"
 #include "third_party/blink/public/platform/web_data.h"
-#include "third_party/blink/public/platform/web_size.h"
 #include "third_party/blink/renderer/platform/image-decoders/image_decoder_test_helpers.h"
 #include "third_party/blink/renderer/platform/wtf/shared_buffer.h"
 #include "third_party/blink/renderer/platform/wtf/vector.h"
diff --git a/third_party/blink/renderer/platform/image-decoders/jpeg/jpeg_image_decoder_test.cc b/third_party/blink/renderer/platform/image-decoders/jpeg/jpeg_image_decoder_test.cc
index 2fae198..b0b8c06 100644
--- a/third_party/blink/renderer/platform/image-decoders/jpeg/jpeg_image_decoder_test.cc
+++ b/third_party/blink/renderer/platform/image-decoders/jpeg/jpeg_image_decoder_test.cc
@@ -37,7 +37,6 @@
 #include "base/test/metrics/histogram_tester.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "third_party/blink/public/platform/web_data.h"
-#include "third_party/blink/public/platform/web_size.h"
 #include "third_party/blink/renderer/platform/graphics/bitmap_image_metrics.h"
 #include "third_party/blink/renderer/platform/image-decoders/image_animation.h"
 #include "third_party/blink/renderer/platform/image-decoders/image_decoder_test_helpers.h"
diff --git a/third_party/blink/renderer/platform/image-decoders/webp/webp_image_decoder_test.cc b/third_party/blink/renderer/platform/image-decoders/webp/webp_image_decoder_test.cc
index e520ac0d..6c705281 100644
--- a/third_party/blink/renderer/platform/image-decoders/webp/webp_image_decoder_test.cc
+++ b/third_party/blink/renderer/platform/image-decoders/webp/webp_image_decoder_test.cc
@@ -35,7 +35,6 @@
 #include "base/stl_util.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "third_party/blink/public/platform/web_data.h"
-#include "third_party/blink/public/platform/web_size.h"
 #include "third_party/blink/renderer/platform/image-decoders/image_decoder_test_helpers.h"
 #include "third_party/blink/renderer/platform/wtf/shared_buffer.h"
 #include "third_party/blink/renderer/platform/wtf/vector.h"
diff --git a/third_party/blink/renderer/platform/loader/child_url_loader_factory_bundle.cc b/third_party/blink/renderer/platform/loader/child_url_loader_factory_bundle.cc
index 01fddcb..a341dd147 100644
--- a/third_party/blink/renderer/platform/loader/child_url_loader_factory_bundle.cc
+++ b/third_party/blink/renderer/platform/loader/child_url_loader_factory_bundle.cc
@@ -237,7 +237,7 @@
   if (base_result)
     return base_result;
 
-  // TODO(https://crbug.com/1114822): Add a
+  // TODO(https://crbug.com/1184292): Add a
   // `DCHECK(!is_deprecated_process_wide_factory_)` assertion below (and later a
   // DwoC with ScopedRequestCrashKeys) once we know of no more cases when the
   // assertion may fire.  After confirming that the assertion (and a DwoC) no
diff --git a/third_party/blink/renderer/platform/loader/fetch/fetch_context.h b/third_party/blink/renderer/platform/loader/fetch/fetch_context.h
index 44683a8..721abd3 100644
--- a/third_party/blink/renderer/platform/loader/fetch/fetch_context.h
+++ b/third_party/blink/renderer/platform/loader/fetch/fetch_context.h
@@ -161,7 +161,9 @@
     return MakeGarbageCollected<FetchContext>();
   }
 
-  virtual const PermissionsPolicy* GetFeaturePolicy() const { return nullptr; }
+  virtual const PermissionsPolicy* GetPermissionsPolicy() const {
+    return nullptr;
+  }
 
   // Determine if the request is on behalf of an advertisement. If so, return
   // true. Checks `resource_request.Url()` unless `alias_url` is non-null, in
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 5cf19870..ee89865 100644
--- a/third_party/blink/renderer/platform/loader/fetch/resource_loader.cc
+++ b/third_party/blink/renderer/platform/loader/fetch/resource_loader.cc
@@ -743,7 +743,7 @@
     std::vector<std::string>* removed_headers) {
   DCHECK(!passed_redirect_response.IsNull());
   if (removed_headers) {
-    FindClientHintsToRemove(Context().GetFeaturePolicy(),
+    FindClientHintsToRemove(Context().GetPermissionsPolicy(),
                             GURL(new_url.GetString().Utf8()), removed_headers);
   }
 
diff --git a/third_party/blink/renderer/platform/peerconnection/stun_field_trial.cc b/third_party/blink/renderer/platform/peerconnection/stun_field_trial.cc
deleted file mode 100644
index bd64f2e0..0000000
--- a/third_party/blink/renderer/platform/peerconnection/stun_field_trial.cc
+++ /dev/null
@@ -1,312 +0,0 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "third_party/blink/renderer/platform/peerconnection/stun_field_trial.h"
-
-#include <math.h>
-
-#include "base/logging.h"
-#include "base/metrics/histogram_macros.h"
-#include "base/rand_util.h"
-#include "base/stl_util.h"
-#include "base/strings/string_number_conversions.h"
-#include "base/strings/string_split.h"
-#include "base/strings/stringprintf.h"
-#include "base/time/time.h"
-#include "third_party/webrtc/api/packet_socket_factory.h"
-#include "third_party/webrtc/rtc_base/async_packet_socket.h"
-#include "third_party/webrtc/rtc_base/async_resolver_interface.h"
-#include "third_party/webrtc/rtc_base/ip_address.h"
-#include "third_party/webrtc/rtc_base/network.h"
-#include "third_party/webrtc/rtc_base/socket_address.h"
-#include "third_party/webrtc/rtc_base/thread.h"
-
-using stunprober::StunProber;
-
-namespace blink {
-
-namespace {
-
-// This needs to be the same as NatTypeCounters in histograms.xml.
-enum NatType {
-  NAT_TYPE_NONE,
-  NAT_TYPE_UNKNOWN,
-  NAT_TYPE_SYMMETRIC,
-  NAT_TYPE_NON_SYMMETRIC,
-  NAT_TYPE_MAX
-};
-
-// This needs to match "NatType" in histograms.xml.
-const char* const NatTypeNames[] = {"NoNAT", "UnknownNAT", "SymNAT",
-                                    "NonSymNAT"};
-static_assert(base::size(NatTypeNames) == NAT_TYPE_MAX,
-              "NatType enums must match names");
-
-NatType GetNatType(stunprober::NatType nat_type) {
-  switch (nat_type) {
-    case stunprober::NATTYPE_NONE:
-      return NAT_TYPE_NONE;
-    case stunprober::NATTYPE_UNKNOWN:
-      return NAT_TYPE_UNKNOWN;
-    case stunprober::NATTYPE_SYMMETRIC:
-      return NAT_TYPE_SYMMETRIC;
-    case stunprober::NATTYPE_NON_SYMMETRIC:
-      return NAT_TYPE_NON_SYMMETRIC;
-    default:
-      return NAT_TYPE_MAX;
-  }
-}
-
-std::string HistogramName(const std::string& prefix,
-                          NatType nat_type,
-                          int interval_ms,
-                          int batch_index) {
-  return base::StringPrintf("WebRTC.Stun.%s.%s.%dms.%d", prefix.c_str(),
-                            NatTypeNames[nat_type], interval_ms, batch_index);
-}
-
-}  // namespace
-
-StunProberTrial::Param::Param() {}
-
-StunProberTrial::Param::~Param() {}
-
-StunProberTrial::StunProberTrial(rtc::NetworkManager* network_manager,
-                                 const std::string& params,
-                                 rtc::PacketSocketFactory* factory)
-    : network_manager_(network_manager),
-      param_line_(params),
-      factory_(factory) {
-  // We have to connect to the signal to avoid a race condition if network
-  // manager hasn't received the network update when we start, the StunProber
-  // will just fail.
-  network_manager_->SignalNetworksChanged.connect(
-      this, &StunProberTrial::OnNetworksChanged);
-  network_manager_->StartUpdating();
-}
-
-StunProberTrial::~StunProberTrial() {}
-
-void StunProberTrial::SaveHistogramData() {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-  NatType nat_type = NAT_TYPE_UNKNOWN;
-  int interval_ms = 0;
-  int count = 0;
-  int total_requests_sent = 0;
-  int total_responses_received = 0;
-  for (auto* prober : probers_) {
-    ++count;
-
-    // Get the stats.
-    StunProber::Stats stats;
-    if (!prober->GetStats(&stats))
-      return;
-
-    // Check if the NAT type is consistent.
-    if (nat_type == NAT_TYPE_UNKNOWN) {
-      nat_type = GetNatType(stats.nat_type);
-    } else {
-      NatType type = GetNatType(stats.nat_type);
-      // For subsequent probers, we might get unknown as nattype if all the
-      // bindings fail, but it's ok.
-      if (nat_type != type && type != NAT_TYPE_UNKNOWN)
-        return;
-    }
-
-    // Check that the interval is consistent. Use the real probe interval for
-    // reporting, converting from nanosecond to millisecond.
-    int new_interval_ms =
-        round(static_cast<float>(stats.actual_request_interval_ns) / 1000);
-    if (interval_ms == 0) {
-      interval_ms = new_interval_ms;
-    } else if (abs(interval_ms - new_interval_ms) > 3) {
-      DVLOG(1) << "current interval: " << new_interval_ms
-               << " is too far off from previous one: " << interval_ms;
-      continue;
-    }
-
-    // Sum up the total sent and recv packets.
-    total_requests_sent += stats.raw_num_request_sent;
-    total_responses_received += stats.num_response_received;
-
-    if (count % batch_size_ > 0)
-      continue;
-
-    // If 50% of probers are not counted, ignore this batch.
-    // |raw_num_request_sent| should be the same for each prober.
-    if (total_requests_sent < (stats.raw_num_request_sent * batch_size_ / 2)) {
-      total_responses_received = 0;
-      total_requests_sent = 0;
-      continue;
-    }
-
-    int success_rate = total_responses_received * 100 / total_requests_sent;
-    // Use target_request_interval_ns for naming of UMA to avoid inconsistency.
-    std::string histogram_name = HistogramName(
-        "BatchSuccessPercent", nat_type,
-        stats.target_request_interval_ns / 1000, count / batch_size_);
-
-    // Mimic the same behavior as UMA_HISTOGRAM_PERCENTAGE. We can't use
-    // that macro as the histogram name is determined dynamically.
-    base::HistogramBase* histogram =
-        base::Histogram::FactoryGet(histogram_name, 1, 101, 102,
-                                    base::Histogram::kUmaTargetedHistogramFlag);
-    histogram->Add(success_rate);
-
-    DVLOG(1) << "Histogram '" << histogram_name.c_str()
-             << "' = " << success_rate;
-
-    DVLOG(1) << "Shared Socket Mode: " << stats.shared_socket_mode;
-    DVLOG(1) << "Requests sent: " << total_requests_sent;
-    DVLOG(1) << "Responses received: " << total_responses_received;
-    DVLOG(1) << "Target interval (ns): " << stats.target_request_interval_ns;
-    DVLOG(1) << "Actual interval (ns): " << stats.actual_request_interval_ns;
-    DVLOG(1) << "NAT Type: " << NatTypeNames[nat_type];
-    DVLOG(1) << "Host IP: " << stats.host_ip;
-
-    total_requests_sent = 0;
-    total_responses_received = 0;
-  }
-}
-
-bool StunProberTrial::ParseParameters(const std::string& param_line,
-                                      StunProberTrial::Param* params) {
-  std::vector<std::string> stun_params = base::SplitString(
-      param_line, "/", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL);
-
-  if (stun_params.size() < 5) {
-    DLOG(ERROR) << "Not enough parameters specified in StartStunProbeTrial";
-    return false;
-  }
-  auto param = stun_params.begin();
-
-  if (param->empty()) {
-    params->requests_per_ip = 10;
-  } else if (!base::StringToInt(*param, &params->requests_per_ip)) {
-    DLOG(ERROR) << "Failed to parse request_per_ip in StartStunProbeTrial";
-    return false;
-  }
-  param++;
-
-  // Set inter-probe interval randomly from 0, 5, 10, ... 50, 100 ms.
-  if ((*param).empty()) {
-    params->interval_ms = base::RandInt(0, 11) * 5;
-  } else if (!base::StringToInt(*param, &params->interval_ms)) {
-    DLOG(ERROR) << "Failed to parse interval in StartStunProbeTrial";
-    return false;
-  }
-  param++;
-
-  if ((*param).empty()) {
-    params->shared_socket_mode = base::RandInt(0, 1);
-  } else if (!base::StringToInt(*param, &params->shared_socket_mode)) {
-    DLOG(ERROR) << "Failed to parse shared_socket_mode in StartStunProbeTrial";
-    return false;
-  }
-  param++;
-
-  if (param->empty()) {
-    params->batch_size = 5;
-  } else if (!base::StringToInt(*param, &params->batch_size)) {
-    DLOG(ERROR) << "Failed to parse batch_size in StartStunProbeTrial";
-    return false;
-  }
-  param++;
-
-  if (param->empty()) {
-    params->total_batches = 5;
-  } else if (!base::StringToInt(*param, &params->total_batches)) {
-    DLOG(ERROR) << "Failed to parse total_batches in StartStunProbeTrial";
-    return false;
-  }
-  param++;
-
-  while (param != stun_params.end() && !param->empty()) {
-    rtc::SocketAddress server;
-    if (!server.FromString(*param)) {
-      DLOG(ERROR) << "Failed to parse address in StartStunProbeTrial";
-      return false;
-    }
-    params->servers.push_back(server);
-    param++;
-  }
-
-  return !params->servers.empty();
-}
-
-void StunProberTrial::OnNetworksChanged() {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-  DVLOG(1) << "Starting stun trial with params: " << param_line_;
-  rtc::NetworkManager::NetworkList networks;
-  network_manager_->GetNetworks(&networks);
-
-  // If we don't have local addresses, we won't be able to determine whether
-  // we're behind NAT or not.
-  if (networks.empty()) {
-    DLOG(ERROR) << "No networks specified in StartStunProbeTrial";
-    return;
-  }
-
-  network_manager_->StopUpdating();
-  network_manager_->SignalNetworksChanged.disconnect(this);
-
-  StunProberTrial::Param params;
-  if (!ParseParameters(param_line_, &params)) {
-    return;
-  }
-
-  batch_size_ = params.batch_size;
-  total_probers_ = params.total_batches * batch_size_;
-
-  for (int i = 0; i < total_probers_; i++) {
-    std::unique_ptr<StunProber> prober(
-        new StunProber(factory_, rtc::Thread::Current(), networks));
-    if (!prober->Prepare(params.servers, (params.shared_socket_mode != 0),
-                         params.interval_ms, params.requests_per_ip, 1000,
-                         this)) {
-      DLOG(ERROR) << "Failed to Prepare in StartStunProbeTrial";
-      return;
-    }
-
-    probers_.push_back(prober.release());
-  }
-}
-
-void StunProberTrial::OnFinished(StunProber* prober,
-                                 StunProber::Status result) {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-  if (result == StunProber::SUCCESS)
-    ++finished_probers_;
-
-  if (finished_probers_ == total_probers_)
-    SaveHistogramData();
-}
-
-void StunProberTrial::OnPrepared(StunProber* prober,
-                                 StunProber::Status result) {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-  if (result == StunProber::SUCCESS)
-    ++ready_probers_;
-
-  if (ready_probers_ == total_probers_) {
-    // TODO(guoweis) estimated_execution_time() is the same for all probers. It
-    // could be moved up to the StunProberTrial class once the DNS resolution
-    // part is moved up too.
-    timer_.Start(FROM_HERE,
-                 base::TimeDelta::FromMilliseconds(
-                     probers_.front()->estimated_execution_time()),
-                 this, &StunProberTrial::OnTimer);
-  }
-}
-
-void StunProberTrial::OnTimer() {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-  probers_[started_probers_]->Start(this);
-  started_probers_++;
-
-  if (started_probers_ == total_probers_)
-    timer_.Stop();
-}
-
-}  // namespace blink
diff --git a/third_party/blink/renderer/platform/peerconnection/stun_field_trial.h b/third_party/blink/renderer/platform/peerconnection/stun_field_trial.h
deleted file mode 100644
index 223e0145..0000000
--- a/third_party/blink/renderer/platform/peerconnection/stun_field_trial.h
+++ /dev/null
@@ -1,103 +0,0 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_PEERCONNECTION_STUN_FIELD_TRIAL_H_
-#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_PEERCONNECTION_STUN_FIELD_TRIAL_H_
-
-#include <memory>
-#include <string>
-#include <vector>
-
-#include "base/macros.h"
-#include "base/threading/thread_checker.h"
-#include "base/timer/timer.h"
-#include "third_party/blink/renderer/platform/p2p/network_list_manager.h"
-#include "third_party/blink/renderer/platform/p2p/network_list_observer.h"
-#include "third_party/blink/renderer/platform/platform_export.h"
-#include "third_party/webrtc/p2p/stunprober/stun_prober.h"
-#include "third_party/webrtc/rtc_base/network.h"
-#include "third_party/webrtc/rtc_base/third_party/sigslot/sigslot.h"
-
-namespace rtc {
-class PacketSocketFactory;
-class SocketAddress;
-}  // namespace rtc
-
-namespace blink {
-
-// Wait for 30 seconds to avoid high CPU usage during browser start-up which
-// might affect the accuracy of the trial. The trial wakes up the browser every
-// 1 ms for no more than 3 seconds to see if time has passed for sending next
-// stun probe.
-static const int kExperimentStartDelayMs = 30000;
-
-// TODO(crbug.com/787254): Migrate away from std::vector and std::string.
-class StunProberTrial : public stunprober::StunProber::Observer,
-                        public sigslot::has_slots<> {
- public:
-  struct PLATFORM_EXPORT Param {
-    Param();
-    ~Param();
-    int requests_per_ip = 0;
-    int interval_ms = 0;
-    int shared_socket_mode = 0;
-    int batch_size = 0;
-    int total_batches = 0;
-    std::vector<rtc::SocketAddress> servers;
-  };
-
-  PLATFORM_EXPORT StunProberTrial(rtc::NetworkManager* network_manager,
-                                  const std::string& params,
-                                  rtc::PacketSocketFactory* factory);
-  ~StunProberTrial() override;
-
- private:
-  // This will use |factory_| to create sockets, send stun binding requests with
-  // various intervals as determined by |params|, observed the success rate and
-  // latency of the stun responses and report through UMA.
-  void OnNetworksChanged();
-
-  // Parsing function to decode the '/' separated parameter string |params|.
-  static PLATFORM_EXPORT bool ParseParameters(const std::string& param_line,
-                                              Param* params);
-
-  // stunprober::StunProber::Observer:
-  void OnPrepared(stunprober::StunProber* prober,
-                  stunprober::StunProber::Status status) override;
-  // OnFinished is invoked when the StunProber receives all the responses or
-  // times out.
-  void OnFinished(stunprober::StunProber* prober,
-                  stunprober::StunProber::Status status) override;
-
-  // This will be invoked repeatedly for |total_probers_| times with the
-  // interval equal to the estimated run time of a prober.
-  void OnTimer();
-
-  void SaveHistogramData();
-
-  rtc::NetworkManager* network_manager_;
-  std::string param_line_;
-  rtc::PacketSocketFactory* factory_ = nullptr;
-  int total_probers_ = 0;
-  int batch_size_ = 0;
-  int ready_probers_ = 0;
-  int started_probers_ = 0;
-  int finished_probers_ = 0;
-  std::vector<stunprober::StunProber*> probers_;
-  THREAD_CHECKER(thread_checker_);
-
-  // The reason we use a timer instead of depending on the OnFinished callback
-  // of each prober is that the OnFinished is not fired at the last of STUN
-  // request of each prober, instead, it includes a timeout period which waits
-  // the server response to come back. Having a timer guarantees the
-  // inter-prober intervals is the same as the STUN interval inside a prober.
-  base::RepeatingTimer timer_;
-
-  FRIEND_TEST_ALL_PREFIXES(StunProbeTrial, VerifyParameterParsing);
-  DISALLOW_COPY_AND_ASSIGN(StunProberTrial);
-};
-
-}  // namespace blink
-
-#endif  // THIRD_PARTY_BLINK_RENDERER_PLATFORM_PEERCONNECTION_STUN_FIELD_TRIAL_H_
diff --git a/third_party/blink/renderer/platform/peerconnection/stun_field_trial_test.cc b/third_party/blink/renderer/platform/peerconnection/stun_field_trial_test.cc
deleted file mode 100644
index e48d6c04..0000000
--- a/third_party/blink/renderer/platform/peerconnection/stun_field_trial_test.cc
+++ /dev/null
@@ -1,41 +0,0 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "third_party/blink/renderer/platform/peerconnection/stun_field_trial.h"
-
-#include "testing/gtest/include/gtest/gtest.h"
-#include "third_party/webrtc/rtc_base/socket_address.h"
-
-namespace blink {
-
-TEST(StunProbeTrial, VerifyParameterParsing) {
-  StunProberTrial::Param params;
-  std::string param_line;
-
-  param_line = "20/100/1/3/3/server:3478/server2:3478";
-  EXPECT_TRUE(StunProberTrial::ParseParameters(param_line, &params));
-  EXPECT_EQ(params.requests_per_ip, 20);
-  EXPECT_EQ(params.interval_ms, 100);
-  EXPECT_EQ(params.shared_socket_mode, 1);
-  EXPECT_EQ(params.batch_size, 3);
-  EXPECT_EQ(params.total_batches, 3);
-  EXPECT_EQ(params.servers.size(), 2u);
-  EXPECT_EQ(params.servers[0], rtc::SocketAddress("server", 3478));
-  EXPECT_EQ(params.servers[1], rtc::SocketAddress("server2", 3478));
-  params.servers.clear();
-
-  param_line = "/////server:3478";
-  EXPECT_TRUE(StunProberTrial::ParseParameters(param_line, &params));
-  EXPECT_EQ(params.requests_per_ip, 10);
-  EXPECT_EQ(params.servers.size(), 1u);
-  EXPECT_EQ(params.servers[0], rtc::SocketAddress("server", 3478));
-  params.servers.clear();
-
-  // Make sure there is no crash. Parsing will fail as there is no server
-  // specified.
-  param_line = "/////";
-  EXPECT_FALSE(StunProberTrial::ParseParameters(param_line, &params));
-}
-
-}  // namespace blink
diff --git a/third_party/blink/renderer/platform/testing/empty_web_media_player.cc b/third_party/blink/renderer/platform/testing/empty_web_media_player.cc
index a0373a934..4897f65 100644
--- a/third_party/blink/renderer/platform/testing/empty_web_media_player.cc
+++ b/third_party/blink/renderer/platform/testing/empty_web_media_player.cc
@@ -5,7 +5,6 @@
 #include "third_party/blink/renderer/platform/testing/empty_web_media_player.h"
 
 #include "media/base/video_frame.h"
-#include "third_party/blink/public/platform/web_size.h"
 #include "third_party/blink/public/platform/web_time_range.h"
 
 namespace blink {
diff --git a/third_party/blink/renderer/platform/wtf/allocator/partitions.cc b/third_party/blink/renderer/platform/wtf/allocator/partitions.cc
index 8621cb4d..60ca0b8 100644
--- a/third_party/blink/renderer/platform/wtf/allocator/partitions.cc
+++ b/third_party/blink/renderer/platform/wtf/allocator/partitions.cc
@@ -109,8 +109,7 @@
 #if PA_ALLOW_PCSCAN
   if (base::FeatureList::IsEnabled(base::features::kPartitionAllocPCScan) ||
       base::FeatureList::IsEnabled(kPCScanBlinkPartitions)) {
-    auto& pcscan =
-        base::internal::PCScan<base::internal::ThreadSafe>::Instance();
+    auto& pcscan = base::internal::PCScan::Instance();
     pcscan.RegisterNonScannableRoot(array_buffer_root_);
 #if !BUILDFLAG(USE_PARTITION_ALLOC_AS_MALLOC)
     pcscan.RegisterScannableRoot(fast_malloc_root_);
diff --git a/third_party/blink/web_tests/animations/animation-display-lock.html b/third_party/blink/web_tests/animations/animation-display-lock.html
new file mode 100644
index 0000000..df005c3
--- /dev/null
+++ b/third_party/blink/web_tests/animations/animation-display-lock.html
@@ -0,0 +1,174 @@
+<!DOCTYPE html>
+<meta charset=utf8>
+<title>Test getComputedStyle on a CSS animation in a display locked subtree</title>
+<script src="../external/wpt/web-animations/testcommon.js"></script>
+<script src="../resources/testharness.js"></script>
+<script src="../resources/testharnessreport.js"></script>
+<!-- TODO(crbug.com/959441): Move to WPT once behavior is specced -->
+<style>
+  #container {
+    content-visibility: visible;
+    contain: style layout paint;
+    contain-intrinsic-size: 0 100px;
+  }
+  @keyframes fade {
+    from { opacity: 1; }
+    to { opacity: 0;  }
+  }
+  #target {
+    background: 'green';
+    height: 100px;
+    width: 100px;
+  }
+  .animate {
+    animation: fade 1s linear 2 alternate;
+  }
+  .transition {
+    transition: opacity 1s linear;
+  }
+</style>
+<body>
+  <div id="container"></div>
+</body>
+<script>
+"use strict";
+
+function reset() {
+  const container = document.getElementById('container');
+  const target = document.getElementById('target');
+  container.style = '';
+  container.removeChild(target);
+}
+
+function createAnimatingElement(test, name) {
+  const container = document.getElementById('container');
+  const target = document.createElement('div');
+  container.appendChild(target);
+  target.id = 'target';
+  target.className = name;
+  test.add_cleanup(() => {
+    reset();
+  });
+  return target;
+}
+
+promise_test(async t => {
+  const container = document.getElementById('container');
+  const target = createAnimatingElement(t, 'animate');
+  let animationIterationEvent = false;
+  target.addEventListener('animationiteration', () => {
+    animationIterationEvent = true;
+  });
+  const animation = target.getAnimations()[0];
+  await animation.ready;
+  await waitForAnimationFrames(1);
+  container.style.contentVisibility = 'hidden';
+  animation.currentTime = 1500;
+  assert_approx_equals(
+      parseFloat(getComputedStyle(target).opacity), 0.5, 1e-6,
+      'Computed style is updated even when the animation is running in a ' +
+      'display locked subtree');
+  await waitForAnimationFrames(2);
+  assert_false(animationIterationEvent,
+               'Animation events do no fire while the animation is ' +
+               'running in a display locked subtree');
+  container.style.contentVisibility = 'visible';
+  await waitForAnimationFrames(2);
+  assert_true(animationIterationEvent,
+              'The animationiteration event fires once the animation is ' +
+              'no longer display locked');
+}, 'Animation events do not fire for a CSS animation running in a display ' +
+   'locked subtree');
+
+promise_test(async t => {
+  const container = document.getElementById('container');
+  const target = createAnimatingElement(t, 'animate');
+  const animation = target.getAnimations()[0];
+  await animation.ready;
+  let finishedWhileDisplayLocked = false;
+  animation.finished.then(() => {
+    finishedWhileDisplayLocked =
+        getComputedStyle(container).contentVisibility == 'hidden';
+  });
+  await waitForAnimationFrames(1);
+  container.style.contentVisibility = 'hidden';
+  // Advance to just shy of the effect end.
+  animation.currentTime = 1999;
+  assert_approx_equals(
+      parseFloat(getComputedStyle(target).opacity), 0.999, 1e-6,
+                'Computed style is updated even when the animation is ' +
+                'running in a display locked subtree');
+  // Advancing frames should not resolve the finished promise.
+  await waitForAnimationFrames(3);
+  container.style.contentVisibility = 'visible';
+  // Now we can resolve the finished promise.
+  await animation.finished;
+  assert_equals(finishedWhileDisplayLocked, false);
+}, 'The finished promise does not resolve due to the normal passage of time  ' +
+   'for a CSS animation in a display locked subtree');
+
+promise_test(async t => {
+  const container = document.getElementById('container');
+  await waitForAnimationFrames(1);
+  const target = createAnimatingElement(t, 'transition');
+  await waitForAnimationFrames(1);
+  target.style.opacity = 0;
+  const animation = target.getAnimations()[0];
+  await animation.ready;
+  let finishedWhileDisplayLocked = false;
+  animation.finished.then(() => {
+    finishedWhileDisplayLocked =
+        getComputedStyle(container).contentVisibility == 'hidden';
+  });
+  await waitForAnimationFrames(1);
+  container.style.contentVisibility = 'hidden';
+  // Advance to just shy of the effect end.
+  animation.currentTime = 999;
+  assert_approx_equals(
+      parseFloat(getComputedStyle(target).opacity), 0.001, 1e-6,
+                'Computed style is updated even when the animation is ' +
+                'running in a display locked subtree');
+  // Advancing frames should not resolve the finished promise.
+  await waitForAnimationFrames(3);
+  container.style.contentVisibility = 'visible';
+  // Now we can resolve the finished promise.
+  await animation.finished;
+  assert_equals(finishedWhileDisplayLocked, false);
+}, 'The finished promise does not resolve due to the normal passage of time  ' +
+   'for a CSS transition in a display locked subtree');
+
+promise_test(async t => {
+  const container = document.getElementById('container');
+  const target = createAnimatingElement(t, 'animate');
+  const animation = target.getAnimations()[0];
+  target.className = '';
+  container.style.contentVisibility = 'hidden';
+  assert_equals(target.getAnimations().length, 0);
+  let animationStartEvent = false;
+  let animationFinished = false;
+  target.addEventListener('animationstart', () => {
+    animationStartEvent = true;
+  });
+  // Though originally a CSS animation, it is no longer associated with
+  // CSS rules and no longer has an owning element. It now behaves like a
+  // programmatic web animation. Events should be dispatched and promises
+  // resolved despite being in a display locked subtree.
+  animation.play();
+  animation.finished.then(() => {
+    animationFinished = true;
+  });
+  assert_equals(target.getAnimations().length, 1);
+  await animation.ready;
+  await waitForAnimationFrames(2);
+  assert_true(animationStartEvent,
+              'Animation event not blocked on display locked subtree if ' +
+              'no owning element');
+  animation.currentTime = 1999;
+  await waitForAnimationFrames(2);
+  assert_true(animationFinished,
+              'Finished promise not blocked on display locked subtrtee if ' +
+              'no owning element');
+}, 'Events and promises are handled normally for animations without an ' +
+   'owning element');
+
+</script>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-tables/tentative/table-width-redistribution-fixed.html b/third_party/blink/web_tests/external/wpt/css/css-tables/tentative/table-width-redistribution-fixed.html
index ed126710..4f7cf8e 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-tables/tentative/table-width-redistribution-fixed.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-tables/tentative/table-width-redistribution-fixed.html
@@ -24,7 +24,7 @@
   }
 </style>
 <main>
-<h1>Fixed tables: Compute column computed widths from assignable table width</h1>
+ <h1>Fixed tables: Compute column computed widths from assignable table width</h1>
 <ul>
   <li>auto columns have a min width of 0. Max width still gets computed.</li>
   <li>percent columns have a min width of 0.</li>
@@ -298,7 +298,7 @@
 <h2>Percentage/auto/fixed mix</h2>
 
 <p class="testdesc">Assignable: 100px;C0:50% C1:100px C2: Auto
-C0: 50% becomes
+C0, C1 get assigned values, C2 fills the rest.
 <table style="width:calc(100px + 32px)" data-expected-width=132>
   <tr>
     <td style="width:50%" data-expected-width=50>50%</td>
@@ -326,6 +326,48 @@
     <td style="width:60px" data-expected-width=60>60px</td>
   </tr>
 </table>
+
+<h2>Fixed 0-width columns</h2>
+<p>Fixed 0-width columns are an exception. They are treated as a mix of fixed and auto columns.</p>
+  <li>If there are only zero-width columns, width is distibuted evenly.</li>
+  <li>If there are any fixed,percentage, or auto columns,  0-width columns do not grow.</li>
+<p class="testdesc">Assignable: 100px;C0:0-width, C1:0-width
+  All 0-width columns grow.
+</p>
+<table style="width:calc(100px + 24px)" data-expected-width=124>
+  <tr>
+    <td style="width:0" data-expected-width=50>0</td>
+    <td style="width:0" data-expected-width=50>0</td>
+  </tr>
+</table>
+<p class="testdesc">Assignable: 100px;C0:0-width, C1:auto
+  0-width column does not grow.
+</p>
+<table style="width:calc(100px + 24px)" data-expected-width=124>
+  <tr>
+    <td style="width:0" data-expected-width=0>0</td>
+    <td style="width:auto" data-expected-width=100>0</td>
+  </tr>
+</table>
+<p class="testdesc">Assignable: 100px;C0:0-width, C1:50px
+  0-width column does not grow.
+</p>
+<table style="width:calc(100px + 24px)" data-expected-width=124>
+  <tr>
+    <td style="width:0" data-expected-width=0>0</td>
+    <td style="width:50px" data-expected-width=100>0</td>
+  </tr>
+</table>
+<p class="testdesc">Assignable: 100px;C0:0-width, C1:50%
+  0-width column does not grow.
+</p>
+<table style="width:calc(100px + 24px)" data-expected-width=124>
+  <tr>
+    <td style="width:0" data-expected-width=0>0</td>
+    <td style="width:50%" data-expected-width=100>0</td>
+  </tr>
+</table>
+
 </main>
 <script>
   checkLayout("table");
diff --git a/third_party/blink/web_tests/external/wpt/resource-timing/entry-attributes.html b/third_party/blink/web_tests/external/wpt/resource-timing/entry-attributes.html
index 1aee1a3..b8d3371 100644
--- a/third_party/blink/web_tests/external/wpt/resource-timing/entry-attributes.html
+++ b/third_party/blink/web_tests/external/wpt/resource-timing/entry-attributes.html
@@ -46,18 +46,7 @@
   });
 }
 
-promise_test(async () => {
-  // Clean up entries from scripts includes.
-  performance.clearResourceTimings();
-  await load_image("resources/fake_responses.py#hash=1");
-  const entry_list = performance.getEntriesByType("resource");
-  if (entry_list.length != 1) {
-    throw new Error("There should be one entry for one resource");
-  }
-  const entry = entry_list[0];
-  assert_true(entry.name.includes('#hash=1'),
-    "There should be a hash in the resource name");
-
+function assert_http_resource(entry) {
   assert_ordered(entry, [
     "fetchStart",
     "domainLookupStart",
@@ -86,6 +75,21 @@
     "encodedBodySize",
     "decodedBodySize",
   ]);
+}
+
+promise_test(async () => {
+  // Clean up entries from scripts includes.
+  performance.clearResourceTimings();
+  await load_image("resources/fake_responses.py#hash=1");
+  const entry_list = performance.getEntriesByType("resource");
+  if (entry_list.length != 1) {
+    throw new Error("There should be one entry for one resource");
+  }
+  const entry = entry_list[0];
+  assert_true(entry.name.includes('#hash=1'),
+    "There should be a hash in the resource name");
+
+  assert_http_resource(entry);
 }, "URL fragments should be present in the 'name' attribute");
 
 </script>
diff --git a/third_party/blink/web_tests/flag-specific/disable-layout-ng/external/wpt/css/css-tables/tentative/table-width-redistribution-fixed-expected.txt b/third_party/blink/web_tests/flag-specific/disable-layout-ng/external/wpt/css/css-tables/tentative/table-width-redistribution-fixed-expected.txt
index 01f1ddb..3dd4e86 100644
--- a/third_party/blink/web_tests/flag-specific/disable-layout-ng/external/wpt/css/css-tables/tentative/table-width-redistribution-fixed-expected.txt
+++ b/third_party/blink/web_tests/flag-specific/disable-layout-ng/external/wpt/css/css-tables/tentative/table-width-redistribution-fixed-expected.txt
@@ -34,5 +34,9 @@
 PASS table 20
 PASS table 21
 PASS table 22
+PASS table 23
+PASS table 24
+PASS table 25
+PASS table 26
 Harness: the test ran to completion.
 
diff --git a/tools/mb/mb_config.pyl b/tools/mb/mb_config.pyl
index bd40d8c6..a5f4c875 100644
--- a/tools/mb/mb_config.pyl
+++ b/tools/mb/mb_config.pyl
@@ -118,8 +118,8 @@
       # on the chromium.gpu waterfall, which it mirrors via trybots.pyl.
       'android-marshmallow-arm64-rel': 'gpu_tests_android_release_bot_minimal_symbols_arm64_fastbuild',
 
-      'android-marshmallow-x86-rel': 'android_release_bot_minimal_symbols_x86_fastbuild_resource_whitelisting_webview_google',
-      'android-marshmallow-x86-rel-non-cq': 'android_release_bot_minimal_symbols_x86_fastbuild_resource_whitelisting_webview_google',
+      'android-marshmallow-x86-rel': 'android_release_bot_minimal_symbols_x86_fastbuild_resource_allowlisting_webview_google',
+      'android-marshmallow-x86-rel-non-cq': 'android_release_bot_minimal_symbols_x86_fastbuild_resource_allowlisting_webview_google',
       'android-nougat-arm64-rel': 'android_release_bot_minimal_symbols_arm64_fastbuild_webview_google',
       # TODO(crbug/1182468) Remove android coverage bots after coverage is
       # running on CQ.
@@ -433,8 +433,8 @@
       'GPU Mac Builder (dbg)': 'gpu_tests_debug_bot',
       'GPU Linux Builder': 'gpu_tests_release_trybot',
       'GPU Linux Builder (dbg)': 'gpu_tests_debug_bot',
-      'GPU Win x64 Builder': 'gpu_tests_release_trybot_resource_whitelisting',
-      'GPU Win x64 Builder Code Coverage': 'gpu_tests_release_trybot_resource_whitelisting_code_coverage',
+      'GPU Win x64 Builder': 'gpu_tests_release_trybot_resource_allowlisting',
+      'GPU Win x64 Builder Code Coverage': 'gpu_tests_release_trybot_resource_allowlisting_code_coverage',
       'GPU Win x64 Builder (dbg)': 'gpu_tests_debug_bot',
       'Android Release (Nexus 5X)': 'gpu_tests_android_release_trybot_arm64_fastbuild',
     },
@@ -587,7 +587,7 @@
       'linux-swangle-x64': 'angle_deqp_release_trybot',
       'linux-swangle-x86': 'angle_deqp_release_trybot_x86',
       'mac-swangle-chromium-x64': 'gpu_tests_release_trybot_deterministic_mac',
-      'win-swangle-chromium-x86': 'gpu_tests_release_trybot_x86_resource_whitelisting',
+      'win-swangle-chromium-x86': 'gpu_tests_release_trybot_x86_resource_allowlisting',
       'win-swangle-tot-angle-x64': 'angle_deqp_release_trybot',
       'win-swangle-tot-angle-x86': 'angle_deqp_release_trybot_x86',
       'win-swangle-tot-swiftshader-x64': 'angle_deqp_release_trybot',
@@ -655,7 +655,7 @@
       'V8 Blink Mac': 'release_bot_blink',
       'V8 Blink Win': 'release_bot_blink',
       'V8 Linux GN': 'release_bot',
-      'Win V8 FYI Release (NVIDIA)': 'gpu_tests_release_trybot_x86_resource_whitelisting',
+      'Win V8 FYI Release (NVIDIA)': 'gpu_tests_release_trybot_x86_resource_allowlisting',
     },
 
     'chromium.updater': {
@@ -781,9 +781,9 @@
       'android-cronet-marshmallow-arm64-rel': 'android_cronet_release_trybot_arm64',
       'android-inverse-fieldtrials-pie-x86-fyi-rel': 'android_release_trybot_x86_fastbuild_webview_google_invert_fieldtrials',
       'android-lollipop-arm-rel': 'android_release_trybot_webview_google',
-      'android-marshmallow-arm64-rel': 'gpu_tests_android_release_trybot_arm64_resource_whitelisting_fastbuild_java_coverage',
-      'android-marshmallow-x86-rel': 'android_release_trybot_x86_fastbuild_resource_whitelisting_webview_google',
-      'android-marshmallow-x86-rel-non-cq': 'android_release_trybot_x86_fastbuild_resource_whitelisting_webview_google',
+      'android-marshmallow-arm64-rel': 'gpu_tests_android_release_trybot_arm64_resource_allowlisting_fastbuild_java_coverage',
+      'android-marshmallow-x86-rel': 'android_release_trybot_x86_fastbuild_resource_allowlisting_webview_google',
+      'android-marshmallow-x86-rel-non-cq': 'android_release_trybot_x86_fastbuild_resource_allowlisting_webview_google',
       'android-nougat-arm64-rel': 'android_release_trybot_arm64_fastbuild_webview_google',
       'android-oreo-arm64-cts-networkservice-dbg': 'android_debug_trybot_arm64',
       # TODO(crbug/1182468) Remove android coverage bots after coverage is
@@ -1107,7 +1107,7 @@
       'linux-swangle-try-x64': 'angle_deqp_release_trybot',
       'linux-swangle-try-x86': 'angle_deqp_release_trybot_x86',
       'mac-swangle-chromium-try-x64': 'gpu_tests_release_trybot_deterministic_mac',
-      'win-swangle-chromium-try-x86': 'gpu_tests_release_trybot_x86_resource_whitelisting',
+      'win-swangle-chromium-try-x86': 'gpu_tests_release_trybot_x86_resource_allowlisting',
       'win-swangle-try-tot-angle-x64': 'angle_deqp_release_trybot',
       'win-swangle-try-tot-angle-x86': 'angle_deqp_release_trybot_x86',
       'win-swangle-try-tot-swiftshader-x64': 'angle_deqp_release_trybot',
@@ -1139,19 +1139,19 @@
       'gpu-fyi-try-win10-nvidia-rel-32': 'gpu_fyi_tests_release_trybot_x86',
       'gpu-fyi-try-win10-nvidia-rel-64': 'gpu_fyi_tests_release_trybot',
       'gpu-fyi-try-win10-nvidia-sk-dawn-rel-64': 'gpu_tests_sk_dawn_release_trybot',
-      'win10_chromium_inverse_fieldtrials_x64_fyi_rel_ng': 'gpu_tests_release_trybot_resource_whitelisting_invert_fieldtrials',
+      'win10_chromium_inverse_fieldtrials_x64_fyi_rel_ng': 'gpu_tests_release_trybot_resource_allowlisting_invert_fieldtrials',
       'win10_chromium_x64_dbg_ng': 'gpu_tests_debug_bot',
-      'win10_chromium_x64_rel_ng': 'gpu_tests_release_trybot_resource_whitelisting_code_coverage',
+      'win10_chromium_x64_rel_ng': 'gpu_tests_release_trybot_resource_allowlisting_code_coverage',
       'win10_chromium_x64_rel_ng_exp': 'release_trybot',
       'win-annotator-rel': 'release_trybot',
       'win-asan': 'asan_clang_fuzzer_static_v8_heap_minimal_symbols_release',
       'win-celab-try-rel': 'release_bot_minimal_symbols',
       'win-libfuzzer-asan-rel': 'libfuzzer_windows_asan_release_trybot',
-      'win7-rel': 'gpu_tests_release_trybot_x86_resource_whitelisting',
+      'win7-rel': 'gpu_tests_release_trybot_x86_resource_allowlisting',
       'win_x64_archive': 'release_trybot',
       'win_archive': 'release_trybot_x86',
       'win_chromium_compile_dbg_ng': 'gpu_tests_debug_bot_x86_no_symbols',
-      'win_chromium_compile_rel_ng': 'gpu_tests_release_trybot_x86_resource_whitelisting',
+      'win_chromium_compile_rel_ng': 'gpu_tests_release_trybot_x86_resource_allowlisting',
       'win_chromium_dbg_ng': 'gpu_tests_debug_bot_x86_no_symbols',
       'win_chromium_x64_rel_ng': 'gpu_tests_release_trybot',
       'win_mojo': 'release_trybot_x86',
@@ -1171,7 +1171,7 @@
     },
 
     'tryserver.webrtc': {
-      'win_chromium_compile': 'gpu_tests_release_trybot_resource_whitelisting',
+      'win_chromium_compile': 'gpu_tests_release_trybot_resource_allowlisting',
       'win_chromium_compile_dbg': 'gpu_tests_debug_bot_x86_no_symbols',
       'mac_chromium_compile': 'gpu_tests_release_trybot',
       'linux_chromium_compile': 'release_trybot',
@@ -1397,9 +1397,9 @@
       'webview_google',
     ],
 
-    'android_release_bot_minimal_symbols_x86_fastbuild_resource_whitelisting_webview_google': [
+    'android_release_bot_minimal_symbols_x86_fastbuild_resource_allowlisting_webview_google': [
       'android', 'release_bot', 'minimal_symbols', 'x86',
-      'android_fastbuild', 'resource_whitelisting', 'webview_google',
+      'android_fastbuild', 'resource_allowlisting', 'webview_google',
     ],
 
     'android_release_bot_minimal_symbols_x86_fastbuild_webview_google': [
@@ -1457,9 +1457,9 @@
       'webview_google',
     ],
 
-    'android_release_trybot_x86_fastbuild_resource_whitelisting_webview_google': [
+    'android_release_trybot_x86_fastbuild_resource_allowlisting_webview_google': [
       'android', 'release_trybot', 'x86', 'android_fastbuild',
-      'resource_whitelisting', 'webview_google',
+      'resource_allowlisting', 'webview_google',
     ],
 
     'android_release_trybot_x86_fastbuild_webview_google': [
@@ -2066,13 +2066,13 @@
 
     'gpu_tests_android_release_bot_minimal_symbols_arm64_fastbuild': [
       'gpu_tests', 'android', 'release_bot', 'minimal_symbols', 'arm64',
-      'resource_whitelisting', 'static_angle', 'android_fastbuild',
+      'resource_allowlisting', 'static_angle', 'android_fastbuild',
       'webview_google',
     ],
 
     'gpu_tests_android_release_bot_minimal_symbols_arm64_fastbuild_java_coverage': [
       'gpu_tests', 'android', 'release_bot', 'minimal_symbols', 'arm64',
-      'resource_whitelisting', 'static_angle', 'android_fastbuild', 'webview_google',
+      'resource_allowlisting', 'static_angle', 'android_fastbuild', 'webview_google',
       'android_no_proguard', 'use_java_coverage',
     ],
 
@@ -2080,7 +2080,7 @@
     # android_webview_unittests target.
     'gpu_tests_android_release_bot_no_symbols_arm64_fastbuild_native_coverage': [
       'gpu_tests', 'android', 'release_bot', 'arm64',
-      'resource_whitelisting', 'static_angle', 'android_fastbuild', 'webview_google',
+      'resource_allowlisting', 'static_angle', 'android_fastbuild', 'webview_google',
       'android_no_proguard', 'use_clang_coverage',
     ],
 
@@ -2097,9 +2097,9 @@
       'android_fastbuild',
     ],
 
-    'gpu_tests_android_release_trybot_arm64_resource_whitelisting_fastbuild_java_coverage': [
+    'gpu_tests_android_release_trybot_arm64_resource_allowlisting_fastbuild_java_coverage': [
       'gpu_tests', 'android', 'release_trybot', 'arm64', 'static_angle',
-      'resource_whitelisting', 'android_fastbuild', 'webview_google',
+      'resource_allowlisting', 'android_fastbuild', 'webview_google',
       'use_java_coverage', 'partial_code_coverage_instrumentation',
     ],
 
@@ -2184,20 +2184,20 @@
       'gpu_tests', 'release_trybot', 'mac_deterministic_build', 'invert_fieldtrials',
     ],
 
-    'gpu_tests_release_trybot_resource_whitelisting': [
-      'gpu_tests', 'release_trybot', 'resource_whitelisting',
+    'gpu_tests_release_trybot_resource_allowlisting': [
+      'gpu_tests', 'release_trybot', 'resource_allowlisting',
     ],
 
     # TODO(crbug.com/1004523) Delete this once coverage mode is enabled on the
     # standard Windows trybot and the dedicated coverage trybot is no longer
     # needed.
-    'gpu_tests_release_trybot_resource_whitelisting_code_coverage': [
-      'gpu_tests', 'release_trybot', 'resource_whitelisting',
+    'gpu_tests_release_trybot_resource_allowlisting_code_coverage': [
+      'gpu_tests', 'release_trybot', 'resource_allowlisting',
       'use_clang_coverage', 'partial_code_coverage_instrumentation',
     ],
 
-    'gpu_tests_release_trybot_resource_whitelisting_invert_fieldtrials': [
-      'gpu_tests', 'release_trybot', 'resource_whitelisting', 'invert_fieldtrials',
+    'gpu_tests_release_trybot_resource_allowlisting_invert_fieldtrials': [
+      'gpu_tests', 'release_trybot', 'resource_allowlisting', 'invert_fieldtrials',
     ],
 
     'gpu_tests_release_trybot_x86': [
@@ -2224,8 +2224,8 @@
       'gpu_tests', 'release_trybot', 'v8_pointer_compression',
     ],
 
-    'gpu_tests_release_trybot_x86_resource_whitelisting': [
-      'gpu_tests', 'release_trybot', 'x86', 'resource_whitelisting',
+    'gpu_tests_release_trybot_x86_resource_allowlisting': [
+      'gpu_tests', 'release_trybot', 'x86', 'resource_allowlisting',
     ],
 
     'gpu_tests_sk_dawn_release_trybot': [
@@ -2456,7 +2456,7 @@
     ],
 
     'official_goma_x64_pgo': [
-      'official', 'goma', 'x64', 'static', 'no_symbols', 'pgo_phase_1', 'no_resource_whitelisting',
+      'official', 'goma', 'x64', 'static', 'no_symbols', 'pgo_phase_1', 'no_resource_allowlisting',
     ],
 
     'official_goma_x86': [
@@ -2468,7 +2468,7 @@
     ],
 
     'official_goma_x86_pgo': [
-      'official', 'goma', 'x86', 'static', 'no_symbols', 'pgo_phase_1', 'no_resource_whitelisting',
+      'official', 'goma', 'x86', 'static', 'no_symbols', 'pgo_phase_1', 'no_resource_allowlisting',
     ],
 
     'official_optimize_goma': [
@@ -2759,7 +2759,7 @@
     },
 
     'amd64-lacros': {
-      'gn_args': 'use_ozone=true ozone_platform_wayland=true ozone_platform_x11=false target_os="chromeos" use_evdev_gestures=false use_vaapi=false use_gtk=false use_glib=false enable_linux_installer=false rtc_use_pipewire=false use_gio=false use_v8_context_snapshot=false use_custom_libcxx=false use_pulseaudio=false use_pangocairo=false chromeos_is_browser_only=true use_system_libsync=false cros_host_sysroot="//build/linux/debian_sid_amd64-sysroot" cros_v8_snapshot_sysroot="//build/linux/debian_sid_amd64-sysroot" use_custom_libcxx_for_host=true'
+      'gn_args': 'use_ozone=true ozone_platform_wayland=true ozone_platform_x11=false target_os="chromeos" use_evdev_gestures=false use_vaapi=true use_gtk=false use_glib=false enable_linux_installer=false rtc_use_pipewire=false use_gio=false use_v8_context_snapshot=false use_custom_libcxx=false use_pulseaudio=false use_pangocairo=false chromeos_is_browser_only=true use_system_libsync=false cros_host_sysroot="//build/linux/debian_sid_amd64-sysroot" cros_v8_snapshot_sysroot="//build/linux/debian_sid_amd64-sysroot" use_custom_libcxx_for_host=true'
     },
 
     # We build Android with codecs on most bots to ensure maximum test
@@ -3257,7 +3257,7 @@
       'gn_args': 'optimize_webui=false',
     },
 
-    'no_resource_whitelisting': {
+    'no_resource_allowlisting': {
       'gn_args': 'enable_resource_allowlist_generation=false',
     },
 
@@ -3387,7 +3387,7 @@
       'mixins': ['release_trybot', 'dcheck_off',],
     },
 
-    'resource_whitelisting': {
+    'resource_allowlisting': {
       'gn_args': 'enable_resource_allowlist_generation=true',
     },
 
diff --git a/tools/mb/mb_config_expectations/chrome.json b/tools/mb/mb_config_expectations/chrome.json
index fc45870..3735f39 100644
--- a/tools/mb/mb_config_expectations/chrome.json
+++ b/tools/mb/mb_config_expectations/chrome.json
@@ -227,7 +227,7 @@
       "use_system_libsync": false,
       "use_thin_lto": true,
       "use_v8_context_snapshot": false,
-      "use_vaapi": false
+      "use_vaapi": true
     }
   },
   "linux-chrome": {
diff --git a/tools/mb/mb_config_expectations/chromium.chromiumos.json b/tools/mb/mb_config_expectations/chromium.chromiumos.json
index 7b760d02..a9dc2d3e 100644
--- a/tools/mb/mb_config_expectations/chromium.chromiumos.json
+++ b/tools/mb/mb_config_expectations/chromium.chromiumos.json
@@ -64,7 +64,7 @@
       "use_pulseaudio": false,
       "use_system_libsync": false,
       "use_v8_context_snapshot": false,
-      "use_vaapi": false
+      "use_vaapi": true
     }
   },
   "chromeos-amd64-generic-rel": {
@@ -126,7 +126,7 @@
       "use_pulseaudio": false,
       "use_system_libsync": false,
       "use_v8_context_snapshot": false,
-      "use_vaapi": false
+      "use_vaapi": true
     }
   },
   "lacros-amd64-generic-rel": {
@@ -154,7 +154,7 @@
       "use_pulseaudio": false,
       "use_system_libsync": false,
       "use_v8_context_snapshot": false,
-      "use_vaapi": false
+      "use_vaapi": true
     }
   },
   "linux-cfm-rel": {
diff --git a/tools/mb/mb_config_expectations/chromium.fyi.json b/tools/mb/mb_config_expectations/chromium.fyi.json
index 73725eb..25f0564 100644
--- a/tools/mb/mb_config_expectations/chromium.fyi.json
+++ b/tools/mb/mb_config_expectations/chromium.fyi.json
@@ -619,7 +619,7 @@
       "use_pulseaudio": false,
       "use_system_libsync": false,
       "use_v8_context_snapshot": false,
-      "use_vaapi": false
+      "use_vaapi": true
     }
   },
   "linux-annotator-rel": {
diff --git a/tools/mb/mb_config_expectations/chromium.perf.json b/tools/mb/mb_config_expectations/chromium.perf.json
index 90af3c4f..33eb3b63 100644
--- a/tools/mb/mb_config_expectations/chromium.perf.json
+++ b/tools/mb/mb_config_expectations/chromium.perf.json
@@ -87,7 +87,7 @@
       "use_system_libsync": false,
       "use_thin_lto": true,
       "use_v8_context_snapshot": false,
-      "use_vaapi": false
+      "use_vaapi": true
     }
   },
   "linux-builder-perf": {
diff --git a/tools/mb/mb_config_expectations/internal.chrome.fyi.json b/tools/mb/mb_config_expectations/internal.chrome.fyi.json
index fc5a748..dbceb49 100644
--- a/tools/mb/mb_config_expectations/internal.chrome.fyi.json
+++ b/tools/mb/mb_config_expectations/internal.chrome.fyi.json
@@ -24,7 +24,7 @@
       "use_pulseaudio": false,
       "use_system_libsync": false,
       "use_v8_context_snapshot": false,
-      "use_vaapi": false
+      "use_vaapi": true
     }
   },
   "linux-autofill-captured-sites-rel": {
diff --git a/tools/mb/mb_config_expectations/internal.chromeos.fyi.json b/tools/mb/mb_config_expectations/internal.chromeos.fyi.json
index 44dcb30e..85727d0 100644
--- a/tools/mb/mb_config_expectations/internal.chromeos.fyi.json
+++ b/tools/mb/mb_config_expectations/internal.chromeos.fyi.json
@@ -65,7 +65,7 @@
       "use_system_libsync": false,
       "use_thin_lto": true,
       "use_v8_context_snapshot": false,
-      "use_vaapi": false
+      "use_vaapi": true
     }
   }
 }
\ No newline at end of file
diff --git a/tools/mb/mb_config_expectations/official.chrome.continuous.json b/tools/mb/mb_config_expectations/official.chrome.continuous.json
index 5e9ade0..42baadc 100644
--- a/tools/mb/mb_config_expectations/official.chrome.continuous.json
+++ b/tools/mb/mb_config_expectations/official.chrome.continuous.json
@@ -29,7 +29,7 @@
       "use_system_libsync": false,
       "use_thin_lto": true,
       "use_v8_context_snapshot": false,
-      "use_vaapi": false
+      "use_vaapi": true
     }
   }
 }
\ No newline at end of file
diff --git a/tools/mb/mb_config_expectations/official.chrome.json b/tools/mb/mb_config_expectations/official.chrome.json
index 7a87748..6849d29 100644
--- a/tools/mb/mb_config_expectations/official.chrome.json
+++ b/tools/mb/mb_config_expectations/official.chrome.json
@@ -29,7 +29,7 @@
       "use_system_libsync": false,
       "use_thin_lto": true,
       "use_v8_context_snapshot": false,
-      "use_vaapi": false
+      "use_vaapi": true
     }
   }
 }
\ No newline at end of file
diff --git a/tools/mb/mb_config_expectations/tryserver.chrome.json b/tools/mb/mb_config_expectations/tryserver.chrome.json
index 13701124..b120099 100644
--- a/tools/mb/mb_config_expectations/tryserver.chrome.json
+++ b/tools/mb/mb_config_expectations/tryserver.chrome.json
@@ -149,7 +149,7 @@
       "use_system_libsync": false,
       "use_thin_lto": true,
       "use_v8_context_snapshot": false,
-      "use_vaapi": false
+      "use_vaapi": true
     }
   },
   "linux-chrome": {
diff --git a/tools/mb/mb_config_expectations/tryserver.chromium.chromiumos.json b/tools/mb/mb_config_expectations/tryserver.chromium.chromiumos.json
index 241a516..d96d63f2 100644
--- a/tools/mb/mb_config_expectations/tryserver.chromium.chromiumos.json
+++ b/tools/mb/mb_config_expectations/tryserver.chromium.chromiumos.json
@@ -115,7 +115,7 @@
       "use_pulseaudio": false,
       "use_system_libsync": false,
       "use_v8_context_snapshot": false,
-      "use_vaapi": false
+      "use_vaapi": true
     }
   },
   "linux-cfm-rel": {
diff --git a/tools/metrics/actions/actions.xml b/tools/metrics/actions/actions.xml
index 84172c12..0d8e07c 100644
--- a/tools/metrics/actions/actions.xml
+++ b/tools/metrics/actions/actions.xml
@@ -14061,7 +14061,6 @@
 </action>
 
 <action name="MobileMenuBackward">
-  <obsolete>Deprecated as of 3/2021</obsolete>
   <owner>gangwu@chromium.org</owner>
   <description>User pressed the back icon in the app menu.</description>
 </action>
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml
index 76c5b12..245e0bcf 100644
--- a/tools/metrics/histograms/enums.xml
+++ b/tools/metrics/histograms/enums.xml
@@ -1029,6 +1029,10 @@
     User has completed the account addition flow triggered from the bottom
     sheet.
   </int>
+  <int value="16" label="SuppressedConsecutiveDismissals">
+    The bottom sheet was suppressed as the user hit consecutive active dismissal
+    limit.
+  </int>
 </enum>
 
 <enum name="AccountConsistencyPromoAfterDismissal">
@@ -63419,6 +63423,7 @@
   <int value="2" label="localProfileCustomization"/>
   <int value="3" label="loadSignIn"/>
   <int value="4" label="loadForceSignIn"/>
+  <int value="5" label="profileSwitch"/>
 </enum>
 
 <enum name="ProfileResetRequestOriginEnum">
@@ -79916,6 +79921,8 @@
   <int value="10" label="Icon download failed"/>
   <int value="11" label="Icon read from disk failed"/>
   <int value="12" label="App ID mismatch"/>
+  <int value="13" label="Web app origin associations update failed"/>
+  <int value="14" label="Web app origin associations updated"/>
 </enum>
 
 <enum name="WebAppMoverResult">
diff --git a/tools/metrics/histograms/histograms_xml/android/histograms.xml b/tools/metrics/histograms/histograms_xml/android/histograms.xml
index 686bb08..9eaa70c4 100644
--- a/tools/metrics/histograms/histograms_xml/android/histograms.xml
+++ b/tools/metrics/histograms/histograms_xml/android/histograms.xml
@@ -21,6 +21,22 @@
 
 <histograms>
 
+<variants name="AutofillAssistantIntents">
+  <variant name="" summary="aggregated across all intents"/>
+  <variant name=".BuyMovieTicket"/>
+  <variant name=".FlightsCheckin"/>
+  <variant name=".FoodOrdering"/>
+  <variant name=".FoodOrderingDelivery"/>
+  <variant name=".FoodOrderingPickup"/>
+  <variant name=".NotSet"/>
+  <variant name=".PasswordChange"/>
+  <variant name=".RentCar"/>
+  <variant name=".Shopping"/>
+  <variant name=".ShoppingAssistedCheckout"/>
+  <variant name=".Teleport"/>
+  <variant name=".UnknownIntent"/>
+</variants>
+
 <histogram name="Android.AdaptiveToolbarButton.Clicked"
     enum="AdaptiveToolbarButtonVariant" expires_after="2022-02-15">
   <owner>bttk@chromium.org</owner>
@@ -66,16 +82,19 @@
   </summary>
 </histogram>
 
-<histogram name="Android.AutofillAssistant.DropOutReason"
+<histogram name="Android.AutofillAssistant.DropOutReason{Intent}"
     enum="AutofillAssistantDropOutReason" expires_after="2021-08-22">
+  <owner>selakovic@google.com</owner>
   <owner>mcarlen@chromium.org</owner>
   <summary>
-    Reports the drop out reason of an Autofill Assistant script. It is recorded
-    when Autofill Assistant is shut down or terminated. The AA_START value is
-    used as a baseline and counts the number of attempted starts of Autofill
-    Assistant flows. The sum of all drop out reasons should be the same as the
-    number of attempted starts (i.e. AA_START).
+    Reports the drop out reason of an Autofill Assistant script during the
+    {Intent} flow. It is recorded when Autofill Assistant is shut down or
+    terminated. The AA_START value is used as a baseline and counts the number
+    of attempted starts of Autofill Assistant flows. The sum of all drop out
+    reasons should be the same as the number of attempted starts (i.e.
+    AA_START).
   </summary>
+  <token key="Intent" variants="AutofillAssistantIntents"/>
 </histogram>
 
 <histogram name="Android.AutofillAssistant.FeatureModuleInstallation"
@@ -90,16 +109,6 @@
   </summary>
 </histogram>
 
-<histogram name="Android.AutofillAssistant.OnBoarding"
-    enum="AutofillAssistantOnBoarding" expires_after="2021-06-20">
-  <owner>lsuder@chromium.org</owner>
-  <owner>mcarlen@chromium.org</owner>
-  <summary>
-    Reports the basic user interactions that can happen in regard on boarding.
-    It is recorded on Autofill Assistant startup and during the on boarding.
-  </summary>
-</histogram>
-
 <histogram name="Android.AutofillAssistant.OnboardingFetcher.ResultStatus"
     enum="AutofillAssistantOnboardingFetcherResultStatus" expires_after="M93">
   <owner>sandromaggi@google.com</owner>
@@ -112,6 +121,18 @@
   </summary>
 </histogram>
 
+<histogram name="Android.AutofillAssistant.OnBoarding{Intent}"
+    enum="AutofillAssistantOnBoarding" expires_after="2021-09-04">
+  <owner>lsuder@chromium.org</owner>
+  <owner>mcarlen@chromium.org</owner>
+  <summary>
+    Reports the basic user interactions that can happen in regard to onboarding
+    during the {Intent} flow. It is recorded on Autofill Assistant startup and
+    during the on boarding.
+  </summary>
+  <token key="Intent" variants="AutofillAssistantIntents"/>
+</histogram>
+
 <histogram name="Android.AutofillAssistant.PaymentRequest.AutofillChanged"
     enum="AutofillAssistantPaymentRequestAutofillInfoChanged"
     expires_after="2021-07-18">
@@ -1725,6 +1746,16 @@
   <summary>Records how the omnibox was focused.</summary>
 </histogram>
 
+<histogram name="Android.OpenHistoryFromMenu.PerProfileType"
+    enum="BrowserProfileType" expires_after="2022-02-02">
+  <owner>sideyilmaz@chromium.org</owner>
+  <owner>chrome-incognito@google.com</owner>
+  <summary>
+    Records the clicks on History menu item separately for each profile type in
+    Android.
+  </summary>
+</histogram>
+
 <histogram name="Android.PackageStats.CacheSize" units="MB"
     expires_after="2021-08-25">
   <owner>nyquist@chromium.org</owner>
diff --git a/tools/metrics/histograms/histograms_xml/assistant/histograms.xml b/tools/metrics/histograms/histograms_xml/assistant/histograms.xml
index b5e250e..c631031b 100644
--- a/tools/metrics/histograms/histograms_xml/assistant/histograms.xml
+++ b/tools/metrics/histograms/histograms_xml/assistant/histograms.xml
@@ -201,6 +201,17 @@
   </summary>
 </histogram>
 
+<histogram name="Assistant.VoiceSearch.AgsaVersion" units="Version"
+    expires_after="2021-08-29">
+  <owner>wylieb@chromium.org</owner>
+  <owner>fgorski@chromium.org</owner>
+  <summary>
+    (Android only) Reports the current Agsa version on the device. The version
+    is reported as described in GSAState#parseAgsaMajorMinorVersionAsInteger.
+    Reported when the mic button is pressed.
+  </summary>
+</histogram>
+
 <histogram name="Assistant.VoiceSearch.ConsentOutcome"
     enum="AssistantConsentOutcome" expires_after="2021-08-29">
   <owner>wylieb@chromium.org</owner>
diff --git a/tools/metrics/histograms/histograms_xml/autofill/histograms.xml b/tools/metrics/histograms/histograms_xml/autofill/histograms.xml
index f16a012c..e4a2f26 100644
--- a/tools/metrics/histograms/histograms_xml/autofill/histograms.xml
+++ b/tools/metrics/histograms/histograms_xml/autofill/histograms.xml
@@ -1882,6 +1882,9 @@
 
 <histogram name="Autofill.UnownedFieldsWereFiltered" enum="Boolean"
     expires_after="M77">
+  <obsolete>
+    Removed 03/2021 as it is no longer needed for analysis.
+  </obsolete>
   <owner>battre@chromium.org</owner>
   <owner>chrome-autofill@google.com</owner>
   <summary>
diff --git a/tools/metrics/histograms/histograms_xml/new_tab_page/histograms.xml b/tools/metrics/histograms/histograms_xml/new_tab_page/histograms.xml
index 771bfb7..8502d59 100644
--- a/tools/metrics/histograms/histograms_xml/new_tab_page/histograms.xml
+++ b/tools/metrics/histograms/histograms_xml/new_tab_page/histograms.xml
@@ -674,6 +674,17 @@
   </summary>
 </histogram>
 
+<histogram name="NewTabPage.Drive.FileClick" units="index"
+    expires_after="2022-01-01">
+  <owner>tiborg@chromium.org</owner>
+  <owner>aee@chromium.org</owner>
+  <owner>andrevincent@google.com</owner>
+  <summary>
+    Logged when a user clicks on a file within the Drive Module. The index is
+    equal to the index of the file.
+  </summary>
+</histogram>
+
 <histogram name="NewTabPage.Languages.UILanguageRatioInTwoTopLanguages"
     units="%" expires_after="M77">
   <owner>jkrcal@chromium.org</owner>
diff --git a/tools/perf/core/perfetto_binary_roller/binary_deps.json b/tools/perf/core/perfetto_binary_roller/binary_deps.json
index ef16be0..a5264de 100644
--- a/tools/perf/core/perfetto_binary_roller/binary_deps.json
+++ b/tools/perf/core/perfetto_binary_roller/binary_deps.json
@@ -1,12 +1,12 @@
 {
     "trace_processor_shell": {
         "win": {
-            "hash": "036fcb5b80e4bf62b3e581fdfb09b6d949e7fbee",
-            "remote_path": "perfetto_binaries/trace_processor_shell/win/23f73816bf3ccb0f05a3ff9d12cb244efafd6f56/trace_processor_shell.exe"
+            "hash": "48c3b648e323cf9272b7ec69359684b2d4a3ad46",
+            "remote_path": "perfetto_binaries/trace_processor_shell/win/37518c39e3db120322359090db3d54f6ac100078/trace_processor_shell.exe"
         },
         "mac": {
-            "hash": "e3cff68dab2e6f915854ba3a81e8e29a0de2200a",
-            "remote_path": "perfetto_binaries/trace_processor_shell/mac/23f73816bf3ccb0f05a3ff9d12cb244efafd6f56/trace_processor_shell"
+            "hash": "b87a725de0aff939d4cf4cee236d9a932b706c0f",
+            "remote_path": "perfetto_binaries/trace_processor_shell/mac/37518c39e3db120322359090db3d54f6ac100078/trace_processor_shell"
         },
         "linux": {
             "hash": "17fe62a4edf94304989815b2ec0f9ef7c8d3fd99",
diff --git a/tools/run-swarmed.py b/tools/run-swarmed.py
index 371f3684..e78d2f3 100755
--- a/tools/run-swarmed.py
+++ b/tools/run-swarmed.py
@@ -102,6 +102,11 @@
     runner_args.append('--gtest_filter=' + args.gtest_filter)
   if args.gtest_repeat:
     runner_args.append('--gtest_repeat=' + args.gtest_repeat)
+  if args.test_launcher_shard_index and args.test_launcher_total_shards:
+    runner_args.append('--test-launcher-shard-index=' +
+                       args.test_launcher_shard_index)
+    runner_args.append('--test-launcher-total-shards=' +
+                       args.test_launcher_total_shards)
   elif args.target_os == 'fuchsia':
     filter_file = \
         'testing/buildbot/filters/fuchsia.' + args.target_name + '.filter'
@@ -184,6 +189,12 @@
   parser.add_argument(
       '--gtest_repeat',
       help='Number of times to repeat the specified set of tests.')
+  parser.add_argument(
+      '--test-launcher-shard-index',
+      help='Shard index to run. Use with --test-launcher-total-shards.')
+  parser.add_argument('--test-launcher-total-shards',
+                      help='Number of shards to split the test into. Use with'
+                      ' --test-launcher-shard-index.')
   parser.add_argument('--no-test-flags', action='store_true',
                       help='Do not add --test-launcher-summary-output and '
                            '--system-log-file flags to the comment.')
diff --git a/ui/color/BUILD.gn b/ui/color/BUILD.gn
index 449dedaa..938bb68 100644
--- a/ui/color/BUILD.gn
+++ b/ui/color/BUILD.gn
@@ -47,6 +47,15 @@
     "//skia:skia",
     "//ui/gfx:color_utils",
   ]
+
+  if (is_mac) {
+    frameworks = [ "AppKit.framework" ]
+    sources += [
+      "mac/native_color_transform.mm",
+      "mac/system_color_utils.h",
+      "mac/system_color_utils.mm",
+    ]
+  }
 }
 
 test("color_unittests") {
diff --git a/ui/color/color_mixers.h b/ui/color/color_mixers.h
index 4d309e26..48ae995 100644
--- a/ui/color/color_mixers.h
+++ b/ui/color/color_mixers.h
@@ -6,6 +6,7 @@
 #define UI_COLOR_COLOR_MIXERS_H_
 
 #include "base/component_export.h"
+#include "build/build_config.h"
 
 namespace ui {
 
@@ -42,6 +43,11 @@
                            bool dark_window,
                            bool high_contrast);
 
+#if defined(OS_MAC)
+COMPONENT_EXPORT(COLOR)
+void AddSystemTintMixer(ColorProvider* provider);
+#endif
+
 }  // namespace ui
 
 #endif  // UI_COLOR_COLOR_MIXERS_H_
diff --git a/ui/color/color_transform.h b/ui/color/color_transform.h
index efa45e3..5d954842 100644
--- a/ui/color/color_transform.h
+++ b/ui/color/color_transform.h
@@ -8,6 +8,7 @@
 #include "base/callback.h"
 #include "base/component_export.h"
 #include "base/optional.h"
+#include "build/build_config.h"
 #include "third_party/skia/include/core/SkColor.h"
 #include "ui/color/color_id.h"
 #include "ui/gfx/color_utils.h"
@@ -116,6 +117,11 @@
 COMPONENT_EXPORT(COLOR)
 ColorTransform SetAlpha(ColorTransform transform, SkAlpha alpha);
 
+#if defined(OS_MAC)
+COMPONENT_EXPORT(COLOR)
+ColorTransform ApplySystemControlTintIfNeeded();
+#endif
+
 }  // namespace ui
 
 #endif  // UI_COLOR_COLOR_TRANSFORM_H_
diff --git a/ui/color/mac/native_color_mixers.mm b/ui/color/mac/native_color_mixers.mm
index 6b5e151..53cd58c 100644
--- a/ui/color/mac/native_color_mixers.mm
+++ b/ui/color/mac/native_color_mixers.mm
@@ -5,7 +5,10 @@
 #include "ui/color/color_mixers.h"
 
 #import <Cocoa/Cocoa.h>
+
+#include "base/containers/fixed_flat_set.h"
 #import "skia/ext/skia_utils_mac.h"
+#include "ui/color/color_id.h"
 #include "ui/color/color_mixer.h"
 #include "ui/color/color_provider.h"
 #include "ui/color/color_recipe.h"
@@ -13,6 +16,22 @@
 #include "ui/color/mac/scoped_current_nsappearance.h"
 #include "ui/gfx/color_palette.h"
 
+namespace {
+// All the native OS colors which are retrieved from the system directly.
+// clang-format off
+constexpr auto kNativeOSColorIds = base::MakeFixedFlatSet<ui::ColorId>({
+    ui::kColorFocusableBorderFocused,
+    ui::kColorLabelSelectionBackground,
+    ui::kColorMenuBorder,
+    ui::kColorMenuItemForegroundDisabled,
+    ui::kColorMenuItemForeground,
+    ui::kColorMenuSeparator,
+    ui::kColorTextSelectionBackground,
+    ui::kColorTextfieldSelectionBackground,
+    ui::kColorTableBackgroundAlternate});
+// clang-format on
+}
+
 namespace ui {
 
 void AddNativeCoreColorMixer(ColorProvider* provider,
@@ -67,4 +86,14 @@
   mixer[kColorMenuSeparator] = {menu_separator_color};
 }
 
+void AddSystemTintMixer(ColorProvider* provider) {
+  ColorMixer& mixer = provider->AddMixer();
+
+  for (ui::ColorId id = ui::kUiColorsStart; id < kUiColorsLast; ++id) {
+    // Apply system tint to non-OS colors.
+    if (!kNativeOSColorIds.contains(id))
+      mixer[id] += ApplySystemControlTintIfNeeded();
+  }
+}
+
 }  // namespace ui
diff --git a/ui/color/mac/native_color_transform.mm b/ui/color/mac/native_color_transform.mm
new file mode 100644
index 0000000..af1c77044
--- /dev/null
+++ b/ui/color/mac/native_color_transform.mm
@@ -0,0 +1,25 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/color/color_transform.h"
+
+#import <Cocoa/Cocoa.h>
+
+#include "third_party/skia/include/core/SkColor.h"
+#include "ui/color/color_id.h"
+#include "ui/color/color_mixer.h"
+#include "ui/color/mac/system_color_utils.h"
+#include "ui/gfx/color_utils.h"
+
+namespace ui {
+
+ColorTransform ApplySystemControlTintIfNeeded() {
+  return base::BindRepeating(
+      [](SkColor input_color, const ui::ColorMixer& mixer) -> SkColor {
+        return IsSystemGraphiteTinted() ? ColorToGrayscale(input_color)
+                                        : input_color;
+      });
+}
+
+}  // namespace ui
diff --git a/ui/color/mac/system_color_utils.h b/ui/color/mac/system_color_utils.h
new file mode 100644
index 0000000..37058288
--- /dev/null
+++ b/ui/color/mac/system_color_utils.h
@@ -0,0 +1,30 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_COLOR_MAC_SYSTEM_COLOR_UTILS_H_
+#define UI_COLOR_MAC_SYSTEM_COLOR_UTILS_H_
+
+#include "base/component_export.h"
+#include "third_party/skia/include/core/SkColor.h"
+
+namespace ui {
+
+COMPONENT_EXPORT(COLOR) bool IsSystemGraphiteTinted();
+
+COMPONENT_EXPORT(COLOR) SkColor ColorToGrayscale(SkColor color);
+
+class COMPONENT_EXPORT(COLOR) ScopedEnableGraphiteTint {
+ public:
+  ScopedEnableGraphiteTint();
+  ScopedEnableGraphiteTint(const ScopedEnableGraphiteTint&) = delete;
+  ScopedEnableGraphiteTint& operator=(const ScopedEnableGraphiteTint&) = delete;
+  ~ScopedEnableGraphiteTint();
+
+ private:
+  bool original_test_override_ = false;
+};
+
+}  // namespace ui
+
+#endif  // UI_COLOR_MAC_SYSTEM_COLOR_UTILS_H_
diff --git a/ui/color/mac/system_color_utils.mm b/ui/color/mac/system_color_utils.mm
new file mode 100644
index 0000000..4862fd45
--- /dev/null
+++ b/ui/color/mac/system_color_utils.mm
@@ -0,0 +1,40 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/color/mac/system_color_utils.h"
+
+#import <Cocoa/Cocoa.h>
+
+#include "third_party/skia/include/core/SkScalar.h"
+
+namespace {
+bool graphite_tint_test_override = false;
+}
+
+namespace ui {
+
+bool IsSystemGraphiteTinted() {
+  if (graphite_tint_test_override)
+    return true;
+
+  return [NSColor currentControlTint] == NSGraphiteControlTint;
+}
+
+SkColor ColorToGrayscale(SkColor color) {
+  SkScalar luminance = SkColorGetR(color) * 0.21 + SkColorGetG(color) * 0.72 +
+                       SkColorGetB(color) * 0.07;
+  uint8_t component = SkScalarRoundToInt(luminance);
+  return SkColorSetARGB(SkColorGetA(color), component, component, component);
+}
+
+ScopedEnableGraphiteTint::ScopedEnableGraphiteTint() {
+  original_test_override_ = graphite_tint_test_override;
+  graphite_tint_test_override = true;
+}
+
+ScopedEnableGraphiteTint::~ScopedEnableGraphiteTint() {
+  graphite_tint_test_override = original_test_override_;
+}
+
+}  // ui
diff --git a/ui/gfx/geometry/scroll_offset.h b/ui/gfx/geometry/scroll_offset.h
index 96e8d960..a0e7e8e 100644
--- a/ui/gfx/geometry/scroll_offset.h
+++ b/ui/gfx/geometry/scroll_offset.h
@@ -20,8 +20,8 @@
 
 class GEOMETRY_EXPORT ScrollOffset {
  public:
-  ScrollOffset() : x_(0), y_(0) {}
-  ScrollOffset(float x, float y) : x_(x), y_(y) {}
+  constexpr ScrollOffset() : x_(0), y_(0) {}
+  constexpr ScrollOffset(float x, float y) : x_(x), y_(y) {}
   explicit ScrollOffset(const Vector2dF& v) : x_(v.x()), y_(v.y()) {}
   explicit ScrollOffset(const Vector2d& v) : x_(v.x()), y_(v.y()) {}
 
diff --git a/ui/native_theme/BUILD.gn b/ui/native_theme/BUILD.gn
index 1f2ec80..ee16648 100644
--- a/ui/native_theme/BUILD.gn
+++ b/ui/native_theme/BUILD.gn
@@ -35,6 +35,11 @@
   }
 
   if (is_mac) {
+    frameworks = [
+      "CoreGraphics.framework",
+      "AppKit.framework",
+      "MediaAccessibility.framework",
+    ]
     sources += [
       "caption_style_mac.mm",
       "native_theme_mac.h",
@@ -73,14 +78,6 @@
     "//ui/gfx/geometry",
     "//ui/resources",
   ]
-
-  if (is_mac) {
-    frameworks = [
-      "CoreGraphics.framework",
-      "AppKit.framework",
-      "MediaAccessibility.framework",
-    ]
-  }
 }
 
 if (is_win) {
@@ -135,10 +132,6 @@
     sources += [ "native_theme_aura_unittest.cc" ]
   }
 
-  if (is_mac) {
-    sources += [ "native_theme_mac_unittest.mm" ]
-  }
-
   if (is_win) {
     sources += [
       "caption_style_win_unittest.cc",
@@ -156,4 +149,9 @@
     "//ui/base",
     "//ui/gfx/geometry:geometry",
   ]
+
+  if (is_mac) {
+    sources += [ "native_theme_mac_unittest.mm" ]
+    deps += [ "//ui/color" ]
+  }
 }
diff --git a/ui/native_theme/native_theme.cc b/ui/native_theme/native_theme.cc
index 1b925b09..a72f176a 100644
--- a/ui/native_theme/native_theme.cc
+++ b/ui/native_theme/native_theme.cc
@@ -245,6 +245,11 @@
           ui::AddNativeCoreColorMixer(provider, dark_mode, high_contrast);
           ui::AddUiColorMixer(provider);
           ui::AddNativeUiColorMixer(provider, dark_mode, high_contrast);
+#if defined(OS_MAC)
+          // Always keep this mixer at the last so the system tint will be
+          // applied after getting the proper color.
+          ui::AddSystemTintMixer(provider);
+#endif
         }));
   });
   if (!color_provider_manager_init.is_null())
diff --git a/ui/native_theme/native_theme_mac.mm b/ui/native_theme/native_theme_mac.mm
index f7c133d..782268e 100644
--- a/ui/native_theme/native_theme_mac.mm
+++ b/ui/native_theme/native_theme_mac.mm
@@ -16,6 +16,7 @@
 #include "ui/base/ui_base_features.h"
 #include "ui/base/ui_base_switches.h"
 #include "ui/color/mac/scoped_current_nsappearance.h"
+#include "ui/color/mac/system_color_utils.h"
 #include "ui/gfx/canvas.h"
 #include "ui/gfx/color_palette.h"
 #include "ui/gfx/color_utils.h"
@@ -101,17 +102,6 @@
   VALUE array[static_cast<size_t>(KEY::COUNT)];
 };
 
-// Converts an SkColor to grayscale by using luminance for all three components.
-// Experimentally, this seems to produce a better result than a flat average or
-// a min/max average for UI controls.
-SkColor ColorToGrayscale(SkColor color) {
-  SkScalar luminance = SkColorGetR(color) * 0.21 +
-                       SkColorGetG(color) * 0.72 +
-                       SkColorGetB(color) * 0.07;
-  uint8_t component = SkScalarRoundToInt(luminance);
-  return SkColorSetARGB(SkColorGetA(color), component, component, component);
-}
-
 }  // namespace
 
 namespace ui {
@@ -149,9 +139,7 @@
 
 // static
 SkColor NativeThemeMac::ApplySystemControlTint(SkColor color) {
-  if ([NSColor currentControlTint] == NSGraphiteControlTint)
-    return ColorToGrayscale(color);
-  return color;
+  return ui::IsSystemGraphiteTinted() ? ui::ColorToGrayscale(color) : color;
 }
 
 SkColor NativeThemeMac::GetSystemColorImpl(ColorId color_id,
diff --git a/ui/native_theme/native_theme_unittest.cc b/ui/native_theme/native_theme_unittest.cc
index 2a32fb4..b96b655 100644
--- a/ui/native_theme/native_theme_unittest.cc
+++ b/ui/native_theme/native_theme_unittest.cc
@@ -9,12 +9,16 @@
 
 #include "base/strings/stringprintf.h"
 #include "base/test/scoped_feature_list.h"
+#include "build/build_config.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "ui/base/ui_base_features.h"
 #include "ui/native_theme/native_theme_color_id.h"
 
-namespace ui {
+#if defined(OS_MAC)
+#include "ui/color/mac/system_color_utils.h"
+#endif
 
+namespace ui {
 namespace {
 
 constexpr const char* kColorIdStringName[] = {
@@ -81,15 +85,10 @@
   }
 };
 
-}  // namespace
-
-TEST_P(NativeThemeRedirectedEquivalenceTest, NativeUiGetSystemColor) {
-  // Verifies that colors with and without the Color Provider are the same.
+std::pair<PrintableSkColor, PrintableSkColor> GetOriginalAndRedirected(
+    NativeTheme::ColorId color_id,
+    NativeTheme::ColorScheme color_scheme) {
   NativeTheme* native_theme = NativeTheme::GetInstanceForNativeUi();
-  auto param_tuple = GetParam();
-  auto color_scheme = std::get<0>(param_tuple);
-  auto color_id = std::get<1>(param_tuple);
-
   PrintableSkColor original{
       native_theme->GetSystemColor(color_id, color_scheme)};
 
@@ -98,9 +97,38 @@
   PrintableSkColor redirected{
       native_theme->GetSystemColor(color_id, color_scheme)};
 
+  return std::make_pair(original, redirected);
+}
+
+}  // namespace
+
+TEST_P(NativeThemeRedirectedEquivalenceTest, NativeUiGetSystemColor) {
+  auto param_tuple = GetParam();
+  auto color_scheme = std::get<NativeTheme::ColorScheme>(param_tuple);
+  auto color_id = std::get<NativeTheme::ColorId>(param_tuple);
+
+  // Verifies that colors with and without the Color Provider are the same.
+  auto pair = GetOriginalAndRedirected(color_id, color_scheme);
+  auto original = pair.first;
+  auto redirected = pair.second;
   EXPECT_EQ(original, redirected);
 }
 
+#if defined(OS_MAC)
+TEST_P(NativeThemeRedirectedEquivalenceTest, NativeUiGetSystemColorWithTint) {
+  auto param_tuple = GetParam();
+  auto color_scheme = std::get<NativeTheme::ColorScheme>(param_tuple);
+  auto color_id = std::get<NativeTheme::ColorId>(param_tuple);
+
+  ScopedEnableGraphiteTint enable_graphite_tint;
+  // Verifies that colors with and without the Color Provider are the same.
+  auto pair = GetOriginalAndRedirected(color_id, color_scheme);
+  auto original = pair.first;
+  auto redirected = pair.second;
+  EXPECT_EQ(original, redirected);
+}
+#endif
+
 #define OP(enum_name) NativeTheme::ColorId::enum_name
 INSTANTIATE_TEST_SUITE_P(
     ,
diff --git a/ui/ozone/platform/wayland/host/wayland_popup.cc b/ui/ozone/platform/wayland/host/wayland_popup.cc
index 736b2388..73ac973 100644
--- a/ui/ozone/platform/wayland/host/wayland_popup.cc
+++ b/ui/ozone/platform/wayland/host/wayland_popup.cc
@@ -56,6 +56,12 @@
   if (shell_popup_)
     return;
 
+  // Map parent window as WaylandPopup cannot become a visible child of a
+  // window that is not mapped.
+  DCHECK(parent_window());
+  if (!parent_window()->IsVisible())
+    parent_window()->Show(false);
+
   if (!CreateShellPopup()) {
     Close();
     return;
diff --git a/ui/views/controls/table/table_view.cc b/ui/views/controls/table/table_view.cc
index b9bac9d..7f1a45b 100644
--- a/ui/views/controls/table/table_view.cc
+++ b/ui/views/controls/table/table_view.cc
@@ -727,13 +727,18 @@
   DCHECK_GE(length, 0);
   DCHECK_LE(start + length, GetRowCount());
 
-  for (int i = 0; i < length; ++i)
+  for (int i = 0; i < length; ++i) {
+    // Increment selection model counter at start.
     selection_model_.IncrementFrom(start);
 
-  // Create the accessibility view for the new row and insert it in the
-  // virtual accessibility tree.
-  for (int i = start; i < start + length; i++)
-    GetViewAccessibility().AddVirtualChildView(CreateRowAccessibilityView(i));
+    // Append new virtual row to accessibility view.
+    const int virtual_children_count =
+        GetViewAccessibility().virtual_children().size();
+    const int next_index =
+        header_ ? virtual_children_count - 1 : virtual_children_count;
+    GetViewAccessibility().AddVirtualChildView(
+        CreateRowAccessibilityView(next_index));
+  }
 
   SortItemsAndUpdateMapping(/*schedule_paint=*/true);
   PreferredSizeChanged();
diff --git a/ui/views/controls/table/table_view_unittest.cc b/ui/views/controls/table/table_view_unittest.cc
index ff2060e..c02265cb 100644
--- a/ui/views/controls/table/table_view_unittest.cc
+++ b/ui/views/controls/table/table_view_unittest.cc
@@ -501,12 +501,7 @@
   }
 
   void VerifyTableViewAndAXOrder(std::string expected_view_order) {
-    auto& virtual_children = table_->GetViewAccessibility().virtual_children();
-
-    // Makes sure the virtual children count takes into account of the header
-    // row.
-    int virtual_row_count = table_->GetRowCount() + (helper_->header() ? 1 : 0);
-    EXPECT_EQ(virtual_row_count, int{virtual_children.size()});
+    VerifyAXRowIndexes();
 
     // The table views should match the expected view order.
     EXPECT_EQ(expected_view_order, GetRowsInViewOrderAsString(table_));
@@ -520,6 +515,33 @@
     EXPECT_EQ(expected_view_order, GetRowsInVirtualViewAsString(table_));
   }
 
+  // Verifies that there is an unique, properly-indexed virtual row for every
+  // row.
+  void VerifyAXRowIndexes() {
+    auto& virtual_children = table_->GetViewAccessibility().virtual_children();
+
+    // Makes sure the virtual row count factors in the presence of the header.
+    const int first_row_index = helper_->header() ? 1 : 0;
+    const int virtual_row_count = table_->GetRowCount() + first_row_index;
+    EXPECT_EQ(virtual_row_count, int{virtual_children.size()});
+
+    // Make sure every virtual row is valid.
+    for (int index = first_row_index; index < virtual_row_count; index++) {
+      const auto& row = virtual_children[index];
+      ASSERT_TRUE(row);
+
+      // Normalize the row index to account for the presence of a header if
+      // necessary.
+      const int normalized_index = index - first_row_index;
+
+      // Make sure the stored row index matches the row index in the table.
+      const ui::AXNodeData& row_data = row->GetCustomData();
+      const int stored_index =
+          row_data.GetIntAttribute(ax::mojom::IntAttribute::kTableRowIndex);
+      EXPECT_EQ(stored_index, normalized_index);
+    }
+  }
+
   // Helper function for comparing the bounds of |table_|'s virtual
   // accessibility child rows and cells with a set of expected bounds.
   void VerifyTableAccChildrenBounds(
diff --git a/weblayer/app/content_main_delegate_impl.cc b/weblayer/app/content_main_delegate_impl.cc
index 16aa4d3..958e0b01 100644
--- a/weblayer/app/content_main_delegate_impl.cc
+++ b/weblayer/app/content_main_delegate_impl.cc
@@ -189,8 +189,6 @@
         autofill::features::kAutofillExtractAllDatalists);
     enabled_features.push_back(
         autofill::features::kAutofillSkipComparingInferredLabels);
-    disabled_features.push_back(
-        autofill::features::kAutofillRestrictUnownedFieldsToFormlessCheckout);
   }
 #endif