diff --git a/AUTHORS b/AUTHORS
index 427ccec..9332e18 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -231,6 +231,7 @@
 Daniel Waxweiler <daniel.waxweiler@gmail.com>
 Dániel Bátyai <dbatyai@inf.u-szeged.hu>
 Dániel Vince <vinced@inf.u-szeged.hu>
+Daoming Qiu <daoming.qiu@intel.com>
 Darshini KN <kn.darshini@samsung.com>
 Dave Vandyke <kzar@kzar.co.uk>
 David Benjamin <davidben@mit.edu>
diff --git a/DEPS b/DEPS
index 07d89511..f1d1631 100644
--- a/DEPS
+++ b/DEPS
@@ -200,11 +200,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': 'a0f5452c6e2373678f2caac934bd311dacff0836',
+  'skia_revision': 'e07f2b21917d886c5ed6ab1a95d0c1eb28636d0d',
   # 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': '28cb2dd6633ecb818598c6babfb5f82fcfe7843c',
+  'v8_revision': '23b0ebb5ce894d691bce6f969da676930254cff9',
   # 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.
@@ -212,7 +212,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': 'a2ef814426ee780c50e89f40c22daca0486ca9dd',
+  'angle_revision': '481fb88fee3376caef75a784fbfca0b8501a686a',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling SwiftShader
   # and whatever else without interference from each other.
@@ -220,7 +220,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling PDFium
   # and whatever else without interference from each other.
-  'pdfium_revision': 'a58a676ab96a459703d02f9f3ea8e06b13ce484d',
+  'pdfium_revision': '055495dfbb246495879fef8540f4447fb9ccb6cb',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling BoringSSL
   # and whatever else without interference from each other.
@@ -263,7 +263,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling catapult
   # and whatever else without interference from each other.
-  'catapult_revision': 'b7c1c3f1140ba42e6367f25c6f3950678be55c56',
+  'catapult_revision': 'dfccae249ee2a6cc6a26219916d22397ec939628',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling libFuzzer
   # and whatever else without interference from each other.
@@ -271,7 +271,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': '9a5e8ce8b8733d889ef5a8c6b4483492b804e915',
+  'devtools_frontend_revision': '179979c8b3825e2342cb5f15738ee70ada5eb6b8',
   # 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': '73b70229af3a98baea034bc5a521878e86b0447e',
+  'dawn_revision': '6298d2b70cb67bb929f7817f2186f618ec8f1ca1',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling feed
   # and whatever else without interference from each other.
@@ -351,7 +351,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling nearby
   # and whatever else without interference from each other.
-  'nearby_revision': 'e9dd5d32f0f7a81b50ba8a5f327edf2ac738f956',
+  'nearby_revision': '3498e8fedac41185885d831904d8b7323b498e54',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling securemessage
   # and whatever else without interference from each other.
@@ -906,7 +906,7 @@
   },
 
   'src/third_party/depot_tools':
-    Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + '6e970e597b25a3a74a560746711d1811133841d2',
+    Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + '8e567c5cf50785dc808ab558d5e8f52c649fb53b',
 
   'src/third_party/devtools-frontend/src':
     Var('chromium_git') + '/devtools/devtools-frontend' + '@' + Var('devtools_frontend_revision'),
@@ -1491,7 +1491,7 @@
   },
 
   'src/third_party/webrtc':
-    Var('webrtc_git') + '/src.git' + '@' + '0c83e15c6b614d44f7bd545d518d02c681dedd65',
+    Var('webrtc_git') + '/src.git' + '@' + '239f92ecf7fc8ca27e0376dd192b33ce33377b3c',
 
   'src/third_party/libgifcodec':
      Var('skia_git') + '/libgifcodec' + '@'+  Var('libgifcodec_revision'),
@@ -1563,7 +1563,7 @@
     Var('chromium_git') + '/v8/v8.git' + '@' +  Var('v8_revision'),
 
   'src-internal': {
-    'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@df97f4c2861e3577c51ad1531aba6cb5e10e969e',
+    'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@0963e7ee54a874d281499ca3fda422d4b65fa377',
     'condition': 'checkout_src_internal',
   },
 
diff --git a/android_webview/BUILD.gn b/android_webview/BUILD.gn
index 0357f58..d9760be 100644
--- a/android_webview/BUILD.gn
+++ b/android_webview/BUILD.gn
@@ -657,6 +657,7 @@
     "//components/viz:viz_java",
     "//gpu/config:config_java",
     "//third_party/android_deps:androidx_annotation_annotation_java",
+    "//third_party/blink/public/common:common_java",
   ]
   srcjar_deps = [
     ":common_java_features_srcjar",
diff --git a/android_webview/java/src/org/chromium/android_webview/common/ProductionSupportedFlagList.java b/android_webview/java/src/org/chromium/android_webview/common/ProductionSupportedFlagList.java
index ee3e072d..5d9da63 100644
--- a/android_webview/java/src/org/chromium/android_webview/common/ProductionSupportedFlagList.java
+++ b/android_webview/java/src/org/chromium/android_webview/common/ProductionSupportedFlagList.java
@@ -5,6 +5,7 @@
 package org.chromium.android_webview.common;
 
 import org.chromium.base.BaseSwitches;
+import org.chromium.blink_public.common.BlinkFeatures;
 import org.chromium.cc.base.CcSwitches;
 import org.chromium.components.metrics.MetricsSwitches;
 import org.chromium.components.viz.common.VizFeatures;
@@ -74,8 +75,8 @@
                             + "security checks."),
             Flag.baseFeature(AwFeatures.WEBVIEW_BROTLI_SUPPORT,
                     "Enables brotli compression support in WebView."),
-            Flag.baseFeature(
-                    "AppCache", "Controls AppCache to facilitate testing against future removal."),
+            Flag.baseFeature(BlinkFeatures.APP_CACHE,
+                    "Controls AppCache to facilitate testing against future removal."),
             Flag.baseFeature(AwFeatures.WEBVIEW_EXTRA_HEADERS_SAME_ORIGIN_ONLY,
                     "Only allow extra headers added via loadUrl() to be sent to the same origin "
                             + "as the original request."),
@@ -88,7 +89,7 @@
                             + "of the total screen size. Depending on the number of WebVieaws and "
                             + "the size of the screen this might be expensive so hidden behind a "
                             + "feature flag until the true runtime cost can be measured."),
-            Flag.baseFeature("WebComponentsV0",
+            Flag.baseFeature(BlinkFeatures.WEB_COMPONENTS_V0,
                     "Re-enables the deprecated Web Components v0 features (Shadow DOM v0, Custom "
                             + "Elements v0, and HTML Imports)."),
             Flag.baseFeature(AwFeatures.WEBVIEW_DISPLAY_CUTOUT,
diff --git a/android_webview/nonembedded/java/res_devui/layout/fragment_flags.xml b/android_webview/nonembedded/java/res_devui/layout/fragment_flags.xml
index 81fc6dc6..360409f 100644
--- a/android_webview/nonembedded/java/res_devui/layout/fragment_flags.xml
+++ b/android_webview/nonembedded/java/res_devui/layout/fragment_flags.xml
@@ -33,7 +33,7 @@
             android:singleLine="true"
             android:drawablePadding="4dp"
             android:drawableStart="@drawable/ic_devui_search"
-            android:imeOptions="actionDone|actionSearch"
+            android:imeOptions="actionDone"
             android:drawableTint="?android:textColorPrimary"
             android:textAppearance="?android:attr/textAppearanceMedium"/>
 
diff --git a/ash/clipboard/clipboard_nudge.cc b/ash/clipboard/clipboard_nudge.cc
index 6a5aab1..41c23eb 100644
--- a/ash/clipboard/clipboard_nudge.cc
+++ b/ash/clipboard/clipboard_nudge.cc
@@ -8,14 +8,11 @@
 #include "ash/public/cpp/shelf_config.h"
 #include "ash/public/cpp/shell_window_ids.h"
 #include "ash/resources/vector_icons/vector_icons.h"
-#include "ash/root_window_controller.h"
-#include "ash/shelf/hotseat_widget.h"
 #include "ash/shell.h"
 #include "ash/strings/grit/ash_strings.h"
 #include "ash/style/ash_color_provider.h"
 #include "ui/base/l10n/l10n_util.h"
 #include "ui/chromeos/events/keyboard_layout_util.h"
-#include "ui/compositor/scoped_layer_animation_settings.h"
 #include "ui/gfx/color_palette.h"
 #include "ui/gfx/paint_vector_icon.h"
 #include "ui/views/border.h"
@@ -52,9 +49,6 @@
 // The padding which separates the nudge's border with its inner contents.
 constexpr int kNudgePadding = 16;
 
-constexpr base::TimeDelta kNudgeBoundsAnimationTime =
-    base::TimeDelta::FromMilliseconds(250);
-
 bool IsAssistantAvailable() {
   AssistantStateBase* state = AssistantState::Get();
   return state->allowed_state() ==
@@ -149,11 +143,7 @@
   views::ImageView* clipboard_icon_ = nullptr;
 };
 
-ClipboardNudge::ClipboardNudge()
-    : widget_(std::make_unique<views::Widget>()),
-      root_window_(Shell::GetRootWindowForNewWindows()) {
-  shelf_observer_.Add(RootWindowController::ForWindow(root_window_)->shelf());
-
+ClipboardNudge::ClipboardNudge() : widget_(std::make_unique<views::Widget>()) {
   views::Widget::InitParams params(
       views::Widget::InitParams::TYPE_WINDOW_FRAMELESS);
   params.z_order = ui::ZOrderLevel::kFloatingWindow;
@@ -161,8 +151,8 @@
   params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
   params.name = "ClipboardContextualNudge";
   params.layer_type = ui::LAYER_NOT_DRAWN;
-  params.parent =
-      root_window_->GetChildById(kShellWindowId_SettingBubbleContainer);
+  params.parent = Shell::GetPrimaryRootWindow()->GetChildById(
+      kShellWindowId_OverlayContainer);
   widget_->Init(std::move(params));
 
   nudge_view_ =
@@ -173,18 +163,14 @@
 
 ClipboardNudge::~ClipboardNudge() = default;
 
-void ClipboardNudge::OnHotseatStateChanged(HotseatState old_state,
-                                           HotseatState new_state) {
-  CalculateAndSetWidgetBounds();
-}
-
 void ClipboardNudge::Close() {
   widget_->CloseWithReason(views::Widget::ClosedReason::kUnspecified);
 }
 
 void ClipboardNudge::CalculateAndSetWidgetBounds() {
-  gfx::Rect display_bounds = root_window_->bounds();
-  ::wm::ConvertRectToScreen(root_window_, &display_bounds);
+  aura::Window* root_window = Shell::GetRootWindowForNewWindows();
+  gfx::Rect display_bounds = root_window->bounds();
+  ::wm::ConvertRectToScreen(root_window, &display_bounds);
   gfx::Rect widget_bounds;
 
   // Calculate the nudge's size to ensure the label text accurately fits.
@@ -202,26 +188,6 @@
   if (base::i18n::IsRTL())
     widget_bounds.set_x(display_bounds.right() - nudge_width - kNudgeMargin);
 
-  // Set the nudge's bounds above the hotseat when it is extended.
-  HotseatWidget* hotseat_widget =
-      RootWindowController::ForWindow(root_window_)->shelf()->hotseat_widget();
-  if (hotseat_widget->state() == HotseatState::kExtended) {
-    widget_bounds.set_y(hotseat_widget->GetTargetBounds().y() - nudge_height -
-                        kNudgeMargin);
-  }
-
-  // Only run the widget bounds animation if the widget's bounds have already
-  // been initialized.
-  std::unique_ptr<ui::ScopedLayerAnimationSettings> settings;
-  if (widget_->GetWindowBoundsInScreen().size() != gfx::Size()) {
-    settings = std::make_unique<ui::ScopedLayerAnimationSettings>(
-        widget_->GetLayer()->GetAnimator());
-    settings->SetPreemptionStrategy(
-        ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET);
-    settings->SetTransitionDuration(kNudgeBoundsAnimationTime);
-    settings->SetTweenType(gfx::Tween::EASE_OUT);
-  }
-
   widget_->SetBounds(widget_bounds);
 }
 
diff --git a/ash/clipboard/clipboard_nudge.h b/ash/clipboard/clipboard_nudge.h
index e5010eb..2724461 100644
--- a/ash/clipboard/clipboard_nudge.h
+++ b/ash/clipboard/clipboard_nudge.h
@@ -6,24 +6,18 @@
 #define ASH_CLIPBOARD_CLIPBOARD_NUDGE_H_
 
 #include "ash/ash_export.h"
-#include "ash/shelf/shelf.h"
-#include "ash/shelf/shelf_observer.h"
-#include "base/scoped_observer.h"
 #include "ui/views/widget/widget.h"
 
 namespace ash {
 
 // Implements a contextual nudge for multipaste.
-class ASH_EXPORT ClipboardNudge : public ShelfObserver {
+class ASH_EXPORT ClipboardNudge {
  public:
   ClipboardNudge();
   ClipboardNudge(const ClipboardNudge&) = delete;
   ClipboardNudge& operator=(const ClipboardNudge&) = delete;
-  ~ClipboardNudge() override;
+  ~ClipboardNudge();
 
-  // ShelfObserver overrides:
-  void OnHotseatStateChanged(HotseatState old_state,
-                             HotseatState new_state) override;
   void Close();
 
  private:
@@ -36,10 +30,6 @@
   std::unique_ptr<views::Widget> widget_;
 
   ClipboardNudgeView* nudge_view_ = nullptr;  // not_owned
-
-  aura::Window* const root_window_;
-
-  ScopedObserver<Shelf, ShelfObserver> shelf_observer_{this};
 };
 
 }  // namespace ash
diff --git a/ash/wallpaper/wallpaper_controller_impl.cc b/ash/wallpaper/wallpaper_controller_impl.cc
index 70c9f69..be7a2527 100644
--- a/ash/wallpaper/wallpaper_controller_impl.cc
+++ b/ash/wallpaper/wallpaper_controller_impl.cc
@@ -1343,9 +1343,12 @@
   if (!active_user_session)
     return false;
 
+  // Since everything gets wiped at the end of the Public Session (and Managed
+  // Guest Session), users are disallowed to set wallpaper (and other
+  // personalization settings) to avoid unnecessary confusion and surprise when
+  // everything resets.
   user_manager::UserType active_user_type = active_user_session->user_info.type;
   return active_user_type == user_manager::USER_TYPE_REGULAR ||
-         active_user_type == user_manager::USER_TYPE_PUBLIC_ACCOUNT ||
          active_user_type == user_manager::USER_TYPE_SUPERVISED ||
          active_user_type == user_manager::USER_TYPE_CHILD;
 }
diff --git a/ash/wallpaper/wallpaper_controller_unittest.cc b/ash/wallpaper/wallpaper_controller_unittest.cc
index 4f37bf5df..6c2c8dca 100644
--- a/ash/wallpaper/wallpaper_controller_unittest.cc
+++ b/ash/wallpaper/wallpaper_controller_unittest.cc
@@ -1468,6 +1468,12 @@
       controller_->GetUserWallpaperInfo(account_id_1, &wallpaper_info));
 }
 
+// Disable the wallpaper setting for public session since it is ephemeral.
+TEST_F(WallpaperControllerTest, NotShowWallpaperSettingInPublicSession) {
+  SimulateUserLogin("public_session", user_manager::USER_TYPE_PUBLIC_ACCOUNT);
+  EXPECT_FALSE(controller_->ShouldShowWallpaperSetting());
+}
+
 TEST_F(WallpaperControllerTest, IgnoreWallpaperRequestWhenPolicyIsEnforced) {
   SetBypassDecode();
   gfx::ImageSkia image = CreateImage(640, 480, kWallpaperColor);
diff --git a/base/allocator/partition_allocator/partition_bucket.cc b/base/allocator/partition_allocator/partition_bucket.cc
index c5826bf..c749f47 100644
--- a/base/allocator/partition_allocator/partition_bucket.cc
+++ b/base/allocator/partition_allocator/partition_bucket.cc
@@ -258,7 +258,7 @@
     return ret;
   }
 
-  // Need a new super page. We want to allocate super pages in a continguous
+  // Need a new super page. We want to allocate super pages in a contiguous
   // address region as much as possible. This is important for not causing
   // page table bloat and not fragmenting address spaces in 32 bit
   // architectures.
@@ -296,6 +296,8 @@
   char* ret = quarantine_bitmaps + quarantine_bitmaps_size;
   root->next_partition_page = ret + total_size;
   root->next_partition_page_end = root->next_super_page - PartitionPageSize();
+  PA_DCHECK(ret == SuperPagePayloadBegin(super_page, root->pcscan.has_value()));
+  PA_DCHECK(root->next_partition_page_end == SuperPagePayloadEnd(super_page));
 
   // The first slot span is accessible. The given committed_size is equal to
   // the system-page-aligned size of the slot span.
@@ -398,14 +400,6 @@
 }
 
 template <bool thread_safe>
-ALWAYS_INLINE uint16_t PartitionBucket<thread_safe>::get_pages_per_slot_span() {
-  // Rounds up to nearest multiple of NumSystemPagesPerPartitionPage().
-  return (num_system_pages_per_slot_span +
-          (NumSystemPagesPerPartitionPage() - 1)) /
-         NumSystemPagesPerPartitionPage();
-}
-
-template <bool thread_safe>
 ALWAYS_INLINE void PartitionBucket<thread_safe>::InitializeSlotSpan(
     SlotSpanMetadata<thread_safe>* slot_span) {
   // The bucket never changes. We set it up once.
diff --git a/base/allocator/partition_allocator/partition_bucket.h b/base/allocator/partition_allocator/partition_bucket.h
index 1643717e2..8e340f7 100644
--- a/base/allocator/partition_allocator/partition_bucket.h
+++ b/base/allocator/partition_allocator/partition_bucket.h
@@ -77,6 +77,15 @@
     // https://crbug.com/680657
     return static_cast<uint16_t>(get_bytes_per_span() / slot_size);
   }
+  // Returns a natural number of partition pages (calculated by
+  // get_system_pages_per_slot_span()) to allocate from the current
+  // super page when the bucket runs out of slots.
+  ALWAYS_INLINE uint16_t get_pages_per_slot_span() const {
+    // Rounds up to nearest multiple of NumSystemPagesPerPartitionPage().
+    return (num_system_pages_per_slot_span +
+            (NumSystemPagesPerPartitionPage() - 1)) /
+           NumSystemPagesPerPartitionPage();
+  }
 
   static ALWAYS_INLINE size_t get_direct_map_size(size_t size) {
     // Caller must check that the size is not above the MaxDirectMapped()
@@ -122,11 +131,6 @@
  private:
   static NOINLINE void OnFull();
 
-  // Returns a natural number of partition pages (calculated by
-  // get_system_pages_per_slot_span()) to allocate from the current
-  // super page when the bucket runs out of slots.
-  ALWAYS_INLINE uint16_t get_pages_per_slot_span();
-
   // Returns the number of system pages in a slot span.
   //
   // The calculation attempts to find the best number of system pages to
diff --git a/base/allocator/partition_allocator/partition_page.cc b/base/allocator/partition_allocator/partition_page.cc
index f97129a9..e6eb3ef 100644
--- a/base/allocator/partition_allocator/partition_page.cc
+++ b/base/allocator/partition_allocator/partition_page.cc
@@ -178,6 +178,7 @@
   freelist_head = nullptr;
   num_unprovisioned_slots = 0;
   PA_DCHECK(is_decommitted());
+  PA_DCHECK(bucket);
 }
 
 template <bool thread_safe>
diff --git a/base/allocator/partition_allocator/partition_page.h b/base/allocator/partition_allocator/partition_page.h
index 01ac53b..da6b03f 100644
--- a/base/allocator/partition_allocator/partition_page.h
+++ b/base/allocator/partition_allocator/partition_page.h
@@ -229,16 +229,27 @@
   return reinterpret_cast<char*>(pointer_as_uint + SystemPageSize());
 }
 
-ALWAYS_INLINE bool IsWithinSuperPagePayload(bool with_pcscan, void* ptr) {
+ALWAYS_INLINE char* SuperPagePayloadBegin(char* super_page_base,
+                                          bool with_pcscan) {
+  PA_DCHECK(
+      !(reinterpret_cast<uintptr_t>(super_page_base) % kSuperPageAlignment));
+  return super_page_base + PartitionPageSize() + ReservedTagBitmapSize() +
+         (with_pcscan ? 2 * sizeof(QuarantineBitmap) : 0);
+}
+
+ALWAYS_INLINE char* SuperPagePayloadEnd(char* super_page_base) {
+  PA_DCHECK(
+      !(reinterpret_cast<uintptr_t>(super_page_base) % kSuperPageAlignment));
+  return super_page_base + kSuperPageSize - PartitionPageSize();
+}
+
+ALWAYS_INLINE bool IsWithinSuperPagePayload(char* ptr, bool with_pcscan) {
   PA_DCHECK(!IsManagedByPartitionAllocDirectMap(ptr));
-  const auto ptr_as_uint = reinterpret_cast<uintptr_t>(ptr);
-  const auto super_page_base = ptr_as_uint & kSuperPageBaseMask;
-  const uintptr_t payload_start =
-      super_page_base + PartitionPageSize() + ReservedTagBitmapSize() +
-      (with_pcscan ? 2 * sizeof(QuarantineBitmap) : 0);
-  const uintptr_t payload_end =
-      super_page_base + kSuperPageSize - PartitionPageSize();
-  return ptr_as_uint >= payload_start && ptr_as_uint < payload_end;
+  char* super_page_base = reinterpret_cast<char*>(
+      reinterpret_cast<uintptr_t>(ptr) & kSuperPageBaseMask);
+  char* payload_start = SuperPagePayloadBegin(super_page_base, with_pcscan);
+  char* payload_end = SuperPagePayloadEnd(super_page_base);
+  return ptr >= payload_start && ptr < payload_end;
 }
 
 // See the comment for |FromPointer|.
@@ -446,6 +457,35 @@
   return (pcscan_epoch & 1) ? second_bitmap : first_bitmap;
 }
 
+template <bool thread_safe, typename Callback>
+void IterateActiveAndFullSlotSpans(char* super_page_base,
+                                   bool with_pcscan,
+                                   Callback callback) {
+  PA_DCHECK(
+      !(reinterpret_cast<uintptr_t>(super_page_base) % kSuperPageAlignment));
+#if DCHECK_IS_ON()
+  auto* extent_entry =
+      reinterpret_cast<PartitionSuperPageExtentEntry<thread_safe>*>(
+          PartitionSuperPageToMetadataArea(super_page_base));
+  extent_entry->root->lock_.AssertAcquired();
+#endif
+
+  using Page = PartitionPage<thread_safe>;
+  auto* const first_page = Page::FromPointerNoAlignmentCheck(
+      SuperPagePayloadBegin(super_page_base, with_pcscan));
+  auto* const last_page = Page::FromPointerNoAlignmentCheck(
+      SuperPagePayloadEnd(super_page_base) - PartitionPageSize());
+  for (auto* page = first_page;
+       page <= last_page && page->slot_span_metadata.bucket;
+       page += page->slot_span_metadata.bucket->get_pages_per_slot_span()) {
+    auto* slot_span = &page->slot_span_metadata;
+    if (slot_span->is_empty() || slot_span->is_decommitted()) {
+      continue;
+    }
+    callback(slot_span);
+  }
+}
+
 }  // namespace internal
 }  // namespace base
 
diff --git a/base/allocator/partition_allocator/pcscan.cc b/base/allocator/partition_allocator/pcscan.cc
index 146875d..5cc93dbbd 100644
--- a/base/allocator/partition_allocator/pcscan.cc
+++ b/base/allocator/partition_allocator/pcscan.cc
@@ -11,6 +11,7 @@
 #include <vector>
 
 #include "base/allocator/partition_allocator/object_bitmap.h"
+#include "base/allocator/partition_allocator/page_allocator_constants.h"
 #include "base/allocator/partition_allocator/partition_address_space.h"
 #include "base/allocator/partition_allocator/partition_alloc.h"
 #include "base/allocator/partition_allocator/partition_alloc_constants.h"
@@ -141,8 +142,8 @@
   if (it == super_pages_.end() || *it != super_page_base)
     return nullptr;
 
-  if (!IsWithinSuperPagePayload(true /*with pcscan*/,
-                                reinterpret_cast<void*>(maybe_ptr)))
+  if (!IsWithinSuperPagePayload(reinterpret_cast<char*>(maybe_ptr),
+                                true /*with pcscan*/))
     return nullptr;
 
   // We are certain here that |maybe_ptr| points to the super page payload.
@@ -281,8 +282,15 @@
 template <bool thread_safe>
 PCScan<thread_safe>::PCScanTask::PCScanTask(PCScan& pcscan, Root& root)
     : pcscan_(pcscan), root_(root) {
+  // Take a snapshot of all allocated non-empty slot spans.
+  static constexpr size_t kScanAreasReservationSlack = 10;
+  const size_t kScanAreasReservationSize = root_.total_size_of_committed_pages /
+                                           PartitionPageSize() /
+                                           kScanAreasReservationSlack;
+  scan_areas_.reserve(kScanAreasReservationSize);
+
   typename Root::ScopedGuard guard(root.lock_);
-  // Take a snapshot of all super pages.
+  // Take a snapshot of all super pages and scannable slot spans.
   // TODO(bikineev): Consider making current_extent lock-free and moving it to
   // the concurrent thread.
   for (auto* super_page_extent = root_.first_extent; super_page_extent;
@@ -290,35 +298,19 @@
     for (char* super_page = super_page_extent->super_page_base;
          super_page != super_page_extent->super_pages_end;
          super_page += kSuperPageSize) {
+      // TODO(bikineev): Consider following freelists instead of slot spans.
+      IterateActiveAndFullSlotSpans<thread_safe>(
+          super_page, true /*with pcscan*/, [this](SlotSpan* slot_span) {
+            auto* payload_begin =
+                static_cast<uintptr_t*>(SlotSpan::ToPointer(slot_span));
+            auto* payload_end =
+                payload_begin +
+                (slot_span->bucket->get_bytes_per_span() / sizeof(uintptr_t));
+            scan_areas_.push_back({payload_begin, payload_end});
+          });
       super_pages_.insert(reinterpret_cast<uintptr_t>(super_page));
     }
   }
-
-  // Take a snapshot of all active slot spans.
-  static constexpr size_t kScanAreasReservationSlack = 10;
-  const size_t kScanAreasReservationSize = root_.total_size_of_committed_pages /
-                                           PartitionPageSize() /
-                                           kScanAreasReservationSlack;
-  scan_areas_.reserve(kScanAreasReservationSize);
-  {
-    // TODO(bikineev): Scan full slot spans.
-    for (const auto& bucket : root_.buckets) {
-      for (auto* slot_span = bucket.active_slot_spans_head;
-           slot_span && slot_span != slot_span->get_sentinel_slot_span();
-           slot_span = slot_span->next_slot_span) {
-        // The active list may contain false positives, skip them.
-        if (slot_span->is_empty() || slot_span->is_decommitted())
-          continue;
-
-        auto* payload_begin =
-            static_cast<uintptr_t*>(SlotSpan::ToPointer(slot_span));
-        auto* payload_end =
-            payload_begin +
-            (slot_span->bucket->get_bytes_per_span() / sizeof(uintptr_t));
-        scan_areas_.push_back({payload_begin, payload_end});
-      }
-    }
-  }
 }
 
 // TODO(bikineev): Synchronize task execution with destruction of
diff --git a/base/allocator/partition_allocator/pcscan_unittest.cc b/base/allocator/partition_allocator/pcscan_unittest.cc
index 99fbf65..048bbae 100644
--- a/base/allocator/partition_allocator/pcscan_unittest.cc
+++ b/base/allocator/partition_allocator/pcscan_unittest.cc
@@ -173,7 +173,7 @@
     // Run PCScan.
     test.RunPCScan();
     // Check that the object is still quarantined since it's referenced by
-    // |from|.
+    // |source|.
     EXPECT_TRUE(test.IsInQuarantine(value));
   }
   {
@@ -240,6 +240,36 @@
   TestDanglingReference(*this, source, value);
 }
 
+TEST_F(PCScanTest, DanglingReferenceFromFullPage) {
+  using SourceList = List<64>;
+  using ValueList = SourceList;
+
+  FullSlotSpanAllocation full_slot_span =
+      GetFullSlotSpan(root(), sizeof(SourceList));
+  void* source_addr = full_slot_span.first;
+  // This allocation must go through the slow path and call SetNewActivePage(),
+  // which will flush the full page from the active page list.
+  void* value_addr = root().AllocFlagsNoHooks(0, sizeof(ValueList));
+
+  // Assert that the first and the last objects are in different slot spans but
+  // in the same bucket.
+  SlotSpan* source_slot_span =
+      ThreadSafePartitionRoot::SlotSpan::FromPointerNoAlignmentCheck(
+          source_addr);
+  SlotSpan* value_slot_span =
+      ThreadSafePartitionRoot::SlotSpan::FromPointerNoAlignmentCheck(
+          value_addr);
+  ASSERT_NE(source_slot_span, value_slot_span);
+  ASSERT_EQ(source_slot_span->bucket, value_slot_span->bucket);
+
+  // Create two objects, where |source| is in a full detached page.
+  auto* value = new (value_addr) ValueList;
+  auto* source = new (source_addr) SourceList;
+  source->next = value;
+
+  TestDanglingReference(*this, source, value);
+}
+
 }  // namespace internal
 }  // namespace base
 
diff --git a/base/cpu_affinity_posix_unittest.cc b/base/cpu_affinity_posix_unittest.cc
index 15622c0..86ffa04d 100644
--- a/base/cpu_affinity_posix_unittest.cc
+++ b/base/cpu_affinity_posix_unittest.cc
@@ -101,9 +101,10 @@
   } else if (device_model == "Pixel 3a" || device_model == "Pixel 3a XL") {
     expected_little_cores = 6;
     EXPECT_LT(expected_little_cores, expected_total_cores);
-  } else if (device_model == "Nexus 5") {
-    // On our Nexus 5 bots, something else in the system seems to set affinity
-    // for the test process, making these tests flaky (crbug.com/1113964).
+  } else if (device_model == "Nexus 5" || device_model == "Nexus 7") {
+    // On our Nexus 5 and Nexus 7 bots, something else in the system seems to
+    // set affinity for the test process, making these tests flaky
+    // (crbug.com/1113964).
     return;
   }
 
diff --git a/base/metrics/ukm_source_id.h b/base/metrics/ukm_source_id.h
index 93fc390..7cf9725 100644
--- a/base/metrics/ukm_source_id.h
+++ b/base/metrics/ukm_source_id.h
@@ -33,7 +33,7 @@
     // interval; it will not be kept in memory between different reports.
     APP_ID = 2,
     // Source ID for background events that don't have an open tab but the
-    // associated URL is still present in the browser's history. A new source of
+    // associated URL is still present in the browsing history. A new source of
     // this type and associated events are expected to be recorded within the
     // same report interval; it will not be kept in memory between different
     // reports.
diff --git a/base/task/sequence_manager/thread_controller.h b/base/task/sequence_manager/thread_controller.h
index 6b017e25..70ed81f 100644
--- a/base/task/sequence_manager/thread_controller.h
+++ b/base/task/sequence_manager/thread_controller.h
@@ -102,13 +102,17 @@
   virtual void DetachFromMessagePump() = 0;
 #endif
 
+  // Sets the SingleThreadTaskRunner that will be returned by
+  // ThreadTaskRunnerHandle::Get on the thread controlled by this
+  // ThreadController.
+  virtual void SetDefaultTaskRunner(scoped_refptr<SingleThreadTaskRunner>) = 0;
+
   // TODO(altimin): Get rid of the methods below.
   // These methods exist due to current integration of SequenceManager
   // with MessageLoop.
 
   virtual bool RunsTasksInCurrentSequence() = 0;
   virtual const TickClock* GetClock() = 0;
-  virtual void SetDefaultTaskRunner(scoped_refptr<SingleThreadTaskRunner>) = 0;
   virtual scoped_refptr<SingleThreadTaskRunner> GetDefaultTaskRunner() = 0;
   virtual void RestoreDefaultTaskRunner() = 0;
   virtual void AddNestingObserver(RunLoop::NestingObserver* observer) = 0;
diff --git a/base/task/sequence_manager/thread_controller_power_monitor.cc b/base/task/sequence_manager/thread_controller_power_monitor.cc
index 96beb41..29ce8c4 100644
--- a/base/task/sequence_manager/thread_controller_power_monitor.cc
+++ b/base/task/sequence_manager/thread_controller_power_monitor.cc
@@ -30,7 +30,7 @@
 }
 
 void ThreadControllerPowerMonitor::BindToCurrentThread() {
-  // Occasionally registration happens twice (i.e. when the deprecated
+  // Occasionally registration happens twice (i.e. when the
   // ThreadController::SetDefaultTaskRunner() re-initializes the
   // ThreadController).
   if (is_observer_registered_)
diff --git a/build/build_config.h b/build/build_config.h
index 2c3e81ee..c37c7429 100644
--- a/build/build_config.h
+++ b/build/build_config.h
@@ -61,7 +61,11 @@
 #define OS_MAC 1
 #endif  // defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE
 #elif defined(__linux__)
+#if !defined(OS_CHROMEOS)
+// Do not define OS_LINUX on Chrome OS build.
+// The OS_CHROMEOS macro is defined in GN.
 #define OS_LINUX 1
+#endif  // !defined(OS_CHROMEOS)
 // Include a system header to pull in features.h for glibc/uclibc macros.
 #include <unistd.h>
 #if defined(__GLIBC__) && !defined(__UCLIBC__)
diff --git a/build/config/compiler/compiler.gni b/build/config/compiler/compiler.gni
index 4d70712..9b019c1e 100644
--- a/build/config/compiler/compiler.gni
+++ b/build/config/compiler/compiler.gni
@@ -73,10 +73,6 @@
   # If true, use Goma for ThinLTO code generation where applicable.
   use_goma_thin_lto = false
 
-  # Ignored, only exists temporarily for backwards compat.
-  # TODO(thakis): Remove this once bots no longer set it.
-  max_jobs_per_link = 8
-
   # Whether we're using a sample profile collected on an architecture different
   # than the one we're compiling for.
   #
diff --git a/build/config/ios/BUILD.gn b/build/config/ios/BUILD.gn
index 5bf00ac..f00bd70 100644
--- a/build/config/ios/BUILD.gn
+++ b/build/config/ios/BUILD.gn
@@ -31,46 +31,31 @@
 
   # CPU architecture.
   if (current_cpu == "x64") {
-    common_ios_flags += [
-      "-arch",
-      "x86_64",
-    ]
-    swiftflags = [
-      "-target",
-      "x86_64-apple-ios$ios_deployment_target-simulator",
-    ]
+    triplet_cpu = "x86_64"
   } else if (current_cpu == "x86") {
-    common_ios_flags += [
-      "-arch",
-      "i386",
-    ]
-    swiftflags = [
-      "-target",
-      "i386-apple-ios$ios_deployment_target-simulator",
-    ]
-  } else if (current_cpu == "armv7" || current_cpu == "arm") {
-    common_ios_flags += [
-      "-arch",
-      "armv7",
-    ]
-    swiftflags = [
-      "-target",
-      "armv7-apple-ios$ios_deployment_target",
-    ]
+    triplet_cpu = "i386"
+  } else if (current_cpu == "arm" || current_cpu == "armv7") {
+    triplet_cpu = "armv7"
   } else if (current_cpu == "arm64") {
-    common_ios_flags += [
-      "-arch",
-      "arm64",
-    ]
-    swiftflags = [
-      "-target",
-      "arm64-apple-ios$ios_deployment_target",
-    ]
+    triplet_cpu = "arm64"
+  } else {
+    assert(false, "unsupported cpu: $current_cpu")
   }
 
-  swiftflags += [
-    "-swift-version",
-    "5",
+  # Environment.
+  if (use_ios_simulator) {
+    triplet_environment = "-simulator"
+  } else {
+    triplet_environment = ""
+  }
+
+  # OS.
+  triplet_os = "apple-ios"
+
+  # Set target.
+  common_ios_flags = [
+    "-target",
+    "$triplet_cpu-$triplet_os$ios_deployment_target$triplet_environment",
   ]
 
   # This is here so that all files get recompiled after an Xcode update.
@@ -80,6 +65,12 @@
 
   asmflags = common_ios_flags
   cflags = common_ios_flags
+  swiftflags = common_ios_flags
+
+  swiftflags += [
+    "-swift-version",
+    "5",
+  ]
 
   # Without this, the constructors and destructors of a C++ object inside
   # an Objective C struct won't be called, which is very bad.
@@ -93,31 +84,19 @@
 # that is iOS-only. Please see that target for advice on what should go in
 # :runtime_library vs. :compiler.
 config("runtime_library") {
+  _sysroot_path = sysroot
   if (ios_enable_relative_sdk_path) {
-    common_flags = [
-      "-isysroot",
-      rebase_path(sysroot, root_build_dir),
-    ]
-    swiftflags = [
-      "-sdk",
-      rebase_path(sysroot, root_build_dir),
-    ]
-  } else {
-    common_flags = [
-      "-isysroot",
-      sysroot,
-    ]
-    swiftflags = [
-      "-sdk",
-      sysroot,
-    ]
+    _sysroot_path = rebase_path(sysroot, root_build_dir)
   }
 
-  if (use_ios_simulator) {
-    common_flags += [ "-mios-simulator-version-min=$ios_deployment_target" ]
-  } else {
-    common_flags += [ "-miphoneos-version-min=$ios_deployment_target" ]
-  }
+  common_flags = [
+    "-isysroot",
+    _sysroot_path,
+  ]
+  swiftflags = [
+    "-sdk",
+    _sysroot_path,
+  ]
 
   if (use_xcode_clang && enable_ios_bitcode && !use_ios_simulator) {
     if (is_debug) {
diff --git a/build/config/ios/ios_sdk.gni b/build/config/ios/ios_sdk.gni
index 62119d7..2f4ec308 100644
--- a/build/config/ios/ios_sdk.gni
+++ b/build/config/ios/ios_sdk.gni
@@ -59,8 +59,26 @@
 
   # TODO(crbug.com/1015730): remove this flag because ios_use_goma_rbe covers.
   ios_enable_relative_sdk_path = ios_use_goma_rbe
+
+  # Configure the environment for which to build. Could be either "device",
+  # "simulator" or "catalyst". If unspecified, then it will be assumed to be
+  # "simulator" if the target_cpu if "x68" or "x64", "device" otherwise. The
+  # default is only there for compatibility reason and will be removed (see
+  # crbug.com/1138425 for more details).
+  target_environment = ""
 }
 
+if (target_environment == "") {
+  if (current_cpu == "x86" || current_cpu == "x64") {
+    target_environment = "simulator"
+  } else {
+    target_environment = "device"
+  }
+}
+
+assert(target_environment == "simulator" || target_environment == "device" ||
+       target_environment == "catalyst")
+
 # Official builds may not use goma.
 assert(!(use_goma && is_chrome_branded && is_official_build &&
              target_cpu == "arm64"),
@@ -69,7 +87,7 @@
 assert(custom_toolchain == "" || additional_target_cpus == [],
        "cannot define both custom_toolchain and additional_target_cpus")
 
-use_ios_simulator = current_cpu == "x86" || current_cpu == "x64"
+use_ios_simulator = target_environment == "simulator"
 
 # If codesigning is enabled, use must configure either a codesigning identity
 # or a filter to automatically select the codesigning identity.
diff --git a/build/fuchsia/linux.sdk.sha1 b/build/fuchsia/linux.sdk.sha1
index 2affec6a..2c5896c7 100644
--- a/build/fuchsia/linux.sdk.sha1
+++ b/build/fuchsia/linux.sdk.sha1
@@ -1 +1 @@
-0.20201014.3.1
+0.20201015.1.1
diff --git a/build/fuchsia/mac.sdk.sha1 b/build/fuchsia/mac.sdk.sha1
index 2affec6a..2c5896c7 100644
--- a/build/fuchsia/mac.sdk.sha1
+++ b/build/fuchsia/mac.sdk.sha1
@@ -1 +1 @@
-0.20201014.3.1
+0.20201015.1.1
diff --git a/chrome/android/chrome_test_java_sources.gni b/chrome/android/chrome_test_java_sources.gni
index 31f00264..8c54f85d 100644
--- a/chrome/android/chrome_test_java_sources.gni
+++ b/chrome/android/chrome_test_java_sources.gni
@@ -75,7 +75,6 @@
   "javatests/src/org/chromium/chrome/browser/bookmarks/BookmarkPersonalizedSigninPromoDismissTest.java",
   "javatests/src/org/chromium/chrome/browser/bookmarks/BookmarkPersonalizedSigninPromoTest.java",
   "javatests/src/org/chromium/chrome/browser/bookmarks/BookmarkTest.java",
-  "javatests/src/org/chromium/chrome/browser/browserservices/ManageTrustedWebActivityDataActivityTest.java",
   "javatests/src/org/chromium/chrome/browser/browserservices/OriginVerifierTest.java",
   "javatests/src/org/chromium/chrome/browser/browserservices/QualityEnforcerTest.java",
   "javatests/src/org/chromium/chrome/browser/browserservices/RunningInChromeTest.java",
diff --git a/chrome/android/expectations/monochrome_public_bundle.AndroidManifest.expected b/chrome/android/expectations/monochrome_public_bundle.AndroidManifest.expected
index 6060768..ec0a8cc 100644
--- a/chrome/android/expectations/monochrome_public_bundle.AndroidManifest.expected
+++ b/chrome/android/expectations/monochrome_public_bundle.AndroidManifest.expected
@@ -1106,7 +1106,6 @@
         <category android:name="androidx.browser.customtabs.category.NavBarColorCustomization"/>
         <category android:name="androidx.browser.trusted.category.ImmersiveMode"/>
         <category android:name="androidx.browser.trusted.category.LaunchSiteSettings"/>
-        <category android:name="androidx.browser.trusted.category.LaunchWebApkSiteSettings"/>
         <category android:name="androidx.browser.trusted.category.TrustedWebActivities"/>
         <category android:name="androidx.browser.trusted.category.TrustedWebActivitySplashScreensV1"/>
         <category android:name="androidx.browser.trusted.category.WebShareTargetV2"/>
diff --git a/chrome/android/expectations/trichrome_chrome_bundle.AndroidManifest.expected b/chrome/android/expectations/trichrome_chrome_bundle.AndroidManifest.expected
index c907fa2..4df0164 100644
--- a/chrome/android/expectations/trichrome_chrome_bundle.AndroidManifest.expected
+++ b/chrome/android/expectations/trichrome_chrome_bundle.AndroidManifest.expected
@@ -1013,7 +1013,6 @@
         <category android:name="androidx.browser.customtabs.category.NavBarColorCustomization"/>
         <category android:name="androidx.browser.trusted.category.ImmersiveMode"/>
         <category android:name="androidx.browser.trusted.category.LaunchSiteSettings"/>
-        <category android:name="androidx.browser.trusted.category.LaunchWebApkSiteSettings"/>
         <category android:name="androidx.browser.trusted.category.TrustedWebActivities"/>
         <category android:name="androidx.browser.trusted.category.TrustedWebActivitySplashScreensV1"/>
         <category android:name="androidx.browser.trusted.category.WebShareTargetV2"/>
diff --git a/chrome/android/java/AndroidManifest.xml b/chrome/android/java/AndroidManifest.xml
index b8ce0a9e..63b59514 100644
--- a/chrome/android/java/AndroidManifest.xml
+++ b/chrome/android/java/AndroidManifest.xml
@@ -1107,7 +1107,6 @@
               <category android:name="androidx.browser.customtabs.category.NavBarColorCustomization"/>
               <category android:name="androidx.browser.trusted.category.ImmersiveMode"/>
               <category android:name="androidx.browser.trusted.category.LaunchSiteSettings" />
-              <category android:name="androidx.browser.trusted.category.LaunchWebApkSiteSettings"/>
               <category android:name="androidx.browser.trusted.category.TrustedWebActivities"/>
               <category android:name="androidx.browser.trusted.category.TrustedWebActivitySplashScreensV1"/>
               <category android:name="androidx.browser.trusted.category.WebShareTargetV2"/>
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/browserservices/ManageTrustedWebActivityDataActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/browserservices/ManageTrustedWebActivityDataActivity.java
index 183a2ab..a58cbf1 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/browserservices/ManageTrustedWebActivityDataActivity.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/browserservices/ManageTrustedWebActivityDataActivity.java
@@ -14,7 +14,6 @@
 import org.chromium.chrome.browser.ChromeApplication;
 import org.chromium.chrome.browser.customtabs.CustomTabsConnection;
 import org.chromium.chrome.browser.init.ChromeBrowserInitializer;
-import org.chromium.webapk.lib.common.WebApkConstants;
 
 /**
  * Launched by Trusted Web Activity apps when the user clears data.
@@ -29,14 +28,11 @@
     @Override
     protected void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
-
-        String urlToLaunchSettingsFor = getIntent().getData().toString();
-        boolean isWebApk = getIntent().getBooleanExtra(WebApkConstants.EXTRA_IS_WEBAPK, false);
-        launchSettings(urlToLaunchSettingsFor, isWebApk);
+        launchSettings();
         finish();
     }
 
-    private void launchSettings(@Nullable String urlToLaunchSettingsFor, boolean isWebApk) {
+    private void launchSettings() {
         String packageName = getClientPackageName();
         if (packageName == null) {
             logNoPackageName();
@@ -45,13 +41,7 @@
         }
         new TrustedWebActivityUmaRecorder(ChromeBrowserInitializer.getInstance())
                 .recordOpenedSettingsViaManageSpace();
-
-        if (isWebApk) {
-            TrustedWebActivitySettingsLauncher.launchForWebApkPackageName(
-                    this, packageName, urlToLaunchSettingsFor);
-        } else {
-            TrustedWebActivitySettingsLauncher.launchForPackageName(this, packageName);
-        }
+        TrustedWebActivitySettingsLauncher.launchForPackageName(this, packageName);
     }
 
     @Nullable
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/browserservices/TrustedWebActivitySettingsLauncher.java b/chrome/android/java/src/org/chromium/chrome/browser/browserservices/TrustedWebActivitySettingsLauncher.java
index 59bb8a5b..8e31acf4 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/browserservices/TrustedWebActivitySettingsLauncher.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/browserservices/TrustedWebActivitySettingsLauncher.java
@@ -13,12 +13,10 @@
 import org.chromium.chrome.R;
 import org.chromium.chrome.browser.settings.SettingsLauncher;
 import org.chromium.chrome.browser.settings.SettingsLauncherImpl;
-import org.chromium.chrome.browser.webapps.ChromeWebApkHost;
 import org.chromium.components.browser_ui.site_settings.AllSiteSettings;
 import org.chromium.components.browser_ui.site_settings.SettingsNavigationSource;
 import org.chromium.components.browser_ui.site_settings.SingleWebsiteSettings;
 import org.chromium.components.browser_ui.site_settings.SiteSettingsCategory;
-import org.chromium.components.webapk.lib.client.WebApkValidator;
 
 import java.util.ArrayList;
 import java.util.Collection;
@@ -35,8 +33,13 @@
      * able to work with each of them.
      */
     public static void launchForPackageName(Context context, String packageName) {
-        Integer applicationUid = getApplicationUid(context, packageName);
-        if (applicationUid == null) return;
+        int applicationUid;
+        try {
+            applicationUid = context.getPackageManager().getApplicationInfo(packageName, 0).uid;
+        } catch (PackageManager.NameNotFoundException e) {
+            Log.d(TAG, "Package " + packageName + " not found");
+            return;
+        }
 
         ClientAppDataRegister register = new ClientAppDataRegister();
         Collection<String> domains = register.getDomainsForRegisteredUid(applicationUid);
@@ -49,33 +52,6 @@
     }
 
     /**
-     * Launches site-settings for a WebApk with a given package name and associated url.
-     */
-    public static void launchForWebApkPackageName(
-            Context context, String packageName, String webApkUrl) {
-        if (!WebApkValidator.canWebApkHandleUrl(context, packageName, webApkUrl)) {
-            Log.d(TAG, "WebApk " + packageName + " can't handle url " + webApkUrl);
-            return;
-        }
-        if (getApplicationUid(context, packageName) == null) return;
-
-        // Handle the case when settings are selected but Chrome was not running.
-        ChromeWebApkHost.init();
-        openSingleWebsitePrefs(context, webApkUrl);
-    }
-
-    private static Integer getApplicationUid(Context context, String packageName) {
-        int applicationUid;
-        try {
-            applicationUid = context.getPackageManager().getApplicationInfo(packageName, 0).uid;
-        } catch (PackageManager.NameNotFoundException e) {
-            Log.d(TAG, "Package " + packageName + " not found");
-            return null;
-        }
-        return applicationUid;
-    }
-
-    /**
      * Same as above, but with list of associated origins and domains already retrieved.
      */
     public static void launch(Context context, Collection<String> origins,
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/features/toolbar/CustomTabToolbar.java b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/features/toolbar/CustomTabToolbar.java
index f838fa5..056ce6d 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/features/toolbar/CustomTabToolbar.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/features/toolbar/CustomTabToolbar.java
@@ -396,6 +396,118 @@
         }
     }
 
+    private void updateToolbarLayoutMargin() {
+        int startMargin = calculateStartMarginWhenCloseButtonVisibilityGone();
+
+        updateStartMarginOfVisibleElementsUntilLocationBarFrameLayout(startMargin);
+
+        int locationBarLayoutChildIndex = getLocationBarFrameLayoutIndex();
+        assert locationBarLayoutChildIndex != -1;
+        updateLocationBarLayoutEndMargin(locationBarLayoutChildIndex);
+
+        // Update left margin of mTitleUrlContainer here to make sure the security icon is
+        // always placed left of the urlbar.
+        updateLeftMarginOfTitleUrlContainer();
+    }
+
+    private int calculateStartMarginWhenCloseButtonVisibilityGone() {
+        return (mCloseButton.getVisibility() == GONE) ? getResources().getDimensionPixelSize(
+                       R.dimen.custom_tabs_toolbar_horizontal_margin_no_close)
+                                                      : 0;
+    }
+
+    private void updateStartMarginOfVisibleElementsUntilLocationBarFrameLayout(int startMargin) {
+        int locationBarFrameLayoutIndex = getLocationBarFrameLayoutIndex();
+        for (int i = 0; i < locationBarFrameLayoutIndex; ++i) {
+            View childView = getChildAt(i);
+            if (childView.getVisibility() == GONE) continue;
+
+            updateViewLayoutParams(childView, startMargin);
+
+            LayoutParams childLayoutParams = (LayoutParams) childView.getLayoutParams();
+            int widthMeasureSpec = calcWidthMeasure(childLayoutParams);
+            int heightMeasureSpec = calcHeightMeasure(childLayoutParams);
+            childView.measure(widthMeasureSpec, heightMeasureSpec);
+            startMargin += childView.getMeasuredWidth();
+        }
+
+        updateStartMarginOfLocationBarFrameLayout(startMargin);
+    }
+
+    private void updateStartMarginOfLocationBarFrameLayout(int startMargin) {
+        int locationBarFrameLayoutIndex = getLocationBarFrameLayoutIndex();
+        View locationBarLayoutView = getChildAt(locationBarFrameLayoutIndex);
+        updateViewLayoutParams(locationBarLayoutView, startMargin);
+    }
+
+    private void updateViewLayoutParams(View view, int margin) {
+        LayoutParams layoutParams = (LayoutParams) view.getLayoutParams();
+        if (MarginLayoutParamsCompat.getMarginStart(layoutParams) != margin) {
+            MarginLayoutParamsCompat.setMarginStart(layoutParams, margin);
+            view.setLayoutParams(layoutParams);
+        }
+    }
+
+    private void updateLocationBarLayoutEndMargin(int startIndex) {
+        int locationBarLayoutEndMargin = 0;
+        for (int i = startIndex + 1; i < getChildCount(); i++) {
+            View childView = getChildAt(i);
+            if (childView.getVisibility() != GONE) {
+                locationBarLayoutEndMargin += childView.getMeasuredWidth();
+            }
+        }
+        LayoutParams urlLayoutParams = (LayoutParams) mLocationBarFrameLayout.getLayoutParams();
+
+        if (MarginLayoutParamsCompat.getMarginEnd(urlLayoutParams) != locationBarLayoutEndMargin) {
+            MarginLayoutParamsCompat.setMarginEnd(urlLayoutParams, locationBarLayoutEndMargin);
+            mLocationBarFrameLayout.setLayoutParams(urlLayoutParams);
+        }
+    }
+
+    private void updateLeftMarginOfTitleUrlContainer() {
+        int leftMargin = mSecurityButton.getMeasuredWidth();
+        LayoutParams lp = (LayoutParams) mTitleUrlContainer.getLayoutParams();
+
+        if (mSecurityButton.getVisibility() == View.GONE) {
+            leftMargin -= mSecurityButton.getMeasuredWidth();
+        }
+
+        lp.leftMargin = leftMargin;
+        mTitleUrlContainer.setLayoutParams(lp);
+    }
+
+    private int getLocationBarFrameLayoutIndex() {
+        assert mLocationBarFrameLayout.getVisibility() != GONE;
+        for (int i = 0; i < getChildCount(); i++) {
+            if (getChildAt(i) == mLocationBarFrameLayout) return i;
+        }
+        return -1;
+    }
+
+    private int calcWidthMeasure(LayoutParams childLayoutParams) {
+        if (childLayoutParams.width == LayoutParams.WRAP_CONTENT) {
+            return MeasureSpec.makeMeasureSpec(getMeasuredWidth(), MeasureSpec.AT_MOST);
+        }
+
+        if (childLayoutParams.width == LayoutParams.MATCH_PARENT) {
+            return MeasureSpec.makeMeasureSpec(getMeasuredWidth(), MeasureSpec.EXACTLY);
+        }
+
+        return MeasureSpec.makeMeasureSpec(childLayoutParams.width, MeasureSpec.EXACTLY);
+    }
+
+    private int calcHeightMeasure(LayoutParams childLayoutParams) {
+        if (childLayoutParams.height == LayoutParams.WRAP_CONTENT) {
+            return MeasureSpec.makeMeasureSpec(getMeasuredHeight(), MeasureSpec.AT_MOST);
+        }
+
+        if (childLayoutParams.height == LayoutParams.MATCH_PARENT) {
+            return MeasureSpec.makeMeasureSpec(getMeasuredHeight(), MeasureSpec.EXACTLY);
+        }
+
+        return MeasureSpec.makeMeasureSpec(childLayoutParams.height, MeasureSpec.EXACTLY);
+    }
+
     @Override
     protected void onConfigurationChanged(Configuration newConfig) {
         super.onConfigurationChanged(newConfig);
@@ -456,80 +568,11 @@
         if (!shouldAnimate) mBrandColorTransitionAnimation.end();
     }
 
-    private void updateLayoutParams() {
-        int startMargin = 0;
-        int locationBarLayoutChildIndex = -1;
-        for (int i = 0; i < getChildCount(); i++) {
-            View childView = getChildAt(i);
-            if (childView == mCloseButton && childView.getVisibility() == GONE) {
-                startMargin += getResources().getDimensionPixelSize(
-                        R.dimen.custom_tabs_toolbar_horizontal_margin_no_close);
-            } else if (childView.getVisibility() != GONE) {
-                LayoutParams childLayoutParams = (LayoutParams) childView.getLayoutParams();
-                if (MarginLayoutParamsCompat.getMarginStart(childLayoutParams) != startMargin) {
-                    MarginLayoutParamsCompat.setMarginStart(childLayoutParams, startMargin);
-                    childView.setLayoutParams(childLayoutParams);
-                }
-                if (childView == mLocationBarFrameLayout) {
-                    locationBarLayoutChildIndex = i;
-                    break;
-                }
-                int widthMeasureSpec;
-                int heightMeasureSpec;
-                if (childLayoutParams.width == LayoutParams.WRAP_CONTENT) {
-                    widthMeasureSpec =
-                            MeasureSpec.makeMeasureSpec(getMeasuredWidth(), MeasureSpec.AT_MOST);
-                } else if (childLayoutParams.width == LayoutParams.MATCH_PARENT) {
-                    widthMeasureSpec =
-                            MeasureSpec.makeMeasureSpec(getMeasuredWidth(), MeasureSpec.EXACTLY);
-                } else {
-                    widthMeasureSpec = MeasureSpec.makeMeasureSpec(
-                            childLayoutParams.width, MeasureSpec.EXACTLY);
-                }
-                if (childLayoutParams.height == LayoutParams.WRAP_CONTENT) {
-                    heightMeasureSpec =
-                            MeasureSpec.makeMeasureSpec(getMeasuredHeight(), MeasureSpec.AT_MOST);
-                } else if (childLayoutParams.height == LayoutParams.MATCH_PARENT) {
-                    heightMeasureSpec =
-                            MeasureSpec.makeMeasureSpec(getMeasuredHeight(), MeasureSpec.EXACTLY);
-                } else {
-                    heightMeasureSpec = MeasureSpec.makeMeasureSpec(
-                            childLayoutParams.height, MeasureSpec.EXACTLY);
-                }
-                childView.measure(widthMeasureSpec, heightMeasureSpec);
-                startMargin += childView.getMeasuredWidth();
-            }
-        }
 
-        assert locationBarLayoutChildIndex != -1;
-        int locationBarLayoutEndMargin = 0;
-        for (int i = locationBarLayoutChildIndex + 1; i < getChildCount(); i++) {
-            View childView = getChildAt(i);
-            if (childView.getVisibility() != GONE) {
-                locationBarLayoutEndMargin += childView.getMeasuredWidth();
-            }
-        }
-        LayoutParams urlLayoutParams = (LayoutParams) mLocationBarFrameLayout.getLayoutParams();
-
-        if (MarginLayoutParamsCompat.getMarginEnd(urlLayoutParams) != locationBarLayoutEndMargin) {
-            MarginLayoutParamsCompat.setMarginEnd(urlLayoutParams, locationBarLayoutEndMargin);
-            mLocationBarFrameLayout.setLayoutParams(urlLayoutParams);
-        }
-
-        // Update left margin of mTitleUrlContainer here to make sure the security icon is always
-        // placed left of the urlbar.
-        LayoutParams lp = (LayoutParams) mTitleUrlContainer.getLayoutParams();
-        if (mSecurityButton.getVisibility() == View.GONE) {
-            lp.leftMargin = 0;
-        } else {
-            lp.leftMargin = mSecurityButton.getMeasuredWidth();
-        }
-        mTitleUrlContainer.setLayoutParams(lp);
-    }
 
     @Override
     protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
-        updateLayoutParams();
+        updateToolbarLayoutMargin();
         super.onMeasure(widthMeasureSpec, heightMeasureSpec);
     }
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadManagerService.java b/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadManagerService.java
index 1e6608a..9f7ffc3 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadManagerService.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadManagerService.java
@@ -111,6 +111,7 @@
 
     private final Handler mHandler;
 
+    // Deprecated after new download backend.
     /** Generic interface for notifying external UI components about downloads and their states. */
     public interface DownloadObserver extends DownloadSharedPreferenceHelper.Observer {
         /** Called in response to {@link DownloadManagerService#getAllDownloads(boolean)}. */
@@ -158,6 +159,7 @@
         void interceptDownloadRequest(DownloadItem item, boolean notifyComplete);
     }
 
+    // Deprecated after new download backend.
     /**
      * Class representing progress of a download.
      */
@@ -291,6 +293,7 @@
         mInfoBarController = infoBarController;
     }
 
+    // Deprecated after new download backend.
     @Override
     public void onDownloadCompleted(final DownloadInfo downloadInfo) {
         @DownloadStatus
@@ -311,6 +314,7 @@
         updateDownloadInfoBar(downloadItem);
     }
 
+    // Deprecated after new download backend.
     @Override
     public void onDownloadUpdated(final DownloadInfo downloadInfo) {
         DownloadItem item = new DownloadItem(false, downloadInfo);
@@ -323,6 +327,7 @@
         scheduleUpdateIfNeeded();
     }
 
+    // Deprecated after new download backend.
     @Override
     public void onDownloadCancelled(final DownloadInfo downloadInfo) {
         DownloadInfo newInfo = DownloadInfo.Builder.fromDownloadInfo(downloadInfo)
@@ -334,6 +339,7 @@
         updateDownloadInfoBar(item);
     }
 
+    // Deprecated after new download backend.
     @Override
     public void onDownloadInterrupted(final DownloadInfo downloadInfo, boolean isAutoResumable) {
         @DownloadStatus
@@ -369,6 +375,7 @@
         }
     }
 
+    // Deprecated after native auto-resumption.
     /**
      * Helper method to schedule a download for resumption.
      * @param item DownloadItem to resume.
@@ -409,6 +416,7 @@
      * Broadcast that a download was successful.
      * @param downloadInfo info about the download.
      */
+    // For testing only.
     protected void broadcastDownloadSuccessful(DownloadInfo downloadInfo) {
         for (DownloadObserver observer : mDownloadObservers) {
             observer.broadcastDownloadSuccessfulForTesting(downloadInfo);
@@ -474,6 +482,7 @@
         }
     }
 
+    // Deprecated after new download backend.
     /**
      * Update notification for a specific download.
      * @param progress Specific notification to update.
@@ -520,6 +529,7 @@
         if (removeFromDownloadProgressMap) mDownloadProgressMap.remove(item.getId());
     }
 
+    // Deprecated after new download backend.
     /**
      * Helper method to schedule a task to update the download success notification.
      * @param progress Download progress to update.
@@ -598,6 +608,7 @@
                 DownloadOpenSource.AUTO_OPEN);
     }
 
+    // Deprecated after new download backend.
     /**
      * Schedule an update if there is no update scheduled.
      */
@@ -633,6 +644,7 @@
      * @param downloadItem Information about the download.
      * @param downloadStatus Status of the download.
      */
+    // Deprecated after new download backend.
     private void updateDownloadProgress(
             DownloadItem downloadItem, @DownloadStatus int downloadStatus) {
         boolean isSupportedMimeType = downloadStatus == DownloadStatus.COMPLETE
@@ -908,6 +920,7 @@
         }
     }
 
+    // Deprecated after new download backend.
     @Override
     public void resumeDownload(ContentId id, DownloadItem item, boolean hasUserGesture) {
         DownloadProgress progress = mDownloadProgressMap.get(item.getId());
@@ -964,6 +977,8 @@
      * @param item The current download that needs to retry.
      * @param hasUserGesture Whether the request was originated due to user gesture.
      */
+    // Deprecated after new download backend.
+    // TODO(shaktisahu): Add retry to offline content provider or route it from resume call.
     public void retryDownload(ContentId id, DownloadItem item, boolean hasUserGesture) {
         DownloadManagerServiceJni.get().retryDownload(getNativeDownloadManagerService(),
                 DownloadManagerService.this, item.getId(),
@@ -975,6 +990,7 @@
      * @param id The {@link ContentId} of the download to cancel.
      * @param isOffTheRecord Whether the download is off the record.
      */
+    // Deprecated after new download backend.
     @Override
     public void cancelDownload(ContentId id, boolean isOffTheRecord) {
         DownloadManagerServiceJni.get().cancelDownload(getNativeDownloadManagerService(),
@@ -998,6 +1014,7 @@
      * @param id The {@link ContentId} of the download to pause.
      * @param isOffTheRecord Whether the download is off the record.
      */
+    // Deprecated after new download backend.
     @Override
     public void pauseDownload(ContentId id, boolean isOffTheRecord) {
         DownloadManagerServiceJni.get().pauseDownload(getNativeDownloadManagerService(),
@@ -1217,6 +1234,7 @@
      * Helper method to add an auto resumable download.
      * @param guid Id of the download item.
      */
+    // Deprecated after native auto-resumption handler.
     private void addAutoResumableDownload(String guid) {
         if (CachedFeatureFlags.isEnabled(ChromeFeatureList.DOWNLOADS_AUTO_RESUMPTION_NATIVE)) {
             return;
@@ -1234,6 +1252,7 @@
      * Helper method to remove an auto resumable download.
      * @param guid Id of the download item.
      */
+    // Deprecated after native auto-resumption.
     private void removeAutoResumableDownload(String guid) {
         if (CachedFeatureFlags.isEnabled(ChromeFeatureList.DOWNLOADS_AUTO_RESUMPTION_NATIVE)) {
             return;
@@ -1247,12 +1266,14 @@
      * Helper method to remove a download from |mDownloadProgressMap|.
      * @param guid Id of the download item.
      */
+    // Deprecated after new download backend.
     private void removeDownloadProgress(String guid) {
         mDownloadProgressMap.remove(guid);
         removeAutoResumableDownload(guid);
         sFirstSeenDownloadIds.remove(guid);
     }
 
+    // Deprecated after native auto resumption.
     @Override
     public void onConnectionTypeChanged(int connectionType) {
         if (CachedFeatureFlags.isEnabled(ChromeFeatureList.DOWNLOADS_AUTO_RESUMPTION_NATIVE)) {
@@ -1280,6 +1301,7 @@
      * Helper method to stop listening to the connection type change
      * if it is no longer needed.
      */
+    // Deprecated after native auto resumption.
     private void stopListenToConnectionChangeIfNotNeeded() {
         if (mAutoResumableDownloadIds.isEmpty() && mNetworkChangeNotifier != null) {
             mNetworkChangeNotifier.destroy();
@@ -1287,6 +1309,7 @@
         }
     }
 
+    // Deprecated after native auto resumption.
     static boolean isActiveNetworkMetered(Context context) {
         if (sIsNetworkListenerDisabled) return sIsNetworkMetered;
         ConnectivityManager cm =
@@ -1295,12 +1318,14 @@
     }
 
     /** Adds a new DownloadObserver to the list. */
+    // Deprecated after new download backend.
     public void addDownloadObserver(DownloadObserver observer) {
         mDownloadObservers.addObserver(observer);
         DownloadSharedPreferenceHelper.getInstance().addObserver(observer);
     }
 
     /** Removes a DownloadObserver from the list. */
+    // Deprecated after new download backend.
     public void removeDownloadObserver(DownloadObserver observer) {
         mDownloadObservers.removeObserver(observer);
         DownloadSharedPreferenceHelper.getInstance().removeObserver(observer);
@@ -1313,6 +1338,7 @@
      *
      * @param isOffTheRecord Whether or not to get downloads for the off the record profile.
      */
+    // Deprecated after new download backend.
     public void getAllDownloads(boolean isOffTheRecord) {
         DownloadManagerServiceJni.get().getAllDownloads(getNativeDownloadManagerService(),
                 DownloadManagerService.this, getProfileKey(isOffTheRecord));
@@ -1322,6 +1348,7 @@
      * Fires an Intent that alerts the DownloadNotificationService that an action must be taken
      * for a particular item.
      */
+    // Deprecated after new download backend.
     public void broadcastDownloadAction(DownloadItem downloadItem, String action) {
         Context appContext = ContextUtils.getApplicationContext();
             Intent intent = DownloadNotificationFactory.buildActionIntent(appContext, action,
@@ -1331,6 +1358,7 @@
             appContext.startService(intent);
     }
 
+    // Deprecated after new download backend.
     public void renameDownload(ContentId id, String name,
             Callback<Integer /*RenameResult*/> callback, boolean isOffTheRecord) {
         DownloadManagerServiceJni.get().renameDownload(getNativeDownloadManagerService(),
@@ -1343,6 +1371,7 @@
      * @param schedule The download schedule that defines when to start the download.
      * @param isOffTheRecord Whether the download is for off the record profile.
      */
+    // Deprecated after new download backend.
     public void changeSchedule(
             final ContentId id, final OfflineItemSchedule schedule, boolean isOffTheRecord) {
         boolean onlyOnWifi = (schedule == null) ? false : schedule.onlyOnWifi;
@@ -1358,6 +1387,7 @@
      * @param intent The Intent associated with the download action.
      * @param downloadItem The download associated with download action.
      */
+    // Deprecated after new download backend.
     private void addCancelExtra(Intent intent, DownloadItem downloadItem) {
         if (intent.getAction().equals(DownloadNotificationService.ACTION_DOWNLOAD_CANCEL)) {
             int state;
@@ -1387,16 +1417,19 @@
                 getProfileKey(isOffTheRecord));
     }
 
+    // Deprecated after new download backend.
     @CalledByNative
     private List<DownloadItem> createDownloadItemList() {
         return new ArrayList<DownloadItem>();
     }
 
+    // Deprecated after new download backend.
     @CalledByNative
     private void addDownloadItemToList(List<DownloadItem> list, DownloadItem item) {
         list.add(item);
     }
 
+    // Deprecated after new download backend.
     @CalledByNative
     private void onAllDownloadsRetrieved(final List<DownloadItem> list, ProfileKey profileKey) {
         // TODO(https://crbug.com/1099577): Pass the profileKey/profile to adapter instead of the
@@ -1415,6 +1448,7 @@
      *
      * @param list  List of DownloadItems to check.
      */
+    // TODO(shaktisahu): Drive this from a similar observer.
     private void maybeShowMissingSdCardError(List<DownloadItem> list) {
         PrefService prefService = UserPrefs.get(Profile.getLastUsedRegularProfile());
         // Only show the missing directory snackbar once.
@@ -1480,6 +1514,7 @@
         return true;
     }
 
+    // Deprecated after new download backend.
     @CalledByNative
     private void onDownloadItemCreated(DownloadItem item) {
         for (DownloadObserver adapter : mDownloadObservers) {
@@ -1487,6 +1522,7 @@
         }
     }
 
+    // Deprecated after new download backend.
     @CalledByNative
     private void onDownloadItemUpdated(DownloadItem item) {
         for (DownloadObserver adapter : mDownloadObservers) {
@@ -1494,6 +1530,7 @@
         }
     }
 
+    // Deprecated after new download backend.
     @CalledByNative
     private void onDownloadItemRemoved(String guid, boolean isOffTheRecord) {
         DownloadInfoBarController infobarController = getInfoBarController(isOffTheRecord);
@@ -1507,6 +1544,7 @@
         }
     }
 
+    // Deprecated after new download backend.
     @CalledByNative
     private void openDownloadItem(DownloadItem downloadItem, @DownloadOpenSource int source) {
         DownloadInfo downloadInfo = downloadItem.getDownloadInfo();
@@ -1524,6 +1562,7 @@
      * @param id The {@link ContentId} of the download to be opened.
      * @param source The source where the user opened this download.
      */
+    // Deprecated after new download backend.
     public void openDownload(ContentId id, boolean isOffTheRecord, @DownloadOpenSource int source) {
         DownloadManagerServiceJni.get().openDownload(getNativeDownloadManagerService(),
                 DownloadManagerService.this, id.id, getProfileKey(isOffTheRecord), source);
@@ -1631,6 +1670,7 @@
      * @param downloadGuid Download GUID.
      * @param hasUserGesture Whether the retry is caused by user gesture.
      */
+    // Deprecated after new download backend.
     private void incrementDownloadRetryCount(String downloadGuid, boolean hasUserGesture) {
         String name = getDownloadRetryCountSharedPrefName(downloadGuid, hasUserGesture, false);
         incrementDownloadRetrySharedPreferenceCount(name);
@@ -1642,6 +1682,7 @@
      * Helper method to increment the retry count for a SharedPreference entry.
      * @param sharedPreferenceName Name of the SharedPreference entry.
      */
+    // Deprecated after new download backend.
     private void incrementDownloadRetrySharedPreferenceCount(String sharedPreferenceName) {
         SharedPreferences sharedPrefs = getAutoRetryCountSharedPreference();
         int count = sharedPrefs.getInt(sharedPreferenceName, 0);
@@ -1659,6 +1700,7 @@
      * @param hasUserGesture Whether the SharedPreference is for manual retry attempts.
      * @param isTotalCount Whether the SharedPreference is for total retry attempts.
      */
+    // Deprecated after new download backend.
     private String getDownloadRetryCountSharedPrefName(
             String downloadGuid, boolean hasUserGesture, boolean isTotalCount) {
         if (isTotalCount) return downloadGuid + DOWNLOAD_TOTAL_RETRY_SUFFIX;
@@ -1672,6 +1714,7 @@
      * @param downloadGuid Download GUID.
      * @param isAutoRetryOnly Whether to clear the auto retry count only.
      */
+    // Deprecated after new download backend.
     private void clearDownloadRetryCount(String downloadGuid, boolean isAutoRetryOnly) {
         SharedPreferences sharedPrefs = getAutoRetryCountSharedPreference();
         String name = getDownloadRetryCountSharedPrefName(downloadGuid, !isAutoRetryOnly, false);
@@ -1694,6 +1737,7 @@
         editor.apply();
     }
 
+    // Deprecated after new download backend.
     int getAutoResumptionLimit() {
         if (mAutoResumptionLimit < 0) {
             mAutoResumptionLimit = DownloadManagerServiceJni.get().getAutoResumptionLimit();
@@ -1722,6 +1766,7 @@
      * @param downloadGuid Download GUID.
      * @param isOffTheRecord Whether the download is off the record.
      */
+    // Deprecated after new download backend.
     public void updateLastAccessTime(String downloadGuid, boolean isOffTheRecord) {
         if (TextUtils.isEmpty(downloadGuid)) return;
 
@@ -1729,18 +1774,23 @@
                 DownloadManagerService.this, downloadGuid, getProfileKey(isOffTheRecord));
     }
 
+    // Deprecated after native auto-resumption handler.
     @Override
     public void onConnectionSubtypeChanged(int newConnectionSubtype) {}
 
+    // Deprecated after native auto-resumption handler.
     @Override
     public void onNetworkConnect(long netId, int connectionType) {}
 
+    // Deprecated after native auto-resumption handler.
     @Override
     public void onNetworkSoonToDisconnect(long netId) {}
 
+    // Deprecated after native auto-resumption handler.
     @Override
     public void onNetworkDisconnect(long netId) {}
 
+    // Deprecated after native auto-resumption handler.
     @Override
     public void purgeActiveNetworkList(long[] activeNetIds) {}
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadResumptionBackgroundTask.java b/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadResumptionBackgroundTask.java
index b595faf3..1c1cf8e 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadResumptionBackgroundTask.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadResumptionBackgroundTask.java
@@ -17,6 +17,7 @@
  * This class currently just starts the {@link DownloadNotificationService} or calls
  * {@link DownloadNotificationService}, which handles the actual resumption.
  */
+// Deprecated after native auto-resumption handler.
 public class DownloadResumptionBackgroundTask extends NativeBackgroundTask {
     // NativeBackgroundTask implementation.
     @Override
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadResumptionScheduler.java b/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadResumptionScheduler.java
index b7f49a9..130a6e64 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadResumptionScheduler.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadResumptionScheduler.java
@@ -20,6 +20,7 @@
 /**
  * Class for scheduing download resumption tasks.
  */
+// Deprecated after native auto-resumption handler.
 public class DownloadResumptionScheduler {
     @SuppressLint("StaticFieldLeak")
     private static DownloadResumptionScheduler sDownloadResumptionScheduler;
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/browserservices/ManageTrustedWebActivityDataActivityTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/browserservices/ManageTrustedWebActivityDataActivityTest.java
deleted file mode 100644
index 3c1e42e9..0000000
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/browserservices/ManageTrustedWebActivityDataActivityTest.java
+++ /dev/null
@@ -1,110 +0,0 @@
-// Copyright 2020 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-package org.chromium.chrome.browser.browserservices;
-
-import static org.chromium.chrome.browser.browserservices.TrustedWebActivityTestUtil.createSession;
-import static org.chromium.chrome.browser.browserservices.TrustedWebActivityTestUtil.spoofVerification;
-
-import android.app.Activity;
-import android.content.ComponentName;
-import android.content.Intent;
-import android.content.pm.PackageManager;
-import android.net.Uri;
-import android.support.test.InstrumentationRegistry;
-
-import androidx.browser.customtabs.CustomTabsIntent;
-import androidx.browser.customtabs.CustomTabsSession;
-import androidx.test.filters.MediumTest;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import org.chromium.base.ApplicationStatus;
-import org.chromium.base.test.util.CommandLineFlags;
-import org.chromium.base.test.util.Matchers;
-import org.chromium.chrome.browser.flags.ChromeSwitches;
-import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
-import org.chromium.components.webapk.lib.client.WebApkValidator;
-import org.chromium.content_public.browser.test.util.Criteria;
-import org.chromium.content_public.browser.test.util.CriteriaHelper;
-import org.chromium.webapk.lib.common.WebApkConstants;
-
-import java.util.concurrent.TimeoutException;
-
-/**
- * Instrumentation tests for launching site settings for WebApks.
- * Site settings are added as a dynamic android shortcut.
- * The shortcut launches a {@link ManageTrustedWebActivityDataActivity}
- * intent that validates the WebApk and launches the chromium SettingsActivity.
- */
-@RunWith(ChromeJUnit4ClassRunner.class)
-@CommandLineFlags.Add({ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE})
-public class ManageTrustedWebActivityDataActivityTest {
-    private static final String SETTINGS_ACTIVITY_NAME =
-            "org.chromium.chrome.browser.settings.SettingsActivity";
-    private static final String WEBAPK_TEST_URL = "https://www.example.com";
-    private static final String TEST_PACKAGE_NAME =
-            InstrumentationRegistry.getTargetContext().getPackageName();
-
-    @Test
-    @MediumTest
-    public void launchesWebApkSiteSettings() {
-        Intent siteSettingsIntent =
-                createWebApkSiteSettingsIntent(TEST_PACKAGE_NAME, Uri.parse(WEBAPK_TEST_URL));
-
-        WebApkValidator.setDisableValidationForTesting(true);
-        try {
-            launchSiteSettingsIntent(siteSettingsIntent);
-
-            // Check settings activity is running.
-            CriteriaHelper.pollUiThread(() -> {
-                try {
-                    Criteria.checkThat("Site settings activity was not launched",
-                            siteSettingsActivityRunning(), Matchers.is(true));
-                } catch (PackageManager.NameNotFoundException e) {
-                    e.printStackTrace();
-                }
-            });
-        } catch (TimeoutException e) {
-            e.printStackTrace();
-        }
-    }
-
-    private boolean siteSettingsActivityRunning() throws PackageManager.NameNotFoundException {
-        for (Activity a : ApplicationStatus.getRunningActivities()) {
-            String activityName =
-                    a.getPackageManager().getActivityInfo(a.getComponentName(), 0).name;
-            if (activityName.equals(SETTINGS_ACTIVITY_NAME)) {
-                return true;
-            }
-        }
-        return false;
-    }
-
-    private static Intent createWebApkSiteSettingsIntent(String packageName, Uri uri) {
-        // CustomTabsIntent builder is used just to put in the session extras.
-        CustomTabsIntent.Builder builder =
-                new CustomTabsIntent.Builder(CustomTabsSession.createMockSessionForTesting(
-                        new ComponentName(InstrumentationRegistry.getTargetContext(),
-                                ManageTrustedWebActivityDataActivity.class)));
-        Intent intent = builder.build().intent;
-        intent.setAction(
-                "android.support.customtabs.action.ACTION_MANAGE_TRUSTED_WEB_ACTIVITY_DATA");
-        intent.setPackage(packageName);
-        intent.setData(uri);
-        intent.putExtra(WebApkConstants.EXTRA_IS_WEBAPK, true);
-        // The following flag is required because the test starts the intent outside of an activity.
-        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
-        return intent;
-    }
-
-    public void launchSiteSettingsIntent(Intent intent) throws TimeoutException {
-        String url = intent.getData().toString();
-        spoofVerification(TEST_PACKAGE_NAME, url);
-        createSession(intent, TEST_PACKAGE_NAME);
-
-        InstrumentationRegistry.getInstrumentation().startActivitySync(intent);
-    }
-}
diff --git a/chrome/android/profiles/newest.txt b/chrome/android/profiles/newest.txt
index 36bf3d4..633a3491 100644
--- a/chrome/android/profiles/newest.txt
+++ b/chrome/android/profiles/newest.txt
@@ -1 +1 @@
-chromeos-chrome-amd64-88.0.4291.0_rc-r1-merged.afdo.bz2
+chromeos-chrome-amd64-88.0.4292.0_rc-r1-merged.afdo.bz2
diff --git a/chrome/android/webapk/libs/common/src/org/chromium/webapk/lib/common/WebApkConstants.java b/chrome/android/webapk/libs/common/src/org/chromium/webapk/lib/common/WebApkConstants.java
index 0171d3f..9751a64 100644
--- a/chrome/android/webapk/libs/common/src/org/chromium/webapk/lib/common/WebApkConstants.java
+++ b/chrome/android/webapk/libs/common/src/org/chromium/webapk/lib/common/WebApkConstants.java
@@ -33,7 +33,6 @@
             "org.chromium.chrome.browser.webapk.splash_provided_by_webapk";
     // Tells the host browser to relaunch the WebAPK.
     public static final String EXTRA_RELAUNCH = "org.chromium.webapk.relaunch";
-    public static final String EXTRA_IS_WEBAPK = "org.chromium.webapk.is_webapk";
 
     // Must be kept in sync with chrome/browser/android/shortcut_info.h.
     public static final int SHORTCUT_SOURCE_UNKNOWN = 0;
diff --git a/chrome/android/webapk/shell_apk/AndroidManifest.xml b/chrome/android/webapk/shell_apk/AndroidManifest.xml
index 7d43085..a1d47fd 100644
--- a/chrome/android/webapk/shell_apk/AndroidManifest.xml
+++ b/chrome/android/webapk/shell_apk/AndroidManifest.xml
@@ -59,10 +59,6 @@
             {{{raw_intent_filters}}}
          </activity>
 
-        <activity android:name="org.chromium.webapk.shell_apk.ManageDataLauncherActivity"
-            android:theme="@android:style/Theme.Translucent.NoTitleBar">
-        </activity>
-
         <activity android:name="org.chromium.webapk.shell_apk.h2o.H2OOpaqueMainActivity"
                   android:theme="@style/SplashTheme"
                   android:relinquishTaskIdentity="true"
diff --git a/chrome/android/webapk/shell_apk/BUILD.gn b/chrome/android/webapk/shell_apk/BUILD.gn
index f4bd0ce..df4640b2 100644
--- a/chrome/android/webapk/shell_apk/BUILD.gn
+++ b/chrome/android/webapk/shell_apk/BUILD.gn
@@ -60,7 +60,6 @@
       "src/org/chromium/webapk/shell_apk/IdentityService.java",
       "src/org/chromium/webapk/shell_apk/InstallHostBrowserDialog.java",
       "src/org/chromium/webapk/shell_apk/LaunchHostBrowserSelector.java",
-      "src/org/chromium/webapk/shell_apk/ManageDataLauncherActivity.java",
       "src/org/chromium/webapk/shell_apk/TransparentLauncherActivity.java",
       "src/org/chromium/webapk/shell_apk/WebApkSharedPreferences.java",
       "src/org/chromium/webapk/shell_apk/WebApkUtils.java",
@@ -77,7 +76,6 @@
       "//chrome/android/webapk/libs/common:splash_java",
       "//components/webapk/android/libs/common:java",
       "//third_party/android_deps:androidx_annotation_annotation_java",
-      "//third_party/android_sdk/androidx_browser:androidx_browser_java",
     ]
   }
 }
@@ -151,7 +149,6 @@
 
   android_resources(_resources_target_name) {
     sources = [
-      "res/drawable-hdpi/ic_site_settings.png",
       "res/drawable-hdpi/last_resort_runtime_host_logo.png",
       "res/drawable-hdpi/notification_badge.png",
       "res/drawable-hdpi/shortcut_1_icon.png",
@@ -159,28 +156,24 @@
       "res/drawable-hdpi/shortcut_3_icon.png",
       "res/drawable-hdpi/shortcut_4_icon.png",
       "res/drawable-hdpi/splash_icon.xml",
-      "res/drawable-mdpi/ic_site_settings.png",
       "res/drawable-mdpi/notification_badge.png",
       "res/drawable-mdpi/shortcut_1_icon.png",
       "res/drawable-mdpi/shortcut_2_icon.png",
       "res/drawable-mdpi/shortcut_3_icon.png",
       "res/drawable-mdpi/shortcut_4_icon.png",
       "res/drawable-mdpi/splash_icon.xml",
-      "res/drawable-xhdpi/ic_site_settings.png",
       "res/drawable-xhdpi/notification_badge.png",
       "res/drawable-xhdpi/shortcut_1_icon.png",
       "res/drawable-xhdpi/shortcut_2_icon.png",
       "res/drawable-xhdpi/shortcut_3_icon.png",
       "res/drawable-xhdpi/shortcut_4_icon.png",
       "res/drawable-xhdpi/splash_icon.xml",
-      "res/drawable-xxhdpi/ic_site_settings.png",
       "res/drawable-xxhdpi/notification_badge.png",
       "res/drawable-xxhdpi/shortcut_1_icon.png",
       "res/drawable-xxhdpi/shortcut_2_icon.png",
       "res/drawable-xxhdpi/shortcut_3_icon.png",
       "res/drawable-xxhdpi/shortcut_4_icon.png",
       "res/drawable-xxhdpi/splash_icon.xml",
-      "res/drawable-xxxhdpi/ic_site_settings.png",
       "res/drawable-xxxhdpi/notification_badge.png",
       "res/drawable-xxxhdpi/shortcut_1_icon.png",
       "res/drawable-xxxhdpi/shortcut_2_icon.png",
diff --git a/chrome/android/webapk/shell_apk/current_version/current_version.gni b/chrome/android/webapk/shell_apk/current_version/current_version.gni
index e5c2c84a..85d57b4 100644
--- a/chrome/android/webapk/shell_apk/current_version/current_version.gni
+++ b/chrome/android/webapk/shell_apk/current_version/current_version.gni
@@ -12,4 +12,4 @@
 # //chrome/android/webapk/shell_apk:webapk is changed. This includes
 # Java files, Android resource files and AndroidManifest.xml. Does not affect
 # Chrome.apk
-current_shell_apk_version = 133
+current_shell_apk_version = 132
diff --git a/chrome/android/webapk/shell_apk/junit/src/org/chromium/webapk/shell_apk/h2o/LaunchTest.java b/chrome/android/webapk/shell_apk/junit/src/org/chromium/webapk/shell_apk/h2o/LaunchTest.java
index 069cf8c..ea14a9a1 100644
--- a/chrome/android/webapk/shell_apk/junit/src/org/chromium/webapk/shell_apk/h2o/LaunchTest.java
+++ b/chrome/android/webapk/shell_apk/junit/src/org/chromium/webapk/shell_apk/h2o/LaunchTest.java
@@ -4,11 +4,6 @@
 
 package org.chromium.webapk.shell_apk.h2o;
 
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
-
-import static org.chromium.webapk.shell_apk.ManageDataLauncherActivity.SITE_SETTINGS_SHORTCUT_ID;
-
 import android.app.Activity;
 import android.app.ActivityManager;
 import android.content.ComponentName;
@@ -16,9 +11,6 @@
 import android.content.Intent;
 import android.content.SharedPreferences;
 import android.content.pm.PackageManager;
-import android.content.pm.ResolveInfo;
-import android.content.pm.ShortcutInfo;
-import android.content.pm.ShortcutManager;
 import android.net.Uri;
 import android.os.Build;
 import android.os.Bundle;
@@ -48,8 +40,6 @@
 import org.chromium.webapk.test.WebApkTestHelper;
 
 import java.util.ArrayList;
-import java.util.List;
-import java.util.stream.Collectors;
 
 /** Tests launching WebAPK. */
 @RunWith(LocalRobolectricTestRunner.class)
@@ -58,12 +48,9 @@
     /** Values based on manifest specified in GN file. */
     private static final String BROWSER_PACKAGE_NAME = "com.google.android.apps.chrome";
     private static final String DEFAULT_START_URL = "https://pwa.rocks/";
-    private static final String CATEGORY_LAUNCH_WEBAPK_SITE_SETTINGS =
-            "androidx.browser.trusted.category.LaunchWebApkSiteSettings";
 
     /** Chromium version which does not support showing the splash screen within WebAPK. */
     private static final int BROWSER_H2O_INCOMPATIBLE_VERSION = 57;
-    public static final int SITE_SETTINGS_COMPATIBLE_BROWSER_VERSION = 87;
 
     private static String sWebApkPackageName;
 
@@ -102,8 +89,8 @@
 
         ArrayList<Intent> launchedIntents =
                 launchAndCheckBrowserLaunched(false /* opaqueMainActivityInitiallyEnabled */,
-                        launchIntent, H2OTransparentLauncherActivity.class,
-                        HostBrowserUtils.MINIMUM_REQUIRED_CHROMIUM_VERSION_NEW_SPLASH);
+                        true /* browserCompatibleWithSplashActivity */, launchIntent,
+                        H2OTransparentLauncherActivity.class);
         Assert.assertEquals(1, launchedIntents.size());
         assertIntentIsForBrowserLaunch(launchedIntents.get(0), deepLinkUrl);
 
@@ -128,17 +115,18 @@
         launchIntent.setPackage(sWebApkPackageName);
 
         ArrayList<Intent> launchedIntents;
-        launchedIntents = launchAndCheckBrowserLaunched(
-                false /* opaqueMainActivityInitiallyEnabled */, launchIntent,
-                H2OTransparentLauncherActivity.class, BROWSER_H2O_INCOMPATIBLE_VERSION);
+        launchedIntents =
+                launchAndCheckBrowserLaunched(false /* opaqueMainActivityInitiallyEnabled */,
+                        false /* browserCompatibleWithSplashActivity */, launchIntent,
+                        H2OTransparentLauncherActivity.class);
         Assert.assertEquals(1, launchedIntents.size());
         assertIntentIsForBrowserLaunch(launchedIntents.get(0), deepLinkUrl);
         assertOnlyEnabledMainIntentHandler(H2OMainActivity.class);
 
         launchedIntents =
                 launchAndCheckBrowserLaunched(false /* opaqueMainActivityInitiallyEnabled */,
-                        launchIntent, H2OTransparentLauncherActivity.class,
-                        HostBrowserUtils.MINIMUM_REQUIRED_CHROMIUM_VERSION_NEW_SPLASH);
+                        true /* browserCompatibleWithSplashActivity */, launchIntent,
+                        H2OTransparentLauncherActivity.class);
         Assert.assertEquals(5, launchedIntents.size());
         assertIntentComponentClassNameEquals(H2OMainActivity.class, launchedIntents.get(0));
         Assert.assertEquals(BROWSER_PACKAGE_NAME, launchedIntents.get(1).getPackage());
@@ -148,9 +136,10 @@
         assertIntentIsForBrowserLaunch(launchedIntents.get(4), deepLinkUrl);
         assertOnlyEnabledMainIntentHandler(H2OOpaqueMainActivity.class);
 
-        launchedIntents = launchAndCheckBrowserLaunched(
-                true /* opaqueMainActivityInitiallyEnabled */, launchIntent,
-                H2OTransparentLauncherActivity.class, BROWSER_H2O_INCOMPATIBLE_VERSION);
+        launchedIntents =
+                launchAndCheckBrowserLaunched(true /* opaqueMainActivityInitiallyEnabled */,
+                        false /* browserCompatibleWithSplashActivity */, launchIntent,
+                        H2OTransparentLauncherActivity.class);
         Assert.assertEquals(2, launchedIntents.size());
         assertIntentComponentClassNameEquals(SplashActivity.class, launchedIntents.get(0));
         assertIntentIsForBrowserLaunch(launchedIntents.get(1), deepLinkUrl);
@@ -158,8 +147,8 @@
 
         launchedIntents =
                 launchAndCheckBrowserLaunched(true /* opaqueMainActivityInitiallyEnabled */,
-                        launchIntent, H2OTransparentLauncherActivity.class,
-                        HostBrowserUtils.MINIMUM_REQUIRED_CHROMIUM_VERSION_NEW_SPLASH);
+                        true /* browserCompatibleWithSplashActivity */, launchIntent,
+                        H2OTransparentLauncherActivity.class);
         Assert.assertEquals(2, launchedIntents.size());
         assertIntentComponentClassNameEquals(SplashActivity.class, launchedIntents.get(0));
         assertIntentIsForBrowserLaunch(launchedIntents.get(1), deepLinkUrl);
@@ -177,14 +166,16 @@
         ArrayList<Intent> launchedIntents;
         launchedIntents =
                 launchAndCheckBrowserLaunched(false /* opaqueMainActivityInitiallyEnabled */,
-                        launchIntent, H2OMainActivity.class, BROWSER_H2O_INCOMPATIBLE_VERSION);
+                        false /* browserCompatibleWithSplashActivity */, launchIntent,
+                        H2OMainActivity.class);
         Assert.assertEquals(1, launchedIntents.size());
         assertIntentIsForBrowserLaunch(launchedIntents.get(0), DEFAULT_START_URL);
         assertOnlyEnabledMainIntentHandler(H2OMainActivity.class);
 
-        launchedIntents = launchAndCheckBrowserLaunched(
-                false /* opaqueMainActivityInitiallyEnabled */, launchIntent, H2OMainActivity.class,
-                HostBrowserUtils.MINIMUM_REQUIRED_CHROMIUM_VERSION_NEW_SPLASH);
+        launchedIntents =
+                launchAndCheckBrowserLaunched(false /* opaqueMainActivityInitiallyEnabled */,
+                        true /* browserCompatibleWithSplashActivity */, launchIntent,
+                        H2OMainActivity.class);
         Assert.assertEquals(4, launchedIntents.size());
         Assert.assertEquals(BROWSER_PACKAGE_NAME, launchedIntents.get(0).getPackage());
         assertIntentComponentClassNameEquals(
@@ -193,9 +184,10 @@
         assertIntentIsForBrowserLaunch(launchedIntents.get(3), DEFAULT_START_URL);
         assertOnlyEnabledMainIntentHandler(H2OOpaqueMainActivity.class);
 
-        launchedIntents = launchAndCheckBrowserLaunched(
-                true /* opaqueMainActivityInitiallyEnabled */, launchIntent,
-                H2OOpaqueMainActivity.class, BROWSER_H2O_INCOMPATIBLE_VERSION);
+        launchedIntents =
+                launchAndCheckBrowserLaunched(true /* opaqueMainActivityInitiallyEnabled */,
+                        false /* browserCompatibleWithSplashActivity */, launchIntent,
+                        H2OOpaqueMainActivity.class);
         Assert.assertEquals(2, launchedIntents.size());
         assertIntentComponentClassNameEquals(SplashActivity.class, launchedIntents.get(0));
         assertIntentIsForBrowserLaunch(launchedIntents.get(1), DEFAULT_START_URL);
@@ -203,8 +195,8 @@
 
         launchedIntents =
                 launchAndCheckBrowserLaunched(true /* opaqueMainActivityInitiallyEnabled */,
-                        launchIntent, H2OOpaqueMainActivity.class,
-                        HostBrowserUtils.MINIMUM_REQUIRED_CHROMIUM_VERSION_NEW_SPLASH);
+                        true /* browserCompatibleWithSplashActivity */, launchIntent,
+                        H2OOpaqueMainActivity.class);
         Assert.assertEquals(2, launchedIntents.size());
         assertIntentComponentClassNameEquals(SplashActivity.class, launchedIntents.get(0));
         assertIntentIsForBrowserLaunch(launchedIntents.get(1), DEFAULT_START_URL);
@@ -235,9 +227,10 @@
         launchIntent.setComponent(new ComponentName(sWebApkPackageName, shareActivityClassName));
         launchIntent.putExtra(Intent.EXTRA_TEXT, "subject_value");
 
-        ArrayList<Intent> launchedIntents = launchAndCheckBrowserLaunched(
-                true /* opaqueMainActivityInitiallyEnabled */, launchIntent,
-                H2OTransparentLauncherActivity.class, BROWSER_H2O_INCOMPATIBLE_VERSION);
+        ArrayList<Intent> launchedIntents =
+                launchAndCheckBrowserLaunched(true /* opaqueMainActivityInitiallyEnabled */,
+                        false /* browserCompatibleWithSplashActivity */, launchIntent,
+                        H2OTransparentLauncherActivity.class);
         Assert.assertTrue(launchedIntents.size() > 1);
 
         Intent browserLaunchIntent = launchedIntents.get(launchedIntents.size() - 1);
@@ -264,8 +257,8 @@
 
         ArrayList<Intent> launchedIntents =
                 launchAndCheckBrowserLaunched(true /* opaqueMainActivityInitiallyEnabled */,
-                        launchIntent, H2OTransparentLauncherActivity.class,
-                        HostBrowserUtils.MINIMUM_REQUIRED_CHROMIUM_VERSION_NEW_SPLASH);
+                        true /* browserCompatibleWithSplashActivity */, launchIntent,
+                        H2OTransparentLauncherActivity.class);
         Assert.assertTrue(launchedIntents.size() > 1);
 
         Intent browserLaunchIntent = launchedIntents.get(launchedIntents.size() - 1);
@@ -291,8 +284,8 @@
 
         ArrayList<Intent> launchedIntents =
                 launchAndCheckBrowserLaunched(true /* opaqueMainActivityInitiallyEnabled */,
-                        launchIntent, H2OTransparentLauncherActivity.class,
-                        HostBrowserUtils.MINIMUM_REQUIRED_CHROMIUM_VERSION_NEW_SPLASH);
+                        true /* browserCompatibleWithSplashActivity */, launchIntent,
+                        H2OTransparentLauncherActivity.class);
         Assert.assertTrue(launchedIntents.size() > 1);
 
         Intent browserLaunchIntent = launchedIntents.get(launchedIntents.size() - 1);
@@ -391,8 +384,8 @@
 
         ArrayList<Intent> launchedIntents =
                 launchAndCheckBrowserLaunched(false /* opaqueMainActivityInitiallyEnabled */,
-                        launchIntent, H2OTransparentLauncherActivity.class,
-                        HostBrowserUtils.MINIMUM_REQUIRED_CHROMIUM_VERSION_NEW_SPLASH);
+                        true /* browserCompatibleWithSplashActivity */, launchIntent,
+                        H2OTransparentLauncherActivity.class);
         Assert.assertEquals(1, launchedIntents.size());
         assertIntentIsForBrowserLaunch(launchedIntents.get(0), deepLinkUrl);
         assertOnlyEnabledMainIntentHandler(H2OMainActivity.class);
@@ -411,9 +404,10 @@
         Intent launchIntent = new Intent(Intent.ACTION_MAIN);
         launchIntent.setPackage(sWebApkPackageName);
 
-        ArrayList<Intent> launchedIntents = launchAndCheckBrowserLaunched(
-                false /* opaqueMainActivityInitiallyEnabled */, launchIntent, H2OMainActivity.class,
-                HostBrowserUtils.MINIMUM_REQUIRED_CHROMIUM_VERSION_NEW_SPLASH);
+        ArrayList<Intent> launchedIntents =
+                launchAndCheckBrowserLaunched(false /* opaqueMainActivityInitiallyEnabled */,
+                        true /* browserCompatibleWithSplashActivity */, launchIntent,
+                        H2OMainActivity.class);
         Assert.assertEquals(1, launchedIntents.size());
         assertIntentIsForBrowserLaunch(launchedIntents.get(0), DEFAULT_START_URL);
         assertOnlyEnabledMainIntentHandler(H2OMainActivity.class);
@@ -487,76 +481,6 @@
                 RuntimeEnvironment.application, true /* isNewStyleWebApk */));
     }
 
-    /**
-     * Tests that we add site settings shortcuts both when
-     * opaque main activity is enabled and when it is not enabled.
-     */
-    @Test
-    @Config(sdk = Build.VERSION_CODES.N_MR1)
-    public void testAddsSiteSettings() {
-        registerWebApk(true /* isNewStyleWebApk */);
-        registerSiteSettingsCategory();
-
-        Intent launchIntent = new Intent(Intent.ACTION_MAIN);
-        launchIntent.setPackage(sWebApkPackageName);
-
-        launchAndCheckBrowserLaunched(false /* opaqueMainActivityInitiallyEnabled */, launchIntent,
-                H2OMainActivity.class, SITE_SETTINGS_COMPATIBLE_BROWSER_VERSION);
-
-        ShortcutManager shortcutManager = mAppContext.getSystemService(ShortcutManager.class);
-        assertTrue(containsSiteSettingsDynamicShortcut(shortcutManager));
-
-        shortcutManager.removeAllDynamicShortcuts();
-
-        launchAndCheckBrowserLaunched(true /* opaqueMainActivityInitiallyEnabled */, launchIntent,
-                H2OOpaqueMainActivity.class, SITE_SETTINGS_COMPATIBLE_BROWSER_VERSION);
-        assertTrue(containsSiteSettingsDynamicShortcut(shortcutManager));
-    }
-
-    /**
-     * Tests that we remove the shortcut in the case that it was previously
-     * added but the current version of Chrome no longer supports it.
-     */
-    @Test
-    @Config(sdk = Build.VERSION_CODES.N_MR1)
-    public void testDoesNotAddSiteSettingsIfCategoryMissing() {
-        registerWebApk(true /* isNewStyleWebApk */);
-
-        Intent launchIntent = new Intent(Intent.ACTION_MAIN);
-        launchIntent.setPackage(sWebApkPackageName);
-
-        launchAndCheckBrowserLaunched(false /* opaqueMainActivityInitiallyEnabled */, launchIntent,
-                H2OMainActivity.class, SITE_SETTINGS_COMPATIBLE_BROWSER_VERSION);
-
-        ShortcutManager shortcutManager = mAppContext.getSystemService(ShortcutManager.class);
-        assertFalse(containsSiteSettingsDynamicShortcut(shortcutManager));
-    }
-
-    /** Tests that we do not attempt to add a shortcut on Android versions lower than N. */
-    @Test
-    @Config(sdk = Build.VERSION_CODES.LOLLIPOP)
-    public void testDoesNotAddSiteSettingsWhenSdkLow() {
-        registerWebApk(true /* isNewStyleWebApk */);
-        registerSiteSettingsCategory();
-
-        Intent launchIntent = new Intent(Intent.ACTION_MAIN);
-        launchIntent.setPackage(sWebApkPackageName);
-
-        launchAndCheckBrowserLaunched(false /* opaqueMainActivityInitiallyEnabled */, launchIntent,
-                H2OMainActivity.class, SITE_SETTINGS_COMPATIBLE_BROWSER_VERSION);
-
-        // There is no shortcut manager in Android M. Therefore if
-        // this test passes, then we did not attempt to add the shortcut.
-    }
-
-    private static boolean containsSiteSettingsDynamicShortcut(ShortcutManager shortcutManager) {
-        List<String> shortcutIDs = shortcutManager.getDynamicShortcuts()
-                                           .stream()
-                                           .map(ShortcutInfo::getId)
-                                           .collect(Collectors.toList());
-        return shortcutIDs.contains(SITE_SETTINGS_SHORTCUT_ID);
-    }
-
     /** Checks the name of the intent's component class name. */
     private static void assertIntentComponentClassNameEquals(Class expectedClass, Intent intent) {
         Assert.assertEquals(expectedClass.getName(), intent.getComponent().getClassName());
@@ -582,31 +506,27 @@
         WebApkTestHelper.registerWebApkWithMetaData(sWebApkPackageName, metadata, null);
     }
 
-    private void registerSiteSettingsCategory() {
-        Intent intent =
-                new Intent().setAction("android.support.customtabs.action.CustomTabsService");
-        intent.setPackage(BROWSER_PACKAGE_NAME);
-        intent.addCategory(CATEGORY_LAUNCH_WEBAPK_SITE_SETTINGS);
-        mShadowPackageManager.addResolveInfoForIntent(intent, new ResolveInfo());
-    }
-
     /**
      * Launches WebAPK with the given intent and configuration. Tests that the host
      * browser is launched and which activities are enabled after the browser launch.
      * @param opaqueMainActivityInitiallyEnabled Whether H2OOpaqueActivity is enabled at the
      *        beginning of the test case.
+     * @param browserCompatibleWithSplashActivity Whether the host browser supports the ShellAPK
+     *         showing the splash screen.
      * @param launchIntent Intent to launch.
      * @param launchActivity Activity which should receive the launch intent.
-     * @param browserVersion The version of the Chromium browser to install.
      * @return List of launched activity intents (including the host browser launch intent).
      */
     private ArrayList<Intent> launchAndCheckBrowserLaunched(
-            boolean opaqueMainActivityInitiallyEnabled, Intent launchIntent,
-            Class<? extends Activity> launchActivity, int browserVersion) {
+            boolean opaqueMainActivityInitiallyEnabled, boolean browserCompatibleWithSplashActivity,
+            Intent launchIntent, Class<? extends Activity> launchActivity) {
         changeEnabledActivity(opaqueMainActivityInitiallyEnabled ? H2OOpaqueMainActivity.class
                                                                  : H2OMainActivity.class);
 
-        installBrowser(BROWSER_PACKAGE_NAME, browserVersion);
+        installBrowser(BROWSER_PACKAGE_NAME,
+                browserCompatibleWithSplashActivity
+                        ? HostBrowserUtils.MINIMUM_REQUIRED_CHROMIUM_VERSION_NEW_SPLASH
+                        : BROWSER_H2O_INCOMPATIBLE_VERSION);
 
         ArrayList<Intent> launchedIntents =
                 runActivityChain(launchIntent, launchActivity, BROWSER_PACKAGE_NAME);
diff --git a/chrome/android/webapk/shell_apk/res/drawable-hdpi/ic_site_settings.png b/chrome/android/webapk/shell_apk/res/drawable-hdpi/ic_site_settings.png
deleted file mode 100644
index ddfa40a..0000000
--- a/chrome/android/webapk/shell_apk/res/drawable-hdpi/ic_site_settings.png
+++ /dev/null
Binary files differ
diff --git a/chrome/android/webapk/shell_apk/res/drawable-mdpi/ic_site_settings.png b/chrome/android/webapk/shell_apk/res/drawable-mdpi/ic_site_settings.png
deleted file mode 100644
index 11bcebf..0000000
--- a/chrome/android/webapk/shell_apk/res/drawable-mdpi/ic_site_settings.png
+++ /dev/null
Binary files differ
diff --git a/chrome/android/webapk/shell_apk/res/drawable-xhdpi/ic_site_settings.png b/chrome/android/webapk/shell_apk/res/drawable-xhdpi/ic_site_settings.png
deleted file mode 100644
index bfb26bad..0000000
--- a/chrome/android/webapk/shell_apk/res/drawable-xhdpi/ic_site_settings.png
+++ /dev/null
Binary files differ
diff --git a/chrome/android/webapk/shell_apk/res/drawable-xxhdpi/ic_site_settings.png b/chrome/android/webapk/shell_apk/res/drawable-xxhdpi/ic_site_settings.png
deleted file mode 100644
index 52860852..0000000
--- a/chrome/android/webapk/shell_apk/res/drawable-xxhdpi/ic_site_settings.png
+++ /dev/null
Binary files differ
diff --git a/chrome/android/webapk/shell_apk/res/drawable-xxxhdpi/ic_site_settings.png b/chrome/android/webapk/shell_apk/res/drawable-xxxhdpi/ic_site_settings.png
deleted file mode 100644
index 8cba619..0000000
--- a/chrome/android/webapk/shell_apk/res/drawable-xxxhdpi/ic_site_settings.png
+++ /dev/null
Binary files differ
diff --git a/chrome/android/webapk/shell_apk/src/org/chromium/webapk/shell_apk/HostBrowserLauncher.java b/chrome/android/webapk/shell_apk/src/org/chromium/webapk/shell_apk/HostBrowserLauncher.java
index db1b0ff7..720e9b9 100644
--- a/chrome/android/webapk/shell_apk/src/org/chromium/webapk/shell_apk/HostBrowserLauncher.java
+++ b/chrome/android/webapk/shell_apk/src/org/chromium/webapk/shell_apk/HostBrowserLauncher.java
@@ -34,6 +34,8 @@
      * Otherwise, launches the host browser in tabbed mode.
      */
     public static void launch(Activity activity, HostBrowserLauncherParams params) {
+        Log.v(TAG, "WebAPK Launch URL: " + params.getStartUrl());
+
         if (HostBrowserUtils.shouldLaunchInTab(params)) {
             launchInTab(activity.getApplicationContext(), params);
             return;
@@ -46,8 +48,6 @@
     /** Launches host browser in WebAPK mode. */
     public static void launchBrowserInWebApkMode(Activity activity,
             HostBrowserLauncherParams params, Bundle extraExtras, int flags, boolean expectResult) {
-        ManageDataLauncherActivity.updateSiteSettingsShortcut(
-                activity.getApplicationContext(), params);
         Intent intent = new Intent();
         intent.setAction(ACTION_START_WEBAPK);
         intent.setPackage(params.getHostBrowserPackageName());
@@ -102,7 +102,6 @@
 
     /** Launches a WebAPK in its runtime host browser as a tab. */
     private static void launchInTab(Context context, HostBrowserLauncherParams params) {
-        ManageDataLauncherActivity.updateSiteSettingsShortcut(context, params);
         Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(params.getStartUrl()));
         intent.setPackage(params.getHostBrowserPackageName());
         intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
diff --git a/chrome/android/webapk/shell_apk/src/org/chromium/webapk/shell_apk/ManageDataLauncherActivity.java b/chrome/android/webapk/shell_apk/src/org/chromium/webapk/shell_apk/ManageDataLauncherActivity.java
deleted file mode 100644
index 07705648..0000000
--- a/chrome/android/webapk/shell_apk/src/org/chromium/webapk/shell_apk/ManageDataLauncherActivity.java
+++ /dev/null
@@ -1,238 +0,0 @@
-// Copyright 2020 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-package org.chromium.webapk.shell_apk;
-
-import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
-
-import android.annotation.TargetApi;
-import android.app.Activity;
-import android.content.ActivityNotFoundException;
-import android.content.ComponentName;
-import android.content.Context;
-import android.content.Intent;
-import android.content.pm.ApplicationInfo;
-import android.content.pm.PackageManager;
-import android.content.pm.ResolveInfo;
-import android.content.pm.ShortcutInfo;
-import android.content.pm.ShortcutManager;
-import android.graphics.drawable.Icon;
-import android.net.Uri;
-import android.os.Build;
-import android.os.Bundle;
-import android.view.Gravity;
-import android.view.View;
-import android.widget.FrameLayout;
-import android.widget.ProgressBar;
-import android.widget.Toast;
-
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
-import androidx.browser.customtabs.CustomTabsClient;
-import androidx.browser.customtabs.CustomTabsIntent;
-import androidx.browser.customtabs.CustomTabsService;
-import androidx.browser.customtabs.CustomTabsServiceConnection;
-import androidx.browser.customtabs.CustomTabsSession;
-
-import org.chromium.webapk.lib.common.WebApkConstants;
-
-import java.util.Collections;
-import java.util.List;
-
-/**
- * A convenience class for adding site setting shortcuts into WebApks.
- * The shortcut opens the web browser's site settings for the url
- * associated to the WebApk.
- */
-public class ManageDataLauncherActivity extends Activity {
-    private static final String TAG = "ManageDataLauncher";
-
-    public static final String ACTION_SITE_SETTINGS =
-            "android.support.customtabs.action.ACTION_MANAGE_TRUSTED_WEB_ACTIVITY_DATA";
-
-    public static final String SITE_SETTINGS_SHORTCUT_ID =
-            "android.support.customtabs.action.SITE_SETTINGS_SHORTCUT";
-
-    private static final String EXTRA_SITE_SETTINGS_URL = "SITE_SETTINGS_URL";
-    private static final String EXTRA_PROVIDER_PACKAGE = "PROVIDER_PACKAGE";
-
-    private static final String CATEGORY_LAUNCH_WEBAPK_SITE_SETTINGS =
-            "androidx.browser.trusted.category.LaunchWebApkSiteSettings";
-
-    @Nullable
-    private String mProviderPackage;
-
-    @Nullable
-    private CustomTabsServiceConnection mConnection;
-
-    @Nullable
-    private Uri mUrl;
-
-    @Override
-    protected void onCreate(@Nullable Bundle savedInstanceState) {
-        super.onCreate(savedInstanceState);
-        mProviderPackage = getIntent().getStringExtra(EXTRA_PROVIDER_PACKAGE);
-        mUrl = Uri.parse(getIntent().getStringExtra(EXTRA_SITE_SETTINGS_URL));
-
-        if (!supportsWebApkManageSpace(this, mProviderPackage)) {
-            handleNoSupportForManageSpace();
-            return;
-        }
-        setContentView(createLoadingView());
-
-        mConnection = new CustomTabsServiceConnection() {
-            @Override
-            public void onCustomTabsServiceConnected(
-                    ComponentName componentName, CustomTabsClient client) {
-                if (!isFinishing()) {
-                    launchSettings(client.newSession(null));
-                }
-            }
-
-            @Override
-            public void onServiceDisconnected(ComponentName componentName) {}
-        };
-        CustomTabsClient.bindCustomTabsService(this, mProviderPackage, mConnection);
-    }
-
-    /**
-     * Returns the url of the page for which the settings will be shown.
-     * The url must be provided as an intent extra to {@link ManageDataLauncherActivity}.
-     */
-    @Nullable
-    private Uri getWebApkStartUrl() {
-        return mUrl;
-    }
-
-    /**
-     * Returns a view with a loading spinner.
-     */
-    @NonNull
-    private View createLoadingView() {
-        ProgressBar progressBar = new ProgressBar(this);
-        FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(WRAP_CONTENT, WRAP_CONTENT);
-        params.gravity = Gravity.CENTER;
-        progressBar.setLayoutParams(params);
-        FrameLayout layout = new FrameLayout(this);
-        layout.addView(progressBar);
-        return layout;
-    }
-
-    /**
-     * Called if a TWA provider doesn't support manage space feature. The default behavior is to
-     * show a toast telling the user where the data is stored.
-     */
-    private void handleNoSupportForManageSpace() {
-        String appName;
-        try {
-            ApplicationInfo info = getPackageManager().getApplicationInfo(mProviderPackage, 0);
-            appName = getPackageManager().getApplicationLabel(info).toString();
-        } catch (PackageManager.NameNotFoundException e) {
-            appName = mProviderPackage;
-        }
-
-        Toast.makeText(this, getString(R.string.no_support_for_manage_space, appName),
-                     Toast.LENGTH_LONG)
-                .show();
-        finish();
-    }
-
-    @Override
-    protected void onStop() {
-        super.onStop();
-        if (mConnection != null) {
-            unbindService(mConnection);
-        }
-        finish();
-    }
-
-    private void launchSettings(CustomTabsSession session) {
-        boolean success =
-                launchBrowserSiteSettings(this, session, mProviderPackage, getWebApkStartUrl());
-        if (success) {
-            finish();
-        } else {
-            handleNoSupportForManageSpace();
-        }
-    }
-
-    private static boolean launchBrowserSiteSettings(
-            Activity activity, CustomTabsSession session, String packageName, Uri defaultUri) {
-        // A Custom Tabs Session is required so that the browser can verify this app's identity.
-        Intent intent = new CustomTabsIntent.Builder().setSession(session).build().intent;
-        intent.setAction(ACTION_SITE_SETTINGS);
-        intent.setPackage(packageName);
-        intent.setData(defaultUri);
-        intent.putExtra(WebApkConstants.EXTRA_IS_WEBAPK, true);
-        try {
-            activity.startActivity(intent);
-            return true;
-        } catch (ActivityNotFoundException e) {
-            return false;
-        }
-    }
-
-    private static boolean supportsWebApkManageSpace(Context context, String providerPackage) {
-        Intent customTabsIntent = new Intent(CustomTabsService.ACTION_CUSTOM_TABS_CONNECTION);
-        customTabsIntent.addCategory(CATEGORY_LAUNCH_WEBAPK_SITE_SETTINGS);
-        customTabsIntent.setPackage(providerPackage);
-        List<ResolveInfo> services = context.getPackageManager().queryIntentServices(
-                customTabsIntent, PackageManager.GET_RESOLVED_FILTER);
-        return services.size() > 0;
-    }
-
-    /**
-     * Returns the {@link ShortcutInfo} for a dynamic shortcut into site settings,
-     * provided that {@link ManageDataLauncherActivity} is present in the manifest
-     * and an Intent for managing site settings is available.
-     *
-     * Otherwise returns null if {@link ManageDataLauncherActivity} is not launchable
-     * or if shortcuts are not supported by the Android SDK version.
-     *
-     * The shortcut returned does not specify an activity. Thus when the shortcut is added,
-     * the app's main activity will be used by default. This activity needs to define the
-     * MAIN action and LAUNCHER category in order to attach the shortcut.
-     */
-    @NonNull
-    @TargetApi(Build.VERSION_CODES.N_MR1)
-    private static ShortcutInfo createSiteSettingsShortcutInfo(
-            Context context, String url, String providerPackage) {
-        Intent siteSettingsIntent = new Intent(context, ManageDataLauncherActivity.class);
-        // Intent needs to have an action set, we can set an arbitrary action.
-        siteSettingsIntent.setAction(ACTION_SITE_SETTINGS);
-        siteSettingsIntent.putExtra(EXTRA_SITE_SETTINGS_URL, url);
-        siteSettingsIntent.putExtra(EXTRA_PROVIDER_PACKAGE, providerPackage);
-
-        return new ShortcutInfo.Builder(context, SITE_SETTINGS_SHORTCUT_ID)
-                .setShortLabel(context.getString(R.string.site_settings_short_label))
-                .setLongLabel(context.getString(R.string.site_settings_long_label))
-                .setIcon(Icon.createWithResource(context, R.drawable.ic_site_settings))
-                .setIntent(siteSettingsIntent)
-                .build();
-    }
-
-    /**
-     * Adds dynamic shortcut to site settings if the twa provider and android version supports it.
-     *
-     * Removes previously added site settings shortcut if it is no longer supported, e.g. the user
-     * changed their default browser.
-     */
-    public static void updateSiteSettingsShortcut(
-            Context context, HostBrowserLauncherParams params) {
-        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N_MR1) return;
-
-        ShortcutManager shortcutManager = context.getSystemService(ShortcutManager.class);
-
-        // Remove potentially existing shortcut if package does not support shortcuts.
-        if (!supportsWebApkManageSpace(context, params.getHostBrowserPackageName())) {
-            shortcutManager.removeDynamicShortcuts(Collections.singletonList(
-                    ManageDataLauncherActivity.SITE_SETTINGS_SHORTCUT_ID));
-            return;
-        }
-
-        ShortcutInfo shortcut = createSiteSettingsShortcutInfo(
-                context, params.getStartUrl(), params.getHostBrowserPackageName());
-        shortcutManager.addDynamicShortcuts(Collections.singletonList(shortcut));
-    }
-}
diff --git a/chrome/android/webapk/strings/android_webapk_strings.grd b/chrome/android/webapk/strings/android_webapk_strings.grd
index f718b07c..06a43b3 100644
--- a/chrome/android/webapk/strings/android_webapk_strings.grd
+++ b/chrome/android/webapk/strings/android_webapk_strings.grd
@@ -167,15 +167,6 @@
   </translations>
   <release allow_pseudo="false" seq="1">
     <messages fallback_to_english="true">
-      <message name="IDS_SITE_SETTINGS_LONG_LABEL" desc="Site settings Android app shortcut title to display on devices with larger screens. (ideally less than 25 characters)">
-        Manage website settings
-      </message>
-      <message name="IDS_SITE_SETTINGS_SHORT_LABEL" desc="Site settings Android app shortcut title. (ideally less than 10 characters)">
-        Site settings
-      </message>
-      <message name="IDS_NO_SUPPORT_FOR_MANAGE_SPACE" desc="Text to show in a toast when a user clicks on a site settings shortcut but managing space is not suported by the browser.">
-        Managing space not supported by: <ph name="BROWSER_PACKAGE">%1$s<ex>org.chromium.chrome</ex></ph>.
-      </message>
       <!-- Select host browser dialog -->
       <message name="IDS_CHOOSE_HOST_BROWSER_DIALOG_TITLE" desc="Title for the host browser picker dialog, which is used to ask users to pick a browser to launch the installed WebAPK.">
         <ph name="APP_NAME">%1$s<ex>Progressive Web Apps</ex></ph> requires a web browser
diff --git a/chrome/browser/BUILD.gn b/chrome/browser/BUILD.gn
index fb2f314..0fc6632 100644
--- a/chrome/browser/BUILD.gn
+++ b/chrome/browser/BUILD.gn
@@ -4507,6 +4507,8 @@
       "themes/theme_helper_win.cc",
       "themes/theme_helper_win.h",
       "upgrade_detector/get_installed_version_win.cc",
+      "upgrade_detector/registry_monitor.cc",
+      "upgrade_detector/registry_monitor.h",
       "webshare/win/show_share_ui_for_window_operation.cc",
       "webshare/win/show_share_ui_for_window_operation.h",
       "win/app_icon.cc",
@@ -4752,6 +4754,8 @@
       "renderer_host/chrome_render_widget_host_view_mac_history_swiper.h",
       "renderer_host/chrome_render_widget_host_view_mac_history_swiper.mm",
       "shell_integration_mac.mm",
+      "upgrade_detector/directory_monitor.cc",
+      "upgrade_detector/directory_monitor.h",
       "upgrade_detector/get_installed_version_mac.mm",
     ]
     deps += [
@@ -4829,6 +4833,8 @@
       "shell_integration_linux.h",
       "themes/theme_service_aura_linux.cc",
       "themes/theme_service_aura_linux.h",
+      "upgrade_detector/directory_monitor.cc",
+      "upgrade_detector/directory_monitor.h",
       "upgrade_detector/get_installed_version_linux.cc",
     ]
     deps += [ "//chrome/app/theme:chrome_unscaled_resources_grit" ]
@@ -5002,6 +5008,7 @@
       "signin/signin_global_error_factory.h",
       "upgrade_detector/get_installed_version.cc",
       "upgrade_detector/get_installed_version.h",
+      "upgrade_detector/installed_version_monitor.h",
       "upgrade_detector/installed_version_poller.cc",
       "upgrade_detector/installed_version_poller.h",
       "upgrade_detector/upgrade_detector_impl.cc",
diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc
index 77b0d8d..be1717f 100644
--- a/chrome/browser/about_flags.cc
+++ b/chrome/browser/about_flags.cc
@@ -6179,6 +6179,10 @@
     {"enhanced_clipboard", flag_descriptions::kEnhancedClipboardName,
      flag_descriptions::kEnhancedClipboardDescription, kOsCrOS,
      FEATURE_VALUE_TYPE(chromeos::features::kClipboardHistory)},
+    {"enhanced_clipboard_simple_render",
+     flag_descriptions::kEnhancedClipboardSimpleRenderName,
+     flag_descriptions::kEnhancedClipboardSimpleRenderDescription, kOsCrOS,
+     FEATURE_VALUE_TYPE(chromeos::features::kClipboardHistorySimpleRender)},
 #endif  // defined(OS_CHROMEOS)
 
 #if defined(OS_WIN)
diff --git a/chrome/browser/chromeos/arc/fileapi/arc_select_files_handler.cc b/chrome/browser/chromeos/arc/fileapi/arc_select_files_handler.cc
index f7eef64..6769451 100644
--- a/chrome/browser/chromeos/arc/fileapi/arc_select_files_handler.cc
+++ b/chrome/browser/chromeos/arc/fileapi/arc_select_files_handler.cc
@@ -95,6 +95,7 @@
     ConvertToElementVector(value.FindKey("dirNames"),
                            &result->directory_elements);
     ConvertToElementVector(value.FindKey("fileNames"), &result->file_elements);
+    // TODO(niwa): Fill result->search_query.
   }
   std::move(callback).Run(std::move(result));
 }
@@ -246,14 +247,15 @@
   ui::SelectFileDialog::FileTypeInfo file_type_info;
   BuildFileTypeInfo(request, &file_type_info);
   base::FilePath default_path = GetInitialFilePath(request);
+  std::string search_query = request->search_query.value_or(std::string());
 
   // Android picker apps should be shown in GET_CONTENT mode.
   bool show_android_picker_apps =
       request->action_type == mojom::SelectFilesActionType::GET_CONTENT;
 
-  bool success =
-      dialog_holder_->SelectFile(dialog_type, default_path, &file_type_info,
-                                 request->task_id, show_android_picker_apps);
+  bool success = dialog_holder_->SelectFile(
+      dialog_type, default_path, &file_type_info, request->task_id,
+      search_query, show_android_picker_apps);
   if (!success) {
     std::move(callback_).Run(mojom::SelectFilesResult::New());
   }
@@ -376,6 +378,7 @@
     const base::FilePath& default_path,
     const ui::SelectFileDialog::FileTypeInfo* file_types,
     int task_id,
+    const std::string& search_query,
     bool show_android_picker_apps) {
   aura::Window* owner_window = nullptr;
   for (auto* window : ChromeLauncherController::instance()->GetArcWindows()) {
@@ -389,6 +392,7 @@
     return false;
   }
 
+  // TODO(niwa): Pass search query as well.
   SelectFileDialogExtension::Owner owner;
   owner.window = owner_window;
   owner.android_task_id = task_id;
diff --git a/chrome/browser/chromeos/arc/fileapi/arc_select_files_handler.h b/chrome/browser/chromeos/arc/fileapi/arc_select_files_handler.h
index 254ca24..b3fcd626 100644
--- a/chrome/browser/chromeos/arc/fileapi/arc_select_files_handler.h
+++ b/chrome/browser/chromeos/arc/fileapi/arc_select_files_handler.h
@@ -133,6 +133,7 @@
                           const base::FilePath& default_path,
                           const ui::SelectFileDialog::FileTypeInfo* file_types,
                           int task_id,
+                          const std::string& search_query,
                           bool show_android_picker_apps);
 
   virtual void ExecuteJavaScript(
diff --git a/chrome/browser/chromeos/arc/fileapi/arc_select_files_handler_unittest.cc b/chrome/browser/chromeos/arc/fileapi/arc_select_files_handler_unittest.cc
index 651b9ca..7d8ee4e 100644
--- a/chrome/browser/chromeos/arc/fileapi/arc_select_files_handler_unittest.cc
+++ b/chrome/browser/chromeos/arc/fileapi/arc_select_files_handler_unittest.cc
@@ -81,11 +81,12 @@
   explicit MockSelectFileDialogHolder(ui::SelectFileDialog::Listener* listener)
       : SelectFileDialogHolder(listener) {}
   ~MockSelectFileDialogHolder() override = default;
-  MOCK_METHOD5(SelectFile,
+  MOCK_METHOD6(SelectFile,
                bool(ui::SelectFileDialog::Type type,
                     const base::FilePath& default_path,
                     const ui::SelectFileDialog::FileTypeInfo* file_types,
                     int task_id,
+                    const std::string& search_query,
                     bool show_android_picker_apps));
   MOCK_METHOD2(ExecuteJavaScript,
                void(const std::string&, JavaScriptResultCallback));
@@ -113,7 +114,7 @@
     mock_dialog_holder_ = mock_dialog_holder.get();
     arc_select_files_handler_->SetDialogHolderForTesting(
         std::move(mock_dialog_holder));
-    ON_CALL(*mock_dialog_holder_, SelectFile(_, _, _, _, _))
+    ON_CALL(*mock_dialog_holder_, SelectFile(_, _, _, _, _, _))
         .WillByDefault(Return(true));
   }
 
@@ -133,7 +134,7 @@
     request->allow_multiple = request_allow_multiple;
 
     EXPECT_CALL(*mock_dialog_holder_,
-                SelectFile(expected_dialog_type, _, _, _,
+                SelectFile(expected_dialog_type, _, _, _, _,
                            expected_show_android_picker_apps))
         .Times(1);
 
@@ -204,7 +205,7 @@
       *mock_dialog_holder_,
       SelectFile(_, _,
                  testing::Pointee(FileTypeInfoMatcher(expected_file_type_info)),
-                 1234, _))
+                 1234, _, _))
       .Times(1);
 
   base::MockCallback<SelectFilesCallback> callback;
@@ -231,7 +232,7 @@
       *mock_dialog_holder_,
       SelectFile(_, _,
                  testing::Pointee(FileTypeInfoMatcher(expected_file_type_info)),
-                 1234, _))
+                 1234, _, _))
       .Times(1);
 
   base::MockCallback<SelectFilesCallback> callback;
@@ -250,7 +251,7 @@
       "/special/arc-documents-provider/testing.provider/doc:root");
 
   EXPECT_CALL(*mock_dialog_holder_,
-              SelectFile(_, FilePathMatcher(expected_file_path), _, _, _))
+              SelectFile(_, FilePathMatcher(expected_file_path), _, _, _, _))
       .Times(1);
 
   base::MockCallback<SelectFilesCallback> callback;
diff --git a/chrome/browser/chromeos/file_manager/devtools_listener.cc b/chrome/browser/chromeos/file_manager/devtools_listener.cc
index 9360eca..9f06b925 100644
--- a/chrome/browser/chromeos/file_manager/devtools_listener.cc
+++ b/chrome/browser/chromeos/file_manager/devtools_listener.cc
@@ -26,10 +26,6 @@
 
 namespace {
 
-base::span<const uint8_t> StringToSpan(const std::string& s) {
-  return base::as_bytes(base::make_span(s));
-}
-
 base::StringPiece SpanToStringPiece(const base::span<const uint8_t>& s) {
   return {reinterpret_cast<const char*>(s.data()), s.size()};
 }
@@ -37,7 +33,7 @@
 std::string EncodeURIComponent(const std::string& component) {
   url::RawCanonOutputT<char> encoded;
   url::EncodeURIComponent(component.c_str(), component.size(), &encoded);
-  return std::string(encoded.data(), encoded.length());
+  return {encoded.data(), encoded.length()};
 }
 
 }  // namespace
@@ -91,28 +87,28 @@
 
 void DevToolsListener::Start(content::DevToolsAgentHost* host) {
   std::string enable_runtime = "{\"id\":10,\"method\":\"Runtime.enable\"}";
-  host->DispatchProtocolMessage(this, StringToSpan(enable_runtime));
+  SendCommandMessage(host, enable_runtime);
 
   std::string enable_page = "{\"id\":11,\"method\":\"Page.enable\"}";
-  host->DispatchProtocolMessage(this, StringToSpan(enable_page));
+  SendCommandMessage(host, enable_page);
 }
 
 bool DevToolsListener::StartJSCoverage(content::DevToolsAgentHost* host) {
   std::string enable_profiler = "{\"id\":20,\"method\":\"Profiler.enable\"}";
-  host->DispatchProtocolMessage(this, StringToSpan(enable_profiler));
+  SendCommandMessage(host, enable_profiler);
 
   std::string start_precise_coverage =
       "{\"id\":21,\"method\":\"Profiler.startPreciseCoverage\",\"params\":{"
       "\"callCount\":true,\"detailed\":true}}";
-  host->DispatchProtocolMessage(this, StringToSpan(start_precise_coverage));
+  SendCommandMessage(host, start_precise_coverage);
 
   std::string enable_debugger = "{\"id\":22,\"method\":\"Debugger.enable\"}";
-  host->DispatchProtocolMessage(this, StringToSpan(enable_debugger));
+  SendCommandMessage(host, enable_debugger);
 
-  std::string skip_pauses =
+  std::string skip_all_pauses =
       "{\"id\":23,\"method\":\"Debugger.setSkipAllPauses\""
       ",\"params\":{\"skip\":true}}";
-  host->DispatchProtocolMessage(this, StringToSpan(skip_pauses));
+  SendCommandMessage(host, skip_all_pauses);
 
   return true;
 }
@@ -120,19 +116,19 @@
 void DevToolsListener::StopAndStoreJSCoverage(content::DevToolsAgentHost* host,
                                               const base::FilePath& store,
                                               const std::string& test) {
-  std::string precise_coverage =
+  std::string get_precise_coverage =
       "{\"id\":40,\"method\":\"Profiler.takePreciseCoverage\"}";
-  host->DispatchProtocolMessage(this, StringToSpan(precise_coverage));
-  AwaitMessageResponse(40);
+  SendCommandMessage(host, get_precise_coverage);
+  AwaitCommandResponse(40);
 
   script_coverage_.reset(value_.release());
   StoreScripts(host, store);
 
-  std::string debugger = "{\"id\":41,\"method\":\"Debugger.disable\"}";
-  host->DispatchProtocolMessage(this, StringToSpan(debugger));
+  std::string stop_debugger = "{\"id\":41,\"method\":\"Debugger.disable\"}";
+  SendCommandMessage(host, stop_debugger);
 
-  std::string profiler = "{\"id\":42,\"method\":\"Profiler.disable\"}";
-  host->DispatchProtocolMessage(this, StringToSpan(profiler));
+  std::string stop_profiler = "{\"id\":42,\"method\":\"Profiler.disable\"}";
+  SendCommandMessage(host, stop_profiler);
 
   base::DictionaryValue* result = nullptr;
   CHECK(script_coverage_->GetDictionary("result", &result));
@@ -175,7 +171,7 @@
   script_id_map_.clear();
   script_.clear();
 
-  AwaitMessageResponse(42);
+  AwaitCommandResponse(42);
   value_.reset();
 }
 
@@ -192,12 +188,12 @@
     if (url.empty())
       continue;
 
-    std::string script_source = base::StringPrintf(
+    std::string get_script_source = base::StringPrintf(
         "{\"id\":50,\"method\":\"Debugger.getScriptSource\""
         ",\"params\":{\"scriptId\":\"%s\"}}",
         id.c_str());
-    host->DispatchProtocolMessage(this, StringToSpan(script_source));
-    AwaitMessageResponse(50);
+    SendCommandMessage(host, get_script_source);
+    AwaitCommandResponse(50);
 
     base::DictionaryValue* result = nullptr;
     CHECK(value_->GetDictionary("result", &result));
@@ -230,7 +226,13 @@
   }
 }
 
-void DevToolsListener::AwaitMessageResponse(int id) {
+void DevToolsListener::SendCommandMessage(content::DevToolsAgentHost* host,
+                                          const std::string& command) {
+  auto message = base::as_bytes(base::make_span(command));
+  host->DispatchProtocolMessage(this, message);
+}
+
+void DevToolsListener::AwaitCommandResponse(int id) {
   value_.reset();
   value_id_ = id;
 
@@ -245,22 +247,22 @@
   if (!navigated_)
     return;
 
-  std::unique_ptr<base::DictionaryValue> response = base::DictionaryValue::From(
+  std::unique_ptr<base::DictionaryValue> value = base::DictionaryValue::From(
       base::JSONReader::ReadDeprecated(SpanToStringPiece(message)));
-  CHECK(response);
+  CHECK(value);
 
-  std::string* method = response->FindStringPath("method");
+  std::string* method = value->FindStringPath("method");
   if (method) {
     if (*method == "Runtime.executionContextsCreated")
       script_.clear();
     else if (*method == "Debugger.scriptParsed")
-      script_.push_back(std::move(response));
+      script_.push_back(std::move(value));
     return;
   }
 
-  base::Optional<int> id = response->FindIntPath("id");
+  base::Optional<int> id = value->FindIntPath("id");
   if (id.has_value() && id.value() == value_id_) {
-    value_.reset(response.release());
+    value_.reset(value.release());
     CHECK(value_closure_);
     std::move(value_closure_).Run();
   }
diff --git a/chrome/browser/chromeos/file_manager/devtools_listener.h b/chrome/browser/chromeos/file_manager/devtools_listener.h
index 5b995332..39d369d 100644
--- a/chrome/browser/chromeos/file_manager/devtools_listener.h
+++ b/chrome/browser/chromeos/file_manager/devtools_listener.h
@@ -16,62 +16,63 @@
 
 namespace file_manager {
 
-// Collects code coverage from a WebContents during a
-// browser test using Chrome Devtools Protocol (CDP).
+// Collects code coverage from a WebContents, during a browser test
+// for example, using Chrome Devtools Protocol (CDP).
 class DevToolsListener : public content::DevToolsAgentHostClient {
  public:
-  // Attaches to a host and enables CDP.
+  // Attaches to host and enables CDP.
   DevToolsListener(content::DevToolsAgentHost* host, uint32_t uuid);
   ~DevToolsListener() override;
 
-  // Starts code coverage.
+  // Host navigation starts code coverage.
   void Navigated(content::DevToolsAgentHost* host);
 
   // Returns true if host has started code coverage.
   bool HasCoverage(content::DevToolsAgentHost* host);
 
-  // If host HasCoverage() collect the coverage and
-  // write it into the |store|.
+  // If host HasCoverage(), collect it and save it in |store|.
   void GetCoverage(content::DevToolsAgentHost* host,
                    const base::FilePath& store,
                    const std::string& test);
 
-  // Detaches from a host.
+  // Detaches from host.
   void Detach(content::DevToolsAgentHost* host);
 
-  // Returns a string that uniquely identifies a host
-  // with an optional prefix.
+  // Returns a unique host identifier, with optional |prefix|.
   static std::string HostString(content::DevToolsAgentHost* host,
                                 const std::string& prefix = {});
 
  private:
-  // Enable CDP on host.
+  // Starts CDP session on host.
   void Start(content::DevToolsAgentHost* host);
 
-  // Starts JavaScript code coverage on host.
+  // Starts JavaScript (JS) code coverage on host.
   bool StartJSCoverage(content::DevToolsAgentHost* host);
 
-  // Collects JavaScript code coverage on host and writes
-  // it into the |store|.
+  // Collects JavaScript coverage from host and saves it in |store|.
   void StopAndStoreJSCoverage(content::DevToolsAgentHost* host,
                               const base::FilePath& store,
                               const std::string& test);
 
-  // Stores scripts that are parsed during execution on host.
+  // Stores JS scripts used during code execution on host.
   void StoreScripts(content::DevToolsAgentHost* host,
                     const base::FilePath& store);
 
-  // Await CDP response to command |id|.
-  void AwaitMessageResponse(int id);
+  // Sends CDP commands to host.
+  void SendCommandMessage(content::DevToolsAgentHost* host,
+                          const std::string& command);
 
-  // Receives CDP messages sent by host.
+  // Awaits CDP response to command |id|.
+  void AwaitCommandResponse(int id);
+
+  // Receives CDP messages from host.
   void DispatchProtocolMessage(content::DevToolsAgentHost* host,
                                base::span<const uint8_t> message) override;
 
   // Returns true if URL should be attached to.
   bool MayAttachToURL(const GURL& url, bool is_webui) override;
 
-  // Clean up when host is closed.
+  // Called if host was shut down (closed).
   void AgentHostClosed(content::DevToolsAgentHost* host) override;
 
  private:
diff --git a/chrome/browser/chromeos/file_manager/file_manager_browsertest_base.cc b/chrome/browser/chromeos/file_manager/file_manager_browsertest_base.cc
index 2815e8a..35f60c11 100644
--- a/chrome/browser/chromeos/file_manager/file_manager_browsertest_base.cc
+++ b/chrome/browser/chromeos/file_manager/file_manager_browsertest_base.cc
@@ -1351,7 +1351,7 @@
   std::string EncodeURI(const std::string& component) {
     url::RawCanonOutputT<char> encoded;
     url::EncodeURIComponent(component.c_str(), component.size(), &encoded);
-    return std::string(encoded.data(), encoded.length());
+    return {encoded.data(), encoded.length()};
   }
 
   DISALLOW_COPY_AND_ASSIGN(DocumentsProviderTestVolume);
diff --git a/chrome/browser/chromeos/policy/device_policy_decoder_chromeos.cc b/chrome/browser/chromeos/policy/device_policy_decoder_chromeos.cc
index 033c2d2..89cf7bd 100644
--- a/chrome/browser/chromeos/policy/device_policy_decoder_chromeos.cc
+++ b/chrome/browser/chromeos/policy/device_policy_decoder_chromeos.cc
@@ -1872,6 +1872,15 @@
           nullptr);
     }
   }
+
+  if (policy.has_arc_data_snapshot_hours()) {
+    const em::DeviceArcDataSnapshotHoursProto& container(
+        policy.arc_data_snapshot_hours());
+    if (container.has_arc_data_snapshot_hours()) {
+      SetJsonDevicePolicy(key::kDeviceArcDataSnapshotHours,
+                          container.arc_data_snapshot_hours(), policies);
+    }
+  }
 }
 
 }  // namespace
diff --git a/chrome/browser/chromeos/usb/cros_usb_detector.cc b/chrome/browser/chromeos/usb/cros_usb_detector.cc
index 6b62d17..3436559 100644
--- a/chrome/browser/chromeos/usb/cros_usb_detector.cc
+++ b/chrome/browser/chromeos/usb/cros_usb_detector.cc
@@ -4,11 +4,14 @@
 
 #include "chrome/browser/chromeos/usb/cros_usb_detector.h"
 
+#include <fcntl.h>
+
 #include <string>
 #include <utility>
 
 #include "ash/public/cpp/notification_utils.h"
 #include "base/bind_helpers.h"
+#include "base/files/file_util.h"
 #include "base/metrics/histogram_macros.h"
 #include "base/stl_util.h"
 #include "chrome/browser/chromeos/crostini/crostini_features.h"
@@ -539,10 +542,27 @@
   }
 }
 
+bool CrosUsbDetector::IsDeviceAlreadySharedWithVm(const std::string& vm_name,
+                                                  const std::string& guid) {
+  for (const auto& device : usb_devices_) {
+    if (device.guid == guid && device.shared_vm_name == vm_name &&
+        device.guest_port) {
+      VLOG(1) << "Device " << device.label << " is already shared with vm "
+              << vm_name;
+      return true;
+    }
+  }
+  return false;
+}
+
 void CrosUsbDetector::AttachUsbDeviceToVm(
     const std::string& vm_name,
     const std::string& guid,
     base::OnceCallback<void(bool success)> callback) {
+  if (IsDeviceAlreadySharedWithVm(vm_name, guid)) {
+    std::move(callback).Run(true);
+    return;
+  }
   uint32_t allowed_interfaces_mask = 0;
   for (auto& device : usb_devices_) {
     if (device.guid == guid) {
@@ -575,11 +595,37 @@
 
   const auto& device_info = it->second;
 
+  auto claim_it = devices_claimed_.find(guid);
+  if (claim_it != devices_claimed_.end()) {
+    if (claim_it->second.device_file.IsValid()) {
+      // We take a dup here which will be closed if DoVmAttach fails.
+      base::ScopedFD device_fd(
+          claim_it->second.device_file.Duplicate().TakePlatformFile());
+      DoVmAttach(vm_name, device_info.Clone(), std::move(device_fd),
+                 std::move(callback));
+    } else {
+      LOG(WARNING) << "Device " << guid << " already claimed and awaiting fd.";
+      std::move(callback).Run(false);
+    }
+    return;
+  }
+
   VLOG(1) << "Opening " << guid << " with mask " << std::hex
           << allowed_interfaces_mask;
+
+  base::ScopedFD read_end, write_end;
+  if (!base::CreatePipe(&read_end, &write_end, /*non_blocking=*/true)) {
+    LOG(ERROR) << "Couldn't create pipe for " << guid;
+    std::move(callback).Run(false);
+    return;
+  }
+
+  VLOG(1) << "Saving lifeline_fd " << write_end.get();
+  devices_claimed_[guid].lifeline_file = base::File(std::move(write_end));
+
   // Open a file descriptor to pass to CrostiniManager & Concierge.
   device_manager_->OpenFileDescriptor(
-      guid, allowed_interfaces_mask,
+      guid, allowed_interfaces_mask, mojo::PlatformHandle(std::move(read_end)),
       base::BindOnce(&CrosUsbDetector::OnAttachUsbDeviceOpened,
                      weak_ptr_factory_.GetWeakPtr(), vm_name,
                      device_info.Clone(), std::move(callback)));
@@ -614,6 +660,7 @@
 
   if (!guest_port) {
     LOG(ERROR) << "No port found to detach " << guid;
+    RelinquishDeviceClaim(guid);
     std::move(callback).Run(/*success=*/true);
     return;
   }
@@ -647,23 +694,21 @@
     std::move(callback).Run(/*success=*/false);
     return;
   }
-  base::ScopedFD fd(file.TakePlatformFile());
+  devices_claimed_[device_info->guid].device_file = file.Duplicate();
   if (!manager()) {
     LOG(ERROR) << "Attaching device without Crostini manager instance";
     std::move(callback).Run(/*success=*/false);
     return;
   }
-  for (const auto& device : usb_devices_) {
-    if (device.guid == device_info->guid) {
-      if (device.shared_vm_name == vm_name && device.guest_port) {
-        LOG(ERROR) << "Device " << device.label << " is already shared";
-        // The device is already attached.
-        std::move(callback).Run(/*success=*/true);
-        return;
-      }
-    }
-  }
+  DoVmAttach(vm_name, device_info.Clone(),
+             base::ScopedFD(file.TakePlatformFile()), std::move(callback));
+}
 
+void CrosUsbDetector::DoVmAttach(
+    const std::string& vm_name,
+    device::mojom::UsbDeviceInfoPtr device_info,
+    base::ScopedFD fd,
+    base::OnceCallback<void(bool success)> callback) {
   vm_tools::concierge::AttachUsbDeviceRequest request;
   request.set_vm_name(vm_name);
   request.set_owner_id(crostini::CryptohomeIdForProfile(profile()));
@@ -727,6 +772,7 @@
       break;
     }
   }
+  RelinquishDeviceClaim(guid);
   SignalUsbDeviceObservers();
   std::move(callback).Run(success);
 }
@@ -743,4 +789,16 @@
   }
   AttachUsbDeviceToVm(vm_name, guid, std::move(callback));
 }
+
+void CrosUsbDetector::RelinquishDeviceClaim(const std::string& guid) {
+  auto it = devices_claimed_.find(guid);
+  if (it != devices_claimed_.end()) {
+    VLOG(1) << "Closing lifeline_fd "
+            << it->second.lifeline_file.GetPlatformFile();
+    devices_claimed_.erase(it);
+  } else {
+    LOG(ERROR) << "Relinquishing device with no prior claim: " << guid;
+  }
+}
+
 }  // namespace chromeos
diff --git a/chrome/browser/chromeos/usb/cros_usb_detector.h b/chrome/browser/chromeos/usb/cros_usb_detector.h
index fe6ffd1..47ec587 100644
--- a/chrome/browser/chromeos/usb/cros_usb_detector.h
+++ b/chrome/browser/chromeos/usb/cros_usb_detector.h
@@ -113,6 +113,10 @@
                              const std::string& guid,
                              base::OnceCallback<void(bool success)> callback);
 
+  // Returns true if device was successfully shared with |vm_name|.
+  bool IsDeviceAlreadySharedWithVm(const std::string& vm_name,
+                                   const std::string& guid);
+
   void AddUsbDeviceObserver(CrosUsbDeviceObserver* observer);
   void RemoveUsbDeviceObserver(CrosUsbDeviceObserver* observer);
   void SignalUsbDeviceObservers();
@@ -159,6 +163,11 @@
                                base::OnceCallback<void(bool success)> callback,
                                base::File file);
 
+  void DoVmAttach(const std::string& vm_name,
+                  device::mojom::UsbDeviceInfoPtr device_info,
+                  base::ScopedFD fd,
+                  base::OnceCallback<void(bool success)> callback);
+
   // Callbacks for when the USB device state has been updated.
   void OnUsbDeviceAttachFinished(
       const std::string& vm_name,
@@ -182,6 +191,8 @@
   bool ShouldShowNotification(const device::mojom::UsbDeviceInfo& device_info,
                               uint32_t allowed_interfaces_mask);
 
+  void RelinquishDeviceClaim(const std::string& guid);
+
   mojo::Remote<device::mojom::UsbDeviceManager> device_manager_;
   mojo::AssociatedReceiver<device::mojom::UsbDeviceManagerClient>
       client_receiver_{this};
@@ -195,6 +206,16 @@
   // A mapping from GUID -> UsbDeviceInfo for each attached USB device
   std::map<std::string, device::mojom::UsbDeviceInfoPtr> available_device_info_;
 
+  // Populated when we open the device path on the host. Acts as a claim on the
+  // device even if the intended VM has not started yet. Removed when the device
+  // is shared successfully with the VM. When an file is closed (here or by the
+  // VM,  PermissionBroker will reattach the previous host drivers (if any).
+  struct DeviceClaim {
+    base::File device_file;
+    base::File lifeline_file;
+  };
+  std::map<std::string, DeviceClaim> devices_claimed_;
+
   std::vector<CrosUsbDeviceInfo> usb_devices_;
 
   base::ObserverList<CrosUsbDeviceObserver> usb_device_observers_;
diff --git a/chrome/browser/devtools/devtools_contents_resizing_strategy.cc b/chrome/browser/devtools/devtools_contents_resizing_strategy.cc
index b11cd814..c2a2157 100644
--- a/chrome/browser/devtools/devtools_contents_resizing_strategy.cc
+++ b/chrome/browser/devtools/devtools_contents_resizing_strategy.cc
@@ -6,28 +6,30 @@
 
 #include <algorithm>
 
-DevToolsContentsResizingStrategy::DevToolsContentsResizingStrategy()
-    : hide_inspected_contents_(false) {
-}
+#include "base/check_op.h"
+
+DevToolsContentsResizingStrategy::DevToolsContentsResizingStrategy() = default;
 
 DevToolsContentsResizingStrategy::DevToolsContentsResizingStrategy(
-    const gfx::Rect& bounds)
+    const gfx::Rect& bounds,
+    bool is_docked)
     : bounds_(bounds),
       hide_inspected_contents_(bounds_.IsEmpty() && !bounds_.x() &&
-          !bounds_.y()) {
-}
-
+                               !bounds_.y()),
+      is_docked_(is_docked) {}
 
 void DevToolsContentsResizingStrategy::CopyFrom(
     const DevToolsContentsResizingStrategy& strategy) {
   bounds_ = strategy.bounds();
   hide_inspected_contents_ = strategy.hide_inspected_contents();
+  is_docked_ = strategy.is_docked();
 }
 
 bool DevToolsContentsResizingStrategy::Equals(
     const DevToolsContentsResizingStrategy& strategy) {
   return bounds_ == strategy.bounds() &&
-      hide_inspected_contents_ == strategy.hide_inspected_contents();
+         hide_inspected_contents_ == strategy.hide_inspected_contents() &&
+         is_docked_ == strategy.is_docked();
 }
 
 void ApplyDevToolsContentsResizingStrategy(
@@ -39,6 +41,7 @@
       0, 0, container_size.width(), container_size.height());
 
   const gfx::Rect& bounds = strategy.bounds();
+
   if (bounds.size().IsEmpty() && !strategy.hide_inspected_contents()) {
     new_contents_bounds->SetRect(
         0, 0, container_size.width(), container_size.height());
@@ -49,5 +52,22 @@
   int top = std::min(bounds.y(), container_size.height());
   int width = std::min(bounds.width(), container_size.width() - left);
   int height = std::min(bounds.height(), container_size.height() - top);
+
+  if (strategy.is_docked()) {
+    // Devtools console requires at least 240 pixels when docked.
+    // https://cs.chromium.org/chromium/src/third_party/blink/renderer/devtools/front_end/ui/InspectorView.js?l=38&rcl=f8763532a3fe4f7d028f4cb23f56b289efbb70c0
+    constexpr int kDevtoolsMinWidth = 240;
+    // If container_size.width() == bounds.width(), dev tools is docked at
+    // the bottom, otherwise it's docked to the right or left.
+    const int available_content_width = container_size.width() == bounds.width()
+                                            ? bounds.width()
+                                            : container_size.width() - width;
+    DCHECK_GE(available_content_width, 0);
+    if (available_content_width < kDevtoolsMinWidth) {
+      const int width_adjustment = kDevtoolsMinWidth - available_content_width;
+      DCHECK_GE(width, width_adjustment);
+      width -= width_adjustment;
+    }
+  }
   new_contents_bounds->SetRect(left, top, width, height);
 }
diff --git a/chrome/browser/devtools/devtools_contents_resizing_strategy.h b/chrome/browser/devtools/devtools_contents_resizing_strategy.h
index 9a8d22c..b472df7f 100644
--- a/chrome/browser/devtools/devtools_contents_resizing_strategy.h
+++ b/chrome/browser/devtools/devtools_contents_resizing_strategy.h
@@ -15,21 +15,24 @@
 class DevToolsContentsResizingStrategy {
  public:
   DevToolsContentsResizingStrategy();
-  explicit DevToolsContentsResizingStrategy(
-      const gfx::Rect& bounds);
+  DevToolsContentsResizingStrategy(const gfx::Rect& bounds, bool is_docked);
 
   void CopyFrom(const DevToolsContentsResizingStrategy& strategy);
   bool Equals(const DevToolsContentsResizingStrategy& strategy);
 
   const gfx::Rect& bounds() const { return bounds_; }
   bool hide_inspected_contents() const { return hide_inspected_contents_; }
+  bool is_docked() const { return is_docked_; }
 
  private:
   // Contents bounds. When non-empty, used instead of insets.
   gfx::Rect bounds_;
 
-  // Determines whether inspected contents is visible.
-  bool hide_inspected_contents_;
+  // Whether inspected contents is hidden.
+  bool hide_inspected_contents_ = false;
+
+  // Whether devtools is docked.
+  bool is_docked_ = false;
 
   DISALLOW_COPY_AND_ASSIGN(DevToolsContentsResizingStrategy);
 };
diff --git a/chrome/browser/devtools/devtools_window.cc b/chrome/browser/devtools/devtools_window.cc
index d6c3737..3e85ed10 100644
--- a/chrome/browser/devtools/devtools_window.cc
+++ b/chrome/browser/devtools/devtools_window.cc
@@ -1360,7 +1360,7 @@
 }
 
 void DevToolsWindow::SetInspectedPageBounds(const gfx::Rect& rect) {
-  DevToolsContentsResizingStrategy strategy(rect);
+  DevToolsContentsResizingStrategy strategy(rect, is_docked_);
   if (contents_resizing_strategy_.Equals(strategy))
     return;
 
diff --git a/chrome/browser/download/download_file_icon_extractor.h b/chrome/browser/download/download_file_icon_extractor.h
index 454790a2..43a03ab 100644
--- a/chrome/browser/download/download_file_icon_extractor.h
+++ b/chrome/browser/download/download_file_icon_extractor.h
@@ -18,7 +18,7 @@
   // Callback for |ExtractIconForPath|. The parameter is a URL as a string for a
   // suitable icon. The string could be empty if the icon could not be
   // determined.
-  typedef base::Callback<void(const std::string&)> IconURLCallback;
+  typedef base::OnceCallback<void(const std::string&)> IconURLCallback;
 
   virtual ~DownloadFileIconExtractor() {}
 
diff --git a/chrome/browser/download/download_query.cc b/chrome/browser/download/download_query.cc
index 57d748d..4a2127a 100644
--- a/chrome/browser/download/download_query.cc
+++ b/chrome/browser/download/download_query.cc
@@ -143,11 +143,11 @@
 // and |accessor|. |accessor| is conceptually a function that takes a
 // DownloadItem and returns one of its fields, which is then compared to
 // |value|.
-template<typename ValueType>
+template <typename ValueType>
 bool FieldMatches(
     const ValueType& value,
     ComparisonType cmptype,
-    const base::Callback<ValueType(const DownloadItem&)>& accessor,
+    const base::RepeatingCallback<ValueType(const DownloadItem&)>& accessor,
     const DownloadItem& item) {
   switch (cmptype) {
     case LT: return accessor.Run(item) < value;
@@ -164,8 +164,8 @@
     ValueType (*accessor)(const DownloadItem&)) {
   ValueType cpp_value;
   if (!GetAs(value, &cpp_value)) return DownloadQuery::FilterCallback();
-  return base::Bind(&FieldMatches<ValueType>, cpp_value, cmptype,
-                    base::Bind(accessor));
+  return base::BindRepeating(&FieldMatches<ValueType>, cpp_value, cmptype,
+                             base::BindRepeating(accessor));
 }
 
 // Returns true if |accessor.Run(item)| matches |pattern|.
@@ -256,13 +256,13 @@
 }
 
 void DownloadQuery::AddFilter(DownloadItem::DownloadState state) {
-  AddFilter(base::Bind(&FieldMatches<DownloadItem::DownloadState>, state, EQ,
-      base::Bind(&GetState)));
+  AddFilter(base::BindRepeating(&FieldMatches<DownloadItem::DownloadState>,
+                                state, EQ, base::BindRepeating(&GetState)));
 }
 
 void DownloadQuery::AddFilter(DownloadDangerType danger) {
-  AddFilter(base::Bind(&FieldMatches<DownloadDangerType>, danger, EQ,
-      base::Bind(&GetDangerType)));
+  AddFilter(base::BindRepeating(&FieldMatches<DownloadDangerType>, danger, EQ,
+                                base::BindRepeating(&GetDangerType)));
 }
 
 bool DownloadQuery::AddFilter(DownloadQuery::FilterType type,
@@ -286,7 +286,7 @@
       std::vector<base::string16> query_terms;
       return GetAs(value, &query_terms) &&
              (query_terms.empty() ||
-              AddFilter(base::Bind(&MatchesQuery, query_terms)));
+              AddFilter(base::BindRepeating(&MatchesQuery, query_terms)));
     }
     case FILTER_ENDED_AFTER:
       return AddFilter(BuildFilter<std::string>(value, GT, &GetEndTime));
@@ -345,8 +345,9 @@
   template<typename ValueType>
   static Sorter Build(DownloadQuery::SortDirection adirection,
                          ValueType (*accessor)(const DownloadItem&)) {
-    return Sorter(adirection, base::Bind(&Compare<ValueType>,
-        base::Bind(accessor)));
+    return Sorter(adirection,
+                  base::BindRepeating(&Compare<ValueType>,
+                                      base::BindRepeating(accessor)));
   }
 
   Sorter(DownloadQuery::SortDirection adirection,
diff --git a/chrome/browser/download/download_query.h b/chrome/browser/download/download_query.h
index 967d99c99..0e0d7a0 100644
--- a/chrome/browser/download/download_query.h
+++ b/chrome/browser/download/download_query.h
@@ -48,7 +48,8 @@
   // FilterCallback is a Callback that takes a DownloadItem and returns true if
   // the item matches the filter and false otherwise.
   // query.AddFilter(base::Bind(&YourFilterFunction));
-  typedef base::Callback<bool(const download::DownloadItem&)> FilterCallback;
+  typedef base::RepeatingCallback<bool(const download::DownloadItem&)>
+      FilterCallback;
 
   // All times are ISO 8601 strings.
   enum FilterType {
diff --git a/chrome/browser/engagement/site_engagement_service_unittest.cc b/chrome/browser/engagement/site_engagement_service_unittest.cc
index 7270228..09a9743 100644
--- a/chrome/browser/engagement/site_engagement_service_unittest.cc
+++ b/chrome/browser/engagement/site_engagement_service_unittest.cc
@@ -553,7 +553,7 @@
 }
 
 // Disabled due to flakiness on Builder Linux Tests. crbug.com/1137759
-#if defined(OS_LINUX)
+#if defined(OS_LINUX) || defined(OS_CHROMEOS)
 #define MAYBE_CheckHistograms DISABLED_CheckHistograms
 #else
 #define MAYBE_CheckHistograms CheckHistograms
diff --git a/chrome/browser/extensions/api/downloads/downloads_api.cc b/chrome/browser/extensions/api/downloads/downloads_api.cc
index 9c28cf3..49e8773 100644
--- a/chrome/browser/extensions/api/downloads/downloads_api.cc
+++ b/chrome/browser/extensions/api/downloads/downloads_api.cc
@@ -329,7 +329,7 @@
 
  private:
   void OnIconLoadComplete(float scale,
-                          const IconURLCallback& callback,
+                          IconURLCallback callback,
                           gfx::Image icon);
 
   base::CancelableTaskTracker cancelable_task_tracker_;
@@ -347,17 +347,16 @@
   im->LoadIcon(
       path, icon_size,
       base::BindOnce(&DownloadFileIconExtractorImpl::OnIconLoadComplete,
-                     base::Unretained(this), scale, callback),
+                     base::Unretained(this), scale, std::move(callback)),
       &cancelable_task_tracker_);
   return true;
 }
 
-void DownloadFileIconExtractorImpl::OnIconLoadComplete(
-    float scale,
-    const IconURLCallback& callback,
-    gfx::Image icon) {
+void DownloadFileIconExtractorImpl::OnIconLoadComplete(float scale,
+                                                       IconURLCallback callback,
+                                                       gfx::Image icon) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
-  callback.Run(
+  std::move(callback).Run(
       icon.IsEmpty()
           ? std::string()
           : webui::GetBitmapDataUrl(
@@ -614,7 +613,7 @@
     if (incognito_manager)
       incognito_manager->GetAllDownloads(&all_items);
   }
-  query_out.AddFilter(base::Bind(&ShouldExport));
+  query_out.AddFilter(base::BindRepeating(&ShouldExport));
   query_out.Search(all_items.begin(), all_items.end(), results);
 }
 
@@ -1610,10 +1609,9 @@
   if (web_contents && web_contents->GetRenderWidgetHostView())
     scale = web_contents->GetRenderWidgetHostView()->GetDeviceScaleFactor();
   EXTENSION_FUNCTION_VALIDATE(icon_extractor_->ExtractIconURLForPath(
-      download_item->GetTargetFilePath(),
-      scale,
+      download_item->GetTargetFilePath(), scale,
       IconLoaderSizeFromPixelSize(icon_size),
-      base::Bind(&DownloadsGetFileIconFunction::OnIconURLExtracted, this)));
+      base::BindOnce(&DownloadsGetFileIconFunction::OnIconURLExtracted, this)));
   return RespondLater();
 }
 
diff --git a/chrome/browser/extensions/api/downloads/downloads_api_browsertest.cc b/chrome/browser/extensions/api/downloads/downloads_api_browsertest.cc
index 55dc967..386e702 100644
--- a/chrome/browser/extensions/api/downloads/downloads_api_browsertest.cc
+++ b/chrome/browser/extensions/api/downloads/downloads_api_browsertest.cc
@@ -700,7 +700,7 @@
     EXPECT_EQ(expected_icon_size_, icon_size);
     if (expected_path_ == path &&
         expected_icon_size_ == icon_size) {
-      callback_ = callback;
+      callback_ = std::move(callback);
       content::GetUIThreadTaskRunner({})->PostTask(
           FROM_HERE, base::BindOnce(&MockIconExtractorImpl::RunCallback,
                                     base::Unretained(this)));
@@ -712,7 +712,8 @@
 
  private:
   void RunCallback() {
-    callback_.Run(response_);
+    DCHECK(callback_);
+    std::move(callback_).Run(response_);
     // Drop the reference on extension function to avoid memory leaks.
     callback_ = IconURLCallback();
   }
diff --git a/chrome/browser/extensions/api/virtual_keyboard_private/chrome_virtual_keyboard_delegate.cc b/chrome/browser/extensions/api/virtual_keyboard_private/chrome_virtual_keyboard_delegate.cc
index 7394ee1..19f5426 100644
--- a/chrome/browser/extensions/api/virtual_keyboard_private/chrome_virtual_keyboard_delegate.cc
+++ b/chrome/browser/extensions/api/virtual_keyboard_private/chrome_virtual_keyboard_delegate.cc
@@ -423,9 +423,10 @@
   features->AppendString(GenerateFeatureFlag(
       "mozcinputlogic",
       base::FeatureList::IsEnabled(chromeos::features::kImeInputLogicMozc)));
-  // Flag used to enable UIL Mojo APIs instead of NaCl APIs.
+  // Flag used to enable system built-in IME decoder instead of NaCl.
   features->AppendString(GenerateFeatureFlag(
-      "usemojodecoder", chromeos::features::IsImeSandboxEnabled()));
+      "usemojodecoder",
+      base::FeatureList::IsEnabled(chromeos::features::kImeMojoDecoder)));
   features->AppendString(GenerateFeatureFlag(
       "borderedkey", base::FeatureList::IsEnabled(
                          chromeos::features::kVirtualKeyboardBorderedKey)));
diff --git a/chrome/browser/net/net_error_diagnostics_dialog_win.cc b/chrome/browser/net/net_error_diagnostics_dialog_win.cc
index c809095d..5c2d971 100644
--- a/chrome/browser/net/net_error_diagnostics_dialog_win.cc
+++ b/chrome/browser/net/net_error_diagnostics_dialog_win.cc
@@ -89,7 +89,8 @@
       Profile::FromBrowserContext(web_contents->GetBrowserContext());
   // The Windows diagnostic tool logs URLs it's run with, so it shouldn't be
   // used with incognito or guest profiles.  See https://crbug.com/929141
-  return !profile->IsOffTheRecord() && !profile->IsGuestSession();
+  return !profile->IsIncognitoProfile() && !profile->IsGuestSession() &&
+         !profile->IsEphemeralGuestProfile();
 }
 
 void ShowNetworkDiagnosticsDialog(content::WebContents* web_contents,
diff --git a/chrome/browser/notifications/notification_platform_bridge_mac_unnotification.h b/chrome/browser/notifications/notification_platform_bridge_mac_unnotification.h
index 1b70c495..e9f387d 100644
--- a/chrome/browser/notifications/notification_platform_bridge_mac_unnotification.h
+++ b/chrome/browser/notifications/notification_platform_bridge_mac_unnotification.h
@@ -5,6 +5,8 @@
 #ifndef CHROME_BROWSER_NOTIFICATIONS_NOTIFICATION_PLATFORM_BRIDGE_MAC_UNNOTIFICATION_H_
 #define CHROME_BROWSER_NOTIFICATIONS_NOTIFICATION_PLATFORM_BRIDGE_MAC_UNNOTIFICATION_H_
 
+#import <Foundation/Foundation.h>
+
 #include <memory>
 #include <string>
 
@@ -51,8 +53,6 @@
 
   // Request permission to send notifications
   void RequestPermission();
-  // Create default categories for banners and alerts
-  void CreateDefaultCategories();
 
  private:
   // Cocoa class that receives callbacks from the UNUserNotificationCenter.
@@ -64,6 +64,9 @@
 
   // An object that keeps temp files alive long enough for macOS to pick up.
   NotificationImageRetainer image_retainer_;
+
+  // An object that carries the categories for the notifications
+  base::scoped_nsobject<NSMutableSet> categories_;
 };
 
 #endif  // CHROME_BROWSER_NOTIFICATIONS_NOTIFICATION_PLATFORM_BRIDGE_MAC_UNNOTIFICATION_H_
diff --git a/chrome/browser/notifications/notification_platform_bridge_mac_unnotification.mm b/chrome/browser/notifications/notification_platform_bridge_mac_unnotification.mm
index e3813a0..09e6500 100644
--- a/chrome/browser/notifications/notification_platform_bridge_mac_unnotification.mm
+++ b/chrome/browser/notifications/notification_platform_bridge_mac_unnotification.mm
@@ -19,19 +19,13 @@
 #import "chrome/browser/ui/cocoa/notifications/unnotification_response_builder_mac.h"
 #include "chrome/grit/generated_resources.h"
 #include "content/public/browser/browser_task_traits.h"
+#include "third_party/blink/public/common/notifications/notification_constants.h"
 #include "ui/base/l10n/l10n_util_mac.h"
 #include "ui/message_center/public/cpp/notification.h"
 
 @class UNMutableNotificationContent;
 @class UNUserNotificationCenter;
 
-namespace {
-
-NSString* const kCloseAndSettingsCategory = @"CLOSE_AND_SETTINGS";
-NSString* const kCloseCategory = @"CLOSE";
-
-}  // namespace
-
 // A Cocoa class that represents the delegate of UNUserNotificationCenter and
 // can forward commands to C++.
 API_AVAILABLE(macosx(10.14))
@@ -49,12 +43,12 @@
     NotificationPlatformBridgeMacUNNotification(
         UNUserNotificationCenter* notification_center)
     : delegate_([UNNotificationCenterDelegate alloc]),
-      notification_center_([notification_center retain]) {
+      notification_center_([notification_center retain]),
+      categories_([[NSMutableSet alloc] init]) {
   [notification_center_ setDelegate:delegate_.get()];
 
   // TODO(crbug/1129366): Determine when to request permission
   NotificationPlatformBridgeMacUNNotification::RequestPermission();
-  NotificationPlatformBridgeMacUNNotification::CreateDefaultCategories();
 }
 
 NotificationPlatformBridgeMacUNNotification::
@@ -68,8 +62,12 @@
     Profile* profile,
     const message_center::Notification& notification,
     std::unique_ptr<NotificationCommon::Metadata> metadata) {
-  base::scoped_nsobject<UNNotificationBuilder> builder(
-      [[UNNotificationBuilder alloc] init]);
+  base::scoped_nsobject<UNNotificationBuilder> builder([[UNNotificationBuilder
+      alloc]
+      initWithCloseLabel:l10n_util::GetNSString(IDS_NOTIFICATION_BUTTON_CLOSE)
+            optionsLabel:l10n_util::GetNSString(IDS_NOTIFICATION_BUTTON_MORE)
+           settingsLabel:l10n_util::GetNSString(
+                             IDS_NOTIFICATION_BUTTON_SETTINGS)]);
 
   base::string16 context_message =
       notification.items().empty()
@@ -97,6 +95,18 @@
     [builder setIconPath:base::SysUTF8ToNSString(path.value())];
   }
 
+  [builder setShowSettingsButton:notification.should_show_settings_button()];
+  const std::vector<message_center::ButtonInfo>& buttons =
+      notification.buttons();
+  if (!buttons.empty()) {
+    DCHECK_LE(buttons.size(), blink::kNotificationMaxActions);
+    NSString* buttonOne = base::SysUTF16ToNSString(buttons[0].title);
+    NSString* buttonTwo = nullptr;
+    if (buttons.size() > 1)
+      buttonTwo = base::SysUTF16ToNSString(buttons[1].title);
+    [builder setButtons:buttonOne secondaryButton:buttonTwo];
+  }
+
   [builder setOrigin:base::SysUTF8ToNSString(notification.origin_url().spec())];
   [builder setNotificationId:base::SysUTF8ToNSString(notification.id())];
   [builder setProfileId:base::SysUTF8ToNSString(GetProfileId(profile))];
@@ -108,14 +118,13 @@
       setNotificationType:[NSNumber numberWithInteger:static_cast<NSInteger>(
                                                           notification_type)]];
 
-  UNMutableNotificationContent* content = [builder buildUserNotification];
+  UNNotificationCategory* category = [builder buildCategory];
+  [categories_ addObject:category];
+  // TODO(crbug/1138470): Determine when to remove UNNotificationCategory so
+  // that they do not accumulate during browser lifetime
+  [notification_center_ setNotificationCategories:categories_];
 
-  // TODO(crbug/1136061): Add support for complex categories and move setting
-  // the categories to the place that will be building the complex categories
-  if (notification.should_show_settings_button())
-    [content setCategoryIdentifier:kCloseAndSettingsCategory];
-  else
-    [content setCategoryIdentifier:kCloseCategory];
+  UNMutableNotificationContent* content = [builder buildUserNotification];
 
   UNNotificationRequest* request = [UNNotificationRequest
       requestWithIdentifier:base::SysUTF8ToNSString(notification.id())
@@ -217,38 +226,6 @@
                     }];
 }
 
-void NotificationPlatformBridgeMacUNNotification::CreateDefaultCategories() {
-  UNNotificationAction* closeButton = [UNNotificationAction
-      actionWithIdentifier:notification_constants::kNotificationCloseButtonTag
-                     title:l10n_util::GetNSString(IDS_NOTIFICATION_BUTTON_CLOSE)
-                   options:UNNotificationActionOptionNone];
-
-  UNNotificationAction* settingsButton = [UNNotificationAction
-      actionWithIdentifier:notification_constants::
-                               kNotificationSettingsButtonTag
-                     title:l10n_util::GetNSString(
-                               IDS_NOTIFICATION_BUTTON_SETTINGS)
-                   options:UNNotificationActionOptionForeground];
-
-  // The actions in categories are ordered by LIFO. So having closeButton at the
-  // end ensures that it is always the button on top.
-  UNNotificationCategory* closeAndSettingsCategory = [UNNotificationCategory
-      categoryWithIdentifier:kCloseAndSettingsCategory
-                     actions:@[ settingsButton, closeButton ]
-           intentIdentifiers:@[]
-                     options:UNNotificationCategoryOptionCustomDismissAction];
-
-  UNNotificationCategory* closeCategory = [UNNotificationCategory
-      categoryWithIdentifier:kCloseCategory
-                     actions:@[ closeButton ]
-           intentIdentifiers:@[]
-                     options:UNNotificationCategoryOptionCustomDismissAction];
-
-  [notification_center_
-      setNotificationCategories:[NSSet setWithObjects:closeAndSettingsCategory,
-                                                      closeCategory, nil]];
-}
-
 // /////////////////////////////////////////////////////////////////////////////
 @implementation UNNotificationCenterDelegate
 
diff --git a/chrome/browser/policy/configuration_policy_handler_list_factory.cc b/chrome/browser/policy/configuration_policy_handler_list_factory.cc
index 7226d38..74bdfab 100644
--- a/chrome/browser/policy/configuration_policy_handler_list_factory.cc
+++ b/chrome/browser/policy/configuration_policy_handler_list_factory.cc
@@ -1141,6 +1141,9 @@
   { key::kRequiredClientCertificateForDevice,
     prefs::kRequiredClientCertificateForDevice,
     base::Value::Type::LIST },
+  { key::kDeviceArcDataSnapshotHours,
+    arc::prefs::kArcSnapshotHours,
+    base::Value::Type::DICTIONARY },
 
 #else  // defined(OS_CHROMEOS)
   { key::kMetricsReportingEnabled,
diff --git a/chrome/browser/prefs/browser_prefs.cc b/chrome/browser/prefs/browser_prefs.cc
index 1576e23..531c0668 100644
--- a/chrome/browser/prefs/browser_prefs.cc
+++ b/chrome/browser/prefs/browser_prefs.cc
@@ -339,7 +339,7 @@
 #include "chrome/browser/upgrade_detector/upgrade_detector_chromeos.h"
 #include "chromeos/audio/audio_devices_pref_handler_impl.h"
 #include "chromeos/components/account_manager/account_manager.h"
-#include "chromeos/components/local_search_service/search_metrics_reporter.h"
+#include "chromeos/components/local_search_service/search_metrics_reporter_sync.h"
 #include "chromeos/components/quick_answers/public/cpp/quick_answers_prefs.h"
 #include "chromeos/constants/chromeos_switches.h"
 #include "chromeos/network/fast_transition_observer.h"
@@ -654,7 +654,7 @@
   chromeos::KioskAppManager::RegisterPrefs(registry);
   chromeos::KioskCryptohomeRemover::RegisterPrefs(registry);
   chromeos::language_prefs::RegisterPrefs(registry);
-  chromeos::local_search_service::SearchMetricsReporter::
+  chromeos::local_search_service::SearchMetricsReporterSync::
       RegisterLocalStatePrefs(registry);
   chromeos::MultiProfileUserController::RegisterPrefs(registry);
   chromeos::NetworkMetadataStore::RegisterPrefs(registry);
diff --git a/chrome/browser/printing/print_browsertest.cc b/chrome/browser/printing/print_browsertest.cc
index 84b8f88e..37520b7a 100644
--- a/chrome/browser/printing/print_browsertest.cc
+++ b/chrome/browser/printing/print_browsertest.cc
@@ -593,6 +593,26 @@
                          "window.scrollX"));
 }
 
+// Before invoking print preview, page scale is changed to a different value.
+// Test that when print preview is ready, in other words when printing is
+// finished, the page scale factor gets reset to initial scale.
+IN_PROC_BROWSER_TEST_F(PrintBrowserTest, ResetPageScaleAfterPrintPreview) {
+  ASSERT_TRUE(embedded_test_server()->Started());
+  GURL url(embedded_test_server()->GetURL("/printing/test1.html"));
+  ui_test_utils::NavigateToURL(browser(), url);
+
+  auto* contents = browser()->tab_strip_model()->GetActiveWebContents();
+  contents->SetPageScale(1.5);
+
+  PrintAndWaitUntilPreviewIsReady(/*print_only_selection=*/false);
+
+  double contents_page_scale_after_print =
+      content::EvalJs(contents, "window.visualViewport.scale").ExtractDouble();
+
+  constexpr double kContentsInitialScale = 1.0;
+  EXPECT_EQ(kContentsInitialScale, contents_page_scale_after_print);
+}
+
 // Printing frame content for the main frame of a generic webpage.
 // This test passes when the printed result is sent back and checked in
 // TestPrintRenderFrame::OnDidPrintFrameContent().
diff --git a/chrome/browser/profiles/off_the_record_profile_impl.cc b/chrome/browser/profiles/off_the_record_profile_impl.cc
index 32260255..2b78362 100644
--- a/chrome/browser/profiles/off_the_record_profile_impl.cc
+++ b/chrome/browser/profiles/off_the_record_profile_impl.cc
@@ -148,11 +148,11 @@
   BrowserContextDependencyManager::GetInstance()->CreateBrowserContextServices(
       this);
 
+  // Incognito is not available for ephemeral Guest profiles.
+  CHECK(!profile_->IsEphemeralGuestProfile());
+
   // Always crash when incognito is not available.
-  // Guest profiles may always be OTR, and non primary OTRs are always allowed.
-  // Check IncognitoModePrefs otherwise.
-  CHECK(profile_->IsGuestSession() || profile_->IsSystemProfile() ||
-        !IsPrimaryOTRProfile() ||
+  CHECK(!profile_->IsIncognitoProfile() ||
         IncognitoModePrefs::GetAvailability(profile_->GetPrefs()) !=
             IncognitoModePrefs::DISABLED);
 
diff --git a/chrome/browser/profiles/profile_activity_metrics_recorder.cc b/chrome/browser/profiles/profile_activity_metrics_recorder.cc
index 0e0b318..25bfc1f 100644
--- a/chrome/browser/profiles/profile_activity_metrics_recorder.cc
+++ b/chrome/browser/profiles/profile_activity_metrics_recorder.cc
@@ -31,7 +31,7 @@
     base::TimeDelta::FromMinutes(30);
 
 int GetMetricsBucketIndex(const Profile* profile) {
-  if (profile->IsGuestSession())
+  if (profile->IsGuestSession() || profile->IsEphemeralGuestProfile())
     return 0;
 
   ProfileAttributesEntry* entry;
diff --git a/chrome/browser/profiles/profile_manager.cc b/chrome/browser/profiles/profile_manager.cc
index ee309c0..6d54647 100644
--- a/chrome/browser/profiles/profile_manager.cc
+++ b/chrome/browser/profiles/profile_manager.cc
@@ -600,13 +600,17 @@
   if (!callback.is_null()) {
     if (iter != profiles_info_.end() && info->created) {
       Profile* profile = info->profile.get();
-      // If this was the guest profile, apply settings and go OffTheRecord.
+      // If this was the non-ephemeral Guest profile, apply settings and go
+      // OffTheRecord.
       // The system profile also needs characteristics of being off the record,
       // such as having no extensions, not writing to disk, etc.
-      if (profile->IsGuestSession() || profile->IsSystemProfile()) {
+      if (profile->IsGuestSession() || profile->IsEphemeralGuestProfile() ||
+          profile->IsSystemProfile()) {
         SetNonPersonalProfilePrefs(profile);
-        profile = profile->GetPrimaryOTRProfile();
       }
+      if (profile->IsGuestSession() || profile->IsSystemProfile())
+        profile = profile->GetPrimaryOTRProfile();
+
       // Profile has already been created. Run callback immediately.
       callback.Run(profile, Profile::CREATE_STATUS_INITIALIZED);
     } else {
@@ -718,7 +722,7 @@
       if (profile) {
         // crbug.com/823338 -> CHECK that the profiles aren't guest or
         // incognito, causing a crash during session restore.
-        CHECK(!profile->IsGuestSession())
+        CHECK(!profile->IsGuestSession() && !profile->IsEphemeralGuestProfile())
             << "Guest profiles shouldn't have been saved as active profiles";
         CHECK(!profile->IsOffTheRecord())
             << "OTR profiles shouldn't have been saved as active profiles";
@@ -1060,7 +1064,7 @@
   size_t avatar_index;
   std::string profile_name;
   std::string supervised_user_id;
-  if (profile->IsGuestSession()) {
+  if (profile->IsGuestSession() || profile->IsEphemeralGuestProfile()) {
     profile_name = l10n_util::GetStringUTF8(IDS_PROFILES_GUEST_PROFILE_NAME);
     avatar_index = 0;
   } else {
@@ -1198,8 +1202,10 @@
   if (profile) {
     // If this was the guest or system profile, finish setting its special
     // status.
-    if (profile->IsGuestSession() || profile->IsSystemProfile())
+    if (profile->IsGuestSession() || profile->IsSystemProfile() ||
+        profile->IsEphemeralGuestProfile()) {
       SetNonPersonalProfilePrefs(profile);
+    }
 
     // Invoke CREATED callback for incognito profiles.
     if (go_off_the_record)
diff --git a/chrome/browser/profiles/profile_metrics.cc b/chrome/browser/profiles/profile_metrics.cc
index 4de5028..b5f34b3 100644
--- a/chrome/browser/profiles/profile_metrics.cc
+++ b/chrome/browser/profiles/profile_metrics.cc
@@ -178,7 +178,7 @@
     Profile* profile) {
   if (profile->IsSystemProfile())
     return profile_metrics::BrowserProfileType::kSystem;
-  if (profile->IsGuestSession())
+  if (profile->IsGuestSession() || profile->IsEphemeralGuestProfile())
     return profile_metrics::BrowserProfileType::kGuest;
   // A regular profile can be in a guest session or a system profile. Hence it
   // should be checked after them.
diff --git a/chrome/browser/profiles/profile_window.cc b/chrome/browser/profiles/profile_window.cc
index ac7785e..7683630 100644
--- a/chrome/browser/profiles/profile_window.cc
+++ b/chrome/browser/profiles/profile_window.cc
@@ -205,7 +205,7 @@
   }
 
 #if !defined(OS_CHROMEOS)
-  if (!profile->IsGuestSession()) {
+  if (!profile->IsGuestSession() && !profile->IsEphemeralGuestProfile()) {
     ProfileAttributesEntry* entry;
     if (g_browser_process->profile_manager()->GetProfileAttributesStorage().
             GetProfileAttributesWithPath(profile->GetPath(), &entry) &&
@@ -284,7 +284,8 @@
 #endif
 
 bool HasProfileSwitchTargets(Profile* profile) {
-  size_t min_profiles = profile->IsGuestSession() ? 1 : 2;
+  size_t min_profiles =
+      (profile->IsGuestSession() || profile->IsEphemeralGuestProfile()) ? 1 : 2;
   size_t number_of_profiles =
       g_browser_process->profile_manager()->GetNumberOfProfiles();
   return number_of_profiles >= min_profiles;
@@ -354,8 +355,10 @@
 
 bool IsLockAvailable(Profile* profile) {
   DCHECK(profile);
-  if (profile->IsGuestSession() || profile->IsSystemProfile())
+  if (profile->IsGuestSession() || profile->IsSystemProfile() ||
+      profile->IsEphemeralGuestProfile()) {
     return false;
+  }
 
   std::string hosted_domain = profile->GetPrefs()->
       GetString(prefs::kGoogleServicesHostedDomain);
diff --git a/chrome/browser/profiles/profile_window_browsertest.cc b/chrome/browser/profiles/profile_window_browsertest.cc
index 5df0047..c6fdc181 100644
--- a/chrome/browser/profiles/profile_window_browsertest.cc
+++ b/chrome/browser/profiles/profile_window_browsertest.cc
@@ -15,6 +15,8 @@
 #include "build/build_config.h"
 #include "chrome/app/chrome_command_ids.h"
 #include "chrome/browser/browser_process.h"
+#include "chrome/browser/devtools/devtools_window.h"
+#include "chrome/browser/devtools/devtools_window_testing.h"
 #include "chrome/browser/history/history_service_factory.h"
 #include "chrome/browser/profiles/profile_attributes_storage.h"
 #include "chrome/browser/profiles/profile_manager.h"
@@ -151,13 +153,88 @@
   return browser;
 }
 
+class OTRProfileWindowBrowserTest : public ProfileWindowBrowserTest,
+                                    public testing::WithParamInterface<bool> {
+ protected:
+  OTRProfileWindowBrowserTest() { is_guest_ = GetParam(); }
+
+  int GetWindowCount() {
+    return is_guest_ ? BrowserList::GetGuestBrowserCount()
+                     : BrowserList::GetOffTheRecordBrowsersActiveForProfile(
+                           browser()->profile());
+  }
+
+  Browser* CreateGuestOrIncognitoBrowser() {
+    Browser* new_browser;
+    // When |profile_| is null this means no browsers have been created,
+    // this is the first browser instance.
+    // |is_guest_| is used to determine which browser type to open.
+    if (!profile_) {
+      new_browser = is_guest_ ? OpenGuestBrowser()
+                              : CreateIncognitoBrowser(browser()->profile());
+      profile_ = new_browser->profile();
+    } else {
+      // Using |CreateIncognitoBrowser| to create OTR profile browser, if
+      // |profile_| is a guest profile this method opens a Guest Window. On the
+      // other hand if |profile_| is a primary profile it creates an incognito
+      // window for said profile.
+      new_browser = CreateIncognitoBrowser(profile_);
+    }
+
+    return new_browser;
+  }
+
+ private:
+  bool is_guest_;
+  Profile* profile_ = nullptr;
+};
+
+IN_PROC_BROWSER_TEST_P(OTRProfileWindowBrowserTest, CountOTRProfileWindows) {
+  DCHECK_EQ(0, GetWindowCount());
+
+  // Create a browser and check the count.
+  Browser* browser1 = CreateGuestOrIncognitoBrowser();
+  DCHECK_EQ(1, GetWindowCount());
+
+  // Create another browser and check the count.
+  Browser* browser2 = CreateGuestOrIncognitoBrowser();
+  DCHECK_EQ(2, GetWindowCount());
+
+  // Open a docked DevTool window and count.
+  DevToolsWindow* devtools_window =
+      DevToolsWindowTesting::OpenDevToolsWindowSync(browser1, true);
+  DCHECK_EQ(2, GetWindowCount());
+  DevToolsWindowTesting::CloseDevToolsWindowSync(devtools_window);
+
+  // Open a detached DevTool window and count.
+  devtools_window =
+      DevToolsWindowTesting::OpenDevToolsWindowSync(browser1, false);
+  DCHECK_EQ(2, GetWindowCount());
+  DevToolsWindowTesting::CloseDevToolsWindowSync(devtools_window);
+
+  // Close one browser and count.
+  CloseBrowserSynchronously(browser2);
+  DCHECK_EQ(1, GetWindowCount());
+
+  // Close another browser and count.
+  CloseBrowserSynchronously(browser1);
+  DCHECK_EQ(0, GetWindowCount());
+}
+
+INSTANTIATE_TEST_SUITE_P(IncognitoAndGuestWindowCount,
+                         OTRProfileWindowBrowserTest,
+                         /*is_guest_=*/testing::Bool());
+
 IN_PROC_BROWSER_TEST_F(ProfileWindowBrowserTest, OpenGuestBrowser) {
   EXPECT_TRUE(OpenGuestBrowser());
 }
 
 IN_PROC_BROWSER_TEST_F(ProfileWindowBrowserTest, GuestIsIncognito) {
-  Browser* guest_browser = OpenGuestBrowser();
-  EXPECT_TRUE(guest_browser->profile()->IsOffTheRecord());
+  Profile* guest_profile = OpenGuestBrowser()->profile();
+  if (guest_profile->IsEphemeralGuestProfile())
+    EXPECT_FALSE(guest_profile->IsOffTheRecord());
+  else
+    EXPECT_TRUE(guest_profile->IsOffTheRecord());
 }
 
 IN_PROC_BROWSER_TEST_F(ProfileWindowBrowserTest, GuestIgnoresHistory) {
@@ -175,7 +252,10 @@
 
   std::vector<GURL> urls =
       ui_test_utils::HistoryEnumerator(guest_browser->profile()).urls();
-  ASSERT_EQ(0U, urls.size());
+
+  unsigned int expect_history =
+      guest_browser->profile()->IsEphemeralGuestProfile() ? 1 : 0;
+  ASSERT_EQ(expect_history, urls.size());
 }
 
 IN_PROC_BROWSER_TEST_F(ProfileWindowBrowserTest, GuestClearsCookies) {
diff --git a/chrome/browser/profiles/profiles_state.cc b/chrome/browser/profiles/profiles_state.cc
index e4dc2990..2e0645f 100644
--- a/chrome/browser/profiles/profiles_state.cc
+++ b/chrome/browser/profiles/profiles_state.cc
@@ -164,7 +164,8 @@
 
 bool IsRegularOrGuestSession(Browser* browser) {
   Profile* profile = browser->profile();
-  return profile->IsRegularProfile() || profile->IsGuestSession();
+  return profile->IsRegularProfile() || profile->IsGuestSession() ||
+         profile->IsEphemeralGuestProfile();
 }
 
 bool IsProfileLocked(const base::FilePath& profile_path) {
diff --git a/chrome/browser/signin/account_consistency_mode_manager.cc b/chrome/browser/signin/account_consistency_mode_manager.cc
index 627d217..8c0099e 100644
--- a/chrome/browser/signin/account_consistency_mode_manager.cc
+++ b/chrome/browser/signin/account_consistency_mode_manager.cc
@@ -163,11 +163,11 @@
 bool AccountConsistencyModeManager::ShouldBuildServiceForProfile(
     Profile* profile) {
   // IsGuestSession() returns true for the ProfileImpl associated with Guest
-  // profiles. This profile manually sets the kSigninAllowed prference, which
+  // profiles. This profile manually sets the kSigninAllowed preference, which
   // causes crashes if the AccountConsistencyModeManager is instantiated. See
   // https://crbug.com/940026
   return profile->IsRegularProfile() && !profile->IsGuestSession() &&
-         !profile->IsSystemProfile();
+         !profile->IsEphemeralGuestProfile() && !profile->IsSystemProfile();
 }
 
 AccountConsistencyMethod
diff --git a/chrome/browser/sync/test/integration/profile_sync_service_harness.cc b/chrome/browser/sync/test/integration/profile_sync_service_harness.cc
index d927008..10b48cc99 100644
--- a/chrome/browser/sync/test/integration/profile_sync_service_harness.cc
+++ b/chrome/browser/sync/test/integration/profile_sync_service_harness.cc
@@ -229,14 +229,14 @@
   auto* cmd_line = base::CommandLine::ForCurrentProcess();
   DCHECK(cmd_line->HasSwitch(kSyncUrlClearServerDataKey))
       << "Missing switch " << kSyncUrlClearServerDataKey;
-  std::string url =
-      cmd_line->GetSwitchValueASCII(kSyncUrlClearServerDataKey) + "/command/?";
-  url += syncer::MakeSyncQueryString(sync_prefs.GetCacheGuid());
+  GURL base_url(cmd_line->GetSwitchValueASCII(kSyncUrlClearServerDataKey) +
+                "/command/?");
+  GURL url = syncer::AppendSyncQueryString(base_url, sync_prefs.GetCacheGuid());
 
   // Call sync server to clear sync data.
   std::string access_token = service()->GetAccessTokenForTest();
   DCHECK(access_token.size()) << "Access token is not available.";
-  ResetAccount(profile_->GetURLLoaderFactory().get(), access_token, GURL(url),
+  ResetAccount(profile_->GetURLLoaderFactory().get(), access_token, url,
                username_, sync_prefs.GetBirthday());
 }
 
diff --git a/chrome/browser/ui/app_list/search/mixer.cc b/chrome/browser/ui/app_list/search/mixer.cc
index 83f98108..4cc713ae 100644
--- a/chrome/browser/ui/app_list/search/mixer.cc
+++ b/chrome/browser/ui/app_list/search/mixer.cc
@@ -122,11 +122,6 @@
     results.insert(results.end(), group->results().begin(),
                    group->results().begin() + num_results);
   }
-  // Remove results with duplicate IDs before sorting. If two providers give a
-  // result with the same ID, the result from the provider with the *lower group
-  // number* will be kept (e.g., an app result takes priority over a web store
-  // result with the same ID).
-  RemoveDuplicates(&results);
 
   // Zero state search results: if any search provider won't have any results
   // displayed, but has a high-scoring result that the user hasn't seen many
@@ -144,13 +139,11 @@
   const size_t original_size = results.size();
   if (original_size < num_max_results) {
     // We didn't get enough results. Insert all the results again, and this
-    // time, do not limit the maximum number of results from each group. (This
-    // will result in duplicates, which will be removed by RemoveDuplicates.)
+    // time, do not limit the maximum number of results from each group.
     for (const auto& group : groups_) {
       results.insert(results.end(), group->results().begin(),
                      group->results().end());
     }
-    RemoveDuplicates(&results);
     // Sort just the newly added results. This ensures that, for example, if
     // there are 6 Omnibox results (score = 0.8) and 1 People result (score =
     // 0.4) that the People result will be 5th, not 7th, because the Omnibox
@@ -167,21 +160,6 @@
   model_updater_->PublishSearchResults(new_results);
 }
 
-void Mixer::RemoveDuplicates(SortedResults* results) {
-  SortedResults final;
-  final.reserve(results->size());
-
-  std::set<std::string> id_set;
-  for (const SortData& sort_data : *results) {
-    if (!id_set.insert(sort_data.result->id()).second)
-      continue;
-
-    final.emplace_back(sort_data);
-  }
-
-  results->swap(final);
-}
-
 void Mixer::FetchResults(const base::string16& query) {
   if (search_result_ranker_)
     search_result_ranker_->FetchRankings(query);
diff --git a/chrome/browser/ui/app_list/search/mixer.h b/chrome/browser/ui/app_list/search/mixer.h
index 908abd88..8481510 100644
--- a/chrome/browser/ui/app_list/search/mixer.h
+++ b/chrome/browser/ui/app_list/search/mixer.h
@@ -88,12 +88,6 @@
   class Group;
   typedef std::vector<std::unique_ptr<Group>> Groups;
 
-  // Removes entries from |results| with duplicate IDs. When two or more results
-  // have the same ID, the earliest one in the |results| list is kept.
-  // NOTE: This is not necessarily the one with the highest *score*, as
-  // |results| may not have been sorted yet.
-  static void RemoveDuplicates(SortedResults* results);
-
   void FetchResults(const base::string16& query);
 
   AppListModelUpdater* const model_updater_;  // Not owned.
diff --git a/chrome/browser/ui/app_list/search/tests/mixer_unittest.cc b/chrome/browser/ui/app_list/search/tests/mixer_unittest.cc
index 6aec6267..44dc571 100644
--- a/chrome/browser/ui/app_list/search/tests/mixer_unittest.cc
+++ b/chrome/browser/ui/app_list/search/tests/mixer_unittest.cc
@@ -232,28 +232,5 @@
       GetResults());
 }
 
-TEST_F(MixerTest, RemoveDuplicates) {
-  CreateMixer();
-
-  const std::string dup = "dup";
-
-  // This gives "dup0,dup1,dup2".
-  app_provider()->set_prefix(dup);
-  app_provider()->set_count(3);
-
-  // This gives "dup0,dup1".
-  omnibox_provider()->set_prefix(dup);
-  omnibox_provider()->set_count(2);
-
-  // This gives "dup0".
-  playstore_provider()->set_prefix(dup);
-  playstore_provider()->set_count(1);
-
-  RunQuery();
-
-  // Only three results with unique id are kept.
-  EXPECT_EQ("dup0,dup1,dup2", GetResults());
-}
-
 }  // namespace test
 }  // namespace app_list
diff --git a/chrome/browser/ui/browser_browsertest.cc b/chrome/browser/ui/browser_browsertest.cc
index 20a354ad8..9bb7bc70 100644
--- a/chrome/browser/ui/browser_browsertest.cc
+++ b/chrome/browser/ui/browser_browsertest.cc
@@ -2822,45 +2822,6 @@
   tab->DecrementCapturerCount(/* stay_hidden */ false);
 }
 
-IN_PROC_BROWSER_TEST_F(BrowserTest, CountIncognitoWindows) {
-  DCHECK_EQ(0, BrowserList::GetOffTheRecordBrowsersActiveForProfile(
-                   browser()->profile()));
-
-  // Create an incognito browser and check the count.
-  Browser* browser1 = CreateIncognitoBrowser(browser()->profile());
-  DCHECK_EQ(1, BrowserList::GetOffTheRecordBrowsersActiveForProfile(
-                   browser()->profile()));
-
-  // Create another incognito browser and check the count.
-  Browser* browser2 = CreateIncognitoBrowser(browser()->profile());
-  DCHECK_EQ(2, BrowserList::GetOffTheRecordBrowsersActiveForProfile(
-                   browser()->profile()));
-
-  // Open a docked DevTool window and count.
-  DevToolsWindow* devtools_window =
-      DevToolsWindowTesting::OpenDevToolsWindowSync(browser1, true);
-  DCHECK_EQ(2, BrowserList::GetOffTheRecordBrowsersActiveForProfile(
-                   browser()->profile()));
-  DevToolsWindowTesting::CloseDevToolsWindowSync(devtools_window);
-
-  // Open a detached DevTool window and count.
-  devtools_window =
-      DevToolsWindowTesting::OpenDevToolsWindowSync(browser1, false);
-  DCHECK_EQ(2, BrowserList::GetOffTheRecordBrowsersActiveForProfile(
-                   browser()->profile()));
-  DevToolsWindowTesting::CloseDevToolsWindowSync(devtools_window);
-
-  // Close one browser and count.
-  CloseBrowserSynchronously(browser2);
-  DCHECK_EQ(1, BrowserList::GetOffTheRecordBrowsersActiveForProfile(
-                   browser()->profile()));
-
-  // Close another browser and count.
-  CloseBrowserSynchronously(browser1);
-  DCHECK_EQ(0, BrowserList::GetOffTheRecordBrowsersActiveForProfile(
-                   browser()->profile()));
-}
-
 IN_PROC_BROWSER_TEST_F(BrowserTest, IsOffTheRecordBrowserInUse) {
   EXPECT_FALSE(BrowserList::IsOffTheRecordBrowserInUse(browser()->profile()));
 
diff --git a/chrome/browser/ui/cocoa/notifications/notification_builder_base.h b/chrome/browser/ui/cocoa/notifications/notification_builder_base.h
index 558ea73..1c6f072e 100644
--- a/chrome/browser/ui/cocoa/notifications/notification_builder_base.h
+++ b/chrome/browser/ui/cocoa/notifications/notification_builder_base.h
@@ -14,8 +14,10 @@
   base::scoped_nsobject<NSMutableDictionary> _notificationData;
 }
 
-// Initializes an empty builder along with |_notificationData|.
-- (instancetype)init;
+// Initializes a builder with default values for the button labels.
+- (instancetype)initWithCloseLabel:(NSString*)closeLabel
+                      optionsLabel:(NSString*)optionsLabel
+                     settingsLabel:(NSString*)settingsLabel;
 
 // Initializes a builder by deserializing |data|. The |data| must have been
 // generated by calling the buildDictionary function on another builder
diff --git a/chrome/browser/ui/cocoa/notifications/notification_builder_base.mm b/chrome/browser/ui/cocoa/notifications/notification_builder_base.mm
index 4d24b29d..e39c3a6 100644
--- a/chrome/browser/ui/cocoa/notifications/notification_builder_base.mm
+++ b/chrome/browser/ui/cocoa/notifications/notification_builder_base.mm
@@ -8,9 +8,20 @@
 
 @implementation NotificationBuilderBase
 
-- (instancetype)init {
+- (instancetype)initWithCloseLabel:(NSString*)closeLabel
+                      optionsLabel:(NSString*)optionsLabel
+                     settingsLabel:(NSString*)settingsLabel {
   if ((self = [super init])) {
     _notificationData.reset([[NSMutableDictionary alloc] init]);
+    [_notificationData
+        setObject:closeLabel
+           forKey:notification_constants::kNotificationCloseButtonTag];
+    [_notificationData
+        setObject:optionsLabel
+           forKey:notification_constants::kNotificationOptionsButtonTag];
+    [_notificationData
+        setObject:settingsLabel
+           forKey:notification_constants::kNotificationSettingsButtonTag];
   }
   return self;
 }
diff --git a/chrome/browser/ui/cocoa/notifications/notification_builder_mac.h b/chrome/browser/ui/cocoa/notifications/notification_builder_mac.h
index a672946..690779077 100644
--- a/chrome/browser/ui/cocoa/notifications/notification_builder_mac.h
+++ b/chrome/browser/ui/cocoa/notifications/notification_builder_mac.h
@@ -19,7 +19,7 @@
 //     base::scoped_nsobject<NotificationBuilder> builder(
 //         [[NotificationBuilder alloc] initWithCloseLabel:@"Close"
 //                                            optionsLabel:@"Options"
-//                                           settingsLabel:@"Settings")]);
+//                                           settingsLabel:@"Settings"]);
 //     [builder setTitle:@"Hello"];
 //
 //     // Build a notification out of the data.
@@ -34,11 +34,6 @@
 //         [[NotificationBuilder alloc] initWithData:notificationData]);
 @interface NotificationBuilder : NotificationBuilderBase
 
-// Initializes a builder with default values for the button labels.
-- (instancetype)initWithCloseLabel:(NSString*)closeLabel
-                      optionsLabel:(NSString*)optionsLabel
-                     settingsLabel:(NSString*)settingsLabel;
-
 // Sets the icon that is displayed in the notification if present
 - (void)setIcon:(NSImage*)icon;
 
diff --git a/chrome/browser/ui/cocoa/notifications/notification_builder_mac.mm b/chrome/browser/ui/cocoa/notifications/notification_builder_mac.mm
index 8d1abd2..2b6d5c9 100644
--- a/chrome/browser/ui/cocoa/notifications/notification_builder_mac.mm
+++ b/chrome/browser/ui/cocoa/notifications/notification_builder_mac.mm
@@ -13,23 +13,6 @@
 
 @implementation NotificationBuilder
 
-- (instancetype)initWithCloseLabel:(NSString*)closeLabel
-                      optionsLabel:(NSString*)optionsLabel
-                     settingsLabel:(NSString*)settingsLabel {
-  if ((self = [super init])) {
-    [_notificationData
-        setObject:closeLabel
-           forKey:notification_constants::kNotificationCloseButtonTag];
-    [_notificationData
-        setObject:optionsLabel
-           forKey:notification_constants::kNotificationOptionsButtonTag];
-    [_notificationData
-        setObject:settingsLabel
-           forKey:notification_constants::kNotificationSettingsButtonTag];
-  }
-  return self;
-}
-
 - (void)setIcon:(NSImage*)icon {
   if (!icon)
     return;
diff --git a/chrome/browser/ui/cocoa/notifications/notification_constants_mac.h b/chrome/browser/ui/cocoa/notifications/notification_constants_mac.h
index 8bb63ff..06e9903 100644
--- a/chrome/browser/ui/cocoa/notifications/notification_constants_mac.h
+++ b/chrome/browser/ui/cocoa/notifications/notification_constants_mac.h
@@ -20,6 +20,7 @@
 extern NSString* const kNotificationCloseButtonTag;
 extern NSString* const kNotificationOptionsButtonTag;
 extern NSString* const kNotificationSettingsButtonTag;
+extern NSString* const kNotificationCategoryIdentifier;
 
 extern NSString* const kNotificationOrigin;
 extern NSString* const kNotificationId;
diff --git a/chrome/browser/ui/cocoa/notifications/notification_constants_mac.mm b/chrome/browser/ui/cocoa/notifications/notification_constants_mac.mm
index b1fc5dde..9e01bf0 100644
--- a/chrome/browser/ui/cocoa/notifications/notification_constants_mac.mm
+++ b/chrome/browser/ui/cocoa/notifications/notification_constants_mac.mm
@@ -19,6 +19,7 @@
 NSString* const kNotificationCloseButtonTag = @"closeButton";
 NSString* const kNotificationOptionsButtonTag = @"optionsButton";
 NSString* const kNotificationSettingsButtonTag = @"settingsButton";
+NSString* const kNotificationCategoryIdentifier = @"categoryIdentifier";
 
 // Applicable to NotificationBuilder and NotificationResponseBuilder
 NSString* const kNotificationOrigin = @"notificationOrigin";
diff --git a/chrome/browser/ui/cocoa/notifications/unnotification_builder_mac.h b/chrome/browser/ui/cocoa/notifications/unnotification_builder_mac.h
index d166f32..a01f892 100644
--- a/chrome/browser/ui/cocoa/notifications/unnotification_builder_mac.h
+++ b/chrome/browser/ui/cocoa/notifications/unnotification_builder_mac.h
@@ -11,13 +11,16 @@
 #import "chrome/browser/ui/cocoa/notifications/notification_builder_base.h"
 
 @class UNMutableNotificationContent;
+@class UNNotificationCategory;
 
 // Provides a marshallable way for storing the information required to construct
 // a UNMutableNotificationContent that is to be displayed on the system.
 //
 // A quick example:
 //     base::scoped_nsobject<UNNotificationBuilder> builder(
-//         [[UNNotificationBuilder alloc] init]);
+//         [[UNNotificationBuilder alloc] initWithCloseLabel:@"Close"
+//                                         optionsLabel:@"Options"
+//                                        settingsLabel:@"Settings"]);
 //     [builder setTitle:@"Hello"];
 //
 //     // Build a notification out of the data.
@@ -36,6 +39,10 @@
 // Sets the icon path that is used to display it in the notification if present
 - (void)setIconPath:(NSString*)iconPath;
 
+// Returns a UNNotificationCategory with the specified buttons. Needs to be
+// called after setNotificationId is.
+- (UNNotificationCategory*)buildCategory;
+
 // Returns a notification ready to be displayed out of the provided
 // |notificationData|.
 - (UNMutableNotificationContent*)buildUserNotification;
diff --git a/chrome/browser/ui/cocoa/notifications/unnotification_builder_mac.mm b/chrome/browser/ui/cocoa/notifications/unnotification_builder_mac.mm
index 7e7f9bc..6bc03e0 100644
--- a/chrome/browser/ui/cocoa/notifications/unnotification_builder_mac.mm
+++ b/chrome/browser/ui/cocoa/notifications/unnotification_builder_mac.mm
@@ -19,6 +19,104 @@
                         forKey:notification_constants::kNotificationIconPath];
 }
 
+- (UNNotificationCategory*)buildCategory {
+  DCHECK(
+      [_notificationData objectForKey:notification_constants::kNotificationId]);
+  DCHECK([_notificationData
+      objectForKey:notification_constants::kNotificationHasSettingsButton]);
+
+  NSMutableArray* buttonsArray = [NSMutableArray arrayWithCapacity:4];
+
+  // Extensions don't have a settings button.
+  NSNumber* showSettingsButton = [_notificationData
+      objectForKey:notification_constants::kNotificationHasSettingsButton];
+  BOOL settingsButton = [showSettingsButton boolValue];
+
+  UNNotificationAction* closeButton = [UNNotificationAction
+      actionWithIdentifier:notification_constants::kNotificationCloseButtonTag
+                     title:[_notificationData
+                               objectForKey:notification_constants::
+                                                kNotificationCloseButtonTag]
+                   options:UNNotificationActionOptionNone];
+  [buttonsArray addObject:closeButton];
+
+  if ([_notificationData
+          objectForKey:notification_constants::kNotificationButtonOne]) {
+    UNNotificationAction* buttonOne = [UNNotificationAction
+        actionWithIdentifier:notification_constants::kNotificationButtonOne
+                       title:[_notificationData
+                                 objectForKey:notification_constants::
+                                                  kNotificationButtonOne]
+                     options:UNNotificationActionOptionNone];
+    [buttonsArray addObject:buttonOne];
+  }
+  if ([_notificationData
+          objectForKey:notification_constants::kNotificationButtonTwo]) {
+    UNNotificationAction* buttonTwo = [UNNotificationAction
+        actionWithIdentifier:notification_constants::kNotificationButtonTwo
+                       title:[_notificationData
+                                 objectForKey:notification_constants::
+                                                  kNotificationButtonTwo]
+                     options:UNNotificationActionOptionNone];
+    [buttonsArray addObject:buttonTwo];
+  }
+
+  if (settingsButton) {
+    UNNotificationAction* settingsButton = [UNNotificationAction
+        actionWithIdentifier:notification_constants::
+                                 kNotificationSettingsButtonTag
+                       title:
+                           [_notificationData
+                               objectForKey:notification_constants::
+                                                kNotificationSettingsButtonTag]
+                     options:UNNotificationActionOptionNone];
+    [buttonsArray addObject:settingsButton];
+  }
+
+  // If there are only 2 buttons [Close, button] then the actions array need to
+  // be set as [button, Close] so that close is on top. This is to safeguard the
+  // order of the buttons in case respondsToSelector:@selector(alternateAction)
+  // were to return false.
+  if ([buttonsArray count] == 2) {
+    // Remove the close button and move it to the end of the array
+    [buttonsArray removeObject:closeButton];
+    [buttonsArray addObject:closeButton];
+  }
+
+  UNNotificationCategory* category = [UNNotificationCategory
+      categoryWithIdentifier:
+          [_notificationData
+              objectForKey:notification_constants::kNotificationId]
+                     actions:buttonsArray
+           intentIdentifiers:@[]
+                     options:UNNotificationCategoryOptionCustomDismissAction];
+  [_notificationData
+      setObject:[_notificationData
+                    objectForKey:notification_constants::kNotificationId]
+         forKey:notification_constants::kNotificationCategoryIdentifier];
+
+  // This uses a private API to make sure the close button is always visible in
+  // both alerts and banners, and modifies its content so that it is consistent
+  // with the rest of the notification buttons. Otherwise, the text inside the
+  // close button will come from the Apple API
+  if ([category respondsToSelector:@selector(alternateAction)]) {
+    [buttonsArray removeObject:closeButton];
+    [category setValue:buttonsArray forKey:@"actions"];
+    [category setValue:closeButton forKey:@"_alternateAction"];
+  }
+
+  // This uses a private API to change the text of the actions menu title so
+  // that it is consistent with the rest of the notification buttons
+  if ([category respondsToSelector:@selector(actionsMenuTitle)]) {
+    [category setValue:[_notificationData
+                           objectForKey:notification_constants::
+                                            kNotificationOptionsButtonTag]
+                forKey:@"_actionsMenuTitle"];
+  }
+
+  return category;
+}
+
 - (UNMutableNotificationContent*)buildUserNotification {
   base::scoped_nsobject<UNMutableNotificationContent> toast(
       [[UNMutableNotificationContent alloc] init]);
@@ -94,6 +192,14 @@
     if (attachment != nil)
       [toast setAttachments:@[ attachment ]];
   }
+  // Category
+  if ([_notificationData objectForKey:notification_constants::
+                                          kNotificationCategoryIdentifier]) {
+    [toast setCategoryIdentifier:
+               [_notificationData
+                   objectForKey:notification_constants::
+                                    kNotificationCategoryIdentifier]];
+  }
 
   [toast setUserInfo:@{
     notification_constants::kNotificationOrigin : origin,
diff --git a/chrome/browser/ui/cocoa/notifications/unnotification_builder_mac_unittest.mm b/chrome/browser/ui/cocoa/notifications/unnotification_builder_mac_unittest.mm
index b138757..c4bb705 100644
--- a/chrome/browser/ui/cocoa/notifications/unnotification_builder_mac_unittest.mm
+++ b/chrome/browser/ui/cocoa/notifications/unnotification_builder_mac_unittest.mm
@@ -25,7 +25,9 @@
 base::scoped_nsobject<UNNotificationBuilder> NewTestBuilder(
     NotificationHandler::Type type) {
   base::scoped_nsobject<UNNotificationBuilder> builder(
-      [[UNNotificationBuilder alloc] init]);
+      [[UNNotificationBuilder alloc] initWithCloseLabel:@"Close"
+                                           optionsLabel:@"Options"
+                                          settingsLabel:@"Settings"]);
   [builder setNotificationId:@"notificationId"];
   [builder setProfileId:@"profileId"];
   [builder setIncognito:false];
@@ -52,6 +54,244 @@
   }
 }
 
+TEST(UNNotificationBuilderMacTest, TestNotificationNoButtons) {
+  if (@available(macOS 10.14, *)) {
+    base::scoped_nsobject<UNNotificationBuilder> builder =
+        NewTestBuilder(NotificationHandler::Type::WEB_NON_PERSISTENT);
+
+    [builder setShowSettingsButton:true];
+    UNNotificationCategory* category = [builder buildCategory];
+
+    // Test contents of the category
+    if ([category respondsToSelector:@selector(alternateAction)]) {
+      EXPECT_EQ("Close", base::SysNSStringToUTF8([[category
+                             valueForKey:@"_alternateAction"] title]));
+      EXPECT_EQ(base::SysNSStringToUTF8(
+                    notification_constants::kNotificationCloseButtonTag),
+                base::SysNSStringToUTF8(
+                    [[category valueForKey:@"_alternateAction"] identifier]));
+
+      EXPECT_EQ(1ul, [[category actions] count]);
+    } else {
+      EXPECT_EQ("Close", base::SysNSStringToUTF8(
+                             [[[category actions] firstObject] title]));
+      EXPECT_EQ(base::SysNSStringToUTF8(
+                    notification_constants::kNotificationCloseButtonTag),
+                base::SysNSStringToUTF8(
+                    [[[category actions] firstObject] identifier]));
+
+      EXPECT_EQ(2ul, [[category actions] count]);
+    }
+
+    EXPECT_EQ("Settings",
+              base::SysNSStringToUTF8([[[category actions] lastObject] title]));
+    EXPECT_EQ(
+        base::SysNSStringToUTF8(
+            notification_constants::kNotificationSettingsButtonTag),
+        base::SysNSStringToUTF8([[[category actions] lastObject] identifier]));
+
+    UNMutableNotificationContent* content = [builder buildUserNotification];
+    EXPECT_EQ("notificationId",
+              base::SysNSStringToUTF8([content categoryIdentifier]));
+  }
+}
+
+TEST(UNNotificationBuilderMacTest, TestNotificationOneButton) {
+  if (@available(macOS 10.14, *)) {
+    base::scoped_nsobject<UNNotificationBuilder> builder =
+        NewTestBuilder(NotificationHandler::Type::WEB_NON_PERSISTENT);
+
+    [builder setButtons:@"Button1" secondaryButton:@""];
+    [builder setShowSettingsButton:true];
+    UNNotificationCategory* category = [builder buildCategory];
+
+    // Test contents of the category
+    if ([category respondsToSelector:@selector(alternateAction)]) {
+      EXPECT_EQ("Close", base::SysNSStringToUTF8([[category
+                             valueForKey:@"_alternateAction"] title]));
+      EXPECT_EQ(base::SysNSStringToUTF8(
+                    notification_constants::kNotificationCloseButtonTag),
+                base::SysNSStringToUTF8(
+                    [[category valueForKey:@"_alternateAction"] identifier]));
+      EXPECT_EQ(2ul, [[category actions] count]);
+    } else {
+      EXPECT_EQ("Close", base::SysNSStringToUTF8(
+                             [[[category actions] firstObject] title]));
+      EXPECT_EQ(base::SysNSStringToUTF8(
+                    notification_constants::kNotificationCloseButtonTag),
+                base::SysNSStringToUTF8(
+                    [[[category actions] firstObject] identifier]));
+      EXPECT_EQ(3ul, [[category actions] count]);
+    }
+
+    EXPECT_EQ("Button1",
+              base::SysNSStringToUTF8([[category actions][0] title]));
+    EXPECT_EQ(
+        base::SysNSStringToUTF8(notification_constants::kNotificationButtonOne),
+        base::SysNSStringToUTF8([[category actions][0] identifier]));
+
+    EXPECT_EQ("Settings",
+              base::SysNSStringToUTF8([[[category actions] lastObject] title]));
+    EXPECT_EQ(
+        base::SysNSStringToUTF8(
+            notification_constants::kNotificationSettingsButtonTag),
+        base::SysNSStringToUTF8([[[category actions] lastObject] identifier]));
+
+    if ([category respondsToSelector:@selector(actionsMenuTitle)]) {
+      EXPECT_EQ("Options", base::SysNSStringToUTF8(
+                               [category valueForKey:@"_actionsMenuTitle"]));
+    }
+
+    UNMutableNotificationContent* content = [builder buildUserNotification];
+    EXPECT_EQ("notificationId",
+              base::SysNSStringToUTF8([content categoryIdentifier]));
+  }
+}
+
+TEST(UNNotificationBuilderMacTest, TestNotificationTwoButtons) {
+  if (@available(macOS 10.14, *)) {
+    base::scoped_nsobject<UNNotificationBuilder> builder =
+        NewTestBuilder(NotificationHandler::Type::WEB_NON_PERSISTENT);
+
+    [builder setButtons:@"Button1" secondaryButton:@"Button2"];
+    [builder setShowSettingsButton:true];
+    UNNotificationCategory* category = [builder buildCategory];
+
+    // Test contents of the category
+    if ([category respondsToSelector:@selector(alternateAction)]) {
+      EXPECT_EQ("Close", base::SysNSStringToUTF8([[category
+                             valueForKey:@"_alternateAction"] title]));
+      EXPECT_EQ(base::SysNSStringToUTF8(
+                    notification_constants::kNotificationCloseButtonTag),
+                base::SysNSStringToUTF8(
+                    [[category valueForKey:@"_alternateAction"] identifier]));
+      EXPECT_EQ(3ul, [[category actions] count]);
+    } else {
+      EXPECT_EQ("Close", base::SysNSStringToUTF8(
+                             [[[category actions] firstObject] title]));
+      EXPECT_EQ(base::SysNSStringToUTF8(
+                    notification_constants::kNotificationCloseButtonTag),
+                base::SysNSStringToUTF8(
+                    [[[category actions] firstObject] identifier]));
+      EXPECT_EQ(4ul, [[category actions] count]);
+    }
+
+    EXPECT_EQ("Button1",
+              base::SysNSStringToUTF8([[category actions][0] title]));
+    EXPECT_EQ(
+        base::SysNSStringToUTF8(notification_constants::kNotificationButtonOne),
+        base::SysNSStringToUTF8([[category actions][0] identifier]));
+
+    EXPECT_EQ("Button2",
+              base::SysNSStringToUTF8([[category actions][1] title]));
+    EXPECT_EQ(
+        base::SysNSStringToUTF8(notification_constants::kNotificationButtonTwo),
+        base::SysNSStringToUTF8([[category actions][1] identifier]));
+
+    EXPECT_EQ("Settings",
+              base::SysNSStringToUTF8([[[category actions] lastObject] title]));
+    EXPECT_EQ(
+        base::SysNSStringToUTF8(
+            notification_constants::kNotificationSettingsButtonTag),
+        base::SysNSStringToUTF8([[[category actions] lastObject] identifier]));
+
+    if ([category respondsToSelector:@selector(actionsMenuTitle)]) {
+      EXPECT_EQ("Options", base::SysNSStringToUTF8(
+                               [category valueForKey:@"_actionsMenuTitle"]));
+    }
+
+    UNMutableNotificationContent* content = [builder buildUserNotification];
+    EXPECT_EQ("notificationId",
+              base::SysNSStringToUTF8([content categoryIdentifier]));
+    EXPECT_EQ(0ul, [[content attachments] count]);
+  }
+}
+
+TEST(UNNotificationBuilderMacTest, TestNotificationExtensionNoButtons) {
+  if (@available(macOS 10.14, *)) {
+    base::scoped_nsobject<UNNotificationBuilder> builder =
+        NewTestBuilder(NotificationHandler::Type::EXTENSION);
+
+    UNNotificationCategory* category = [builder buildCategory];
+
+    // Test contents of the category
+    if ([category respondsToSelector:@selector(alternateAction)]) {
+      EXPECT_EQ("Close", base::SysNSStringToUTF8([[category
+                             valueForKey:@"_alternateAction"] title]));
+      EXPECT_EQ(base::SysNSStringToUTF8(
+                    notification_constants::kNotificationCloseButtonTag),
+                base::SysNSStringToUTF8(
+                    [[category valueForKey:@"_alternateAction"] identifier]));
+
+      EXPECT_EQ(0ul, [[category actions] count]);
+    } else {
+      EXPECT_EQ("Close", base::SysNSStringToUTF8(
+                             [[[category actions] firstObject] title]));
+      EXPECT_EQ(base::SysNSStringToUTF8(
+                    notification_constants::kNotificationCloseButtonTag),
+                base::SysNSStringToUTF8(
+                    [[[category actions] firstObject] identifier]));
+
+      EXPECT_EQ(1ul, [[category actions] count]);
+    }
+
+    UNMutableNotificationContent* content = [builder buildUserNotification];
+    EXPECT_EQ("notificationId",
+              base::SysNSStringToUTF8([content categoryIdentifier]));
+  }
+}
+
+TEST(UNNotificationBuilderMacTest, TestNotificationExtensionTwoButtons) {
+  if (@available(macOS 10.14, *)) {
+    base::scoped_nsobject<UNNotificationBuilder> builder =
+        NewTestBuilder(NotificationHandler::Type::EXTENSION);
+
+    [builder setButtons:@"Button1" secondaryButton:@"Button2"];
+    UNNotificationCategory* category = [builder buildCategory];
+
+    // Test contents of the category
+    if ([category respondsToSelector:@selector(alternateAction)]) {
+      EXPECT_EQ("Close", base::SysNSStringToUTF8([[category
+                             valueForKey:@"_alternateAction"] title]));
+      EXPECT_EQ(base::SysNSStringToUTF8(
+                    notification_constants::kNotificationCloseButtonTag),
+                base::SysNSStringToUTF8(
+                    [[category valueForKey:@"_alternateAction"] identifier]));
+      EXPECT_EQ(2ul, [[category actions] count]);
+    } else {
+      EXPECT_EQ("Close", base::SysNSStringToUTF8(
+                             [[[category actions] firstObject] title]));
+      EXPECT_EQ(base::SysNSStringToUTF8(
+                    notification_constants::kNotificationCloseButtonTag),
+                base::SysNSStringToUTF8(
+                    [[[category actions] firstObject] identifier]));
+      EXPECT_EQ(3ul, [[category actions] count]);
+    }
+
+    EXPECT_EQ("Button1",
+              base::SysNSStringToUTF8([[category actions][0] title]));
+    EXPECT_EQ(
+        base::SysNSStringToUTF8(notification_constants::kNotificationButtonOne),
+        base::SysNSStringToUTF8([[category actions][0] identifier]));
+
+    EXPECT_EQ("Button2",
+              base::SysNSStringToUTF8([[[category actions] lastObject] title]));
+    EXPECT_EQ(
+        base::SysNSStringToUTF8(notification_constants::kNotificationButtonTwo),
+        base::SysNSStringToUTF8([[[category actions] lastObject] identifier]));
+
+    if ([category respondsToSelector:@selector(actionsMenuTitle)]) {
+      EXPECT_EQ("Options", base::SysNSStringToUTF8(
+                               [category valueForKey:@"_actionsMenuTitle"]));
+    }
+
+    UNMutableNotificationContent* content = [builder buildUserNotification];
+    EXPECT_EQ("notificationId",
+              base::SysNSStringToUTF8([content categoryIdentifier]));
+    EXPECT_EQ(0ul, [[content attachments] count]);
+  }
+}
+
 TEST(UNNotificationBuilderMacTest, TestNotificationDataMissingContextMessage) {
   if (@available(macOS 10.14, *)) {
     base::scoped_nsobject<UNNotificationBuilder> builder =
diff --git a/chrome/browser/ui/cocoa/notifications/unnotification_response_builder_mac.mm b/chrome/browser/ui/cocoa/notifications/unnotification_response_builder_mac.mm
index 97eefc3..46c7efa2 100644
--- a/chrome/browser/ui/cocoa/notifications/unnotification_response_builder_mac.mm
+++ b/chrome/browser/ui/cocoa/notifications/unnotification_response_builder_mac.mm
@@ -58,6 +58,16 @@
                  isEqualToString:notification_constants::
                                      kNotificationSettingsButtonTag]) {
     operation = NotificationOperation::NOTIFICATION_SETTINGS;
+  } else if ([[response actionIdentifier]
+                 isEqualToString:notification_constants::
+                                     kNotificationButtonOne]) {
+    operation = NotificationOperation::NOTIFICATION_CLICK;
+    buttonIndex = 0;
+  } else if ([[response actionIdentifier]
+                 isEqualToString:notification_constants::
+                                     kNotificationButtonTwo]) {
+    operation = NotificationOperation::NOTIFICATION_CLICK;
+    buttonIndex = 1;
   } else {
     NOTREACHED();
   }
diff --git a/chrome/browser/ui/cocoa/notifications/unnotification_response_builder_mac_unittest.mm b/chrome/browser/ui/cocoa/notifications/unnotification_response_builder_mac_unittest.mm
index 6bb15c3f..21a9379 100644
--- a/chrome/browser/ui/cocoa/notifications/unnotification_response_builder_mac_unittest.mm
+++ b/chrome/browser/ui/cocoa/notifications/unnotification_response_builder_mac_unittest.mm
@@ -53,7 +53,9 @@
 base::scoped_nsobject<UNNotificationBuilder> NewTestBuilder(
     NotificationHandler::Type type) {
   base::scoped_nsobject<UNNotificationBuilder> builder(
-      [[UNNotificationBuilder alloc] init]);
+      [[UNNotificationBuilder alloc] initWithCloseLabel:@"Close"
+                                           optionsLabel:@"Options"
+                                          settingsLabel:@"Settings"]);
   [builder setTitle:@"Title"];
   [builder setSubTitle:@"https://www.moe.com"];
   [builder setContextMessage:@"hey there"];
@@ -210,3 +212,55 @@
               buttonIndex.intValue);
   }
 }
+
+TEST(UNNotificationResponseBuilderMacTest, TestNotificationButtonOne) {
+  if (@available(macOS 10.14, *)) {
+    base::scoped_nsobject<UNNotificationBuilder> builder =
+        NewTestBuilder(NotificationHandler::Type::WEB_PERSISTENT);
+    UNMutableNotificationContent* content = [builder buildUserNotification];
+    base::scoped_nsobject<NSMutableDictionary> userInfo(
+        [[content userInfo] mutableCopy]);
+
+    FakeUNNotificationResponse* fakeResponse = CreateFakeResponse(userInfo);
+    fakeResponse.actionIdentifier =
+        notification_constants::kNotificationButtonOne;
+
+    NSDictionary* response = [UNNotificationResponseBuilder
+        buildDictionary:static_cast<UNNotificationResponse*>(fakeResponse)];
+
+    NSNumber* operation =
+        [response objectForKey:notification_constants::kNotificationOperation];
+    NSNumber* buttonIndex = [response
+        objectForKey:notification_constants::kNotificationButtonIndex];
+
+    EXPECT_EQ(static_cast<int>(NotificationOperation::NOTIFICATION_CLICK),
+              operation.intValue);
+    EXPECT_EQ(0, buttonIndex.intValue);
+  }
+}
+
+TEST(UNNotificationResponseBuilderMacTest, TestNotificationButtonTwo) {
+  if (@available(macOS 10.14, *)) {
+    base::scoped_nsobject<UNNotificationBuilder> builder =
+        NewTestBuilder(NotificationHandler::Type::WEB_PERSISTENT);
+    UNMutableNotificationContent* content = [builder buildUserNotification];
+    base::scoped_nsobject<NSMutableDictionary> userInfo(
+        [[content userInfo] mutableCopy]);
+
+    FakeUNNotificationResponse* fakeResponse = CreateFakeResponse(userInfo);
+    fakeResponse.actionIdentifier =
+        notification_constants::kNotificationButtonTwo;
+
+    NSDictionary* response = [UNNotificationResponseBuilder
+        buildDictionary:static_cast<UNNotificationResponse*>(fakeResponse)];
+
+    NSNumber* operation =
+        [response objectForKey:notification_constants::kNotificationOperation];
+    NSNumber* buttonIndex = [response
+        objectForKey:notification_constants::kNotificationButtonIndex];
+
+    EXPECT_EQ(static_cast<int>(NotificationOperation::NOTIFICATION_CLICK),
+              operation.intValue);
+    EXPECT_EQ(1, buttonIndex.intValue);
+  }
+}
diff --git a/chrome/browser/ui/views/sync/dice_bubble_sync_promo_view.cc b/chrome/browser/ui/views/sync/dice_bubble_sync_promo_view.cc
index 9589488a..b47ce95 100644
--- a/chrome/browser/ui/views/sync/dice_bubble_sync_promo_view.cc
+++ b/chrome/browser/ui/views/sync/dice_bubble_sync_promo_view.cc
@@ -54,37 +54,31 @@
     AddChildView(title);
   }
 
+  views::Button::PressedCallback callback = base::BindRepeating(
+      [](DiceBubbleSyncPromoView* promo) {
+        promo->EnableSync(true, promo->signin_button_view_->account());
+      },
+      base::Unretained(this));
   if (account.IsEmpty()) {
-    signin_button_view_ =
-        new DiceSigninButtonView(this, signin_button_prominent);
+    signin_button_view_ = AddChildView(std::make_unique<DiceSigninButtonView>(
+        std::move(callback), signin_button_prominent));
   } else {
     gfx::Image account_icon = account.account_image;
     if (account_icon.IsEmpty()) {
       account_icon = ui::ResourceBundle::GetSharedInstance().GetImageNamed(
           profiles::GetPlaceholderAvatarIconResourceID());
     }
-    signin_button_view_ =
-        new DiceSigninButtonView(account, account_icon, this,
-                                 /*use_account_name_as_title=*/true);
+    signin_button_view_ = AddChildView(std::make_unique<DiceSigninButtonView>(
+        account, account_icon, std::move(callback),
+        /*use_account_name_as_title=*/true));
   }
   signin_metrics::RecordSigninImpressionUserActionForAccessPoint(access_point);
   signin_metrics::RecordSigninImpressionWithAccountUserActionForAccessPoint(
       access_point, !account.IsEmpty() /* with_account */);
-  AddChildView(signin_button_view_);
 }
 
 DiceBubbleSyncPromoView::~DiceBubbleSyncPromoView() = default;
 
-void DiceBubbleSyncPromoView::ButtonPressed(views::Button* sender,
-                                            const ui::Event& event) {
-  if (sender == signin_button_view_->signin_button()) {
-    EnableSync(true /* is_default_promo_account */,
-               signin_button_view_->account());
-    return;
-  }
-  NOTREACHED();
-}
-
 views::View* DiceBubbleSyncPromoView::GetSigninButtonForTesting() {
   return signin_button_view_ ? signin_button_view_->signin_button() : nullptr;
 }
diff --git a/chrome/browser/ui/views/sync/dice_bubble_sync_promo_view.h b/chrome/browser/ui/views/sync/dice_bubble_sync_promo_view.h
index a9f2e2fd..7f2cbb7 100644
--- a/chrome/browser/ui/views/sync/dice_bubble_sync_promo_view.h
+++ b/chrome/browser/ui/views/sync/dice_bubble_sync_promo_view.h
@@ -11,7 +11,6 @@
 #include "base/macros.h"
 #include "chrome/browser/ui/sync/bubble_sync_promo_delegate.h"
 #include "components/signin/public/base/signin_metrics.h"
-#include "ui/views/controls/button/button.h"
 #include "ui/views/style/typography.h"
 #include "ui/views/view.h"
 
@@ -26,8 +25,7 @@
 //   the user to sign in to Chrome.
 // * If Chrome has at least one account, then the promo button is personalized
 //   with the user full name and avatar icon and allows the user to enable sync.
-class DiceBubbleSyncPromoView : public views::View,
-                                public views::ButtonListener {
+class DiceBubbleSyncPromoView : public views::View {
  public:
   // Creates a personalized sync promo view.
   // |delegate| is not owned by DiceBubbleSyncPromoView.
@@ -46,9 +44,6 @@
                           int text_style = views::style::STYLE_PRIMARY);
   ~DiceBubbleSyncPromoView() override;
 
-  // views::ButtonListener:
-  void ButtonPressed(views::Button* sender, const ui::Event& event) override;
-
   // Returns the sign-in button.
   views::View* GetSigninButtonForTesting();
 
diff --git a/chrome/browser/ui/views/sync/dice_signin_button_view.cc b/chrome/browser/ui/views/sync/dice_signin_button_view.cc
index a1f1855a..058299ec 100644
--- a/chrome/browser/ui/views/sync/dice_signin_button_view.cc
+++ b/chrome/browser/ui/views/sync/dice_signin_button_view.cc
@@ -22,13 +22,13 @@
 #include "ui/views/layout/grid_layout.h"
 
 DiceSigninButtonView::DiceSigninButtonView(
-    views::ButtonListener* button_listener,
+    views::Button::PressedCallback callback,
     bool prominent)
     : account_(base::nullopt) {
   SetLayoutManager(std::make_unique<views::FillLayout>());
   // Regular MD text button when there is no account.
   auto button = std::make_unique<views::MdTextButton>(
-      button_listener,
+      std::move(callback),
       l10n_util::GetStringUTF16(IDS_PROFILES_DICE_SIGNIN_BUTTON));
   button->SetProminent(prominent);
   signin_button_ = AddChildView(std::move(button));
@@ -37,7 +37,7 @@
 DiceSigninButtonView::DiceSigninButtonView(
     const AccountInfo& account,
     const gfx::Image& account_icon,
-    views::ButtonListener* button_listener,
+    views::Button::PressedCallback callback,
     bool use_account_name_as_title)
     : account_(account) {
   views::GridLayout* grid_layout =
@@ -57,8 +57,8 @@
           ? base::UTF8ToUTF16(account.full_name)
           : l10n_util::GetStringUTF16(IDS_PROFILES_DICE_NOT_SYNCING_TITLE);
   auto account_card = std::make_unique<HoverButton>(
-      button_listener, std::move(account_icon_view), card_title,
-      base::ASCIIToUTF16(account_->email));
+      views::Button::PressedCallback(), std::move(account_icon_view),
+      card_title, base::ASCIIToUTF16(account_->email));
   account_card->SetBorder(nullptr);
   account_card->SetEnabled(false);
   grid_layout->AddView(std::move(account_card));
@@ -70,7 +70,7 @@
   columns->AddColumn(views::GridLayout::FILL, views::GridLayout::TRAILING, 1.0,
                      views::GridLayout::ColumnSize::kUsePreferred, 0, 0);
   auto signin_button = std::make_unique<views::MdTextButton>(
-      button_listener,
+      std::move(callback),
       l10n_util::GetStringUTF16(IDS_PROFILES_DICE_SIGNIN_BUTTON));
   signin_button->SetProminent(true);
   signin_button_ = grid_layout->AddView(std::move(signin_button));
diff --git a/chrome/browser/ui/views/sync/dice_signin_button_view.h b/chrome/browser/ui/views/sync/dice_signin_button_view.h
index ea99bef..dbecbb3 100644
--- a/chrome/browser/ui/views/sync/dice_signin_button_view.h
+++ b/chrome/browser/ui/views/sync/dice_signin_button_view.h
@@ -21,19 +21,17 @@
 class DiceSigninButtonView : public views::View {
  public:
   // Create a non-personalized sign-in button.
-  // |button_listener| is called every time the user interacts with this button.
+  // |callback| is called every time the user interacts with this button.
   // The button is prominent by default but can be made non-prominent by setting
   // |prominent| to false.
-  explicit DiceSigninButtonView(views::ButtonListener* button_listener,
+  explicit DiceSigninButtonView(views::Button::PressedCallback callback,
                                 bool prominent = true);
 
   // Creates a sign-in button personalized with the data from |account|.
-  // |button_listener| will be called for events originating from |this| or from
-  // |drop_down_arrow|. The drop down arrow will only be shown if
-  // |show_drop_down_arrow| is true.
+  // |callback| is called every time the user interacts with this button.
   DiceSigninButtonView(const AccountInfo& account_info,
                        const gfx::Image& account_icon,
-                       views::ButtonListener* button_listener,
+                       views::Button::PressedCallback callback,
                        bool use_account_name_as_title = false);
   ~DiceSigninButtonView() override;
 
diff --git a/chrome/browser/ui/views/sync/profile_signin_confirmation_dialog_views.cc b/chrome/browser/ui/views/sync/profile_signin_confirmation_dialog_views.cc
index ff2e5fe0..0430335 100644
--- a/chrome/browser/ui/views/sync/profile_signin_confirmation_dialog_views.cc
+++ b/chrome/browser/ui/views/sync/profile_signin_confirmation_dialog_views.cc
@@ -66,7 +66,10 @@
 
   if (prompt_for_new_profile) {
     SetExtraView(std::make_unique<views::MdTextButton>(
-        this, l10n_util::GetStringUTF16(IDS_ENTERPRISE_SIGNIN_CONTINUE)));
+        base::BindRepeating(
+            &ProfileSigninConfirmationDialogViews::ContinueSigninButtonPressed,
+            base::Unretained(this)),
+        l10n_util::GetStringUTF16(IDS_ENTERPRISE_SIGNIN_CONTINUE)));
   }
 
   using Delegate = ui::ProfileSigninConfirmationDelegate;
@@ -246,9 +249,7 @@
                          kPreferredWidth, explanation_label_height);
 }
 
-void ProfileSigninConfirmationDialogViews::ButtonPressed(
-    views::Button* sender,
-    const ui::Event& event) {
+void ProfileSigninConfirmationDialogViews::ContinueSigninButtonPressed() {
   DCHECK(prompt_for_new_profile_);
   if (delegate_) {
     delegate_->OnContinueSignin();
diff --git a/chrome/browser/ui/views/sync/profile_signin_confirmation_dialog_views.h b/chrome/browser/ui/views/sync/profile_signin_confirmation_dialog_views.h
index d83079fab..60b06a7 100644
--- a/chrome/browser/ui/views/sync/profile_signin_confirmation_dialog_views.h
+++ b/chrome/browser/ui/views/sync/profile_signin_confirmation_dialog_views.h
@@ -10,7 +10,6 @@
 #include "base/compiler_specific.h"
 #include "base/macros.h"
 #include "chrome/browser/ui/sync/profile_signin_confirmation_helper.h"
-#include "ui/views/controls/button/button.h"
 #include "ui/views/window/dialog_delegate.h"
 
 class Browser;
@@ -18,8 +17,7 @@
 
 // A tab-modal dialog to allow a user signing in with a managed account
 // to create a new Chrome profile.
-class ProfileSigninConfirmationDialogViews : public views::DialogDelegateView,
-                                             public views::ButtonListener {
+class ProfileSigninConfirmationDialogViews : public views::DialogDelegateView {
  public:
   // Create and show the dialog, which owns itself.
   static void ShowDialog(
@@ -47,8 +45,7 @@
   void ViewHierarchyChanged(
       const views::ViewHierarchyChangedDetails& details) override;
 
-  // views::ButtonListener:
-  void ButtonPressed(views::Button*, const ui::Event& event) override;
+  void ContinueSigninButtonPressed();
 
   // Called when the "learn more" link is clicked.
   void LearnMoreClicked(const ui::Event& event);
diff --git a/chrome/browser/ui/views/test/view_event_test_base.cc b/chrome/browser/ui/views/test/view_event_test_base.cc
index 3ccd1cc..ea517ab7 100644
--- a/chrome/browser/ui/views/test/view_event_test_base.cc
+++ b/chrome/browser/ui/views/test/view_event_test_base.cc
@@ -25,9 +25,9 @@
 #include "ui/views/test/test_desktop_screen_x11.h"
 #endif  // defined(USE_X11)
 
-#if defined(OS_LINUX) && defined(USE_OZONE)
+#if defined(OS_LINUX) && !defined(OS_CHROMEOS) && defined(USE_OZONE)
 #include "ui/views/test/test_desktop_screen_ozone.h"
-#endif  // defined(OS_LINUX) && defined(USE_OZONE)
+#endif  // defined(OS_LINUX) && !defined(OS_CHROMEOS) && defined(USE_OZONE)
 #endif
 
 namespace {
@@ -102,7 +102,7 @@
   if (!features::IsUsingOzonePlatform())
     views::test::TestDesktopScreenX11::GetInstance();
 #endif  // defined(USE_X11)
-#if !defined(OS_CHROMEOS) && defined(OS_LINUX) && defined(USE_OZONE)
+#if defined(OS_LINUX) && !defined(OS_CHROMEOS) && defined(USE_OZONE)
   if (!display::Screen::GetScreen())
     display::Screen::SetScreenInstance(
         views::test::TestDesktopScreenOzone::GetInstance());
diff --git a/chrome/browser/ui/webui/settings/chromeos/account_manager_handler.cc b/chrome/browser/ui/webui/settings/chromeos/account_manager_handler.cc
index b9acb8d7..9efbeab4 100644
--- a/chrome/browser/ui/webui/settings/chromeos/account_manager_handler.cc
+++ b/chrome/browser/ui/webui/settings/chromeos/account_manager_handler.cc
@@ -230,20 +230,21 @@
 
   base::Value callback_id = args_list[0].Clone();
 
-  account_manager_->GetAccounts(
-      base::BindOnce(&AccountManagerUIHandler::OnGetAccounts,
-                     weak_factory_.GetWeakPtr(), std::move(callback_id)));
+  account_manager_->CheckDummyGaiaTokenForAllAccounts(base::BindOnce(
+      &AccountManagerUIHandler::OnCheckDummyGaiaTokenForAllAccounts,
+      weak_factory_.GetWeakPtr(), std::move(callback_id)));
 }
 
-void AccountManagerUIHandler::OnGetAccounts(
+void AccountManagerUIHandler::OnCheckDummyGaiaTokenForAllAccounts(
     base::Value callback_id,
-    const std::vector<AccountManager::Account>& stored_accounts) {
+    const std::vector<std::pair<chromeos::AccountManager::Account, bool>>&
+        account_dummy_token_list) {
   user_manager::User* user = ProfileHelper::Get()->GetUserByProfile(profile_);
   DCHECK(user);
 
   base::DictionaryValue gaia_device_account;
   base::ListValue accounts =
-      GetSecondaryGaiaAccounts(stored_accounts, user->GetAccountId(),
+      GetSecondaryGaiaAccounts(account_dummy_token_list, user->GetAccountId(),
                                profile_->IsChild(), &gaia_device_account);
 
   AccountBuilder device_account;
@@ -291,12 +292,14 @@
 }
 
 base::ListValue AccountManagerUIHandler::GetSecondaryGaiaAccounts(
-    const std::vector<AccountManager::Account>& stored_accounts,
+    const std::vector<std::pair<chromeos::AccountManager::Account, bool>>&
+        account_dummy_token_list,
     const AccountId device_account_id,
     const bool is_child_user,
     base::DictionaryValue* device_account) {
   base::ListValue accounts;
-  for (const auto& stored_account : stored_accounts) {
+  for (const auto& account_token_pair : account_dummy_token_list) {
+    const AccountManager::Account& stored_account = account_token_pair.first;
     const AccountManager::AccountKey& account_key = stored_account.key;
     // We are only interested in listing GAIA accounts.
     if (account_key.account_type !=
@@ -304,7 +307,6 @@
       continue;
     }
 
-
     base::Optional<AccountInfo> maybe_account_info =
         identity_manager_
             ->FindExtendedAccountInfoForAccountWithRefreshTokenByGaiaId(
@@ -317,13 +319,11 @@
         .SetIsDeviceAccount(false)
         .SetFullName(maybe_account_info->full_name)
         .SetEmail(stored_account.raw_email)
-        // Secondary accounts in child user session cannot be unmigrated. If
-        // such account has dummy gaia token, it was invalidated.
-        .SetUnmigrated(!is_child_user &&
-                       account_manager_->HasDummyGaiaTokenSync(account_key))
+        .SetUnmigrated(!is_child_user && account_token_pair.second)
         .SetIsSignedIn(!identity_manager_
                             ->HasAccountWithRefreshTokenInPersistentErrorState(
                                 maybe_account_info->account_id));
+
     if (!maybe_account_info->account_image.IsEmpty()) {
       account.SetPic(webui::GetBitmapDataUrl(
           maybe_account_info->account_image.AsBitmap()));
diff --git a/chrome/browser/ui/webui/settings/chromeos/account_manager_handler.h b/chrome/browser/ui/webui/settings/chromeos/account_manager_handler.h
index 1a0e815a..366cd6d 100644
--- a/chrome/browser/ui/webui/settings/chromeos/account_manager_handler.h
+++ b/chrome/browser/ui/webui/settings/chromeos/account_manager_handler.h
@@ -71,10 +71,11 @@
   // WebUI "showWelcomeDialogIfRequired" message callback.
   void HandleShowWelcomeDialogIfRequired(const base::ListValue* args);
 
-  // |AccountManager::GetAccounts| callback.
-  void OnGetAccounts(
+  // |AccountManager::CheckDummyGaiaTokenForAllAccounts| callback.
+  void OnCheckDummyGaiaTokenForAllAccounts(
       base::Value callback_id,
-      const std::vector<AccountManager::Account>& stored_accounts);
+      const std::vector<std::pair<chromeos::AccountManager::Account, bool>>&
+          account_dummy_token_list);
 
   // Returns secondary Gaia accounts from |stored_accounts| list. If the Device
   // Account is a Gaia account, populates |device_account| with information
@@ -83,7 +84,8 @@
   // in this case "unmigrated" property will be always false for secondary
   // accounts.
   base::ListValue GetSecondaryGaiaAccounts(
-      const std::vector<AccountManager::Account>& stored_accounts,
+      const std::vector<std::pair<chromeos::AccountManager::Account, bool>>&
+          account_dummy_token_list,
       const AccountId device_account_id,
       const bool is_child_user,
       base::DictionaryValue* device_account);
diff --git a/chrome/browser/updates/announcement_notification/announcement_notification_service.cc b/chrome/browser/updates/announcement_notification/announcement_notification_service.cc
index 6feb737..9d938c7b 100644
--- a/chrome/browser/updates/announcement_notification/announcement_notification_service.cc
+++ b/chrome/browser/updates/announcement_notification/announcement_notification_service.cc
@@ -266,7 +266,8 @@
   if (!profile)
     return false;
 
-  return !(profile->IsGuestSession() || profile->IsSystemProfile());
+  return !(profile->IsGuestSession() || profile->IsEphemeralGuestProfile() ||
+           profile->IsSystemProfile());
 }
 
 AnnouncementNotificationService::AnnouncementNotificationService() = default;
diff --git a/chrome/browser/upgrade_detector/directory_monitor.cc b/chrome/browser/upgrade_detector/directory_monitor.cc
new file mode 100644
index 0000000..a8161f8
--- /dev/null
+++ b/chrome/browser/upgrade_detector/directory_monitor.cc
@@ -0,0 +1,86 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/upgrade_detector/directory_monitor.h"
+
+#include <memory>
+#include <utility>
+
+#include "base/base_paths.h"
+#include "base/bind.h"
+#include "base/check.h"
+#include "base/files/file_path.h"
+#include "base/files/file_path_watcher.h"
+#include "base/location.h"
+#include "base/memory/scoped_refptr.h"
+#include "base/path_service.h"
+#include "base/sequenced_task_runner.h"
+#include "base/task/task_traits.h"
+#include "base/task/thread_pool.h"
+#include "base/threading/sequenced_task_runner_handle.h"
+#include "build/build_config.h"
+#include "chrome/browser/upgrade_detector/installed_version_monitor.h"
+
+#if defined(OS_MAC)
+#include "base/mac/bundle_locations.h"
+#endif
+
+namespace {
+
+base::FilePath GetDefaultMonitorLocation() {
+#if defined(OS_MAC)
+  return base::mac::OuterBundlePath();
+#else
+  return base::PathService::CheckedGet(base::DIR_EXE);
+#endif
+}
+
+}  // namespace
+
+DirectoryMonitor::DirectoryMonitor(base::FilePath install_dir)
+    : install_dir_(std::move(install_dir)) {
+  DCHECK(!install_dir_.empty());
+}
+
+DirectoryMonitor::~DirectoryMonitor() {
+  if (watcher_)
+    task_runner_->DeleteSoon(FROM_HERE, std::move(watcher_));
+}
+
+void DirectoryMonitor::Start(Callback on_change_callback) {
+  DCHECK(!watcher_);
+  task_runner_ = base::ThreadPool::CreateSequencedTaskRunner(
+      {base::TaskPriority::BEST_EFFORT,
+       base::TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN, base::MayBlock()});
+  watcher_ = std::make_unique<base::FilePathWatcher>();
+
+  // Start the watcher on a background sequence, reporting all events back to
+  // this sequence. base::Unretained is safe because the watcher instance lives
+  // on the target sequence and will be destroyed there in a subsequent task.
+  task_runner_->PostTaskAndReplyWithResult(
+      FROM_HERE,
+      base::BindOnce(
+          &base::FilePathWatcher::Watch, base::Unretained(watcher_.get()),
+          std::move(install_dir_),
+          /*recursive=*/false,
+          base::BindRepeating(
+              [](scoped_refptr<base::SequencedTaskRunner> main_sequence,
+                 const Callback& on_change_callback, const base::FilePath&,
+                 bool error) {
+                main_sequence->PostTask(
+                    FROM_HERE, base::BindOnce(on_change_callback, error));
+              },
+              base::SequencedTaskRunnerHandle::Get(), on_change_callback)),
+      base::BindOnce(
+          [](Callback on_change_callback, bool start_result) {
+            if (!start_result)
+              on_change_callback.Run(/*error=*/true);
+          },
+          on_change_callback));
+}
+
+// static
+std::unique_ptr<InstalledVersionMonitor> InstalledVersionMonitor::Create() {
+  return std::make_unique<DirectoryMonitor>(GetDefaultMonitorLocation());
+}
diff --git a/chrome/browser/upgrade_detector/directory_monitor.h b/chrome/browser/upgrade_detector/directory_monitor.h
new file mode 100644
index 0000000..c671dd8
--- /dev/null
+++ b/chrome/browser/upgrade_detector/directory_monitor.h
@@ -0,0 +1,35 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_UPGRADE_DETECTOR_DIRECTORY_MONITOR_H_
+#define CHROME_BROWSER_UPGRADE_DETECTOR_DIRECTORY_MONITOR_H_
+
+#include <memory>
+
+#include "base/files/file_path.h"
+#include "base/memory/scoped_refptr.h"
+#include "chrome/browser/upgrade_detector/installed_version_monitor.h"
+
+namespace base {
+class FilePathWatcher;
+class SequencedTaskRunner;
+}  // namespace base
+
+// A monitor of installs that watches for changes in the browser's installation
+// directory.
+class DirectoryMonitor final : public InstalledVersionMonitor {
+ public:
+  explicit DirectoryMonitor(base::FilePath install_dir);
+  ~DirectoryMonitor() override;
+
+  // InstalledVersionMonitor:
+  void Start(Callback on_change_callback) override;
+
+ private:
+  base::FilePath install_dir_;
+  scoped_refptr<base::SequencedTaskRunner> task_runner_;
+  std::unique_ptr<base::FilePathWatcher> watcher_;
+};
+
+#endif  // CHROME_BROWSER_UPGRADE_DETECTOR_DIRECTORY_MONITOR_H_
diff --git a/chrome/browser/upgrade_detector/directory_monitor_unittest.cc b/chrome/browser/upgrade_detector/directory_monitor_unittest.cc
new file mode 100644
index 0000000..83a8f86
--- /dev/null
+++ b/chrome/browser/upgrade_detector/directory_monitor_unittest.cc
@@ -0,0 +1,102 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/upgrade_detector/directory_monitor.h"
+
+#include "base/files/file_path.h"
+#include "base/files/file_util.h"
+#include "base/files/scoped_temp_dir.h"
+#include "base/run_loop.h"
+#include "base/test/mock_callback.h"
+#include "base/test/task_environment.h"
+#include "base/time/time.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+class DirectoryMonitorTest : public ::testing::Test {
+ protected:
+  void SetUp() override { ASSERT_TRUE(temp_dir_.CreateUniqueTempDir()); }
+
+  // Returns the test directory to monitor.
+  base::FilePath GetDirectoryToMonitor() { return temp_dir_.GetPath(); }
+
+  base::ScopedTempDir temp_dir_;
+  base::test::TaskEnvironment task_environment_;
+};
+
+// Tests that the callback is not invoked when nothing happens.
+TEST_F(DirectoryMonitorTest, NoNoise) {
+  DirectoryMonitor monitor(GetDirectoryToMonitor());
+  ::testing::StrictMock<base::MockRepeatingCallback<void(bool)>> callback;
+  monitor.Start(callback.Get());
+  task_environment_.RunUntilIdle();
+}
+
+// Tests that the callback is invoked when the directory is modified.
+TEST_F(DirectoryMonitorTest, OneChange) {
+  DirectoryMonitor monitor(GetDirectoryToMonitor());
+  ::testing::StrictMock<base::MockRepeatingCallback<void(bool)>> callback;
+
+  monitor.Start(callback.Get());
+  task_environment_.RunUntilIdle();
+
+  base::RunLoop run_loop;
+  EXPECT_CALL(callback, Run(false)).WillOnce([&run_loop]() {
+    run_loop.Quit();
+  });
+  ASSERT_TRUE(base::WriteFile(
+      GetDirectoryToMonitor().Append(FILE_PATH_LITERAL("some file")),
+      "hi, mom"));
+  run_loop.Run();
+}
+
+// Tests that the callback is invoked multiple times for multiple
+// modifications.
+TEST_F(DirectoryMonitorTest, MultipleChanges) {
+  DirectoryMonitor monitor(GetDirectoryToMonitor());
+  ::testing::StrictMock<base::MockRepeatingCallback<void(bool)>> callback;
+
+  monitor.Start(callback.Get());
+  task_environment_.RunUntilIdle();
+  {
+    base::RunLoop run_loop;
+    EXPECT_CALL(callback, Run(false)).WillOnce([&run_loop]() {
+      run_loop.Quit();
+    });
+    ASSERT_TRUE(base::WriteFile(
+        GetDirectoryToMonitor().Append(FILE_PATH_LITERAL("some file")),
+        "hi, mom"));
+    run_loop.Run();
+    ASSERT_TRUE(::testing::Mock::VerifyAndClearExpectations(&callback));
+  }
+
+  {
+    base::RunLoop run_loop;
+    EXPECT_CALL(callback, Run(false)).WillOnce([&run_loop]() {
+      run_loop.Quit();
+    });
+    ASSERT_TRUE(base::WriteFile(
+        GetDirectoryToMonitor().Append(FILE_PATH_LITERAL("other file")),
+        "hi, dad"));
+    run_loop.Run();
+    ASSERT_TRUE(::testing::Mock::VerifyAndClearExpectations(&callback));
+  }
+}
+
+// Tests that the callback is invoked when the directory's mtime is modified.
+TEST_F(DirectoryMonitorTest, MtimeChange) {
+  DirectoryMonitor monitor(GetDirectoryToMonitor());
+  ::testing::StrictMock<base::MockRepeatingCallback<void(bool)>> callback;
+
+  monitor.Start(callback.Get());
+  task_environment_.RunUntilIdle();
+
+  base::RunLoop run_loop;
+  EXPECT_CALL(callback, Run(false)).WillOnce([&run_loop]() {
+    run_loop.Quit();
+  });
+  const base::Time now = base::Time::Now();
+  ASSERT_TRUE(base::TouchFile(GetDirectoryToMonitor(), now, now));
+  run_loop.Run();
+}
diff --git a/chrome/browser/upgrade_detector/installed_version_monitor.h b/chrome/browser/upgrade_detector/installed_version_monitor.h
new file mode 100644
index 0000000..5a8186631
--- /dev/null
+++ b/chrome/browser/upgrade_detector/installed_version_monitor.h
@@ -0,0 +1,39 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_UPGRADE_DETECTOR_INSTALLED_VERSION_MONITOR_H_
+#define CHROME_BROWSER_UPGRADE_DETECTOR_INSTALLED_VERSION_MONITOR_H_
+
+#include <memory>
+
+#include "base/callback_forward.h"
+
+// An abstract base for an object that monitors the browser's installation for
+// updates.
+class InstalledVersionMonitor {
+ public:
+  // A callback run to indicate either a monitored change or an error. The
+  // single boolean argument is true in case of error, or false in case of a
+  // change.
+  using Callback = base::RepeatingCallback<void(bool)>;
+
+  // Returns a new instance.
+  static std::unique_ptr<InstalledVersionMonitor> Create();
+
+  InstalledVersionMonitor(const InstalledVersionMonitor&) = delete;
+  InstalledVersionMonitor& operator=(const InstalledVersionMonitor&) = delete;
+  virtual ~InstalledVersionMonitor() = default;
+
+  // Starts the monitor; may only be called once per instance. |callback| will
+  // be run zero or more times with a false argument to report changes in the
+  // installation, and at most one time with a true argument to report an error.
+  // In case of error, no further notifications will be made. There is no
+  // guarantee that |callback| will not be run after this instance is destroyed.
+  virtual void Start(Callback callback) = 0;
+
+ protected:
+  InstalledVersionMonitor() = default;
+};
+
+#endif  // CHROME_BROWSER_UPGRADE_DETECTOR_INSTALLED_VERSION_MONITOR_H_
diff --git a/chrome/browser/upgrade_detector/installed_version_poller.cc b/chrome/browser/upgrade_detector/installed_version_poller.cc
index c474795..3202016 100644
--- a/chrome/browser/upgrade_detector/installed_version_poller.cc
+++ b/chrome/browser/upgrade_detector/installed_version_poller.cc
@@ -12,11 +12,15 @@
 #include "base/bind.h"
 #include "base/command_line.h"
 #include "base/location.h"
+#include "base/metrics/histogram_functions.h"
+#include "base/sequenced_task_runner.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/task/post_task.h"
 #include "base/task/thread_pool.h"
+#include "base/threading/sequenced_task_runner_handle.h"
 #include "chrome/browser/upgrade_detector/build_state.h"
 #include "chrome/browser/upgrade_detector/get_installed_version.h"
+#include "chrome/browser/upgrade_detector/installed_version_monitor.h"
 #include "chrome/common/chrome_switches.h"
 #include "components/version_info/version_info.h"
 
@@ -100,6 +104,15 @@
 
 // InstalledVersionPoller ------------------------------------------------------
 
+// These values are persisted to logs. Entries should not be renumbered and
+// numeric values should never be reused.
+enum class InstalledVersionPoller::PollType {
+  kStartup = 0,   // The initial poll created at startup.
+  kMonitor = 1,   // A poll in response to notification from the monitor.
+  kPeriodic = 2,  // The periodic poll.
+  kMaxValue = kPeriodic
+};
+
 // static
 const base::TimeDelta InstalledVersionPoller::kDefaultPollingInterval =
     base::TimeDelta::FromHours(2);
@@ -107,31 +120,56 @@
 InstalledVersionPoller::InstalledVersionPoller(BuildState* build_state)
     : InstalledVersionPoller(build_state,
                              GetGetInstalledVersionCallback(),
+                             InstalledVersionMonitor::Create(),
                              nullptr) {}
 
 InstalledVersionPoller::InstalledVersionPoller(
     BuildState* build_state,
     GetInstalledVersionCallback get_installed_version,
+    std::unique_ptr<InstalledVersionMonitor> monitor,
     const base::TickClock* tick_clock)
     : build_state_(build_state),
       get_installed_version_(std::move(get_installed_version)),
-      timer_(FROM_HERE,
-             GetPollingInterval(),
-             base::BindRepeating(&InstalledVersionPoller::Poll,
-                                 base::Unretained(this)),
-             tick_clock) {
+      timer_(tick_clock) {
   // Make the first check in the background without delay. Suppress this if
   // polling is disabled for testing. This prevents all polling from taking
   // place since the result of poll N kicks off poll N+1.
-  if (!g_disabled_for_testing)
-    Poll();
+  if (!g_disabled_for_testing) {
+    StartMonitor(std::move(monitor));
+    Poll(PollType::kStartup);
+  }
 }
 
 InstalledVersionPoller::~InstalledVersionPoller() {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
 }
 
-void InstalledVersionPoller::Poll() {
+void InstalledVersionPoller::StartMonitor(
+    std::unique_ptr<InstalledVersionMonitor> monitor) {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  DCHECK(!monitor_);
+  monitor_ = std::move(monitor);
+  monitor_->Start(base::BindRepeating(&InstalledVersionPoller::OnMonitorResult,
+                                      weak_ptr_factory_.GetWeakPtr()));
+}
+
+void InstalledVersionPoller::OnMonitorResult(bool error) {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+
+  if (!error) {
+    // Wait ten seconds before polling for the new version in case the monitor
+    // provides multiple notifications during a normal update. Repeat
+    // notifications will push back the poll.
+    timer_.Start(FROM_HERE, base::TimeDelta::FromSeconds(10),
+                 base::BindOnce(&InstalledVersionPoller::Poll,
+                                base::Unretained(this), PollType::kMonitor));
+  } else {
+    // An error occurred while monitoring; disable the monitor.
+    monitor_.reset();
+  }
+}
+
+void InstalledVersionPoller::Poll(PollType poll_type) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   // Run the version getter in the background. Get the result back via a weak
   // pointer so that the result is dropped on the floor should this instance be
@@ -142,10 +180,11 @@
        base::TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN, base::MayBlock()},
       base::BindOnce(get_installed_version_),
       base::BindOnce(&InstalledVersionPoller::OnInstalledVersion,
-                     weak_ptr_factory_.GetWeakPtr()));
+                     weak_ptr_factory_.GetWeakPtr(), poll_type));
 }
 
 void InstalledVersionPoller::OnInstalledVersion(
+    PollType poll_type,
     InstalledAndCriticalVersion versions) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
 
@@ -171,7 +210,20 @@
     // version) or differs from the running version. Report it accordingly.
     build_state_->SetUpdate(update_type, versions.installed_version,
                             versions.critical_version);
+    // Report the first type of poll that discovers an update.
+    RecordPollTypeOnce(poll_type);
   }
   // Poll again after the polling interval passes.
-  timer_.Reset();
+  timer_.Start(FROM_HERE, GetPollingInterval(),
+               base::BindOnce(&InstalledVersionPoller::Poll,
+                              base::Unretained(this), PollType::kPeriodic));
+}
+
+void InstalledVersionPoller::RecordPollTypeOnce(PollType poll_type) {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  if (recorded_poll_type_)
+    return;
+
+  base::UmaHistogramEnumeration("UpgradeDetector.PollType", poll_type);
+  recorded_poll_type_ = true;
 }
diff --git a/chrome/browser/upgrade_detector/installed_version_poller.h b/chrome/browser/upgrade_detector/installed_version_poller.h
index 7179ef5..dffb79d4 100644
--- a/chrome/browser/upgrade_detector/installed_version_poller.h
+++ b/chrome/browser/upgrade_detector/installed_version_poller.h
@@ -5,23 +5,30 @@
 #ifndef CHROME_BROWSER_UPGRADE_DETECTOR_INSTALLED_VERSION_POLLER_H_
 #define CHROME_BROWSER_UPGRADE_DETECTOR_INSTALLED_VERSION_POLLER_H_
 
+#include <memory>
+
 #include "base/callback.h"
+#include "base/files/file_path.h"
+#include "base/memory/scoped_refptr.h"
 #include "base/memory/weak_ptr.h"
+#include "base/optional.h"
 #include "base/sequence_checker.h"
 #include "base/time/time.h"
 #include "base/timer/timer.h"
 #include "chrome/browser/upgrade_detector/get_installed_version.h"
 
 class BuildState;
+class InstalledVersionMonitor;
 
 namespace base {
 class TickClock;
 }  // namespace base
 
-// Periodically polls for the installed version of the browser in the
-// background. Polling begins automatically after construction and continues
-// until destruction. The discovered version is provided to the given BuildState
-// on each poll.
+// Polls for the installed version of the browser in the background every two
+// hours. Polling begins automatically after construction and continues until
+// destruction. Modifications to the browser's install directory trigger a
+// premature poll. The discovered version is provided to the given BuildState on
+// each poll.
 class InstalledVersionPoller {
  public:
   // The default polling interval. This may be overridden for testing by
@@ -41,6 +48,7 @@
   // version getter.
   InstalledVersionPoller(BuildState* build_state,
                          GetInstalledVersionCallback get_installed_version,
+                         std::unique_ptr<InstalledVersionMonitor> monitor,
                          const base::TickClock* tick_clock);
   InstalledVersionPoller(const InstalledVersionPoller&) = delete;
   InstalledVersionPoller& operator=(const InstalledVersionPoller&) = delete;
@@ -65,14 +73,39 @@
   }
 
  private:
+  enum class PollType;
+
+  // Starts observing changes to the browser's installation.
+  void StartMonitor(std::unique_ptr<InstalledVersionMonitor> monitor);
+
+  // Handles the result of a change in the browser's installation. If |error| is
+  // false, a task will be scheduled to poll the installed version in the
+  // background. Otherwise, if |error| is true, an error has occurred and no
+  // further changes will be monitored.
+  void OnMonitorResult(bool error);
+
   // Initiates a poll in the background.
-  void Poll();
-  void OnInstalledVersion(InstalledAndCriticalVersion installed_version);
+  void Poll(PollType poll_type);
+
+  // Handles the result of a poll. |poll_type| indicates the reason for the poll
+  // (used for metrics), and |installed_version| contains the discovered version
+  // information.
+  void OnInstalledVersion(PollType poll_type,
+                          InstalledAndCriticalVersion installed_version);
+
+  // Record |poll_type| if no PollType has previously been reported.
+  void RecordPollTypeOnce(PollType poll_type);
 
   SEQUENCE_CHECKER(sequence_checker_);
   BuildState* const build_state_;
   const GetInstalledVersionCallback get_installed_version_;
-  base::RetainingOneShotTimer timer_;
+  base::OneShotTimer timer_;
+
+  // Valid while observing modifications to the installation.
+  std::unique_ptr<InstalledVersionMonitor> monitor_;
+
+  bool recorded_poll_type_ = false;
+
   base::WeakPtrFactory<InstalledVersionPoller> weak_ptr_factory_{this};
 };
 
diff --git a/chrome/browser/upgrade_detector/installed_version_poller_unittest.cc b/chrome/browser/upgrade_detector/installed_version_poller_unittest.cc
index f7ba79e..3bc48e9 100644
--- a/chrome/browser/upgrade_detector/installed_version_poller_unittest.cc
+++ b/chrome/browser/upgrade_detector/installed_version_poller_unittest.cc
@@ -4,16 +4,24 @@
 
 #include "chrome/browser/upgrade_detector/installed_version_poller.h"
 
+#include "stdint.h"
+
+#include <memory>
+#include <utility>
 #include <vector>
 
+#include "base/strings/string_piece.h"
+#include "base/test/metrics/histogram_tester.h"
 #include "base/test/mock_callback.h"
 #include "base/test/task_environment.h"
 #include "chrome/browser/upgrade_detector/build_state.h"
+#include "chrome/browser/upgrade_detector/installed_version_monitor.h"
 #include "chrome/browser/upgrade_detector/mock_build_state_observer.h"
 #include "components/version_info/version_info.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
+using ::testing::_;
 using ::testing::AllOf;
 using ::testing::ByMove;
 using ::testing::Eq;
@@ -22,6 +30,27 @@
 using ::testing::Property;
 using ::testing::Return;
 
+namespace {
+
+constexpr base::StringPiece kPollTypeHistogramName("UpgradeDetector.PollType");
+
+class FakeMonitor final : public InstalledVersionMonitor {
+ public:
+  FakeMonitor() = default;
+
+  // Simulate that either a change was detected (|error| is false) or that an
+  // error occurred (|error| is true).
+  void Notify(bool error) { callback_.Run(error); }
+
+  // InstalledVersionMonitor:
+  void Start(Callback callback) override { callback_ = std::move(callback); }
+
+ private:
+  Callback callback_;
+};
+
+}  // namespace
+
 class InstalledVersionPollerTest : public ::testing::Test {
  protected:
   InstalledVersionPollerTest() { build_state_.AddObserver(&mock_observer_); }
@@ -78,10 +107,23 @@
     return InstalledAndCriticalVersion(GetRollbackVersion());
   }
 
+  std::unique_ptr<InstalledVersionMonitor> MakeMonitor() {
+    EXPECT_FALSE(fake_monitor_);
+    auto monitor = std::make_unique<FakeMonitor>();
+    fake_monitor_ = monitor.get();
+    return monitor;
+  }
+
+  void TriggerMonitor() {
+    ASSERT_NE(fake_monitor_, nullptr);
+    fake_monitor_->Notify(false);
+  }
+
   base::test::TaskEnvironment task_environment_{
       base::test::TaskEnvironment::TimeSource::MOCK_TIME};
   ::testing::StrictMock<MockBuildStateObserver> mock_observer_;
   BuildState build_state_;
+  FakeMonitor* fake_monitor_ = nullptr;
 };
 
 // Tests that a poll returning the current version does not update the
@@ -89,7 +131,7 @@
 TEST_F(InstalledVersionPollerTest, TestNoUpdate) {
   base::MockRepeatingCallback<InstalledAndCriticalVersion()> callback;
   EXPECT_CALL(callback, Run()).WillOnce(Return(ByMove(MakeNoUpdateVersions())));
-  InstalledVersionPoller poller(&build_state_, callback.Get(),
+  InstalledVersionPoller poller(&build_state_, callback.Get(), MakeMonitor(),
                                 task_environment_.GetMockTickClock());
   task_environment_.RunUntilIdle();
   ::testing::Mock::VerifyAndClearExpectations(&callback);
@@ -109,7 +151,7 @@
 
   // No update the first time.
   EXPECT_CALL(callback, Run()).WillOnce(Return(ByMove(MakeNoUpdateVersions())));
-  InstalledVersionPoller poller(&build_state_, callback.Get(),
+  InstalledVersionPoller poller(&build_state_, callback.Get(), MakeMonitor(),
                                 task_environment_.GetMockTickClock());
   task_environment_.RunUntilIdle();
   ::testing::Mock::VerifyAndClearExpectations(&callback);
@@ -157,7 +199,7 @@
           Property(&BuildState::installed_version,
                    Eq(base::Optional<base::Version>(GetUpgradeVersion()))),
           Property(&BuildState::critical_version, IsFalse()))));
-  InstalledVersionPoller poller(&build_state_, callback.Get(),
+  InstalledVersionPoller poller(&build_state_, callback.Get(), MakeMonitor(),
                                 task_environment_.GetMockTickClock());
   task_environment_.RunUntilIdle();
   ::testing::Mock::VerifyAndClearExpectations(&callback);
@@ -197,7 +239,7 @@
           Property(&BuildState::critical_version, IsTrue()),
           Property(&BuildState::critical_version,
                    Eq(base::Optional<base::Version>(GetCriticalVersion()))))));
-  InstalledVersionPoller poller(&build_state_, callback.Get(),
+  InstalledVersionPoller poller(&build_state_, callback.Get(), MakeMonitor(),
                                 task_environment_.GetMockTickClock());
   task_environment_.RunUntilIdle();
   ::testing::Mock::VerifyAndClearExpectations(&callback);
@@ -216,7 +258,7 @@
                               Eq(BuildState::UpdateType::kNormalUpdate)),
                      Property(&BuildState::installed_version, IsFalse()),
                      Property(&BuildState::critical_version, IsFalse()))));
-  InstalledVersionPoller poller(&build_state_, callback.Get(),
+  InstalledVersionPoller poller(&build_state_, callback.Get(), MakeMonitor(),
                                 task_environment_.GetMockTickClock());
   task_environment_.RunUntilIdle();
   ::testing::Mock::VerifyAndClearExpectations(&callback);
@@ -238,9 +280,126 @@
           Property(&BuildState::installed_version,
                    Eq(base::Optional<base::Version>(GetRollbackVersion()))),
           Property(&BuildState::critical_version, IsFalse()))));
-  InstalledVersionPoller poller(&build_state_, callback.Get(),
+  InstalledVersionPoller poller(&build_state_, callback.Get(), MakeMonitor(),
                                 task_environment_.GetMockTickClock());
   task_environment_.RunUntilIdle();
   ::testing::Mock::VerifyAndClearExpectations(&callback);
   ::testing::Mock::VerifyAndClearExpectations(&mock_observer_);
 }
+
+// Tests that a modification in the monitored location triggers a poll.
+TEST_F(InstalledVersionPollerTest, TestMonitor) {
+  // Provide a GetInstalledVersionCallback that always reports no update, and
+  // don't make any noise about it being called.
+  ::testing::NiceMock<
+      base::MockRepeatingCallback<InstalledAndCriticalVersion()>>
+      callback;
+  ON_CALL(callback, Run()).WillByDefault([]() {
+    return MakeNoUpdateVersions();
+  });
+
+  InstalledVersionPoller poller(&build_state_, callback.Get(), MakeMonitor(),
+                                task_environment_.GetMockTickClock());
+  task_environment_.RunUntilIdle();
+
+  // Poke the monitor so that it announces a change.
+  TriggerMonitor();
+  ::testing::Mock::VerifyAndClearExpectations(&callback);
+
+  // Expect a poll in ten seconds.
+  EXPECT_CALL(callback, Run());
+  task_environment_.FastForwardBy(base::TimeDelta::FromSeconds(10));
+}
+
+// Tests that no metrics are reported if no poll finds an update.
+TEST_F(InstalledVersionPollerTest, NoOpNoMetrics) {
+  base::HistogramTester histogram_tester;
+  base::MockRepeatingCallback<InstalledAndCriticalVersion()> callback;
+  EXPECT_CALL(callback, Run())
+      .WillOnce(Return(ByMove(MakeNoUpdateVersions())))
+      .WillOnce(Return(ByMove(MakeNoUpdateVersions())))
+      .WillOnce(Return(ByMove(MakeNoUpdateVersions())));
+  InstalledVersionPoller poller(&build_state_, callback.Get(), MakeMonitor(),
+                                task_environment_.GetMockTickClock());
+  // First no-op: the startup task.
+  task_environment_.RunUntilIdle();
+  // Second no-op: the periodic task.
+  task_environment_.FastForwardBy(
+      InstalledVersionPoller::kDefaultPollingInterval);
+  // Third no-op: the monitor task.
+  TriggerMonitor();
+  task_environment_.FastForwardBy(base::TimeDelta::FromSeconds(10));
+  histogram_tester.ExpectTotalCount(kPollTypeHistogramName, 0);
+}
+
+// Tests that the PollType metric is recorded when the startup poll finds an
+// update.
+TEST_F(InstalledVersionPollerTest, StartupMetrics) {
+  base::HistogramTester histogram_tester;
+  base::MockRepeatingCallback<InstalledAndCriticalVersion()> callback;
+  EXPECT_CALL(callback, Run()).WillOnce(Return(ByMove(MakeUpgradeVersions())));
+  EXPECT_CALL(mock_observer_, OnUpdate(_));
+  InstalledVersionPoller poller(&build_state_, callback.Get(), MakeMonitor(),
+                                task_environment_.GetMockTickClock());
+  // Run the startup task.
+  task_environment_.RunUntilIdle();
+  histogram_tester.ExpectUniqueSample(kPollTypeHistogramName, 0, 1);
+}
+
+// Tests that the PollType metric is recorded when the monitor poll finds an
+// update.
+TEST_F(InstalledVersionPollerTest, MonitorMetrics) {
+  base::HistogramTester histogram_tester;
+  base::MockRepeatingCallback<InstalledAndCriticalVersion()> callback;
+  EXPECT_CALL(callback, Run())
+      .WillOnce(Return(ByMove(MakeNoUpdateVersions())))
+      .WillOnce(Return(ByMove(MakeUpgradeVersions())));
+  EXPECT_CALL(mock_observer_, OnUpdate(_));
+  InstalledVersionPoller poller(&build_state_, callback.Get(), MakeMonitor(),
+                                task_environment_.GetMockTickClock());
+  // Run the startup task.
+  task_environment_.RunUntilIdle();
+  // The monitor finds a change.
+  TriggerMonitor();
+  task_environment_.FastForwardBy(base::TimeDelta::FromSeconds(10));
+  histogram_tester.ExpectUniqueSample(kPollTypeHistogramName, 1, 1);
+}
+
+// Tests that the PollType metric is recorded when the periodic poll finds an
+// update.
+TEST_F(InstalledVersionPollerTest, PeriodicMetrics) {
+  base::HistogramTester histogram_tester;
+  base::MockRepeatingCallback<InstalledAndCriticalVersion()> callback;
+  EXPECT_CALL(callback, Run())
+      .WillOnce(Return(ByMove(MakeNoUpdateVersions())))
+      .WillOnce(Return(ByMove(MakeUpgradeVersions())));
+  EXPECT_CALL(mock_observer_, OnUpdate(_));
+  InstalledVersionPoller poller(&build_state_, callback.Get(), MakeMonitor(),
+                                task_environment_.GetMockTickClock());
+  // Run the startup task.
+  task_environment_.RunUntilIdle();
+  // Run the periodic task.
+  task_environment_.FastForwardBy(
+      InstalledVersionPoller::kDefaultPollingInterval);
+  histogram_tester.ExpectUniqueSample(kPollTypeHistogramName, 2, 1);
+}
+
+// Tests that the PollType metric is recorded only once even in case of multiple
+// polls.
+TEST_F(InstalledVersionPollerTest, MetricsOnlyOnce) {
+  base::HistogramTester histogram_tester;
+  base::MockRepeatingCallback<InstalledAndCriticalVersion()> callback;
+  EXPECT_CALL(callback, Run())
+      .WillOnce(Return(ByMove(MakeUpgradeVersions())))
+      .WillOnce(Return(ByMove(MakeUpgradeVersions())));
+  EXPECT_CALL(mock_observer_, OnUpdate(_));
+  InstalledVersionPoller poller(&build_state_, callback.Get(), MakeMonitor(),
+                                task_environment_.GetMockTickClock());
+  // Run the startup task.
+  task_environment_.RunUntilIdle();
+  // Run the periodic task.
+  task_environment_.FastForwardBy(
+      InstalledVersionPoller::kDefaultPollingInterval);
+  // Only the startup poll is recorded.
+  histogram_tester.ExpectUniqueSample(kPollTypeHistogramName, 0, 1);
+}
diff --git a/chrome/browser/upgrade_detector/registry_monitor.cc b/chrome/browser/upgrade_detector/registry_monitor.cc
new file mode 100644
index 0000000..c59f690
--- /dev/null
+++ b/chrome/browser/upgrade_detector/registry_monitor.cc
@@ -0,0 +1,65 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/upgrade_detector/registry_monitor.h"
+
+#include <memory>
+#include <utility>
+
+#include "base/bind.h"
+#include "base/callback.h"
+#include "base/location.h"
+#include "base/sequenced_task_runner.h"
+#include "base/threading/sequenced_task_runner_handle.h"
+#include "base/win/registry.h"
+#include "chrome/browser/upgrade_detector/installed_version_monitor.h"
+#include "chrome/install_static/install_util.h"
+
+namespace {
+
+base::win::RegKey GetDefaultMonitorLocation() {
+  return base::win::RegKey(install_static::IsSystemInstall()
+                               ? HKEY_LOCAL_MACHINE
+                               : HKEY_CURRENT_USER,
+                           install_static::GetClientsKeyPath().c_str(),
+                           KEY_NOTIFY | KEY_WOW64_32KEY);
+}
+
+}  // namespace
+
+RegistryMonitor::RegistryMonitor(base::win::RegKey key)
+    : clients_key_(std::move(key)) {}
+
+RegistryMonitor::~RegistryMonitor() = default;
+
+void RegistryMonitor::Start(Callback on_change_callback) {
+  DCHECK(on_change_callback);
+  DCHECK(!on_change_callback_);
+  on_change_callback_ = std::move(on_change_callback);
+  StartWatching();
+}
+
+void RegistryMonitor::StartWatching() {
+  // base::Unretained is safe because RegistryMonitor owns the RegKey.
+  // Destruction of this instance will cancel the watch and disable any
+  // outstanding notifications.
+  if (!clients_key_.Valid() ||
+      !clients_key_.StartWatching(base::BindOnce(
+          &RegistryMonitor::OnClientsKeyChanged, base::Unretained(this)))) {
+    // Starting the watch failed. Report this back to the poller via a delayed
+    // task.
+    base::SequencedTaskRunnerHandle::Get()->PostTask(
+        FROM_HERE, base::BindOnce(on_change_callback_, /*error=*/true));
+  }
+}
+
+void RegistryMonitor::OnClientsKeyChanged() {
+  on_change_callback_.Run(/*error=*/false);
+  StartWatching();
+}
+
+// static
+std::unique_ptr<InstalledVersionMonitor> InstalledVersionMonitor::Create() {
+  return std::make_unique<RegistryMonitor>(GetDefaultMonitorLocation());
+}
diff --git a/chrome/browser/upgrade_detector/registry_monitor.h b/chrome/browser/upgrade_detector/registry_monitor.h
new file mode 100644
index 0000000..284de7f
--- /dev/null
+++ b/chrome/browser/upgrade_detector/registry_monitor.h
@@ -0,0 +1,30 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_UPGRADE_DETECTOR_REGISTRY_MONITOR_H_
+#define CHROME_BROWSER_UPGRADE_DETECTOR_REGISTRY_MONITOR_H_
+
+#include "base/callback.h"
+#include "base/win/registry.h"
+#include "chrome/browser/upgrade_detector/installed_version_monitor.h"
+
+// A monitor of installs on Windows that watches for changes in the browser's
+// Clients registry key.
+class RegistryMonitor final : public InstalledVersionMonitor {
+ public:
+  explicit RegistryMonitor(base::win::RegKey key);
+  ~RegistryMonitor() override;
+
+  // InstalledVersionMonitor:
+  void Start(Callback on_change_callback) override;
+
+ private:
+  void StartWatching();
+  void OnClientsKeyChanged();
+
+  base::win::RegKey clients_key_;
+  Callback on_change_callback_;
+};
+
+#endif  // CHROME_BROWSER_UPGRADE_DETECTOR_REGISTRY_MONITOR_H_
diff --git a/chrome/browser/upgrade_detector/registry_monitor_unittest.cc b/chrome/browser/upgrade_detector/registry_monitor_unittest.cc
new file mode 100644
index 0000000..ad7096a
--- /dev/null
+++ b/chrome/browser/upgrade_detector/registry_monitor_unittest.cc
@@ -0,0 +1,98 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/upgrade_detector/registry_monitor.h"
+
+#include "base/run_loop.h"
+#include "base/test/mock_callback.h"
+#include "base/test/task_environment.h"
+#include "base/test/test_reg_util_win.h"
+#include "base/win/registry.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+class RegistryMonitorTest : public ::testing::Test {
+ protected:
+  void SetUp() override {
+    ASSERT_NO_FATAL_FAILURE(
+        registry_override_.OverrideRegistry(HKEY_CURRENT_USER));
+    ASSERT_EQ(test_key_.Create(HKEY_CURRENT_USER,
+                               L"Software\\Chromium\\RegistryMonitorTest",
+                               KEY_SET_VALUE),
+              ERROR_SUCCESS);
+  }
+
+  // Returns the test registry key to monitor. |access| may be used to override
+  // the default access rights for the key.
+  base::win::RegKey GetKeyToMonitor(REGSAM access = KEY_NOTIFY) {
+    base::win::RegKey key;
+    EXPECT_EQ(key.Open(test_key_.Handle(), L"", access), ERROR_SUCCESS);
+    return key;
+  }
+
+  registry_util::RegistryOverrideManager registry_override_;
+  base::win::RegKey test_key_;
+  base::test::TaskEnvironment task_environment_;
+};
+
+// Tests that the callback is invoked when the key is invalid.
+TEST_F(RegistryMonitorTest, ErrorOnInvalidKey) {
+  RegistryMonitor monitor{base::win::RegKey()};
+  ::testing::StrictMock<base::MockRepeatingCallback<void(bool)>> callback;
+  base::RunLoop run_loop;
+  EXPECT_CALL(callback, Run(true)).WillOnce([&run_loop]() { run_loop.Quit(); });
+  monitor.Start(callback.Get());
+  run_loop.Run();
+}
+
+// Tests that the callback is invoked when the key doesn't have NOTIFY access.
+TEST_F(RegistryMonitorTest, ErrorOnWrongPerms) {
+  RegistryMonitor monitor(GetKeyToMonitor(KEY_QUERY_VALUE));
+  ::testing::StrictMock<base::MockRepeatingCallback<void(bool)>> callback;
+  base::RunLoop run_loop;
+  EXPECT_CALL(callback, Run(true)).WillOnce([&run_loop]() { run_loop.Quit(); });
+  monitor.Start(callback.Get());
+  run_loop.Run();
+}
+
+// Tests that the callback is not invoked when nothing happens.
+TEST_F(RegistryMonitorTest, NoNoise) {
+  RegistryMonitor monitor(GetKeyToMonitor());
+  ::testing::StrictMock<base::MockRepeatingCallback<void(bool)>> callback;
+  monitor.Start(callback.Get());
+  task_environment_.RunUntilIdle();
+}
+
+// Tests that the callback is invoked when the key is modified.
+TEST_F(RegistryMonitorTest, OneChange) {
+  RegistryMonitor monitor(GetKeyToMonitor());
+  ::testing::StrictMock<base::MockRepeatingCallback<void(bool)>> callback;
+  base::RunLoop run_loop;
+  EXPECT_CALL(callback, Run(false)).WillOnce([&run_loop]() {
+    run_loop.Quit();
+  });
+  monitor.Start(callback.Get());
+  test_key_.WriteValue(L"some value", L"hi, mom");
+  run_loop.Run();
+}
+
+// Tests that the callback is invoked multiple times for multiple modifications.
+TEST_F(RegistryMonitorTest, MultipleChanges) {
+  RegistryMonitor monitor(GetKeyToMonitor());
+  ::testing::StrictMock<base::MockRepeatingCallback<void(bool)>> callback;
+  ::testing::InSequence sequence;
+  base::RunLoop run_loop;
+  base::RunLoop run_loop2;
+  EXPECT_CALL(callback, Run(false)).WillOnce([&run_loop]() {
+    run_loop.Quit();
+  });
+  EXPECT_CALL(callback, Run(false)).WillOnce([&run_loop2]() {
+    run_loop2.Quit();
+  });
+  monitor.Start(callback.Get());
+  test_key_.WriteValue(L"some value", L"hi, mom");
+  run_loop.Run();
+  test_key_.WriteValue(L"some value", L"hi, dad");
+  run_loop2.Run();
+}
diff --git a/chrome/browser/video_tutorials/internal/android/java/src/org/chromium/chrome/browser/video_tutorials/bridges/TutorialConversionBridge.java b/chrome/browser/video_tutorials/internal/android/java/src/org/chromium/chrome/browser/video_tutorials/bridges/TutorialConversionBridge.java
index 6141876..7422a7a 100644
--- a/chrome/browser/video_tutorials/internal/android/java/src/org/chromium/chrome/browser/video_tutorials/bridges/TutorialConversionBridge.java
+++ b/chrome/browser/video_tutorials/internal/android/java/src/org/chromium/chrome/browser/video_tutorials/bridges/TutorialConversionBridge.java
@@ -8,7 +8,6 @@
 
 import org.chromium.base.annotations.CalledByNative;
 import org.chromium.base.annotations.JNINamespace;
-import org.chromium.chrome.browser.video_tutorials.Language;
 import org.chromium.chrome.browser.video_tutorials.Tutorial;
 
 import java.util.ArrayList;
@@ -20,19 +19,6 @@
 @JNINamespace("video_tutorials")
 public class TutorialConversionBridge {
     @CalledByNative
-    private static List<Language> createLanguageList() {
-        return new ArrayList<>();
-    }
-
-    @CalledByNative
-    private static Language createLanguageAndMaybeAddToList(
-            @Nullable List<Language> list, String locale, String name, String nativeName) {
-        Language language = new Language(locale, name, nativeName);
-        if (list != null) list.add(language);
-        return language;
-    }
-
-    @CalledByNative
     private static List<Tutorial> createTutorialList() {
         return new ArrayList<>();
     }
diff --git a/chrome/browser/video_tutorials/internal/android/java/src/org/chromium/chrome/browser/video_tutorials/bridges/VideoTutorialServiceBridge.java b/chrome/browser/video_tutorials/internal/android/java/src/org/chromium/chrome/browser/video_tutorials/bridges/VideoTutorialServiceBridge.java
index 8a476bd5..7240251b0 100644
--- a/chrome/browser/video_tutorials/internal/android/java/src/org/chromium/chrome/browser/video_tutorials/bridges/VideoTutorialServiceBridge.java
+++ b/chrome/browser/video_tutorials/internal/android/java/src/org/chromium/chrome/browser/video_tutorials/bridges/VideoTutorialServiceBridge.java
@@ -9,7 +9,6 @@
 import org.chromium.base.annotations.JNINamespace;
 import org.chromium.base.annotations.NativeMethods;
 import org.chromium.chrome.browser.video_tutorials.FeatureType;
-import org.chromium.chrome.browser.video_tutorials.Language;
 import org.chromium.chrome.browser.video_tutorials.Tutorial;
 import org.chromium.chrome.browser.video_tutorials.VideoTutorialService;
 
@@ -47,11 +46,9 @@
 
     @Override
     public List<String> getSupportedLanguages() {
-        return null;
-        // TODO(shaktisahu): Fix the native to return a list of locales instead of languages.
-        // if (mNativeVideoTutorialServiceBridge == 0) return null;
-        // return VideoTutorialServiceBridgeJni.get().getSupportedLanguages(
-        //         mNativeVideoTutorialServiceBridge, this);
+        if (mNativeVideoTutorialServiceBridge == 0) return null;
+        return VideoTutorialServiceBridgeJni.get().getSupportedLanguages(
+                mNativeVideoTutorialServiceBridge, this);
     }
 
     @Override
@@ -79,7 +76,7 @@
                 Callback<List<Tutorial>> callback);
         void getTutorial(long nativeVideoTutorialServiceBridge, VideoTutorialServiceBridge caller,
                 int feature, Callback<Tutorial> callback);
-        List<Language> getSupportedLanguages(
+        List<String> getSupportedLanguages(
                 long nativeVideoTutorialServiceBridge, VideoTutorialServiceBridge caller);
         String getPreferredLocale(
                 long nativeVideoTutorialServiceBridge, VideoTutorialServiceBridge caller);
diff --git a/chrome/browser/video_tutorials/internal/android/tutorial_conversion_bridge.cc b/chrome/browser/video_tutorials/internal/android/tutorial_conversion_bridge.cc
index 70b1dc6d..1d07c88 100644
--- a/chrome/browser/video_tutorials/internal/android/tutorial_conversion_bridge.cc
+++ b/chrome/browser/video_tutorials/internal/android/tutorial_conversion_bridge.cc
@@ -7,36 +7,12 @@
 #include <memory>
 #include <string>
 
-#include "base/android/jni_array.h"
 #include "base/android/jni_string.h"
 #include "chrome/browser/video_tutorials/internal/jni_headers/TutorialConversionBridge_jni.h"
 
 namespace video_tutorials {
 
 using base::android::ConvertUTF8ToJavaString;
-using base::android::ToJavaArrayOfStrings;
-
-ScopedJavaLocalRef<jobject> CreateJavaLanguageAndMaybeAddToList(
-    JNIEnv* env,
-    ScopedJavaLocalRef<jobject> jlist,
-    const Language& language) {
-  return Java_TutorialConversionBridge_createLanguageAndMaybeAddToList(
-      env, jlist, ConvertUTF8ToJavaString(env, language.locale),
-      ConvertUTF8ToJavaString(env, language.name),
-      ConvertUTF8ToJavaString(env, language.native_name));
-}
-
-ScopedJavaLocalRef<jobject> TutorialConversionBridge::CreateJavaLanguages(
-    JNIEnv* env,
-    const std::vector<Language>& languages) {
-  ScopedJavaLocalRef<jobject> jlist =
-      Java_TutorialConversionBridge_createLanguageList(env);
-
-  for (const auto& language : languages)
-    CreateJavaLanguageAndMaybeAddToList(env, jlist, language);
-
-  return jlist;
-}
 
 ScopedJavaLocalRef<jobject> CreateJavaTutorialAndMaybeAddToList(
     JNIEnv* env,
diff --git a/chrome/browser/video_tutorials/internal/android/tutorial_conversion_bridge.h b/chrome/browser/video_tutorials/internal/android/tutorial_conversion_bridge.h
index abde0e01..fd71ca9 100644
--- a/chrome/browser/video_tutorials/internal/android/tutorial_conversion_bridge.h
+++ b/chrome/browser/video_tutorials/internal/android/tutorial_conversion_bridge.h
@@ -19,10 +19,6 @@
 // and Java.
 class TutorialConversionBridge {
  public:
-  static ScopedJavaLocalRef<jobject> CreateJavaLanguages(
-      JNIEnv* env,
-      const std::vector<Language>& languages);
-
   static ScopedJavaLocalRef<jobject> CreateJavaTutorials(
       JNIEnv* env,
       const std::vector<Tutorial>& tutorials);
diff --git a/chrome/browser/video_tutorials/internal/android/video_tutorial_service_bridge.cc b/chrome/browser/video_tutorials/internal/android/video_tutorial_service_bridge.cc
index f146089..78a31ac 100644
--- a/chrome/browser/video_tutorials/internal/android/video_tutorial_service_bridge.cc
+++ b/chrome/browser/video_tutorials/internal/android/video_tutorial_service_bridge.cc
@@ -93,7 +93,7 @@
 ScopedJavaLocalRef<jobject> VideoTutorialServiceBridge::GetSupportedLanguages(
     JNIEnv* env,
     const JavaParamRef<jobject>& jcaller) {
-  return TutorialConversionBridge::CreateJavaLanguages(
+  return base::android::ToJavaArrayOfStrings(
       env, video_tutorial_service_->GetSupportedLanguages());
 }
 
diff --git a/chrome/browser/video_tutorials/internal/proto_conversions.cc b/chrome/browser/video_tutorials/internal/proto_conversions.cc
index 628058a70..eb850eb 100644
--- a/chrome/browser/video_tutorials/internal/proto_conversions.cc
+++ b/chrome/browser/video_tutorials/internal/proto_conversions.cc
@@ -55,22 +55,6 @@
 
 }  // namespace
 
-void LanguageToProto(Language* language, LanguageProto* proto) {
-  DCHECK(language);
-  DCHECK(proto);
-  proto->set_locale(language->locale);
-  proto->set_name(language->name);
-  proto->set_native_name(language->native_name);
-}
-
-void LanguageFromProto(LanguageProto* proto, Language* language) {
-  DCHECK(language);
-  DCHECK(proto);
-  language->locale = proto->locale();
-  language->name = proto->name();
-  language->native_name = proto->native_name();
-}
-
 void TutorialToProto(Tutorial* tutorial, TutorialProto* proto) {
   DCHECK(tutorial);
   DCHECK(proto);
@@ -98,7 +82,7 @@
 void TutorialGroupToProto(TutorialGroup* group, TutorialGroupProto* proto) {
   DCHECK(group);
   DCHECK(proto);
-  LanguageToProto(&group->language, proto->mutable_language());
+  proto->set_language(group->language);
   proto->clear_tutorials();
   for (auto& tutorial : group->tutorials)
     TutorialToProto(&tutorial, proto->add_tutorials());
@@ -107,7 +91,7 @@
 void TutorialGroupFromProto(TutorialGroupProto* proto, TutorialGroup* group) {
   DCHECK(group);
   DCHECK(proto);
-  LanguageFromProto(proto->mutable_language(), &group->language);
+  group->language = proto->language();
   group->tutorials.clear();
   for (auto tutorial_proto : proto->tutorials()) {
     Tutorial tutorial;
diff --git a/chrome/browser/video_tutorials/internal/proto_conversions.h b/chrome/browser/video_tutorials/internal/proto_conversions.h
index 94add8be..dad9d864 100644
--- a/chrome/browser/video_tutorials/internal/proto_conversions.h
+++ b/chrome/browser/video_tutorials/internal/proto_conversions.h
@@ -10,17 +10,10 @@
 
 namespace video_tutorials {
 
-using LanguageProto = video_tutorials::proto::Language;
 using TutorialProto = video_tutorials::proto::VideoTutorial;
 using TutorialGroupProto = video_tutorials::proto::VideoTutorialGroup;
 using ServerResponseProto = video_tutorials::proto::ServerResponse;
 
-// Convert in-memory struct Language to proto::Language.
-void LanguageToProto(Language* language, LanguageProto* proto);
-
-// Convert proto::Language to in-memory struct Language.
-void LanguageFromProto(LanguageProto* proto, Language* language);
-
 // Convert in-memory struct Tutorial to proto::VideoTutorial.
 void TutorialToProto(Tutorial* tutorial, TutorialProto* proto);
 
diff --git a/chrome/browser/video_tutorials/internal/proto_conversions_unittest.cc b/chrome/browser/video_tutorials/internal/proto_conversions_unittest.cc
index c5ceb450..c3d4e47 100644
--- a/chrome/browser/video_tutorials/internal/proto_conversions_unittest.cc
+++ b/chrome/browser/video_tutorials/internal/proto_conversions_unittest.cc
@@ -25,18 +25,6 @@
   }
 }
 
-// Verify round-way conversion of Language struct.
-TEST(VideoTutorialsProtoConversionsTest, LanguageConversion) {
-  Language expected, actual;
-  expected.locale = "jp";
-  expected.name = "Japanese";
-  expected.native_name = "Japanese-Native";
-  LanguageProto intermediate;
-  LanguageToProto(&expected, &intermediate);
-  LanguageFromProto(&intermediate, &actual);
-  EXPECT_EQ(expected, actual);
-}
-
 // Verify round-way conversion of Tutorial struct.
 TEST(VideoTutorialsProtoConversionsTest, TutorialConversion) {
   Tutorial expected, actual;
diff --git a/chrome/browser/video_tutorials/internal/tutorial_group.cc b/chrome/browser/video_tutorials/internal/tutorial_group.cc
index 1da7a79..52cbe459 100644
--- a/chrome/browser/video_tutorials/internal/tutorial_group.cc
+++ b/chrome/browser/video_tutorials/internal/tutorial_group.cc
@@ -8,7 +8,8 @@
 
 TutorialGroup::TutorialGroup() = default;
 
-TutorialGroup::TutorialGroup(const Language& language) : language(language) {}
+TutorialGroup::TutorialGroup(const std::string& language)
+    : language(language) {}
 
 bool TutorialGroup::operator==(const TutorialGroup& other) const {
   return language == other.language && tutorials == other.tutorials;
diff --git a/chrome/browser/video_tutorials/internal/tutorial_group.h b/chrome/browser/video_tutorials/internal/tutorial_group.h
index 66832af..e5d303c 100644
--- a/chrome/browser/video_tutorials/internal/tutorial_group.h
+++ b/chrome/browser/video_tutorials/internal/tutorial_group.h
@@ -12,7 +12,7 @@
 // In memory struct of a group of video tutorials with same language .
 struct TutorialGroup {
   TutorialGroup();
-  explicit TutorialGroup(const Language& language);
+  explicit TutorialGroup(const std::string& language);
   ~TutorialGroup();
 
   bool operator==(const TutorialGroup& other) const;
@@ -22,7 +22,7 @@
   TutorialGroup& operator=(const TutorialGroup& other);
 
   // Language of this group.
-  Language language;
+  std::string language;
 
   // A list of tutorials.
   std::vector<Tutorial> tutorials;
diff --git a/chrome/browser/video_tutorials/internal/tutorial_group_unittest.cc b/chrome/browser/video_tutorials/internal/tutorial_group_unittest.cc
index 4ca0be0..dc6f909f 100644
--- a/chrome/browser/video_tutorials/internal/tutorial_group_unittest.cc
+++ b/chrome/browser/video_tutorials/internal/tutorial_group_unittest.cc
@@ -10,9 +10,7 @@
 namespace {
 
 void ResetTutorialGroup(TutorialGroup* group) {
-  Language language;
-  language.locale = "en";
-  *group = TutorialGroup(language);
+  *group = TutorialGroup("en");
   group->tutorials.resize(3, Tutorial());
   group->tutorials.front().feature = FeatureType::kDownload;
   group->tutorials.back().feature = FeatureType::kSearch;
@@ -26,7 +24,7 @@
 
   EXPECT_EQ(lhs, rhs);
 
-  rhs.language.locale = "jp";
+  rhs.language = "jp";
   EXPECT_NE(lhs, rhs);
   ResetTutorialGroup(&rhs);
 
diff --git a/chrome/browser/video_tutorials/internal/tutorial_manager.h b/chrome/browser/video_tutorials/internal/tutorial_manager.h
index cc5bfadd..3d13c66 100644
--- a/chrome/browser/video_tutorials/internal/tutorial_manager.h
+++ b/chrome/browser/video_tutorials/internal/tutorial_manager.h
@@ -22,7 +22,7 @@
   virtual void GetTutorials(GetTutorialsCallback callback) = 0;
 
   // Returns a list of languages for which video tutorials are available.
-  virtual const std::vector<Language>& GetSupportedLanguages() = 0;
+  virtual const std::vector<std::string>& GetSupportedLanguages() = 0;
 
   // Returns the preferred locale for the video tutorials.
   virtual std::string GetPreferredLocale() = 0;
diff --git a/chrome/browser/video_tutorials/internal/tutorial_manager_impl.cc b/chrome/browser/video_tutorials/internal/tutorial_manager_impl.cc
index 64938e3..36ada78 100644
--- a/chrome/browser/video_tutorials/internal/tutorial_manager_impl.cc
+++ b/chrome/browser/video_tutorials/internal/tutorial_manager_impl.cc
@@ -37,8 +37,7 @@
 
   // Find the data from cache.
   std::string locale = GetPreferredLocale();
-  if (tutorial_group_.has_value() &&
-      tutorial_group_->language.locale == locale) {
+  if (tutorial_group_.has_value() && tutorial_group_->language == locale) {
     std::move(callback).Run(tutorial_group_->tutorials);
     return;
   }
@@ -51,7 +50,7 @@
                      weak_ptr_factory_.GetWeakPtr(), std::move(callback)));
 }
 
-const std::vector<Language>& TutorialManagerImpl::GetSupportedLanguages() {
+const std::vector<std::string>& TutorialManagerImpl::GetSupportedLanguages() {
   return supported_languages_;
 }
 
@@ -122,17 +121,17 @@
   std::vector<std::string> new_locales;
   std::vector<std::pair<std::string, TutorialGroup>> key_entry_pairs;
   for (auto& group : *groups.get()) {
-    new_locales.emplace_back(group.language.locale);
-    key_entry_pairs.emplace_back(std::make_pair(group.language.locale, group));
+    new_locales.emplace_back(group.language);
+    key_entry_pairs.emplace_back(std::make_pair(group.language, group));
   }
 
   // Remove the languages that don't exist in the new data.
   // TODO(shaktisahu): Maybe completely nuke the DB and save new data.
   std::vector<std::string> keys_to_delete;
   for (auto& old_language : supported_languages_) {
-    if (std::find(new_locales.begin(), new_locales.end(),
-                  old_language.locale) == new_locales.end()) {
-      keys_to_delete.emplace_back(old_language.locale);
+    if (std::find(new_locales.begin(), new_locales.end(), old_language) ==
+        new_locales.end()) {
+      keys_to_delete.emplace_back(old_language);
     }
   }
 
diff --git a/chrome/browser/video_tutorials/internal/tutorial_manager_impl.h b/chrome/browser/video_tutorials/internal/tutorial_manager_impl.h
index e8bd5dc..2df7836 100644
--- a/chrome/browser/video_tutorials/internal/tutorial_manager_impl.h
+++ b/chrome/browser/video_tutorials/internal/tutorial_manager_impl.h
@@ -29,7 +29,7 @@
  private:
   // TutorialManager implementation.
   void GetTutorials(GetTutorialsCallback callback) override;
-  const std::vector<Language>& GetSupportedLanguages() override;
+  const std::vector<std::string>& GetSupportedLanguages() override;
   std::string GetPreferredLocale() override;
   void SetPreferredLocale(const std::string& locale) override;
   void SaveGroups(std::unique_ptr<std::vector<TutorialGroup>> groups,
@@ -50,7 +50,7 @@
   PrefService* prefs_;
 
   // List of languages for which we have tutorials.
-  std::vector<Language> supported_languages_;
+  std::vector<std::string> supported_languages_;
 
   // We only keep the tutorials for the preferred locale.
   base::Optional<TutorialGroup> tutorial_group_;
diff --git a/chrome/browser/video_tutorials/internal/tutorial_manager_impl_unittest.cc b/chrome/browser/video_tutorials/internal/tutorial_manager_impl_unittest.cc
index 237b5a6..734bed7b 100644
--- a/chrome/browser/video_tutorials/internal/tutorial_manager_impl_unittest.cc
+++ b/chrome/browser/video_tutorials/internal/tutorial_manager_impl_unittest.cc
@@ -27,7 +27,7 @@
   std::vector<TutorialGroup> groups;
   for (const auto& locale : locales) {
     TutorialGroup group;
-    group.language.locale = locale;
+    group.language = locale;
     group.tutorials.emplace_back(Tutorial());
     group.tutorials.emplace_back(Tutorial());
     groups.emplace_back(group);
@@ -63,7 +63,7 @@
         entries->emplace_back(group);
       } else {
         for (auto& key : keys) {
-          if (key == group.language.locale) {
+          if (key == group.language) {
             entries->emplace_back(group);
           }
         }
diff --git a/chrome/browser/video_tutorials/internal/tutorial_service_impl.cc b/chrome/browser/video_tutorials/internal/tutorial_service_impl.cc
index e3a0841..0c10699f 100644
--- a/chrome/browser/video_tutorials/internal/tutorial_service_impl.cc
+++ b/chrome/browser/video_tutorials/internal/tutorial_service_impl.cc
@@ -78,7 +78,7 @@
                                 base::BindOnce(std::move(lambda)));
 }
 
-const std::vector<Language>& TutorialServiceImpl::GetSupportedLanguages() {
+const std::vector<std::string>& TutorialServiceImpl::GetSupportedLanguages() {
   return tutorial_manager_->GetSupportedLanguages();
 }
 
diff --git a/chrome/browser/video_tutorials/internal/tutorial_service_impl.h b/chrome/browser/video_tutorials/internal/tutorial_service_impl.h
index 75c39c4..af96f977 100644
--- a/chrome/browser/video_tutorials/internal/tutorial_service_impl.h
+++ b/chrome/browser/video_tutorials/internal/tutorial_service_impl.h
@@ -25,7 +25,7 @@
   void GetTutorials(MultipleItemCallback callback) override;
   void GetTutorial(FeatureType feature_type,
                    SingleItemCallback callback) override;
-  const std::vector<Language>& GetSupportedLanguages() override;
+  const std::vector<std::string>& GetSupportedLanguages() override;
   std::string GetPreferredLocale() override;
   void SetPreferredLocale(const std::string& locale) override;
 
diff --git a/chrome/browser/video_tutorials/internal/tutorial_store_unittest.cc b/chrome/browser/video_tutorials/internal/tutorial_store_unittest.cc
index fa3142b..4657d4b1 100644
--- a/chrome/browser/video_tutorials/internal/tutorial_store_unittest.cc
+++ b/chrome/browser/video_tutorials/internal/tutorial_store_unittest.cc
@@ -57,7 +57,7 @@
     for (auto& entry : input) {
       TutorialGroupProto proto;
       TutorialGroupToProto(&entry, &proto);
-      db_entries_.emplace(entry.language.locale, proto);
+      db_entries_.emplace(entry.language, proto);
     }
   }
 
@@ -177,8 +177,7 @@
   TutorialGroup test_group;
   test::BuildTestGroup(&test_group);
   std::vector<std::pair<std::string, TutorialGroup>> entries_to_save;
-  entries_to_save.emplace_back(
-      std::make_pair(test_group.language.locale, test_group));
+  entries_to_save.emplace_back(std::make_pair(test_group.language, test_group));
   std::vector<std::string> keys_to_delete;
   store()->UpdateAll(
       entries_to_save, keys_to_delete,
@@ -186,7 +185,7 @@
   db()->UpdateCallback(true);
 
   auto expected = std::make_unique<KeysAndEntries>();
-  expected->emplace(test_group.language.locale, std::move(test_group));
+  expected->emplace(test_group.language, std::move(test_group));
   VerifyDataInDb(std::move(expected));
 }
 
@@ -194,7 +193,7 @@
 TEST_F(TutorialStoreTest, Delete) {
   TutorialGroup test_group;
   test::BuildTestGroup(&test_group);
-  std::string locale = test_group.language.locale;
+  std::string locale = test_group.language;
   std::vector<TutorialGroup> test_data;
   test_data.emplace_back(std::move(test_group));
   Init(test_data, InitStatus::kOK, true /* expected */);
diff --git a/chrome/browser/video_tutorials/proto/video_tutorials.proto b/chrome/browser/video_tutorials/proto/video_tutorials.proto
index 542a246..1fbb86d 100644
--- a/chrome/browser/video_tutorials/proto/video_tutorials.proto
+++ b/chrome/browser/video_tutorials/proto/video_tutorials.proto
@@ -20,22 +20,10 @@
   TEST = 9999999;
 }
 
-// Metadata about a language.
-message Language {
-  // The locale associated with the lnaguage.
-  string locale = 1;
-
-  // Name of the language.
-  string name = 2;
-
-  // Name of the language in native text.
-  string native_name = 3;
-}
-
 // A group of video tutorials with same language.
 message VideoTutorialGroup {
   // Language of the video.
-  Language language = 1;
+  string language = 1;
 
   // A list of video tutorials metadata.
   repeated VideoTutorial tutorials = 2;
diff --git a/chrome/browser/video_tutorials/test/test_utils.cc b/chrome/browser/video_tutorials/test/test_utils.cc
index 7483530..a3e076d 100644
--- a/chrome/browser/video_tutorials/test/test_utils.cc
+++ b/chrome/browser/video_tutorials/test/test_utils.cc
@@ -17,9 +17,7 @@
 }
 
 void BuildTestGroup(TutorialGroup* group) {
-  Language language;
-  language.locale = "en";
-  *group = TutorialGroup(language);
+  *group = TutorialGroup("en");
   group->tutorials.clear();
   Tutorial entry1;
   BuildTestEntry(&entry1);
diff --git a/chrome/browser/video_tutorials/tutorial.cc b/chrome/browser/video_tutorials/tutorial.cc
index b3002d8..4e807b5 100644
--- a/chrome/browser/video_tutorials/tutorial.cc
+++ b/chrome/browser/video_tutorials/tutorial.cc
@@ -6,15 +6,6 @@
 
 namespace video_tutorials {
 
-bool Language::operator==(const Language& other) const {
-  return locale == other.locale && name == other.name &&
-         native_name == other.native_name;
-}
-
-bool Language::operator!=(const Language& other) const {
-  return !(*this == other);
-}
-
 Tutorial::Tutorial() : feature(FeatureType::kInvalid), video_length(0) {}
 
 Tutorial::Tutorial(FeatureType feature,
diff --git a/chrome/browser/video_tutorials/tutorial.h b/chrome/browser/video_tutorials/tutorial.h
index bb96610..80936f20 100644
--- a/chrome/browser/video_tutorials/tutorial.h
+++ b/chrome/browser/video_tutorials/tutorial.h
@@ -27,27 +27,6 @@
   kMaxValue = kVoiceSearch,
 };
 
-// In memory struct representing a language.
-struct Language {
-  Language() = default;
-  ~Language() = default;
-
-  Language(const Language& other) = default;
-  Language& operator=(const Language& other) = default;
-
-  bool operator==(const Language& other) const;
-  bool operator!=(const Language& other) const;
-
-  // The locale associated with the language.
-  std::string locale;
-
-  // The name of the language.
-  std::string name;
-
-  // The name of the language in native text.
-  std::string native_name;
-};
-
 // In memory struct of a video tutorial entry.
 // Represents the metadata required to play a video tutorial.
 struct Tutorial {
diff --git a/chrome/browser/video_tutorials/video_tutorial_service.h b/chrome/browser/video_tutorials/video_tutorial_service.h
index 6fa803d..34643f7 100644
--- a/chrome/browser/video_tutorials/video_tutorial_service.h
+++ b/chrome/browser/video_tutorials/video_tutorial_service.h
@@ -33,7 +33,7 @@
                            SingleItemCallback callback) = 0;
 
   // Called to retrieve all the supported locales.
-  virtual const std::vector<Language>& GetSupportedLanguages() = 0;
+  virtual const std::vector<std::string>& GetSupportedLanguages() = 0;
 
   // Called to retrieve the preferred locale.
   virtual std::string GetPreferredLocale() = 0;
diff --git a/chrome/browser/web_applications/components/app_icon_manager.h b/chrome/browser/web_applications/components/app_icon_manager.h
index 5729262..b01da62 100644
--- a/chrome/browser/web_applications/components/app_icon_manager.h
+++ b/chrome/browser/web_applications/components/app_icon_manager.h
@@ -127,6 +127,8 @@
                                      SquareSizePx min_icon_size,
                                      ReadCompressedIconCallback callback) const;
 
+  // Returns a square icon of gfx::kFaviconSize px, or an empty bitmap if not
+  // found.
   virtual SkBitmap GetFavicon(const AppId& app_id) const = 0;
 
  protected:
diff --git a/chrome/browser/web_applications/components/web_app_utils.cc b/chrome/browser/web_applications/components/web_app_utils.cc
index 447462af..f5413c14 100644
--- a/chrome/browser/web_applications/components/web_app_utils.cc
+++ b/chrome/browser/web_applications/components/web_app_utils.cc
@@ -50,7 +50,7 @@
 
 bool AreWebAppsUserInstallable(Profile* profile) {
   return AreWebAppsEnabled(profile) && !profile->IsGuestSession() &&
-         !profile->IsOffTheRecord();
+         !profile->IsEphemeralGuestProfile() && !profile->IsOffTheRecord();
 }
 
 content::BrowserContext* GetBrowserContextForWebApps(
@@ -66,8 +66,10 @@
   // Use original profile to create only one KeyedService instance.
   Profile* original_profile =
       Profile::FromBrowserContext(context)->GetOriginalProfile();
-  const bool is_web_app_metrics_enabled = AreWebAppsEnabled(original_profile) &&
-                                          !original_profile->IsGuestSession();
+  const bool is_web_app_metrics_enabled =
+      AreWebAppsEnabled(original_profile) &&
+      !original_profile->IsGuestSession() &&
+      !original_profile->IsEphemeralGuestProfile();
   return is_web_app_metrics_enabled ? original_profile : nullptr;
 }
 
diff --git a/chrome/browser/web_applications/web_app_icon_manager.cc b/chrome/browser/web_applications/web_app_icon_manager.cc
index 20d623d..174afdf 100644
--- a/chrome/browser/web_applications/web_app_icon_manager.cc
+++ b/chrome/browser/web_applications/web_app_icon_manager.cc
@@ -769,14 +769,17 @@
   if (!HasSmallestIcon(app_id, {IconPurpose::ANY}, gfx::kFaviconSize))
     return;
 
-  ReadSmallestIconAny(app_id, gfx::kFaviconSize,
-                      base::BindOnce(&WebAppIconManager::OnReadFavicon,
-                                     weak_ptr_factory_.GetWeakPtr(), app_id));
+  ReadIconAndResize(app_id, IconPurpose::ANY, gfx::kFaviconSize,
+                    base::BindOnce(&WebAppIconManager::OnReadFavicon,
+                                   weak_ptr_factory_.GetWeakPtr(), app_id));
 }
 
-void WebAppIconManager::OnReadFavicon(const AppId& app_id,
-                                      const SkBitmap& bitmap) {
-  favicon_cache_[app_id] = bitmap;
+void WebAppIconManager::OnReadFavicon(
+    const AppId& app_id,
+    const std::map<SquareSizePx, SkBitmap> icons) {
+  const auto it = icons.find(gfx::kFaviconSize);
+  if (it != icons.end())
+    favicon_cache_[app_id] = it->second;
   if (favicon_read_callback_)
     favicon_read_callback_.Run(app_id);
 }
diff --git a/chrome/browser/web_applications/web_app_icon_manager.h b/chrome/browser/web_applications/web_app_icon_manager.h
index 7651889..fd1f3add5 100644
--- a/chrome/browser/web_applications/web_app_icon_manager.h
+++ b/chrome/browser/web_applications/web_app_icon_manager.h
@@ -106,7 +106,8 @@
       SquareSizePx max_size) const;
 
   void ReadFavicon(const AppId& app_id);
-  void OnReadFavicon(const AppId& app_id, const SkBitmap&);
+  void OnReadFavicon(const AppId& app_id,
+                     std::map<SquareSizePx, SkBitmap> icons);
 
   WebAppRegistrar& registrar_;
   base::FilePath web_apps_directory_;
diff --git a/chrome/browser/web_applications/web_app_icon_manager_unittest.cc b/chrome/browser/web_applications/web_app_icon_manager_unittest.cc
index 24d793f2..da61da01 100644
--- a/chrome/browser/web_applications/web_app_icon_manager_unittest.cc
+++ b/chrome/browser/web_applications/web_app_icon_manager_unittest.cc
@@ -1120,6 +1120,38 @@
   EXPECT_EQ(SK_ColorGREEN, bitmap.getColor(0, 0));
 }
 
+TEST_F(WebAppIconManagerTest, CacheAppFaviconWithResize) {
+  auto web_app = CreateWebApp();
+  const AppId app_id = web_app->app_id();
+
+  // App does not declare an icon of gfx::kFaviconSize, forcing a resize.
+  const std::vector<int> sizes_px{8, icon_size::k48, icon_size::k64};
+  ASSERT_FALSE(base::Contains(sizes_px, gfx::kFaviconSize));
+  const std::vector<SkColor> colors{SK_ColorBLACK, SK_ColorGREEN, SK_ColorRED};
+  WriteIcons(app_id, {IconPurpose::ANY}, sizes_px, colors);
+
+  web_app->SetDownloadedIconSizes(IconPurpose::ANY, sizes_px);
+
+  controller().RegisterApp(std::move(web_app));
+
+  base::RunLoop run_loop;
+  icon_manager().SetFaviconReadCallbackForTesting(
+      base::BindLambdaForTesting([&](const AppId& cached_app_id) {
+        EXPECT_EQ(cached_app_id, app_id);
+        run_loop.Quit();
+      }));
+
+  icon_manager().Start();
+  run_loop.Run();
+
+  SkBitmap bitmap = icon_manager().GetFavicon(app_id);
+  EXPECT_FALSE(bitmap.empty());
+  EXPECT_EQ(gfx::kFaviconSize, bitmap.width());
+  EXPECT_EQ(gfx::kFaviconSize, bitmap.height());
+  // Correct size wasn't available so larger icon should be used.
+  EXPECT_EQ(SK_ColorGREEN, bitmap.getColor(0, 0));
+}
+
 TEST_F(WebAppIconManagerTest, CacheNewAppFavicon) {
   icon_manager().Start();
 
diff --git a/chrome/build/linux.pgo.txt b/chrome/build/linux.pgo.txt
index e1a8f3a..158aa8e 100644
--- a/chrome/build/linux.pgo.txt
+++ b/chrome/build/linux.pgo.txt
@@ -1 +1 @@
-chrome-linux-master-1602719900-429a2df71c95e6dc087ec01302b187e7e9fb6918.profdata
+chrome-linux-master-1602741093-4d55155af2d57fc162c54eb0d019ea99dc26a80f.profdata
diff --git a/chrome/build/mac.pgo.txt b/chrome/build/mac.pgo.txt
index ec7d8ad2..366fa27 100644
--- a/chrome/build/mac.pgo.txt
+++ b/chrome/build/mac.pgo.txt
@@ -1 +1 @@
-chrome-mac-master-1602719900-0adf1708ffdf07a3257db3881b100b59132f390a.profdata
+chrome-mac-master-1602741093-813b9f30d38756007f17b964e7014a850d40bedc.profdata
diff --git a/chrome/build/win32.pgo.txt b/chrome/build/win32.pgo.txt
index 168dcf8..fa42ea7b 100644
--- a/chrome/build/win32.pgo.txt
+++ b/chrome/build/win32.pgo.txt
@@ -1 +1 @@
-chrome-win32-master-1602676072-6b1951d9f0e9d329ad053bceb12040099bb1e856.profdata
+chrome-win32-master-1602709027-5dd91a5323ea4bffe2a30c2aaff27b21af6d45ea.profdata
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn
index a54cdef..359d9cf4 100644
--- a/chrome/test/BUILD.gn
+++ b/chrome/test/BUILD.gn
@@ -3842,6 +3842,7 @@
       "../browser/shell_integration_win_unittest.cc",
       "../browser/ui/webui/version_handler_win_unittest.cc",
       "../browser/upgrade_detector/get_installed_version_win_unittest.cc",
+      "../browser/upgrade_detector/registry_monitor_unittest.cc",
       "../browser/win/chrome_elf_init_unittest.cc",
       "../browser/win/jumplist_file_util_unittest.cc",
       "../browser/win/jumplist_update_util_unittest.cc",
@@ -3868,6 +3869,7 @@
       "../browser/notifications/stub_notification_center_mac.mm",
       "../browser/policy/browser_dm_token_storage_mac_unittest.cc",
       "../browser/service_process/service_process_control_mac_unittest.mm",
+      "../browser/upgrade_detector/directory_monitor_unittest.cc",
       "../common/mac/mock_launchd.h",
       "../common/mac/mock_launchd.mm",
     ]
@@ -5460,6 +5462,7 @@
     sources += [
       "../browser/shell_integration_linux_unittest.cc",
       "../browser/ui/global_media_controls/media_notification_device_monitor_unittest.cc",
+      "../browser/upgrade_detector/directory_monitor_unittest.cc",
       "../browser/upgrade_detector/get_installed_version_linux_unittest.cc",
     ]
   }
diff --git a/chrome/test/data/policy/policy_test_cases.json b/chrome/test/data/policy/policy_test_cases.json
index 696db6d..5c6ed19 100644
--- a/chrome/test/data/policy/policy_test_cases.json
+++ b/chrome/test/data/policy/policy_test_cases.json
@@ -7265,6 +7265,43 @@
       }
     ]
   },
+  "DeviceArcDataSnapshotHours": {
+    "os": ["chromeos"],
+    "policy_pref_mapping_test": [
+      {
+        "policies": {
+          "DeviceArcDataSnapshotHours": {
+            "intervals": [
+              {
+                "start": {
+                  "day_of_week": 1,
+                  "time": 1284000
+                },
+                "end": {
+                  "day_of_week": 1,
+                  "time": 21720000
+                }
+              },
+              {
+                "start": {
+                  "day_of_week": 2,
+                  "time": 1284000
+                },
+                "end": {
+                  "day_of_week": 2,
+                  "time": 21720000
+                }
+              }
+            ],
+            "timezone": "GMT"
+          }
+        },
+        "prefs": {
+          "arc.snapshot_hours": { "local_state": true }
+        }
+      }
+    ]
+  },
 
   "----- Chrome Frame policies -------------------------------------------": {},
 
diff --git a/chrome/test/data/webui/chromeos/scanning/scanning_app_test.js b/chrome/test/data/webui/chromeos/scanning/scanning_app_test.js
index 830fe4ac..ee4b7f24 100644
--- a/chrome/test/data/webui/chromeos/scanning/scanning_app_test.js
+++ b/chrome/test/data/webui/chromeos/scanning/scanning_app_test.js
@@ -17,6 +17,12 @@
   COLOR: chromeos.scanning.mojom.ColorMode.kColor,
 };
 
+const FileType = {
+  JPG: chromeos.scanning.mojom.FileType.kJpg,
+  PDF: chromeos.scanning.mojom.FileType.kPdf,
+  PNG: chromeos.scanning.mojom.FileType.kPng,
+};
+
 const SourceType = {
   FLATBED: chromeos.scanning.mojom.SourceType.kFlatbed,
   ADF_SIMPLEX: chromeos.scanning.mojom.SourceType.kAdfSimplex,
@@ -245,6 +251,7 @@
               tokenToString(firstScannerId), scanningApp.selectedScannerId);
           assertEquals(
               firstCapabilities.sources[0].name, scanningApp.selectedSource);
+          assertEquals(FileType.PDF, scanningApp.selectedFileType);
           assertEquals(
               firstCapabilities.colorModes[0], scanningApp.selectedColorMode);
           assertEquals(
@@ -256,6 +263,8 @@
           assertFalse(scannerSelect.disabled);
           const sourceSelect = scanningApp.$$('#sourceSelect').$$('select');
           assertFalse(sourceSelect.disabled);
+          const fileTypeSelect = scanningApp.$$('#fileTypeSelect').$$('select');
+          assertFalse(fileTypeSelect.disabled);
           const colorModeSelect =
               scanningApp.$$('#colorModeSelect').$$('select');
           assertFalse(colorModeSelect.disabled);
@@ -273,6 +282,7 @@
           // scanning is in progress.
           assertTrue(scannerSelect.disabled);
           assertTrue(sourceSelect.disabled);
+          assertTrue(fileTypeSelect.disabled);
           assertTrue(colorModeSelect.disabled);
           assertTrue(resolutionSelect.disabled);
           assertTrue(scanButton.disabled);
@@ -285,6 +295,7 @@
           // complete.
           assertFalse(scanningApp.$$('#scannerSelect').$$('select').disabled);
           assertFalse(scanningApp.$$('#sourceSelect').$$('select').disabled);
+          assertFalse(scanningApp.$$('#fileTypeSelect').$$('select').disabled);
           assertFalse(scanningApp.$$('#colorModeSelect').$$('select').disabled);
           assertFalse(
               scanningApp.$$('#resolutionSelect').$$('select').disabled);
@@ -447,6 +458,42 @@
   });
 });
 
+suite('FileTypeSelectTest', () => {
+  /** @type {!FileTypeSelectElement} */
+  let fileTypeSelect;
+
+  setup(() => {
+    fileTypeSelect = document.createElement('file-type-select');
+    assertTrue(!!fileTypeSelect);
+    document.body.appendChild(fileTypeSelect);
+  });
+
+  teardown(() => {
+    fileTypeSelect.remove();
+    fileTypeSelect = null;
+  });
+
+  test('initializeFileTypeSelect', () => {
+    // The dropdown should be initialized as enabled with three options. The
+    // default option should be PDF.
+    const select = fileTypeSelect.$$('select');
+    assertTrue(!!select);
+    assertFalse(select.disabled);
+    assertEquals(3, select.length);
+    assertEquals('JPG', select.options[0].textContent.trim());
+    assertEquals('PDF', select.options[1].textContent.trim());
+    assertEquals('PNG', select.options[2].textContent.trim());
+    assertEquals(FileType.PDF.toString(), select.value);
+
+    // Selecting a different option should update the selected value.
+    select.value = FileType.JPG.toString();
+    select.dispatchEvent(new CustomEvent('change'));
+    flush();
+
+    assertEquals(FileType.JPG.toString(), fileTypeSelect.selectedFileType);
+  });
+});
+
 suite('ColorModeSelectTest', () => {
   /** @type {!ColorModeSelectElement} */
   let colorModeSelect;
diff --git a/chromeos/chromeos_strings.grd b/chromeos/chromeos_strings.grd
index 26ca7761..7dafa851 100644
--- a/chromeos/chromeos_strings.grd
+++ b/chromeos/chromeos_strings.grd
@@ -472,6 +472,18 @@
       <message name="IDS_SCANNING_APP_SOURCE_DROPDOWN_LABEL" desc="The label for the dropdown that displays available scan sources (e.g. flatbed, document feeder, etc.).">
         Source
       </message>
+      <message name="IDS_SCANNING_APP_FILE_TYPE_DROPDOWN_LABEL" desc="The label for the dropdown that displays available file types.">
+        File type
+      </message>
+      <message name="IDS_SCANNING_APP_JPG_OPTION_TEXT" desc="The text displayed for the JPG file type option.">
+        JPG
+      </message>
+      <message name="IDS_SCANNING_APP_PDF_OPTION_TEXT" desc="The text displayed for the PDF file type option.">
+        PDF
+      </message>
+      <message name="IDS_SCANNING_APP_PNG_OPTION_TEXT" desc="The text displayed for the PNG file type option.">
+        PNG
+      </message>
       <message name="IDS_SCANNING_APP_COLOR_MODE_DROPDOWN_LABEL" desc="The label for the dropdown that displays available color modes (e.g. color, grayscale, black and white, etc.).">
         Color mode
       </message>
diff --git a/chromeos/chromeos_strings_grd/IDS_SCANNING_APP_FILE_TYPE_DROPDOWN_LABEL.png.sha1 b/chromeos/chromeos_strings_grd/IDS_SCANNING_APP_FILE_TYPE_DROPDOWN_LABEL.png.sha1
new file mode 100644
index 0000000..4011875
--- /dev/null
+++ b/chromeos/chromeos_strings_grd/IDS_SCANNING_APP_FILE_TYPE_DROPDOWN_LABEL.png.sha1
@@ -0,0 +1 @@
+086936e86b46d2a6d557fd41b0067935bf54031c
\ No newline at end of file
diff --git a/chromeos/chromeos_strings_grd/IDS_SCANNING_APP_JPG_OPTION_TEXT.png.sha1 b/chromeos/chromeos_strings_grd/IDS_SCANNING_APP_JPG_OPTION_TEXT.png.sha1
new file mode 100644
index 0000000..3e68650
--- /dev/null
+++ b/chromeos/chromeos_strings_grd/IDS_SCANNING_APP_JPG_OPTION_TEXT.png.sha1
@@ -0,0 +1 @@
+63f399f4f3917a1405a86f945f09c5cf1ed32e7e
\ No newline at end of file
diff --git a/chromeos/chromeos_strings_grd/IDS_SCANNING_APP_PDF_OPTION_TEXT.png.sha1 b/chromeos/chromeos_strings_grd/IDS_SCANNING_APP_PDF_OPTION_TEXT.png.sha1
new file mode 100644
index 0000000..3e68650
--- /dev/null
+++ b/chromeos/chromeos_strings_grd/IDS_SCANNING_APP_PDF_OPTION_TEXT.png.sha1
@@ -0,0 +1 @@
+63f399f4f3917a1405a86f945f09c5cf1ed32e7e
\ No newline at end of file
diff --git a/chromeos/chromeos_strings_grd/IDS_SCANNING_APP_PNG_OPTION_TEXT.png.sha1 b/chromeos/chromeos_strings_grd/IDS_SCANNING_APP_PNG_OPTION_TEXT.png.sha1
new file mode 100644
index 0000000..3e68650
--- /dev/null
+++ b/chromeos/chromeos_strings_grd/IDS_SCANNING_APP_PNG_OPTION_TEXT.png.sha1
@@ -0,0 +1 @@
+63f399f4f3917a1405a86f945f09c5cf1ed32e7e
\ No newline at end of file
diff --git a/chromeos/components/local_search_service/BUILD.gn b/chromeos/components/local_search_service/BUILD.gn
index 10043fbb..cd37190 100644
--- a/chromeos/components/local_search_service/BUILD.gn
+++ b/chromeos/components/local_search_service/BUILD.gn
@@ -22,8 +22,8 @@
     "local_search_service_sync_factory.h",
     "pref_names.cc",
     "pref_names.h",
-    "search_metrics_reporter.cc",
-    "search_metrics_reporter.h",
+    "search_metrics_reporter_sync.cc",
+    "search_metrics_reporter_sync.h",
     "search_utils.cc",
     "search_utils.h",
     "shared_structs.cc",
@@ -94,7 +94,7 @@
     "linear_map_search_unittest.cc",
     "local_search_service_proxy_unittest.cc",
     "local_search_service_sync_unittest.cc",
-    "search_metrics_reporter_unittest.cc",
+    "search_metrics_reporter_sync_unittest.cc",
     "search_utils_unittest.cc",
   ]
 
diff --git a/chromeos/components/local_search_service/index_sync.cc b/chromeos/components/local_search_service/index_sync.cc
index e6d0614b..d6cd06a2 100644
--- a/chromeos/components/local_search_service/index_sync.cc
+++ b/chromeos/components/local_search_service/index_sync.cc
@@ -20,7 +20,7 @@
 }
 
 std::string IndexIdBasedHistogramPrefix(IndexId index_id) {
-  const std::string prefix = "LocalSearchServiceSync.";
+  const std::string prefix = "LocalSearchService.";
   switch (index_id) {
     case IndexId::kCrosSettings:
       return prefix + "CrosSettings";
@@ -42,7 +42,7 @@
     return;
   }
 
-  reporter_ = std::make_unique<SearchMetricsReporter>(local_state);
+  reporter_ = std::make_unique<SearchMetricsReporterSync>(local_state);
   DCHECK(reporter_);
   reporter_->SetIndexId(index_id);
 }
diff --git a/chromeos/components/local_search_service/index_sync.h b/chromeos/components/local_search_service/index_sync.h
index 24b4dc1c..ebe2d51 100644
--- a/chromeos/components/local_search_service/index_sync.h
+++ b/chromeos/components/local_search_service/index_sync.h
@@ -15,7 +15,7 @@
 #include "base/optional.h"
 #include "base/strings/string16.h"
 #include "base/time/time.h"
-#include "chromeos/components/local_search_service/search_metrics_reporter.h"
+#include "chromeos/components/local_search_service/search_metrics_reporter_sync.h"
 #include "chromeos/components/local_search_service/shared_structs.h"
 
 class PrefService;
@@ -78,7 +78,7 @@
 
  private:
   std::string histogram_prefix_;
-  std::unique_ptr<SearchMetricsReporter> reporter_;
+  std::unique_ptr<SearchMetricsReporterSync> reporter_;
   base::WeakPtrFactory<IndexSync> weak_ptr_factory_{this};
 };
 
diff --git a/chromeos/components/local_search_service/search_metrics_reporter.cc b/chromeos/components/local_search_service/search_metrics_reporter_sync.cc
similarity index 75%
rename from chromeos/components/local_search_service/search_metrics_reporter.cc
rename to chromeos/components/local_search_service/search_metrics_reporter_sync.cc
index 38b01af..d45aeccb 100644
--- a/chromeos/components/local_search_service/search_metrics_reporter.cc
+++ b/chromeos/components/local_search_service/search_metrics_reporter_sync.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "chromeos/components/local_search_service/search_metrics_reporter.h"
+#include "chromeos/components/local_search_service/search_metrics_reporter_sync.h"
 
 #include "base/check_op.h"
 #include "base/metrics/histogram_functions.h"
@@ -20,33 +20,33 @@
     base::TimeDelta::FromMinutes(30);
 
 // Prefs corresponding to IndexId values.
-constexpr std::array<const char*, SearchMetricsReporter::kNumberIndexIds>
+constexpr std::array<const char*, SearchMetricsReporterSync::kNumberIndexIds>
     kDailyCountPrefs = {
         prefs::kLocalSearchServiceMetricsCrosSettingsCount,
         prefs::kLocalSearchServiceMetricsHelpAppCount,
 };
 
 // Histograms corresponding to IndexId values.
-constexpr std::array<const char*, SearchMetricsReporter::kNumberIndexIds>
+constexpr std::array<const char*, SearchMetricsReporterSync::kNumberIndexIds>
     kDailyCountHistograms = {
-        SearchMetricsReporter::kCrosSettingsName,
-        SearchMetricsReporter::kHelpAppName,
+        SearchMetricsReporterSync::kCrosSettingsName,
+        SearchMetricsReporterSync::kHelpAppName,
 };
 
 }  // namespace
 
-constexpr char SearchMetricsReporter::kDailyEventIntervalName[];
-constexpr char SearchMetricsReporter::kCrosSettingsName[];
-constexpr char SearchMetricsReporter::kHelpAppName[];
+constexpr char SearchMetricsReporterSync::kDailyEventIntervalName[];
+constexpr char SearchMetricsReporterSync::kCrosSettingsName[];
+constexpr char SearchMetricsReporterSync::kHelpAppName[];
 
-constexpr int SearchMetricsReporter::kNumberIndexIds;
+constexpr int SearchMetricsReporterSync::kNumberIndexIds;
 
 // This class is needed since metrics::DailyEvent requires taking ownership
 // of its observers. It just forwards events to SearchMetricsReporter.
-class SearchMetricsReporter::DailyEventObserver
+class SearchMetricsReporterSync::DailyEventObserver
     : public metrics::DailyEvent::Observer {
  public:
-  explicit DailyEventObserver(SearchMetricsReporter* reporter)
+  explicit DailyEventObserver(SearchMetricsReporterSync* reporter)
       : reporter_(reporter) {
     DCHECK(reporter_);
   }
@@ -61,11 +61,11 @@
   }
 
  private:
-  SearchMetricsReporter* reporter_;  // Not owned.
+  SearchMetricsReporterSync* reporter_;  // Not owned.
 };
 
 // static:
-void SearchMetricsReporter::RegisterLocalStatePrefs(
+void SearchMetricsReporterSync::RegisterLocalStatePrefs(
     PrefRegistrySimple* registry) {
   metrics::DailyEvent::RegisterPref(
       registry, prefs::kLocalSearchServiceMetricsDailySample);
@@ -74,7 +74,7 @@
   }
 }
 
-SearchMetricsReporter::SearchMetricsReporter(
+SearchMetricsReporterSync::SearchMetricsReporterSync(
     PrefService* local_state_pref_service)
     : pref_service_(local_state_pref_service),
       daily_event_(std::make_unique<metrics::DailyEvent>(
@@ -91,15 +91,15 @@
                &metrics::DailyEvent::CheckInterval);
 }
 
-SearchMetricsReporter::~SearchMetricsReporter() = default;
+SearchMetricsReporterSync::~SearchMetricsReporterSync() = default;
 
-void SearchMetricsReporter::SetIndexId(IndexId index_id) {
+void SearchMetricsReporterSync::SetIndexId(IndexId index_id) {
   DCHECK(!index_id_);
   index_id_ = index_id;
   DCHECK_LT(static_cast<size_t>(index_id), kDailyCountPrefs.size());
 }
 
-void SearchMetricsReporter::OnSearchPerformed() {
+void SearchMetricsReporterSync::OnSearchPerformed() {
   DCHECK(index_id_);
   const size_t index = static_cast<size_t>(*index_id_);
   const char* daily_count_pref = kDailyCountPrefs[index];
@@ -107,12 +107,12 @@
   pref_service_->SetInteger(daily_count_pref, daily_counts_[index]);
 }
 
-void SearchMetricsReporter::ReportDailyMetricsForTesting(
+void SearchMetricsReporterSync::ReportDailyMetricsForTesting(
     metrics::DailyEvent::IntervalType type) {
   ReportDailyMetrics(type);
 }
 
-void SearchMetricsReporter::ReportDailyMetrics(
+void SearchMetricsReporterSync::ReportDailyMetrics(
     metrics::DailyEvent::IntervalType type) {
   if (!index_id_)
     return;
diff --git a/chromeos/components/local_search_service/search_metrics_reporter.h b/chromeos/components/local_search_service/search_metrics_reporter_sync.h
similarity index 87%
rename from chromeos/components/local_search_service/search_metrics_reporter.h
rename to chromeos/components/local_search_service/search_metrics_reporter_sync.h
index 36c5926..76866343 100644
--- a/chromeos/components/local_search_service/search_metrics_reporter.h
+++ b/chromeos/components/local_search_service/search_metrics_reporter_sync.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef CHROMEOS_COMPONENTS_LOCAL_SEARCH_SERVICE_SEARCH_METRICS_REPORTER_H_
-#define CHROMEOS_COMPONENTS_LOCAL_SEARCH_SERVICE_SEARCH_METRICS_REPORTER_H_
+#ifndef CHROMEOS_COMPONENTS_LOCAL_SEARCH_SERVICE_SEARCH_METRICS_REPORTER_SYNC_H_
+#define CHROMEOS_COMPONENTS_LOCAL_SEARCH_SERVICE_SEARCH_METRICS_REPORTER_SYNC_H_
 
 #include <array>
 #include <memory>
@@ -22,7 +22,7 @@
 namespace local_search_service {
 
 // SearchMetricsReporter logs daily search requests to UMA.
-class SearchMetricsReporter {
+class SearchMetricsReporterSync {
  public:
   static constexpr int kNumberIndexIds =
       static_cast<int>(IndexId::kMaxValue) + 1;
@@ -42,11 +42,12 @@
   static void RegisterLocalStatePrefs(PrefRegistrySimple* registry);
 
   // RegisterLocalStatePrefs() must be called before instantiating this class.
-  explicit SearchMetricsReporter(PrefService* local_state_pref_service);
-  ~SearchMetricsReporter();
+  explicit SearchMetricsReporterSync(PrefService* local_state_pref_service);
+  ~SearchMetricsReporterSync();
 
-  SearchMetricsReporter(const SearchMetricsReporter&) = delete;
-  SearchMetricsReporter& operator=(const SearchMetricsReporter&) = delete;
+  SearchMetricsReporterSync(const SearchMetricsReporterSync&) = delete;
+  SearchMetricsReporterSync& operator=(const SearchMetricsReporterSync&) =
+      delete;
 
   // Sets |index_id_|.
   void SetIndexId(IndexId index_id);
@@ -83,4 +84,4 @@
 }  // namespace local_search_service
 }  // namespace chromeos
 
-#endif  // CHROMEOS_COMPONENTS_LOCAL_SEARCH_SERVICE_SEARCH_METRICS_REPORTER_H_
+#endif  // CHROMEOS_COMPONENTS_LOCAL_SEARCH_SERVICE_SEARCH_METRICS_REPORTER_SYNC_H_
diff --git a/chromeos/components/local_search_service/search_metrics_reporter_unittest.cc b/chromeos/components/local_search_service/search_metrics_reporter_sync_unittest.cc
similarity index 69%
rename from chromeos/components/local_search_service/search_metrics_reporter_unittest.cc
rename to chromeos/components/local_search_service/search_metrics_reporter_sync_unittest.cc
index 7ff959b..c3e57e8 100644
--- a/chromeos/components/local_search_service/search_metrics_reporter_unittest.cc
+++ b/chromeos/components/local_search_service/search_metrics_reporter_sync_unittest.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "chromeos/components/local_search_service/search_metrics_reporter.h"
+#include "chromeos/components/local_search_service/search_metrics_reporter_sync.h"
 
 #include <memory>
 
@@ -18,20 +18,21 @@
 namespace chromeos {
 namespace local_search_service {
 
-class SearchMetricsReporterTest : public testing::Test {
+class SearchMetricsReporterSyncTest : public testing::Test {
  public:
-  SearchMetricsReporterTest() = default;
-  ~SearchMetricsReporterTest() override = default;
+  SearchMetricsReporterSyncTest() = default;
+  ~SearchMetricsReporterSyncTest() override = default;
 
   void SetUp() override {
-    SearchMetricsReporter::RegisterLocalStatePrefs(pref_service_.registry());
+    SearchMetricsReporterSync::RegisterLocalStatePrefs(
+        pref_service_.registry());
   }
 
   void TearDown() override { reporter_.reset(); }
 
  protected:
   void SetReporter(IndexId index_id) {
-    reporter_ = std::make_unique<SearchMetricsReporter>(&pref_service_);
+    reporter_ = std::make_unique<SearchMetricsReporterSync>(&pref_service_);
     reporter_->SetIndexId(index_id);
   }
 
@@ -55,50 +56,50 @@
 
   base::test::TaskEnvironment task_environment_;
   TestingPrefServiceSimple pref_service_;
-  std::unique_ptr<SearchMetricsReporter> reporter_;
+  std::unique_ptr<SearchMetricsReporterSync> reporter_;
 };
 
-TEST_F(SearchMetricsReporterTest, CountAndReportEvents) {
+TEST_F(SearchMetricsReporterSyncTest, CountAndReportEvents) {
   SetReporter(IndexId::kCrosSettings);
   SendOnSearchPerformed();
   SendOnSearchPerformed();
   SendOnSearchPerformed();
-  TriggerDailyEventAndVerifyHistograms(SearchMetricsReporter::kCrosSettingsName,
-                                       3);
+  TriggerDailyEventAndVerifyHistograms(
+      SearchMetricsReporterSync::kCrosSettingsName, 3);
 
   // The next day, another two searches.
   SendOnSearchPerformed();
   SendOnSearchPerformed();
-  TriggerDailyEventAndVerifyHistograms(SearchMetricsReporter::kCrosSettingsName,
-                                       2);
+  TriggerDailyEventAndVerifyHistograms(
+      SearchMetricsReporterSync::kCrosSettingsName, 2);
 }
 
-TEST_F(SearchMetricsReporterTest, LoadInitialCountsFromPrefs) {
+TEST_F(SearchMetricsReporterSyncTest, LoadInitialCountsFromPrefs) {
   // Create a new reporter and check that it loads its initial event counts from
   // prefs.
   pref_service_.SetInteger(prefs::kLocalSearchServiceMetricsCrosSettingsCount,
                            2);
   SetReporter(IndexId::kCrosSettings);
 
-  TriggerDailyEventAndVerifyHistograms(SearchMetricsReporter::kCrosSettingsName,
-                                       2);
+  TriggerDailyEventAndVerifyHistograms(
+      SearchMetricsReporterSync::kCrosSettingsName, 2);
 
   // The previous report should've cleared the prefs, so a new reporter should
   // start out at zero.
-  TriggerDailyEventAndVerifyHistograms(SearchMetricsReporter::kCrosSettingsName,
-                                       0);
+  TriggerDailyEventAndVerifyHistograms(
+      SearchMetricsReporterSync::kCrosSettingsName, 0);
 }
 
-TEST_F(SearchMetricsReporterTest, IgnoreDailyEventFirstRun) {
+TEST_F(SearchMetricsReporterSyncTest, IgnoreDailyEventFirstRun) {
   SetReporter(IndexId::kCrosSettings);
   // metrics::DailyEvent notifies observers immediately on first run. Histograms
   // shouldn't be sent in this case.
   base::HistogramTester tester;
   TriggerDailyEvent(metrics::DailyEvent::IntervalType::FIRST_RUN);
-  tester.ExpectTotalCount(SearchMetricsReporter::kCrosSettingsName, 0);
+  tester.ExpectTotalCount(SearchMetricsReporterSync::kCrosSettingsName, 0);
 }
 
-TEST_F(SearchMetricsReporterTest, IgnoreDailyEventClockChanged) {
+TEST_F(SearchMetricsReporterSyncTest, IgnoreDailyEventClockChanged) {
   SetReporter(IndexId::kCrosSettings);
   SendOnSearchPerformed();
 
@@ -106,12 +107,12 @@
   // jumped back. Histograms shouldn't be sent in this case.
   base::HistogramTester tester;
   TriggerDailyEvent(metrics::DailyEvent::IntervalType::CLOCK_CHANGED);
-  tester.ExpectTotalCount(SearchMetricsReporter::kCrosSettingsName, 0);
+  tester.ExpectTotalCount(SearchMetricsReporterSync::kCrosSettingsName, 0);
 
   // The existing stats should be cleared when the clock change notification is
   // received, so the next report should only contain zeros.
-  TriggerDailyEventAndVerifyHistograms(SearchMetricsReporter::kCrosSettingsName,
-                                       0);
+  TriggerDailyEventAndVerifyHistograms(
+      SearchMetricsReporterSync::kCrosSettingsName, 0);
 }
 
 }  // namespace local_search_service
diff --git a/chromeos/components/phonehub/connection_manager_impl.cc b/chromeos/components/phonehub/connection_manager_impl.cc
index 57e754fa..b8204ca6 100644
--- a/chromeos/components/phonehub/connection_manager_impl.cc
+++ b/chromeos/components/phonehub/connection_manager_impl.cc
@@ -5,6 +5,7 @@
 #include "chromeos/components/phonehub/connection_manager_impl.h"
 
 #include "base/bind_helpers.h"
+#include "base/time/time.h"
 #include "chromeos/constants/chromeos_features.h"
 #include "chromeos/services/device_sync/public/cpp/device_sync_client.h"
 #include "chromeos/services/multidevice_setup/public/cpp/multidevice_setup_client.h"
@@ -13,19 +14,33 @@
 namespace chromeos {
 namespace phonehub {
 namespace {
-const char kPhoneHubFeatureName[] = "phone_hub";
+constexpr char kPhoneHubFeatureName[] = "phone_hub";
+constexpr base::TimeDelta kConnectionTimeoutSeconds(
+    base::TimeDelta::FromSeconds(15u));
 }  // namespace
 
 ConnectionManagerImpl::ConnectionManagerImpl(
     multidevice_setup::MultiDeviceSetupClient* multidevice_setup_client,
     device_sync::DeviceSyncClient* device_sync_client,
-    chromeos::secure_channel::SecureChannelClient* secure_channel_client)
+    chromeos::secure_channel::SecureChannelClient* secure_channel_client) {
+  ConnectionManagerImpl(multidevice_setup_client_, device_sync_client,
+                        secure_channel_client,
+                        std::make_unique<base::OneShotTimer>());
+}
+
+ConnectionManagerImpl::ConnectionManagerImpl(
+    multidevice_setup::MultiDeviceSetupClient* multidevice_setup_client,
+    device_sync::DeviceSyncClient* device_sync_client,
+    chromeos::secure_channel::SecureChannelClient* secure_channel_client,
+    std::unique_ptr<base::OneShotTimer> timer)
     : multidevice_setup_client_(multidevice_setup_client),
       device_sync_client_(device_sync_client),
-      secure_channel_client_(secure_channel_client) {
+      secure_channel_client_(secure_channel_client),
+      timer_(std::move(timer)) {
   DCHECK(multidevice_setup_client_);
   DCHECK(device_sync_client_);
   DCHECK(secure_channel_client_);
+  DCHECK(timer_);
 }
 
 ConnectionManagerImpl::~ConnectionManagerImpl() {
@@ -81,6 +96,10 @@
   connection_attempt_->SetDelegate(this);
 
   NotifyStatusChanged();
+
+  timer_->Start(FROM_HERE, kConnectionTimeoutSeconds,
+                base::BindOnce(&ConnectionManagerImpl::OnConnectionTimeout,
+                               weak_ptr_factory_.GetWeakPtr()));
 }
 
 void ConnectionManagerImpl::SendMessage(const std::string& payload) {
@@ -96,6 +115,7 @@
     chromeos::secure_channel::mojom::ConnectionAttemptFailureReason reason) {
   PA_LOG(WARNING) << "AttemptConnection() failed to establish connection with "
                   << "error: " << reason << ".";
+  timer_->Stop();
   connection_attempt_.reset();
   NotifyStatusChanged();
 }
@@ -104,12 +124,15 @@
     std::unique_ptr<chromeos::secure_channel::ClientChannel> channel) {
   PA_LOG(VERBOSE) << "AttemptConnection() successfully established a "
                   << "connection between local and remote device.";
+  timer_->Stop();
   channel_ = std::move(channel);
   channel_->AddObserver(this);
   NotifyStatusChanged();
 }
 
 void ConnectionManagerImpl::OnDisconnected() {
+  // Stop timer in case we are disconnected before the connection timed out.
+  timer_->Stop();
   connection_attempt_.reset();
   channel_->RemoveObserver(this);
   channel_.reset();
@@ -120,5 +143,13 @@
   NotifyMessageReceived(payload);
 }
 
+void ConnectionManagerImpl::OnConnectionTimeout() {
+  PA_LOG(WARNING) << "AttemptionConnection() has timed out. Closing connection "
+                  << "attempt.";
+
+  connection_attempt_.reset();
+  NotifyStatusChanged();
+}
+
 }  // namespace phonehub
 }  // namespace chromeos
diff --git a/chromeos/components/phonehub/connection_manager_impl.h b/chromeos/components/phonehub/connection_manager_impl.h
index 08e7ff1..eaf961fb 100644
--- a/chromeos/components/phonehub/connection_manager_impl.h
+++ b/chromeos/components/phonehub/connection_manager_impl.h
@@ -7,7 +7,9 @@
 
 #include <memory>
 
+#include "base/memory/weak_ptr.h"
 #include "base/optional.h"
+#include "base/timer/timer.h"
 #include "chromeos/components/phonehub/connection_manager.h"
 #include "chromeos/services/secure_channel/public/cpp/client/client_channel.h"
 #include "chromeos/services/secure_channel/public/cpp/client/connection_attempt.h"
@@ -48,6 +50,14 @@
   void SendMessage(const std::string& payload) override;
 
  private:
+  friend class ConnectionManagerImplTest;
+
+  ConnectionManagerImpl(
+      multidevice_setup::MultiDeviceSetupClient* multidevice_setup_client,
+      device_sync::DeviceSyncClient* device_sync_client,
+      chromeos::secure_channel::SecureChannelClient* secure_channel_client,
+      std::unique_ptr<base::OneShotTimer> timer);
+
   // chromeos::secure_channel::ConnectionAttempt::Delegate:
   void OnConnectionAttemptFailure(
       chromeos::secure_channel::mojom::ConnectionAttemptFailureReason reason)
@@ -59,6 +69,8 @@
   void OnDisconnected() override;
   void OnMessageReceived(const std::string& payload) override;
 
+  void OnConnectionTimeout();
+
   multidevice_setup::MultiDeviceSetupClient* multidevice_setup_client_;
 
   device_sync::DeviceSyncClient* device_sync_client_;
@@ -70,6 +82,10 @@
       connection_attempt_;
 
   std::unique_ptr<chromeos::secure_channel::ClientChannel> channel_;
+
+  std::unique_ptr<base::OneShotTimer> timer_;
+
+  base::WeakPtrFactory<ConnectionManagerImpl> weak_ptr_factory_{this};
 };
 
 }  // namespace phonehub
diff --git a/chromeos/components/phonehub/connection_manager_impl_unittest.cc b/chromeos/components/phonehub/connection_manager_impl_unittest.cc
index b3f041a..6eaad0e 100644
--- a/chromeos/components/phonehub/connection_manager_impl_unittest.cc
+++ b/chromeos/components/phonehub/connection_manager_impl_unittest.cc
@@ -7,7 +7,10 @@
 #include <memory>
 
 #include "base/macros.h"
+#include "base/memory/ptr_util.h"
 #include "base/test/scoped_feature_list.h"
+#include "base/time/time.h"
+#include "base/timer/mock_timer.h"
 #include "chromeos/components/multidevice/remote_device_test_util.h"
 #include "chromeos/constants/chromeos_features.h"
 #include "chromeos/services/device_sync/public/cpp/fake_device_sync_client.h"
@@ -23,6 +26,9 @@
 
 using multidevice_setup::mojom::HostStatus;
 
+constexpr base::TimeDelta kExpectedTimeoutSeconds(
+    base::TimeDelta::FromSeconds(15u));
+
 class FakeObserver : public ConnectionManager::Observer {
  public:
   FakeObserver() = default;
@@ -66,12 +72,14 @@
 
   // testing::Test:
   void SetUp() override {
+    auto timer = std::make_unique<base::MockOneShotTimer>();
+    mock_timer_ = timer.get();
     fake_device_sync_client_.set_local_device_metadata(test_local_device_);
     fake_multidevice_setup_client_.SetHostStatusWithDevice(
         std::make_pair(HostStatus::kHostVerified, test_remote_device_));
-    connection_manager_ = std::make_unique<ConnectionManagerImpl>(
+    connection_manager_ = base::WrapUnique(new ConnectionManagerImpl(
         &fake_multidevice_setup_client_, &fake_device_sync_client_,
-        fake_secure_channel_client_.get());
+        fake_secure_channel_client_.get(), std::move(timer)));
     connection_manager_->AddObserver(&fake_observer_);
     EXPECT_EQ(ConnectionManager::Status::kDisconnected, GetStatus());
   }
@@ -107,6 +115,19 @@
     }
   }
 
+  void VerifyTimerSet() {
+    EXPECT_TRUE(mock_timer_->IsRunning());
+    EXPECT_EQ(kExpectedTimeoutSeconds, mock_timer_->GetCurrentDelay());
+  }
+
+  void VerifyTimerStopped() { EXPECT_FALSE(mock_timer_->IsRunning()); }
+
+  void InvokeTimerTask() {
+    VerifyTimerSet();
+    mock_timer_->Fire();
+  }
+
+  base::MockOneShotTimer* mock_timer_;
   chromeos::multidevice::RemoteDeviceRef test_remote_device_;
   chromeos::multidevice::RemoteDeviceRef test_local_device_;
   device_sync::FakeDeviceSyncClient fake_device_sync_client_;
@@ -260,5 +281,23 @@
   EXPECT_EQ(ConnectionManager::Status::kConnected, GetStatus());
 }
 
+TEST_F(ConnectionManagerImplTest, ConnectionTimeout) {
+  CreateFakeConnectionAttempt();
+  connection_manager_->AttemptConnection();
+
+  // Status has been updated to connecting, verify that the status observer
+  // has been called.
+  EXPECT_EQ(1u, GetNumStatusObserverCalls());
+  EXPECT_EQ(ConnectionManager::Status::kConnecting, GetStatus());
+  VerifyTimerSet();
+
+  // Simulate fast forwarding time to time out the connection request.
+  InvokeTimerTask();
+
+  VerifyTimerStopped();
+  EXPECT_EQ(2u, GetNumStatusObserverCalls());
+  EXPECT_EQ(ConnectionManager::Status::kDisconnected, GetStatus());
+}
+
 }  // namespace phonehub
 }  // namespace chromeos
diff --git a/chromeos/components/scanning/resources/BUILD.gn b/chromeos/components/scanning/resources/BUILD.gn
index 0853ab5..1e36ade1 100644
--- a/chromeos/components/scanning/resources/BUILD.gn
+++ b/chromeos/components/scanning/resources/BUILD.gn
@@ -11,6 +11,7 @@
   is_polymer3 = true
   deps = [
     ":color_mode_select",
+    ":file_type_select",
     ":mojo_interface_provider",
     ":resolution_select",
     ":scanner_select",
@@ -30,6 +31,14 @@
   ]
 }
 
+js_library("file_type_select") {
+  deps = [
+    "//chromeos/components/scanning/mojom:mojom_js_library_for_compile",
+    "//third_party/polymer/v3_0/components-chromium/polymer:polymer_bundled",
+    "//ui/webui/resources/js:i18n_behavior.m",
+  ]
+}
+
 js_library("resolution_select") {
   deps = [
     "//chromeos/components/scanning/mojom:mojom_js_library_for_compile",
@@ -52,6 +61,7 @@
 js_library("scanning_app") {
   deps = [
     ":color_mode_select",
+    ":file_type_select",
     ":mojo_interface_provider",
     ":resolution_select",
     ":scanner_select",
@@ -59,6 +69,7 @@
     ":scanning_app_util",
     ":source_select",
     "//third_party/polymer/v3_0/components-chromium/polymer:polymer_bundled",
+    "//ui/webui/resources/js:i18n_behavior.m",
   ]
 }
 
@@ -87,7 +98,9 @@
 html_to_js("web_components") {
   js_files = [
     "color_mode_select.js",
+    "file_type_select.js",
     "resolution_select.js",
+    "scan_settings_section.js",
     "scanner_select.js",
     "scanning_app.js",
     "source_select.js",
diff --git a/chromeos/components/scanning/resources/color_mode_select.html b/chromeos/components/scanning/resources/color_mode_select.html
index e1071001c..0de621e7 100644
--- a/chromeos/components/scanning/resources/color_mode_select.html
+++ b/chromeos/components/scanning/resources/color_mode_select.html
@@ -1,26 +1,16 @@
-<style>
-  #title {
-    height: 32px;
-    padding-inline-end: 10px;
-  }
-
-  #controls {
-    display: inline-block;
-    height: 32px;
-    width: 300px;
-  }
-</style>
-<span id="title">[[i18n('colorModeDropdownLabel')]]</span>
-<div id="controls">
-  <!-- TODO(jschettler): Verify this meets a11y expecations (e.g. ChromeVox
-      should announce when a new option is focused). -->
-  <select class="md-select" value="{{selectedColorMode::change}}"
-      disabled="[[disabled_]]">
-    <!-- TODO(jschettler): Determine how the color modes should be sorted. -->
-    <template is="dom-repeat" items="[[colorModes]]" as="colorMode">
-      <option value="[[colorMode]]">
-        [[getColorModeString_(colorMode)]]
-      </option>
-    </template>
-  </select>
-</div>
+<scan-settings-section>
+  <span id="colorModeLabel" slot="label">[[i18n('colorModeDropdownLabel')]]</span>
+  <div slot="settings">
+    <!-- TODO(jschettler): Verify this meets a11y expecations (e.g. ChromeVox
+        should announce when a new option is focused). -->
+    <select class="md-select" value="{{selectedColorMode::change}}"
+        disabled="[[disabled_]]">
+      <!-- TODO(jschettler): Determine how the color modes should be sorted. -->
+      <template is="dom-repeat" items="[[colorModes]]" as="colorMode">
+        <option value="[[colorMode]]">
+          [[getColorModeString_(colorMode)]]
+        </option>
+      </template>
+    </select>
+  </div>
+</scan-settings-section>
diff --git a/chromeos/components/scanning/resources/color_mode_select.js b/chromeos/components/scanning/resources/color_mode_select.js
index 6732404..7f653e9e 100644
--- a/chromeos/components/scanning/resources/color_mode_select.js
+++ b/chromeos/components/scanning/resources/color_mode_select.js
@@ -3,6 +3,7 @@
 // found in the LICENSE file.
 
 import './scanning.mojom-lite.js';
+import './scan_settings_section.js';
 
 import {getColorModeString} from './scanning_app_util.js';
 import {html, Polymer} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
diff --git a/chromeos/components/scanning/resources/file_type_select.html b/chromeos/components/scanning/resources/file_type_select.html
new file mode 100644
index 0000000..c3f82cc
--- /dev/null
+++ b/chromeos/components/scanning/resources/file_type_select.html
@@ -0,0 +1,15 @@
+<scan-settings-section>
+  <span id="fileTypeLabel" slot="label">[[i18n('fileTypeDropdownLabel')]]</span>
+  <div slot="settings">
+    <!-- TODO(jschettler): Verify this meets a11y expecations (e.g. ChromeVox
+        should announce when a new option is focused). -->
+    <select class="md-select" value="{{selectedFileType::change}}"
+        disabled="[[settingsDisabled]]">
+      <!-- The option values must match the chromeos.scanning.mojom.FileType
+          values they correspond to. -->
+      <option value="0">[[i18n('jpgOptionText')]]</option>
+      <option value="1" selected>[[i18n('pdfOptionText')]]</option>
+      <option value="2">[[i18n('pngOptionText')]]</option>
+    </select>
+  </div>
+</scan-settings-section>
diff --git a/chromeos/components/scanning/resources/file_type_select.js b/chromeos/components/scanning/resources/file_type_select.js
new file mode 100644
index 0000000..88e98af
--- /dev/null
+++ b/chromeos/components/scanning/resources/file_type_select.js
@@ -0,0 +1,35 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+import './scanning.mojom-lite.js';
+import './scan_settings_section.js';
+
+import {html, Polymer} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
+import {I18nBehavior} from 'chrome://resources/js/i18n_behavior.m.js';
+import './strings.js';
+
+/**
+ * @fileoverview
+ * 'file-type-select' displays the available file types in a dropdown.
+ */
+Polymer({
+  is: 'file-type-select',
+
+  _template: html`{__html_template__}`,
+
+  behaviors: [I18nBehavior],
+
+  properties: {
+    /** @type {chromeos.scanning.mojom.FileType|undefined} */
+    selectedFileType: {
+      type: chromeos.scanning.mojom.FileType,
+      notify: true,
+    },
+
+    /**
+     * Indicates whether all settings have been disabled by the parent element.
+     */
+    settingsDisabled: Boolean,
+  },
+});
diff --git a/chromeos/components/scanning/resources/resolution_select.html b/chromeos/components/scanning/resources/resolution_select.html
index 46accea..8b32bc45 100644
--- a/chromeos/components/scanning/resources/resolution_select.html
+++ b/chromeos/components/scanning/resources/resolution_select.html
@@ -1,26 +1,16 @@
-<style>
-  #title {
-    height: 32px;
-    padding-inline-end: 10px;
-  }
-
-  #controls {
-    display: inline-block;
-    height: 32px;
-    width: 300px;
-  }
-</style>
-<span id="title">[[i18n('resolutionDropdownLabel')]]</span>
-<div id="controls">
-  <!-- TODO(jschettler): Verify this meets a11y expecations (e.g. ChromeVox
-      should announce when a new option is focused). -->
-  <select class="md-select" value="{{selectedResolution::change}}"
-      disabled="[[disabled_]]">
-    <!-- TODO(jschettler): Sort the resolutions. -->
-    <template is="dom-repeat" items="[[resolutions]]" as="resolution">
-      <option value="[[resolution]]">
-        [[getResolutionString_(resolution)]]
-      </option>
-    </template>
-  </select>
-</div>
+<scan-settings-section>
+  <span id="resolutionLabel" slot="label">[[i18n('resolutionDropdownLabel')]]</span>
+  <div slot="settings">
+    <!-- TODO(jschettler): Verify this meets a11y expecations (e.g. ChromeVox
+        should announce when a new option is focused). -->
+    <select class="md-select" value="{{selectedResolution::change}}"
+        disabled="[[disabled_]]">
+      <!-- TODO(jschettler): Sort the resolutions. -->
+      <template is="dom-repeat" items="[[resolutions]]" as="resolution">
+        <option value="[[resolution]]">
+          [[getResolutionString_(resolution)]]
+        </option>
+      </template>
+    </select>
+  </div>
+</scan-settings-section>
diff --git a/chromeos/components/scanning/resources/resolution_select.js b/chromeos/components/scanning/resources/resolution_select.js
index 65b79ed..dbf65d4c0 100644
--- a/chromeos/components/scanning/resources/resolution_select.js
+++ b/chromeos/components/scanning/resources/resolution_select.js
@@ -3,6 +3,7 @@
 // found in the LICENSE file.
 
 import './scanning.mojom-lite.js';
+import './scan_settings_section.js';
 
 import {html, Polymer} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
 import {I18nBehavior} from 'chrome://resources/js/i18n_behavior.m.js';
diff --git a/chromeos/components/scanning/resources/scan_settings_section.html b/chromeos/components/scanning/resources/scan_settings_section.html
new file mode 100644
index 0000000..46d8c5b6
--- /dev/null
+++ b/chromeos/components/scanning/resources/scan_settings_section.html
@@ -0,0 +1,30 @@
+<!-- TODO(jschettler): Update styling to match the spec. -->
+<style>
+  :host {
+    display: flex;
+  }
+
+  ::slotted([slot=label]),
+  ::slotted([slot=settings]) {
+    display: flex;
+    flex-direction: column;
+    min-height: 38px;
+  }
+
+  ::slotted([slot=label]) {
+    flex: none;
+    flex-basis: 100px;
+    flex-grow: 0;
+    flex-shrink: 0;
+    padding-inline-end: 10px;
+  }
+
+  ::slotted([slot=settings]) {
+    flex: 1;
+    flex-basis: 250px;
+    flex-grow: 0;
+    flex-shrink: 0;
+  }
+</style>
+<slot name="label"></slot>
+<slot name="settings"></slot>
diff --git a/chromeos/components/scanning/resources/scan_settings_section.js b/chromeos/components/scanning/resources/scan_settings_section.js
new file mode 100644
index 0000000..0fa252a3
--- /dev/null
+++ b/chromeos/components/scanning/resources/scan_settings_section.js
@@ -0,0 +1,11 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+import {html, Polymer} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
+
+Polymer({
+  is: 'scan-settings-section',
+
+  _template: html`{__html_template__}`,
+});
diff --git a/chromeos/components/scanning/resources/scanner_select.html b/chromeos/components/scanning/resources/scanner_select.html
index af9bc5a..2846c08 100644
--- a/chromeos/components/scanning/resources/scanner_select.html
+++ b/chromeos/components/scanning/resources/scanner_select.html
@@ -1,35 +1,26 @@
-<style include="throbber">
-  #title {
-    padding-inline-end: 10px;
-    height: 32px;
-  }
-
-  #controls {
-    display: inline-block;
-    height: 32px;
-    width: 300px;
-  }
-</style>
-<span id="title">[[i18n('scannerDropdownLabel')]]</span>
-<div id="controls">
-  <div class="throbber-container" hidden$="[[loaded]]">
-    <div class="throbber"></div>
+<style include="throbber"></style>
+<scan-settings-section>
+  <span id="scannerLabel" slot="label">[[i18n('scannerDropdownLabel')]]</span>
+  <div slot="settings">
+    <div class="throbber-container" hidden$="[[loaded]]">
+      <div class="throbber"></div>
+    </div>
+    <!-- TODO(jschettler): Verify this meets a11y expecations (e.g. ChromeVox
+        should announce when a new option is focused). -->
+    <select class="md-select" value="{{selectedScannerId::change}}"
+        hidden$="[[!loaded]]" disabled="[[disabled_]]">
+      <!-- TODO(jschettler): Figure out why hiding/disabling the option doesn't
+          remove it from the dropdown. -->
+      <template is="dom-if" if="[[!scanners.length]]" restamp>
+        <option value="">
+          [[i18n('noScannersText')]]
+        </option>
+      </template>
+      <template is="dom-repeat" items="[[scanners]]" as="scanner">
+        <option value="[[getTokenAsString_(scanner)]]">
+          [[getScannerDisplayName_(scanner)]]
+        </option>
+      </template>
+    </select>
   </div>
-  <!-- TODO(jschettler): Verify this meets a11y expecations (e.g. ChromeVox
-      should announce when a new option is focused). -->
-  <select class="md-select" value="{{selectedScannerId::change}}"
-      hidden$="[[!loaded]]" disabled="[[disabled_]]">
-    <!-- TODO(jschettler): Figure out why hiding/disabling the option doesn't
-        remove it from the dropdown. -->
-    <template is="dom-if" if="[[!scanners.length]]" restamp>
-      <option value="">
-        [[i18n('noScannersText')]]
-      </option>
-    </template>
-    <template is="dom-repeat" items="[[scanners]]" as="scanner">
-      <option value="[[getTokenAsString_(scanner)]]">
-        [[getScannerDisplayName_(scanner)]]
-      </option>
-    </template>
-  </select>
-</div>
+</scan-settings-section>
diff --git a/chromeos/components/scanning/resources/scanner_select.js b/chromeos/components/scanning/resources/scanner_select.js
index a02d027..dc39c2b 100644
--- a/chromeos/components/scanning/resources/scanner_select.js
+++ b/chromeos/components/scanning/resources/scanner_select.js
@@ -6,6 +6,7 @@
 import 'chrome://resources/mojo/mojo/public/mojom/base/string16.mojom-lite.js';
 import 'chrome://resources/mojo/mojo/public/mojom/base/unguessable_token.mojom-lite.js';
 import './scanning.mojom-lite.js';
+import './scan_settings_section.js';
 import './throbber_css.js';
 
 import {html, Polymer} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
diff --git a/chromeos/components/scanning/resources/scanning_app.html b/chromeos/components/scanning/resources/scanning_app.html
index 93c2c088..4e7ce290 100644
--- a/chromeos/components/scanning/resources/scanning_app.html
+++ b/chromeos/components/scanning/resources/scanning_app.html
@@ -1,26 +1,20 @@
-<div id="header"></div>
-<div>
-  <scanner-select id="scannerSelect" scanners="[[scanners_]]"
-      loaded="[[loaded_]]" settings-disabled="[[settingsDisabled_]]"
-      selected-scanner-id="{{selectedScannerId}}"></scanner-select>
-</div>
-<div>
-  <source-select id="sourceSelect" sources="[[capabilities_.sources]]"
-      settings-disabled="[[settingsDisabled_]]"
-      selected-source="{{selectedSource}}"></source-select>
-</div>
-<div>
-  <color-mode-select id="colorModeSelect"
-      color-modes="[[capabilities_.colorModes]]"
-      settings-disabled="[[settingsDisabled_]]"
-      selected-color-mode="{{selectedColorMode}}"></color-mode-select>
-</div>
-<div>
-  <resolution-select id="resolutionSelect"
-      resolutions="[[capabilities_.resolutions]]"
-      settings-disabled="[[settingsDisabled_]]"
-      selected-resolution="{{selectedResolution}}"></resolution-select>
-</div>
+<h1 id="appTitle">[[i18n('appTitle')]]</h1>
+<scanner-select id="scannerSelect" scanners="[[scanners_]]" loaded="[[loaded_]]"
+    settings-disabled="[[settingsDisabled_]]"
+    selected-scanner-id="{{selectedScannerId}}"></scanner-select>
+<source-select id="sourceSelect" sources="[[capabilities_.sources]]"
+    settings-disabled="[[settingsDisabled_]]"
+    selected-source="{{selectedSource}}"></source-select>
+<file-type-select id="fileTypeSelect" settings-disabled="[[settingsDisabled_]]"
+    selected-file-type="{{selectedFileType}}"></file-type-select>
+<color-mode-select id="colorModeSelect"
+    color-modes="[[capabilities_.colorModes]]"
+    settings-disabled="[[settingsDisabled_]]"
+    selected-color-mode="{{selectedColorMode}}"></color-mode-select>
+<resolution-select id="resolutionSelect"
+    resolutions="[[capabilities_.resolutions]]"
+    settings-disabled="[[settingsDisabled_]]"
+    selected-resolution="{{selectedResolution}}"></resolution-select>
 <!-- TODO(jschettler): Replace button label with finalized i18n string. -->
 <cr-button id="scanButton" on-click="onScanClick_"
     disabled$="[[scanButtonDisabled_]]">
diff --git a/chromeos/components/scanning/resources/scanning_app.js b/chromeos/components/scanning/resources/scanning_app.js
index 5125b6f..2af521a 100644
--- a/chromeos/components/scanning/resources/scanning_app.js
+++ b/chromeos/components/scanning/resources/scanning_app.js
@@ -7,11 +7,13 @@
 import 'chrome://resources/mojo/mojo/public/mojom/base/string16.mojom-lite.js';
 import 'chrome://resources/mojo/mojo/public/mojom/base/unguessable_token.mojom-lite.js';
 import './color_mode_select.js';
+import './file_type_select.js';
 import './resolution_select.js';
 import './scanner_select.js';
 import './source_select.js';
 
 import {html, Polymer} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
+import {I18nBehavior} from 'chrome://resources/js/i18n_behavior.m.js';
 import {getScanService} from './mojo_interface_provider.js';
 import {ScannerArr} from './scanning_app_types.js';
 import {tokenToString} from './scanning_app_util.js';
@@ -25,6 +27,8 @@
 
   _template: html`{__html_template__}`,
 
+  behaviors: [I18nBehavior],
+
   /** @private {?chromeos.scanning.mojom.ScanServiceInterface} */
   scanService_: null,
 
@@ -53,6 +57,9 @@
     /** @type {?string} */
     selectedSource: String,
 
+    /** @type {chromeos.scanning.mojom.FileType|undefined} */
+    selectedFileType: chromeos.scanning.mojom.FileType,
+
     /** @type {chromeos.scanning.mojom.ColorMode|undefined} */
     selectedColorMode: chromeos.scanning.mojom.ColorMode,
 
@@ -113,6 +120,9 @@
     this.selectedColorMode = this.capabilities_.colorModes[0];
     this.selectedResolution = this.capabilities_.resolutions[0];
 
+    // PDF is the default file type.
+    this.selectedFileType = chromeos.scanning.mojom.FileType.kPdf;
+
     this.scanButtonDisabled_ = false;
   },
 
@@ -161,6 +171,7 @@
   /** @private */
   onScanClick_() {
     if (!this.selectedScannerId || !this.selectedSource ||
+        this.selectedFileType === undefined ||
         this.selectedColorMode === undefined ||
         this.selectedResolution === undefined) {
       // TODO(jschettler): Replace status text with finalized i18n strings.
@@ -172,8 +183,8 @@
     this.settingsDisabled_ = true;
     this.scanButtonDisabled_ = true;
 
-    // TODO(jschettler): Set file type using the selected value when the
-    // corresponding dropdown is added.
+    // TODO(jschettler): Use the selected file type when ScanService supports
+    // it.
     const settings = {
       'sourceName': this.selectedSource,
       'fileType': chromeos.scanning.mojom.FileType.kPng,
diff --git a/chromeos/components/scanning/resources/scanning_app_resources.grd b/chromeos/components/scanning/resources/scanning_app_resources.grd
index 4038642..476e5f34 100644
--- a/chromeos/components/scanning/resources/scanning_app_resources.grd
+++ b/chromeos/components/scanning/resources/scanning_app_resources.grd
@@ -13,17 +13,20 @@
   <release seq="1">
     <includes>
       <!-- Privileged app host contents. -->
-      <include name="IDR_SCANNING_APP_INDEX_HTML" file="index.html" type="BINDATA" compress="gzip" />
-      <include name="IDR_SCANNING_MOJO_LITE_JS" file="${root_gen_dir}/chromeos/components/scanning/mojom/scanning.mojom-lite.js" compress="gzip" use_base_dir="false" type="BINDATA" />
-      <include name="IDR_SCANNING_APP_JS" file="${root_gen_dir}/chromeos/components/scanning/resources/scanning_app.js" use_base_dir="false" compress="gzip" type="BINDATA"/>
-      <include name="IDR_SCANNING_APP_SCANNER_SELECT_HTML" file="scanner_select.html" compress="gzip" type="BINDATA"/>
-      <include name="IDR_SCANNING_APP_SCANNER_SELECT_JS" file="${root_gen_dir}/chromeos/components/scanning/resources/scanner_select.js" use_base_dir="false" compress="gzip" type="BINDATA"/>
-      <include name="IDR_SCANNING_APP_SOURCE_SELECT_HTML" file="source_select.html" compress="gzip" type="BINDATA"/>
-      <include name="IDR_SCANNING_APP_SOURCE_SELECT_JS" file="${root_gen_dir}/chromeos/components/scanning/resources/source_select.js" use_base_dir="false" compress="gzip" type="BINDATA"/>
-      <include name="IDR_SCANNING_APP_COLOR_MODE_SELECT_HTML" file="color_mode_select.html" compress="gzip" type="BINDATA"/>
-      <include name="IDR_SCANNING_APP_COLOR_MODE_SELECT_JS" file="${root_gen_dir}/chromeos/components/scanning/resources/color_mode_select.js" use_base_dir="false" compress="gzip" type="BINDATA"/>
-      <include name="IDR_SCANNING_APP_RESOLUTION_SELECT_HTML" file="resolution_select.html" compress="gzip" type="BINDATA"/>
-      <include name="IDR_SCANNING_APP_RESOLUTION_SELECT_JS" file="${root_gen_dir}/chromeos/components/scanning/resources/resolution_select.js" use_base_dir="false" compress="gzip" type="BINDATA"/>
+      <include name="IDR_SCANNING_APP_INDEX_HTML" file="index.html" type="BINDATA" />
+      <include name="IDR_SCANNING_MOJO_LITE_JS" file="${root_gen_dir}/chromeos/components/scanning/mojom/scanning.mojom-lite.js" use_base_dir="false" type="BINDATA" />
+      <include name="IDR_SCANNING_APP_JS" file="${root_gen_dir}/chromeos/components/scanning/resources/scanning_app.js" use_base_dir="false" type="BINDATA"/>
+      <include name="IDR_SCANNING_APP_SCANNER_SELECT_HTML" file="scanner_select.html" type="BINDATA"/>
+      <include name="IDR_SCANNING_APP_SCANNER_SELECT_JS" file="${root_gen_dir}/chromeos/components/scanning/resources/scanner_select.js" use_base_dir="false" type="BINDATA"/>
+      <include name="IDR_SCANNING_APP_SOURCE_SELECT_HTML" file="source_select.html" type="BINDATA"/>
+      <include name="IDR_SCANNING_APP_SOURCE_SELECT_JS" file="${root_gen_dir}/chromeos/components/scanning/resources/source_select.js" use_base_dir="false" type="BINDATA"/>
+      <include name="IDR_SCANNING_APP_FILE_TYPE_SELECT_HTML" file="file_type_select.html" type="BINDATA"/>
+      <include name="IDR_SCANNING_APP_FILE_TYPE_SELECT_JS" file="${root_gen_dir}/chromeos/components/scanning/resources/file_type_select.js" use_base_dir="false" type="BINDATA"/>
+      <include name="IDR_SCANNING_APP_COLOR_MODE_SELECT_HTML" file="color_mode_select.html" type="BINDATA"/>
+      <include name="IDR_SCANNING_APP_COLOR_MODE_SELECT_JS" file="${root_gen_dir}/chromeos/components/scanning/resources/color_mode_select.js" use_base_dir="false" type="BINDATA"/>
+      <include name="IDR_SCANNING_APP_RESOLUTION_SELECT_HTML" file="resolution_select.html" type="BINDATA"/>
+      <include name="IDR_SCANNING_APP_RESOLUTION_SELECT_JS" file="${root_gen_dir}/chromeos/components/scanning/resources/resolution_select.js" use_base_dir="false" type="BINDATA"/>
+      <include name="IDR_SCANNING_APP_SCAN_SETTINGS_SECTION_JS" file="${root_gen_dir}/chromeos/components/scanning/resources/scan_settings_section.js" use_base_dir="false" type="BINDATA"/>
       <include name="IDR_SCANNING_APP_THROBBER_CSS_JS" file="${root_gen_dir}/chromeos/components/scanning/resources/throbber_css.js" use_base_dir="false" type="BINDATA"/>
       <include name="IDR_SCANNING_APP_ICON" file="app_icon_192.png" type="BINDATA" />
     </includes>
diff --git a/chromeos/components/scanning/resources/source_select.html b/chromeos/components/scanning/resources/source_select.html
index 0aebf8a..32d1a5c 100644
--- a/chromeos/components/scanning/resources/source_select.html
+++ b/chromeos/components/scanning/resources/source_select.html
@@ -1,26 +1,16 @@
-<style>
-  #title {
-    height: 32px;
-    padding-inline-end: 10px;
-  }
-
-  #controls {
-    display: inline-block;
-    height: 32px;
-    width: 300px;
-  }
-</style>
-<span id="title">[[i18n('sourceDropdownLabel')]]</span>
-<div id="controls">
-  <!-- TODO(jschettler): Verify this meets a11y expecations (e.g. ChromeVox
-      should announce when a new option is focused). -->
-  <select class="md-select" value="{{selectedSource::change}}"
-      disabled="[[disabled_]]">
-    <!-- TODO(jschettler): Determine how the sources should be sorted. -->
-    <template is="dom-repeat" items="[[sources]]" as="source">
-      <option value="[[source.name]]">
-        [[getSourceTypeString_(source.type)]]
-      </option>
-    </template>
-  </select>
-</div>
+<scan-settings-section>
+  <span id="sourceLabel" slot="label">[[i18n('sourceDropdownLabel')]]</span>
+  <div slot="settings">
+    <!-- TODO(jschettler): Verify this meets a11y expecations (e.g. ChromeVox
+        should announce when a new option is focused). -->
+    <select class="md-select" value="{{selectedSource::change}}"
+        disabled="[[disabled_]]">
+      <!-- TODO(jschettler): Determine how the sources should be sorted. -->
+      <template is="dom-repeat" items="[[sources]]" as="source">
+        <option value="[[source.name]]">
+          [[getSourceTypeString_(source.type)]]
+        </option>
+      </template>
+    </select>
+  </div>
+</scan-settings-section>
diff --git a/chromeos/components/scanning/resources/source_select.js b/chromeos/components/scanning/resources/source_select.js
index 1f27f5d4..a33c05e 100644
--- a/chromeos/components/scanning/resources/source_select.js
+++ b/chromeos/components/scanning/resources/source_select.js
@@ -2,10 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-import 'chrome://resources/mojo/mojo/public/mojom/base/big_buffer.mojom-lite.js';
-import 'chrome://resources/mojo/mojo/public/mojom/base/string16.mojom-lite.js';
-import 'chrome://resources/mojo/mojo/public/mojom/base/unguessable_token.mojom-lite.js';
 import './scanning.mojom-lite.js';
+import './scan_settings_section.js';
 
 import {getSourceTypeString} from './scanning_app_util.js';
 import {html, Polymer} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
diff --git a/chromeos/components/scanning/scanning_ui.cc b/chromeos/components/scanning/scanning_ui.cc
index 5809ebb..449c5dd 100644
--- a/chromeos/components/scanning/scanning_ui.cc
+++ b/chromeos/components/scanning/scanning_ui.cc
@@ -49,12 +49,16 @@
 void AddScanningAppStrings(content::WebUIDataSource* html_source) {
   static constexpr webui::LocalizedString kLocalizedStrings[] = {
       {"appTitle", IDS_SCANNING_APP_TITLE},
-      {"scannerDropdownLabel", IDS_SCANNING_APP_SCANNER_DROPDOWN_LABEL},
-      {"noScannersText", IDS_SCANNING_APP_NO_SCANNERS_TEXT},
-      {"sourceDropdownLabel", IDS_SCANNING_APP_SOURCE_DROPDOWN_LABEL},
       {"colorModeDropdownLabel", IDS_SCANNING_APP_COLOR_MODE_DROPDOWN_LABEL},
+      {"fileTypeDropdownLabel", IDS_SCANNING_APP_FILE_TYPE_DROPDOWN_LABEL},
+      {"jpgOptionText", IDS_SCANNING_APP_JPG_OPTION_TEXT},
+      {"noScannersText", IDS_SCANNING_APP_NO_SCANNERS_TEXT},
+      {"pdfOptionText", IDS_SCANNING_APP_PDF_OPTION_TEXT},
+      {"pngOptionText", IDS_SCANNING_APP_PNG_OPTION_TEXT},
       {"resolutionDropdownLabel", IDS_SCANNING_APP_RESOLUTION_DROPDOWN_LABEL},
-      {"resolutionOptionText", IDS_SCANNING_APP_RESOLUTION_OPTION_TEXT}};
+      {"resolutionOptionText", IDS_SCANNING_APP_RESOLUTION_OPTION_TEXT},
+      {"scannerDropdownLabel", IDS_SCANNING_APP_SCANNER_DROPDOWN_LABEL},
+      {"sourceDropdownLabel", IDS_SCANNING_APP_SOURCE_DROPDOWN_LABEL}};
 
   for (const auto& str : kLocalizedStrings)
     html_source->AddLocalizedString(str.name, str.id);
diff --git a/chromeos/constants/chromeos_features.cc b/chromeos/constants/chromeos_features.cc
index 33c8cbe..cc94f49 100644
--- a/chromeos/constants/chromeos_features.cc
+++ b/chromeos/constants/chromeos_features.cc
@@ -327,7 +327,7 @@
 
 // Controls whether to launch IME service with an 'ime' sandbox.
 const base::Feature kEnableImeSandbox{"EnableImeSandbox",
-                                      base::FEATURE_DISABLED_BY_DEFAULT};
+                                      base::FEATURE_ENABLED_BY_DEFAULT};
 
 // Enable restriction of symlink traversal on user-supplied filesystems.
 const base::Feature kFsNosymfollow{"FsNosymfollow",
@@ -374,6 +374,10 @@
 const base::Feature kImeInputLogicMozc{"ImeInputLogicMozc",
                                        base::FEATURE_DISABLED_BY_DEFAULT};
 
+// Enable or disable IME decoder via Mojo connection on Chrome OS.
+const base::Feature kImeMojoDecoder{"ImeMojoDecoder",
+                                    base::FEATURE_DISABLED_BY_DEFAULT};
+
 // Enables view-based version of multiprofile login, as opposed to Web UI one.
 const base::Feature kViewBasedMultiprofileLogin{
     "ViewBasedMultiprofileLogin", base::FEATURE_DISABLED_BY_DEFAULT};
diff --git a/chromeos/constants/chromeos_features.h b/chromeos/constants/chromeos_features.h
index 1828ca8..9ad2e9f 100644
--- a/chromeos/constants/chromeos_features.h
+++ b/chromeos/constants/chromeos_features.h
@@ -172,6 +172,8 @@
 COMPONENT_EXPORT(CHROMEOS_CONSTANTS)
 extern const base::Feature kImeInputLogicMozc;
 COMPONENT_EXPORT(CHROMEOS_CONSTANTS)
+extern const base::Feature kImeMojoDecoder;
+COMPONENT_EXPORT(CHROMEOS_CONSTANTS)
 extern const base::Feature kImeOptionsInSettings;
 COMPONENT_EXPORT(CHROMEOS_CONSTANTS)
 extern const base::Feature kVirtualKeyboardFloatingDefault;
diff --git a/chromeos/dbus/permission_broker/fake_permission_broker_client.cc b/chromeos/dbus/permission_broker/fake_permission_broker_client.cc
index 4ac93c06..a916321 100644
--- a/chromeos/dbus/permission_broker/fake_permission_broker_client.cc
+++ b/chromeos/dbus/permission_broker/fake_permission_broker_client.cc
@@ -93,6 +93,15 @@
   OpenPath(path, std::move(callback), std::move(error_callback));
 }
 
+void FakePermissionBrokerClient::ClaimDevicePath(
+    const std::string& path,
+    uint32_t allowed_interfaces_mask,
+    int lifeline_fd,
+    OpenPathCallback callback,
+    ErrorCallback error_callback) {
+  OpenPath(path, std::move(callback), std::move(error_callback));
+}
+
 void FakePermissionBrokerClient::RequestTcpPortAccess(
     uint16_t port,
     const std::string& interface,
diff --git a/chromeos/dbus/permission_broker/fake_permission_broker_client.h b/chromeos/dbus/permission_broker/fake_permission_broker_client.h
index 5b1eac6..7662f04a 100644
--- a/chromeos/dbus/permission_broker/fake_permission_broker_client.h
+++ b/chromeos/dbus/permission_broker/fake_permission_broker_client.h
@@ -35,6 +35,11 @@
                                      uint32_t allowed_interfaces_mask,
                                      OpenPathCallback callback,
                                      ErrorCallback error_callback) override;
+  void ClaimDevicePath(const std::string& path,
+                       uint32_t allowed_interfaces_mask,
+                       int lifeline_fd,
+                       OpenPathCallback callback,
+                       ErrorCallback error_callback) override;
   void RequestTcpPortAccess(uint16_t port,
                             const std::string& interface,
                             int lifeline_fd,
diff --git a/chromeos/dbus/permission_broker/permission_broker_client.cc b/chromeos/dbus/permission_broker/permission_broker_client.cc
index b27a60a..69844c39 100644
--- a/chromeos/dbus/permission_broker/permission_broker_client.cc
+++ b/chromeos/dbus/permission_broker/permission_broker_client.cc
@@ -18,6 +18,7 @@
 #include "third_party/cros_system_api/dbus/service_constants.h"
 
 using permission_broker::kCheckPathAccess;
+using permission_broker::kClaimDevicePath;
 using permission_broker::kOpenPath;
 using permission_broker::kOpenPathWithDroppedPrivileges;
 using permission_broker::kPermissionBrokerInterface;
@@ -91,6 +92,25 @@
                        std::move(error_callback)));
   }
 
+  void ClaimDevicePath(const std::string& path,
+                       uint32_t allowed_interfaces_mask,
+                       int lifeline_fd,
+                       OpenPathCallback callback,
+                       ErrorCallback error_callback) override {
+    dbus::MethodCall method_call(kPermissionBrokerInterface, kClaimDevicePath);
+    dbus::MessageWriter writer(&method_call);
+    writer.AppendString(path);
+    writer.AppendUint32(allowed_interfaces_mask);
+    writer.AppendFileDescriptor(lifeline_fd);
+    proxy_->CallMethodWithErrorCallback(
+        &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
+        base::BindOnce(&PermissionBrokerClientImpl::OnOpenPathResponse,
+                       weak_ptr_factory_.GetWeakPtr(), std::move(callback)),
+        base::BindOnce(&PermissionBrokerClientImpl::OnError,
+                       weak_ptr_factory_.GetWeakPtr(),
+                       std::move(error_callback)));
+  }
+
   void RequestTcpPortAccess(uint16_t port,
                             const std::string& interface,
                             int lifeline_fd,
diff --git a/chromeos/dbus/permission_broker/permission_broker_client.h b/chromeos/dbus/permission_broker/permission_broker_client.h
index daacfb17f..9bc1179f 100644
--- a/chromeos/dbus/permission_broker/permission_broker_client.h
+++ b/chromeos/dbus/permission_broker/permission_broker_client.h
@@ -80,6 +80,22 @@
                                              OpenPathCallback callback,
                                              ErrorCallback error_callback) = 0;
 
+  // ClaimDevicePath requests that the permission broker open
+  // the device node identified by |path| and set of USB interfaces that can be
+  // claimed |allowed_interfaces_mask|, returning the resulting file descriptor.
+  // The interface number 0 corresponds to the LSB of |allowed_interfaces_mask|.
+  // For example, a device which has an ADB interface and other interfaces for
+  // Camera or Storage may be opened purely as an ADB device using a mask that
+  // zeros out the Camera and Storage interface number bit positions.
+  // One of |callback| or |error_callback| is called. |lifeline_fd| is the
+  // read side of a pipe that is is watched by permission broker. When this
+  // pipe closes, any kernel drivers removed from the device are reattached.
+  virtual void ClaimDevicePath(const std::string& path,
+                               uint32_t allowed_interfaces_mask,
+                               int lifeline_fd,
+                               OpenPathCallback callback,
+                               ErrorCallback error_callback) = 0;
+
   // Requests the |port| be opened on the firewall for incoming TCP/IP
   // connections received on |interface| (an empty string indicates all
   // interfaces). One end of an open pipe must be passed as |lifeline_fd| so
diff --git a/chromeos/services/ime/constants.cc b/chromeos/services/ime/constants.cc
index a2cc1d2a..1222d3f 100644
--- a/chromeos/services/ime/constants.cc
+++ b/chromeos/services/ime/constants.cc
@@ -4,6 +4,9 @@
 
 #include "chromeos/services/ime/constants.h"
 
+#include <string.h>
+
+#include "base/files/file_util.h"
 #include "build/branding_buildflags.h"
 
 #define FPL FILE_PATH_LITERAL
@@ -25,6 +28,17 @@
 const base::FilePath::CharType kLanguageDataDirName[] =
     FILE_PATH_LITERAL("google");
 const char kCrosImeDecoderLib[] = "libimedecoder.so";
+
+bool ImeDecoderInstalled() {
+  base::FilePath lib_path("/usr");
+#if defined(__x86_64__) || defined(__aarch64__)
+  lib_path = lib_path.Append("lib64");
+#else
+  lib_path = lib_path.Append("lib");
+#endif
+  lib_path = lib_path.Append(kCrosImeDecoderLib);
+  return base::PathExists(lib_path);
+}
 #else
 // IME service does not support third-party IME yet, so the paths below kind
 // of act like a placeholder. In the future, put some well-designed paths here.
@@ -38,6 +52,10 @@
     FILE_PATH_LITERAL("data");
 // IME service does not support third-party IME decoder yet.
 const char kCrosImeDecoderLib[] = "";
+
+bool ImeDecoderInstalled() {
+  return false;
+}
 #endif
 
 const char kGoogleKeyboardDownloadDomain[] = "dl.google.com";
diff --git a/chromeos/services/ime/constants.h b/chromeos/services/ime/constants.h
index 48f29f2..c3da3a6 100644
--- a/chromeos/services/ime/constants.h
+++ b/chromeos/services/ime/constants.h
@@ -48,6 +48,9 @@
 // The name of ChromeOS IME decoder shared Library.
 COMPONENT_EXPORT(CHROMEOS_IME_CONSTANTS)
 extern const char kCrosImeDecoderLib[];
+
+// Whether IME decoder is installed.
+COMPONENT_EXPORT(CHROMEOS_IME_CONSTANTS) bool ImeDecoderInstalled();
 }  // namespace ime
 }  // namespace chromeos
 
diff --git a/chromeos/services/ime/decoder/decoder_engine.cc b/chromeos/services/ime/decoder/decoder_engine.cc
index d627e2f..4980ecc 100644
--- a/chromeos/services/ime/decoder/decoder_engine.cc
+++ b/chromeos/services/ime/decoder/decoder_engine.cc
@@ -74,7 +74,7 @@
     // TODO(b/156897880): Add a fake main entry.
   } else {
     if (!TryLoadDecoder()) {
-      LOG(ERROR) << "DecoderEngine INIT FAILED!";
+      LOG(WARNING) << "DecoderEngine INIT INCOMPLETED.";
     }
   }
 }
@@ -82,6 +82,11 @@
 DecoderEngine::~DecoderEngine() {}
 
 bool DecoderEngine::TryLoadDecoder() {
+  if (!ImeDecoderInstalled()) {
+    LOG(WARNING) << "IME decoder shared library is not installed.";
+    return false;
+  }
+
   if (engine_main_entry_)
     return true;
 
diff --git a/chromeos/services/ime/ime_sandbox_hook.cc b/chromeos/services/ime/ime_sandbox_hook.cc
index 47bd8d3..052948c 100644
--- a/chromeos/services/ime/ime_sandbox_hook.cc
+++ b/chromeos/services/ime/ime_sandbox_hook.cc
@@ -35,8 +35,11 @@
 constexpr int dlopen_flag = RTLD_LAZY | RTLD_NODELETE;
 
 void PreloadSharedLibrary() {
-  if (!dlopen(kCrosImeDecoderLib, dlopen_flag))
-    LOG(ERROR) << "Unable to open " << kCrosImeDecoderLib << " : " << dlerror();
+  if (ImeDecoderInstalled()) {
+    if (!dlopen(kCrosImeDecoderLib, dlopen_flag))
+      LOG(ERROR) << "Unable to open " << kCrosImeDecoderLib << " : "
+                 << dlerror();
+  }
 }
 
 void AddBundleFolder(std::vector<BrokerFilePermission>* permissions) {
diff --git a/chromeos/services/tts/public/mojom/tts_service.mojom b/chromeos/services/tts/public/mojom/tts_service.mojom
index 9b7be4c..927fbde3 100644
--- a/chromeos/services/tts/public/mojom/tts_service.mojom
+++ b/chromeos/services/tts/public/mojom/tts_service.mojom
@@ -58,6 +58,12 @@
 
   // Sets the volume of the tts playback (0.0 to 1.0).
   SetVolume(float volume);
+
+  // Pauses tts playback. Safe to call repeatedly (no-op for subsequent calls).
+  Pause();
+
+  // Resumes tts playback. Safe to call repeatedly (no-op for subsequent calls).
+  Resume();
 };
 
 // Returned to callers of TtsStream.speak(). It receives notable events
diff --git a/chromeos/services/tts/tts_service.cc b/chromeos/services/tts/tts_service.cc
index b0af110..3143563 100644
--- a/chromeos/services/tts/tts_service.cc
+++ b/chromeos/services/tts/tts_service.cc
@@ -139,6 +139,15 @@
   output_device_->SetVolume(volume);
 }
 
+void TtsService::Pause() {
+  base::AutoLock al(state_lock_);
+  StopLocked(false /* clear_buffers */);
+}
+
+void TtsService::Resume() {
+  output_device_->Play();
+}
+
 int TtsService::Render(base::TimeDelta delay,
                        base::TimeTicks delay_timestamp,
                        int prior_frames_skipped,
@@ -191,12 +200,14 @@
 
 void TtsService::OnRenderError() {}
 
-void TtsService::StopLocked() {
+void TtsService::StopLocked(bool clear_buffers) {
   if (!is_playing_)
     return;
 
   output_device_->Pause();
-  buffers_.clear();
+  if (clear_buffers)
+    buffers_.clear();
+
   is_playing_ = false;
 }
 
diff --git a/chromeos/services/tts/tts_service.h b/chromeos/services/tts/tts_service.h
index 061937b..3eb7682 100644
--- a/chromeos/services/tts/tts_service.h
+++ b/chromeos/services/tts/tts_service.h
@@ -43,6 +43,8 @@
              SpeakCallback callback) override;
   void Stop() override;
   void SetVolume(float volume) override;
+  void Pause() override;
+  void Resume() override;
 
   // media::AudioRendererSink::RenderCallback:
   int Render(base::TimeDelta delay,
@@ -52,7 +54,8 @@
   void OnRenderError() override;
 
   // Handles stopping tts.
-  void StopLocked() EXCLUSIVE_LOCKS_REQUIRED(state_lock_);
+  void StopLocked(bool clear_buffers = true)
+      EXCLUSIVE_LOCKS_REQUIRED(state_lock_);
 
   void ReadMoreFrames(bool is_first_buffer);
 
diff --git a/components/arc/arc_prefs.cc b/components/arc/arc_prefs.cc
index fb66e9f..6d624f80 100644
--- a/components/arc/arc_prefs.cc
+++ b/components/arc/arc_prefs.cc
@@ -129,12 +129,16 @@
 // Android properties. Used only in ARCVM.
 const char kArcSerialNumberSalt[] = "arc.serialno_salt";
 
+// A preference to keep time intervals when snapshotting is allowed.
+const char kArcSnapshotHours[] = "arc.snapshot_hours";
+
 // A preferece to keep ARC snapshot related info in dictionary.
 const char kArcSnapshotInfo[] = "arc.snapshot";
 
 void RegisterLocalStatePrefs(PrefRegistrySimple* registry) {
   // Sorted in lexicographical order.
   registry->RegisterStringPref(kArcSerialNumberSalt, std::string());
+  registry->RegisterDictionaryPref(kArcSnapshotHours);
   registry->RegisterDictionaryPref(kArcSnapshotInfo);
   registry->RegisterBooleanPref(kNativeBridge64BitSupportExperimentEnabled,
                                 false);
diff --git a/components/arc/arc_prefs.h b/components/arc/arc_prefs.h
index b3f5cc66..9d496f0 100644
--- a/components/arc/arc_prefs.h
+++ b/components/arc/arc_prefs.h
@@ -45,6 +45,7 @@
 
 // Local state prefs in lexicographical order.
 ARC_EXPORT extern const char kArcSerialNumberSalt[];
+ARC_EXPORT extern const char kArcSnapshotHours[];
 ARC_EXPORT extern const char kArcSnapshotInfo[];
 ARC_EXPORT extern const char kNativeBridge64BitSupportExperimentEnabled[];
 ARC_EXPORT extern const char kStabilityMetrics[];
diff --git a/components/arc/mojom/file_system.mojom b/components/arc/mojom/file_system.mojom
index 7a74c610..79f7525 100644
--- a/components/arc/mojom/file_system.mojom
+++ b/components/arc/mojom/file_system.mojom
@@ -167,6 +167,10 @@
 
   // Android task ID of the request sender.
   int32 task_id;
+
+  // Search query to run when the file selector is launched.
+  // Corresponds to Intent.EXTRA_CONTENT_QUERY.
+  string? search_query;
 };
 
 // Represents a path to a document served by a DocumentsProvider.
@@ -234,6 +238,9 @@
 
   // List of files in the right pane.
   array<FileSelectorElement> file_elements;
+
+  // Query text filled in the search box.
+  string? search_query;
 };
 
 // Next method ID: 9
diff --git a/components/autofill_assistant/browser/element_area.cc b/components/autofill_assistant/browser/element_area.cc
index 0b513492..37c17533 100644
--- a/components/autofill_assistant/browser/element_area.cc
+++ b/components/autofill_assistant/browser/element_area.cc
@@ -128,9 +128,9 @@
 
   for (auto& rectangle : rectangles_) {
     for (auto& position : rectangle.positions) {
-      delegate_->GetWebController()->GetElementPosition(
+      delegate_->GetWebController()->GetElementRect(
           position.selector,
-          base::BindOnce(&ElementArea::OnGetElementPosition,
+          base::BindOnce(&ElementArea::OnGetElementRect,
                          weak_ptr_factory_.GetWeakPtr(), position.selector));
     }
   }
@@ -205,10 +205,10 @@
   return;
 }
 
-void ElementArea::OnGetElementPosition(const Selector& selector,
-                                       bool found,
-                                       const RectF& rect) {
-  // found == false, has all coordinates set to 0.0, which clears the area.
+void ElementArea::OnGetElementRect(const Selector& selector,
+                                   const ClientStatus& rect_status,
+                                   const RectF& rect) {
+  // !rect_status.ok() has all coordinates set to 0.0, which clears the area.
   bool updated = false;
   for (auto& rectangle : rectangles_) {
     for (auto& position : rectangle.positions) {
@@ -227,12 +227,13 @@
   // rectangles_. This is fine.
 }
 
-void ElementArea::OnGetVisualViewport(bool success, const RectF& rect) {
+void ElementArea::OnGetVisualViewport(const ClientStatus& rect_status,
+                                      const RectF& rect) {
   if (!visual_viewport_pending_update_)
     return;
 
   visual_viewport_pending_update_ = false;
-  if (!success)
+  if (!rect_status.ok())
     return;
 
   visual_viewport_ = rect;
diff --git a/components/autofill_assistant/browser/element_area.h b/components/autofill_assistant/browser/element_area.h
index 4ff578e..01c78e1 100644
--- a/components/autofill_assistant/browser/element_area.h
+++ b/components/autofill_assistant/browser/element_area.h
@@ -121,10 +121,10 @@
   void AddRectangles(const ::google::protobuf::RepeatedPtrField<
                          ElementAreaProto::Rectangle>& rectangles_proto,
                      bool restricted);
-  void OnGetElementPosition(const Selector& selector,
-                            bool found,
-                            const RectF& rect);
-  void OnGetVisualViewport(bool success, const RectF& rect);
+  void OnGetElementRect(const Selector& selector,
+                        const ClientStatus& rect_status,
+                        const RectF& rect);
+  void OnGetVisualViewport(const ClientStatus& status, const RectF& rect);
   void ReportUpdate();
 
   ScriptExecutorDelegate* const delegate_;
diff --git a/components/autofill_assistant/browser/element_area_unittest.cc b/components/autofill_assistant/browser/element_area_unittest.cc
index 3ccde28..0646ab2 100644
--- a/components/autofill_assistant/browser/element_area_unittest.cc
+++ b/components/autofill_assistant/browser/element_area_unittest.cc
@@ -70,10 +70,12 @@
     delegate_.GetMutableSettings()->element_position_update_interval =
         base::TimeDelta::FromMilliseconds(100);
 
-    ON_CALL(mock_web_controller_, OnGetElementPosition(_, _))
-        .WillByDefault(RunOnceCallback<1>(false, RectF()));
+    ON_CALL(mock_web_controller_, OnGetElementRect(_, _))
+        .WillByDefault(
+            RunOnceCallback<1>(ClientStatus(UNEXPECTED_JS_ERROR), RectF()));
     ON_CALL(mock_web_controller_, OnGetVisualViewport(_))
-        .WillByDefault(RunOnceCallback<0>(true, RectF(0, 0, 200, 400)));
+        .WillByDefault(
+            RunOnceCallback<0>(OkClientStatus(), RectF(0, 0, 200, 400)));
 
     element_area_.SetOnUpdate(base::BindRepeating(&ElementAreaTest::OnUpdate,
                                                   base::Unretained(this)));
@@ -144,8 +146,8 @@
 
 TEST_F(ElementAreaTest, OneRectangle) {
   EXPECT_CALL(mock_web_controller_,
-              OnGetElementPosition(Eq(Selector({"#found"}).MustBeVisible()), _))
-      .WillOnce(RunOnceCallback<1>(true, RectF(25, 25, 75, 75)));
+              OnGetElementRect(Eq(Selector({"#found"}).MustBeVisible()), _))
+      .WillOnce(RunOnceCallback<1>(OkClientStatus(), RectF(25, 25, 75, 75)));
 
   SetElement("#found");
   std::vector<RectF> rectangles;
@@ -155,8 +157,8 @@
 
 TEST_F(ElementAreaTest, CallOnUpdate) {
   EXPECT_CALL(mock_web_controller_,
-              OnGetElementPosition(Eq(Selector({"#found"}).MustBeVisible()), _))
-      .WillOnce(RunOnceCallback<1>(true, RectF(25, 25, 75, 75)));
+              OnGetElementRect(Eq(Selector({"#found"}).MustBeVisible()), _))
+      .WillOnce(RunOnceCallback<1>(OkClientStatus(), RectF(25, 25, 75, 75)));
 
   SetElement("#found");
   EXPECT_EQ(on_update_call_count_, 1);
@@ -166,8 +168,9 @@
 
 TEST_F(ElementAreaTest, CallOnUpdateAfterSetFromProto) {
   EXPECT_CALL(mock_web_controller_,
-              OnGetElementPosition(Eq(Selector({"#found"}).MustBeVisible()), _))
-      .WillRepeatedly(RunOnceCallback<1>(true, RectF(25, 25, 75, 75)));
+              OnGetElementRect(Eq(Selector({"#found"}).MustBeVisible()), _))
+      .WillRepeatedly(
+          RunOnceCallback<1>(OkClientStatus(), RectF(25, 25, 75, 75)));
 
   SetElement("#found");
   EXPECT_EQ(on_update_call_count_, 1);
@@ -181,8 +184,8 @@
   EXPECT_CALL(mock_web_controller_, OnGetVisualViewport(_))
       .WillOnce(DoNothing());
   EXPECT_CALL(mock_web_controller_,
-              OnGetElementPosition(Eq(Selector({"#found"}).MustBeVisible()), _))
-      .WillOnce(RunOnceCallback<1>(true, RectF(25, 25, 75, 75)));
+              OnGetElementRect(Eq(Selector({"#found"}).MustBeVisible()), _))
+      .WillOnce(RunOnceCallback<1>(OkClientStatus(), RectF(25, 25, 75, 75)));
 
   SetElement("#found");
   EXPECT_EQ(on_update_call_count_, 0);
@@ -190,7 +193,8 @@
 
 TEST_F(ElementAreaTest, CallOnUpdateWhenViewportMissingAndEmptyRect) {
   EXPECT_CALL(mock_web_controller_, OnGetVisualViewport(_))
-      .WillRepeatedly(RunOnceCallback<0>(false, RectF()));
+      .WillRepeatedly(
+          RunOnceCallback<0>(ClientStatus(UNEXPECTED_JS_ERROR), RectF()));
 
   SetElement("#found");
 
@@ -204,14 +208,13 @@
 }
 
 TEST_F(ElementAreaTest, TwoRectangles) {
+  EXPECT_CALL(mock_web_controller_,
+              OnGetElementRect(Eq(Selector({"#top_left"}).MustBeVisible()), _))
+      .WillOnce(RunOnceCallback<1>(OkClientStatus(), RectF(0, 0, 25, 25)));
   EXPECT_CALL(
       mock_web_controller_,
-      OnGetElementPosition(Eq(Selector({"#top_left"}).MustBeVisible()), _))
-      .WillOnce(RunOnceCallback<1>(true, RectF(0, 0, 25, 25)));
-  EXPECT_CALL(
-      mock_web_controller_,
-      OnGetElementPosition(Eq(Selector({"#bottom_right"}).MustBeVisible()), _))
-      .WillOnce(RunOnceCallback<1>(true, RectF(25, 25, 100, 100)));
+      OnGetElementRect(Eq(Selector({"#bottom_right"}).MustBeVisible()), _))
+      .WillOnce(RunOnceCallback<1>(OkClientStatus(), RectF(25, 25, 100, 100)));
 
   ElementAreaProto area_proto;
   *area_proto.add_touchable()->add_elements() = ToSelectorProto("#top_left");
@@ -226,14 +229,12 @@
 }
 
 TEST_F(ElementAreaTest, OneRectangleTwoElements) {
-  EXPECT_CALL(
-      mock_web_controller_,
-      OnGetElementPosition(Eq(Selector({"#element1"}).MustBeVisible()), _))
-      .WillOnce(RunOnceCallback<1>(true, RectF(1, 3, 2, 4)));
-  EXPECT_CALL(
-      mock_web_controller_,
-      OnGetElementPosition(Eq(Selector({"#element2"}).MustBeVisible()), _))
-      .WillOnce(RunOnceCallback<1>(true, RectF(5, 2, 6, 5)));
+  EXPECT_CALL(mock_web_controller_,
+              OnGetElementRect(Eq(Selector({"#element1"}).MustBeVisible()), _))
+      .WillOnce(RunOnceCallback<1>(OkClientStatus(), RectF(1, 3, 2, 4)));
+  EXPECT_CALL(mock_web_controller_,
+              OnGetElementRect(Eq(Selector({"#element2"}).MustBeVisible()), _))
+      .WillOnce(RunOnceCallback<1>(OkClientStatus(), RectF(5, 2, 6, 5)));
 
   ElementAreaProto area_proto;
   auto* rectangle_proto = area_proto.add_touchable();
@@ -247,16 +248,14 @@
 }
 
 TEST_F(ElementAreaTest, DoNotReportIncompleteRectangles) {
-  EXPECT_CALL(
-      mock_web_controller_,
-      OnGetElementPosition(Eq(Selector({"#element1"}).MustBeVisible()), _))
-      .WillOnce(RunOnceCallback<1>(true, RectF(1, 3, 2, 4)));
+  EXPECT_CALL(mock_web_controller_,
+              OnGetElementRect(Eq(Selector({"#element1"}).MustBeVisible()), _))
+      .WillOnce(RunOnceCallback<1>(OkClientStatus(), RectF(1, 3, 2, 4)));
 
   // Getting the position of #element2 neither succeeds nor fails, simulating an
   // intermediate state which shouldn't be reported to the callback.
-  EXPECT_CALL(
-      mock_web_controller_,
-      OnGetElementPosition(Eq(Selector({"#element2"}).MustBeVisible()), _))
+  EXPECT_CALL(mock_web_controller_,
+              OnGetElementRect(Eq(Selector({"#element2"}).MustBeVisible()), _))
       .WillOnce(DoNothing());  // overrides default action
 
   ElementAreaProto area_proto;
@@ -273,22 +272,18 @@
 }
 
 TEST_F(ElementAreaTest, OneRectangleFourElements) {
-  EXPECT_CALL(
-      mock_web_controller_,
-      OnGetElementPosition(Eq(Selector({"#element1"}).MustBeVisible()), _))
-      .WillOnce(RunOnceCallback<1>(true, RectF(0, 0, 1, 1)));
-  EXPECT_CALL(
-      mock_web_controller_,
-      OnGetElementPosition(Eq(Selector({"#element2"}).MustBeVisible()), _))
-      .WillOnce(RunOnceCallback<1>(true, RectF(9, 9, 100, 100)));
-  EXPECT_CALL(
-      mock_web_controller_,
-      OnGetElementPosition(Eq(Selector({"#element3"}).MustBeVisible()), _))
-      .WillOnce(RunOnceCallback<1>(true, RectF(0, 9, 1, 100)));
-  EXPECT_CALL(
-      mock_web_controller_,
-      OnGetElementPosition(Eq(Selector({"#element4"}).MustBeVisible()), _))
-      .WillOnce(RunOnceCallback<1>(true, RectF(9, 0, 100, 1)));
+  EXPECT_CALL(mock_web_controller_,
+              OnGetElementRect(Eq(Selector({"#element1"}).MustBeVisible()), _))
+      .WillOnce(RunOnceCallback<1>(OkClientStatus(), RectF(0, 0, 1, 1)));
+  EXPECT_CALL(mock_web_controller_,
+              OnGetElementRect(Eq(Selector({"#element2"}).MustBeVisible()), _))
+      .WillOnce(RunOnceCallback<1>(OkClientStatus(), RectF(9, 9, 100, 100)));
+  EXPECT_CALL(mock_web_controller_,
+              OnGetElementRect(Eq(Selector({"#element3"}).MustBeVisible()), _))
+      .WillOnce(RunOnceCallback<1>(OkClientStatus(), RectF(0, 9, 1, 100)));
+  EXPECT_CALL(mock_web_controller_,
+              OnGetElementRect(Eq(Selector({"#element4"}).MustBeVisible()), _))
+      .WillOnce(RunOnceCallback<1>(OkClientStatus(), RectF(9, 0, 100, 1)));
 
   ElementAreaProto area_proto;
   auto* rectangle_proto = area_proto.add_touchable();
@@ -304,14 +299,12 @@
 }
 
 TEST_F(ElementAreaTest, OneRectangleMissingElementsReported) {
-  EXPECT_CALL(
-      mock_web_controller_,
-      OnGetElementPosition(Eq(Selector({"#element1"}).MustBeVisible()), _))
-      .WillOnce(RunOnceCallback<1>(true, RectF(1, 1, 2, 2)));
-  EXPECT_CALL(
-      mock_web_controller_,
-      OnGetElementPosition(Eq(Selector({"#element2"}).MustBeVisible()), _))
-      .WillOnce(RunOnceCallback<1>(false, RectF()));
+  EXPECT_CALL(mock_web_controller_,
+              OnGetElementRect(Eq(Selector({"#element1"}).MustBeVisible()), _))
+      .WillOnce(RunOnceCallback<1>(OkClientStatus(), RectF(1, 1, 2, 2)));
+  EXPECT_CALL(mock_web_controller_,
+              OnGetElementRect(Eq(Selector({"#element2"}).MustBeVisible()), _))
+      .WillOnce(RunOnceCallback<1>(ClientStatus(UNEXPECTED_JS_ERROR), RectF()));
 
   ElementAreaProto area_proto;
   auto* rectangle_proto = area_proto.add_touchable();
@@ -327,16 +320,15 @@
 }
 
 TEST_F(ElementAreaTest, FullWidthRectangle) {
-  EXPECT_CALL(
-      mock_web_controller_,
-      OnGetElementPosition(Eq(Selector({"#element1"}).MustBeVisible()), _))
-      .WillOnce(RunOnceCallback<1>(true, RectF(1, 3, 2, 4)));
-  EXPECT_CALL(
-      mock_web_controller_,
-      OnGetElementPosition(Eq(Selector({"#element2"}).MustBeVisible()), _))
-      .WillOnce(RunOnceCallback<1>(true, RectF(5, 7, 6, 8)));
+  EXPECT_CALL(mock_web_controller_,
+              OnGetElementRect(Eq(Selector({"#element1"}).MustBeVisible()), _))
+      .WillOnce(RunOnceCallback<1>(OkClientStatus(), RectF(1, 3, 2, 4)));
+  EXPECT_CALL(mock_web_controller_,
+              OnGetElementRect(Eq(Selector({"#element2"}).MustBeVisible()), _))
+      .WillOnce(RunOnceCallback<1>(OkClientStatus(), RectF(5, 7, 6, 8)));
   EXPECT_CALL(mock_web_controller_, OnGetVisualViewport(_))
-      .WillRepeatedly(RunOnceCallback<0>(true, RectF(100, 0, 200, 400)));
+      .WillRepeatedly(
+          RunOnceCallback<0>(OkClientStatus(), RectF(100, 0, 200, 400)));
 
   ElementAreaProto area_proto;
   auto* rectangle_proto = area_proto.add_touchable();
@@ -355,11 +347,10 @@
 
 TEST_F(ElementAreaTest, ElementMovesAfterUpdate) {
   testing::InSequence seq;
-  EXPECT_CALL(
-      mock_web_controller_,
-      OnGetElementPosition(Eq(Selector({"#element"}).MustBeVisible()), _))
-      .WillOnce(RunOnceCallback<1>(true, RectF(0, 25, 100, 50)))
-      .WillOnce(RunOnceCallback<1>(true, RectF(0, 50, 100, 75)));
+  EXPECT_CALL(mock_web_controller_,
+              OnGetElementRect(Eq(Selector({"#element"}).MustBeVisible()), _))
+      .WillOnce(RunOnceCallback<1>(OkClientStatus(), RectF(0, 25, 100, 50)))
+      .WillOnce(RunOnceCallback<1>(OkClientStatus(), RectF(0, 50, 100, 75)));
 
   SetElement("#element");
 
@@ -381,11 +372,11 @@
 
 TEST_F(ElementAreaTest, ElementMovesWithTime) {
   testing::InSequence seq;
-  EXPECT_CALL(
-      mock_web_controller_,
-      OnGetElementPosition(Eq(Selector({"#element"}).MustBeVisible()), _))
-      .WillOnce(RunOnceCallback<1>(true, RectF(0, 25, 100, 50)))
-      .WillRepeatedly(RunOnceCallback<1>(true, RectF(0, 50, 100, 75)));
+  EXPECT_CALL(mock_web_controller_,
+              OnGetElementRect(Eq(Selector({"#element"}).MustBeVisible()), _))
+      .WillOnce(RunOnceCallback<1>(OkClientStatus(), RectF(0, 25, 100, 50)))
+      .WillRepeatedly(
+          RunOnceCallback<1>(OkClientStatus(), RectF(0, 50, 100, 75)));
 
   SetElement("#element");
 
@@ -409,9 +400,9 @@
 
 TEST_F(ElementAreaTest, RestrictedElement) {
   EXPECT_CALL(mock_web_controller_,
-              OnGetElementPosition(
+              OnGetElementRect(
                   Eq(Selector({"#restricted_element"}).MustBeVisible()), _))
-      .WillOnce(RunOnceCallback<1>(true, RectF(25, 25, 75, 75)));
+      .WillOnce(RunOnceCallback<1>(OkClientStatus(), RectF(25, 25, 75, 75)));
 
   SetElement("#restricted_element", /* restricted= */ true);
 
diff --git a/components/autofill_assistant/browser/web/element_rect_getter.cc b/components/autofill_assistant/browser/web/element_rect_getter.cc
index e9154125..155ff658a 100644
--- a/components/autofill_assistant/browser/web/element_rect_getter.cc
+++ b/components/autofill_assistant/browser/web/element_rect_getter.cc
@@ -86,7 +86,9 @@
       !result->GetResult()->GetValue()->is_list() ||
       result->GetResult()->GetValue()->GetList().size() != 4u) {
     VLOG(2) << __func__ << " Failed to get element rect: " << status;
-    std::move(callback).Run(false, RectF());
+    std::move(callback).Run(
+        JavaScriptErrorStatus(reply_status, __FILE__, __LINE__, nullptr),
+        RectF());
     return;
   }
 
@@ -108,11 +110,12 @@
   }
 
   if (index >= element->frame_stack.size()) {
-    std::move(callback).Run(true, rect);
-  } else {
-    GetBoundingClientRect(std::move(element), index + 1, rect,
-                          std::move(callback));
+    std::move(callback).Run(OkClientStatus(), rect);
+    return;
   }
+
+  GetBoundingClientRect(std::move(element), index + 1, rect,
+                        std::move(callback));
 }
 
 }  // namespace autofill_assistant
diff --git a/components/autofill_assistant/browser/web/element_rect_getter.h b/components/autofill_assistant/browser/web/element_rect_getter.h
index 6a8ba05..f38b763 100644
--- a/components/autofill_assistant/browser/web/element_rect_getter.h
+++ b/components/autofill_assistant/browser/web/element_rect_getter.h
@@ -37,9 +37,12 @@
 
   // Callback that receives the bounding rect of the element.
   //
-  // If the first element is false, the call failed. Otherwise, the second
-  // element contains the rect.
-  using ElementRectCallback = base::OnceCallback<void(bool, const RectF&)>;
+  // If the first argument is a failure status, the call failed and will
+  // send an empty rectangle as the second argument. Otherwise, if the first
+  // argument is a success status the second argumnt will contain the element's
+  // bounding box in global CSS coordinates.
+  using ElementRectCallback =
+      base::OnceCallback<void(const ClientStatus&, const RectF&)>;
 
   void Start(std::unique_ptr<ElementFinder::Result> element,
              ElementRectCallback callback);
diff --git a/components/autofill_assistant/browser/web/mock_web_controller.h b/components/autofill_assistant/browser/web/mock_web_controller.h
index 0be7e9c5..35b3b7e3 100644
--- a/components/autofill_assistant/browser/web/mock_web_controller.h
+++ b/components/autofill_assistant/browser/web/mock_web_controller.h
@@ -11,6 +11,7 @@
 #include "base/callback.h"
 #include "components/autofill_assistant/browser/top_padding.h"
 #include "components/autofill_assistant/browser/web/element_finder.h"
+#include "components/autofill_assistant/browser/web/element_rect_getter.h"
 #include "components/autofill_assistant/browser/web/web_controller.h"
 #include "testing/gmock/include/gmock/gmock.h"
 
@@ -91,20 +92,22 @@
                                             const std::string&)>& callback));
 
   void GetVisualViewport(
-      base::OnceCallback<void(bool, const RectF&)> callback) override {
+      base::OnceCallback<void(const ClientStatus&, const RectF&)> callback)
+      override {
     OnGetVisualViewport(callback);
   }
   MOCK_METHOD1(OnGetVisualViewport,
-               void(base::OnceCallback<void(bool, const RectF&)>& callback));
+               void(base::OnceCallback<void(const ClientStatus&, const RectF&)>&
+                        callback));
 
-  void GetElementPosition(
+  void GetElementRect(
       const Selector& selector,
-      base::OnceCallback<void(bool, const RectF&)> callback) override {
-    OnGetElementPosition(selector, callback);
+      ElementRectGetter::ElementRectCallback callback) override {
+    OnGetElementRect(selector, callback);
   }
-  MOCK_METHOD2(OnGetElementPosition,
+  MOCK_METHOD2(OnGetElementRect,
                void(const Selector& selector,
-                    base::OnceCallback<void(bool, const RectF&)>& callback));
+                    ElementRectGetter::ElementRectCallback& callback));
 
   void WaitForWindowHeightChange(
       base::OnceCallback<void(const ClientStatus&)> callback) {
diff --git a/components/autofill_assistant/browser/web/web_controller.cc b/components/autofill_assistant/browser/web/web_controller.cc
index 53b55045..f6e357d 100644
--- a/components/autofill_assistant/browser/web/web_controller.cc
+++ b/components/autofill_assistant/browser/web/web_controller.cc
@@ -1144,7 +1144,7 @@
 }
 
 void WebController::GetVisualViewport(
-    base::OnceCallback<void(bool, const RectF&)> callback) {
+    base::OnceCallback<void(const ClientStatus&, const RectF&)> callback) {
   devtools_client_->GetRuntime()->Evaluate(
       runtime::EvaluateParams::Builder()
           .SetExpression(std::string(kGetVisualViewport))
@@ -1156,7 +1156,7 @@
 }
 
 void WebController::OnGetVisualViewport(
-    base::OnceCallback<void(bool, const RectF&)> callback,
+    base::OnceCallback<void(const ClientStatus&, const RectF&)> callback,
     const DevtoolsClient::ReplyStatus& reply_status,
     std::unique_ptr<runtime::EvaluateResult> result) {
   ClientStatus status =
@@ -1165,8 +1165,9 @@
       !result->GetResult()->GetValue()->is_list() ||
       result->GetResult()->GetValue()->GetList().size() != 4u) {
     VLOG(1) << __func__ << " Failed to get visual viewport: " << status;
-    RectF empty;
-    std::move(callback).Run(false, empty);
+    std::move(callback).Run(
+        JavaScriptErrorStatus(reply_status, __FILE__, __LINE__, nullptr),
+        RectF());
     return;
   }
   const auto& list = result->GetResult()->GetValue()->GetList();
@@ -1184,25 +1185,24 @@
   rect.right = left + width;
   rect.bottom = top + height;
 
-  std::move(callback).Run(true, rect);
+  std::move(callback).Run(OkClientStatus(), rect);
 }
 
-void WebController::GetElementPosition(
+void WebController::GetElementRect(
     const Selector& selector,
-    base::OnceCallback<void(bool, const RectF&)> callback) {
+    ElementRectGetter::ElementRectCallback callback) {
   FindElement(
       selector, /* strict_mode= */ true,
-      base::BindOnce(&WebController::OnFindElementForPosition,
+      base::BindOnce(&WebController::OnFindElementForRect,
                      weak_ptr_factory_.GetWeakPtr(), std::move(callback)));
 }
 
-void WebController::OnFindElementForPosition(
-    base::OnceCallback<void(bool, const RectF&)> callback,
-    const ClientStatus& status,
-    std::unique_ptr<ElementFinder::Result> result) {
-  if (!status.ok()) {
-    RectF empty;
-    std::move(callback).Run(false, empty);
+void WebController::OnFindElementForRect(
+    ElementRectGetter::ElementRectCallback callback,
+    const ClientStatus& element_status,
+    std::unique_ptr<ElementFinder::Result> element_result) {
+  if (!element_status.ok()) {
+    std::move(callback).Run(element_status, RectF());
     return;
   }
   std::unique_ptr<ElementRectGetter> getter =
@@ -1210,20 +1210,20 @@
   auto* ptr = getter.get();
   pending_workers_.emplace_back(std::move(getter));
   ptr->Start(
-      std::move(result),
-      base::BindOnce(&WebController::OnGetElementRectResult,
+      std::move(element_result),
+      base::BindOnce(&WebController::OnGetElementRect,
                      weak_ptr_factory_.GetWeakPtr(), ptr, std::move(callback)));
 }
 
-void WebController::OnGetElementRectResult(
+void WebController::OnGetElementRect(
     ElementRectGetter* getter_to_release,
-    base::OnceCallback<void(bool, const RectF&)> callback,
-    bool has_rect,
+    ElementRectGetter::ElementRectCallback callback,
+    const ClientStatus& rect_status,
     const RectF& element_rect) {
   base::EraseIf(pending_workers_, [getter_to_release](const auto& worker) {
     return worker.get() == getter_to_release;
   });
-  std::move(callback).Run(has_rect, element_rect);
+  std::move(callback).Run(rect_status, element_rect);
 }
 
 void WebController::GetOuterHtml(
diff --git a/components/autofill_assistant/browser/web/web_controller.h b/components/autofill_assistant/browser/web/web_controller.h
index 0bec6fd9..9195413a 100644
--- a/components/autofill_assistant/browser/web/web_controller.h
+++ b/components/autofill_assistant/browser/web/web_controller.h
@@ -206,17 +206,17 @@
   //
   // The rectangle is expressed in absolute CSS coordinates.
   virtual void GetVisualViewport(
-      base::OnceCallback<void(bool, const RectF&)> callback);
+      base::OnceCallback<void(const ClientStatus&, const RectF&)> callback);
 
   // Gets the position of the element identified by the selector.
   //
-  // If unsuccessful, the callback gets (false, 0, 0, 0, 0).
+  // If unsuccessful, the callback gets the failure status with an empty rect.
   //
-  // If successful, the callback gets (true, left, top, right, bottom), with
-  // coordinates expressed in absolute CSS coordinates.
-  virtual void GetElementPosition(
-      const Selector& selector,
-      base::OnceCallback<void(bool, const RectF&)> callback);
+  // If successful, the callback gets a success status with a set of
+  // (left, top, right, bottom) coordinates rect, expressed in absolute CSS
+  // coordinates.
+  virtual void GetElementRect(const Selector& selector,
+                              ElementRectGetter::ElementRectCallback callback);
 
   // Checks whether an element matches the given selector.
   //
@@ -336,7 +336,6 @@
       base::OnceCallback<void(const ClientStatus&)> callback,
       const DevtoolsClient::ReplyStatus& reply_status,
       std::unique_ptr<runtime::EvaluateResult> result);
-
   void OnFindElementResult(ElementFinder* finder_to_release,
                            ElementFinder::Callback callback,
                            const ClientStatus& status,
@@ -389,19 +388,17 @@
       size_t index,
       int delay_in_milli,
       base::OnceCallback<void(const ClientStatus&)> callback);
-  void OnFindElementForPosition(
-      base::OnceCallback<void(bool, const RectF&)> callback,
-      const ClientStatus& status,
-      std::unique_ptr<ElementFinder::Result> result);
+  void OnFindElementForRect(ElementRectGetter::ElementRectCallback callback,
+                            const ClientStatus& status,
+                            std::unique_ptr<ElementFinder::Result> result);
+  void OnGetElementRect(ElementRectGetter* getter_to_release,
+                        ElementRectGetter::ElementRectCallback callback,
+                        const ClientStatus& rect_status,
+                        const RectF& element_rect);
   void OnGetVisualViewport(
-      base::OnceCallback<void(bool, const RectF&)> callback,
+      base::OnceCallback<void(const ClientStatus&, const RectF&)> callback,
       const DevtoolsClient::ReplyStatus& reply_status,
       std::unique_ptr<runtime::EvaluateResult> result);
-  void OnGetElementRectResult(
-      ElementRectGetter* getter_to_release,
-      base::OnceCallback<void(bool, const RectF&)> callback,
-      bool has_rect,
-      const RectF& element_rect);
 
   // Creates a new instance of DispatchKeyEventParams for the specified type and
   // unicode codepoint.
diff --git a/components/autofill_assistant/browser/web/web_controller_browsertest.cc b/components/autofill_assistant/browser/web/web_controller_browsertest.cc
index 97f3720f..360b8dbc 100644
--- a/components/autofill_assistant/browser/web/web_controller_browsertest.cc
+++ b/components/autofill_assistant/browser/web/web_controller_browsertest.cc
@@ -745,27 +745,26 @@
                        std::move(done_callback), result_output));
   }
 
-  bool GetElementPosition(const Selector& selector, RectF* rect_output) {
+  ClientStatus GetElementRect(const Selector& selector, RectF* rect_output) {
     base::RunLoop run_loop;
-    bool result;
-    web_controller_->GetElementPosition(
-        selector,
-        base::BindOnce(&WebControllerBrowserTest::OnGetElementPosition,
-                       base::Unretained(this), run_loop.QuitClosure(), &result,
-                       rect_output));
+    ClientStatus result;
+    web_controller_->GetElementRect(
+        selector, base::BindOnce(&WebControllerBrowserTest::OnGetElementRect,
+                                 base::Unretained(this), run_loop.QuitClosure(),
+                                 &result, rect_output));
     run_loop.Run();
     return result;
   }
 
-  void OnGetElementPosition(base::OnceClosure done_callback,
-                            bool* result_output,
-                            RectF* rect_output,
-                            bool non_empty,
-                            const RectF& rect) {
-    if (non_empty) {
+  void OnGetElementRect(base::OnceClosure done_callback,
+                        ClientStatus* result_output,
+                        RectF* rect_output,
+                        const ClientStatus& rect_status,
+                        const RectF& rect) {
+    if (rect_status.ok()) {
       *rect_output = rect;
     }
-    *result_output = non_empty;
+    *result_output = rect_status;
     std::move(done_callback).Run();
   }
 
@@ -1887,23 +1886,28 @@
               AnyOf(DOCUMENT_LOADED, DOCUMENT_INTERACTIVE, DOCUMENT_COMPLETE));
 }
 
-IN_PROC_BROWSER_TEST_F(WebControllerBrowserTest, GetElementPosition) {
+IN_PROC_BROWSER_TEST_F(WebControllerBrowserTest, GetElementRect) {
   RectF document_element_rect;
   Selector document_element({"#full_height_section"});
-  EXPECT_TRUE(GetElementPosition(document_element, &document_element_rect));
+  EXPECT_EQ(
+      ACTION_APPLIED,
+      GetElementRect(document_element, &document_element_rect).proto_status());
 
   // The iFrame must be after the #full_height_section element to check that
   // the resulting rect is global.
   RectF iframe_element_rect;
   Selector iframe_element({"#iframe", "#touch_area_1"});
-  EXPECT_TRUE(GetElementPosition(iframe_element, &iframe_element_rect));
+  EXPECT_EQ(
+      ACTION_APPLIED,
+      GetElementRect(iframe_element, &iframe_element_rect).proto_status());
 
   EXPECT_GT(iframe_element_rect.top, document_element_rect.bottom);
 
   // Make sure the element is within the iframe.
   RectF iframe_rect;
   Selector iframe({"#iframe"});
-  EXPECT_TRUE(GetElementPosition(iframe, &iframe_rect));
+  EXPECT_EQ(ACTION_APPLIED,
+            GetElementRect(iframe, &iframe_rect).proto_status());
 
   EXPECT_GT(iframe_element_rect.left, iframe_rect.left);
   EXPECT_LT(iframe_element_rect.right, iframe_rect.right);
diff --git a/components/background_sync/background_sync_controller_impl.cc b/components/background_sync/background_sync_controller_impl.cc
index 8fe72bb..c1efec9 100644
--- a/components/background_sync/background_sync_controller_impl.cc
+++ b/components/background_sync/background_sync_controller_impl.cc
@@ -260,10 +260,6 @@
 #endif
 }
 
-int BackgroundSyncControllerImpl::GetSiteEngagementPenalty(const GURL& url) {
-  return delegate_->GetSiteEngagementPenalty(url);
-}
-
 base::TimeDelta BackgroundSyncControllerImpl::SnapToMaxOriginFrequency(
     int64_t min_interval,
     int64_t min_gap_for_origin) {
diff --git a/components/background_sync/background_sync_controller_impl.h b/components/background_sync/background_sync_controller_impl.h
index 5190de9..6dc98b8 100644
--- a/components/background_sync/background_sync_controller_impl.h
+++ b/components/background_sync/background_sync_controller_impl.h
@@ -33,8 +33,6 @@
 class Origin;
 }  // namespace url
 
-class GURL;
-
 class BackgroundSyncControllerImpl : public content::BackgroundSyncController,
                                      public KeyedService,
                                      public content_settings::Observer {
@@ -118,13 +116,6 @@
   }
 
  private:
-  // Gets the site engagement penalty for |url|, which is inversely proportional
-  // to the engagement level. The lower the engagement levels with the site,
-  // the less often periodic sync events will be fired.
-  // Returns kEngagementLevelNonePenalty if the engagement level is
-  // blink::mojom::EngagementLevel::NONE.
-  virtual int GetSiteEngagementPenalty(const GURL& url);
-
   // Once we've identified the minimum number of hours between each periodicsync
   // event for an origin, every delay calculated for the origin should be a
   // multiple of the same.
diff --git a/components/background_sync/background_sync_delegate.h b/components/background_sync/background_sync_delegate.h
index 0ab8683..ef4b198 100644
--- a/components/background_sync/background_sync_delegate.h
+++ b/components/background_sync/background_sync_delegate.h
@@ -48,6 +48,10 @@
 
   // Gets the site engagement penalty to add to the Periodic Background Sync
   // interval for the origin corresponding to |url|.
+  // The site engagement penalty is inversely proportional to the engagement
+  // level. The lower the engagement levels with the site, the less often
+  // periodic sync events will be fired.
+  // Returns 0 if the engagement level is blink::mojom::EngagementLevel::NONE.
   virtual int GetSiteEngagementPenalty(const GURL& url) = 0;
 
 #if defined(OS_ANDROID)
diff --git a/components/metrics/generate_expired_histograms_array.gni b/components/metrics/generate_expired_histograms_array.gni
index e9c04067..265559a6 100644
--- a/components/metrics/generate_expired_histograms_array.gni
+++ b/components/metrics/generate_expired_histograms_array.gni
@@ -46,6 +46,7 @@
       "//tools/metrics/histograms/histograms_xml/background/histograms.xml",
       "//tools/metrics/histograms/histograms_xml/blink/histograms.xml",
       "//tools/metrics/histograms/histograms_xml/bluetooth/histograms.xml",
+      "//tools/metrics/histograms/histograms_xml/borealis/histograms.xml",
       "//tools/metrics/histograms/histograms_xml/browser/histograms.xml",
       "//tools/metrics/histograms/histograms_xml/chrome/histograms.xml",
       "//tools/metrics/histograms/histograms_xml/chromeos/histograms.xml",
diff --git a/components/policy/proto/chrome_device_policy.proto b/components/policy/proto/chrome_device_policy.proto
index ad4161f90..23760fe 100644
--- a/components/policy/proto/chrome_device_policy.proto
+++ b/components/policy/proto/chrome_device_policy.proto
@@ -1723,6 +1723,14 @@
   optional bool family_link_accounts_allowed = 1 [default = false];
 }
 
+// Setting that controls whether ARC data snapshotting is enabled for the device
+// and time intervals of updating ARC data snapshot.
+message DeviceArcDataSnapshotHoursProto {
+  // This is a JSON string, for details see
+  // "DeviceArcDataSnapshotHours" in policy_template.json
+  optional string arc_data_snapshot_hours = 1;
+}
+
 message ChromeDeviceSettingsProto {
   reserved 61, 90;
   optional DevicePolicyRefreshRateProto device_policy_refresh_rate = 1;
@@ -1868,4 +1876,5 @@
   optional UsbDetachableAllowlistProto usb_detachable_allowlist = 113;
   optional DeviceFamilyLinkAccountsAllowedProto family_link_accounts_allowed =
       114;
+  optional DeviceArcDataSnapshotHoursProto arc_data_snapshot_hours = 115;
 }
diff --git a/components/policy/resources/policy_templates.json b/components/policy/resources/policy_templates.json
index 3aaef76..cbe9a98 100644
--- a/components/policy/resources/policy_templates.json
+++ b/components/policy/resources/policy_templates.json
@@ -1105,6 +1105,7 @@
         'ArcBackupRestoreEnabled',
         'ArcLocationServiceEnabled',
         'AppRecommendationZeroStateEnabled',
+        'DeviceArcDataSnapshotHours',
       ]
     },
     {
@@ -16739,6 +16740,58 @@
       Changes to the policy only apply while ARC isn't running, for example, while starting Chrome OS.''',
     },
     {
+      'name': 'DeviceArcDataSnapshotHours',
+      'owners': ['file://components/policy/resources/OWNERS'],
+      'type': 'dict',
+      'schema': {
+        'type': 'object',
+        'properties': {
+          'intervals': {
+            'type': 'array',
+            'items': {
+              '$ref': 'WeeklyTimeIntervals'
+            }
+          },
+          'timezone': { 'type': 'string' },
+        }
+      },
+      'supported_on': ['chrome_os:88-'],
+      'device_only': True,
+      'features': {
+        'dynamic_refresh': True
+      },
+      'example_value': {
+        'intervals':
+        [
+          {
+            'start': {
+              'day_of_week': 'MONDAY',
+              'time': 12840000
+            },
+            'end': {
+              'day_of_week': 'MONDAY',
+              'time': 21720000
+            }
+          },
+          {
+            'start': {
+              'day_of_week': 'FRIDAY',
+              'time': 38640000
+            },
+            'end': {
+              'day_of_week': 'FRIDAY',
+              'time': 57600000
+            }
+          }
+        ],
+        'timezone': 'GMT',
+      },
+      'id': 794,
+      'caption': '''Intervals when ARC data snapshot update process can be started for Managed Guest Sessions''',
+      'tags': [],
+      'desc': '''If "DeviceArcDataSnapshotHours" policy is set, then the ARC data snapshotting mechanism is turned on. And the ARC data snapshotting update can be started automatically during the defined time intervals. When an interval starts, ARC snapshot update is required and no user is logged-in, the ARC data snapshot update process is started without user notification. If the user session is active, the UI notification is shown and have to be accepted in order to reboot a device and start ARC data snapshot update process. Note: a device is blocked for usage during the ARC data snapshot update process.''',
+    },
+    {
       'name': 'IsolateOrigins',
       'owners': ['palmer@chromium.org', 'creis@chromium.org'],
       'type': 'string',
@@ -23918,6 +23971,7 @@
     'DeviceMinimumVersionAueMessage': 'device_minimum_version_aue_message.value',
     'ManagedGuestSessionPrivacyWarningsEnabled': 'managed_guest_session_privacy_warnings.enabled',
     'DeviceFamilyLinkAccountsAllowed': 'family_link_accounts_allowed.family_link_accounts_allowed',
+    'DeviceArcDataSnapshotHours': 'arc_data_snapshot_hours.arc_data_snapshot_hours',
   },
   'policy_atomic_group_definitions': [
     {
@@ -24412,6 +24466,6 @@
   'placeholders': [],
   'deleted_policy_ids': [114, 115, 412, 476, 544, 546, 562, 569, 578, 583, 589],
   'deleted_atomic_policy_group_ids': [],
-  'highest_id_currently_used': 793,
+  'highest_id_currently_used': 794,
   'highest_atomic_group_id_currently_used': 40
 }
diff --git a/components/sync/engine/net/http_bridge.cc b/components/sync/engine/net/http_bridge.cc
index f3ed90e..90b7cdfb 100644
--- a/components/sync/engine/net/http_bridge.cc
+++ b/components/sync/engine/net/http_bridge.cc
@@ -7,16 +7,11 @@
 #include <stddef.h>
 
 #include <utility>
-#include <vector>
 
 #include "base/bind.h"
-#include "base/bit_cast.h"
 #include "base/location.h"
 #include "base/metrics/histogram_functions.h"
 #include "base/metrics/histogram_macros.h"
-#include "base/single_thread_task_runner.h"
-#include "base/strings/string_number_conversions.h"
-#include "base/strings/stringprintf.h"
 #include "base/task/post_task.h"
 #include "base/task/thread_pool.h"
 #include "base/threading/thread_restrictions.h"
@@ -106,7 +101,7 @@
   extra_headers_.assign(headers);
 }
 
-void HttpBridge::SetURL(const char* url, int port) {
+void HttpBridge::SetURL(const GURL& url) {
 #if DCHECK_IS_ON()
   DCHECK(thread_checker_.CalledOnValidThread());
   {
@@ -116,11 +111,7 @@
   DCHECK(url_for_request_.is_empty())
       << "HttpBridge::SetURL called more than once?!";
 #endif
-  GURL temp(url);
-  GURL::Replacements replacements;
-  std::string port_str = base::NumberToString(port);
-  replacements.SetPort(port_str.c_str(), url::Component(0, port_str.length()));
-  url_for_request_ = temp.ReplaceComponents(replacements);
+  url_for_request_ = url;
 }
 
 void HttpBridge::SetPostPayload(const char* content_type,
diff --git a/components/sync/engine/net/http_bridge.h b/components/sync/engine/net/http_bridge.h
index 85d867e5e..0225f00 100644
--- a/components/sync/engine/net/http_bridge.h
+++ b/components/sync/engine/net/http_bridge.h
@@ -48,7 +48,7 @@
 
   // HttpPostProviderInterface implementation.
   void SetExtraRequestHeaders(const char* headers) override;
-  void SetURL(const char* url, int port) override;
+  void SetURL(const GURL& url) override;
   void SetPostPayload(const char* content_type,
                       int content_length,
                       const char* content) override;
diff --git a/components/sync/engine/net/http_bridge_unittest.cc b/components/sync/engine/net/http_bridge_unittest.cc
index 0270226b..2358a93 100644
--- a/components/sync/engine/net/http_bridge_unittest.cc
+++ b/components/sync/engine/net/http_bridge_unittest.cc
@@ -9,10 +9,10 @@
 #include <utility>
 
 #include "base/bind.h"
-#include "base/bit_cast.h"
 #include "base/message_loop/message_pump_type.h"
 #include "base/run_loop.h"
 #include "base/single_thread_task_runner.h"
+#include "base/strings/string_number_conversions.h"
 #include "base/strings/stringprintf.h"
 #include "base/test/bind_test_util.h"
 #include "base/test/task_environment.h"
@@ -161,7 +161,7 @@
     base::WaitableEvent* signal_when_released) {
   {
     scoped_refptr<ShuntedHttpBridge> bridge(new ShuntedHttpBridge(this, true));
-    bridge->SetURL("http://www.google.com", 9999);
+    bridge->SetURL(GURL("http://www.google.com:9999"));
     bridge->SetPostPayload("text/plain", 2, " ");
     bridge_for_race_test_ = bridge.get();
     signal_when_created->Signal();
@@ -177,7 +177,7 @@
 // Test the HttpBridge without actually making any network requests.
 TEST_F(MAYBE_SyncHttpBridgeTest, TestMakeSynchronousPostShunted) {
   scoped_refptr<HttpBridge> http_bridge(new ShuntedHttpBridge(this, false));
-  http_bridge->SetURL("http://www.google.com", 9999);
+  http_bridge->SetURL(GURL("http://www.google.com:9999"));
   http_bridge->SetPostPayload("text/plain", 2, " ");
 
   int os_error = 0;
@@ -201,8 +201,7 @@
 
   std::string payload =
       "this should be echoed back, this should be echoed back.";
-  GURL echo = test_server_.GetURL("/echo");
-  http_bridge->SetURL(echo.spec().c_str(), echo.IntPort());
+  http_bridge->SetURL(test_server_.GetURL("/echo"));
   http_bridge->SetPostPayload("application/x-www-form-urlencoded",
                               payload.length(), payload.c_str());
   int os_error = 0;
@@ -230,8 +229,7 @@
 
   scoped_refptr<HttpBridge> http_bridge(BuildBridge());
 
-  GURL echo_header = test_server_.GetURL("/echoall");
-  http_bridge->SetURL(echo_header.spec().c_str(), echo_header.IntPort());
+  http_bridge->SetURL(test_server_.GetURL("/echoall"));
 
   std::string test_payload = "###TEST PAYLOAD###";
   http_bridge->SetPostPayload("text/html", test_payload.length() + 1,
@@ -261,9 +259,7 @@
 
   scoped_refptr<HttpBridge> http_bridge(BuildBridge());
 
-  GURL echo_header = test_server_.GetURL("/echoall");
-
-  http_bridge->SetURL(echo_header.spec().c_str(), echo_header.IntPort());
+  http_bridge->SetURL(test_server_.GetURL("/echoall"));
   http_bridge->SetExtraRequestHeaders("test:fnord");
 
   std::string test_payload = "###TEST PAYLOAD###";
@@ -288,8 +284,7 @@
 
   scoped_refptr<HttpBridge> http_bridge(BuildBridge());
 
-  GURL echo_header = test_server_.GetURL("/echoall");
-  http_bridge->SetURL(echo_header.spec().c_str(), echo_header.IntPort());
+  http_bridge->SetURL(test_server_.GetURL("/echoall"));
 
   std::string test_payload = "###TEST PAYLOAD###";
   http_bridge->SetPostPayload("text/html", test_payload.length() + 1,
@@ -312,9 +307,8 @@
   auto function = base::BindLambdaForTesting([&](net::HttpStatusCode code) {
     scoped_refptr<HttpBridge> http_bridge(BuildBridge());
 
-    GURL echo_status = test_server_.GetURL(std::string("/echo?status=") +
-                                           std::to_string(code));
-    http_bridge->SetURL(echo_status.spec().c_str(), echo_status.IntPort());
+    http_bridge->SetURL(test_server_.GetURL(std::string("/echo?status=") +
+                                            base::NumberToString(code)));
 
     std::string test_payload = "###TEST PAYLOAD###";
     http_bridge->SetPostPayload("text/html", test_payload.length() + 1,
@@ -348,7 +342,7 @@
   // Test deliberately does not start the EmbeddedTestServer.
   scoped_refptr<HttpBridge> http_bridge(BuildBridge());
 
-  http_bridge->SetURL("http://anything", 9999);
+  http_bridge->SetURL(GURL("http://anything:9999"));
 
   std::string test_payload = "###TEST PAYLOAD###";
   http_bridge->SetPostPayload("text/html", test_payload.length() + 1,
@@ -365,7 +359,7 @@
 TEST_F(MAYBE_SyncHttpBridgeTest, Abort) {
   scoped_refptr<ShuntedHttpBridge> http_bridge(
       new ShuntedHttpBridge(this, true));
-  http_bridge->SetURL("http://www.google.com", 9999);
+  http_bridge->SetURL(GURL("http://www.google.com:9999"));
   http_bridge->SetPostPayload("text/plain", 2, " ");
 
   int os_error = 0;
@@ -382,7 +376,7 @@
 TEST_F(MAYBE_SyncHttpBridgeTest, AbortLate) {
   scoped_refptr<ShuntedHttpBridge> http_bridge(
       new ShuntedHttpBridge(this, false));
-  http_bridge->SetURL("http://www.google.com", 9999);
+  http_bridge->SetURL(GURL("http://www.google.com:9999"));
   http_bridge->SetPostPayload("text/plain", 2, " ");
 
   int os_error = 0;
diff --git a/components/sync/engine/net/http_post_provider_interface.h b/components/sync/engine/net/http_post_provider_interface.h
index 8ad649a..4da9cb5 100644
--- a/components/sync/engine/net/http_post_provider_interface.h
+++ b/components/sync/engine/net/http_post_provider_interface.h
@@ -8,6 +8,7 @@
 #include <string>
 
 #include "base/memory/ref_counted.h"
+#include "url/gurl.h"
 
 namespace syncer {
 
@@ -25,7 +26,7 @@
   virtual void SetExtraRequestHeaders(const char* headers) = 0;
 
   // Set the URL to POST to.
-  virtual void SetURL(const char* url, int port) = 0;
+  virtual void SetURL(const GURL& url) = 0;
 
   // Set the type, length and content of the POST payload.
   // |content_type| is a null-terminated MIME type specifier.
diff --git a/components/sync/engine_impl/loopback_server/loopback_connection_manager.cc b/components/sync/engine_impl/loopback_server/loopback_connection_manager.cc
index 17a5186..242d354 100644
--- a/components/sync/engine_impl/loopback_server/loopback_connection_manager.cc
+++ b/components/sync/engine_impl/loopback_server/loopback_connection_manager.cc
@@ -15,9 +15,8 @@
 
 LoopbackConnectionManager::~LoopbackConnectionManager() = default;
 
-HttpResponse LoopbackConnectionManager::PostBufferToPath(
+HttpResponse LoopbackConnectionManager::PostBuffer(
     const std::string& buffer_in,
-    const std::string& path,
     const std::string& access_token,
     std::string* buffer_out) {
   buffer_out->clear();
diff --git a/components/sync/engine_impl/loopback_server/loopback_connection_manager.h b/components/sync/engine_impl/loopback_server/loopback_connection_manager.h
index 6e78daf5..8e83691 100644
--- a/components/sync/engine_impl/loopback_server/loopback_connection_manager.h
+++ b/components/sync/engine_impl/loopback_server/loopback_connection_manager.h
@@ -23,10 +23,9 @@
 
  private:
   // Overridden ServerConnectionManager functions.
-  HttpResponse PostBufferToPath(const std::string& buffer_in,
-                                const std::string& path,
-                                const std::string& access_token,
-                                std::string* buffer_out) override;
+  HttpResponse PostBuffer(const std::string& buffer_in,
+                          const std::string& access_token,
+                          std::string* buffer_out) override;
 
   // The loopback server that will handle the requests locally.
   LoopbackServer loopback_server_;
diff --git a/components/sync/engine_impl/net/server_connection_manager.cc b/components/sync/engine_impl/net/server_connection_manager.cc
index 62a4fd1..3bb83cd2 100644
--- a/components/sync/engine_impl/net/server_connection_manager.cc
+++ b/components/sync/engine_impl/net/server_connection_manager.cc
@@ -20,8 +20,6 @@
 namespace syncer {
 namespace {
 
-const char kSyncServerSyncPath[] = "/command/";
-
 #define ENUM_CASE(x)    \
   case HttpResponse::x: \
     return #x;          \
@@ -101,8 +99,7 @@
 }
 
 ServerConnectionManager::ServerConnectionManager()
-    : proto_sync_path_(kSyncServerSyncPath),
-      server_response_(HttpResponse::Uninitialized()) {}
+    : server_response_(HttpResponse::Uninitialized()) {}
 
 ServerConnectionManager::~ServerConnectionManager() = default;
 
@@ -146,19 +143,17 @@
 
 void ServerConnectionManager::NotifyStatusChanged() {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-  for (auto& observer : listeners_)
+  for (auto& observer : listeners_) {
     observer.OnServerConnectionEvent(
         ServerConnectionEvent(server_response_.server_status));
+  }
 }
 
 HttpResponse ServerConnectionManager::PostBufferWithCachedAuth(
     const std::string& buffer_in,
     std::string* buffer_out) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-  std::string path =
-      MakeSyncServerPath(proto_sync_path(), MakeSyncQueryString(client_id_));
-  HttpResponse http_response =
-      PostBufferToPath(buffer_in, path, access_token_, buffer_out);
+  HttpResponse http_response = PostBuffer(buffer_in, access_token_, buffer_out);
   SetServerResponse(http_response);
   return http_response;
 }
diff --git a/components/sync/engine_impl/net/server_connection_manager.h b/components/sync/engine_impl/net/server_connection_manager.h
index 590ff88a..bf25472 100644
--- a/components/sync/engine_impl/net/server_connection_manager.h
+++ b/components/sync/engine_impl/net/server_connection_manager.h
@@ -102,29 +102,21 @@
   void AddListener(ServerConnectionEventListener* listener);
   void RemoveListener(ServerConnectionEventListener* listener);
 
-  inline HttpResponse::ServerConnectionCode server_status() const {
+  HttpResponse::ServerConnectionCode server_status() const {
     DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
     return server_response_.server_status;
   }
 
-  inline int net_error_code() const {
+  int net_error_code() const {
     DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
     return server_response_.net_error_code;
   }
 
-  inline int http_status_code() const {
+  int http_status_code() const {
     DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
     return server_response_.http_status_code;
   }
 
-  const std::string client_id() const { return client_id_; }
-
-  void set_client_id(const std::string& client_id) {
-    DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-    DCHECK(client_id_.empty());
-    client_id_.assign(client_id);
-  }
-
   // Sets a new access token. If |access_token| is empty, the current token is
   // invalidated and cleared. Returns false if the server is in authentication
   // error state.
@@ -133,30 +125,21 @@
   bool HasInvalidAccessToken() { return access_token_.empty(); }
 
  protected:
-  inline std::string proto_sync_path() const { return proto_sync_path_; }
-
   // Updates |server_response_| and notifies listeners if the server status
   // changed.
   void SetServerResponse(const HttpResponse& server_response);
 
   // Internal PostBuffer base function which subclasses are expected to
   // implement.
-  virtual HttpResponse PostBufferToPath(const std::string& buffer_in,
-                                        const std::string& path,
-                                        const std::string& access_token,
-                                        std::string* buffer_out) = 0;
+  virtual HttpResponse PostBuffer(const std::string& buffer_in,
+                                  const std::string& access_token,
+                                  std::string* buffer_out) = 0;
 
   void ClearAccessToken();
 
  private:
   void NotifyStatusChanged();
 
-  // The unique id of the user's client.
-  std::string client_id_;
-
-  // The paths we post to.
-  std::string proto_sync_path_;
-
   // The access token to use in authenticated requests.
   std::string access_token_;
 
diff --git a/components/sync/engine_impl/net/sync_server_connection_manager.cc b/components/sync/engine_impl/net/sync_server_connection_manager.cc
index 8204c8c..a8bc6819 100644
--- a/components/sync/engine_impl/net/sync_server_connection_manager.cc
+++ b/components/sync/engine_impl/net/sync_server_connection_manager.cc
@@ -20,26 +20,6 @@
 namespace syncer {
 namespace {
 
-std::string StripTrailingSlash(const std::string& s) {
-  int stripped_end_pos = s.size();
-  if (s.at(stripped_end_pos - 1) == '/') {
-    stripped_end_pos = stripped_end_pos - 1;
-  }
-
-  return s.substr(0, stripped_end_pos);
-}
-
-// TODO(crbug.com/951350): Use a GURL instead of string concatenation.
-std::string MakeConnectionURL(const std::string& sync_server,
-                              const std::string& path,
-                              bool use_ssl) {
-  std::string connection_url = (use_ssl ? "https://" : "http://");
-  connection_url += sync_server;
-  connection_url = StripTrailingSlash(connection_url);
-  connection_url += path;
-  return connection_url;
-}
-
 // This provides HTTP Post functionality through the interface provided
 // by the application hosting the syncer backend.
 class Connection : public CancelationObserver {
@@ -49,8 +29,7 @@
              CancelationSignal* cancelation_signal);
   ~Connection() override;
 
-  HttpResponse Init(const std::string& connection_url,
-                    int sync_server_port,
+  HttpResponse Init(const GURL& connection_url,
                     const std::string& access_token,
                     const std::string& payload);
   bool ReadBufferResponse(std::string* buffer_out, HttpResponse* response);
@@ -89,11 +68,10 @@
 
 Connection::~Connection() = default;
 
-HttpResponse Connection::Init(const std::string& connection_url,
-                              int sync_server_port,
+HttpResponse Connection::Init(const GURL& sync_request_url,
                               const std::string& access_token,
                               const std::string& payload) {
-  post_provider_->SetURL(connection_url.c_str(), sync_server_port);
+  post_provider_->SetURL(sync_request_url);
 
   if (!access_token.empty()) {
     std::string headers;
@@ -184,14 +162,10 @@
 }  // namespace
 
 SyncServerConnectionManager::SyncServerConnectionManager(
-    const std::string& server,
-    int port,
-    bool use_ssl,
+    const GURL& sync_request_url,
     std::unique_ptr<HttpPostProviderFactory> factory,
     CancelationSignal* cancelation_signal)
-    : sync_server_(server),
-      sync_server_port_(port),
-      use_ssl_(use_ssl),
+    : sync_request_url_(sync_request_url),
       post_provider_factory_(std::move(factory)),
       cancelation_signal_(cancelation_signal) {
   DCHECK(post_provider_factory_);
@@ -200,9 +174,8 @@
 
 SyncServerConnectionManager::~SyncServerConnectionManager() = default;
 
-HttpResponse SyncServerConnectionManager::PostBufferToPath(
+HttpResponse SyncServerConnectionManager::PostBuffer(
     const std::string& buffer_in,
-    const std::string& path,
     const std::string& access_token,
     std::string* buffer_out) {
   if (access_token.empty()) {
@@ -218,12 +191,11 @@
 
   auto connection = std::make_unique<Connection>(post_provider_factory_.get(),
                                                  cancelation_signal_);
-  std::string connection_url = MakeConnectionURL(sync_server_, path, use_ssl_);
 
-  // Note that |post| may be aborted by now, which will just cause Init to fail
-  // with CONNECTION_UNAVAILABLE.
-  HttpResponse http_response = connection->Init(
-      connection_url, sync_server_port_, access_token, buffer_in);
+  // Note that the post may be aborted by now, which will just cause Init to
+  // fail with CONNECTION_UNAVAILABLE.
+  HttpResponse http_response =
+      connection->Init(sync_request_url_, access_token, buffer_in);
 
   if (http_response.server_status == HttpResponse::SYNC_AUTH_ERROR) {
     ClearAccessToken();
diff --git a/components/sync/engine_impl/net/sync_server_connection_manager.h b/components/sync/engine_impl/net/sync_server_connection_manager.h
index 0df5eed..52b339b 100644
--- a/components/sync/engine_impl/net/sync_server_connection_manager.h
+++ b/components/sync/engine_impl/net/sync_server_connection_manager.h
@@ -12,6 +12,7 @@
 #include "base/gtest_prod_util.h"
 #include "base/macros.h"
 #include "components/sync/engine_impl/net/server_connection_manager.h"
+#include "url/gurl.h"
 
 namespace syncer {
 
@@ -24,34 +25,18 @@
  public:
   // |factory| and |cancelation_signal| must not be null, and the latter must
   // outlive this object.
-  SyncServerConnectionManager(const std::string& server,
-                              int port,
-                              bool use_ssl,
+  SyncServerConnectionManager(const GURL& sync_request_url,
                               std::unique_ptr<HttpPostProviderFactory> factory,
                               CancelationSignal* cancelation_signal);
   ~SyncServerConnectionManager() override;
 
- protected:
-  HttpResponse PostBufferToPath(const std::string& buffer_in,
-                                const std::string& path,
-                                const std::string& access_token,
-                                std::string* buffer_out) override;
+  HttpResponse PostBuffer(const std::string& buffer_in,
+                          const std::string& access_token,
+                          std::string* buffer_out) override;
 
  private:
-  FRIEND_TEST_ALL_PREFIXES(SyncServerConnectionManagerTest, VeryEarlyAbortPost);
-  FRIEND_TEST_ALL_PREFIXES(SyncServerConnectionManagerTest, EarlyAbortPost);
-  FRIEND_TEST_ALL_PREFIXES(SyncServerConnectionManagerTest, AbortPost);
-  FRIEND_TEST_ALL_PREFIXES(SyncServerConnectionManagerTest,
-                           FailPostWithTimedOut);
-
-  // The sync_server_ is the server that requests will be made to.
-  const std::string sync_server_;
-
-  // The sync_server_port_ is the port that HTTP requests will be made on.
-  const int sync_server_port_;
-
-  // Indicates whether or not requests should be made using HTTPS.
-  const bool use_ssl_;
+  // The full URL that requests will be made to.
+  const GURL sync_request_url_;
 
   // A factory creating concrete HttpPostProviders for use whenever we need to
   // issue a POST to sync servers.
diff --git a/components/sync/engine_impl/net/sync_server_connection_manager_unittest.cc b/components/sync/engine_impl/net/sync_server_connection_manager_unittest.cc
index f531004..55d3d71 100644
--- a/components/sync/engine_impl/net/sync_server_connection_manager_unittest.cc
+++ b/components/sync/engine_impl/net/sync_server_connection_manager_unittest.cc
@@ -29,7 +29,7 @@
                         base::WaitableEvent::InitialState::NOT_SIGNALED) {}
 
   void SetExtraRequestHeaders(const char* headers) override {}
-  void SetURL(const char* url, int port) override {}
+  void SetURL(const GURL& url) override {}
   void SetPostPayload(const char* content_type,
                       int content_length,
                       const char* content) override {}
@@ -69,11 +69,11 @@
   CancelationSignal signal;
   signal.Signal();
   SyncServerConnectionManager server(
-      "server", 0, true, std::make_unique<BlockingHttpPostFactory>(), &signal);
+      GURL("https://server"), std::make_unique<BlockingHttpPostFactory>(),
+      &signal);
 
   std::string buffer_out;
-  HttpResponse http_response =
-      server.PostBufferToPath("", "/testpath", "testauth", &buffer_out);
+  HttpResponse http_response = server.PostBuffer("", "testauth", &buffer_out);
 
   EXPECT_EQ(HttpResponse::CONNECTION_UNAVAILABLE, http_response.server_status);
 }
@@ -82,13 +82,12 @@
 TEST(SyncServerConnectionManagerTest, EarlyAbortPost) {
   CancelationSignal signal;
   SyncServerConnectionManager server(
-      "server", 0, true, std::make_unique<BlockingHttpPostFactory>(), &signal);
-
+      GURL("https://server"), std::make_unique<BlockingHttpPostFactory>(),
+      &signal);
 
   signal.Signal();
   std::string buffer_out;
-  HttpResponse http_response =
-      server.PostBufferToPath("", "/testpath", "testauth", &buffer_out);
+  HttpResponse http_response = server.PostBuffer("", "testauth", &buffer_out);
 
   EXPECT_EQ(HttpResponse::CONNECTION_UNAVAILABLE, http_response.server_status);
 }
@@ -97,7 +96,8 @@
 TEST(SyncServerConnectionManagerTest, AbortPost) {
   CancelationSignal signal;
   SyncServerConnectionManager server(
-      "server", 0, true, std::make_unique<BlockingHttpPostFactory>(), &signal);
+      GURL("https://server"), std::make_unique<BlockingHttpPostFactory>(),
+      &signal);
 
   base::Thread abort_thread("Test_AbortThread");
   ASSERT_TRUE(abort_thread.Start());
@@ -107,8 +107,7 @@
       TestTimeouts::tiny_timeout());
 
   std::string buffer_out;
-  HttpResponse http_response =
-      server.PostBufferToPath("", "/testpath", "testauth", &buffer_out);
+  HttpResponse http_response = server.PostBuffer("", "testauth", &buffer_out);
 
   EXPECT_EQ(HttpResponse::CONNECTION_UNAVAILABLE, http_response.server_status);
   abort_thread.Stop();
@@ -122,7 +121,7 @@
       : net_error_code_(net_error_code) {}
 
   void SetExtraRequestHeaders(const char* headers) override {}
-  void SetURL(const char* url, int port) override {}
+  void SetURL(const GURL& url) override {}
   void SetPostPayload(const char* content_type,
                       int content_length,
                       const char* content) override {}
@@ -167,12 +166,11 @@
 TEST(SyncServerConnectionManagerTest, FailPostWithTimedOut) {
   CancelationSignal signal;
   SyncServerConnectionManager server(
-      "server", 0, true,
+      GURL("https://server"),
       std::make_unique<FailingHttpPostFactory>(net::ERR_TIMED_OUT), &signal);
 
   std::string buffer_out;
-  HttpResponse http_response =
-      server.PostBufferToPath("", "/testpath", "testauth", &buffer_out);
+  HttpResponse http_response = server.PostBuffer("", "testauth", &buffer_out);
 
   EXPECT_EQ(HttpResponse::CONNECTION_UNAVAILABLE, http_response.server_status);
 }
diff --git a/components/sync/engine_impl/net/url_translator.cc b/components/sync/engine_impl/net/url_translator.cc
index fb6a6b9..ccc297c 100644
--- a/components/sync/engine_impl/net/url_translator.cc
+++ b/components/sync/engine_impl/net/url_translator.cc
@@ -5,9 +5,7 @@
 #include "components/sync/engine_impl/net/url_translator.h"
 
 #include "build/branding_buildflags.h"
-#include "net/base/escape.h"
-
-using std::string;
+#include "net/base/url_util.h"
 
 namespace syncer {
 
@@ -23,22 +21,10 @@
 #endif  // BUILDFLAG(GOOGLE_CHROME_BRANDING)
 }  // namespace
 
-// This method appends the query string to the sync server path.
-string MakeSyncServerPath(const string& path, const string& query_string) {
-  string result = path;
-  result.append("?");
-  result.append(query_string);
+GURL AppendSyncQueryString(const GURL& base, const std::string& client_id) {
+  GURL result = net::AppendQueryParameter(base, kParameterClient, kClientName);
+  result = net::AppendQueryParameter(result, kParameterClientID, client_id);
   return result;
 }
 
-string MakeSyncQueryString(const string& client_id) {
-  string query;
-  query += kParameterClient;
-  query += "=" + net::EscapeUrlEncodedData(kClientName, true);
-  query += "&";
-  query += kParameterClientID;
-  query += "=" + net::EscapeUrlEncodedData(client_id, true);
-  return query;
-}
-
 }  // namespace syncer
diff --git a/components/sync/engine_impl/net/url_translator.h b/components/sync/engine_impl/net/url_translator.h
index c5373ab..43e2ab63 100644
--- a/components/sync/engine_impl/net/url_translator.h
+++ b/components/sync/engine_impl/net/url_translator.h
@@ -7,16 +7,12 @@
 
 #include <string>
 
+#include "url/gurl.h"
+
 namespace syncer {
 
-// Contains the declaration of a few helper functions used for generating sync
-// URLs.
-
-// This method appends the query string to the sync server path.
-std::string MakeSyncServerPath(const std::string& path,
-                               const std::string& query_string);
-
-std::string MakeSyncQueryString(const std::string& client_id);
+// Appends the appropriate query string to the given sync base URL.
+GURL AppendSyncQueryString(const GURL& base, const std::string& client_id);
 
 }  // namespace syncer
 
diff --git a/components/sync/engine_impl/sync_manager_impl.cc b/components/sync/engine_impl/sync_manager_impl.cc
index 349304d..7852df8 100644
--- a/components/sync/engine_impl/sync_manager_impl.cc
+++ b/components/sync/engine_impl/sync_manager_impl.cc
@@ -26,6 +26,7 @@
 #include "components/sync/engine_impl/loopback_server/loopback_connection_manager.h"
 #include "components/sync/engine_impl/model_type_connector_proxy.h"
 #include "components/sync/engine_impl/net/sync_server_connection_manager.h"
+#include "components/sync/engine_impl/net/url_translator.h"
 #include "components/sync/engine_impl/sync_scheduler.h"
 #include "components/sync/nigori/cryptographer.h"
 #include "components/sync/nigori/keystore_keys_handler.h"
@@ -55,6 +56,28 @@
   return sync_pb::SyncEnums::UNKNOWN_ORIGIN;
 }
 
+const char kSyncServerSyncPath[] = "/command/";
+
+std::string StripTrailingSlash(const std::string& s) {
+  int stripped_end_pos = s.size();
+  if (s.at(stripped_end_pos - 1) == '/') {
+    stripped_end_pos = stripped_end_pos - 1;
+  }
+
+  return s.substr(0, stripped_end_pos);
+}
+
+GURL MakeConnectionURL(const GURL& sync_server, const std::string& client_id) {
+  DCHECK_EQ(kSyncServerSyncPath[0], '/');
+  std::string full_path =
+      StripTrailingSlash(sync_server.path()) + kSyncServerSyncPath;
+
+  GURL::Replacements path_replacement;
+  path_replacement.SetPathStr(full_path);
+  return AppendSyncQueryString(sync_server.ReplaceComponents(path_replacement),
+                               client_id);
+}
+
 }  // namespace
 
 SyncManagerImpl::SyncManagerImpl(
@@ -159,12 +182,9 @@
         args->local_sync_backend_folder);
   } else {
     connection_manager_ = std::make_unique<SyncServerConnectionManager>(
-        args->service_url.host() + args->service_url.path(),
-        args->service_url.EffectiveIntPort(),
-        args->service_url.SchemeIsCryptographic(),
+        MakeConnectionURL(args->service_url, args->cache_guid),
         std::move(args->post_factory), args->cancelation_signal);
   }
-  connection_manager_->set_client_id(args->cache_guid);
   connection_manager_->AddListener(this);
 
   DVLOG(1) << "Setting sync client ID: " << args->cache_guid;
diff --git a/components/sync/engine_impl/sync_manager_impl_unittest.cc b/components/sync/engine_impl/sync_manager_impl_unittest.cc
index 7294d402..39bd096 100644
--- a/components/sync/engine_impl/sync_manager_impl_unittest.cc
+++ b/components/sync/engine_impl/sync_manager_impl_unittest.cc
@@ -68,7 +68,7 @@
 class TestHttpPostProviderInterface : public HttpPostProviderInterface {
  public:
   void SetExtraRequestHeaders(const char* headers) override {}
-  void SetURL(const char* url, int port) override {}
+  void SetURL(const GURL& url) override {}
   void SetPostPayload(const char* content_type,
                       int content_length,
                       const char* content) override {}
diff --git a/components/sync/engine_impl/syncer_proto_util_unittest.cc b/components/sync/engine_impl/syncer_proto_util_unittest.cc
index ff83fb3..78af334 100644
--- a/components/sync/engine_impl/syncer_proto_util_unittest.cc
+++ b/components/sync/engine_impl/syncer_proto_util_unittest.cc
@@ -216,10 +216,9 @@
  public:
   DummyConnectionManager() = default;
 
-  HttpResponse PostBufferToPath(const std::string& buffer_in,
-                                const std::string& path,
-                                const std::string& access_token,
-                                std::string* buffer_out) override {
+  HttpResponse PostBuffer(const std::string& buffer_in,
+                          const std::string& access_token,
+                          std::string* buffer_out) override {
     if (send_error_) {
       return HttpResponse::ForIoError();
     }
diff --git a/components/sync/test/engine/mock_connection_manager.cc b/components/sync/test/engine/mock_connection_manager.cc
index 4f7efe2..02c6ef7c 100644
--- a/components/sync/test/engine/mock_connection_manager.cc
+++ b/components/sync/test/engine/mock_connection_manager.cc
@@ -66,11 +66,9 @@
   mid_commit_observer_ = observer;
 }
 
-HttpResponse MockConnectionManager::PostBufferToPath(
-    const std::string& buffer_in,
-    const std::string& path,
-    const std::string& access_token,
-    std::string* buffer_out) {
+HttpResponse MockConnectionManager::PostBuffer(const std::string& buffer_in,
+                                               const std::string& access_token,
+                                               std::string* buffer_out) {
   ClientToServerMessage post;
   if (!post.ParseFromString(buffer_in)) {
     ADD_FAILURE();
diff --git a/components/sync/test/engine/mock_connection_manager.h b/components/sync/test/engine/mock_connection_manager.h
index ed9e0f6..70e7197 100644
--- a/components/sync/test/engine/mock_connection_manager.h
+++ b/components/sync/test/engine/mock_connection_manager.h
@@ -39,10 +39,9 @@
   ~MockConnectionManager() override;
 
   // Overridden ServerConnectionManager functions.
-  HttpResponse PostBufferToPath(const std::string& buffer_in,
-                                const std::string& path,
-                                const std::string& access_token,
-                                std::string* buffer_out) override;
+  HttpResponse PostBuffer(const std::string& buffer_in,
+                          const std::string& access_token,
+                          std::string* buffer_out) override;
 
   // Control of commit response.
   // NOTE: Commit callback is invoked only once then reset.
diff --git a/components/sync/test/fake_server/fake_server_http_post_provider.cc b/components/sync/test/fake_server/fake_server_http_post_provider.cc
index 6dc65c1..cee14f2 100644
--- a/components/sync/test/fake_server/fake_server_http_post_provider.cc
+++ b/components/sync/test/fake_server/fake_server_http_post_provider.cc
@@ -51,12 +51,10 @@
   extra_request_headers_.assign(headers);
 }
 
-void FakeServerHttpPostProvider::SetURL(const char* url, int port) {
+void FakeServerHttpPostProvider::SetURL(const GURL& url) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
 
-  // TODO(pvalenzuela): Add assertions on these values.
-  request_url_.assign(url);
-  request_port_ = port;
+  request_url_ = url;
 }
 
 void FakeServerHttpPostProvider::SetPostPayload(const char* content_type,
diff --git a/components/sync/test/fake_server/fake_server_http_post_provider.h b/components/sync/test/fake_server/fake_server_http_post_provider.h
index efe9764..0f80c02 100644
--- a/components/sync/test/fake_server/fake_server_http_post_provider.h
+++ b/components/sync/test/fake_server/fake_server_http_post_provider.h
@@ -30,7 +30,7 @@
 
   // HttpPostProviderInterface implementation.
   void SetExtraRequestHeaders(const char* headers) override;
-  void SetURL(const char* url, int port) override;
+  void SetURL(const GURL& url) override;
   void SetPostPayload(const char* content_type,
                       int content_length,
                       const char* content) override;
@@ -68,8 +68,7 @@
   std::atomic_bool aborted_;
 
   std::string response_;
-  std::string request_url_;
-  int request_port_;
+  GURL request_url_;
   std::string request_content_;
   std::string request_content_type_;
   std::string extra_request_headers_;
diff --git a/components/webapk/android/libs/client/src/org/chromium/components/webapk/lib/client/WebApkValidator.java b/components/webapk/android/libs/client/src/org/chromium/components/webapk/lib/client/WebApkValidator.java
index ae8dd11..d73e493 100644
--- a/components/webapk/android/libs/client/src/org/chromium/components/webapk/lib/client/WebApkValidator.java
+++ b/components/webapk/android/libs/client/src/org/chromium/components/webapk/lib/client/WebApkValidator.java
@@ -194,15 +194,15 @@
             }
             return false;
         }
-        if (sOverrideValidationForTesting) {
-            if (DEBUG) {
-                Log.d(TAG, "WebApk validation is disabled for testing.");
-            }
-            return true;
-        }
         if (isNotWebApkQuick(packageInfo)) {
             return false;
         }
+        if (sOverrideValidationForTesting) {
+            if (DEBUG) {
+                Log.d(TAG, "Ok! Looks like a WebApk (has start url) and validation is disabled.");
+            }
+            return true;
+        }
         if (verifyV1WebApk(packageInfo, webappPackageName)) {
             return true;
         }
diff --git a/content/browser/download/download_browsertest.cc b/content/browser/download/download_browsertest.cc
index 71e8491..02f5dbbd 100644
--- a/content/browser/download/download_browsertest.cc
+++ b/content/browser/download/download_browsertest.cc
@@ -4316,7 +4316,7 @@
 // Verify that if the second request fails after the beginning request takes
 // over and completes its slice, download should complete.
 // Flaky on Linux.  http://crbug.com/1106059
-#if defined(OS_LINUX)
+#if defined(OS_LINUX) || defined(OS_CHROMEOS)
 #define MAYBE_MiddleSliceDelayedError DISABLED_MiddleSliceDelayedError
 #else
 #define MAYBE_MiddleSliceDelayedError MiddleSliceDelayedError
diff --git a/content/browser/download/download_manager_impl.cc b/content/browser/download/download_manager_impl.cc
index 388682f2..ba902ab 100644
--- a/content/browser/download/download_manager_impl.cc
+++ b/content/browser/download/download_manager_impl.cc
@@ -82,7 +82,7 @@
 #include "third_party/blink/public/common/loader/referrer_utils.h"
 #include "third_party/blink/public/common/loader/throttling_url_loader.h"
 
-#if defined(OS_LINUX)
+#if defined(OS_LINUX) || defined(OS_CHROMEOS)
 #include "base/nix/xdg_util.h"
 #endif
 
@@ -218,7 +218,7 @@
   }
 };
 
-#if defined(OS_LINUX)
+#if defined(OS_LINUX) || defined(OS_CHROMEOS)
 base::FilePath GetTemporaryDownloadDirectory() {
   std::unique_ptr<base::Environment> env(base::Environment::Create());
   return base::nix::GetXDGDirectory(env.get(), "XDG_DATA_HOME", ".local/share");
@@ -559,7 +559,7 @@
 
 base::FilePath DownloadManagerImpl::GetDefaultDownloadDirectory() {
   base::FilePath default_download_directory;
-#if defined(OS_LINUX)
+#if defined(OS_LINUX) || defined(OS_CHROMEOS)
   // TODO(thomasanderson,crbug.com/784010): Remove this when all Linux
   // distros with versions of GTK lower than 3.14.7 are no longer
   // supported.  This should happen when support for Ubuntu Trusty and
diff --git a/content/browser/download/download_manager_impl_unittest.cc b/content/browser/download/download_manager_impl_unittest.cc
index 91bf615..477d12af 100644
--- a/content/browser/download/download_manager_impl_unittest.cc
+++ b/content/browser/download/download_manager_impl_unittest.cc
@@ -611,7 +611,7 @@
   // distros with versions of GTK lower than 3.14.7 are no longer
   // supported.  This should happen when support for Ubuntu Trusty and
   // Debian Jessie are removed.
-#if defined(OS_LINUX)
+#if defined(OS_LINUX) || defined(OS_CHROMEOS)
   // Doing nothing will set the default download directory to null.
   EXPECT_CALL(GetMockDownloadManagerDelegate(), GetSaveDir(_, _, _)).Times(0);
 #else
@@ -654,7 +654,7 @@
   // distros with versions of GTK lower than 3.14.7 are no longer
   // supported.  This should happen when support for Ubuntu Trusty and
   // Debian Jessie are removed.
-#if defined(OS_LINUX)
+#if defined(OS_LINUX) || defined(OS_CHROMEOS)
   // Doing nothing will set the default download directory to null.
   EXPECT_CALL(GetMockDownloadManagerDelegate(), GetSaveDir(_, _, _)).Times(0);
 #else
diff --git a/content/browser/renderer_host/render_widget_host_view_child_frame_browsertest.cc b/content/browser/renderer_host/render_widget_host_view_child_frame_browsertest.cc
index e085f1e..d3ee1ff 100644
--- a/content/browser/renderer_host/render_widget_host_view_child_frame_browsertest.cc
+++ b/content/browser/renderer_host/render_widget_host_view_child_frame_browsertest.cc
@@ -512,7 +512,7 @@
 // Validate that the root widget's window segments are correctly propagated
 // via the SynchronizeVisualProperties cascade.
 // Flaky on Mac and Linux (http://crbug/1089994).
-#if defined(OS_MAC) || defined(OS_LINUX)
+#if defined(OS_MAC) || defined(OS_LINUX) || defined(OS_CHROMEOS)
 #define MAYBE_VisualPropertiesPropagation_RootWindowSegments \
   DISABLED_VisualPropertiesPropagation_RootWindowSegments
 #else
diff --git a/content/browser/web_contents/web_contents_view_aura.cc b/content/browser/web_contents/web_contents_view_aura.cc
index 66e0014..5d4dac32 100644
--- a/content/browser/web_contents/web_contents_view_aura.cc
+++ b/content/browser/web_contents/web_contents_view_aura.cc
@@ -153,7 +153,7 @@
   DISALLOW_COPY_AND_ASSIGN(WebDragSourceAura);
 };
 
-#if defined(OS_LINUX) || defined(OS_WIN)
+#if defined(OS_LINUX) || defined(OS_CHROMEOS) || defined(OS_WIN)
 // Fill out the OSExchangeData with a file contents, synthesizing a name if
 // necessary.
 void PrepareDragForFileContents(const DropData& drop_data,
@@ -239,7 +239,7 @@
   if (!drop_data.download_metadata.empty())
     PrepareDragForDownload(drop_data, provider, web_contents);
 #endif
-#if defined(OS_LINUX) || defined(OS_WIN)
+#if defined(OS_LINUX) || defined(OS_CHROMEOS) || defined(OS_WIN)
   // We set the file contents before the URL because the URL also sets file
   // contents (to a .URL shortcut).  We want to prefer file content data over
   // a shortcut so we add it first.
diff --git a/content/browser/web_contents/web_contents_view_aura_unittest.cc b/content/browser/web_contents/web_contents_view_aura_unittest.cc
index 70682e22..f22d2ca3 100644
--- a/content/browser/web_contents/web_contents_view_aura_unittest.cc
+++ b/content/browser/web_contents/web_contents_view_aura_unittest.cc
@@ -41,7 +41,7 @@
 constexpr gfx::Rect kBounds = gfx::Rect(0, 0, 20, 20);
 constexpr gfx::PointF kClientPt = {5, 10};
 
-#if defined(OS_LINUX) || defined(OS_WIN)
+#if defined(OS_LINUX) || defined(OS_CHROMEOS) || defined(OS_WIN)
 constexpr gfx::PointF kScreenPt = {17, 3};
 #endif
 
@@ -287,7 +287,7 @@
 
 #endif  // defined(OS_LINUX) && !defined(OS_CHROMEOS) || defined(OS_WIN)
 
-#if defined(OS_LINUX) || defined(OS_WIN)
+#if defined(OS_LINUX) || defined(OS_CHROMEOS) || defined(OS_WIN)
 TEST_F(WebContentsViewAuraTest, DragDropFilesOriginateFromRenderer) {
   WebContentsViewAura* view = GetView();
   auto data = std::make_unique<ui::OSExchangeData>();
@@ -327,7 +327,7 @@
   view->OnDragEntered(event);
   ASSERT_NE(nullptr, view->current_drop_data_);
 
-#if defined(OS_LINUX)
+#if defined(OS_LINUX) || defined(OS_CHROMEOS)
   // By design, Linux implementations return an empty string if file data
   // is also present.
   EXPECT_TRUE(!view->current_drop_data_->text ||
@@ -351,7 +351,7 @@
 
   CheckDropData(view);
 
-#if defined(OS_LINUX)
+#if defined(OS_LINUX) || defined(OS_CHROMEOS)
   // By design, Linux implementations returns an empty string if file data is
   // also present.
   EXPECT_TRUE(!drop_complete_data_->drop_data.text ||
diff --git a/content/browser/webrtc/webrtc_capture_from_element_browsertest.cc b/content/browser/webrtc/webrtc_capture_from_element_browsertest.cc
index 8910d26..e5615f078 100644
--- a/content/browser/webrtc/webrtc_capture_from_element_browsertest.cc
+++ b/content/browser/webrtc/webrtc_capture_from_element_browsertest.cc
@@ -19,9 +19,10 @@
 #include "base/system/sys_info.h"
 #endif
 
-#if BUILDFLAG(ENABLE_MOJO_RENDERER)
+#if BUILDFLAG(ENABLE_MOJO_RENDERER) || defined(THREAD_SANITIZER)
 // Remote mojo renderer does not send audio/video frames back to the renderer
 // process and hence does not support capture: https://crbug.com/641559.
+// Failing on TSan: crbug.com/1138712
 #define MAYBE_CaptureFromMediaElement DISABLED_CaptureFromMediaElement
 #else
 #define MAYBE_CaptureFromMediaElement CaptureFromMediaElement
diff --git a/content/ppapi_plugin/ppapi_thread.cc b/content/ppapi_plugin/ppapi_thread.cc
index 99075d5..a22d80e 100644
--- a/content/ppapi_plugin/ppapi_thread.cc
+++ b/content/ppapi_plugin/ppapi_thread.cc
@@ -15,8 +15,6 @@
 #include "base/files/file_util.h"
 #include "base/logging.h"
 #include "base/memory/discardable_memory_allocator.h"
-#include "base/metrics/histogram_functions.h"
-#include "base/metrics/histogram_macros.h"
 #include "base/rand_util.h"
 #include "base/single_thread_task_runner.h"
 #include "base/strings/stringprintf.h"
@@ -294,39 +292,24 @@
   base::ScopedNativeLibrary library;
   if (!plugin_entry_points_.initialize_module) {
     // Load the plugin from the specified library.
-    base::TimeDelta load_time;
     {
       TRACE_EVENT1("ppapi", "PpapiThread::LoadPlugin", "path",
                    path.MaybeAsASCII());
-
-      base::TimeTicks start = base::TimeTicks::Now();
       library = base::ScopedNativeLibrary(path);
-      load_time = base::TimeTicks::Now() - start;
     }
 
     if (!library.is_valid()) {
       LOG(ERROR) << "Failed to load Pepper module from " << path.value()
                  << " (error: " << library.GetError()->ToString() << ")";
-      if (!base::PathExists(path)) {
-        ReportLoadResult(path, FILE_MISSING);
-        return;
-      }
-      ReportLoadResult(path, LOAD_FAILED);
-      // Report detailed reason for load failure.
-      ReportLoadErrorCode(path, library.GetError());
       return;
     }
 
-    // Only report load time for success loads.
-    ReportLoadTime(path, load_time);
-
     // Get the GetInterface function (required).
     plugin_entry_points_.get_interface =
         reinterpret_cast<PP_GetInterface_Func>(
             library.GetFunctionPointer("PPP_GetInterface"));
     if (!plugin_entry_points_.get_interface) {
       LOG(WARNING) << "No PPP_GetInterface in plugin library";
-      ReportLoadResult(path, ENTRY_POINT_MISSING);
       return;
     }
 
@@ -345,7 +328,6 @@
               library.GetFunctionPointer("PPP_InitializeModule"));
       if (!plugin_entry_points_.initialize_module) {
         LOG(WARNING) << "No PPP_InitializeModule in plugin library";
-        ReportLoadResult(path, ENTRY_POINT_MISSING);
         return;
       }
     }
@@ -397,19 +379,16 @@
             library.GetFunctionPointer("PPP_InitializeBroker"));
     if (!init_broker) {
       LOG(WARNING) << "No PPP_InitializeBroker in plugin library";
-      ReportLoadResult(path, ENTRY_POINT_MISSING);
       return;
     }
 
     int32_t init_error = init_broker(&connect_instance_func_);
     if (init_error != PP_OK) {
       LOG(WARNING) << "InitBroker failed with error " << init_error;
-      ReportLoadResult(path, INIT_FAILED);
       return;
     }
     if (!connect_instance_func_) {
       LOG(WARNING) << "InitBroker did not provide PP_ConnectInstance_Func";
-      ReportLoadResult(path, INIT_FAILED);
       return;
     }
   } else {
@@ -417,15 +396,12 @@
         local_pp_module_, &ppapi::proxy::PluginDispatcher::GetBrowserInterface);
     if (init_error != PP_OK) {
       LOG(WARNING) << "InitModule failed with error " << init_error;
-      ReportLoadResult(path, INIT_FAILED);
       return;
     }
   }
 
   // Initialization succeeded, so keep the plugin DLL loaded.
   library_ = std::move(library);
-
-  ReportLoadResult(path, LOAD_SUCCESS);
 }
 
 void PpapiThread::OnCreateChannel(base::ProcessId renderer_pid,
@@ -506,52 +482,4 @@
       path.BaseName().AsUTF8Unsafe());
 }
 
-static std::string GetHistogramName(bool is_broker,
-                                    const std::string& metric_name,
-                                    const base::FilePath& path) {
-  return std::string("Plugin.Ppapi") + (is_broker ? "Broker" : "Plugin") +
-         metric_name + "_" + path.BaseName().MaybeAsASCII();
-}
-
-void PpapiThread::ReportLoadResult(const base::FilePath& path,
-                                   LoadResult result) {
-  DCHECK_LT(result, LOAD_RESULT_MAX);
-
-  // Note: This leaks memory, which is expected behavior.
-  base::HistogramBase* histogram =
-      base::LinearHistogram::FactoryGet(
-          GetHistogramName(is_broker_, "LoadResult", path),
-          1,
-          LOAD_RESULT_MAX,
-          LOAD_RESULT_MAX + 1,
-          base::HistogramBase::kUmaTargetedHistogramFlag);
-
-  histogram->Add(result);
-}
-
-void PpapiThread::ReportLoadErrorCode(
-    const base::FilePath& path,
-    const base::NativeLibraryLoadError* error) {
-// Only report load error code on Windows because that's the only platform that
-// has a numerical error value.
-#if defined(OS_WIN)
-  base::UmaHistogramSparse(GetHistogramName(is_broker_, "LoadErrorCode", path),
-                           error->code);
-#endif
-}
-
-void PpapiThread::ReportLoadTime(const base::FilePath& path,
-                                 const base::TimeDelta load_time) {
-  // Note: This leaks memory, which is expected behavior.
-  base::HistogramBase* histogram =
-      base::Histogram::FactoryTimeGet(
-          GetHistogramName(is_broker_, "LoadTime", path),
-          base::TimeDelta::FromMilliseconds(1),
-          base::TimeDelta::FromSeconds(10),
-          50,
-          base::HistogramBase::kUmaTargetedHistogramFlag);
-
-  histogram->AddTime(load_time);
-}
-
 }  // namespace content
diff --git a/content/ppapi_plugin/ppapi_thread.h b/content/ppapi_plugin/ppapi_thread.h
index abbbe0b6..7f4404b3 100644
--- a/content/ppapi_plugin/ppapi_thread.h
+++ b/content/ppapi_plugin/ppapi_thread.h
@@ -57,18 +57,6 @@
   void Shutdown() override;
 
  private:
-  // Make sure the enum list in tools/histogram/histograms.xml is updated with
-  // any change in this list.
-  enum LoadResult {
-    LOAD_SUCCESS,
-    LOAD_FAILED,
-    ENTRY_POINT_MISSING,
-    INIT_FAILED,
-    FILE_MISSING,
-    // NOTE: Add new values only immediately above this line.
-    LOAD_RESULT_MAX  // Boundary value for UMA_HISTOGRAM_ENUMERATION.
-  };
-
   // ChildThread overrides.
   bool Send(IPC::Message* msg) override;
   bool OnControlMessageReceived(const IPC::Message& msg) override;
@@ -125,16 +113,6 @@
   // Sets up the name of the plugin for logging using the given path.
   void SavePluginName(const base::FilePath& path);
 
-  void ReportLoadResult(const base::FilePath& path, LoadResult result);
-
-  // Reports |error| to UMA when plugin load fails.
-  void ReportLoadErrorCode(const base::FilePath& path,
-                           const base::NativeLibraryLoadError* error);
-
-  // Reports time to load the plugin.
-  void ReportLoadTime(const base::FilePath& path,
-                      const base::TimeDelta load_time);
-
   // True if running in a broker process rather than a normal plugin process.
   bool is_broker_;
 
diff --git a/content/renderer/accessibility/blink_ax_tree_source.cc b/content/renderer/accessibility/blink_ax_tree_source.cc
index 5f85998..c1e1d5e 100644
--- a/content/renderer/accessibility/blink_ax_tree_source.cc
+++ b/content/renderer/accessibility/blink_ax_tree_source.cc
@@ -223,6 +223,48 @@
   return SearchForExactlyOneInnerImage(obj, inner_image, /* max_depth = */ 3);
 }
 
+std::string GetEquivalentAriaRoleString(const ax::mojom::Role role) {
+  switch (role) {
+    case ax::mojom::Role::kArticle:
+      return "article";
+    case ax::mojom::Role::kBanner:
+      return "banner";
+    case ax::mojom::Role::kButton:
+      return "button";
+    case ax::mojom::Role::kComplementary:
+      return "complementary";
+    case ax::mojom::Role::kFigure:
+      return "figure";
+    case ax::mojom::Role::kFooter:
+      return "contentinfo";
+    case ax::mojom::Role::kHeader:
+      return "banner";
+    case ax::mojom::Role::kHeading:
+      return "heading";
+    case ax::mojom::Role::kImage:
+      return "img";
+    case ax::mojom::Role::kMain:
+      return "main";
+    case ax::mojom::Role::kNavigation:
+      return "navigation";
+    case ax::mojom::Role::kRadioButton:
+      return "radio";
+    case ax::mojom::Role::kRegion:
+      return "region";
+    case ax::mojom::Role::kSection:
+      // A <section> element uses the 'region' ARIA role mapping.
+      return "region";
+    case ax::mojom::Role::kSlider:
+      return "slider";
+    case ax::mojom::Role::kTime:
+      return "time";
+    default:
+      break;
+  }
+
+  return std::string();
+}
+
 }  // namespace
 
 ScopedFreezeBlinkAXTreeSource::ScopedFreezeBlinkAXTreeSource(
@@ -579,14 +621,11 @@
     WebElement element = node.To<WebElement>();
     is_iframe = element.HasHTMLTagName("iframe");
 
+    SerializeElementAttributes(src, element, dst);
     if (accessibility_mode_.has_mode(ui::AXMode::kHTML)) {
       SerializeHTMLAttributes(src, element, dst);
     }
 
-    if (src.IsEditable()) {
-      SerializeEditableTextAttributes(src, dst);
-    }
-
     // Presence of other ARIA attributes.
     if (src.HasAriaAttribute())
       dst->AddBoolAttribute(ax::mojom::BoolAttribute::kHasAriaAttribute, true);
@@ -1055,24 +1094,23 @@
   }
 }
 
-void BlinkAXTreeSource::SerializeEditableTextAttributes(
-    WebAXObject src,
-    ui::AXNodeData* dst) const {
-  DCHECK(src.IsEditable());
+void BlinkAXTreeSource::SerializeElementAttributes(WebAXObject src,
+                                                   WebElement element,
+                                                   ui::AXNodeData* dst) const {
+  if (element.HasAttribute("class")) {
+    TruncateAndAddStringAttribute(dst, ax::mojom::StringAttribute::kClassName,
+                                  element.GetAttribute("class").Utf8());
+  }
 
-  if (src.IsEditableRoot())
-    dst->AddBoolAttribute(ax::mojom::BoolAttribute::kEditableRoot, true);
-
-  if (src.IsNativeTextControl()) {
-    // Selection offsets are only used for plain text controls, (input of a text
-    // field type, and textarea). Rich editable areas, such as contenteditables,
-    // use AXTreeData.
-    //
-    // TODO(nektar): Remove kTextSelStart and kTextSelEnd from the renderer.
-    dst->AddIntAttribute(ax::mojom::IntAttribute::kTextSelStart,
-                         src.SelectionStart());
-    dst->AddIntAttribute(ax::mojom::IntAttribute::kTextSelEnd,
-                         src.SelectionEnd());
+  // ARIA role.
+  if (element.HasAttribute("role")) {
+    TruncateAndAddStringAttribute(dst, ax::mojom::StringAttribute::kRole,
+                                  element.GetAttribute("role").Utf8());
+  } else {
+    std::string role = GetEquivalentAriaRoleString(dst->role);
+    if (!role.empty())
+      TruncateAndAddStringAttribute(dst, ax::mojom::StringAttribute::kRole,
+                                    role);
   }
 }
 
diff --git a/content/renderer/accessibility/blink_ax_tree_source.h b/content/renderer/accessibility/blink_ax_tree_source.h
index b4a2932..4c848c8 100644
--- a/content/renderer/accessibility/blink_ax_tree_source.h
+++ b/content/renderer/accessibility/blink_ax_tree_source.h
@@ -158,8 +158,9 @@
                                        ui::AXNodeData* dst) const;
   void SerializeOtherScreenReaderAttributes(blink::WebAXObject src,
                                             ui::AXNodeData* dst) const;
-  void SerializeEditableTextAttributes(blink::WebAXObject src,
-                                       ui::AXNodeData* dst) const;
+  void SerializeElementAttributes(blink::WebAXObject src,
+                                  blink::WebElement element,
+                                  ui::AXNodeData* dst) const;
   void SerializeHTMLAttributes(blink::WebAXObject src,
                                blink::WebElement element,
                                ui::AXNodeData* dst) const;
diff --git a/content/web_test/renderer/web_ax_object_proxy.cc b/content/web_test/renderer/web_ax_object_proxy.cc
index 8324b58..96f14fa 100644
--- a/content/web_test/renderer/web_ax_object_proxy.cc
+++ b/content/web_test/renderer/web_ax_object_proxy.cc
@@ -1169,7 +1169,8 @@
 
 bool WebAXObjectProxy::IsEditableRoot() {
   UpdateLayout();
-  return accessibility_object_.IsEditableRoot();
+  return GetAXNodeData().GetBoolAttribute(
+      ax::mojom::BoolAttribute::kEditableRoot);
 }
 
 bool WebAXObjectProxy::IsEditable() {
diff --git a/ios/chrome/browser/crash_report/crash_report_multi_parameter.mm b/ios/chrome/browser/crash_report/crash_report_multi_parameter.mm
index 2b1280e..1d97a75 100644
--- a/ios/chrome/browser/crash_report/crash_report_multi_parameter.mm
+++ b/ios/chrome/browser/crash_report/crash_report_multi_parameter.mm
@@ -11,6 +11,7 @@
 #include "base/notreached.h"
 #include "base/strings/sys_string_conversions.h"
 #include "base/values.h"
+#import "components/previous_session_info/previous_session_info.h"
 #import "ios/chrome/browser/crash_report/breakpad_helper.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
@@ -79,11 +80,11 @@
     NOTREACHED();
     return;
   }
-  breakpad_helper::AddReportParameter(
-      _crashReportKey,
-      [NSString stringWithCString:stateAsJson.c_str()
-                         encoding:[NSString defaultCStringEncoding]],
-      true);
+  NSString* value = base::SysUTF8ToNSString(stateAsJson);
+  breakpad_helper::AddReportParameter(_crashReportKey, value, /*async=*/true);
+  [[PreviousSessionInfo sharedInstance]
+      setReportParameterValue:value
+                       forKey:_crashReportKey];
 }
 
 @end
diff --git a/ios/chrome/browser/passwords/ios_chrome_password_check_manager.h b/ios/chrome/browser/passwords/ios_chrome_password_check_manager.h
index 3134cbf7..a03756f 100644
--- a/ios/chrome/browser/passwords/ios_chrome_password_check_manager.h
+++ b/ios/chrome/browser/passwords/ios_chrome_password_check_manager.h
@@ -69,9 +69,10 @@
   GetSavedPasswordsFor(
       const password_manager::CredentialWithPassword& credential) const;
 
-  // Edits password for |form|.
-  void EditPasswordForm(const autofill::PasswordForm& form,
-                        base::StringPiece password);
+  // Edits |username| and |password| for |form| and its duplicates.
+  bool EditPasswordForm(const autofill::PasswordForm& form,
+                        base::StringPiece new_username,
+                        base::StringPiece new_password);
 
   // Edits password form using |insecure_credentials_manager_|.
   void EditCompromisedPasswordForm(const autofill::PasswordForm& form,
diff --git a/ios/chrome/browser/passwords/ios_chrome_password_check_manager.mm b/ios/chrome/browser/passwords/ios_chrome_password_check_manager.mm
index f48766d3..2c14bbb3 100644
--- a/ios/chrome/browser/passwords/ios_chrome_password_check_manager.mm
+++ b/ios/chrome/browser/passwords/ios_chrome_password_check_manager.mm
@@ -157,10 +157,15 @@
   return insecure_credentials_manager_.GetSavedPasswordsFor(credential);
 }
 
-void IOSChromePasswordCheckManager::EditPasswordForm(
+bool IOSChromePasswordCheckManager::EditPasswordForm(
     const autofill::PasswordForm& form,
-    base::StringPiece password) {
-  saved_passwords_presenter_.EditPassword(form, base::UTF8ToUTF16(password));
+    base::StringPiece new_username,
+    base::StringPiece new_password) {
+  auto duplicates =
+      GetDuplicatesOfForm(form, saved_passwords_presenter_.GetSavedPasswords());
+  return saved_passwords_presenter_.EditSavedPasswords(
+      duplicates, base::UTF8ToUTF16(new_username),
+      base::UTF8ToUTF16(new_password));
 }
 
 void IOSChromePasswordCheckManager::EditCompromisedPasswordForm(
diff --git a/ios/chrome/browser/passwords/ios_chrome_password_check_manager_unittest.mm b/ios/chrome/browser/passwords/ios_chrome_password_check_manager_unittest.mm
index 5e2f28d..309de1e11 100644
--- a/ios/chrome/browser/passwords/ios_chrome_password_check_manager_unittest.mm
+++ b/ios/chrome/browser/passwords/ios_chrome_password_check_manager_unittest.mm
@@ -44,6 +44,7 @@
 constexpr char kExampleCom[] = "https://example.com";
 
 constexpr char kUsername1[] = "alice";
+constexpr char kUsername2[] = "bob";
 
 constexpr char kPassword1[] = "s3cre3t";
 constexpr char kPassword2[] = "bett3r_S3cre3t";
@@ -63,6 +64,7 @@
 using ::testing::Field;
 using ::testing::IsEmpty;
 using ::testing::StrictMock;
+using ::testing::Pair;
 
 using InsecureCredentialsView =
     password_manager::InsecureCredentialsManager::CredentialsView;
@@ -142,6 +144,19 @@
       Field(&CredentialWithPassword::insecure_type, insecure_type));
 }
 
+// Returns vector of pairs with username, password only.
+std::vector<std::pair<std::string, std::string>> GetUsernamesAndPasswords(
+    const std::vector<password_manager::PasswordForm>& forms) {
+  std::vector<std::pair<std::string, std::string>> result;
+  result.reserve(forms.size());
+  for (const auto& form : forms) {
+    result.emplace_back(base::UTF16ToUTF8(form.username_value),
+                        base::UTF16ToUTF8(form.password_value));
+  }
+
+  return result;
+}
+
 class IOSChromePasswordCheckManagerTest : public PlatformTest {
  public:
   IOSChromePasswordCheckManagerTest()
@@ -363,15 +378,47 @@
 
 // Tests password value is updated properly.
 TEST_F(IOSChromePasswordCheckManagerTest, EditPassword) {
-  store().AddLogin(MakeSavedPassword(kExampleCom, kUsername1));
+  store().AddLogin(MakeSavedPassword(kExampleCom, kUsername1, kPassword1));
   RunUntilIdle();
 
-  manager().EditPasswordForm(store().stored_passwords().at(kExampleCom).at(0),
-                             kPassword2);
+  EXPECT_TRUE(manager().EditPasswordForm(
+      store().stored_passwords().at(kExampleCom).at(0), kUsername1,
+      kPassword2));
   RunUntilIdle();
 
-  EXPECT_EQ(base::UTF8ToUTF16(kPassword2),
-            store().stored_passwords().at(kExampleCom).at(0).password_value);
+  EXPECT_THAT(
+      GetUsernamesAndPasswords(store().stored_passwords().at(kExampleCom)),
+      ElementsAre(Pair(kUsername1, kPassword2)));
+}
+
+// Tests username value is updated properly.
+TEST_F(IOSChromePasswordCheckManagerTest, EditUsername) {
+  store().AddLogin(MakeSavedPassword(kExampleCom, kUsername1, kPassword1));
+  RunUntilIdle();
+
+  EXPECT_TRUE(manager().EditPasswordForm(
+      store().stored_passwords().at(kExampleCom).at(0), kUsername2,
+      kPassword1));
+  RunUntilIdle();
+
+  EXPECT_THAT(
+      GetUsernamesAndPasswords(store().stored_passwords().at(kExampleCom)),
+      ElementsAre(Pair(kUsername2, kPassword1)));
+}
+
+// Tests username and password values are updated properly.
+TEST_F(IOSChromePasswordCheckManagerTest, EditUsernameAndPassword) {
+  store().AddLogin(MakeSavedPassword(kExampleCom, kUsername1, kPassword1));
+  RunUntilIdle();
+
+  EXPECT_TRUE(manager().EditPasswordForm(
+      store().stored_passwords().at(kExampleCom).at(0), kUsername2,
+      kPassword2));
+  RunUntilIdle();
+
+  EXPECT_THAT(
+      GetUsernamesAndPasswords(store().stored_passwords().at(kExampleCom)),
+      ElementsAre(Pair(kUsername2, kPassword2)));
 }
 
 // Tests compromised password value is updated properly.
diff --git a/ios/chrome/browser/test/perf_test_with_bvc_ios.mm b/ios/chrome/browser/test/perf_test_with_bvc_ios.mm
index 5cac8d6..f636e675 100644
--- a/ios/chrome/browser/test/perf_test_with_bvc_ios.mm
+++ b/ios/chrome/browser/test/perf_test_with_bvc_ios.mm
@@ -123,7 +123,8 @@
                      initWithBrowser:browser_.get()
                    dependencyFactory:bvc_factory_
       browserContainerViewController:[[BrowserContainerViewController alloc]
-                                         init]];
+                                         init]
+                          dispatcher:browser_->GetCommandDispatcher()];
   [bvc_ setActive:YES];
 
   // Create a real window to give to the browser view controller.
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 d46999a0..7d5f2e7 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
@@ -270,6 +270,9 @@
                  @"Keyboard Should be Shown");
   [[EarlGrey selectElementWithMatcher:ManualFallbackPasswordTableViewMatcher()]
       assertWithMatcher:grey_notVisible()];
+
+  [[EarlGrey selectElementWithMatcher:SettingsPasswordMatcher()]
+      performAction:grey_tap()];
 }
 
 // Tests that the Password View Controller is resumed after selecting other
diff --git a/ios/chrome/browser/ui/browser_view/browser_coordinator.mm b/ios/chrome/browser/ui/browser_view/browser_coordinator.mm
index fee6eda..02dff7c 100644
--- a/ios/chrome/browser/ui/browser_view/browser_coordinator.mm
+++ b/ios/chrome/browser/ui/browser_view/browser_coordinator.mm
@@ -242,6 +242,7 @@
   [self removeWebStateListObserver];
   [self uninstallDelegatesForBrowser];
   [self uninstallDelegatesForAllWebStates];
+  self.viewController.commandDispatcher = nil;
   [self.dispatcher stopDispatchingToTarget:self];
   [self stopChildCoordinators];
   [self destroyViewController];
@@ -305,7 +306,8 @@
                      initWithBrowser:self.browser
                    dependencyFactory:factory
       browserContainerViewController:self.browserContainerCoordinator
-                                         .viewController];
+                                         .viewController
+                          dispatcher:self.dispatcher];
 }
 
 // Shuts down the BrowserViewController.
diff --git a/ios/chrome/browser/ui/browser_view/browser_view_controller.h b/ios/chrome/browser/ui/browser_view/browser_view_controller.h
index 13e67ae..32c574e 100644
--- a/ios/chrome/browser/ui/browser_view/browser_view_controller.h
+++ b/ios/chrome/browser/ui/browser_view/browser_view_controller.h
@@ -20,6 +20,7 @@
 class Browser;
 @class BrowserContainerViewController;
 @class BrowserViewControllerDependencyFactory;
+@class CommandDispatcher;
 @class ToolbarAccessoryPresenter;
 
 // The top-level view controller for the browser UI. Manages other controllers
@@ -42,6 +43,7 @@
                      (BrowserViewControllerDependencyFactory*)factory
     browserContainerViewController:
         (BrowserContainerViewController*)browserContainerViewController
+                        dispatcher:(CommandDispatcher*)dispatcher
     NS_DESIGNATED_INITIALIZER;
 
 - (instancetype)initWithNibName:(NSString*)nibNameOrNil
@@ -49,6 +51,9 @@
 
 - (instancetype)initWithCoder:(NSCoder*)aDecoder NS_UNAVAILABLE;
 
+// Command dispatcher.
+@property(nonatomic, weak) CommandDispatcher* commandDispatcher;
+
 // Returns whether or not text to speech is playing.
 @property(nonatomic, assign, readonly, getter=isPlayingTTS) BOOL playingTTS;
 
diff --git a/ios/chrome/browser/ui/browser_view/browser_view_controller.mm b/ios/chrome/browser/ui/browser_view/browser_view_controller.mm
index bd48a9d2..4bfb43a 100644
--- a/ios/chrome/browser/ui/browser_view/browser_view_controller.mm
+++ b/ios/chrome/browser/ui/browser_view/browser_view_controller.mm
@@ -480,8 +480,6 @@
     BrowserContainerViewController* browserContainerViewController;
 // Invisible button used to dismiss the keyboard.
 @property(nonatomic, strong) UIButton* typingShield;
-// Command dispatcher.
-@property(nonatomic, weak) CommandDispatcher* commandDispatcher;
 // The browser's side swipe controller.  Lazily instantiated on the first call.
 @property(nonatomic, strong, readonly) SideSwipeController* sideSwipeController;
 // The object that manages keyboard commands on behalf of the BVC.
@@ -717,14 +715,15 @@
                  dependencyFactory:
                      (BrowserViewControllerDependencyFactory*)factory
     browserContainerViewController:
-        (BrowserContainerViewController*)browserContainerViewController {
+        (BrowserContainerViewController*)browserContainerViewController
+                        dispatcher:(CommandDispatcher*)dispatcher {
   self = [super initWithNibName:nil bundle:base::mac::FrameworkBundle()];
   if (self) {
     DCHECK(factory);
 
+    _commandDispatcher = dispatcher;
     _browserContainerViewController = browserContainerViewController;
     _dependencyFactory = factory;
-    self.commandDispatcher = browser->GetCommandDispatcher();
     self.textZoomHandler =
         HandlerForProtocol(self.commandDispatcher, TextZoomCommands);
     [self.commandDispatcher
diff --git a/ios/chrome/browser/ui/browser_view/browser_view_controller_unittest.mm b/ios/chrome/browser/ui/browser_view/browser_view_controller_unittest.mm
index 972d0f3..b3e6ae0 100644
--- a/ios/chrome/browser/ui/browser_view/browser_view_controller_unittest.mm
+++ b/ios/chrome/browser/ui/browser_view/browser_view_controller_unittest.mm
@@ -164,9 +164,11 @@
         std::make_unique<FakeClipboardRecentContent>());
 
     container_ = [[BrowserContainerViewController alloc] init];
-    bvc_ = [[BrowserViewController alloc] initWithBrowser:browser_.get()
-                                        dependencyFactory:factory
-                           browserContainerViewController:container_];
+    bvc_ = [[BrowserViewController alloc]
+                       initWithBrowser:browser_.get()
+                     dependencyFactory:factory
+        browserContainerViewController:container_
+                            dispatcher:browser_->GetCommandDispatcher()];
 
     // Force the view to load.
     UIWindow* window = [[UIWindow alloc] initWithFrame:CGRectZero];
diff --git a/ios/chrome/browser/ui/settings/password/password_details/BUILD.gn b/ios/chrome/browser/ui/settings/password/password_details/BUILD.gn
index 88c82ee..0d440a26 100644
--- a/ios/chrome/browser/ui/settings/password/password_details/BUILD.gn
+++ b/ios/chrome/browser/ui/settings/password/password_details/BUILD.gn
@@ -55,11 +55,13 @@
     "//components/autofill/core/common",
     "//components/password_manager/core/browser:affiliation",
     "//components/password_manager/core/browser:browser",
+    "//components/password_manager/core/common",
     "//components/strings",
     "//ios/chrome/app/strings:ios_chromium_strings_grit",
     "//ios/chrome/app/strings:ios_strings_grit",
     "//ios/chrome/browser",
     "//ios/chrome/browser/passwords",
+    "//ios/chrome/browser/ui:feature_flags",
     "//ios/chrome/browser/ui/commands",
     "//ios/chrome/browser/ui/infobars/resources:infobar_hide_password_icon",
     "//ios/chrome/browser/ui/infobars/resources:infobar_reveal_password_icon",
diff --git a/ios/chrome/browser/ui/settings/password/password_details/password_details.h b/ios/chrome/browser/ui/settings/password/password_details/password_details.h
index e3a81a5..7604402f9 100644
--- a/ios/chrome/browser/ui/settings/password/password_details/password_details.h
+++ b/ios/chrome/browser/ui/settings/password/password_details/password_details.h
@@ -24,7 +24,7 @@
 @property(nonatomic, copy, readonly) NSString* website;
 
 // Associated username.
-@property(nonatomic, copy, readonly) NSString* username;
+@property(nonatomic, copy) NSString* username;
 
 // Associated password.
 @property(nonatomic, copy) NSString* password;
diff --git a/ios/chrome/browser/ui/settings/password/password_details/password_details_mediator.mm b/ios/chrome/browser/ui/settings/password/password_details/password_details_mediator.mm
index d20dd18..f36a2e8 100644
--- a/ios/chrome/browser/ui/settings/password/password_details/password_details_mediator.mm
+++ b/ios/chrome/browser/ui/settings/password/password_details/password_details_mediator.mm
@@ -62,15 +62,15 @@
             (PasswordDetailsTableViewController*)viewController
                didEditPasswordDetails:(PasswordDetails*)password {
   if ([password.password length] != 0) {
-    password.compromised
-        ? _manager->EditCompromisedPasswordForm(
-              _password, base::SysNSStringToUTF8(password.password))
-        : _manager->EditPasswordForm(
-              _password, base::SysNSStringToUTF8(password.password));
-    _password.password_value = base::SysNSStringToUTF16(password.password);
-  } else {
-    [self fetchPasswordWith:_manager->GetCompromisedCredentials()];
+    if (_manager->EditPasswordForm(
+            _password, base::SysNSStringToUTF8(password.username),
+            base::SysNSStringToUTF8(password.password))) {
+      _password.username_value = base::SysNSStringToUTF16(password.username);
+      _password.password_value = base::SysNSStringToUTF16(password.password);
+      return;
+    }
   }
+  [self fetchPasswordWith:_manager->GetCompromisedCredentials()];
 }
 
 #pragma mark - PasswordCheckObserver
diff --git a/ios/chrome/browser/ui/settings/password/password_details/password_details_table_view_controller.mm b/ios/chrome/browser/ui/settings/password/password_details/password_details_table_view_controller.mm
index 3c89c5c..3762a0e2 100644
--- a/ios/chrome/browser/ui/settings/password/password_details/password_details_table_view_controller.mm
+++ b/ios/chrome/browser/ui/settings/password/password_details/password_details_table_view_controller.mm
@@ -10,6 +10,7 @@
 #include "base/metrics/histogram_macros.h"
 #include "base/strings/sys_string_conversions.h"
 #include "components/password_manager/core/browser/password_manager_metrics_util.h"
+#include "components/password_manager/core/common/password_manager_features.h"
 #import "ios/chrome/browser/ui/commands/application_commands.h"
 #import "ios/chrome/browser/ui/commands/browser_commands.h"
 #import "ios/chrome/browser/ui/commands/open_new_tab_command.h"
@@ -23,6 +24,7 @@
 #import "ios/chrome/browser/ui/table_view/cells/table_view_cells_constants.h"
 #import "ios/chrome/browser/ui/table_view/cells/table_view_text_edit_item.h"
 #import "ios/chrome/browser/ui/table_view/cells/table_view_text_item.h"
+#include "ios/chrome/browser/ui/ui_feature_flags.h"
 #include "ios/chrome/browser/ui/util/uikit_ui_util.h"
 #import "ios/chrome/common/ui/colors/UIColor+cr_semantic_colors.h"
 #import "ios/chrome/common/ui/colors/semantic_color_names.h"
@@ -74,6 +76,9 @@
 // Whether the password is shown in plain text form or in masked form.
 @property(nonatomic, assign, getter=isPasswordShown) BOOL passwordShown;
 
+// The text item related to the username value.
+@property(nonatomic, strong) TableViewTextEditItem* usernameTextItem;
+
 // The text item related to the password value.
 @property(nonatomic, strong) TableViewTextEditItem* passwordTextItem;
 
@@ -119,12 +124,15 @@
   }
 
   if (self.tableView.editing) {
-    // If password value was changed show confirmation dialog before saving
-    // password. Editing mode will be exited only if user confirm saving.
-    if (self.password.password != self.passwordTextItem.textFieldValue) {
+    // If password or username value was changed show confirmation dialog before
+    // saving password. Editing mode will be exited only if user confirm saving.
+    if (self.password.password != self.passwordTextItem.textFieldValue ||
+        self.password.username != self.usernameTextItem.textFieldValue) {
       [self.handler showPasswordEditDialogWithOrigin:self.password.origin];
-      return;
+    } else {
+      [self passwordEditingConfirmed];
     }
+    return;
   }
 
   [super editButtonPressed];
@@ -142,7 +150,8 @@
 
   // Blocked password forms don't have username value.
   if ([self.password.username length]) {
-    [model addItem:[self usernameItem]
+    self.usernameTextItem = [self usernameItem];
+    [model addItem:self.usernameTextItem
         toSectionWithIdentifier:SectionIdentifierPassword];
   }
 
@@ -184,8 +193,16 @@
   item.textFieldName =
       l10n_util::GetNSString(IDS_IOS_SHOW_PASSWORD_VIEW_USERNAME);
   item.textFieldValue = self.password.username;
-  item.textFieldEnabled = NO;
-  item.hideIcon = YES;
+  if (base::FeatureList::IsEnabled(
+          password_manager::features::kEditPasswordsInSettings)) {
+    item.textFieldEnabled = self.tableView.editing;
+    item.hideIcon = !self.tableView.editing;
+    item.autoCapitalizationType = UITextAutocapitalizationTypeNone;
+    item.returnKeyType = UIReturnKeyDone;
+  } else {
+    item.textFieldEnabled = NO;
+    item.hideIcon = YES;
+  }
   return item;
 }
 
@@ -243,13 +260,28 @@
   NSInteger itemType = [model itemTypeForIndexPath:indexPath];
   switch (itemType) {
     case ItemTypeWebsite:
-    case ItemTypeUsername:
       [self ensureContextMenuShownForItemType:itemType
                                     tableView:tableView
                                   atIndexPath:indexPath];
       break;
     case ItemTypeChangePasswordRecommendation:
       break;
+    case ItemTypeUsername: {
+      if (base::FeatureList::IsEnabled(
+              password_manager::features::kEditPasswordsInSettings) &&
+          self.tableView.editing) {
+        UITableViewCell* cell =
+            [self.tableView cellForRowAtIndexPath:indexPath];
+        TableViewTextEditCell* textFieldCell =
+            base::mac::ObjCCastStrict<TableViewTextEditCell>(cell);
+        [textFieldCell.textField becomeFirstResponder];
+      } else {
+        [self ensureContextMenuShownForItemType:itemType
+                                      tableView:tableView
+                                    atIndexPath:indexPath];
+      }
+      break;
+    }
     case ItemTypePassword: {
       if (self.tableView.editing) {
         UITableViewCell* cell =
@@ -321,6 +353,12 @@
   cell.tag = itemType;
 
   switch (itemType) {
+    case ItemTypeUsername: {
+      TableViewTextEditCell* textFieldCell =
+          base::mac::ObjCCastStrict<TableViewTextEditCell>(cell);
+      textFieldCell.textField.delegate = self;
+      break;
+    }
     case ItemTypePassword: {
       TableViewTextEditCell* textFieldCell =
           base::mac::ObjCCastStrict<TableViewTextEditCell>(cell);
@@ -335,7 +373,6 @@
       cell.selectionStyle = UITableViewCellSelectionStyleDefault;
       break;
     case ItemTypeWebsite:
-    case ItemTypeUsername:
     case ItemTypeChangePasswordRecommendation:
       break;
   }
@@ -347,8 +384,10 @@
   NSInteger itemType = [self.tableViewModel itemTypeForIndexPath:indexPath];
   switch (itemType) {
     case ItemTypeWebsite:
-    case ItemTypeUsername:
       return NO;
+    case ItemTypeUsername:
+      return base::FeatureList::IsEnabled(
+          password_manager::features::kEditPasswordsInSettings);
     case ItemTypePassword:
       return YES;
   }
@@ -496,6 +535,7 @@
 }
 
 - (void)passwordEditingConfirmed {
+  self.password.username = self.usernameTextItem.textFieldValue;
   self.password.password = self.passwordTextItem.textFieldValue;
   [self.delegate passwordDetailsViewController:self
                         didEditPasswordDetails:self.password];
@@ -510,10 +550,12 @@
 - (BOOL)isItemAtIndexPathTextEditCell:(NSIndexPath*)cellPath {
   NSInteger itemType = [self.tableViewModel itemTypeForIndexPath:cellPath];
   switch (static_cast<ItemType>(itemType)) {
+    case ItemTypeUsername:
+      return base::FeatureList::IsEnabled(
+          password_manager::features::kEditPasswordsInSettings);
     case ItemTypePassword:
       return YES;
     case ItemTypeWebsite:
-    case ItemTypeUsername:
     case ItemTypeChangePasswordButton:
     case ItemTypeChangePasswordRecommendation:
       return NO;
diff --git a/ios/chrome/browser/ui/settings/password/passwords_settings_egtest.mm b/ios/chrome/browser/ui/settings/password/passwords_settings_egtest.mm
index ba4d7ced..180cec2 100644
--- a/ios/chrome/browser/ui/settings/password/passwords_settings_egtest.mm
+++ b/ios/chrome/browser/ui/settings/password/passwords_settings_egtest.mm
@@ -105,6 +105,12 @@
       inRoot:grey_accessibilityID(kPasswordsExportConfirmViewId)];
 }
 
+GREYElementInteraction* GetPasswordDetailTextFieldWithID(int detail_id) {
+  return GetInteractionForPasswordDetailItem(
+      grey_allOf(grey_accessibilityID(GetTextFieldForID(detail_id)),
+                 grey_kindOfClassName(@"UITextField"), nil));
+}
+
 // Matcher for "Saved Passwords" header in the password list.
 id<GREYMatcher> SavedPasswordsHeaderMatcher() {
   return grey_allOf(
@@ -183,6 +189,13 @@
                     grey_userInteractionEnabled(), nil);
 }
 
+// Matcher for the Confirm button in Confirmation Alert for password editing.
+id<GREYMatcher> EditConfirmationButton() {
+  return grey_allOf(ButtonWithAccessibilityLabel(
+                        l10n_util::GetNSString(IDS_IOS_CONFIRM_PASSWORD_EDIT)),
+                    grey_interactable(), nullptr);
+}
+
 // Matches the pop-up (call-out) menu item with accessibility label equal to the
 // translated string identified by |label|.
 id<GREYMatcher> PopUpMenuItemWithLabel(int label) {
@@ -264,9 +277,7 @@
 }
 
 void CopyPasswordDetailWithID(int detail_id) {
-  [GetInteractionForPasswordDetailItem(grey_allOf(
-      grey_accessibilityID(GetTextFieldForID(detail_id)),
-      grey_kindOfClassName(@"UITextField"), nil)) performAction:grey_tap()];
+  [GetPasswordDetailTextFieldWithID(detail_id) performAction:grey_tap()];
 
   // Tap the context menu item for copying.
   [[EarlGrey selectElementWithMatcher:PopUpMenuItemWithLabel(
@@ -305,6 +316,11 @@
   // TODO(crbug.com/1075494): Remove this once feature is launched.
   config.features_enabled.push_back(password_manager::features::kPasswordCheck);
 
+  if ([self isRunningTest:@selector(testEditUsername)]) {
+    config.features_enabled.push_back(
+        password_manager::features::kEditPasswordsInSettings);
+  }
+
   return config;
 }
 
@@ -1391,4 +1407,88 @@
       assertWithMatcher:grey_nil()];
 }
 
+// Checks that attempts to edit a password provide appropriate feedback.
+- (void)testEditPassword {
+  SaveExamplePasswordForm();
+
+  OpenPasswordSettings();
+
+  [GetInteractionForPasswordEntry(@"example.com, concrete username")
+      performAction:grey_tap()];
+
+  // Check the snackbar in case of successful reauthentication.
+  [PasswordSettingsAppInterface setUpMockReauthenticationModule];
+  [PasswordSettingsAppInterface mockReauthenticationModuleExpectedResult:
+                                    ReauthenticationResult::kSuccess];
+
+  TapEdit();
+
+  [[EarlGrey selectElementWithMatcher:PasswordDetailPassword()]
+      assertWithMatcher:grey_textFieldValue(@"concrete password")];
+
+  [[EarlGrey selectElementWithMatcher:PasswordDetailPassword()]
+      performAction:grey_replaceText(@"new password")];
+
+  [[EarlGrey selectElementWithMatcher:NavigationBarDoneButton()]
+      performAction:grey_tap()];
+
+  [[EarlGrey selectElementWithMatcher:EditConfirmationButton()]
+      performAction:grey_tap()];
+
+  TapEdit();
+
+  [[EarlGrey selectElementWithMatcher:PasswordDetailPassword()]
+      assertWithMatcher:grey_textFieldValue(@"new password")];
+
+  [[EarlGrey selectElementWithMatcher:SettingsMenuBackButton()]
+      performAction:grey_tap()];
+  [[EarlGrey selectElementWithMatcher:SettingsMenuBackButton()]
+      performAction:grey_tap()];
+  [[EarlGrey selectElementWithMatcher:SettingsDoneButton()]
+      performAction:grey_tap()];
+}
+
+// Checks that attempts to edit a username provide appropriate feedback.
+- (void)testEditUsername {
+  SaveExamplePasswordForm();
+
+  OpenPasswordSettings();
+
+  [GetInteractionForPasswordEntry(@"example.com, concrete username")
+      performAction:grey_tap()];
+
+  // Check the snackbar in case of successful reauthentication.
+  [PasswordSettingsAppInterface setUpMockReauthenticationModule];
+  [PasswordSettingsAppInterface mockReauthenticationModuleExpectedResult:
+                                    ReauthenticationResult::kSuccess];
+
+  TapEdit();
+
+  [[EarlGrey selectElementWithMatcher:PasswordDetailUsername()]
+      assertWithMatcher:grey_textFieldValue(@"concrete username")];
+
+  [[EarlGrey selectElementWithMatcher:PasswordDetailUsername()]
+      performAction:grey_replaceText(@"new username")];
+
+  [[EarlGrey selectElementWithMatcher:NavigationBarDoneButton()]
+      performAction:grey_tap()];
+
+  [[EarlGrey selectElementWithMatcher:EditConfirmationButton()]
+      performAction:grey_tap()];
+
+  [[EarlGrey selectElementWithMatcher:PasswordDetailUsername()]
+      assertWithMatcher:grey_textFieldValue(@"new username")];
+
+  [[EarlGrey selectElementWithMatcher:SettingsMenuBackButton()]
+      performAction:grey_tap()];
+
+  [GetInteractionForPasswordEntry(@"example.com, new username")
+      assertWithMatcher:grey_notNil()];
+
+  [[EarlGrey selectElementWithMatcher:SettingsMenuBackButton()]
+      performAction:grey_tap()];
+  [[EarlGrey selectElementWithMatcher:SettingsDoneButton()]
+      performAction:grey_tap()];
+}
+
 @end
diff --git a/media/gpu/vaapi/vaapi_unittest.cc b/media/gpu/vaapi/vaapi_unittest.cc
index f1a2a688..f9484430 100644
--- a/media/gpu/vaapi/vaapi_unittest.cc
+++ b/media/gpu/vaapi/vaapi_unittest.cc
@@ -31,13 +31,19 @@
 base::Optional<VAProfile> ConvertToVAProfile(VideoCodecProfile profile) {
   // A map between VideoCodecProfile and VAProfile.
   const std::map<VideoCodecProfile, VAProfile> kProfileMap = {
-      // VAProfileH264Baseline is deprecated in <va/va.h> from libva 2.0.0.
-      {H264PROFILE_BASELINE, VAProfileH264ConstrainedBaseline},
-      {H264PROFILE_MAIN, VAProfileH264Main},
-      {H264PROFILE_HIGH, VAProfileH264High},
-      {VP8PROFILE_ANY, VAProfileVP8Version0_3},
-      {VP9PROFILE_PROFILE0, VAProfileVP9Profile0},
-      {VP9PROFILE_PROFILE2, VAProfileVP9Profile2},
+    // VAProfileH264Baseline is deprecated in <va/va.h> from libva 2.0.0.
+    {H264PROFILE_BASELINE, VAProfileH264ConstrainedBaseline},
+    {H264PROFILE_MAIN, VAProfileH264Main},
+    {H264PROFILE_HIGH, VAProfileH264High},
+    {VP8PROFILE_ANY, VAProfileVP8Version0_3},
+    {VP9PROFILE_PROFILE0, VAProfileVP9Profile0},
+    {VP9PROFILE_PROFILE2, VAProfileVP9Profile2},
+#if defined(OS_CHROMEOS)
+    // TODO(hiroh): Remove if-macro once libva for linux-chrome is upreved to
+    // 2.9.0 or newer.
+    // https://source.chromium.org/chromium/chromium/src/+/master:build/linux/sysroot_scripts/generated_package_lists/sid.amd64
+    {AV1PROFILE_PROFILE_MAIN, VAProfileAV1Profile0},
+#endif
   };
   auto it = kProfileMap.find(profile);
   return it != kProfileMap.end() ? base::make_optional<VAProfile>(it->second)
@@ -47,17 +53,23 @@
 // Converts the given string to VAProfile
 base::Optional<VAProfile> StringToVAProfile(const std::string& va_profile) {
   const std::map<std::string, VAProfile> kStringToVAProfile = {
-      {"VAProfileNone", VAProfileNone},
-      {"VAProfileH264ConstrainedBaseline", VAProfileH264ConstrainedBaseline},
-      // Even though it's deprecated, we leave VAProfileH264Baseline's
-      // translation here to assert we never encounter it.
-      {"VAProfileH264Baseline", VAProfileH264Baseline},
-      {"VAProfileH264Main", VAProfileH264Main},
-      {"VAProfileH264High", VAProfileH264High},
-      {"VAProfileJPEGBaseline", VAProfileJPEGBaseline},
-      {"VAProfileVP8Version0_3", VAProfileVP8Version0_3},
-      {"VAProfileVP9Profile0", VAProfileVP9Profile0},
-      {"VAProfileVP9Profile2", VAProfileVP9Profile2},
+    {"VAProfileNone", VAProfileNone},
+    {"VAProfileH264ConstrainedBaseline", VAProfileH264ConstrainedBaseline},
+    // Even though it's deprecated, we leave VAProfileH264Baseline's
+    // translation here to assert we never encounter it.
+    {"VAProfileH264Baseline", VAProfileH264Baseline},
+    {"VAProfileH264Main", VAProfileH264Main},
+    {"VAProfileH264High", VAProfileH264High},
+    {"VAProfileJPEGBaseline", VAProfileJPEGBaseline},
+    {"VAProfileVP8Version0_3", VAProfileVP8Version0_3},
+    {"VAProfileVP9Profile0", VAProfileVP9Profile0},
+    {"VAProfileVP9Profile2", VAProfileVP9Profile2},
+#if defined(OS_CHROMEOS)
+    // TODO(hiroh): Remove if-macro once libva for linux-chrome is upreved to
+    // 2.9.0 or newer.
+    // https://source.chromium.org/chromium/chromium/src/+/master:build/linux/sysroot_scripts/generated_package_lists/sid.amd64
+    {"VAProfileAV1Profile0", VAProfileAV1Profile0},
+#endif
   };
 
   auto it = kStringToVAProfile.find(va_profile);
diff --git a/media/gpu/vaapi/vaapi_video_decode_accelerator.cc b/media/gpu/vaapi/vaapi_video_decode_accelerator.cc
index 3772ad5..007bc01 100644
--- a/media/gpu/vaapi/vaapi_video_decode_accelerator.cc
+++ b/media/gpu/vaapi/vaapi_video_decode_accelerator.cc
@@ -1195,9 +1195,12 @@
     const gpu::GpuDriverBugWorkarounds& workarounds) {
   VideoDecodeAccelerator::SupportedProfiles profiles =
       VaapiWrapper::GetSupportedDecodeProfiles(workarounds);
-  // VaVDA never supported VP9 Profile 2, but VaapiWrapper does. Filter it out.
+  // VaVDA never supported VP9 Profile 2 and AV1, but VaapiWrapper does. Filter
+  // them out.
   base::EraseIf(profiles, [](const auto& profile) {
-    return profile.profile == VP9PROFILE_PROFILE2;
+    return profile.profile == VP9PROFILE_PROFILE2 ||
+           VideoCodecProfileToVideoCodec(profile.profile) ==
+               VideoCodec::kCodecAV1;
   });
   return profiles;
 }
diff --git a/media/gpu/vaapi/vaapi_wrapper.cc b/media/gpu/vaapi/vaapi_wrapper.cc
index 6a0ae64..b7bb0cb 100644
--- a/media/gpu/vaapi/vaapi_wrapper.cc
+++ b/media/gpu/vaapi/vaapi_wrapper.cc
@@ -342,17 +342,25 @@
   static const base::NoDestructor<ProfileCodecMap> kMediaToVAProfileMap({
       // VAProfileH264Baseline is deprecated in <va/va.h> since libva 2.0.0.
       {H264PROFILE_BASELINE, VAProfileH264ConstrainedBaseline},
-      {H264PROFILE_MAIN, VAProfileH264Main},
-      // TODO(posciak): See if we can/want to support other variants of
-      // H264PROFILE_HIGH*.
-      {H264PROFILE_HIGH, VAProfileH264High},
-      {VP8PROFILE_ANY, VAProfileVP8Version0_3},
-      {VP9PROFILE_PROFILE0, VAProfileVP9Profile0},
-      // VaapiWrapper does not support VP9 Profile 1, see b/153680337.
-      // {VP9PROFILE_PROFILE1, VAProfileVP9Profile1},
-      {VP9PROFILE_PROFILE2, VAProfileVP9Profile2},
+          {H264PROFILE_MAIN, VAProfileH264Main},
+          // TODO(posciak): See if we can/want to support other variants of
+          // H264PROFILE_HIGH*.
+          {H264PROFILE_HIGH, VAProfileH264High},
+          {VP8PROFILE_ANY, VAProfileVP8Version0_3},
+          {VP9PROFILE_PROFILE0, VAProfileVP9Profile0},
+          // VaapiWrapper does not support VP9 Profile 1, see b/153680337.
+          // {VP9PROFILE_PROFILE1, VAProfileVP9Profile1},
+          {VP9PROFILE_PROFILE2, VAProfileVP9Profile2},
       // VaapiWrapper does not support Profile 3.
       //{VP9PROFILE_PROFILE3, VAProfileVP9Profile3},
+#if defined(OS_CHROMEOS)
+          // TODO(hiroh): Remove if-macro once libva for linux-chrome is upreved
+          // to 2.9.0 or newer.
+          // https://source.chromium.org/chromium/chromium/src/+/master:build/linux/sysroot_scripts/generated_package_lists/sid.amd64
+          {AV1PROFILE_PROFILE_MAIN, VAProfileAV1Profile0},
+#endif  // defined (OS_CHROMEOS)
+        // VaapiWrapper does not support AV1 Profile 1.
+        // {AV1PROFILE_PROFILE_HIGH, VAProfileAV1Profile1},
   });
   return *kMediaToVAProfileMap;
 }
diff --git a/media/gpu/windows/dxva_video_decode_accelerator_win.cc b/media/gpu/windows/dxva_video_decode_accelerator_win.cc
index d9ed085..e72b5c4 100644
--- a/media/gpu/windows/dxva_video_decode_accelerator_win.cc
+++ b/media/gpu/windows/dxva_video_decode_accelerator_win.cc
@@ -617,7 +617,6 @@
       processing_config_changed_(false),
       use_empty_video_hdr_metadata_(workarounds.use_empty_video_hdr_metadata) {
   weak_ptr_ = weak_this_factory_.GetWeakPtr();
-  pb_weak_ptr_ = pb_weak_this_factory_.GetWeakPtr();
   memset(&input_stream_info_, 0, sizeof(input_stream_info_));
   memset(&output_stream_info_, 0, sizeof(output_stream_info_));
   use_color_info_ = base::FeatureList::IsEnabled(kVideoBlitColorAccuracy);
@@ -1139,7 +1138,7 @@
           FROM_HERE,
           base::BindOnce(
               &DXVAVideoDecodeAccelerator::DeferredDismissStaleBuffer,
-              pb_weak_ptr_, picture_buffer_id));
+              weak_ptr_, picture_buffer_id));
     }
     return;
   }
@@ -1199,7 +1198,7 @@
     main_thread_task_runner_->PostDelayedTask(
         FROM_HERE,
         base::BindOnce(&DXVAVideoDecodeAccelerator::WaitForOutputBuffer,
-                       pb_weak_ptr_, picture_buffer_id, count + 1),
+                       weak_ptr_, picture_buffer_id, count + 1),
         base::TimeDelta::FromMilliseconds(kFlushDecoderSurfaceTimeoutMs));
     return;
   }
@@ -1848,7 +1847,7 @@
   main_thread_task_runner_->PostTask(
       FROM_HERE,
       base::BindOnce(&DXVAVideoDecodeAccelerator::RequestPictureBuffers,
-                     pb_weak_ptr_, width, height));
+                     weak_ptr_, width, height));
 
   pictures_requested_ = true;
   return true;
@@ -2011,9 +2010,6 @@
   // resolution changes. We already handle that in the
   // HandleResolutionChanged() function.
   if (GetState() != kConfigChange) {
-    pb_weak_this_factory_.InvalidateWeakPtrs();
-    pb_weak_ptr_ = pb_weak_this_factory_.GetWeakPtr();
-
     output_picture_buffers_.clear();
     stale_output_picture_buffers_.clear();
     // We want to continue processing pending input after detecting a config
@@ -2339,12 +2335,12 @@
   main_thread_task_runner_->PostTask(
       FROM_HERE,
       base::BindOnce(&DXVAVideoDecodeAccelerator::DismissStaleBuffers,
-                     pb_weak_ptr_, false));
+                     weak_ptr_, false));
 
   main_thread_task_runner_->PostTask(
       FROM_HERE,
       base::BindOnce(&DXVAVideoDecodeAccelerator::RequestPictureBuffers,
-                     pb_weak_ptr_, width, height));
+                     weak_ptr_, width, height));
 }
 
 void DXVAVideoDecodeAccelerator::DismissStaleBuffers(bool force) {
diff --git a/media/gpu/windows/dxva_video_decode_accelerator_win.h b/media/gpu/windows/dxva_video_decode_accelerator_win.h
index de916b6..430b01b 100644
--- a/media/gpu/windows/dxva_video_decode_accelerator_win.h
+++ b/media/gpu/windows/dxva_video_decode_accelerator_win.h
@@ -532,7 +532,6 @@
   // thread safety of reaching into this class from multiple threads to
   // attain a WeakPtr.
   base::WeakPtr<DXVAVideoDecodeAccelerator> weak_ptr_;
-  base::WeakPtr<DXVAVideoDecodeAccelerator> pb_weak_ptr_;
 
   // Set to true if we are in the context of a Flush operation. Used to prevent
   // multiple flush done notifications being sent out.
@@ -614,9 +613,6 @@
   // WeakPtrFactory for posting tasks back to |this|.
   base::WeakPtrFactory<DXVAVideoDecodeAccelerator> weak_this_factory_{this};
 
-  // WeakPtrFactory for posting picture buffer related tasks back to |this|.
-  base::WeakPtrFactory<DXVAVideoDecodeAccelerator> pb_weak_this_factory_{this};
-
   // Function pointer for the MFCreateDXGIDeviceManager API.
   static CreateDXGIDeviceManager create_dxgi_device_manager_;
 
diff --git a/rlz/test/rlz_test_helpers.cc b/rlz/test/rlz_test_helpers.cc
index 3aaea20..040cbdb 100644
--- a/rlz/test/rlz_test_helpers.cc
+++ b/rlz/test/rlz_test_helpers.cc
@@ -12,6 +12,7 @@
 #include <map>
 #include <vector>
 
+#include "base/notreached.h"
 #include "base/strings/string16.h"
 #include "build/build_config.h"
 #include "rlz/lib/rlz_lib.h"
diff --git a/services/device/public/cpp/test/fake_usb_device_manager.cc b/services/device/public/cpp/test/fake_usb_device_manager.cc
index fcd876e..c1aa9180 100644
--- a/services/device/public/cpp/test/fake_usb_device_manager.cc
+++ b/services/device/public/cpp/test/fake_usb_device_manager.cc
@@ -90,6 +90,7 @@
 void FakeUsbDeviceManager::OpenFileDescriptor(
     const std::string& guid,
     uint32_t drop_privileges_mask,
+    mojo::PlatformHandle lifeline_fd,
     OpenFileDescriptorCallback callback) {
   std::move(callback).Run(base::File(
       base::FilePath(FILE_PATH_LITERAL("/dev/null")),
diff --git a/services/device/public/cpp/test/fake_usb_device_manager.h b/services/device/public/cpp/test/fake_usb_device_manager.h
index cf9bef5..edacb3aa 100644
--- a/services/device/public/cpp/test/fake_usb_device_manager.h
+++ b/services/device/public/cpp/test/fake_usb_device_manager.h
@@ -90,6 +90,7 @@
 
   void OpenFileDescriptor(const std::string& guid,
                           uint32_t drop_privileges_mask,
+                          mojo::PlatformHandle lifeline_fd,
                           OpenFileDescriptorCallback callback) override;
 #endif  // defined(OS_CHROMEOS)
 
diff --git a/services/device/public/mojom/usb_manager.mojom b/services/device/public/mojom/usb_manager.mojom
index 7f462648..cd0c3e00 100644
--- a/services/device/public/mojom/usb_manager.mojom
+++ b/services/device/public/mojom/usb_manager.mojom
@@ -45,9 +45,12 @@
 
   // Attempt to open a USB device using permission_broker and return
   // a file descriptor. Allow access only to interfaces specified in
-  // |allowed_interfaces_mask|.
+  // |allowed_interfaces_mask|. The |lifeline_fd| should be the remote end of
+  // a pipe created locally, and when this pipe is closed permission_broker
+  // reattaches any kernel drivers that may have been detached when opening.
   [EnableIf=is_chromeos]
-  OpenFileDescriptor(string guid, uint32 allowed_interfaces_mask)
+  OpenFileDescriptor(string guid, uint32 allowed_interfaces_mask,
+                     handle<platform> lifeline_fd)
       => (mojo_base.mojom.File? fd);
 
   // Sets the client for this DeviceManager service. The service will notify its
diff --git a/services/device/usb/mojo/device_manager_impl.cc b/services/device/usb/mojo/device_manager_impl.cc
index 521059f..a60fa63 100644
--- a/services/device/usb/mojo/device_manager_impl.cc
+++ b/services/device/usb/mojo/device_manager_impl.cc
@@ -13,6 +13,7 @@
 
 #include "base/bind.h"
 #include "base/callback_helpers.h"
+#include "base/files/file_util.h"
 #include "base/memory/ptr_util.h"
 #include "mojo/public/cpp/bindings/associated_remote.h"
 #include "services/device/public/cpp/usb/usb_utils.h"
@@ -130,6 +131,7 @@
 void DeviceManagerImpl::OpenFileDescriptor(
     const std::string& guid,
     uint32_t drop_privileges_mask,
+    mojo::PlatformHandle lifeline_fd,
     OpenFileDescriptorCallback callback) {
   scoped_refptr<UsbDevice> device = usb_service_->GetDevice(guid);
   if (!device) {
@@ -140,8 +142,11 @@
         base::AdaptCallbackForRepeating(std::move(callback));
     auto devpath =
         static_cast<device::UsbDeviceLinux*>(device.get())->device_path();
-    chromeos::PermissionBrokerClient::Get()->OpenPathWithDroppedPrivileges(
-        devpath, drop_privileges_mask,
+
+    // The |lifeline_fd| passed through D-Bus gets is duped, so we need to close
+    // our original.
+    chromeos::PermissionBrokerClient::Get()->ClaimDevicePath(
+        devpath, drop_privileges_mask, lifeline_fd.GetFD().get(),
         base::BindOnce(&DeviceManagerImpl::OnOpenFileDescriptor,
                        weak_factory_.GetWeakPtr(), copyable_callback),
         base::BindOnce(&DeviceManagerImpl::OnOpenFileDescriptorError,
diff --git a/services/device/usb/mojo/device_manager_impl.h b/services/device/usb/mojo/device_manager_impl.h
index e73df06b..0d3c5e6 100644
--- a/services/device/usb/mojo/device_manager_impl.h
+++ b/services/device/usb/mojo/device_manager_impl.h
@@ -75,6 +75,7 @@
 
   void OpenFileDescriptor(const std::string& guid,
                           uint32_t drop_privileges_mask,
+                          mojo::PlatformHandle lifeline_fd,
                           OpenFileDescriptorCallback callback) override;
 
   void OnOpenFileDescriptor(OpenFileDescriptorCallback callback,
diff --git a/services/metrics/public/cpp/ukm_recorder.h b/services/metrics/public/cpp/ukm_recorder.h
index 7e2ec0a..f8aafce1 100644
--- a/services/metrics/public/cpp/ukm_recorder.h
+++ b/services/metrics/public/cpp/ukm_recorder.h
@@ -33,6 +33,10 @@
 class DesktopWebAppUkmRecorder;
 }
 
+namespace weblayer {
+class BackgroundSyncDelegateImpl;
+}
+
 namespace ukm {
 
 class DelegatingUkmRecorder;
@@ -96,6 +100,7 @@
       const GURL& service_worker_scope);
 
  private:
+  friend weblayer::BackgroundSyncDelegateImpl;
   friend DelegatingUkmRecorder;
   friend TestRecordingHelper;
   friend UkmBackgroundRecorderService;
diff --git a/services/network/DIR_METADATA b/services/network/DIR_METADATA
new file mode 100644
index 0000000..1fd3fb96
--- /dev/null
+++ b/services/network/DIR_METADATA
@@ -0,0 +1,11 @@
+# Metadata information for this directory.
+#
+# For more information on DIR_METADATA files, see:
+#   https://source.chromium.org/chromium/infra/infra/+/master:go/src/infra/tools/dirmd/README.md
+#
+# For the schema of this file, see Metadata message:
+#   https://source.chromium.org/chromium/infra/infra/+/master:go/src/infra/tools/dirmd/proto/dir_metadata.proto
+
+monorail {
+  component: "Internals>Services>Network"
+}
\ No newline at end of file
diff --git a/services/network/OWNERS b/services/network/OWNERS
index 42433e4..39840e6 100644
--- a/services/network/OWNERS
+++ b/services/network/OWNERS
@@ -39,5 +39,3 @@
 # Content Security Policy
 per-file content_security_policy*=lfg@chromium.org
 per-file content_security_policy*=nasko@chromium.org
-
-# COMPONENT: Internals>Services>Network
diff --git a/services/network/cors/DIR_METADATA b/services/network/cors/DIR_METADATA
new file mode 100644
index 0000000..df937dae
--- /dev/null
+++ b/services/network/cors/DIR_METADATA
@@ -0,0 +1,11 @@
+# Metadata information for this directory.
+#
+# For more information on DIR_METADATA files, see:
+#   https://source.chromium.org/chromium/infra/infra/+/master:go/src/infra/tools/dirmd/README.md
+#
+# For the schema of this file, see Metadata message:
+#   https://source.chromium.org/chromium/infra/infra/+/master:go/src/infra/tools/dirmd/proto/dir_metadata.proto
+
+monorail {
+  component: "Blink>SecurityFeature>CORS"
+}
\ No newline at end of file
diff --git a/services/network/cors/OWNERS b/services/network/cors/OWNERS
deleted file mode 100644
index e1d25b65..0000000
--- a/services/network/cors/OWNERS
+++ /dev/null
@@ -1 +0,0 @@
-# COMPONENT: Blink>SecurityFeature>CORS
diff --git a/services/network/origin_policy/DIR_METADATA b/services/network/origin_policy/DIR_METADATA
new file mode 100644
index 0000000..a53fa43
--- /dev/null
+++ b/services/network/origin_policy/DIR_METADATA
@@ -0,0 +1,11 @@
+# Metadata information for this directory.
+#
+# For more information on DIR_METADATA files, see:
+#   https://source.chromium.org/chromium/infra/infra/+/master:go/src/infra/tools/dirmd/README.md
+#
+# For the schema of this file, see Metadata message:
+#   https://source.chromium.org/chromium/infra/infra/+/master:go/src/infra/tools/dirmd/proto/dir_metadata.proto
+
+monorail {
+  component: "Blink>SecurityFeature"
+}
\ No newline at end of file
diff --git a/services/network/origin_policy/OWNERS b/services/network/origin_policy/OWNERS
index f6ee74b..9d3ad846 100644
--- a/services/network/origin_policy/OWNERS
+++ b/services/network/origin_policy/OWNERS
@@ -1,5 +1,3 @@
 andypaicu@chromium.org
 vogelheim@chromium.org
 mkwst@chromium.org
-
-# COMPONENT: Blink>SecurityFeature
diff --git a/services/network/p2p/DIR_METADATA b/services/network/p2p/DIR_METADATA
new file mode 100644
index 0000000..448c614
--- /dev/null
+++ b/services/network/p2p/DIR_METADATA
@@ -0,0 +1,11 @@
+# Metadata information for this directory.
+#
+# For more information on DIR_METADATA files, see:
+#   https://source.chromium.org/chromium/infra/infra/+/master:go/src/infra/tools/dirmd/README.md
+#
+# For the schema of this file, see Metadata message:
+#   https://source.chromium.org/chromium/infra/infra/+/master:go/src/infra/tools/dirmd/proto/dir_metadata.proto
+
+monorail {
+  component: "Blink>WebRTC"
+}
\ No newline at end of file
diff --git a/services/network/p2p/OWNERS b/services/network/p2p/OWNERS
index 90532e4..4e94c27 100644
--- a/services/network/p2p/OWNERS
+++ b/services/network/p2p/OWNERS
@@ -1,5 +1,3 @@
 guidou@chromium.org
 hta@chromium.org
 sergeyu@chromium.org
-
-# COMPONENT: Blink>WebRTC
diff --git a/services/network/public/DIR_METADATA b/services/network/public/DIR_METADATA
new file mode 100644
index 0000000..1fd3fb96
--- /dev/null
+++ b/services/network/public/DIR_METADATA
@@ -0,0 +1,11 @@
+# Metadata information for this directory.
+#
+# For more information on DIR_METADATA files, see:
+#   https://source.chromium.org/chromium/infra/infra/+/master:go/src/infra/tools/dirmd/README.md
+#
+# For the schema of this file, see Metadata message:
+#   https://source.chromium.org/chromium/infra/infra/+/master:go/src/infra/tools/dirmd/proto/dir_metadata.proto
+
+monorail {
+  component: "Internals>Services>Network"
+}
\ No newline at end of file
diff --git a/services/network/public/OWNERS b/services/network/public/OWNERS
deleted file mode 100644
index 06c2e2b..0000000
--- a/services/network/public/OWNERS
+++ /dev/null
@@ -1 +0,0 @@
-# COMPONENT: Internals>Services>Network
diff --git a/services/network/public/cpp/cert_verifier/DIR_METADATA b/services/network/public/cpp/cert_verifier/DIR_METADATA
new file mode 100644
index 0000000..c97d184
--- /dev/null
+++ b/services/network/public/cpp/cert_verifier/DIR_METADATA
@@ -0,0 +1,11 @@
+# Metadata information for this directory.
+#
+# For more information on DIR_METADATA files, see:
+#   https://source.chromium.org/chromium/infra/infra/+/master:go/src/infra/tools/dirmd/README.md
+#
+# For the schema of this file, see Metadata message:
+#   https://source.chromium.org/chromium/infra/infra/+/master:go/src/infra/tools/dirmd/proto/dir_metadata.proto
+
+monorail {
+  component: "Internals>Network>Certificate"
+}
\ No newline at end of file
diff --git a/services/network/public/cpp/cert_verifier/OWNERS b/services/network/public/cpp/cert_verifier/OWNERS
index 9c391969..83e4ddc93 100644
--- a/services/network/public/cpp/cert_verifier/OWNERS
+++ b/services/network/public/cpp/cert_verifier/OWNERS
@@ -4,5 +4,3 @@
 per-file *_mojom_traits*.*=file://ipc/SECURITY_OWNERS
 per-file *.typemap=set noparent
 per-file *.typemap=file://ipc/SECURITY_OWNERS
-
-# COMPONENT: Internals>Network>Certificate
diff --git a/services/network/public/cpp/url_request_mojom_traits.cc b/services/network/public/cpp/url_request_mojom_traits.cc
index 0bb41983..a6abb4e 100644
--- a/services/network/public/cpp/url_request_mojom_traits.cc
+++ b/services/network/public/cpp/url_request_mojom_traits.cc
@@ -270,8 +270,12 @@
     return false;
   }
   if (data.type() == network::mojom::DataElementType::kBytes) {
-    if (!data.ReadBuf(&out->buf_))
+    mojo_base::BigBufferView big_buffer;
+    if (!data.ReadBuf(&big_buffer))
       return false;
+    out->buf_.clear();
+    out->buf_.insert(out->buf_.end(), big_buffer.data().begin(),
+                     big_buffer.data().end());
   }
   out->type_ = data.type();
   out->data_pipe_getter_ = data.TakeDataPipeGetter<
diff --git a/services/network/public/cpp/url_request_mojom_traits.h b/services/network/public/cpp/url_request_mojom_traits.h
index 6995a9f..e458ff0 100644
--- a/services/network/public/cpp/url_request_mojom_traits.h
+++ b/services/network/public/cpp/url_request_mojom_traits.h
@@ -10,6 +10,7 @@
 
 #include "base/component_export.h"
 #include "base/memory/scoped_refptr.h"
+#include "mojo/public/cpp/base/big_buffer_mojom_traits.h"
 #include "mojo/public/cpp/base/file_mojom_traits.h"
 #include "mojo/public/cpp/base/file_path_mojom_traits.h"
 #include "mojo/public/cpp/base/time_mojom_traits.h"
@@ -308,8 +309,8 @@
       const network::DataElement& element) {
     return element.type_;
   }
-  static const std::vector<uint8_t>& buf(const network::DataElement& element) {
-    return element.buf_;
+  static mojo_base::BigBufferView buf(const network::DataElement& element) {
+    return mojo_base::BigBufferView(element.buf_);
   }
   static const base::FilePath& path(const network::DataElement& element) {
     return element.path_;
diff --git a/services/network/public/mojom/url_loader.mojom b/services/network/public/mojom/url_loader.mojom
index 972ff20b..399a2e2 100644
--- a/services/network/public/mojom/url_loader.mojom
+++ b/services/network/public/mojom/url_loader.mojom
@@ -423,7 +423,7 @@
   DataElementType type;
 
   // For kBytes.
-  array<uint8> buf;
+  mojo_base.mojom.BigBuffer buf;
   // For kFile
   mojo_base.mojom.FilePath path;
   // For kDataPipe
diff --git a/services/network/resource_scheduler/DIR_METADATA b/services/network/resource_scheduler/DIR_METADATA
new file mode 100644
index 0000000..2107bb9
--- /dev/null
+++ b/services/network/resource_scheduler/DIR_METADATA
@@ -0,0 +1,11 @@
+# Metadata information for this directory.
+#
+# For more information on DIR_METADATA files, see:
+#   https://source.chromium.org/chromium/infra/infra/+/master:go/src/infra/tools/dirmd/README.md
+#
+# For the schema of this file, see Metadata message:
+#   https://source.chromium.org/chromium/infra/infra/+/master:go/src/infra/tools/dirmd/proto/dir_metadata.proto
+
+monorail {
+  component: "Internals>Network>NetworkQuality"
+}
\ No newline at end of file
diff --git a/services/network/resource_scheduler/OWNERS b/services/network/resource_scheduler/OWNERS
index bd5f1d8..c3b8dc2 100644
--- a/services/network/resource_scheduler/OWNERS
+++ b/services/network/resource_scheduler/OWNERS
@@ -1,4 +1,2 @@
 tbansal@chromium.org
 ryansturm@chromium.org
-
-# COMPONENT: Internals>Network>NetworkQuality
\ No newline at end of file
diff --git a/sql/database.cc b/sql/database.cc
index db46be6..59f1959d 100644
--- a/sql/database.cc
+++ b/sql/database.cc
@@ -233,19 +233,15 @@
   was_valid_ = was_valid_ && forced;
 }
 
-static_assert(
-    Database::kDefaultPageSize == SQLITE_DEFAULT_PAGE_SIZE,
-    "Database::kDefaultPageSize must match the value configured into SQLite");
+static_assert(DatabaseOptions::kDefaultPageSize == SQLITE_DEFAULT_PAGE_SIZE,
+              "DatabaseOptions::kDefaultPageSize must match the value "
+              "configured into SQLite");
 
-constexpr int Database::kDefaultPageSize;
+Database::Database() : Database({.exclusive_locking = false}) {}
 
-Database::Database()
+Database::Database(DatabaseOptions options)
     : db_(nullptr),
-      page_size_(kDefaultPageSize),
-      cache_size_(0),
-      exclusive_locking_(false),
-      want_wal_mode_(
-          base::FeatureList::IsEnabled(features::kEnableWALModeByDefault)),
+      options_(options),
       transaction_nesting_(0),
       needs_rollback_(false),
       in_memory_(false),
@@ -254,7 +250,12 @@
       mmap_disabled_(!enable_mmap_by_default_),
       mmap_enabled_(false),
       total_changes_at_last_release_(0),
-      stats_histogram_(nullptr) {}
+      stats_histogram_(nullptr) {
+  DCHECK_GE(options.page_size, 512);
+  DCHECK_LE(options.page_size, 65536);
+  DCHECK(!(options.page_size & (options.page_size - 1)))
+      << "page_size must be a power of two";
+}
 
 Database::~Database() {
   Close();
@@ -821,7 +822,7 @@
   }
 
   const std::string page_size_sql =
-      base::StringPrintf("PRAGMA page_size=%d", page_size_);
+      base::StringPrintf("PRAGMA page_size=%d", options_.page_size);
   if (!null_db.Execute(page_size_sql.c_str()))
     return false;
 
@@ -1519,7 +1520,7 @@
   // enabled.
   //
   // TODO(crbug.com/1120969): Remove support for non-exclusive mode.
-  if (!exclusive_locking_) {
+  if (!options_.exclusive_locking) {
     err = ExecuteAndReturnErrorCode("PRAGMA locking_mode=NORMAL");
     if (err != SQLITE_OK)
       return false;
@@ -1562,7 +1563,7 @@
   // Needs to happen before entering WAL mode. Will only work if this the first
   // time the database is being opened in WAL mode.
   const std::string page_size_sql =
-      base::StringPrintf("PRAGMA page_size=%d", page_size_);
+      base::StringPrintf("PRAGMA page_size=%d", options_.page_size);
   ignore_result(ExecuteWithTimeout(page_size_sql.c_str(), kBusyTimeout));
 
   // http://www.sqlite.org/pragma.html#pragma_journal_mode
@@ -1594,9 +1595,9 @@
     ignore_result(Execute("PRAGMA journal_mode=TRUNCATE"));
   }
 
-  if (cache_size_ != 0) {
+  if (options_.cache_size != 0) {
     const std::string cache_size_sql =
-        base::StringPrintf("PRAGMA cache_size=%d", cache_size_);
+        base::StringPrintf("PRAGMA cache_size=%d", options_.cache_size);
     ignore_result(ExecuteWithTimeout(cache_size_sql.c_str(), kBusyTimeout));
   }
 
@@ -1822,9 +1823,9 @@
   // locking, because this case does not require shared memory support.
   // At the time this was implemented (May 2020), Fuchsia's shared
   // memory support was insufficient for SQLite's needs.
-  return want_wal_mode_ && exclusive_locking_;
+  return options_.wal_mode && options_.exclusive_locking;
 #else
-  return want_wal_mode_;
+  return options_.wal_mode;
 #endif  // defined(OS_FUCHSIA)
 }
 
diff --git a/sql/database.h b/sql/database.h
index 6e4334e..c8f365e 100644
--- a/sql/database.h
+++ b/sql/database.h
@@ -17,6 +17,7 @@
 #include "base/compiler_specific.h"
 #include "base/component_export.h"
 #include "base/containers/flat_map.h"
+#include "base/feature_list.h"
 #include "base/gtest_prod_util.h"
 #include "base/macros.h"
 #include "base/memory/ref_counted.h"
@@ -24,6 +25,7 @@
 #include "base/sequence_checker.h"
 #include "base/threading/scoped_blocking_call.h"
 #include "sql/internal_api_token.h"
+#include "sql/sql_features.h"
 #include "sql/statement_id.h"
 
 struct sqlite3;
@@ -46,6 +48,46 @@
 class ScopedErrorExpecter;
 }  // namespace test
 
+struct COMPONENT_EXPORT(SQL) DatabaseOptions {
+  // Default page size for newly created databases.
+  //
+  // Guaranteed to match SQLITE_DEFAULT_PAGE_SIZE.
+  static constexpr int kDefaultPageSize = 4096;
+
+  // If true, the database can only be opened by one process at a time.
+  //
+  // Exclusive mode is strongly recommended. It reduces the I/O cost of setting
+  // up a transaction. It also removes the need of handling transaction failures
+  // due to lock contention.
+  bool exclusive_locking = true;
+
+  // If true, enables SQLite's Write-Ahead Logging (WAL).
+  //
+  // WAL integration is under development, and should not be used in shipping
+  // Chrome features yet. In particular, our custom database recovery code does
+  // not support the WAL log file.
+  //
+  // More details at https://www.sqlite.org/wal.html
+  bool wal_mode =
+      base::FeatureList::IsEnabled(sql::features::kEnableWALModeByDefault);
+
+  // Database page size.
+  //
+  // Larger page sizes result in shallower B-trees, because they allow an inner
+  // page to hold more keys. On the flip side, larger page sizes may result in
+  // more I/O when making small changes to existing records.
+  int page_size = kDefaultPageSize;
+
+  // The size of in-memory cache, in pages.
+  //
+  // SQLite's database cache will take up at most (`page_size` * `cache_size`)
+  // bytes of RAM.
+  //
+  // 0 invokes SQLite's default, which is currently to size up the cache to use
+  // exactly 2,048,000 bytes of RAM.
+  int cache_size = 0;
+};
+
 // Handle to an open SQLite database.
 //
 // Instances of this class are thread-unsafe and DCHECK that they are accessed
@@ -57,7 +99,13 @@
  public:
   // The database is opened by calling Open[InMemory](). Any uncommitted
   // transactions will be rolled back when this object is deleted.
+  //
+  // This constructor is deprecated.
+  // TODO(crbug.com/1126968): Remove this constructor after migrating all
+  //                          uses to the explicit constructor below.
   Database();
+  // |options| only affects newly created databases.
+  explicit Database(DatabaseOptions options);
   ~Database();
 
   // Allows mmapping to be disabled globally by default in the calling process.
@@ -79,11 +127,11 @@
     DCHECK(!(page_size & (page_size - 1)))
         << "page_size must be a power of two";
 
-    page_size_ = page_size;
+    options_.page_size = page_size;
   }
 
   // The page size that will be used when creating a new database.
-  int page_size() const { return page_size_; }
+  int page_size() const { return options_.page_size; }
 
   // Sets the number of pages that will be cached in memory by sqlite. The
   // total cache size in bytes will be page_size * cache_size. This must be
@@ -91,7 +139,7 @@
   void set_cache_size(int cache_size) {
     DCHECK_GE(cache_size, 0);
 
-    cache_size_ = cache_size;
+    options_.cache_size = cache_size;
   }
 
   // Returns whether a database will be opened in WAL mode.
@@ -109,7 +157,7 @@
   // no-ops.
   //
   // This must be called before Open() to have an effect.
-  void want_wal_mode(bool enabled) { want_wal_mode_ = enabled; }
+  void want_wal_mode(bool enabled) { options_.wal_mode = enabled; }
 
   // Makes database accessible by only one process at a time.
   //
@@ -130,7 +178,7 @@
   //
   // SQLite's locking protocol is summarized at
   // https://www.sqlite.org/c3ref/io_methods.html
-  void set_exclusive_locking() { exclusive_locking_ = true; }
+  void set_exclusive_locking() { options_.exclusive_locking = true; }
 
   // Call to use alternative status-tracking for mmap.  Usually this is tracked
   // in the meta table, but some databases have no meta table.
@@ -291,7 +339,7 @@
   // these all return false, since it is unlikely that the caller
   // could fix them.
   //
-  // The database's page size is taken from |page_size_|.  The
+  // The database's page size is taken from |options_.page_size|.  The
   // existing database's |auto_vacuum| setting is lost (the
   // possibility of corruption makes it unreliable to pull it from the
   // existing database).  To re-enable on the empty database requires
@@ -530,11 +578,6 @@
   // the existence of specific files.
   static base::FilePath SharedMemoryFilePath(const base::FilePath& db_path);
 
-  // Default page size for newly created databases.
-  //
-  // Guaranteed to match SQLITE_DEFAULT_PAGE_SIZE.
-  static constexpr int kDefaultPageSize = 4096;
-
   // Internal state accessed by other classes in //sql.
   sqlite3* db(InternalApiToken) const { return db_; }
   bool poisoned(InternalApiToken) const { return poisoned_; }
@@ -738,13 +781,9 @@
   // Init resulted in an error.
   sqlite3* db_;
 
-  // Parameters we'll configure in sqlite before doing anything else. Zero means
-  // use the default value.
-  int page_size_;
-  int cache_size_;
-
-  bool exclusive_locking_;
-  bool want_wal_mode_;
+  // TODO(shuagga@microsoft.com): Make `options_` const after removing all
+  // setters.
+  DatabaseOptions options_;
 
   // Holds references to all cached statements so they remain active.
   //
diff --git a/sql/database_unittest.cc b/sql/database_unittest.cc
index 600f7cc..b7264a42 100644
--- a/sql/database_unittest.cc
+++ b/sql/database_unittest.cc
@@ -445,29 +445,32 @@
   const base::FilePath db_path = db_prefix.InsertBeforeExtensionASCII(
       base::NumberToString(initial_page_size));
   sql::Database::Delete(db_path);
-  sql::Database db;
-  db.set_page_size(initial_page_size);
+  sql::Database db({.page_size = initial_page_size});
   ASSERT_TRUE(db.Open(db_path));
   ASSERT_TRUE(db.Execute(kCreateSql));
   ASSERT_TRUE(db.Execute(kInsertSql1));
   ASSERT_TRUE(db.Execute(kInsertSql2));
   ASSERT_EQ(expected_initial_page_size,
             ExecuteWithResult(&db, "PRAGMA page_size"));
+  db.Close();
 
+  // Re-open the database while setting a new |options.page_size| in the object.
+  sql::Database razed_db({.page_size = final_page_size});
+  ASSERT_TRUE(razed_db.Open(db_path));
   // Raze will use the page size set in the connection object, which may not
   // match the file's page size.
-  db.set_page_size(final_page_size);
-  ASSERT_TRUE(db.Raze());
+  ASSERT_TRUE(razed_db.Raze());
 
   // SQLite 3.10.2 (at least) has a quirk with the sqlite3_backup() API (used by
   // Raze()) which causes the destination database to remember the previous
   // page_size, even if the overwriting database changed the page_size.  Access
   // the actual database to cause the cached value to be updated.
-  EXPECT_EQ("0", ExecuteWithResult(&db, "SELECT COUNT(*) FROM sqlite_master"));
+  EXPECT_EQ("0",
+            ExecuteWithResult(&razed_db, "SELECT COUNT(*) FROM sqlite_master"));
 
   EXPECT_EQ(expected_final_page_size,
-            ExecuteWithResult(&db, "PRAGMA page_size"));
-  EXPECT_EQ("1", ExecuteWithResult(&db, "PRAGMA page_count"));
+            ExecuteWithResult(&razed_db, "PRAGMA page_size"));
+  EXPECT_EQ("1", ExecuteWithResult(&razed_db, "PRAGMA page_count"));
 }
 
 // Verify that sql::Recovery maintains the page size, and the virtual table
@@ -492,8 +495,9 @@
   // Databases with no page size specified should result in the default
   // page size.  2k has never been the default page size.
   ASSERT_NE("2048", default_page_size);
-  EXPECT_NO_FATAL_FAILURE(TestPageSize(
-      db_path(), 2048, "2048", Database::kDefaultPageSize, default_page_size));
+  EXPECT_NO_FATAL_FAILURE(TestPageSize(db_path(), 2048, "2048",
+                                       DatabaseOptions::kDefaultPageSize,
+                                       default_page_size));
 }
 
 // Test that Raze() results are seen in other connections.
@@ -567,6 +571,8 @@
 }
 
 // Verify that Raze() can handle a file of junk.
+// Need exclusive mode off here as there are some subtleties (by design) around
+// how the cache is used with it on which causes the test to fail.
 TEST_F(SQLDatabaseTest, RazeNOTADB) {
   db().Close();
   sql::Database::Delete(db_path());
@@ -809,17 +815,19 @@
 class JournalModeTest : public SQLDatabaseTest,
                         public testing::WithParamInterface<bool> {
  public:
-  void SetUp() override {
+  JournalModeTest() : SQLDatabaseTest(GetDBOptions()) {}
+
+  sql::DatabaseOptions GetDBOptions() {
+    sql::DatabaseOptions options;
+    options.wal_mode = IsWALEnabled();
 #if defined(OS_FUCHSIA)  // Exclusive mode needs to be enabled to enter WAL mode
                          // on Fuchsia
     if (IsWALEnabled()) {
-      db().set_exclusive_locking();
+      options.exclusive_locking = true;
     }
 #endif  // defined(OS_FUCHSIA)
-    db().want_wal_mode(IsWALEnabled());
-    SQLDatabaseTest::SetUp();
+    return options;
   }
-
   bool IsWALEnabled() { return GetParam(); }
 };
 
@@ -884,10 +892,13 @@
     EXPECT_TRUE(base::GetPosixFilePermissions(wal_path, &mode));
     ASSERT_EQ(mode, 0600);
 
-    base::FilePath shm_path = sql::Database::SharedMemoryFilePath(db_path());
-    ASSERT_TRUE(GetPathExists(shm_path));
-    EXPECT_TRUE(base::GetPosixFilePermissions(shm_path, &mode));
-    ASSERT_EQ(mode, 0600);
+    // The shm file doesn't exist in exclusive locking mode.
+    if (ExecuteWithResult(&db(), "PRAGMA locking_mode") == "normal") {
+      base::FilePath shm_path = sql::Database::SharedMemoryFilePath(db_path());
+      ASSERT_TRUE(GetPathExists(shm_path));
+      EXPECT_TRUE(base::GetPosixFilePermissions(shm_path, &mode));
+      ASSERT_EQ(mode, 0600);
+    }
   } else {  // Truncate mode
     base::FilePath journal_path = sql::Database::JournalPath(db_path());
     DLOG(ERROR) << "journal_path: " << journal_path;
@@ -1274,11 +1285,13 @@
       << "Page cache usage should go down after calling TrimMemory()";
 }
 
-TEST_F(SQLDatabaseTest, LockingModeExclusive) {
-  db().Close();
-  db().set_exclusive_locking();
-  ASSERT_TRUE(db().Open(db_path()));
+class SQLDatabaseTestExclusiveMode : public SQLDatabaseTest {
+ public:
+  SQLDatabaseTestExclusiveMode()
+      : SQLDatabaseTest({.exclusive_locking = true}) {}
+};
 
+TEST_F(SQLDatabaseTestExclusiveMode, LockingModeExclusive) {
   EXPECT_EQ(ExecuteWithResult(&db(), "PRAGMA locking_mode"), "exclusive");
 }
 
@@ -1286,53 +1299,14 @@
   EXPECT_EQ(ExecuteWithResult(&db(), "PRAGMA locking_mode"), "normal");
 }
 
-TEST_F(SQLDatabaseTest, EnableWALMode) {
-  db().want_wal_mode(true);
-#if defined(OS_FUCHSIA)  // Exclusive mode needs to be enabled to enter WAL mode
-                         // on Fuchsia
-  db().set_exclusive_locking();
-#endif  // defined(OS_FUCHSIA)
-  ASSERT_TRUE(Reopen());
-
-  EXPECT_EQ(ExecuteWithResult(&db(), "PRAGMA journal_mode"), "wal");
+TEST_P(JournalModeTest, OpenedInCorrectMode) {
+  std::string expected_mode = IsWALEnabled() ? "wal" : "truncate";
+  EXPECT_EQ(ExecuteWithResult(&db(), "PRAGMA journal_mode"), expected_mode);
 }
 
-TEST_F(SQLDatabaseTest, DisableWALMode) {
-  db().want_wal_mode(true);
-#if defined(OS_FUCHSIA)  // Exclusive mode needs to be enabled to enter WAL mode
-                         // on Fuchsia
-  db().set_exclusive_locking();
-#endif  // defined(OS_FUCHSIA)
-  ASSERT_TRUE(Reopen());
-  ASSERT_EQ(ExecuteWithResult(&db(), "PRAGMA journal_mode"), "wal");
-
-  // Add some data to ensure that disabling WAL mode correctly handles a
-  // populated WAL file.
-  ASSERT_TRUE(
-      db().Execute("CREATE TABLE foo (id INTEGER UNIQUE, value INTEGER)"));
-  ASSERT_TRUE(db().Execute("INSERT INTO foo VALUES (1, 1)"));
-  ASSERT_TRUE(db().Execute("INSERT INTO foo VALUES (2, 2)"));
-
-  db().want_wal_mode(false);
-  ASSERT_TRUE(Reopen());
-  EXPECT_EQ(ExecuteWithResult(&db(), "PRAGMA journal_mode"), "truncate");
-  // Check that data is preserved
-  EXPECT_EQ(ExecuteWithResult(&db(), "SELECT SUM(value) FROM foo WHERE id < 3"),
-            "3");
-}
-
-TEST_F(SQLDatabaseTest, CheckpointDatabase) {
-  if (!db().UseWALMode()) {
-    db().Close();
-    sql::Database::Delete(db_path());
-    db().want_wal_mode(true);
-#if defined(OS_FUCHSIA)  // Exclusive mode needs to be enabled to enter WAL mode
-                         // on Fuchsia
-    db().set_exclusive_locking();
-#endif  // defined(OS_FUCHSIA)
-    ASSERT_TRUE(db().Open(db_path()));
-    ASSERT_EQ(ExecuteWithResult(&db(), "PRAGMA journal_mode"), "wal");
-  }
+TEST_P(JournalModeTest, CheckpointDatabase) {
+  if (!IsWALEnabled())
+    return;
 
   base::FilePath wal_path = sql::Database::WriteAheadLogPath(db_path());
 
diff --git a/sql/recovery.cc b/sql/recovery.cc
index a6af79e..4e6d1519 100644
--- a/sql/recovery.cc
+++ b/sql/recovery.cc
@@ -183,10 +183,9 @@
   r->Shutdown(POISON);
 }
 
-Recovery::Recovery(Database* connection) : db_(connection), recover_db_() {
-  // Result should keep the page size specified earlier.
-  recover_db_.set_page_size(db_->page_size());
-
+Recovery::Recovery(Database* connection)
+    : db_(connection),
+      recover_db_({.exclusive_locking = false, .page_size = db_->page_size()}) {
   // Files with I/O errors cannot be safely memory-mapped.
   recover_db_.set_mmap_disabled();
 
diff --git a/sql/recovery_unittest.cc b/sql/recovery_unittest.cc
index 17b8e8a..afd3865 100644
--- a/sql/recovery_unittest.cc
+++ b/sql/recovery_unittest.cc
@@ -29,8 +29,8 @@
 
 namespace {
 
-using sql::test::ExecuteWithResults;
 using sql::test::ExecuteWithResult;
+using sql::test::ExecuteWithResults;
 
 // Dump consistent human-readable representation of the database
 // schema.  For tables or indices, this will contain the sql command
@@ -943,30 +943,33 @@
   const base::FilePath db_path = db_prefix.InsertBeforeExtensionASCII(
       base::NumberToString(initial_page_size));
   sql::Database::Delete(db_path);
-  sql::Database db;
-  db.set_page_size(initial_page_size);
+  sql::Database db({.page_size = initial_page_size});
   ASSERT_TRUE(db.Open(db_path));
   ASSERT_TRUE(db.Execute(kCreateSql));
   ASSERT_TRUE(db.Execute(kInsertSql1));
   ASSERT_TRUE(db.Execute(kInsertSql2));
   ASSERT_EQ(expected_initial_page_size,
             ExecuteWithResult(&db, "PRAGMA page_size"));
-
-  // Recovery will use the page size set in the connection object, which may not
-  // match the file's page size.
-  db.set_page_size(final_page_size);
-  sql::Recovery::RecoverDatabase(&db, db_path);
-
-  // Recovery poisoned the handle, must re-open.
   db.Close();
 
+  // Re-open the database while setting a new |options.page_size| in the object.
+  sql::Database recover_db({.page_size = final_page_size});
+  ASSERT_TRUE(recover_db.Open(db_path));
+  // Recovery will use the page size set in the database object, which may not
+  // match the file's page size.
+  sql::Recovery::RecoverDatabase(&recover_db, db_path);
+
+  // Recovery poisoned the handle, must re-open.
+  recover_db.Close();
+
   // Make sure the page size is read from the file.
-  db.set_page_size(sql::Database::kDefaultPageSize);
-  ASSERT_TRUE(db.Open(db_path));
+  sql::Database recovered_db(
+      {.page_size = sql::DatabaseOptions::kDefaultPageSize});
+  ASSERT_TRUE(recovered_db.Open(db_path));
   ASSERT_EQ(expected_final_page_size,
-            ExecuteWithResult(&db, "PRAGMA page_size"));
+            ExecuteWithResult(&recovered_db, "PRAGMA page_size"));
   EXPECT_EQ("That was a test\nThis is a test",
-            ExecuteWithResults(&db, kSelectSql, "|", "\n"));
+            ExecuteWithResults(&recovered_db, kSelectSql, "|", "\n"));
 }
 
 // Verify that sql::Recovery maintains the page size, and the virtual table
@@ -978,8 +981,8 @@
 
   // Check the default page size first.
   EXPECT_NO_FATAL_FAILURE(TestPageSize(
-      db_path(), sql::Database::kDefaultPageSize, default_page_size,
-      sql::Database::kDefaultPageSize, default_page_size));
+      db_path(), sql::DatabaseOptions::kDefaultPageSize, default_page_size,
+      sql::DatabaseOptions::kDefaultPageSize, default_page_size));
 
   // Sync uses 32k pages.
   EXPECT_NO_FATAL_FAILURE(
@@ -995,7 +998,7 @@
   // page size.  2k has never been the default page size.
   ASSERT_NE("2048", default_page_size);
   EXPECT_NO_FATAL_FAILURE(TestPageSize(db_path(), 2048, "2048",
-                                       sql::Database::kDefaultPageSize,
+                                       sql::DatabaseOptions::kDefaultPageSize,
                                        default_page_size));
 }
 
diff --git a/sql/test/sql_test_base.cc b/sql/test/sql_test_base.cc
index 6598bbb1..ef32741 100644
--- a/sql/test/sql_test_base.cc
+++ b/sql/test/sql_test_base.cc
@@ -11,6 +11,8 @@
 
 SQLTestBase::SQLTestBase() = default;
 
+SQLTestBase::SQLTestBase(sql::DatabaseOptions options) : db_(options) {}
+
 SQLTestBase::~SQLTestBase() = default;
 
 base::FilePath SQLTestBase::db_path() {
diff --git a/sql/test/sql_test_base.h b/sql/test/sql_test_base.h
index 13658e0..cf35f1e 100644
--- a/sql/test/sql_test_base.h
+++ b/sql/test/sql_test_base.h
@@ -25,6 +25,7 @@
 class SQLTestBase : public testing::Test {
  public:
   SQLTestBase();
+  explicit SQLTestBase(sql::DatabaseOptions options);
   ~SQLTestBase() override;
 
   enum WriteJunkType {
diff --git a/testing/buildbot/chromium.clang.json b/testing/buildbot/chromium.clang.json
index d29deeb0..ff0f41ec 100644
--- a/testing/buildbot/chromium.clang.json
+++ b/testing/buildbot/chromium.clang.json
@@ -38600,7 +38600,7 @@
   },
   "ToTWinOfficial": {
     "additional_compile_targets": [
-      "all"
+      "chrome_official_builder"
     ],
     "gtest_tests": [
       {
@@ -39873,7 +39873,7 @@
   },
   "ToTWinThinLTO64": {
     "additional_compile_targets": [
-      "all"
+      "chrome_official_builder"
     ],
     "gtest_tests": [
       {
diff --git a/testing/buildbot/chromium.gpu.json b/testing/buildbot/chromium.gpu.json
index 434b9e8..936f3941 100644
--- a/testing/buildbot/chromium.gpu.json
+++ b/testing/buildbot/chromium.gpu.json
@@ -382,7 +382,6 @@
   "GPU Linux Builder (dbg)": {},
   "GPU Mac Builder": {},
   "GPU Mac Builder (dbg)": {},
-  "GPU Mac Builder Code Coverage": {},
   "Linux Debug (NVIDIA)": {
     "gtest_tests": [
       {
@@ -2517,497 +2516,6 @@
       }
     ]
   },
-  "Mac Release (Intel) Code Coverage": {
-    "gtest_tests": [
-      {
-        "args": [
-          "--enable-gpu",
-          "--test-launcher-bot-mode",
-          "--test-launcher-jobs=1",
-          "--gtest_filter=CastStreamingApiTestWithPixelOutput.EndToEnd*:TabCaptureApiPixelTest.EndToEnd*"
-        ],
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "name": "tab_capture_end2end_tests",
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "containment_type": "AUTO",
-          "dimension_sets": [
-            {
-              "gpu": "8086:0a2e",
-              "os": "Mac-10.15.5"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "browser_tests",
-        "test_id_prefix": "ninja://chrome/test:browser_tests/"
-      },
-      {
-        "args": [
-          "--use-cmd-decoder=passthrough",
-          "--use-gl=angle",
-          "--use-gpu-in-tests"
-        ],
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "name": "gl_tests_passthrough",
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "containment_type": "AUTO",
-          "dimension_sets": [
-            {
-              "gpu": "8086:0a2e",
-              "os": "Mac-10.15.5"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "gl_tests",
-        "test_id_prefix": "ninja://gpu:gl_tests/"
-      },
-      {
-        "args": [
-          "--use-cmd-decoder=validating",
-          "--use-gpu-in-tests"
-        ],
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "name": "gl_tests_validating",
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "containment_type": "AUTO",
-          "dimension_sets": [
-            {
-              "gpu": "8086:0a2e",
-              "os": "Mac-10.15.5"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "gl_tests",
-        "test_id_prefix": "ninja://gpu:gl_tests/"
-      },
-      {
-        "args": [
-          "--use-gpu-in-tests"
-        ],
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "containment_type": "AUTO",
-          "dimension_sets": [
-            {
-              "gpu": "8086:0a2e",
-              "os": "Mac-10.15.5"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "gl_unittests",
-        "test_id_prefix": "ninja://ui/gl:gl_unittests/"
-      },
-      {
-        "args": [
-          "standalone_angle_unittests"
-        ],
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "containment_type": "AUTO",
-          "dimension_sets": [
-            {
-              "gpu": "8086:0a2e",
-              "os": "Mac-10.15.5"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "standalone_angle_unittests",
-        "test_id_prefix": "ninja://third_party/angle/src/tests:standalone_angle_unittests/",
-        "use_isolated_scripts_api": true
-      }
-    ],
-    "isolated_scripts": [
-      {
-        "args": [
-          "context_lost",
-          "--show-stdout",
-          "--browser=release",
-          "--passthrough",
-          "-v",
-          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --use-cmd-decoder=validating"
-        ],
-        "isolate_name": "telemetry_gpu_integration_test",
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
-        },
-        "name": "context_lost_validating_tests",
-        "should_retry_with_patch": false,
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "containment_type": "AUTO",
-          "dimension_sets": [
-            {
-              "gpu": "8086:0a2e",
-              "os": "Mac-10.15.5"
-            }
-          ],
-          "idempotent": false,
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test/"
-      },
-      {
-        "args": [
-          "depth_capture",
-          "--show-stdout",
-          "--browser=release",
-          "--passthrough",
-          "-v",
-          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc"
-        ],
-        "isolate_name": "telemetry_gpu_integration_test",
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
-        },
-        "name": "depth_capture_tests",
-        "should_retry_with_patch": false,
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "containment_type": "AUTO",
-          "dimension_sets": [
-            {
-              "gpu": "8086:0a2e",
-              "os": "Mac-10.15.5"
-            }
-          ],
-          "idempotent": false,
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test/"
-      },
-      {
-        "args": [
-          "gpu_process",
-          "--show-stdout",
-          "--browser=release",
-          "--passthrough",
-          "-v",
-          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc"
-        ],
-        "isolate_name": "telemetry_gpu_integration_test",
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
-        },
-        "name": "gpu_process_launch_tests",
-        "should_retry_with_patch": false,
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "containment_type": "AUTO",
-          "dimension_sets": [
-            {
-              "gpu": "8086:0a2e",
-              "os": "Mac-10.15.5"
-            }
-          ],
-          "idempotent": false,
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test/"
-      },
-      {
-        "args": [
-          "hardware_accelerated_feature",
-          "--show-stdout",
-          "--browser=release",
-          "--passthrough",
-          "-v",
-          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc"
-        ],
-        "isolate_name": "telemetry_gpu_integration_test",
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
-        },
-        "name": "hardware_accelerated_feature_tests",
-        "should_retry_with_patch": false,
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "containment_type": "AUTO",
-          "dimension_sets": [
-            {
-              "gpu": "8086:0a2e",
-              "os": "Mac-10.15.5"
-            }
-          ],
-          "idempotent": false,
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test/"
-      },
-      {
-        "args": [
-          "info_collection",
-          "--show-stdout",
-          "--browser=release",
-          "--passthrough",
-          "-v",
-          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --force_high_performance_gpu",
-          "--expected-vendor-id",
-          "8086",
-          "--expected-device-id",
-          "0a2e"
-        ],
-        "isolate_name": "telemetry_gpu_integration_test",
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
-        },
-        "name": "info_collection_tests",
-        "should_retry_with_patch": false,
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "containment_type": "AUTO",
-          "dimension_sets": [
-            {
-              "gpu": "8086:0a2e",
-              "os": "Mac-10.15.5"
-            }
-          ],
-          "idempotent": false,
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test/"
-      },
-      {
-        "args": [
-          "maps",
-          "--show-stdout",
-          "--browser=release",
-          "--passthrough",
-          "-v",
-          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --use-cmd-decoder=validating",
-          "--dont-restore-color-profile-after-test",
-          "--test-machine-name",
-          "${buildername}",
-          "--git-revision=${got_revision}"
-        ],
-        "isolate_name": "telemetry_gpu_integration_test",
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
-        },
-        "name": "maps_pixel_validating_test",
-        "precommit_args": [
-          "--gerrit-issue=${patch_issue}",
-          "--gerrit-patchset=${patch_set}",
-          "--buildbucket-id=${buildbucket_build_id}"
-        ],
-        "should_retry_with_patch": false,
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "containment_type": "AUTO",
-          "dimension_sets": [
-            {
-              "gpu": "8086:0a2e",
-              "os": "Mac-10.15.5"
-            }
-          ],
-          "idempotent": false,
-          "service_account": "chrome-gpu-gold@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test/"
-      },
-      {
-        "args": [
-          "pixel",
-          "--show-stdout",
-          "--browser=release",
-          "--passthrough",
-          "-v",
-          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --use-cmd-decoder=validating",
-          "--dont-restore-color-profile-after-test",
-          "--test-machine-name",
-          "${buildername}",
-          "--git-revision=${got_revision}"
-        ],
-        "isolate_name": "telemetry_gpu_integration_test",
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
-        },
-        "name": "pixel_skia_gold_validating_test",
-        "precommit_args": [
-          "--gerrit-issue=${patch_issue}",
-          "--gerrit-patchset=${patch_set}",
-          "--buildbucket-id=${buildbucket_build_id}"
-        ],
-        "should_retry_with_patch": false,
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "containment_type": "AUTO",
-          "dimension_sets": [
-            {
-              "gpu": "8086:0a2e",
-              "os": "Mac-10.15.5"
-            }
-          ],
-          "idempotent": false,
-          "service_account": "chrome-gpu-gold@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test/"
-      },
-      {
-        "args": [
-          "../../tools/perf/run_benchmark",
-          "--benchmarks=rendering.desktop"
-        ],
-        "isolate_name": "rendering_representative_perf_tests",
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
-        },
-        "name": "rendering_representative_perf_tests",
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "containment_type": "AUTO",
-          "dimension_sets": [
-            {
-              "gpu": "8086:0a2e",
-              "os": "Mac-10.15.5"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test_id_prefix": "ninja://chrome/test:rendering_representative_perf_tests/"
-      },
-      {
-        "args": [
-          "screenshot_sync",
-          "--show-stdout",
-          "--browser=release",
-          "--passthrough",
-          "-v",
-          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --use-cmd-decoder=validating",
-          "--dont-restore-color-profile-after-test"
-        ],
-        "isolate_name": "telemetry_gpu_integration_test",
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
-        },
-        "name": "screenshot_sync_validating_tests",
-        "should_retry_with_patch": false,
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "containment_type": "AUTO",
-          "dimension_sets": [
-            {
-              "gpu": "8086:0a2e",
-              "os": "Mac-10.15.5"
-            }
-          ],
-          "idempotent": false,
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test/"
-      },
-      {
-        "args": [
-          "trace_test",
-          "--show-stdout",
-          "--browser=release",
-          "--passthrough",
-          "-v",
-          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc"
-        ],
-        "isolate_name": "telemetry_gpu_integration_test",
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
-        },
-        "name": "trace_test",
-        "should_retry_with_patch": false,
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "containment_type": "AUTO",
-          "dimension_sets": [
-            {
-              "gpu": "8086:0a2e",
-              "os": "Mac-10.15.5"
-            }
-          ],
-          "idempotent": false,
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test/"
-      },
-      {
-        "args": [
-          "webgl_conformance",
-          "--show-stdout",
-          "--browser=release",
-          "--passthrough",
-          "-v",
-          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --force_high_performance_gpu",
-          "--read-abbreviated-json-results-from=../../content/test/data/gpu/webgl_conformance_tests_output.json"
-        ],
-        "isolate_name": "telemetry_gpu_integration_test",
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
-        },
-        "name": "webgl_conformance_tests",
-        "should_retry_with_patch": false,
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "containment_type": "AUTO",
-          "dimension_sets": [
-            {
-              "gpu": "8086:0a2e",
-              "os": "Mac-10.15.5"
-            }
-          ],
-          "idempotent": false,
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
-          "shards": 2
-        },
-        "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test/"
-      }
-    ]
-  },
   "Mac Retina Debug (AMD)": {
     "gtest_tests": [
       {
@@ -3968,529 +3476,6 @@
       }
     ]
   },
-  "Mac Retina Release (AMD) Code Coverage": {
-    "gtest_tests": [
-      {
-        "args": [
-          "--enable-gpu",
-          "--test-launcher-bot-mode",
-          "--test-launcher-jobs=1",
-          "--gtest_filter=CastStreamingApiTestWithPixelOutput.EndToEnd*:TabCaptureApiPixelTest.EndToEnd*"
-        ],
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "name": "tab_capture_end2end_tests",
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "containment_type": "AUTO",
-          "dimension_sets": [
-            {
-              "gpu": "1002:6821",
-              "hidpi": "1",
-              "os": "Mac-10.14.6",
-              "pool": "chromium.tests.gpu"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "browser_tests",
-        "test_id_prefix": "ninja://chrome/test:browser_tests/"
-      },
-      {
-        "args": [
-          "--use-cmd-decoder=passthrough",
-          "--use-gl=angle",
-          "--use-gpu-in-tests"
-        ],
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "name": "gl_tests_passthrough",
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "containment_type": "AUTO",
-          "dimension_sets": [
-            {
-              "gpu": "1002:6821",
-              "hidpi": "1",
-              "os": "Mac-10.14.6",
-              "pool": "chromium.tests.gpu"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "gl_tests",
-        "test_id_prefix": "ninja://gpu:gl_tests/"
-      },
-      {
-        "args": [
-          "--use-cmd-decoder=validating",
-          "--use-gpu-in-tests"
-        ],
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "name": "gl_tests_validating",
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "containment_type": "AUTO",
-          "dimension_sets": [
-            {
-              "gpu": "1002:6821",
-              "hidpi": "1",
-              "os": "Mac-10.14.6",
-              "pool": "chromium.tests.gpu"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "gl_tests",
-        "test_id_prefix": "ninja://gpu:gl_tests/"
-      },
-      {
-        "args": [
-          "--use-gpu-in-tests"
-        ],
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "containment_type": "AUTO",
-          "dimension_sets": [
-            {
-              "gpu": "1002:6821",
-              "hidpi": "1",
-              "os": "Mac-10.14.6",
-              "pool": "chromium.tests.gpu"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "gl_unittests",
-        "test_id_prefix": "ninja://ui/gl:gl_unittests/"
-      },
-      {
-        "args": [
-          "standalone_angle_unittests"
-        ],
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "containment_type": "AUTO",
-          "dimension_sets": [
-            {
-              "gpu": "1002:6821",
-              "hidpi": "1",
-              "os": "Mac-10.14.6",
-              "pool": "chromium.tests.gpu"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "standalone_angle_unittests",
-        "test_id_prefix": "ninja://third_party/angle/src/tests:standalone_angle_unittests/",
-        "use_isolated_scripts_api": true
-      }
-    ],
-    "isolated_scripts": [
-      {
-        "args": [
-          "context_lost",
-          "--show-stdout",
-          "--browser=release",
-          "--passthrough",
-          "-v",
-          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --use-cmd-decoder=validating"
-        ],
-        "isolate_name": "telemetry_gpu_integration_test",
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
-        },
-        "name": "context_lost_validating_tests",
-        "should_retry_with_patch": false,
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "containment_type": "AUTO",
-          "dimension_sets": [
-            {
-              "gpu": "1002:6821",
-              "hidpi": "1",
-              "os": "Mac-10.14.6",
-              "pool": "chromium.tests.gpu"
-            }
-          ],
-          "idempotent": false,
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test/"
-      },
-      {
-        "args": [
-          "depth_capture",
-          "--show-stdout",
-          "--browser=release",
-          "--passthrough",
-          "-v",
-          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc"
-        ],
-        "isolate_name": "telemetry_gpu_integration_test",
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
-        },
-        "name": "depth_capture_tests",
-        "should_retry_with_patch": false,
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "containment_type": "AUTO",
-          "dimension_sets": [
-            {
-              "gpu": "1002:6821",
-              "hidpi": "1",
-              "os": "Mac-10.14.6",
-              "pool": "chromium.tests.gpu"
-            }
-          ],
-          "idempotent": false,
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test/"
-      },
-      {
-        "args": [
-          "gpu_process",
-          "--show-stdout",
-          "--browser=release",
-          "--passthrough",
-          "-v",
-          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc"
-        ],
-        "isolate_name": "telemetry_gpu_integration_test",
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
-        },
-        "name": "gpu_process_launch_tests",
-        "should_retry_with_patch": false,
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "containment_type": "AUTO",
-          "dimension_sets": [
-            {
-              "gpu": "1002:6821",
-              "hidpi": "1",
-              "os": "Mac-10.14.6",
-              "pool": "chromium.tests.gpu"
-            }
-          ],
-          "idempotent": false,
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test/"
-      },
-      {
-        "args": [
-          "hardware_accelerated_feature",
-          "--show-stdout",
-          "--browser=release",
-          "--passthrough",
-          "-v",
-          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc"
-        ],
-        "isolate_name": "telemetry_gpu_integration_test",
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
-        },
-        "name": "hardware_accelerated_feature_tests",
-        "should_retry_with_patch": false,
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "containment_type": "AUTO",
-          "dimension_sets": [
-            {
-              "gpu": "1002:6821",
-              "hidpi": "1",
-              "os": "Mac-10.14.6",
-              "pool": "chromium.tests.gpu"
-            }
-          ],
-          "idempotent": false,
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test/"
-      },
-      {
-        "args": [
-          "info_collection",
-          "--show-stdout",
-          "--browser=release",
-          "--passthrough",
-          "-v",
-          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --force_high_performance_gpu",
-          "--expected-vendor-id",
-          "1002",
-          "--expected-device-id",
-          "6821"
-        ],
-        "isolate_name": "telemetry_gpu_integration_test",
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
-        },
-        "name": "info_collection_tests",
-        "should_retry_with_patch": false,
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "containment_type": "AUTO",
-          "dimension_sets": [
-            {
-              "gpu": "1002:6821",
-              "hidpi": "1",
-              "os": "Mac-10.14.6",
-              "pool": "chromium.tests.gpu"
-            }
-          ],
-          "idempotent": false,
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test/"
-      },
-      {
-        "args": [
-          "maps",
-          "--show-stdout",
-          "--browser=release",
-          "--passthrough",
-          "-v",
-          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --use-cmd-decoder=validating",
-          "--dont-restore-color-profile-after-test",
-          "--test-machine-name",
-          "${buildername}",
-          "--git-revision=${got_revision}"
-        ],
-        "isolate_name": "telemetry_gpu_integration_test",
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
-        },
-        "name": "maps_pixel_validating_test",
-        "precommit_args": [
-          "--gerrit-issue=${patch_issue}",
-          "--gerrit-patchset=${patch_set}",
-          "--buildbucket-id=${buildbucket_build_id}"
-        ],
-        "should_retry_with_patch": false,
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "containment_type": "AUTO",
-          "dimension_sets": [
-            {
-              "gpu": "1002:6821",
-              "hidpi": "1",
-              "os": "Mac-10.14.6",
-              "pool": "chromium.tests.gpu"
-            }
-          ],
-          "idempotent": false,
-          "service_account": "chrome-gpu-gold@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test/"
-      },
-      {
-        "args": [
-          "pixel",
-          "--show-stdout",
-          "--browser=release",
-          "--passthrough",
-          "-v",
-          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --use-cmd-decoder=validating",
-          "--dont-restore-color-profile-after-test",
-          "--test-machine-name",
-          "${buildername}",
-          "--git-revision=${got_revision}"
-        ],
-        "isolate_name": "telemetry_gpu_integration_test",
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
-        },
-        "name": "pixel_skia_gold_validating_test",
-        "precommit_args": [
-          "--gerrit-issue=${patch_issue}",
-          "--gerrit-patchset=${patch_set}",
-          "--buildbucket-id=${buildbucket_build_id}"
-        ],
-        "should_retry_with_patch": false,
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "containment_type": "AUTO",
-          "dimension_sets": [
-            {
-              "gpu": "1002:6821",
-              "hidpi": "1",
-              "os": "Mac-10.14.6",
-              "pool": "chromium.tests.gpu"
-            }
-          ],
-          "idempotent": false,
-          "service_account": "chrome-gpu-gold@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test/"
-      },
-      {
-        "args": [
-          "../../tools/perf/run_benchmark",
-          "--benchmarks=rendering.desktop"
-        ],
-        "isolate_name": "rendering_representative_perf_tests",
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
-        },
-        "name": "rendering_representative_perf_tests",
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "containment_type": "AUTO",
-          "dimension_sets": [
-            {
-              "gpu": "1002:6821",
-              "hidpi": "1",
-              "os": "Mac-10.14.6",
-              "pool": "chromium.tests.gpu"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test_id_prefix": "ninja://chrome/test:rendering_representative_perf_tests/"
-      },
-      {
-        "args": [
-          "screenshot_sync",
-          "--show-stdout",
-          "--browser=release",
-          "--passthrough",
-          "-v",
-          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --use-cmd-decoder=validating",
-          "--dont-restore-color-profile-after-test"
-        ],
-        "isolate_name": "telemetry_gpu_integration_test",
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
-        },
-        "name": "screenshot_sync_validating_tests",
-        "should_retry_with_patch": false,
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "containment_type": "AUTO",
-          "dimension_sets": [
-            {
-              "gpu": "1002:6821",
-              "hidpi": "1",
-              "os": "Mac-10.14.6",
-              "pool": "chromium.tests.gpu"
-            }
-          ],
-          "idempotent": false,
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test/"
-      },
-      {
-        "args": [
-          "trace_test",
-          "--show-stdout",
-          "--browser=release",
-          "--passthrough",
-          "-v",
-          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc"
-        ],
-        "isolate_name": "telemetry_gpu_integration_test",
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
-        },
-        "name": "trace_test",
-        "should_retry_with_patch": false,
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "containment_type": "AUTO",
-          "dimension_sets": [
-            {
-              "gpu": "1002:6821",
-              "hidpi": "1",
-              "os": "Mac-10.14.6",
-              "pool": "chromium.tests.gpu"
-            }
-          ],
-          "idempotent": false,
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test/"
-      },
-      {
-        "args": [
-          "webgl_conformance",
-          "--show-stdout",
-          "--browser=release",
-          "--passthrough",
-          "-v",
-          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc --force_high_performance_gpu",
-          "--read-abbreviated-json-results-from=../../content/test/data/gpu/webgl_conformance_tests_output.json"
-        ],
-        "isolate_name": "telemetry_gpu_integration_test",
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
-        },
-        "name": "webgl_conformance_tests",
-        "should_retry_with_patch": false,
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "containment_type": "AUTO",
-          "dimension_sets": [
-            {
-              "gpu": "1002:6821",
-              "hidpi": "1",
-              "os": "Mac-10.14.6",
-              "pool": "chromium.tests.gpu"
-            }
-          ],
-          "idempotent": false,
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
-          "shards": 2
-        },
-        "test_id_prefix": "ninja://chrome/test:telemetry_gpu_integration_test/"
-      }
-    ]
-  },
   "Win10 x64 Debug (NVIDIA)": {
     "gtest_tests": [
       {
diff --git a/testing/buildbot/chromium.mac.json b/testing/buildbot/chromium.mac.json
index 8018d671..2c1f658 100644
--- a/testing/buildbot/chromium.mac.json
+++ b/testing/buildbot/chromium.mac.json
@@ -26,11 +26,6 @@
       "all"
     ]
   },
-  "Mac Builder Code Coverage": {
-    "additional_compile_targets": [
-      "pdf_fuzzers"
-    ]
-  },
   "Mac10.10 Tests": {
     "gtest_tests": [
       {
@@ -8787,1861 +8782,6 @@
       }
     ]
   },
-  "Mac10.13 Tests Code Coverage": {
-    "gtest_tests": [
-      {
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "gpu": "none",
-              "os": "Mac-10.13.6"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "absl_hardening_tests",
-        "test_id_prefix": "ninja://third_party/abseil-cpp:absl_hardening_tests/"
-      },
-      {
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "gpu": "none",
-              "os": "Mac-10.13.6"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "accessibility_unittests",
-        "test_id_prefix": "ninja://ui/accessibility:accessibility_unittests/"
-      },
-      {
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "gpu": "none",
-              "os": "Mac-10.13.6"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "app_shell_unittests",
-        "test_id_prefix": "ninja://extensions/shell:app_shell_unittests/"
-      },
-      {
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "gpu": "none",
-              "os": "Mac-10.13.6"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "base_unittests",
-        "test_id_prefix": "ninja://base:base_unittests/"
-      },
-      {
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "gpu": "none",
-              "os": "Mac-10.13.6"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "base_util_unittests",
-        "test_id_prefix": "ninja://base/util:base_util_unittests/"
-      },
-      {
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "gpu": "none",
-              "os": "Mac-10.13.6"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "blink_common_unittests",
-        "test_id_prefix": "ninja://third_party/blink/common:blink_common_unittests/"
-      },
-      {
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "gpu": "none",
-              "os": "Mac-10.13.6"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "blink_fuzzer_unittests",
-        "test_id_prefix": "ninja://third_party/blink/renderer/platform:blink_fuzzer_unittests/"
-      },
-      {
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "gpu": "none",
-              "os": "Mac-10.13.6"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "blink_heap_unittests",
-        "test_id_prefix": "ninja://third_party/blink/renderer/platform/heap:blink_heap_unittests/"
-      },
-      {
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "gpu": "none",
-              "os": "Mac-10.13.6"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "blink_platform_unittests",
-        "test_id_prefix": "ninja://third_party/blink/renderer/platform:blink_platform_unittests/"
-      },
-      {
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "name": "webkit_unit_tests",
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "gpu": "none",
-              "os": "Mac-10.13.6"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "blink_unittests",
-        "test_id_prefix": "ninja://third_party/blink/renderer/controller:blink_unittests/"
-      },
-      {
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "gpu": "none",
-              "os": "Mac-10.13.6"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "boringssl_crypto_tests",
-        "test_id_prefix": "ninja://third_party/boringssl:boringssl_crypto_tests/"
-      },
-      {
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "gpu": "none",
-              "os": "Mac-10.13.6"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "boringssl_ssl_tests",
-        "test_id_prefix": "ninja://third_party/boringssl:boringssl_ssl_tests/"
-      },
-      {
-        "args": [
-          "--gtest_filter=-*UsingRealWebcam*"
-        ],
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "gpu": "none",
-              "os": "Mac-10.13.6"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "capture_unittests",
-        "test_id_prefix": "ninja://media/capture:capture_unittests/"
-      },
-      {
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "gpu": "none",
-              "os": "Mac-10.13.6"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "cast_unittests",
-        "test_id_prefix": "ninja://media/cast:cast_unittests/"
-      },
-      {
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "gpu": "none",
-              "os": "Mac-10.13.6"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "cc_unittests",
-        "test_id_prefix": "ninja://cc:cc_unittests/"
-      },
-      {
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "gpu": "none",
-              "os": "Mac-10.13.6"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "chrome_app_unittests",
-        "test_id_prefix": "ninja://chrome/test:chrome_app_unittests/"
-      },
-      {
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "gpu": "none",
-              "os": "Mac-10.13.6"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "chromedriver_unittests",
-        "test_id_prefix": "ninja://chrome/test/chromedriver:chromedriver_unittests/"
-      },
-      {
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "gpu": "none",
-              "os": "Mac-10.13.6"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "components_browsertests",
-        "test_id_prefix": "ninja://components:components_browsertests/"
-      },
-      {
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "gpu": "none",
-              "os": "Mac-10.13.6"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "components_unittests",
-        "test_id_prefix": "ninja://components:components_unittests/"
-      },
-      {
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "gpu": "none",
-              "os": "Mac-10.13.6"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
-          "shards": 6
-        },
-        "test": "content_browsertests",
-        "test_id_prefix": "ninja://content/test:content_browsertests/"
-      },
-      {
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "gpu": "none",
-              "os": "Mac-10.13.6"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "content_nocompile_tests",
-        "test_id_prefix": "ninja://content/test:content_nocompile_tests/"
-      },
-      {
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "gpu": "none",
-              "os": "Mac-10.13.6"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "content_unittests",
-        "test_id_prefix": "ninja://content/test:content_unittests/"
-      },
-      {
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "gpu": "none",
-              "os": "Mac-10.13.6"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "crashpad_tests",
-        "test_id_prefix": "ninja://third_party/crashpad/crashpad:crashpad_tests/"
-      },
-      {
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "gpu": "none",
-              "os": "Mac-10.13.6"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "cronet_tests",
-        "test_id_prefix": "ninja://components/cronet:cronet_tests/"
-      },
-      {
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "gpu": "none",
-              "os": "Mac-10.13.6"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "cronet_unittests",
-        "test_id_prefix": "ninja://components/cronet:cronet_unittests/"
-      },
-      {
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "gpu": "none",
-              "os": "Mac-10.13.6"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "crypto_unittests",
-        "test_id_prefix": "ninja://crypto:crypto_unittests/"
-      },
-      {
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "gpu": "none",
-              "os": "Mac-10.13.6"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "device_unittests",
-        "test_id_prefix": "ninja://device:device_unittests/"
-      },
-      {
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "gpu": "none",
-              "os": "Mac-10.13.6"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "display_unittests",
-        "test_id_prefix": "ninja://ui/display:display_unittests/"
-      },
-      {
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "gpu": "none",
-              "os": "Mac-10.13.6"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "events_unittests",
-        "test_id_prefix": "ninja://ui/events:events_unittests/"
-      },
-      {
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "gpu": "none",
-              "os": "Mac-10.13.6"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "extensions_browsertests",
-        "test_id_prefix": "ninja://extensions:extensions_browsertests/"
-      },
-      {
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "gpu": "none",
-              "os": "Mac-10.13.6"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "extensions_unittests",
-        "test_id_prefix": "ninja://extensions:extensions_unittests/"
-      },
-      {
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "gpu": "none",
-              "os": "Mac-10.13.6"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "filesystem_service_unittests",
-        "test_id_prefix": "ninja://components/services/filesystem:filesystem_service_unittests/"
-      },
-      {
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "gpu": "none",
-              "os": "Mac-10.13.6"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "gcm_unit_tests",
-        "test_id_prefix": "ninja://google_apis/gcm:gcm_unit_tests/"
-      },
-      {
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "gpu": "none",
-              "os": "Mac-10.13.6"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "gfx_unittests",
-        "test_id_prefix": "ninja://ui/gfx:gfx_unittests/"
-      },
-      {
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "gpu": "none",
-              "os": "Mac-10.13.6"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "gin_unittests",
-        "test_id_prefix": "ninja://gin:gin_unittests/"
-      },
-      {
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "gpu": "none",
-              "os": "Mac-10.13.6"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "google_apis_unittests",
-        "test_id_prefix": "ninja://google_apis:google_apis_unittests/"
-      },
-      {
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "gpu": "none",
-              "os": "Mac-10.13.6"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "gpu_unittests",
-        "test_id_prefix": "ninja://gpu:gpu_unittests/"
-      },
-      {
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "gpu": "none",
-              "os": "Mac-10.13.6"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "gwp_asan_unittests",
-        "test_id_prefix": "ninja://components/gwp_asan:gwp_asan_unittests/"
-      },
-      {
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "gpu": "none",
-              "os": "Mac-10.13.6"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "headless_browsertests",
-        "test_id_prefix": "ninja://headless:headless_browsertests/"
-      },
-      {
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "gpu": "none",
-              "os": "Mac-10.13.6"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "headless_unittests",
-        "test_id_prefix": "ninja://headless:headless_unittests/"
-      },
-      {
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "gpu": "none",
-              "os": "Mac-10.13.6"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
-          "shards": 3
-        },
-        "test": "interactive_ui_tests",
-        "test_id_prefix": "ninja://chrome/test:interactive_ui_tests/"
-      },
-      {
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "gpu": "none",
-              "os": "Mac-10.13.6"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "ipc_tests",
-        "test_id_prefix": "ninja://ipc:ipc_tests/"
-      },
-      {
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "gpu": "none",
-              "os": "Mac-10.13.6"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "jingle_unittests",
-        "test_id_prefix": "ninja://jingle:jingle_unittests/"
-      },
-      {
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "gpu": "none",
-              "os": "Mac-10.13.6"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "latency_unittests",
-        "test_id_prefix": "ninja://ui/latency:latency_unittests/"
-      },
-      {
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "gpu": "none",
-              "os": "Mac-10.13.6"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "libjingle_xmpp_unittests",
-        "test_id_prefix": "ninja://third_party/libjingle_xmpp:libjingle_xmpp_unittests/"
-      },
-      {
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "gpu": "none",
-              "os": "Mac-10.13.6"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "media_blink_unittests",
-        "test_id_prefix": "ninja://media/blink:media_blink_unittests/"
-      },
-      {
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "gpu": "none",
-              "os": "Mac-10.13.6"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "media_unittests",
-        "test_id_prefix": "ninja://media:media_unittests/"
-      },
-      {
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "gpu": "none",
-              "os": "Mac-10.13.6"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "message_center_unittests",
-        "test_id_prefix": "ninja://ui/message_center:message_center_unittests/"
-      },
-      {
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "gpu": "none",
-              "os": "Mac-10.13.6"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "midi_unittests",
-        "test_id_prefix": "ninja://media/midi:midi_unittests/"
-      },
-      {
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "gpu": "none",
-              "os": "Mac-10.13.6"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "mojo_unittests",
-        "test_id_prefix": "ninja://mojo:mojo_unittests/"
-      },
-      {
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "gpu": "none",
-              "os": "Mac-10.13.6"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "native_theme_unittests",
-        "test_id_prefix": "ninja://ui/native_theme:native_theme_unittests/"
-      },
-      {
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "gpu": "none",
-              "os": "Mac-10.13.6"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "net_unittests",
-        "test_id_prefix": "ninja://net:net_unittests/"
-      },
-      {
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "gpu": "none",
-              "os": "Mac-10.13.6"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "openscreen_unittests",
-        "test_id_prefix": "ninja://chrome/browser/media/router:openscreen_unittests/"
-      },
-      {
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "gpu": "none",
-              "os": "Mac-10.13.6"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "pdf_unittests",
-        "test_id_prefix": "ninja://pdf:pdf_unittests/"
-      },
-      {
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "gpu": "none",
-              "os": "Mac-10.13.6"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "perfetto_unittests",
-        "test_id_prefix": "ninja://third_party/perfetto:perfetto_unittests/"
-      },
-      {
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "gpu": "none",
-              "os": "Mac-10.13.6"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "ppapi_unittests",
-        "test_id_prefix": "ninja://ppapi:ppapi_unittests/"
-      },
-      {
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "gpu": "none",
-              "os": "Mac-10.13.6"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "printing_unittests",
-        "test_id_prefix": "ninja://printing:printing_unittests/"
-      },
-      {
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "gpu": "none",
-              "os": "Mac-10.13.6"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "remoting_unittests",
-        "test_id_prefix": "ninja://remoting:remoting_unittests/"
-      },
-      {
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "gpu": "none",
-              "os": "Mac-10.13.6"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "sandbox_mac_unittests",
-        "test_id_prefix": "ninja://sandbox/mac:sandbox_mac_unittests/"
-      },
-      {
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "gpu": "none",
-              "os": "Mac-10.13.6"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "service_manager_unittests",
-        "test_id_prefix": "ninja://services/service_manager/tests:service_manager_unittests/"
-      },
-      {
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "gpu": "none",
-              "os": "Mac-10.13.6"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "services_unittests",
-        "test_id_prefix": "ninja://services:services_unittests/"
-      },
-      {
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "gpu": "none",
-              "os": "Mac-10.13.6"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "shell_dialogs_unittests",
-        "test_id_prefix": "ninja://ui/shell_dialogs:shell_dialogs_unittests/"
-      },
-      {
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "gpu": "none",
-              "os": "Mac-10.13.6"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "skia_unittests",
-        "test_id_prefix": "ninja://skia:skia_unittests/"
-      },
-      {
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "gpu": "none",
-              "os": "Mac-10.13.6"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "snapshot_unittests",
-        "test_id_prefix": "ninja://ui/snapshot:snapshot_unittests/"
-      },
-      {
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "gpu": "none",
-              "os": "Mac-10.13.6"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "sql_unittests",
-        "test_id_prefix": "ninja://sql:sql_unittests/"
-      },
-      {
-        "args": [
-          "standalone_angle_unittests"
-        ],
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "gpu": "none",
-              "os": "Mac-10.13.6"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "standalone_angle_unittests",
-        "test_id_prefix": "ninja://third_party/angle/src/tests:standalone_angle_unittests/",
-        "use_isolated_scripts_api": true
-      },
-      {
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "gpu": "none",
-              "os": "Mac-10.13.6"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "storage_unittests",
-        "test_id_prefix": "ninja://storage:storage_unittests/"
-      },
-      {
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "gpu": "none",
-              "os": "Mac-10.13.6"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "sync_integration_tests",
-        "test_id_prefix": "ninja://chrome/test:sync_integration_tests/"
-      },
-      {
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "gpu": "none",
-              "os": "Mac-10.13.6"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "ui_base_unittests",
-        "test_id_prefix": "ninja://ui/base:ui_base_unittests/"
-      },
-      {
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "gpu": "none",
-              "os": "Mac-10.13.6"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "ui_touch_selection_unittests",
-        "test_id_prefix": "ninja://ui/touch_selection:ui_touch_selection_unittests/"
-      },
-      {
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "gpu": "none",
-              "os": "Mac-10.13.6"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "unit_tests",
-        "test_id_prefix": "ninja://chrome/test:unit_tests/"
-      },
-      {
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "gpu": "none",
-              "os": "Mac-10.13.6"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "updater_tests",
-        "test_id_prefix": "ninja://chrome/updater:updater_tests/"
-      },
-      {
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "gpu": "none",
-              "os": "Mac-10.13.6"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "url_unittests",
-        "test_id_prefix": "ninja://url:url_unittests/"
-      },
-      {
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "gpu": "none",
-              "os": "Mac-10.13.6"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "views_unittests",
-        "test_id_prefix": "ninja://ui/views:views_unittests/"
-      },
-      {
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "gpu": "none",
-              "os": "Mac-10.13.6"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "viz_unittests",
-        "test_id_prefix": "ninja://components/viz:viz_unittests/"
-      },
-      {
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "gpu": "none",
-              "os": "Mac-10.13.6"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "wtf_unittests",
-        "test_id_prefix": "ninja://third_party/blink/renderer/platform/wtf:wtf_unittests/"
-      },
-      {
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "name": "xr_browser_tests",
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "gpu": "none",
-              "os": "Mac-10.13.6"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "xr_browser_tests",
-        "test_id_prefix": "ninja://chrome/test:xr_browser_tests/"
-      },
-      {
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_gtest_merge.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "gpu": "none",
-              "os": "Mac-10.13.6"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "zlib_unittests",
-        "test_id_prefix": "ninja://third_party/zlib:zlib_unittests/"
-      }
-    ],
-    "isolated_scripts": [
-      {
-        "isolate_name": "blink_python_tests",
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
-        },
-        "name": "blink_python_tests",
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "gpu": "none",
-              "os": "Mac-10.13.6"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test_id_prefix": "ninja://:blink_python_tests/"
-      },
-      {
-        "args": [
-          "--num-retries=3"
-        ],
-        "isolate_name": "blink_web_tests",
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [
-            "--verbose"
-          ],
-          "script": "//third_party/blink/tools/merge_web_test_results.py"
-        },
-        "name": "blink_web_tests",
-        "resultdb": {
-          "enable": true
-        },
-        "results_handler": "layout tests",
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "gpu": "none",
-              "os": "Mac-10.13.6"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
-          "shards": 12
-        },
-        "test_id_prefix": "ninja://:blink_web_tests/"
-      },
-      {
-        "args": [
-          "--test-type=integration"
-        ],
-        "isolate_name": "chromedriver_py_tests",
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
-        },
-        "name": "chromedriver_py_tests",
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "gpu": "none",
-              "os": "Mac-10.13.6"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test_id_prefix": "ninja://chrome/test/chromedriver:chromedriver_py_tests/"
-      },
-      {
-        "isolate_name": "chromedriver_replay_unittests",
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
-        },
-        "name": "chromedriver_replay_unittests",
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "gpu": "none",
-              "os": "Mac-10.13.6"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test_id_prefix": "ninja://chrome/test/chromedriver:chromedriver_replay_unittests/"
-      },
-      {
-        "args": [
-          "--gtest-benchmark-name=components_perftests"
-        ],
-        "isolate_name": "components_perftests",
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [
-            "--smoke-test-mode"
-          ],
-          "script": "//tools/perf/process_perf_results.py"
-        },
-        "name": "components_perftests",
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "gpu": "none",
-              "os": "Mac-10.13.6"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test_id_prefix": "ninja://components:components_perftests/"
-      },
-      {
-        "isolate_name": "content_shell_crash_test",
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
-        },
-        "name": "content_shell_crash_test",
-        "resultdb": {
-          "enable": false
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "gpu": "none",
-              "os": "Mac-10.13.6"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test_id_prefix": "ninja://content/shell:content_shell_crash_test/"
-      },
-      {
-        "isolate_name": "extension_docserver_python_unittests",
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
-        },
-        "name": "extension_docserver_python_unittests",
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "gpu": "none",
-              "os": "Mac-10.13.6"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test_id_prefix": "ninja://chrome/common/extensions/docs/server2:extension_docserver_python_unittests/"
-      },
-      {
-        "isolate_name": "flatbuffers_unittests",
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
-        },
-        "name": "flatbuffers_unittests",
-        "resultdb": {
-          "enable": false
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "gpu": "none",
-              "os": "Mac-10.13.6"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test_id_prefix": "ninja://third_party/flatbuffers:flatbuffers_unittests/"
-      },
-      {
-        "isolate_name": "grit_python_unittests",
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
-        },
-        "name": "grit_python_unittests",
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "gpu": "none",
-              "os": "Mac-10.13.6"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test_id_prefix": "ninja://tools/grit:grit_python_unittests/"
-      },
-      {
-        "isolate_name": "mac_signing_tests",
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
-        },
-        "name": "mac_signing_tests",
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "gpu": "none",
-              "os": "Mac-10.13.6"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test_id_prefix": "ninja://chrome/installer/mac:mac_signing_tests/"
-      },
-      {
-        "isolate_name": "metrics_python_tests",
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
-        },
-        "name": "metrics_python_tests",
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "gpu": "none",
-              "os": "Mac-10.13.6"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test_id_prefix": "ninja://tools/metrics:metrics_python_tests/"
-      },
-      {
-        "isolate_name": "mojo_python_unittests",
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
-        },
-        "name": "mojo_python_unittests",
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "gpu": "none",
-              "os": "Mac-10.13.6"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test_id_prefix": "ninja://mojo/public/tools:mojo_python_unittests/"
-      },
-      {
-        "isolate_name": "telemetry_gpu_unittests",
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
-        },
-        "name": "telemetry_gpu_unittests",
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "gpu": "none",
-              "os": "Mac-10.13.6"
-            }
-          ],
-          "idempotent": false,
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test_id_prefix": "ninja://chrome/test:telemetry_gpu_unittests/"
-      },
-      {
-        "args": [
-          "--jobs=1",
-          "--extra-browser-args=--disable-gpu"
-        ],
-        "isolate_name": "telemetry_unittests",
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
-        },
-        "name": "telemetry_unittests",
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "gpu": "none",
-              "os": "Mac-10.13.6"
-            }
-          ],
-          "idempotent": false,
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
-          "shards": 4
-        },
-        "test_id_prefix": "ninja://chrome/test:telemetry_unittests/"
-      },
-      {
-        "isolate_name": "updater_integration_tests",
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
-        },
-        "name": "updater_integration_tests",
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "gpu": "none",
-              "os": "Mac-10.13.6"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test_id_prefix": "ninja://chrome/updater:updater_integration_tests/"
-      },
-      {
-        "args": [
-          "--gtest-benchmark-name=views_perftests"
-        ],
-        "isolate_name": "views_perftests",
-        "isolate_profile_data": true,
-        "merge": {
-          "args": [
-            "--smoke-test-mode"
-          ],
-          "script": "//tools/perf/process_perf_results.py"
-        },
-        "name": "views_perftests",
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "gpu": "none",
-              "os": "Mac-10.13.6"
-            }
-          ],
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test_id_prefix": "ninja://ui/views:views_perftests/"
-      }
-    ]
-  },
   "Mac10.14 Tests": {
     "gtest_tests": [
       {
diff --git a/testing/buildbot/test_suite_exceptions.pyl b/testing/buildbot/test_suite_exceptions.pyl
index 0f3e5ec..5cf61cf 100644
--- a/testing/buildbot/test_suite_exceptions.pyl
+++ b/testing/buildbot/test_suite_exceptions.pyl
@@ -428,7 +428,6 @@
       'ToTLinuxTSan',  # https://crbug.com/368525
       'Mac10.10 Tests',  # https://crbug.com/828031
       'Mac10.13 Tests',  # https://crbug.com/1042757
-      'Mac10.13 Tests Code Coverage',
       'Linux TSan Tests',  # https://crbug.com/368525
       'Win10 Tests x64 (dbg)',
     ],
@@ -1891,7 +1890,6 @@
       'Mac10.11 Tests',
       'Mac10.13 Tests',
       'Mac10.13 Tests (dbg)',
-      'Mac10.13 Tests Code Coverage',
       'Mac ASan 64 Tests (1)',
       'ToTMacASan',
     ],
@@ -1939,7 +1937,6 @@
       'Mac10.11 Tests',
       'Mac10.13 Tests',
       'Mac10.13 Tests (dbg)',
-      'Mac10.13 Tests Code Coverage',
       'Mac ASan 64 Tests (1)',
       'ToTMacASan',
     ],
@@ -1957,7 +1954,6 @@
       'Mac10.11 Tests',
       'Mac10.13 Tests',
       'Mac10.13 Tests (dbg)',
-      'Mac10.13 Tests Code Coverage',
       'Mac ASan 64 Tests (1)',
       'ToTMacASan',
     ],
@@ -1974,7 +1970,6 @@
       'Mac10.11 Tests',
       'Mac10.13 Tests',
       'Mac10.13 Tests (dbg)',
-      'Mac10.13 Tests Code Coverage',
       'Mac ASan 64 Tests (1)',
       'ToTMacASan',
     ],
@@ -1996,7 +1991,6 @@
       'Mac10.11 Tests',
       'Mac10.13 Tests',
       'Mac10.13 Tests (dbg)',
-      'Mac10.13 Tests Code Coverage',
       'Mac ASan 64 Tests (1)',
       'ToTMacASan',
     ],
@@ -2760,7 +2754,6 @@
       'Mac10.11 Tests',
       'Mac10.13 Tests',
       'Mac10.13 Tests (dbg)',
-      'Mac10.13 Tests Code Coverage',
       'Linux - Future (dbg)',  # client.v8.chromium
       'Win10 Tests x64',
       'Win10 Tests x64 (dbg)',
diff --git a/testing/buildbot/waterfalls.pyl b/testing/buildbot/waterfalls.pyl
index 31e9536..683f636 100644
--- a/testing/buildbot/waterfalls.pyl
+++ b/testing/buildbot/waterfalls.pyl
@@ -1596,7 +1596,7 @@
           'isolated_scripts': 'win_specific_isolated_scripts',
         },
         'additional_compile_targets': [
-          'all',
+          'chrome_official_builder',
         ],
       },
       'ToTWinThinLTO64': {
@@ -1608,7 +1608,7 @@
           'isolated_scripts': 'win_specific_isolated_scripts',
         },
         'additional_compile_targets': [
-          'all',
+          'chrome_official_builder',
         ],
       },
       'ToTiOS': {
@@ -3225,11 +3225,6 @@
       'GPU Linux Builder (dbg)': {},
       'GPU Mac Builder': {},
       'GPU Mac Builder (dbg)': {},
-      'GPU Mac Builder Code Coverage': {
-        'mixins': [
-          'code-coverage',
-        ],
-      },
       'Linux Debug (NVIDIA)': {
         'browser_config': 'debug',
         'os_type': 'linux',
@@ -3275,19 +3270,6 @@
           'isolated_scripts': 'rendering_desktop_representative_perf_tests_isolated_scripts',
         },
       },
-      'Mac Release (Intel) Code Coverage': {
-        'browser_config': 'release',
-        'os_type': 'mac',
-        'mixins': [
-          'isolate_profile_data',
-          'mac_mini_intel_gpu_stable',
-        ],
-        'test_suites': {
-          'gtest_tests': 'gpu_desktop_gtests',
-          'gpu_telemetry_tests': 'gpu_common_telemetry_tests',
-          'isolated_scripts': 'rendering_desktop_representative_perf_tests_isolated_scripts',
-        },
-      },
       'Mac Retina Debug (AMD)': {
         'browser_config': 'debug',
         'os_type': 'mac',
@@ -3311,19 +3293,6 @@
           'isolated_scripts': 'rendering_desktop_representative_perf_tests_isolated_scripts',
         },
       },
-      'Mac Retina Release (AMD) Code Coverage': {
-        'browser_config': 'release',
-        'os_type': 'mac',
-        'mixins': [
-          'isolate_profile_data',
-          'mac_retina_amd_gpu_stable',
-        ],
-        'test_suites': {
-          'gtest_tests': 'gpu_desktop_gtests',
-          'gpu_telemetry_tests': 'gpu_common_telemetry_tests',
-          'isolated_scripts': 'rendering_desktop_representative_perf_tests_isolated_scripts',
-        },
-      },
       'Win10 x64 Debug (NVIDIA)': {
         'browser_config': 'debug_x64',
         'os_type': 'win',
@@ -4641,14 +4610,6 @@
           'all',
         ],
       },
-      'Mac Builder Code Coverage': {
-        'mixins': [
-          'isolate_profile_data',
-        ],
-        'additional_compile_targets': [
-          'pdf_fuzzers',
-        ],
-      },
       'Mac10.10 Tests': {
         'mixins': [
             'mac_10.10',
@@ -4699,17 +4660,6 @@
           'isolated_scripts': 'chromium_dbg_isolated_scripts',
         },
       },
-      'Mac10.13 Tests Code Coverage': {
-        'mixins': [
-            'isolate_profile_data',
-            'mac_10.13',
-            'no_gpu',
-        ],
-        'test_suites': {
-          'gtest_tests': 'chromium_mac_gtests_no_nacl',
-          'isolated_scripts': 'chromium_mac_rel_isolated_scripts',
-        },
-      },
       'Mac10.14 Tests': {
         'mixins': [
             'mac_10.14',
diff --git a/testing/variations/fieldtrial_testing_config.json b/testing/variations/fieldtrial_testing_config.json
index 940ec87..1d51fee 100644
--- a/testing/variations/fieldtrial_testing_config.json
+++ b/testing/variations/fieldtrial_testing_config.json
@@ -5191,6 +5191,21 @@
             ]
         }
     ],
+    "PasswordCheckIOS": [
+        {
+            "platforms": [
+                "ios"
+            ],
+            "experiments": [
+                {
+                    "name": "Enabled",
+                    "enable_features": [
+                        "PasswordCheck"
+                    ]
+                }
+            ]
+        }
+    ],
     "PasswordCompromisedBubble": [
         {
             "platforms": [
diff --git a/third_party/abseil-cpp/CMake/AbseilDll.cmake b/third_party/abseil-cpp/CMake/AbseilDll.cmake
index cf6a8c9a..d67c439 100644
--- a/third_party/abseil-cpp/CMake/AbseilDll.cmake
+++ b/third_party/abseil-cpp/CMake/AbseilDll.cmake
@@ -250,6 +250,7 @@
   "synchronization/notification.h"
   "synchronization/internal/create_thread_identity.cc"
   "synchronization/internal/create_thread_identity.h"
+  "synchronization/internal/futex.h"
   "synchronization/internal/graphcycles.cc"
   "synchronization/internal/graphcycles.h"
   "synchronization/internal/kernel_timeout.h"
diff --git a/third_party/abseil-cpp/README.chromium b/third_party/abseil-cpp/README.chromium
index 288e986..fda94723 100644
--- a/third_party/abseil-cpp/README.chromium
+++ b/third_party/abseil-cpp/README.chromium
@@ -4,7 +4,7 @@
 License: Apache 2.0
 License File: LICENSE
 Version: 0
-Revision: 4b4f9aae75d3c85bdc07b0575de5d4db40cea439
+Revision: f3f785ab59478dd0312bf1b5df65d380650bf0dc
 Security Critical: yes
 
 Description:
diff --git a/third_party/abseil-cpp/absl/algorithm/container.h b/third_party/abseil-cpp/absl/algorithm/container.h
index 3c4fd73..09b91f74 100644
--- a/third_party/abseil-cpp/absl/algorithm/container.h
+++ b/third_party/abseil-cpp/absl/algorithm/container.h
@@ -93,7 +93,7 @@
 //   std::foo(begin(c), end(c));
 // becomes
 //   std::foo(container_algorithm_internal::begin(c),
-//     container_algorithm_internal::end(c));
+//            container_algorithm_internal::end(c));
 // These are meant for internal use only.
 
 template <typename C>
@@ -351,7 +351,9 @@
   auto last2 = container_algorithm_internal::c_end(c2);
 
   for (; first1 != last1 && first2 != last2; ++first1, (void)++first2) {
-    if (*first1 != *first2) {
+    // Negates equality because Cpp17EqualityComparable doesn't require clients
+    // to overload both `operator==` and `operator!=`.
+    if (!(*first1 == *first2)) {
       break;
     }
   }
diff --git a/third_party/abseil-cpp/absl/algorithm/container_test.cc b/third_party/abseil-cpp/absl/algorithm/container_test.cc
index fb94056..605afc8 100644
--- a/third_party/abseil-cpp/absl/algorithm/container_test.cc
+++ b/third_party/abseil-cpp/absl/algorithm/container_test.cc
@@ -183,6 +183,17 @@
     EXPECT_EQ(result.first, sequence_.end());
     EXPECT_EQ(result.second, std::prev(vector_.end()));
   }
+  {
+    struct NoNotEquals {
+      constexpr bool operator==(NoNotEquals) const { return true; }
+      constexpr bool operator!=(NoNotEquals) const = delete;
+    };
+    std::vector<NoNotEquals> first;
+    std::list<NoNotEquals> second;
+
+    // Check this still compiles.
+    absl::c_mismatch(first, second);
+  }
 }
 
 TEST_F(NonMutatingTest, MismatchWithPredicate) {
diff --git a/third_party/abseil-cpp/absl/base/internal/exponential_biased_test.cc b/third_party/abseil-cpp/absl/base/internal/exponential_biased_test.cc
index 90a482d..075583c 100644
--- a/third_party/abseil-cpp/absl/base/internal/exponential_biased_test.cc
+++ b/third_party/abseil-cpp/absl/base/internal/exponential_biased_test.cc
@@ -185,7 +185,7 @@
   ABSL_CONST_INIT static ExponentialBiased eb_static;
   EXPECT_THAT(eb_static.GetSkipCount(2), Ge(0));
 
-#if ABSL_HAVE_THREAD_LOCAL
+#ifdef ABSL_HAVE_THREAD_LOCAL
   thread_local ExponentialBiased eb_thread;
   EXPECT_THAT(eb_thread.GetSkipCount(2), Ge(0));
 #endif
diff --git a/third_party/abseil-cpp/absl/base/internal/sysinfo.cc b/third_party/abseil-cpp/absl/base/internal/sysinfo.cc
index 349d9268..4a3b205 100644
--- a/third_party/abseil-cpp/absl/base/internal/sysinfo.cc
+++ b/third_party/abseil-cpp/absl/base/internal/sysinfo.cc
@@ -426,7 +426,7 @@
 // userspace construct) to avoid unnecessary system calls. Without this caching,
 // it can take roughly 98ns, while it takes roughly 1ns with this caching.
 pid_t GetCachedTID() {
-#if ABSL_HAVE_THREAD_LOCAL
+#ifdef ABSL_HAVE_THREAD_LOCAL
   static thread_local pid_t thread_id = GetTID();
   return thread_id;
 #else
diff --git a/third_party/abseil-cpp/absl/base/internal/unaligned_access.h b/third_party/abseil-cpp/absl/base/internal/unaligned_access.h
index dd5250de..080c197c 100644
--- a/third_party/abseil-cpp/absl/base/internal/unaligned_access.h
+++ b/third_party/abseil-cpp/absl/base/internal/unaligned_access.h
@@ -45,17 +45,7 @@
 // For all three tools, replacing an unaligned access with a tool-specific
 // callback solves the problem.
 
-// Make sure uint16_t/uint32_t/uint64_t are defined.
-#include <stdint.h>
-
-extern "C" {
-uint16_t __sanitizer_unaligned_load16(const void *p);
-uint32_t __sanitizer_unaligned_load32(const void *p);
-uint64_t __sanitizer_unaligned_load64(const void *p);
-void __sanitizer_unaligned_store16(void *p, uint16_t v);
-void __sanitizer_unaligned_store32(void *p, uint32_t v);
-void __sanitizer_unaligned_store64(void *p, uint64_t v);
-}  // extern "C"
+#include <sanitizer/common_interface_defs.h>
 
 namespace absl {
 ABSL_NAMESPACE_BEGIN
diff --git a/third_party/abseil-cpp/absl/base/internal/unscaledcycleclock.cc b/third_party/abseil-cpp/absl/base/internal/unscaledcycleclock.cc
index f1e7bbe..1545288 100644
--- a/third_party/abseil-cpp/absl/base/internal/unscaledcycleclock.cc
+++ b/third_party/abseil-cpp/absl/base/internal/unscaledcycleclock.cc
@@ -123,9 +123,7 @@
 
 #pragma intrinsic(__rdtsc)
 
-int64_t UnscaledCycleClock::Now() {
-  return __rdtsc();
-}
+int64_t UnscaledCycleClock::Now() { return __rdtsc(); }
 
 double UnscaledCycleClock::Frequency() {
   return base_internal::NominalCPUFrequency();
diff --git a/third_party/abseil-cpp/absl/container/internal/layout_test.cc b/third_party/abseil-cpp/absl/container/internal/layout_test.cc
index 757272f1..1d7158f 100644
--- a/third_party/abseil-cpp/absl/container/internal/layout_test.cc
+++ b/third_party/abseil-cpp/absl/container/internal/layout_test.cc
@@ -128,8 +128,10 @@
   {
     using L = Layout<int32_t, int32_t>;
     SameType<std::tuple<int32_t, int32_t>, L::ElementTypes>();
-    SameType<std::tuple<int32_t, int32_t>, decltype(L::Partial())::ElementTypes>();
-    SameType<std::tuple<int32_t, int32_t>, decltype(L::Partial(0))::ElementTypes>();
+    SameType<std::tuple<int32_t, int32_t>,
+             decltype(L::Partial())::ElementTypes>();
+    SameType<std::tuple<int32_t, int32_t>,
+             decltype(L::Partial(0))::ElementTypes>();
   }
   {
     using L = Layout<int8_t, int32_t, Int128>;
@@ -368,18 +370,21 @@
   {
     using L = Layout<int32_t>;
     EXPECT_EQ(0, Distance(p, Type<const int32_t*>(L::Partial().Pointer<0>(p))));
-    EXPECT_EQ(0, Distance(p, Type<const int32_t*>(L::Partial(3).Pointer<0>(p))));
+    EXPECT_EQ(0,
+              Distance(p, Type<const int32_t*>(L::Partial(3).Pointer<0>(p))));
     EXPECT_EQ(0, Distance(p, Type<const int32_t*>(L(3).Pointer<0>(p))));
   }
   {
     using L = Layout<int32_t, int32_t>;
     EXPECT_EQ(0, Distance(p, Type<const int32_t*>(L::Partial().Pointer<0>(p))));
-    EXPECT_EQ(0, Distance(p, Type<const int32_t*>(L::Partial(3).Pointer<0>(p))));
-    EXPECT_EQ(12, Distance(p, Type<const int32_t*>(L::Partial(3).Pointer<1>(p))));
     EXPECT_EQ(0,
-              Distance(p, Type<const int32_t*>(L::Partial(3, 5).Pointer<0>(p))));
+              Distance(p, Type<const int32_t*>(L::Partial(3).Pointer<0>(p))));
     EXPECT_EQ(12,
-              Distance(p, Type<const int32_t*>(L::Partial(3, 5).Pointer<1>(p))));
+              Distance(p, Type<const int32_t*>(L::Partial(3).Pointer<1>(p))));
+    EXPECT_EQ(
+        0, Distance(p, Type<const int32_t*>(L::Partial(3, 5).Pointer<0>(p))));
+    EXPECT_EQ(
+        12, Distance(p, Type<const int32_t*>(L::Partial(3, 5).Pointer<1>(p))));
     EXPECT_EQ(0, Distance(p, Type<const int32_t*>(L(3, 5).Pointer<0>(p))));
     EXPECT_EQ(12, Distance(p, Type<const int32_t*>(L(3, 5).Pointer<1>(p))));
   }
@@ -387,39 +392,44 @@
     using L = Layout<int8_t, int32_t, Int128>;
     EXPECT_EQ(0, Distance(p, Type<const int8_t*>(L::Partial().Pointer<0>(p))));
     EXPECT_EQ(0, Distance(p, Type<const int8_t*>(L::Partial(0).Pointer<0>(p))));
-    EXPECT_EQ(0, Distance(p, Type<const int32_t*>(L::Partial(0).Pointer<1>(p))));
+    EXPECT_EQ(0,
+              Distance(p, Type<const int32_t*>(L::Partial(0).Pointer<1>(p))));
     EXPECT_EQ(0, Distance(p, Type<const int8_t*>(L::Partial(1).Pointer<0>(p))));
-    EXPECT_EQ(4, Distance(p, Type<const int32_t*>(L::Partial(1).Pointer<1>(p))));
+    EXPECT_EQ(4,
+              Distance(p, Type<const int32_t*>(L::Partial(1).Pointer<1>(p))));
     EXPECT_EQ(0, Distance(p, Type<const int8_t*>(L::Partial(5).Pointer<0>(p))));
-    EXPECT_EQ(8, Distance(p, Type<const int32_t*>(L::Partial(5).Pointer<1>(p))));
+    EXPECT_EQ(8,
+              Distance(p, Type<const int32_t*>(L::Partial(5).Pointer<1>(p))));
     EXPECT_EQ(0,
               Distance(p, Type<const int8_t*>(L::Partial(0, 0).Pointer<0>(p))));
-    EXPECT_EQ(0,
-              Distance(p, Type<const int32_t*>(L::Partial(0, 0).Pointer<1>(p))));
+    EXPECT_EQ(
+        0, Distance(p, Type<const int32_t*>(L::Partial(0, 0).Pointer<1>(p))));
     EXPECT_EQ(0,
               Distance(p, Type<const Int128*>(L::Partial(0, 0).Pointer<2>(p))));
     EXPECT_EQ(0,
               Distance(p, Type<const int8_t*>(L::Partial(1, 0).Pointer<0>(p))));
-    EXPECT_EQ(4,
-              Distance(p, Type<const int32_t*>(L::Partial(1, 0).Pointer<1>(p))));
+    EXPECT_EQ(
+        4, Distance(p, Type<const int32_t*>(L::Partial(1, 0).Pointer<1>(p))));
     EXPECT_EQ(8,
               Distance(p, Type<const Int128*>(L::Partial(1, 0).Pointer<2>(p))));
     EXPECT_EQ(0,
               Distance(p, Type<const int8_t*>(L::Partial(5, 3).Pointer<0>(p))));
-    EXPECT_EQ(8,
-              Distance(p, Type<const int32_t*>(L::Partial(5, 3).Pointer<1>(p))));
+    EXPECT_EQ(
+        8, Distance(p, Type<const int32_t*>(L::Partial(5, 3).Pointer<1>(p))));
     EXPECT_EQ(24,
               Distance(p, Type<const Int128*>(L::Partial(5, 3).Pointer<2>(p))));
     EXPECT_EQ(
         0, Distance(p, Type<const int8_t*>(L::Partial(0, 0, 0).Pointer<0>(p))));
     EXPECT_EQ(
-        0, Distance(p, Type<const int32_t*>(L::Partial(0, 0, 0).Pointer<1>(p))));
+        0,
+        Distance(p, Type<const int32_t*>(L::Partial(0, 0, 0).Pointer<1>(p))));
     EXPECT_EQ(
         0, Distance(p, Type<const Int128*>(L::Partial(0, 0, 0).Pointer<2>(p))));
     EXPECT_EQ(
         0, Distance(p, Type<const int8_t*>(L::Partial(1, 0, 0).Pointer<0>(p))));
     EXPECT_EQ(
-        4, Distance(p, Type<const int32_t*>(L::Partial(1, 0, 0).Pointer<1>(p))));
+        4,
+        Distance(p, Type<const int32_t*>(L::Partial(1, 0, 0).Pointer<1>(p))));
     EXPECT_EQ(
         8, Distance(p, Type<const Int128*>(L::Partial(1, 0, 0).Pointer<2>(p))));
     EXPECT_EQ(
@@ -428,7 +438,8 @@
         24,
         Distance(p, Type<const Int128*>(L::Partial(5, 3, 1).Pointer<2>(p))));
     EXPECT_EQ(
-        8, Distance(p, Type<const int32_t*>(L::Partial(5, 3, 1).Pointer<1>(p))));
+        8,
+        Distance(p, Type<const int32_t*>(L::Partial(5, 3, 1).Pointer<1>(p))));
     EXPECT_EQ(0, Distance(p, Type<const int8_t*>(L(5, 3, 1).Pointer<0>(p))));
     EXPECT_EQ(24, Distance(p, Type<const Int128*>(L(5, 3, 1).Pointer<2>(p))));
     EXPECT_EQ(8, Distance(p, Type<const int32_t*>(L(5, 3, 1).Pointer<1>(p))));
@@ -439,75 +450,78 @@
   alignas(max_align_t) const unsigned char p[100] = {};
   {
     using L = Layout<int32_t>;
-    EXPECT_EQ(0,
-              Distance(p, Type<const int32_t*>(L::Partial().Pointer<int32_t>(p))));
-    EXPECT_EQ(0,
-              Distance(p, Type<const int32_t*>(L::Partial(3).Pointer<int32_t>(p))));
+    EXPECT_EQ(
+        0, Distance(p, Type<const int32_t*>(L::Partial().Pointer<int32_t>(p))));
+    EXPECT_EQ(
+        0,
+        Distance(p, Type<const int32_t*>(L::Partial(3).Pointer<int32_t>(p))));
     EXPECT_EQ(0, Distance(p, Type<const int32_t*>(L(3).Pointer<int32_t>(p))));
   }
   {
     using L = Layout<int8_t, int32_t, Int128>;
-    EXPECT_EQ(0, Distance(p, Type<const int8_t*>(L::Partial().Pointer<int8_t>(p))));
-    EXPECT_EQ(0,
-              Distance(p, Type<const int8_t*>(L::Partial(0).Pointer<int8_t>(p))));
-    EXPECT_EQ(0,
-              Distance(p, Type<const int32_t*>(L::Partial(0).Pointer<int32_t>(p))));
-    EXPECT_EQ(0,
-              Distance(p, Type<const int8_t*>(L::Partial(1).Pointer<int8_t>(p))));
-    EXPECT_EQ(4,
-              Distance(p, Type<const int32_t*>(L::Partial(1).Pointer<int32_t>(p))));
-    EXPECT_EQ(0,
-              Distance(p, Type<const int8_t*>(L::Partial(5).Pointer<int8_t>(p))));
-    EXPECT_EQ(8,
-              Distance(p, Type<const int32_t*>(L::Partial(5).Pointer<int32_t>(p))));
     EXPECT_EQ(
-        0, Distance(p, Type<const int8_t*>(L::Partial(0, 0).Pointer<int8_t>(p))));
+        0, Distance(p, Type<const int8_t*>(L::Partial().Pointer<int8_t>(p))));
     EXPECT_EQ(
-        0, Distance(p, Type<const int32_t*>(L::Partial(0, 0).Pointer<int32_t>(p))));
+        0, Distance(p, Type<const int8_t*>(L::Partial(0).Pointer<int8_t>(p))));
+    EXPECT_EQ(
+        0,
+        Distance(p, Type<const int32_t*>(L::Partial(0).Pointer<int32_t>(p))));
+    EXPECT_EQ(
+        0, Distance(p, Type<const int8_t*>(L::Partial(1).Pointer<int8_t>(p))));
+    EXPECT_EQ(
+        4,
+        Distance(p, Type<const int32_t*>(L::Partial(1).Pointer<int32_t>(p))));
+    EXPECT_EQ(
+        0, Distance(p, Type<const int8_t*>(L::Partial(5).Pointer<int8_t>(p))));
+    EXPECT_EQ(
+        8,
+        Distance(p, Type<const int32_t*>(L::Partial(5).Pointer<int32_t>(p))));
+    EXPECT_EQ(
+        0,
+        Distance(p, Type<const int8_t*>(L::Partial(0, 0).Pointer<int8_t>(p))));
+    EXPECT_EQ(0, Distance(p, Type<const int32_t*>(
+                                 L::Partial(0, 0).Pointer<int32_t>(p))));
     EXPECT_EQ(
         0,
         Distance(p, Type<const Int128*>(L::Partial(0, 0).Pointer<Int128>(p))));
     EXPECT_EQ(
-        0, Distance(p, Type<const int8_t*>(L::Partial(1, 0).Pointer<int8_t>(p))));
-    EXPECT_EQ(
-        4, Distance(p, Type<const int32_t*>(L::Partial(1, 0).Pointer<int32_t>(p))));
+        0,
+        Distance(p, Type<const int8_t*>(L::Partial(1, 0).Pointer<int8_t>(p))));
+    EXPECT_EQ(4, Distance(p, Type<const int32_t*>(
+                                 L::Partial(1, 0).Pointer<int32_t>(p))));
     EXPECT_EQ(
         8,
         Distance(p, Type<const Int128*>(L::Partial(1, 0).Pointer<Int128>(p))));
     EXPECT_EQ(
-        0, Distance(p, Type<const int8_t*>(L::Partial(5, 3).Pointer<int8_t>(p))));
-    EXPECT_EQ(
-        8, Distance(p, Type<const int32_t*>(L::Partial(5, 3).Pointer<int32_t>(p))));
+        0,
+        Distance(p, Type<const int8_t*>(L::Partial(5, 3).Pointer<int8_t>(p))));
+    EXPECT_EQ(8, Distance(p, Type<const int32_t*>(
+                                 L::Partial(5, 3).Pointer<int32_t>(p))));
     EXPECT_EQ(
         24,
         Distance(p, Type<const Int128*>(L::Partial(5, 3).Pointer<Int128>(p))));
-    EXPECT_EQ(
-        0,
-        Distance(p, Type<const int8_t*>(L::Partial(0, 0, 0).Pointer<int8_t>(p))));
-    EXPECT_EQ(
-        0,
-        Distance(p, Type<const int32_t*>(L::Partial(0, 0, 0).Pointer<int32_t>(p))));
+    EXPECT_EQ(0, Distance(p, Type<const int8_t*>(
+                                 L::Partial(0, 0, 0).Pointer<int8_t>(p))));
+    EXPECT_EQ(0, Distance(p, Type<const int32_t*>(
+                                 L::Partial(0, 0, 0).Pointer<int32_t>(p))));
     EXPECT_EQ(0, Distance(p, Type<const Int128*>(
                                  L::Partial(0, 0, 0).Pointer<Int128>(p))));
-    EXPECT_EQ(
-        0,
-        Distance(p, Type<const int8_t*>(L::Partial(1, 0, 0).Pointer<int8_t>(p))));
-    EXPECT_EQ(
-        4,
-        Distance(p, Type<const int32_t*>(L::Partial(1, 0, 0).Pointer<int32_t>(p))));
+    EXPECT_EQ(0, Distance(p, Type<const int8_t*>(
+                                 L::Partial(1, 0, 0).Pointer<int8_t>(p))));
+    EXPECT_EQ(4, Distance(p, Type<const int32_t*>(
+                                 L::Partial(1, 0, 0).Pointer<int32_t>(p))));
     EXPECT_EQ(8, Distance(p, Type<const Int128*>(
                                  L::Partial(1, 0, 0).Pointer<Int128>(p))));
-    EXPECT_EQ(
-        0,
-        Distance(p, Type<const int8_t*>(L::Partial(5, 3, 1).Pointer<int8_t>(p))));
+    EXPECT_EQ(0, Distance(p, Type<const int8_t*>(
+                                 L::Partial(5, 3, 1).Pointer<int8_t>(p))));
     EXPECT_EQ(24, Distance(p, Type<const Int128*>(
                                   L::Partial(5, 3, 1).Pointer<Int128>(p))));
-    EXPECT_EQ(
-        8,
-        Distance(p, Type<const int32_t*>(L::Partial(5, 3, 1).Pointer<int32_t>(p))));
+    EXPECT_EQ(8, Distance(p, Type<const int32_t*>(
+                                 L::Partial(5, 3, 1).Pointer<int32_t>(p))));
     EXPECT_EQ(24,
               Distance(p, Type<const Int128*>(L(5, 3, 1).Pointer<Int128>(p))));
-    EXPECT_EQ(8, Distance(p, Type<const int32_t*>(L(5, 3, 1).Pointer<int32_t>(p))));
+    EXPECT_EQ(
+        8, Distance(p, Type<const int32_t*>(L(5, 3, 1).Pointer<int32_t>(p))));
   }
 }
 
@@ -548,15 +562,18 @@
     EXPECT_EQ(8, Distance(p, Type<int32_t*>(L::Partial(5, 3).Pointer<1>(p))));
     EXPECT_EQ(24, Distance(p, Type<Int128*>(L::Partial(5, 3).Pointer<2>(p))));
     EXPECT_EQ(0, Distance(p, Type<int8_t*>(L::Partial(0, 0, 0).Pointer<0>(p))));
-    EXPECT_EQ(0, Distance(p, Type<int32_t*>(L::Partial(0, 0, 0).Pointer<1>(p))));
+    EXPECT_EQ(0,
+              Distance(p, Type<int32_t*>(L::Partial(0, 0, 0).Pointer<1>(p))));
     EXPECT_EQ(0, Distance(p, Type<Int128*>(L::Partial(0, 0, 0).Pointer<2>(p))));
     EXPECT_EQ(0, Distance(p, Type<int8_t*>(L::Partial(1, 0, 0).Pointer<0>(p))));
-    EXPECT_EQ(4, Distance(p, Type<int32_t*>(L::Partial(1, 0, 0).Pointer<1>(p))));
+    EXPECT_EQ(4,
+              Distance(p, Type<int32_t*>(L::Partial(1, 0, 0).Pointer<1>(p))));
     EXPECT_EQ(8, Distance(p, Type<Int128*>(L::Partial(1, 0, 0).Pointer<2>(p))));
     EXPECT_EQ(0, Distance(p, Type<int8_t*>(L::Partial(5, 3, 1).Pointer<0>(p))));
     EXPECT_EQ(24,
               Distance(p, Type<Int128*>(L::Partial(5, 3, 1).Pointer<2>(p))));
-    EXPECT_EQ(8, Distance(p, Type<int32_t*>(L::Partial(5, 3, 1).Pointer<1>(p))));
+    EXPECT_EQ(8,
+              Distance(p, Type<int32_t*>(L::Partial(5, 3, 1).Pointer<1>(p))));
     EXPECT_EQ(0, Distance(p, Type<int8_t*>(L(5, 3, 1).Pointer<0>(p))));
     EXPECT_EQ(24, Distance(p, Type<Int128*>(L(5, 3, 1).Pointer<2>(p))));
     EXPECT_EQ(8, Distance(p, Type<int32_t*>(L(5, 3, 1).Pointer<1>(p))));
@@ -568,48 +585,61 @@
   {
     using L = Layout<int32_t>;
     EXPECT_EQ(0, Distance(p, Type<int32_t*>(L::Partial().Pointer<int32_t>(p))));
-    EXPECT_EQ(0, Distance(p, Type<int32_t*>(L::Partial(3).Pointer<int32_t>(p))));
+    EXPECT_EQ(0,
+              Distance(p, Type<int32_t*>(L::Partial(3).Pointer<int32_t>(p))));
     EXPECT_EQ(0, Distance(p, Type<int32_t*>(L(3).Pointer<int32_t>(p))));
   }
   {
     using L = Layout<int8_t, int32_t, Int128>;
     EXPECT_EQ(0, Distance(p, Type<int8_t*>(L::Partial().Pointer<int8_t>(p))));
     EXPECT_EQ(0, Distance(p, Type<int8_t*>(L::Partial(0).Pointer<int8_t>(p))));
-    EXPECT_EQ(0, Distance(p, Type<int32_t*>(L::Partial(0).Pointer<int32_t>(p))));
+    EXPECT_EQ(0,
+              Distance(p, Type<int32_t*>(L::Partial(0).Pointer<int32_t>(p))));
     EXPECT_EQ(0, Distance(p, Type<int8_t*>(L::Partial(1).Pointer<int8_t>(p))));
-    EXPECT_EQ(4, Distance(p, Type<int32_t*>(L::Partial(1).Pointer<int32_t>(p))));
+    EXPECT_EQ(4,
+              Distance(p, Type<int32_t*>(L::Partial(1).Pointer<int32_t>(p))));
     EXPECT_EQ(0, Distance(p, Type<int8_t*>(L::Partial(5).Pointer<int8_t>(p))));
-    EXPECT_EQ(8, Distance(p, Type<int32_t*>(L::Partial(5).Pointer<int32_t>(p))));
-    EXPECT_EQ(0, Distance(p, Type<int8_t*>(L::Partial(0, 0).Pointer<int8_t>(p))));
-    EXPECT_EQ(0, Distance(p, Type<int32_t*>(L::Partial(0, 0).Pointer<int32_t>(p))));
+    EXPECT_EQ(8,
+              Distance(p, Type<int32_t*>(L::Partial(5).Pointer<int32_t>(p))));
+    EXPECT_EQ(0,
+              Distance(p, Type<int8_t*>(L::Partial(0, 0).Pointer<int8_t>(p))));
+    EXPECT_EQ(
+        0, Distance(p, Type<int32_t*>(L::Partial(0, 0).Pointer<int32_t>(p))));
     EXPECT_EQ(0,
               Distance(p, Type<Int128*>(L::Partial(0, 0).Pointer<Int128>(p))));
-    EXPECT_EQ(0, Distance(p, Type<int8_t*>(L::Partial(1, 0).Pointer<int8_t>(p))));
-    EXPECT_EQ(4, Distance(p, Type<int32_t*>(L::Partial(1, 0).Pointer<int32_t>(p))));
+    EXPECT_EQ(0,
+              Distance(p, Type<int8_t*>(L::Partial(1, 0).Pointer<int8_t>(p))));
+    EXPECT_EQ(
+        4, Distance(p, Type<int32_t*>(L::Partial(1, 0).Pointer<int32_t>(p))));
     EXPECT_EQ(8,
               Distance(p, Type<Int128*>(L::Partial(1, 0).Pointer<Int128>(p))));
-    EXPECT_EQ(0, Distance(p, Type<int8_t*>(L::Partial(5, 3).Pointer<int8_t>(p))));
-    EXPECT_EQ(8, Distance(p, Type<int32_t*>(L::Partial(5, 3).Pointer<int32_t>(p))));
+    EXPECT_EQ(0,
+              Distance(p, Type<int8_t*>(L::Partial(5, 3).Pointer<int8_t>(p))));
+    EXPECT_EQ(
+        8, Distance(p, Type<int32_t*>(L::Partial(5, 3).Pointer<int32_t>(p))));
     EXPECT_EQ(24,
               Distance(p, Type<Int128*>(L::Partial(5, 3).Pointer<Int128>(p))));
-    EXPECT_EQ(0,
-              Distance(p, Type<int8_t*>(L::Partial(0, 0, 0).Pointer<int8_t>(p))));
-    EXPECT_EQ(0,
-              Distance(p, Type<int32_t*>(L::Partial(0, 0, 0).Pointer<int32_t>(p))));
+    EXPECT_EQ(
+        0, Distance(p, Type<int8_t*>(L::Partial(0, 0, 0).Pointer<int8_t>(p))));
+    EXPECT_EQ(
+        0,
+        Distance(p, Type<int32_t*>(L::Partial(0, 0, 0).Pointer<int32_t>(p))));
     EXPECT_EQ(
         0, Distance(p, Type<Int128*>(L::Partial(0, 0, 0).Pointer<Int128>(p))));
-    EXPECT_EQ(0,
-              Distance(p, Type<int8_t*>(L::Partial(1, 0, 0).Pointer<int8_t>(p))));
-    EXPECT_EQ(4,
-              Distance(p, Type<int32_t*>(L::Partial(1, 0, 0).Pointer<int32_t>(p))));
+    EXPECT_EQ(
+        0, Distance(p, Type<int8_t*>(L::Partial(1, 0, 0).Pointer<int8_t>(p))));
+    EXPECT_EQ(
+        4,
+        Distance(p, Type<int32_t*>(L::Partial(1, 0, 0).Pointer<int32_t>(p))));
     EXPECT_EQ(
         8, Distance(p, Type<Int128*>(L::Partial(1, 0, 0).Pointer<Int128>(p))));
-    EXPECT_EQ(0,
-              Distance(p, Type<int8_t*>(L::Partial(5, 3, 1).Pointer<int8_t>(p))));
+    EXPECT_EQ(
+        0, Distance(p, Type<int8_t*>(L::Partial(5, 3, 1).Pointer<int8_t>(p))));
     EXPECT_EQ(
         24, Distance(p, Type<Int128*>(L::Partial(5, 3, 1).Pointer<Int128>(p))));
-    EXPECT_EQ(8,
-              Distance(p, Type<int32_t*>(L::Partial(5, 3, 1).Pointer<int32_t>(p))));
+    EXPECT_EQ(
+        8,
+        Distance(p, Type<int32_t*>(L::Partial(5, 3, 1).Pointer<int32_t>(p))));
     EXPECT_EQ(0, Distance(p, Type<int8_t*>(L(5, 3, 1).Pointer<int8_t>(p))));
     EXPECT_EQ(24, Distance(p, Type<Int128*>(L(5, 3, 1).Pointer<Int128>(p))));
     EXPECT_EQ(8, Distance(p, Type<int32_t*>(L(5, 3, 1).Pointer<int32_t>(p))));
@@ -790,67 +820,72 @@
   {
     using L = Layout<int32_t>;
     EXPECT_EQ(
-        0,
-        Distance(p, Type<Span<const int32_t>>(L::Partial(0).Slice<0>(p)).data()));
+        0, Distance(
+               p, Type<Span<const int32_t>>(L::Partial(0).Slice<0>(p)).data()));
     EXPECT_EQ(
-        0,
-        Distance(p, Type<Span<const int32_t>>(L::Partial(3).Slice<0>(p)).data()));
-    EXPECT_EQ(0, Distance(p, Type<Span<const int32_t>>(L(3).Slice<0>(p)).data()));
+        0, Distance(
+               p, Type<Span<const int32_t>>(L::Partial(3).Slice<0>(p)).data()));
+    EXPECT_EQ(0,
+              Distance(p, Type<Span<const int32_t>>(L(3).Slice<0>(p)).data()));
   }
   {
     using L = Layout<int32_t, int32_t>;
     EXPECT_EQ(
-        0,
-        Distance(p, Type<Span<const int32_t>>(L::Partial(3).Slice<0>(p)).data()));
+        0, Distance(
+               p, Type<Span<const int32_t>>(L::Partial(3).Slice<0>(p)).data()));
     EXPECT_EQ(
         0,
-        Distance(p,
-                 Type<Span<const int32_t>>(L::Partial(3, 5).Slice<0>(p)).data()));
+        Distance(
+            p, Type<Span<const int32_t>>(L::Partial(3, 5).Slice<0>(p)).data()));
     EXPECT_EQ(
         12,
-        Distance(p,
-                 Type<Span<const int32_t>>(L::Partial(3, 5).Slice<1>(p)).data()));
-    EXPECT_EQ(0,
-              Distance(p, Type<Span<const int32_t>>(L(3, 5).Slice<0>(p)).data()));
-    EXPECT_EQ(12,
-              Distance(p, Type<Span<const int32_t>>(L(3, 5).Slice<1>(p)).data()));
+        Distance(
+            p, Type<Span<const int32_t>>(L::Partial(3, 5).Slice<1>(p)).data()));
+    EXPECT_EQ(
+        0, Distance(p, Type<Span<const int32_t>>(L(3, 5).Slice<0>(p)).data()));
+    EXPECT_EQ(
+        12, Distance(p, Type<Span<const int32_t>>(L(3, 5).Slice<1>(p)).data()));
   }
   {
     using L = Layout<int8_t, int32_t, Int128>;
     EXPECT_EQ(
-        0,
-        Distance(p, Type<Span<const int8_t>>(L::Partial(0).Slice<0>(p)).data()));
-    EXPECT_EQ(
-        0,
-        Distance(p, Type<Span<const int8_t>>(L::Partial(1).Slice<0>(p)).data()));
-    EXPECT_EQ(
-        0,
-        Distance(p, Type<Span<const int8_t>>(L::Partial(5).Slice<0>(p)).data()));
+        0, Distance(
+               p, Type<Span<const int8_t>>(L::Partial(0).Slice<0>(p)).data()));
     EXPECT_EQ(
         0, Distance(
-               p, Type<Span<const int8_t>>(L::Partial(0, 0).Slice<0>(p)).data()));
-    EXPECT_EQ(
-        0,
-        Distance(p,
-                 Type<Span<const int32_t>>(L::Partial(0, 0).Slice<1>(p)).data()));
+               p, Type<Span<const int8_t>>(L::Partial(1).Slice<0>(p)).data()));
     EXPECT_EQ(
         0, Distance(
-               p, Type<Span<const int8_t>>(L::Partial(1, 0).Slice<0>(p)).data()));
-    EXPECT_EQ(
-        4,
-        Distance(p,
-                 Type<Span<const int32_t>>(L::Partial(1, 0).Slice<1>(p)).data()));
-    EXPECT_EQ(
-        0, Distance(
-               p, Type<Span<const int8_t>>(L::Partial(5, 3).Slice<0>(p)).data()));
-    EXPECT_EQ(
-        8,
-        Distance(p,
-                 Type<Span<const int32_t>>(L::Partial(5, 3).Slice<1>(p)).data()));
+               p, Type<Span<const int8_t>>(L::Partial(5).Slice<0>(p)).data()));
     EXPECT_EQ(
         0,
         Distance(
-            p, Type<Span<const int8_t>>(L::Partial(0, 0, 0).Slice<0>(p)).data()));
+            p, Type<Span<const int8_t>>(L::Partial(0, 0).Slice<0>(p)).data()));
+    EXPECT_EQ(
+        0,
+        Distance(
+            p, Type<Span<const int32_t>>(L::Partial(0, 0).Slice<1>(p)).data()));
+    EXPECT_EQ(
+        0,
+        Distance(
+            p, Type<Span<const int8_t>>(L::Partial(1, 0).Slice<0>(p)).data()));
+    EXPECT_EQ(
+        4,
+        Distance(
+            p, Type<Span<const int32_t>>(L::Partial(1, 0).Slice<1>(p)).data()));
+    EXPECT_EQ(
+        0,
+        Distance(
+            p, Type<Span<const int8_t>>(L::Partial(5, 3).Slice<0>(p)).data()));
+    EXPECT_EQ(
+        8,
+        Distance(
+            p, Type<Span<const int32_t>>(L::Partial(5, 3).Slice<1>(p)).data()));
+    EXPECT_EQ(
+        0,
+        Distance(
+            p,
+            Type<Span<const int8_t>>(L::Partial(0, 0, 0).Slice<0>(p)).data()));
     EXPECT_EQ(
         0,
         Distance(
@@ -864,7 +899,8 @@
     EXPECT_EQ(
         0,
         Distance(
-            p, Type<Span<const int8_t>>(L::Partial(1, 0, 0).Slice<0>(p)).data()));
+            p,
+            Type<Span<const int8_t>>(L::Partial(1, 0, 0).Slice<0>(p)).data()));
     EXPECT_EQ(
         4,
         Distance(
@@ -878,7 +914,8 @@
     EXPECT_EQ(
         0,
         Distance(
-            p, Type<Span<const int8_t>>(L::Partial(5, 3, 1).Slice<0>(p)).data()));
+            p,
+            Type<Span<const int8_t>>(L::Partial(5, 3, 1).Slice<0>(p)).data()));
     EXPECT_EQ(
         24,
         Distance(
@@ -890,12 +927,14 @@
             p,
             Type<Span<const int32_t>>(L::Partial(5, 3, 1).Slice<1>(p)).data()));
     EXPECT_EQ(
-        0, Distance(p, Type<Span<const int8_t>>(L(5, 3, 1).Slice<0>(p)).data()));
+        0,
+        Distance(p, Type<Span<const int8_t>>(L(5, 3, 1).Slice<0>(p)).data()));
     EXPECT_EQ(
         24,
         Distance(p, Type<Span<const Int128>>(L(5, 3, 1).Slice<2>(p)).data()));
     EXPECT_EQ(
-        8, Distance(p, Type<Span<const int32_t>>(L(5, 3, 1).Slice<1>(p)).data()));
+        8,
+        Distance(p, Type<Span<const int32_t>>(L(5, 3, 1).Slice<1>(p)).data()));
   }
 }
 
@@ -906,98 +945,94 @@
     EXPECT_EQ(
         0,
         Distance(
-            p, Type<Span<const int32_t>>(L::Partial(0).Slice<int32_t>(p)).data()));
+            p,
+            Type<Span<const int32_t>>(L::Partial(0).Slice<int32_t>(p)).data()));
     EXPECT_EQ(
         0,
         Distance(
-            p, Type<Span<const int32_t>>(L::Partial(3).Slice<int32_t>(p)).data()));
+            p,
+            Type<Span<const int32_t>>(L::Partial(3).Slice<int32_t>(p)).data()));
     EXPECT_EQ(
-        0, Distance(p, Type<Span<const int32_t>>(L(3).Slice<int32_t>(p)).data()));
+        0,
+        Distance(p, Type<Span<const int32_t>>(L(3).Slice<int32_t>(p)).data()));
   }
   {
     using L = Layout<int8_t, int32_t, Int128>;
     EXPECT_EQ(
-        0, Distance(
-               p, Type<Span<const int8_t>>(L::Partial(0).Slice<int8_t>(p)).data()));
-    EXPECT_EQ(
-        0, Distance(
-               p, Type<Span<const int8_t>>(L::Partial(1).Slice<int8_t>(p)).data()));
-    EXPECT_EQ(
-        0, Distance(
-               p, Type<Span<const int8_t>>(L::Partial(5).Slice<int8_t>(p)).data()));
-    EXPECT_EQ(
         0,
         Distance(
-            p, Type<Span<const int8_t>>(L::Partial(0, 0).Slice<int8_t>(p)).data()));
+            p,
+            Type<Span<const int8_t>>(L::Partial(0).Slice<int8_t>(p)).data()));
     EXPECT_EQ(
         0,
         Distance(
             p,
-            Type<Span<const int32_t>>(L::Partial(0, 0).Slice<int32_t>(p)).data()));
-    EXPECT_EQ(
-        0,
-        Distance(
-            p, Type<Span<const int8_t>>(L::Partial(1, 0).Slice<int8_t>(p)).data()));
-    EXPECT_EQ(
-        4,
-        Distance(
-            p,
-            Type<Span<const int32_t>>(L::Partial(1, 0).Slice<int32_t>(p)).data()));
-    EXPECT_EQ(
-        0,
-        Distance(
-            p, Type<Span<const int8_t>>(L::Partial(5, 3).Slice<int8_t>(p)).data()));
-    EXPECT_EQ(
-        8,
-        Distance(
-            p,
-            Type<Span<const int32_t>>(L::Partial(5, 3).Slice<int32_t>(p)).data()));
+            Type<Span<const int8_t>>(L::Partial(1).Slice<int8_t>(p)).data()));
     EXPECT_EQ(
         0,
         Distance(
             p,
-            Type<Span<const int8_t>>(L::Partial(0, 0, 0).Slice<int8_t>(p)).data()));
+            Type<Span<const int8_t>>(L::Partial(5).Slice<int8_t>(p)).data()));
     EXPECT_EQ(
         0,
-        Distance(p, Type<Span<const int32_t>>(L::Partial(0, 0, 0).Slice<int32_t>(p))
+        Distance(p, Type<Span<const int8_t>>(L::Partial(0, 0).Slice<int8_t>(p))
                         .data()));
+    EXPECT_EQ(0, Distance(p, Type<Span<const int32_t>>(
+                                 L::Partial(0, 0).Slice<int32_t>(p))
+                                 .data()));
+    EXPECT_EQ(
+        0,
+        Distance(p, Type<Span<const int8_t>>(L::Partial(1, 0).Slice<int8_t>(p))
+                        .data()));
+    EXPECT_EQ(4, Distance(p, Type<Span<const int32_t>>(
+                                 L::Partial(1, 0).Slice<int32_t>(p))
+                                 .data()));
+    EXPECT_EQ(
+        0,
+        Distance(p, Type<Span<const int8_t>>(L::Partial(5, 3).Slice<int8_t>(p))
+                        .data()));
+    EXPECT_EQ(8, Distance(p, Type<Span<const int32_t>>(
+                                 L::Partial(5, 3).Slice<int32_t>(p))
+                                 .data()));
+    EXPECT_EQ(0, Distance(p, Type<Span<const int8_t>>(
+                                 L::Partial(0, 0, 0).Slice<int8_t>(p))
+                                 .data()));
+    EXPECT_EQ(0, Distance(p, Type<Span<const int32_t>>(
+                                 L::Partial(0, 0, 0).Slice<int32_t>(p))
+                                 .data()));
     EXPECT_EQ(0, Distance(p, Type<Span<const Int128>>(
                                  L::Partial(0, 0, 0).Slice<Int128>(p))
                                  .data()));
-    EXPECT_EQ(
-        0,
-        Distance(
-            p,
-            Type<Span<const int8_t>>(L::Partial(1, 0, 0).Slice<int8_t>(p)).data()));
-    EXPECT_EQ(
-        4,
-        Distance(p, Type<Span<const int32_t>>(L::Partial(1, 0, 0).Slice<int32_t>(p))
-                        .data()));
+    EXPECT_EQ(0, Distance(p, Type<Span<const int8_t>>(
+                                 L::Partial(1, 0, 0).Slice<int8_t>(p))
+                                 .data()));
+    EXPECT_EQ(4, Distance(p, Type<Span<const int32_t>>(
+                                 L::Partial(1, 0, 0).Slice<int32_t>(p))
+                                 .data()));
     EXPECT_EQ(8, Distance(p, Type<Span<const Int128>>(
                                  L::Partial(1, 0, 0).Slice<Int128>(p))
                                  .data()));
-    EXPECT_EQ(
-        0,
-        Distance(
-            p,
-            Type<Span<const int8_t>>(L::Partial(5, 3, 1).Slice<int8_t>(p)).data()));
+    EXPECT_EQ(0, Distance(p, Type<Span<const int8_t>>(
+                                 L::Partial(5, 3, 1).Slice<int8_t>(p))
+                                 .data()));
     EXPECT_EQ(24, Distance(p, Type<Span<const Int128>>(
                                   L::Partial(5, 3, 1).Slice<Int128>(p))
                                   .data()));
-    EXPECT_EQ(
-        8,
-        Distance(p, Type<Span<const int32_t>>(L::Partial(5, 3, 1).Slice<int32_t>(p))
-                        .data()));
+    EXPECT_EQ(8, Distance(p, Type<Span<const int32_t>>(
+                                 L::Partial(5, 3, 1).Slice<int32_t>(p))
+                                 .data()));
     EXPECT_EQ(
         0,
-        Distance(p, Type<Span<const int8_t>>(L(5, 3, 1).Slice<int8_t>(p)).data()));
+        Distance(p,
+                 Type<Span<const int8_t>>(L(5, 3, 1).Slice<int8_t>(p)).data()));
     EXPECT_EQ(
         24,
         Distance(p,
                  Type<Span<const Int128>>(L(5, 3, 1).Slice<Int128>(p)).data()));
     EXPECT_EQ(
-        8, Distance(
-               p, Type<Span<const int32_t>>(L(5, 3, 1).Slice<int32_t>(p)).data()));
+        8,
+        Distance(
+            p, Type<Span<const int32_t>>(L(5, 3, 1).Slice<int32_t>(p)).data()));
   }
 }
 
@@ -1005,18 +1040,19 @@
   alignas(max_align_t) unsigned char p[100];
   {
     using L = Layout<int32_t>;
-    EXPECT_EQ(0,
-              Distance(p, Type<Span<int32_t>>(L::Partial(0).Slice<0>(p)).data()));
-    EXPECT_EQ(0,
-              Distance(p, Type<Span<int32_t>>(L::Partial(3).Slice<0>(p)).data()));
+    EXPECT_EQ(
+        0, Distance(p, Type<Span<int32_t>>(L::Partial(0).Slice<0>(p)).data()));
+    EXPECT_EQ(
+        0, Distance(p, Type<Span<int32_t>>(L::Partial(3).Slice<0>(p)).data()));
     EXPECT_EQ(0, Distance(p, Type<Span<int32_t>>(L(3).Slice<0>(p)).data()));
   }
   {
     using L = Layout<int32_t, int32_t>;
-    EXPECT_EQ(0,
-              Distance(p, Type<Span<int32_t>>(L::Partial(3).Slice<0>(p)).data()));
     EXPECT_EQ(
-        0, Distance(p, Type<Span<int32_t>>(L::Partial(3, 5).Slice<0>(p)).data()));
+        0, Distance(p, Type<Span<int32_t>>(L::Partial(3).Slice<0>(p)).data()));
+    EXPECT_EQ(
+        0,
+        Distance(p, Type<Span<int32_t>>(L::Partial(3, 5).Slice<0>(p)).data()));
     EXPECT_EQ(
         12,
         Distance(p, Type<Span<int32_t>>(L::Partial(3, 5).Slice<1>(p)).data()));
@@ -1025,55 +1061,63 @@
   }
   {
     using L = Layout<int8_t, int32_t, Int128>;
-    EXPECT_EQ(0,
-              Distance(p, Type<Span<int8_t>>(L::Partial(0).Slice<0>(p)).data()));
-    EXPECT_EQ(0,
-              Distance(p, Type<Span<int8_t>>(L::Partial(1).Slice<0>(p)).data()));
-    EXPECT_EQ(0,
-              Distance(p, Type<Span<int8_t>>(L::Partial(5).Slice<0>(p)).data()));
     EXPECT_EQ(
-        0, Distance(p, Type<Span<int8_t>>(L::Partial(0, 0).Slice<0>(p)).data()));
+        0, Distance(p, Type<Span<int8_t>>(L::Partial(0).Slice<0>(p)).data()));
     EXPECT_EQ(
-        0, Distance(p, Type<Span<int32_t>>(L::Partial(0, 0).Slice<1>(p)).data()));
+        0, Distance(p, Type<Span<int8_t>>(L::Partial(1).Slice<0>(p)).data()));
     EXPECT_EQ(
-        0, Distance(p, Type<Span<int8_t>>(L::Partial(1, 0).Slice<0>(p)).data()));
-    EXPECT_EQ(
-        4, Distance(p, Type<Span<int32_t>>(L::Partial(1, 0).Slice<1>(p)).data()));
-    EXPECT_EQ(
-        0, Distance(p, Type<Span<int8_t>>(L::Partial(5, 3).Slice<0>(p)).data()));
-    EXPECT_EQ(
-        8, Distance(p, Type<Span<int32_t>>(L::Partial(5, 3).Slice<1>(p)).data()));
+        0, Distance(p, Type<Span<int8_t>>(L::Partial(5).Slice<0>(p)).data()));
     EXPECT_EQ(
         0,
-        Distance(p, Type<Span<int8_t>>(L::Partial(0, 0, 0).Slice<0>(p)).data()));
+        Distance(p, Type<Span<int8_t>>(L::Partial(0, 0).Slice<0>(p)).data()));
     EXPECT_EQ(
         0,
-        Distance(p, Type<Span<int32_t>>(L::Partial(0, 0, 0).Slice<1>(p)).data()));
+        Distance(p, Type<Span<int32_t>>(L::Partial(0, 0).Slice<1>(p)).data()));
+    EXPECT_EQ(
+        0,
+        Distance(p, Type<Span<int8_t>>(L::Partial(1, 0).Slice<0>(p)).data()));
+    EXPECT_EQ(
+        4,
+        Distance(p, Type<Span<int32_t>>(L::Partial(1, 0).Slice<1>(p)).data()));
+    EXPECT_EQ(
+        0,
+        Distance(p, Type<Span<int8_t>>(L::Partial(5, 3).Slice<0>(p)).data()));
+    EXPECT_EQ(
+        8,
+        Distance(p, Type<Span<int32_t>>(L::Partial(5, 3).Slice<1>(p)).data()));
+    EXPECT_EQ(
+        0, Distance(
+               p, Type<Span<int8_t>>(L::Partial(0, 0, 0).Slice<0>(p)).data()));
+    EXPECT_EQ(
+        0, Distance(
+               p, Type<Span<int32_t>>(L::Partial(0, 0, 0).Slice<1>(p)).data()));
     EXPECT_EQ(
         0, Distance(
                p, Type<Span<Int128>>(L::Partial(0, 0, 0).Slice<2>(p)).data()));
     EXPECT_EQ(
-        0,
-        Distance(p, Type<Span<int8_t>>(L::Partial(1, 0, 0).Slice<0>(p)).data()));
+        0, Distance(
+               p, Type<Span<int8_t>>(L::Partial(1, 0, 0).Slice<0>(p)).data()));
     EXPECT_EQ(
-        4,
-        Distance(p, Type<Span<int32_t>>(L::Partial(1, 0, 0).Slice<1>(p)).data()));
+        4, Distance(
+               p, Type<Span<int32_t>>(L::Partial(1, 0, 0).Slice<1>(p)).data()));
     EXPECT_EQ(
         8, Distance(
                p, Type<Span<Int128>>(L::Partial(1, 0, 0).Slice<2>(p)).data()));
     EXPECT_EQ(
-        0,
-        Distance(p, Type<Span<int8_t>>(L::Partial(5, 3, 1).Slice<0>(p)).data()));
+        0, Distance(
+               p, Type<Span<int8_t>>(L::Partial(5, 3, 1).Slice<0>(p)).data()));
     EXPECT_EQ(
         24, Distance(
                 p, Type<Span<Int128>>(L::Partial(5, 3, 1).Slice<2>(p)).data()));
     EXPECT_EQ(
-        8,
-        Distance(p, Type<Span<int32_t>>(L::Partial(5, 3, 1).Slice<1>(p)).data()));
-    EXPECT_EQ(0, Distance(p, Type<Span<int8_t>>(L(5, 3, 1).Slice<0>(p)).data()));
+        8, Distance(
+               p, Type<Span<int32_t>>(L::Partial(5, 3, 1).Slice<1>(p)).data()));
+    EXPECT_EQ(0,
+              Distance(p, Type<Span<int8_t>>(L(5, 3, 1).Slice<0>(p)).data()));
     EXPECT_EQ(24,
               Distance(p, Type<Span<Int128>>(L(5, 3, 1).Slice<2>(p)).data()));
-    EXPECT_EQ(8, Distance(p, Type<Span<int32_t>>(L(5, 3, 1).Slice<1>(p)).data()));
+    EXPECT_EQ(8,
+              Distance(p, Type<Span<int32_t>>(L(5, 3, 1).Slice<1>(p)).data()));
   }
 }
 
@@ -1082,66 +1126,84 @@
   {
     using L = Layout<int32_t>;
     EXPECT_EQ(
-        0,
-        Distance(p, Type<Span<int32_t>>(L::Partial(0).Slice<int32_t>(p)).data()));
+        0, Distance(
+               p, Type<Span<int32_t>>(L::Partial(0).Slice<int32_t>(p)).data()));
     EXPECT_EQ(
-        0,
-        Distance(p, Type<Span<int32_t>>(L::Partial(3).Slice<int32_t>(p)).data()));
-    EXPECT_EQ(0, Distance(p, Type<Span<int32_t>>(L(3).Slice<int32_t>(p)).data()));
+        0, Distance(
+               p, Type<Span<int32_t>>(L::Partial(3).Slice<int32_t>(p)).data()));
+    EXPECT_EQ(0,
+              Distance(p, Type<Span<int32_t>>(L(3).Slice<int32_t>(p)).data()));
   }
   {
     using L = Layout<int8_t, int32_t, Int128>;
     EXPECT_EQ(
-        0, Distance(p, Type<Span<int8_t>>(L::Partial(0).Slice<int8_t>(p)).data()));
-    EXPECT_EQ(
-        0, Distance(p, Type<Span<int8_t>>(L::Partial(1).Slice<int8_t>(p)).data()));
-    EXPECT_EQ(
-        0, Distance(p, Type<Span<int8_t>>(L::Partial(5).Slice<int8_t>(p)).data()));
+        0,
+        Distance(p, Type<Span<int8_t>>(L::Partial(0).Slice<int8_t>(p)).data()));
     EXPECT_EQ(
         0,
-        Distance(p, Type<Span<int8_t>>(L::Partial(0, 0).Slice<int8_t>(p)).data()));
-    EXPECT_EQ(
-        0, Distance(
-               p, Type<Span<int32_t>>(L::Partial(0, 0).Slice<int32_t>(p)).data()));
+        Distance(p, Type<Span<int8_t>>(L::Partial(1).Slice<int8_t>(p)).data()));
     EXPECT_EQ(
         0,
-        Distance(p, Type<Span<int8_t>>(L::Partial(1, 0).Slice<int8_t>(p)).data()));
-    EXPECT_EQ(
-        4, Distance(
-               p, Type<Span<int32_t>>(L::Partial(1, 0).Slice<int32_t>(p)).data()));
+        Distance(p, Type<Span<int8_t>>(L::Partial(5).Slice<int8_t>(p)).data()));
     EXPECT_EQ(
         0,
-        Distance(p, Type<Span<int8_t>>(L::Partial(5, 3).Slice<int8_t>(p)).data()));
-    EXPECT_EQ(
-        8, Distance(
-               p, Type<Span<int32_t>>(L::Partial(5, 3).Slice<int32_t>(p)).data()));
-    EXPECT_EQ(
-        0, Distance(
-               p, Type<Span<int8_t>>(L::Partial(0, 0, 0).Slice<int8_t>(p)).data()));
+        Distance(p,
+                 Type<Span<int8_t>>(L::Partial(0, 0).Slice<int8_t>(p)).data()));
     EXPECT_EQ(
         0,
         Distance(
-            p, Type<Span<int32_t>>(L::Partial(0, 0, 0).Slice<int32_t>(p)).data()));
+            p, Type<Span<int32_t>>(L::Partial(0, 0).Slice<int32_t>(p)).data()));
+    EXPECT_EQ(
+        0,
+        Distance(p,
+                 Type<Span<int8_t>>(L::Partial(1, 0).Slice<int8_t>(p)).data()));
+    EXPECT_EQ(
+        4,
+        Distance(
+            p, Type<Span<int32_t>>(L::Partial(1, 0).Slice<int32_t>(p)).data()));
+    EXPECT_EQ(
+        0,
+        Distance(p,
+                 Type<Span<int8_t>>(L::Partial(5, 3).Slice<int8_t>(p)).data()));
+    EXPECT_EQ(
+        8,
+        Distance(
+            p, Type<Span<int32_t>>(L::Partial(5, 3).Slice<int32_t>(p)).data()));
+    EXPECT_EQ(
+        0,
+        Distance(
+            p,
+            Type<Span<int8_t>>(L::Partial(0, 0, 0).Slice<int8_t>(p)).data()));
+    EXPECT_EQ(
+        0,
+        Distance(
+            p,
+            Type<Span<int32_t>>(L::Partial(0, 0, 0).Slice<int32_t>(p)).data()));
     EXPECT_EQ(
         0,
         Distance(
             p,
             Type<Span<Int128>>(L::Partial(0, 0, 0).Slice<Int128>(p)).data()));
     EXPECT_EQ(
-        0, Distance(
-               p, Type<Span<int8_t>>(L::Partial(1, 0, 0).Slice<int8_t>(p)).data()));
+        0,
+        Distance(
+            p,
+            Type<Span<int8_t>>(L::Partial(1, 0, 0).Slice<int8_t>(p)).data()));
     EXPECT_EQ(
         4,
         Distance(
-            p, Type<Span<int32_t>>(L::Partial(1, 0, 0).Slice<int32_t>(p)).data()));
+            p,
+            Type<Span<int32_t>>(L::Partial(1, 0, 0).Slice<int32_t>(p)).data()));
     EXPECT_EQ(
         8,
         Distance(
             p,
             Type<Span<Int128>>(L::Partial(1, 0, 0).Slice<Int128>(p)).data()));
     EXPECT_EQ(
-        0, Distance(
-               p, Type<Span<int8_t>>(L::Partial(5, 3, 1).Slice<int8_t>(p)).data()));
+        0,
+        Distance(
+            p,
+            Type<Span<int8_t>>(L::Partial(5, 3, 1).Slice<int8_t>(p)).data()));
     EXPECT_EQ(
         24,
         Distance(
@@ -1150,14 +1212,16 @@
     EXPECT_EQ(
         8,
         Distance(
-            p, Type<Span<int32_t>>(L::Partial(5, 3, 1).Slice<int32_t>(p)).data()));
-    EXPECT_EQ(0,
-              Distance(p, Type<Span<int8_t>>(L(5, 3, 1).Slice<int8_t>(p)).data()));
+            p,
+            Type<Span<int32_t>>(L::Partial(5, 3, 1).Slice<int32_t>(p)).data()));
+    EXPECT_EQ(
+        0, Distance(p, Type<Span<int8_t>>(L(5, 3, 1).Slice<int8_t>(p)).data()));
     EXPECT_EQ(
         24,
         Distance(p, Type<Span<Int128>>(L(5, 3, 1).Slice<Int128>(p)).data()));
     EXPECT_EQ(
-        8, Distance(p, Type<Span<int32_t>>(L(5, 3, 1).Slice<int32_t>(p)).data()));
+        8,
+        Distance(p, Type<Span<int32_t>>(L(5, 3, 1).Slice<int32_t>(p)).data()));
   }
 }
 
@@ -1256,17 +1320,17 @@
   }
   {
     const auto x = L::Partial(1, 2, 3);
-    EXPECT_THAT(
-        (Type<std::tuple<Span<int8_t>, Span<int8_t>, Span<Int128>>>(x.Slices(p))),
-        Tuple(IsSameSlice(x.Slice<0>(p)), IsSameSlice(x.Slice<1>(p)),
-              IsSameSlice(x.Slice<2>(p))));
+    EXPECT_THAT((Type<std::tuple<Span<int8_t>, Span<int8_t>, Span<Int128>>>(
+                    x.Slices(p))),
+                Tuple(IsSameSlice(x.Slice<0>(p)), IsSameSlice(x.Slice<1>(p)),
+                      IsSameSlice(x.Slice<2>(p))));
   }
   {
     const L x(1, 2, 3);
-    EXPECT_THAT(
-        (Type<std::tuple<Span<int8_t>, Span<int8_t>, Span<Int128>>>(x.Slices(p))),
-        Tuple(IsSameSlice(x.Slice<0>(p)), IsSameSlice(x.Slice<1>(p)),
-              IsSameSlice(x.Slice<2>(p))));
+    EXPECT_THAT((Type<std::tuple<Span<int8_t>, Span<int8_t>, Span<Int128>>>(
+                    x.Slices(p))),
+                Tuple(IsSameSlice(x.Slice<0>(p)), IsSameSlice(x.Slice<1>(p)),
+                      IsSameSlice(x.Slice<2>(p))));
   }
 }
 
@@ -1398,7 +1462,8 @@
               x.DebugString());
   }
   {
-    constexpr auto x = Layout<int8_t, int32_t, int8_t, Int128>::Partial(1, 2, 3);
+    constexpr auto x =
+        Layout<int8_t, int32_t, int8_t, Int128>::Partial(1, 2, 3);
     EXPECT_EQ(
         "@0<signed char>(1)[1]; @4<int>(4)[2]; @12<signed char>(1)[3]; "
         "@16" +
@@ -1406,7 +1471,8 @@
         x.DebugString());
   }
   {
-    constexpr auto x = Layout<int8_t, int32_t, int8_t, Int128>::Partial(1, 2, 3, 4);
+    constexpr auto x =
+        Layout<int8_t, int32_t, int8_t, Int128>::Partial(1, 2, 3, 4);
     EXPECT_EQ(
         "@0<signed char>(1)[1]; @4<int>(4)[2]; @12<signed char>(1)[3]; "
         "@16" +
diff --git a/third_party/abseil-cpp/absl/container/internal/raw_hash_set.cc b/third_party/abseil-cpp/absl/container/internal/raw_hash_set.cc
index 919ac07..2f744a6 100644
--- a/third_party/abseil-cpp/absl/container/internal/raw_hash_set.cc
+++ b/third_party/abseil-cpp/absl/container/internal/raw_hash_set.cc
@@ -27,7 +27,7 @@
 
 // Returns "random" seed.
 inline size_t RandomSeed() {
-#if ABSL_HAVE_THREAD_LOCAL
+#ifdef ABSL_HAVE_THREAD_LOCAL
   static thread_local size_t counter = 0;
   size_t value = ++counter;
 #else   // ABSL_HAVE_THREAD_LOCAL
diff --git a/third_party/abseil-cpp/absl/container/internal/raw_hash_set_allocator_test.cc b/third_party/abseil-cpp/absl/container/internal/raw_hash_set_allocator_test.cc
index 1a03608..e73f53f 100644
--- a/third_party/abseil-cpp/absl/container/internal/raw_hash_set_allocator_test.cc
+++ b/third_party/abseil-cpp/absl/container/internal/raw_hash_set_allocator_test.cc
@@ -466,6 +466,9 @@
   size_t id_ = std::numeric_limits<size_t>::max();
 };
 
+// This doesn't compile with GCC 5.4 and 5.5 due to a bug in noexcept handing.
+#if !defined(__GNUC__) || __GNUC__ != 5 || (__GNUC_MINOR__ != 4 && \
+    __GNUC_MINOR__ != 5)
 TEST(NoPropagateOn, Swap) {
   using PA = PAlloc<char>;
   using Table = raw_hash_set<Policy, Identity, std::equal_to<int32_t>, PA>;
@@ -475,6 +478,7 @@
   EXPECT_EQ(t1.get_allocator(), PA(1));
   EXPECT_EQ(t2.get_allocator(), PA(2));
 }
+#endif
 
 TEST(NoPropagateOn, CopyConstruct) {
   using PA = PAlloc<char>;
diff --git a/third_party/abseil-cpp/absl/container/internal/raw_hash_set_test.cc b/third_party/abseil-cpp/absl/container/internal/raw_hash_set_test.cc
index f5ae83c4..6210eb64 100644
--- a/third_party/abseil-cpp/absl/container/internal/raw_hash_set_test.cc
+++ b/third_party/abseil-cpp/absl/container/internal/raw_hash_set_test.cc
@@ -847,7 +847,8 @@
 std::vector<int64_t> CollectBadMergeKeys(size_t N) {
   static constexpr int kGroupSize = Group::kWidth - 1;
 
-  auto topk_range = [](size_t b, size_t e, IntTable* t) -> std::vector<int64_t> {
+  auto topk_range = [](size_t b, size_t e,
+                       IntTable* t) -> std::vector<int64_t> {
     for (size_t i = b; i != e; ++i) {
       t->emplace(i);
     }
@@ -1001,8 +1002,8 @@
 // 1. Create new table and reserve it to keys.size() * 2
 // 2. Insert all keys xored with seed
 // 3. Collect ProbeStats from final table.
-ProbeStats CollectProbeStatsOnKeysXoredWithSeed(const std::vector<int64_t>& keys,
-                                                size_t num_iters) {
+ProbeStats CollectProbeStatsOnKeysXoredWithSeed(
+    const std::vector<int64_t>& keys, size_t num_iters) {
   const size_t reserve_size = keys.size() * 2;
 
   ProbeStats stats;
diff --git a/third_party/abseil-cpp/absl/debugging/internal/address_is_readable.cc b/third_party/abseil-cpp/absl/debugging/internal/address_is_readable.cc
index 6537606..329c285f 100644
--- a/third_party/abseil-cpp/absl/debugging/internal/address_is_readable.cc
+++ b/third_party/abseil-cpp/absl/debugging/internal/address_is_readable.cc
@@ -68,6 +68,7 @@
 // unimplemented.
 // This is a namespace-scoped variable for correct zero-initialization.
 static std::atomic<uint64_t> pid_and_fds;  // initially 0, an invalid pid.
+
 bool AddressIsReadable(const void *addr) {
   absl::base_internal::ErrnoSaver errno_saver;
   // We test whether a byte is readable by using write().  Normally, this would
@@ -86,7 +87,7 @@
     int pid;
     int read_fd;
     int write_fd;
-    uint64_t local_pid_and_fds = pid_and_fds.load(std::memory_order_relaxed);
+    uint64_t local_pid_and_fds = pid_and_fds.load(std::memory_order_acquire);
     Unpack(local_pid_and_fds, &pid, &read_fd, &write_fd);
     while (current_pid != pid) {
       int p[2];
@@ -98,13 +99,13 @@
       fcntl(p[1], F_SETFD, FD_CLOEXEC);
       uint64_t new_pid_and_fds = Pack(current_pid, p[0], p[1]);
       if (pid_and_fds.compare_exchange_strong(
-              local_pid_and_fds, new_pid_and_fds, std::memory_order_relaxed,
+              local_pid_and_fds, new_pid_and_fds, std::memory_order_release,
               std::memory_order_relaxed)) {
         local_pid_and_fds = new_pid_and_fds;  // fds exposed to other threads
       } else {  // fds not exposed to other threads; we can close them.
         close(p[0]);
         close(p[1]);
-        local_pid_and_fds = pid_and_fds.load(std::memory_order_relaxed);
+        local_pid_and_fds = pid_and_fds.load(std::memory_order_acquire);
       }
       Unpack(local_pid_and_fds, &pid, &read_fd, &write_fd);
     }
@@ -124,7 +125,7 @@
       // If pid_and_fds contains the problematic file descriptors we just used,
       // this call will forget them, and the loop will try again.
       pid_and_fds.compare_exchange_strong(local_pid_and_fds, 0,
-                                          std::memory_order_relaxed,
+                                          std::memory_order_release,
                                           std::memory_order_relaxed);
     }
   } while (errno == EBADF);
diff --git a/third_party/abseil-cpp/absl/debugging/internal/symbolize.h b/third_party/abseil-cpp/absl/debugging/internal/symbolize.h
index b3729af..4f26130 100644
--- a/third_party/abseil-cpp/absl/debugging/internal/symbolize.h
+++ b/third_party/abseil-cpp/absl/debugging/internal/symbolize.h
@@ -118,16 +118,14 @@
 //   filename != nullptr
 //
 // Returns true if the file was successfully registered.
-bool RegisterFileMappingHint(
-    const void* start, const void* end, uint64_t offset, const char* filename);
+bool RegisterFileMappingHint(const void* start, const void* end,
+                             uint64_t offset, const char* filename);
 
 // Looks up the file mapping registered by RegisterFileMappingHint for an
 // address range. If there is one, the file name is stored in *filename and
 // *start and *end are modified to reflect the registered mapping. Returns
 // whether any hint was found.
-bool GetFileMappingHint(const void** start,
-                        const void** end,
-                        uint64_t    *  offset,
+bool GetFileMappingHint(const void** start, const void** end, uint64_t* offset,
                         const char** filename);
 
 }  // namespace debugging_internal
diff --git a/third_party/abseil-cpp/absl/flags/BUILD.bazel b/third_party/abseil-cpp/absl/flags/BUILD.bazel
index 9de9e223..2bd9478 100644
--- a/third_party/abseil-cpp/absl/flags/BUILD.bazel
+++ b/third_party/abseil-cpp/absl/flags/BUILD.bazel
@@ -381,6 +381,8 @@
     deps = [
         ":flag",
         ":marshalling",
+        ":parse",
+        ":reflection",
         "//absl/strings",
         "//absl/time",
         "//absl/types:optional",
diff --git a/third_party/abseil-cpp/absl/flags/flag_benchmark.cc b/third_party/abseil-cpp/absl/flags/flag_benchmark.cc
index 7b52c9bc..9982b604 100644
--- a/third_party/abseil-cpp/absl/flags/flag_benchmark.cc
+++ b/third_party/abseil-cpp/absl/flags/flag_benchmark.cc
@@ -20,6 +20,8 @@
 
 #include "absl/flags/flag.h"
 #include "absl/flags/marshalling.h"
+#include "absl/flags/parse.h"
+#include "absl/flags/reflection.h"
 #include "absl/strings/string_view.h"
 #include "absl/time/time.h"
 #include "absl/types/optional.h"
@@ -103,6 +105,23 @@
 
 BENCHMARKED_TYPES(FLAG_DEF)
 
+// Register thousands of flags to bloat up the size of the registry.
+// This mimics real life production binaries.
+#define DEFINE_FLAG_0(name) ABSL_FLAG(int, name, 0, "");
+#define DEFINE_FLAG_1(name) DEFINE_FLAG_0(name##0) DEFINE_FLAG_0(name##1)
+#define DEFINE_FLAG_2(name) DEFINE_FLAG_1(name##0) DEFINE_FLAG_1(name##1)
+#define DEFINE_FLAG_3(name) DEFINE_FLAG_2(name##0) DEFINE_FLAG_2(name##1)
+#define DEFINE_FLAG_4(name) DEFINE_FLAG_3(name##0) DEFINE_FLAG_3(name##1)
+#define DEFINE_FLAG_5(name) DEFINE_FLAG_4(name##0) DEFINE_FLAG_4(name##1)
+#define DEFINE_FLAG_6(name) DEFINE_FLAG_5(name##0) DEFINE_FLAG_5(name##1)
+#define DEFINE_FLAG_7(name) DEFINE_FLAG_6(name##0) DEFINE_FLAG_6(name##1)
+#define DEFINE_FLAG_8(name) DEFINE_FLAG_7(name##0) DEFINE_FLAG_7(name##1)
+#define DEFINE_FLAG_9(name) DEFINE_FLAG_8(name##0) DEFINE_FLAG_8(name##1)
+#define DEFINE_FLAG_10(name) DEFINE_FLAG_9(name##0) DEFINE_FLAG_9(name##1)
+#define DEFINE_FLAG_11(name) DEFINE_FLAG_10(name##0) DEFINE_FLAG_10(name##1)
+#define DEFINE_FLAG_12(name) DEFINE_FLAG_11(name##0) DEFINE_FLAG_11(name##1)
+DEFINE_FLAG_12(bloat_flag_);
+
 namespace {
 
 #define BM_GetFlag(T)                                            \
@@ -115,6 +134,20 @@
 
 BENCHMARKED_TYPES(BM_GetFlag)
 
+void BM_ThreadedFindCommandLineFlag(benchmark::State& state) {
+  char dummy[] = "dummy";
+  char* argv[] = {dummy};
+  // We need to ensure that flags have been parsed. That is where the registry
+  // is finalized.
+  absl::ParseCommandLine(1, argv);
+
+  for (auto s : state) {
+    benchmark::DoNotOptimize(
+        absl::FindCommandLineFlag("bloat_flag_010101010101"));
+  }
+}
+BENCHMARK(BM_ThreadedFindCommandLineFlag)->ThreadRange(1, 16);
+
 }  // namespace
 
 #define InvokeGetFlag(T)                                               \
diff --git a/third_party/abseil-cpp/absl/flags/internal/registry.h b/third_party/abseil-cpp/absl/flags/internal/registry.h
index 1df2db79..a8d9eb9c 100644
--- a/third_party/abseil-cpp/absl/flags/internal/registry.h
+++ b/third_party/abseil-cpp/absl/flags/internal/registry.h
@@ -30,9 +30,6 @@
 ABSL_NAMESPACE_BEGIN
 namespace flags_internal {
 
-// Executes specified visitor for each non-retired flag in the registry.
-// Requires the caller hold the registry lock.
-void ForEachFlagUnlocked(std::function<void(CommandLineFlag&)> visitor);
 // Executes specified visitor for each non-retired flag in the registry. While
 // callback are executed, the registry is locked and can't be changed.
 void ForEachFlag(std::function<void(CommandLineFlag&)> visitor);
@@ -41,6 +38,8 @@
 
 bool RegisterCommandLineFlag(CommandLineFlag&);
 
+void FinalizeRegistry();
+
 //-----------------------------------------------------------------------------
 // Retired registrations:
 //
diff --git a/third_party/abseil-cpp/absl/flags/internal/usage.h b/third_party/abseil-cpp/absl/flags/internal/usage.h
index 0c62dc4..619ccce 100644
--- a/third_party/abseil-cpp/absl/flags/internal/usage.h
+++ b/third_party/abseil-cpp/absl/flags/internal/usage.h
@@ -36,7 +36,8 @@
   kHumanReadable,
 };
 
-// Outputs the help message describing specific flag.
+// Streams the help message describing `flag` to `out`.
+// The default value for `flag` is included in the output.
 void FlagHelp(std::ostream& out, const CommandLineFlag& flag,
               HelpFormat format = HelpFormat::kHumanReadable);
 
diff --git a/third_party/abseil-cpp/absl/flags/parse.cc b/third_party/abseil-cpp/absl/flags/parse.cc
index 4f4bb3d5..1835a837 100644
--- a/third_party/abseil-cpp/absl/flags/parse.cc
+++ b/third_party/abseil-cpp/absl/flags/parse.cc
@@ -611,6 +611,11 @@
                                         OnUndefinedFlag on_undef_flag) {
   ABSL_INTERNAL_CHECK(argc > 0, "Missing argv[0]");
 
+  // Once parsing has started we will not have more flag registrations.
+  // If we did, they would be missing during parsing, which is a problem on
+  // itself.
+  flags_internal::FinalizeRegistry();
+
   // This routine does not return anything since we abort on failure.
   CheckDefaultValuesParsingRoundtrip();
 
diff --git a/third_party/abseil-cpp/absl/flags/reflection.cc b/third_party/abseil-cpp/absl/flags/reflection.cc
index d7060221..c6bf8aa 100644
--- a/third_party/abseil-cpp/absl/flags/reflection.cc
+++ b/third_party/abseil-cpp/absl/flags/reflection.cc
@@ -17,6 +17,7 @@
 
 #include <assert.h>
 
+#include <atomic>
 #include <map>
 #include <string>
 
@@ -56,21 +57,23 @@
 
   // Returns the flag object for the specified name, or nullptr if not found.
   // Will emit a warning if a 'retired' flag is specified.
-  CommandLineFlag* FindFlagLocked(absl::string_view name);
+  CommandLineFlag* FindFlag(absl::string_view name);
 
   static FlagRegistry& GlobalRegistry();  // returns a singleton registry
 
  private:
   friend class flags_internal::FlagSaverImpl;  // reads all the flags in order
                                                // to copy them
-  friend void ForEachFlagUnlocked(
-      std::function<void(CommandLineFlag&)> visitor);
+  friend void ForEachFlag(std::function<void(CommandLineFlag&)> visitor);
+  friend void FinalizeRegistry();
 
-  // The map from name to flag, for FindFlagLocked().
+  // The map from name to flag, for FindFlag().
   using FlagMap = std::map<absl::string_view, CommandLineFlag*>;
   using FlagIterator = FlagMap::iterator;
   using FlagConstIterator = FlagMap::const_iterator;
   FlagMap flags_;
+  std::vector<CommandLineFlag*> flat_flags_;
+  std::atomic<bool> finalized_flags_{false};
 
   absl::Mutex lock_;
 
@@ -79,15 +82,6 @@
   FlagRegistry& operator=(const FlagRegistry&);
 };
 
-CommandLineFlag* FlagRegistry::FindFlagLocked(absl::string_view name) {
-  FlagConstIterator i = flags_.find(name);
-  if (i == flags_.end()) {
-    return nullptr;
-  }
-
-  return i->second;
-}
-
 namespace {
 
 class FlagRegistryLock {
@@ -101,8 +95,24 @@
 
 }  // namespace
 
+CommandLineFlag* FlagRegistry::FindFlag(absl::string_view name) {
+  if (finalized_flags_.load(std::memory_order_acquire)) {
+    // We could save some gcus here if we make `Name()` be non-virtual.
+    // We could move the `const char*` name to the base class.
+    auto it = std::partition_point(
+        flat_flags_.begin(), flat_flags_.end(),
+        [=](CommandLineFlag* f) { return f->Name() < name; });
+    if (it != flat_flags_.end() && (*it)->Name() == name) return *it;
+  }
+
+  FlagRegistryLock frl(*this);
+  auto it = flags_.find(name);
+  return it != flags_.end() ? it->second : nullptr;
+}
+
 void FlagRegistry::RegisterFlag(CommandLineFlag& flag) {
   FlagRegistryLock registry_lock(*this);
+
   std::pair<FlagIterator, bool> ins =
       flags_.insert(FlagMap::value_type(flag.Name(), &flag));
   if (ins.second == false) {  // means the name was already in the map
@@ -152,18 +162,15 @@
 
 // --------------------------------------------------------------------
 
-void ForEachFlagUnlocked(std::function<void(CommandLineFlag&)> visitor) {
-  FlagRegistry& registry = FlagRegistry::GlobalRegistry();
-  for (FlagRegistry::FlagConstIterator i = registry.flags_.begin();
-       i != registry.flags_.end(); ++i) {
-    visitor(*i->second);
-  }
-}
-
 void ForEachFlag(std::function<void(CommandLineFlag&)> visitor) {
   FlagRegistry& registry = FlagRegistry::GlobalRegistry();
+
+  if (registry.finalized_flags_.load(std::memory_order_acquire)) {
+    for (const auto& i : registry.flat_flags_) visitor(*i);
+  }
+
   FlagRegistryLock frl(registry);
-  ForEachFlagUnlocked(visitor);
+  for (const auto& i : registry.flags_) visitor(*i.second);
 }
 
 // --------------------------------------------------------------------
@@ -173,6 +180,21 @@
   return true;
 }
 
+void FinalizeRegistry() {
+  auto& registry = FlagRegistry::GlobalRegistry();
+  FlagRegistryLock frl(registry);
+  if (registry.finalized_flags_.load(std::memory_order_relaxed)) {
+    // Was already finalized. Ignore the second time.
+    return;
+  }
+  registry.flat_flags_.reserve(registry.flags_.size());
+  for (const auto& f : registry.flags_) {
+    registry.flat_flags_.push_back(f.second);
+  }
+  registry.flags_.clear();
+  registry.finalized_flags_.store(true, std::memory_order_release);
+}
+
 // --------------------------------------------------------------------
 
 namespace {
@@ -298,9 +320,7 @@
   if (name.empty()) return nullptr;
   flags_internal::FlagRegistry& registry =
       flags_internal::FlagRegistry::GlobalRegistry();
-  flags_internal::FlagRegistryLock frl(registry);
-
-  return registry.FindFlagLocked(name);
+  return registry.FindFlag(name);
 }
 
 // --------------------------------------------------------------------
diff --git a/third_party/abseil-cpp/absl/hash/hash_test.cc b/third_party/abseil-cpp/absl/hash/hash_test.cc
index 39ba24a8..1d2e6cf 100644
--- a/third_party/abseil-cpp/absl/hash/hash_test.cc
+++ b/third_party/abseil-cpp/absl/hash/hash_test.cc
@@ -82,8 +82,8 @@
 }
 
 REGISTER_TYPED_TEST_CASE_P(HashValueIntTest, BasicUsage, FastPath);
-using IntTypes = testing::Types<unsigned char, char, int, int32_t, int64_t, uint32_t,
-                                uint64_t, size_t>;
+using IntTypes = testing::Types<unsigned char, char, int, int32_t, int64_t,
+                                uint32_t, uint64_t, size_t>;
 INSTANTIATE_TYPED_TEST_CASE_P(My, HashValueIntTest, IntTypes);
 
 enum LegacyEnum { kValue1, kValue2, kValue3 };
@@ -819,8 +819,8 @@
 }
 
 REGISTER_TYPED_TEST_CASE_P(HashIntTest, BasicUsage);
-using IntTypes = testing::Types<unsigned char, char, int, int32_t, int64_t, uint32_t,
-                                uint64_t, size_t>;
+using IntTypes = testing::Types<unsigned char, char, int, int32_t, int64_t,
+                                uint32_t, uint64_t, size_t>;
 INSTANTIATE_TYPED_TEST_CASE_P(My, HashIntTest, IntTypes);
 
 struct StructWithPadding {
diff --git a/third_party/abseil-cpp/absl/hash/internal/city.cc b/third_party/abseil-cpp/absl/hash/internal/city.cc
index e122c18..58d4bcb14 100644
--- a/third_party/abseil-cpp/absl/hash/internal/city.cc
+++ b/third_party/abseil-cpp/absl/hash/internal/city.cc
@@ -253,9 +253,8 @@
 
 // Return a 16-byte hash for 48 bytes.  Quick and dirty.
 // Callers do best to use "random-looking" values for a and b.
-static std::pair<uint64_t, uint64_t> WeakHashLen32WithSeeds(uint64_t w, uint64_t x,
-                                                        uint64_t y, uint64_t z,
-                                                        uint64_t a, uint64_t b) {
+static std::pair<uint64_t, uint64_t> WeakHashLen32WithSeeds(
+    uint64_t w, uint64_t x, uint64_t y, uint64_t z, uint64_t a, uint64_t b) {
   a += w;
   b = Rotate(b + a + z, 21);
   uint64_t c = a;
@@ -266,8 +265,9 @@
 }
 
 // Return a 16-byte hash for s[0] ... s[31], a, and b.  Quick and dirty.
-static std::pair<uint64_t, uint64_t> WeakHashLen32WithSeeds(const char *s, uint64_t a,
-                                                        uint64_t b) {
+static std::pair<uint64_t, uint64_t> WeakHashLen32WithSeeds(const char *s,
+                                                            uint64_t a,
+                                                            uint64_t b) {
   return WeakHashLen32WithSeeds(Fetch64(s), Fetch64(s + 8), Fetch64(s + 16),
                                 Fetch64(s + 24), a, b);
 }
@@ -310,8 +310,10 @@
   uint64_t x = Fetch64(s + len - 40);
   uint64_t y = Fetch64(s + len - 16) + Fetch64(s + len - 56);
   uint64_t z = HashLen16(Fetch64(s + len - 48) + len, Fetch64(s + len - 24));
-  std::pair<uint64_t, uint64_t> v = WeakHashLen32WithSeeds(s + len - 64, len, z);
-  std::pair<uint64_t, uint64_t> w = WeakHashLen32WithSeeds(s + len - 32, y + k1, x);
+  std::pair<uint64_t, uint64_t> v =
+      WeakHashLen32WithSeeds(s + len - 64, len, z);
+  std::pair<uint64_t, uint64_t> w =
+      WeakHashLen32WithSeeds(s + len - 32, y + k1, x);
   x = x * k1 + Fetch64(s);
 
   // Decrease len to the nearest multiple of 64, and operate on 64-byte chunks.
@@ -337,7 +339,7 @@
 }
 
 uint64_t CityHash64WithSeeds(const char *s, size_t len, uint64_t seed0,
-                           uint64_t seed1) {
+                             uint64_t seed1) {
   return HashLen16(CityHash64(s, len) - seed0, seed1);
 }
 
diff --git a/third_party/abseil-cpp/absl/hash/internal/city.h b/third_party/abseil-cpp/absl/hash/internal/city.h
index 161c7748e..9c1e7a5 100644
--- a/third_party/abseil-cpp/absl/hash/internal/city.h
+++ b/third_party/abseil-cpp/absl/hash/internal/city.h
@@ -71,7 +71,7 @@
 // Hash function for a byte array.  For convenience, two seeds are also
 // hashed into the result.
 uint64_t CityHash64WithSeeds(const char *s, size_t len, uint64_t seed0,
-                           uint64_t seed1);
+                             uint64_t seed1);
 
 // Hash function for a byte array.  Most useful in 32-bit binaries.
 uint32_t CityHash32(const char *s, size_t len);
diff --git a/third_party/abseil-cpp/absl/random/internal/generate_real_test.cc b/third_party/abseil-cpp/absl/random/internal/generate_real_test.cc
index aa02f0c..4bdc453 100644
--- a/third_party/abseil-cpp/absl/random/internal/generate_real_test.cc
+++ b/third_party/abseil-cpp/absl/random/internal/generate_real_test.cc
@@ -419,8 +419,8 @@
   };
 
   // Rely on RandU64ToFloat generating values from greatest to least when
-  // supplied with uint64_t values from greatest (0xfff...) to least (0x0).  Thus,
-  // this algorithm stores the previous value, and if the new value is at
+  // supplied with uint64_t values from greatest (0xfff...) to least (0x0).
+  // Thus, this algorithm stores the previous value, and if the new value is at
   // greater than or equal to the previous value, then there is a collision in
   // the generation algorithm.
   //
diff --git a/third_party/abseil-cpp/absl/strings/cord_test.cc b/third_party/abseil-cpp/absl/strings/cord_test.cc
index 4443c828..dbed3e9a 100644
--- a/third_party/abseil-cpp/absl/strings/cord_test.cc
+++ b/third_party/abseil-cpp/absl/strings/cord_test.cc
@@ -1,3 +1,17 @@
+// Copyright 2020 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
 #include "absl/strings/cord.h"
 
 #include <algorithm>
diff --git a/third_party/abseil-cpp/absl/strings/internal/str_format/arg.cc b/third_party/abseil-cpp/absl/strings/internal/str_format/arg.cc
index 9feb224..e28a29b1 100644
--- a/third_party/abseil-cpp/absl/strings/internal/str_format/arg.cc
+++ b/third_party/abseil-cpp/absl/strings/internal/str_format/arg.cc
@@ -1,3 +1,17 @@
+// Copyright 2020 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
 //
 // POSIX spec:
 //   http://pubs.opengroup.org/onlinepubs/009695399/functions/fprintf.html
diff --git a/third_party/abseil-cpp/absl/strings/internal/str_format/arg.h b/third_party/abseil-cpp/absl/strings/internal/str_format/arg.h
index 3dbc152..7040c86 100644
--- a/third_party/abseil-cpp/absl/strings/internal/str_format/arg.h
+++ b/third_party/abseil-cpp/absl/strings/internal/str_format/arg.h
@@ -1,3 +1,17 @@
+// Copyright 2020 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
 #ifndef ABSL_STRINGS_INTERNAL_STR_FORMAT_ARG_H_
 #define ABSL_STRINGS_INTERNAL_STR_FORMAT_ARG_H_
 
diff --git a/third_party/abseil-cpp/absl/strings/internal/str_format/bind.cc b/third_party/abseil-cpp/absl/strings/internal/str_format/bind.cc
index 6980ed1d..194e21af 100644
--- a/third_party/abseil-cpp/absl/strings/internal/str_format/bind.cc
+++ b/third_party/abseil-cpp/absl/strings/internal/str_format/bind.cc
@@ -1,3 +1,17 @@
+// Copyright 2020 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
 #include "absl/strings/internal/str_format/bind.h"
 
 #include <cerrno>
diff --git a/third_party/abseil-cpp/absl/strings/internal/str_format/bind.h b/third_party/abseil-cpp/absl/strings/internal/str_format/bind.h
index 585246e..727b2115 100644
--- a/third_party/abseil-cpp/absl/strings/internal/str_format/bind.h
+++ b/third_party/abseil-cpp/absl/strings/internal/str_format/bind.h
@@ -1,3 +1,17 @@
+// Copyright 2020 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
 #ifndef ABSL_STRINGS_INTERNAL_STR_FORMAT_BIND_H_
 #define ABSL_STRINGS_INTERNAL_STR_FORMAT_BIND_H_
 
diff --git a/third_party/abseil-cpp/absl/strings/internal/str_format/bind_test.cc b/third_party/abseil-cpp/absl/strings/internal/str_format/bind_test.cc
index 64790a8..1eef9c4 100644
--- a/third_party/abseil-cpp/absl/strings/internal/str_format/bind_test.cc
+++ b/third_party/abseil-cpp/absl/strings/internal/str_format/bind_test.cc
@@ -1,3 +1,17 @@
+// Copyright 2020 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
 #include "absl/strings/internal/str_format/bind.h"
 
 #include <string.h>
diff --git a/third_party/abseil-cpp/absl/strings/internal/str_format/checker.h b/third_party/abseil-cpp/absl/strings/internal/str_format/checker.h
index 424c51f..2a2601e 100644
--- a/third_party/abseil-cpp/absl/strings/internal/str_format/checker.h
+++ b/third_party/abseil-cpp/absl/strings/internal/str_format/checker.h
@@ -1,3 +1,17 @@
+// Copyright 2020 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
 #ifndef ABSL_STRINGS_INTERNAL_STR_FORMAT_CHECKER_H_
 #define ABSL_STRINGS_INTERNAL_STR_FORMAT_CHECKER_H_
 
diff --git a/third_party/abseil-cpp/absl/strings/internal/str_format/checker_test.cc b/third_party/abseil-cpp/absl/strings/internal/str_format/checker_test.cc
index a76d70b..7c70f47 100644
--- a/third_party/abseil-cpp/absl/strings/internal/str_format/checker_test.cc
+++ b/third_party/abseil-cpp/absl/strings/internal/str_format/checker_test.cc
@@ -1,3 +1,17 @@
+// Copyright 2020 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
 #include <string>
 
 #include "gmock/gmock.h"
diff --git a/third_party/abseil-cpp/absl/strings/internal/str_format/convert_test.cc b/third_party/abseil-cpp/absl/strings/internal/str_format/convert_test.cc
index 634ee78..375db0a 100644
--- a/third_party/abseil-cpp/absl/strings/internal/str_format/convert_test.cc
+++ b/third_party/abseil-cpp/absl/strings/internal/str_format/convert_test.cc
@@ -1,3 +1,17 @@
+// Copyright 2020 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
 #include <errno.h>
 #include <stdarg.h>
 #include <stdio.h>
diff --git a/third_party/abseil-cpp/absl/strings/internal/str_format/float_conversion.cc b/third_party/abseil-cpp/absl/strings/internal/str_format/float_conversion.cc
index 20aeada..d3c5f0a7 100644
--- a/third_party/abseil-cpp/absl/strings/internal/str_format/float_conversion.cc
+++ b/third_party/abseil-cpp/absl/strings/internal/str_format/float_conversion.cc
@@ -1,3 +1,17 @@
+// Copyright 2020 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
 #include "absl/strings/internal/str_format/float_conversion.h"
 
 #include <string.h>
diff --git a/third_party/abseil-cpp/absl/strings/internal/str_format/float_conversion.h b/third_party/abseil-cpp/absl/strings/internal/str_format/float_conversion.h
index e78bc19..71100e71 100644
--- a/third_party/abseil-cpp/absl/strings/internal/str_format/float_conversion.h
+++ b/third_party/abseil-cpp/absl/strings/internal/str_format/float_conversion.h
@@ -1,3 +1,17 @@
+// Copyright 2020 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
 #ifndef ABSL_STRINGS_INTERNAL_STR_FORMAT_FLOAT_CONVERSION_H_
 #define ABSL_STRINGS_INTERNAL_STR_FORMAT_FLOAT_CONVERSION_H_
 
diff --git a/third_party/abseil-cpp/absl/strings/internal/str_format/parser.cc b/third_party/abseil-cpp/absl/strings/internal/str_format/parser.cc
index cc55dfa..f308d02 100644
--- a/third_party/abseil-cpp/absl/strings/internal/str_format/parser.cc
+++ b/third_party/abseil-cpp/absl/strings/internal/str_format/parser.cc
@@ -1,3 +1,17 @@
+// Copyright 2020 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
 #include "absl/strings/internal/str_format/parser.h"
 
 #include <assert.h>
diff --git a/third_party/abseil-cpp/absl/strings/internal/str_format/parser.h b/third_party/abseil-cpp/absl/strings/internal/str_format/parser.h
index fffed04..6504dd3 100644
--- a/third_party/abseil-cpp/absl/strings/internal/str_format/parser.h
+++ b/third_party/abseil-cpp/absl/strings/internal/str_format/parser.h
@@ -1,3 +1,17 @@
+// Copyright 2020 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
 #ifndef ABSL_STRINGS_INTERNAL_STR_FORMAT_PARSER_H_
 #define ABSL_STRINGS_INTERNAL_STR_FORMAT_PARSER_H_
 
diff --git a/third_party/abseil-cpp/absl/strings/internal/str_format/parser_test.cc b/third_party/abseil-cpp/absl/strings/internal/str_format/parser_test.cc
index 5aced987..a5fa1c7 100644
--- a/third_party/abseil-cpp/absl/strings/internal/str_format/parser_test.cc
+++ b/third_party/abseil-cpp/absl/strings/internal/str_format/parser_test.cc
@@ -1,3 +1,17 @@
+// Copyright 2020 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
 #include "absl/strings/internal/str_format/parser.h"
 
 #include <string.h>
diff --git a/third_party/abseil-cpp/absl/strings/str_format_test.cc b/third_party/abseil-cpp/absl/strings/str_format_test.cc
index d9fb25a..c60027a 100644
--- a/third_party/abseil-cpp/absl/strings/str_format_test.cc
+++ b/third_party/abseil-cpp/absl/strings/str_format_test.cc
@@ -1,3 +1,16 @@
+// Copyright 2020 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
 
 #include "absl/strings/str_format.h"
 
diff --git a/third_party/abseil-cpp/absl/synchronization/BUILD.bazel b/third_party/abseil-cpp/absl/synchronization/BUILD.bazel
index b2df413..cd4009a 100644
--- a/third_party/abseil-cpp/absl/synchronization/BUILD.bazel
+++ b/third_party/abseil-cpp/absl/synchronization/BUILD.bazel
@@ -80,6 +80,7 @@
         "barrier.h",
         "blocking_counter.h",
         "internal/create_thread_identity.h",
+        "internal/futex.h",
         "internal/per_thread_sem.h",
         "internal/waiter.h",
         "mutex.h",
diff --git a/third_party/abseil-cpp/absl/synchronization/BUILD.gn b/third_party/abseil-cpp/absl/synchronization/BUILD.gn
index 4d26b4fc..78f64cdf 100644
--- a/third_party/abseil-cpp/absl/synchronization/BUILD.gn
+++ b/third_party/abseil-cpp/absl/synchronization/BUILD.gn
@@ -42,6 +42,7 @@
     "barrier.h",
     "blocking_counter.h",
     "internal/create_thread_identity.h",
+    "internal/futex.h",
     "internal/per_thread_sem.h",
     "internal/waiter.h",
     "mutex.h",
diff --git a/third_party/abseil-cpp/absl/synchronization/CMakeLists.txt b/third_party/abseil-cpp/absl/synchronization/CMakeLists.txt
index c255b03..e633d0bf5 100644
--- a/third_party/abseil-cpp/absl/synchronization/CMakeLists.txt
+++ b/third_party/abseil-cpp/absl/synchronization/CMakeLists.txt
@@ -52,6 +52,7 @@
     "barrier.h"
     "blocking_counter.h"
     "internal/create_thread_identity.h"
+    "internal/futex.h"
     "internal/per_thread_sem.h"
     "internal/waiter.h"
     "mutex.h"
diff --git a/third_party/abseil-cpp/absl/synchronization/internal/futex.h b/third_party/abseil-cpp/absl/synchronization/internal/futex.h
new file mode 100644
index 0000000..06fbd6d
--- /dev/null
+++ b/third_party/abseil-cpp/absl/synchronization/internal/futex.h
@@ -0,0 +1,154 @@
+// Copyright 2020 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+#ifndef ABSL_SYNCHRONIZATION_INTERNAL_FUTEX_H_
+#define ABSL_SYNCHRONIZATION_INTERNAL_FUTEX_H_
+
+#include "absl/base/config.h"
+
+#ifdef _WIN32
+#include <windows.h>
+#else
+#include <sys/time.h>
+#include <unistd.h>
+#endif
+
+#ifdef __linux__
+#include <linux/futex.h>
+#include <sys/syscall.h>
+#endif
+
+#include <errno.h>
+#include <stdio.h>
+#include <time.h>
+
+#include <atomic>
+#include <cstdint>
+
+#include "absl/base/optimization.h"
+#include "absl/synchronization/internal/kernel_timeout.h"
+
+#ifdef ABSL_INTERNAL_HAVE_FUTEX
+#error ABSL_INTERNAL_HAVE_FUTEX may not be set on the command line
+#elif defined(__BIONIC__)
+// Bionic supports all the futex operations we need even when some of the futex
+// definitions are missing.
+#define ABSL_INTERNAL_HAVE_FUTEX
+#elif defined(__linux__) && defined(FUTEX_CLOCK_REALTIME)
+// FUTEX_CLOCK_REALTIME requires Linux >= 2.6.28.
+#define ABSL_INTERNAL_HAVE_FUTEX
+#endif
+
+#ifdef ABSL_INTERNAL_HAVE_FUTEX
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace synchronization_internal {
+
+// Some Android headers are missing these definitions even though they
+// support these futex operations.
+#ifdef __BIONIC__
+#ifndef SYS_futex
+#define SYS_futex __NR_futex
+#endif
+#ifndef FUTEX_WAIT_BITSET
+#define FUTEX_WAIT_BITSET 9
+#endif
+#ifndef FUTEX_PRIVATE_FLAG
+#define FUTEX_PRIVATE_FLAG 128
+#endif
+#ifndef FUTEX_CLOCK_REALTIME
+#define FUTEX_CLOCK_REALTIME 256
+#endif
+#ifndef FUTEX_BITSET_MATCH_ANY
+#define FUTEX_BITSET_MATCH_ANY 0xFFFFFFFF
+#endif
+#endif
+
+#if defined(__NR_futex_time64) && !defined(SYS_futex_time64)
+#define SYS_futex_time64 __NR_futex_time64
+#endif
+
+#if defined(SYS_futex_time64) && !defined(SYS_futex)
+#define SYS_futex SYS_futex_time64
+#endif
+
+class FutexImpl {
+ public:
+  static int WaitUntil(std::atomic<int32_t> *v, int32_t val,
+                       KernelTimeout t) {
+    int err = 0;
+    if (t.has_timeout()) {
+      // https://locklessinc.com/articles/futex_cheat_sheet/
+      // Unlike FUTEX_WAIT, FUTEX_WAIT_BITSET uses absolute time.
+      struct timespec abs_timeout = t.MakeAbsTimespec();
+      // Atomically check that the futex value is still 0, and if it
+      // is, sleep until abs_timeout or until woken by FUTEX_WAKE.
+      err = syscall(
+          SYS_futex, reinterpret_cast<int32_t *>(v),
+          FUTEX_WAIT_BITSET | FUTEX_PRIVATE_FLAG | FUTEX_CLOCK_REALTIME, val,
+          &abs_timeout, nullptr, FUTEX_BITSET_MATCH_ANY);
+    } else {
+      // Atomically check that the futex value is still 0, and if it
+      // is, sleep until woken by FUTEX_WAKE.
+      err = syscall(SYS_futex, reinterpret_cast<int32_t *>(v),
+                    FUTEX_WAIT | FUTEX_PRIVATE_FLAG, val, nullptr);
+    }
+    if (ABSL_PREDICT_FALSE(err != 0)) {
+      err = -errno;
+    }
+    return err;
+  }
+
+  static int WaitBitsetAbsoluteTimeout(std::atomic<int32_t> *v, int32_t val,
+                                       int32_t bits,
+                                       const struct timespec *abstime) {
+    int err = syscall(SYS_futex, reinterpret_cast<int32_t *>(v),
+                      FUTEX_WAIT_BITSET | FUTEX_PRIVATE_FLAG, val, abstime,
+                      nullptr, bits);
+    if (ABSL_PREDICT_FALSE(err != 0)) {
+      err = -errno;
+    }
+    return err;
+  }
+
+  static int Wake(std::atomic<int32_t> *v, int32_t count) {
+    int err = syscall(SYS_futex, reinterpret_cast<int32_t *>(v),
+                      FUTEX_WAKE | FUTEX_PRIVATE_FLAG, count);
+    if (ABSL_PREDICT_FALSE(err < 0)) {
+      err = -errno;
+    }
+    return err;
+  }
+
+  // FUTEX_WAKE_BITSET
+  static int WakeBitset(std::atomic<int32_t> *v, int32_t count, int32_t bits) {
+    int err = syscall(SYS_futex, reinterpret_cast<int32_t *>(v),
+                      FUTEX_WAKE_BITSET | FUTEX_PRIVATE_FLAG, count, nullptr,
+                      nullptr, bits);
+    if (ABSL_PREDICT_FALSE(err < 0)) {
+      err = -errno;
+    }
+    return err;
+  }
+};
+
+class Futex : public FutexImpl {};
+
+}  // namespace synchronization_internal
+ABSL_NAMESPACE_END
+}  // namespace absl
+
+#endif  // ABSL_INTERNAL_HAVE_FUTEX
+
+#endif  // ABSL_SYNCHRONIZATION_INTERNAL_FUTEX_H_
diff --git a/third_party/abseil-cpp/absl/synchronization/internal/kernel_timeout.h b/third_party/abseil-cpp/absl/synchronization/internal/kernel_timeout.h
index 1084e1e..bbd4d2d 100644
--- a/third_party/abseil-cpp/absl/synchronization/internal/kernel_timeout.h
+++ b/third_party/abseil-cpp/absl/synchronization/internal/kernel_timeout.h
@@ -26,6 +26,7 @@
 #define ABSL_SYNCHRONIZATION_INTERNAL_KERNEL_TIMEOUT_H_
 
 #include <time.h>
+
 #include <algorithm>
 #include <limits>
 
@@ -142,7 +143,7 @@
 
   struct timespec abstime;
   int64_t seconds = (std::min)(n / kNanosPerSecond,
-                             int64_t{(std::numeric_limits<time_t>::max)()});
+                               int64_t{(std::numeric_limits<time_t>::max)()});
   abstime.tv_sec = static_cast<time_t>(seconds);
   abstime.tv_nsec = static_cast<decltype(abstime.tv_nsec)>(n % kNanosPerSecond);
   return abstime;
diff --git a/third_party/abseil-cpp/absl/synchronization/internal/waiter.cc b/third_party/abseil-cpp/absl/synchronization/internal/waiter.cc
index b6150b9..2123be6 100644
--- a/third_party/abseil-cpp/absl/synchronization/internal/waiter.cc
+++ b/third_party/abseil-cpp/absl/synchronization/internal/waiter.cc
@@ -48,6 +48,7 @@
 #include "absl/base/optimization.h"
 #include "absl/synchronization/internal/kernel_timeout.h"
 
+
 namespace absl {
 ABSL_NAMESPACE_BEGIN
 namespace synchronization_internal {
@@ -66,71 +67,6 @@
 
 #if ABSL_WAITER_MODE == ABSL_WAITER_MODE_FUTEX
 
-// Some Android headers are missing these definitions even though they
-// support these futex operations.
-#ifdef __BIONIC__
-#ifndef SYS_futex
-#define SYS_futex __NR_futex
-#endif
-#ifndef FUTEX_WAIT_BITSET
-#define FUTEX_WAIT_BITSET 9
-#endif
-#ifndef FUTEX_PRIVATE_FLAG
-#define FUTEX_PRIVATE_FLAG 128
-#endif
-#ifndef FUTEX_CLOCK_REALTIME
-#define FUTEX_CLOCK_REALTIME 256
-#endif
-#ifndef FUTEX_BITSET_MATCH_ANY
-#define FUTEX_BITSET_MATCH_ANY 0xFFFFFFFF
-#endif
-#endif
-
-#if defined(__NR_futex_time64) && !defined(SYS_futex_time64)
-#define SYS_futex_time64 __NR_futex_time64
-#endif
-
-#if defined(SYS_futex_time64) && !defined(SYS_futex)
-#define SYS_futex SYS_futex_time64
-#endif
-
-class Futex {
- public:
-  static int WaitUntil(std::atomic<int32_t> *v, int32_t val,
-                       KernelTimeout t) {
-    int err = 0;
-    if (t.has_timeout()) {
-      // https://locklessinc.com/articles/futex_cheat_sheet/
-      // Unlike FUTEX_WAIT, FUTEX_WAIT_BITSET uses absolute time.
-      struct timespec abs_timeout = t.MakeAbsTimespec();
-      // Atomically check that the futex value is still 0, and if it
-      // is, sleep until abs_timeout or until woken by FUTEX_WAKE.
-      err = syscall(
-          SYS_futex, reinterpret_cast<int32_t *>(v),
-          FUTEX_WAIT_BITSET | FUTEX_PRIVATE_FLAG | FUTEX_CLOCK_REALTIME, val,
-          &abs_timeout, nullptr, FUTEX_BITSET_MATCH_ANY);
-    } else {
-      // Atomically check that the futex value is still 0, and if it
-      // is, sleep until woken by FUTEX_WAKE.
-      err = syscall(SYS_futex, reinterpret_cast<int32_t *>(v),
-                    FUTEX_WAIT | FUTEX_PRIVATE_FLAG, val, nullptr);
-    }
-    if (err != 0) {
-      err = -errno;
-    }
-    return err;
-  }
-
-  static int Wake(std::atomic<int32_t> *v, int32_t count) {
-    int err = syscall(SYS_futex, reinterpret_cast<int32_t *>(v),
-                      FUTEX_WAKE | FUTEX_PRIVATE_FLAG, count);
-    if (ABSL_PREDICT_FALSE(err < 0)) {
-      err = -errno;
-    }
-    return err;
-  }
-};
-
 Waiter::Waiter() {
   futex_.store(0, std::memory_order_relaxed);
 }
diff --git a/third_party/abseil-cpp/absl/synchronization/internal/waiter.h b/third_party/abseil-cpp/absl/synchronization/internal/waiter.h
index 887f9b1..be3df18 100644
--- a/third_party/abseil-cpp/absl/synchronization/internal/waiter.h
+++ b/third_party/abseil-cpp/absl/synchronization/internal/waiter.h
@@ -36,6 +36,7 @@
 #include <cstdint>
 
 #include "absl/base/internal/thread_identity.h"
+#include "absl/synchronization/internal/futex.h"
 #include "absl/synchronization/internal/kernel_timeout.h"
 
 // May be chosen at compile time via -DABSL_FORCE_WAITER_MODE=<index>
@@ -48,12 +49,7 @@
 #define ABSL_WAITER_MODE ABSL_FORCE_WAITER_MODE
 #elif defined(_WIN32) && _WIN32_WINNT >= _WIN32_WINNT_VISTA
 #define ABSL_WAITER_MODE ABSL_WAITER_MODE_WIN32
-#elif defined(__BIONIC__)
-// Bionic supports all the futex operations we need even when some of the futex
-// definitions are missing.
-#define ABSL_WAITER_MODE ABSL_WAITER_MODE_FUTEX
-#elif defined(__linux__) && defined(FUTEX_CLOCK_REALTIME)
-// FUTEX_CLOCK_REALTIME requires Linux >= 2.6.28.
+#elif defined(ABSL_INTERNAL_HAVE_FUTEX)
 #define ABSL_WAITER_MODE ABSL_WAITER_MODE_FUTEX
 #elif defined(ABSL_HAVE_SEMAPHORE_H)
 #define ABSL_WAITER_MODE ABSL_WAITER_MODE_SEM
diff --git a/third_party/abseil-cpp/absl/synchronization/mutex.cc b/third_party/abseil-cpp/absl/synchronization/mutex.cc
index 9b7f088..9e01393 100644
--- a/third_party/abseil-cpp/absl/synchronization/mutex.cc
+++ b/third_party/abseil-cpp/absl/synchronization/mutex.cc
@@ -50,6 +50,7 @@
 #include "absl/base/internal/spinlock.h"
 #include "absl/base/internal/sysinfo.h"
 #include "absl/base/internal/thread_identity.h"
+#include "absl/base/internal/tsan_mutex_interface.h"
 #include "absl/base/port.h"
 #include "absl/debugging/stacktrace.h"
 #include "absl/debugging/symbolize.h"
@@ -88,8 +89,8 @@
 ABSL_CONST_INIT std::atomic<bool> synch_check_invariants(false);
 
 ABSL_INTERNAL_ATOMIC_HOOK_ATTRIBUTES
-    absl::base_internal::AtomicHook<void (*)(int64_t wait_cycles)>
-        submit_profile_data;
+absl::base_internal::AtomicHook<void (*)(int64_t wait_cycles)>
+    submit_profile_data;
 ABSL_INTERNAL_ATOMIC_HOOK_ATTRIBUTES absl::base_internal::AtomicHook<void (*)(
     const char *msg, const void *obj, int64_t wait_cycles)>
     mutex_tracer;
@@ -491,7 +492,7 @@
   std::atomic<intptr_t> *cv_word;
 
   int64_t contention_start_cycles;  // Time (in cycles) when this thread started
-                                  // to contend for the mutex.
+                                    // to contend for the mutex.
 };
 
 struct SynchLocksHeld {
@@ -705,7 +706,7 @@
 static constexpr bool kDebugMode = true;
 #endif
 
-#ifdef ABSL_HAVE_THREAD_SANITIZER
+#ifdef ABSL_INTERNAL_HAVE_TSAN_INTERFACE
 static unsigned TsanFlags(Mutex::MuHow how) {
   return how == kShared ? __tsan_mutex_read_lock : 0;
 }
@@ -1767,7 +1768,7 @@
   // All memory accesses are ignored inside of mutex operations + for unlock
   // operation tsan considers that we've already released the mutex.
   bool res = false;
-#ifdef ABSL_HAVE_THREAD_SANITIZER
+#ifdef ABSL_INTERNAL_HAVE_TSAN_INTERFACE
   const int flags = read_lock ? __tsan_mutex_read_lock : 0;
   const int tryflags = flags | (trylock ? __tsan_mutex_try_lock : 0);
 #endif
@@ -2311,7 +2312,8 @@
     if (!cond_waiter) {
       // Sample lock contention events only if the (first) waiter was trying to
       // acquire the lock, not waiting on a condition variable or Condition.
-      int64_t wait_cycles = base_internal::CycleClock::Now() - enqueue_timestamp;
+      int64_t wait_cycles =
+          base_internal::CycleClock::Now() - enqueue_timestamp;
       mutex_tracer("slow release", this, wait_cycles);
       ABSL_TSAN_MUTEX_PRE_DIVERT(this, 0);
       submit_profile_data(enqueue_timestamp);
diff --git a/third_party/abseil-cpp/absl/synchronization/mutex.h b/third_party/abseil-cpp/absl/synchronization/mutex.h
index 6340bd63..f686c4d 100644
--- a/third_party/abseil-cpp/absl/synchronization/mutex.h
+++ b/third_party/abseil-cpp/absl/synchronization/mutex.h
@@ -667,10 +667,10 @@
   //   };
   //   mu_.Await(Condition(&reached));
   //
-  // NOTE: never use "mu_.AssertHeld()" instead of "mu_.AssertReadHeld()" in the
-  // lambda as it may be called when the mutex is being unlocked from a scope
-  // holding only a reader lock, which will make the assertion not fulfilled and
-  // crash the binary.
+  // NOTE: never use "mu_.AssertHeld()" instead of "mu_.AssertReaderHeld()" in
+  // the lambda as it may be called when the mutex is being unlocked from a
+  // scope holding only a reader lock, which will make the assertion not
+  // fulfilled and crash the binary.
 
   // See class comment for performance advice. In particular, if there
   // might be more than one waiter for the same condition, make sure
@@ -954,7 +954,7 @@
 //
 // This has the same memory ordering concerns as RegisterMutexProfiler() above.
 void RegisterMutexTracer(void (*fn)(const char *msg, const void *obj,
-                              int64_t wait_cycles));
+                                    int64_t wait_cycles));
 
 // TODO(gfalcon): Combine RegisterMutexProfiler() and RegisterMutexTracer()
 // into a single interface, since they are only ever called in pairs.
diff --git a/third_party/abseil-cpp/absl/time/clock.cc b/third_party/abseil-cpp/absl/time/clock.cc
index e5c423c7e..6862e01 100644
--- a/third_party/abseil-cpp/absl/time/clock.cc
+++ b/third_party/abseil-cpp/absl/time/clock.cc
@@ -74,9 +74,7 @@
 #if !ABSL_USE_CYCLECLOCK_FOR_GET_CURRENT_TIME_NANOS
 namespace absl {
 ABSL_NAMESPACE_BEGIN
-int64_t GetCurrentTimeNanos() {
-  return GET_CURRENT_TIME_NANOS_FROM_SYSTEM();
-}
+int64_t GetCurrentTimeNanos() { return GET_CURRENT_TIME_NANOS_FROM_SYSTEM(); }
 ABSL_NAMESPACE_END
 }  // namespace absl
 #else  // Use the cyclecounter-based implementation below.
diff --git a/third_party/abseil-cpp/absl/time/duration.cc b/third_party/abseil-cpp/absl/time/duration.cc
index eca1a6d..4443109 100644
--- a/third_party/abseil-cpp/absl/time/duration.cc
+++ b/third_party/abseil-cpp/absl/time/duration.cc
@@ -356,7 +356,7 @@
 // the remainder.  If it does not saturate, the remainder remain accurate,
 // but the returned quotient will over/underflow int64_t and should not be used.
 int64_t IDivDuration(bool satq, const Duration num, const Duration den,
-                   Duration* rem) {
+                     Duration* rem) {
   int64_t q = 0;
   if (IDivFastPath(num, den, &q, rem)) {
     return q;
diff --git a/third_party/abseil-cpp/absl/time/time.cc b/third_party/abseil-cpp/absl/time/time.cc
index 6bb36cb..1ec2026 100644
--- a/third_party/abseil-cpp/absl/time/time.cc
+++ b/third_party/abseil-cpp/absl/time/time.cc
@@ -60,9 +60,10 @@
 inline int64_t FloorToUnit(absl::Duration d, absl::Duration unit) {
   absl::Duration rem;
   int64_t q = absl::IDivDuration(d, unit, &rem);
-  return (q > 0 ||
-          rem >= ZeroDuration() ||
-          q == std::numeric_limits<int64_t>::min()) ? q : q - 1;
+  return (q > 0 || rem >= ZeroDuration() ||
+          q == std::numeric_limits<int64_t>::min())
+             ? q
+             : q - 1;
 }
 
 inline absl::Time::Breakdown InfiniteFutureBreakdown() {
diff --git a/third_party/abseil-cpp/absl/time/time.h b/third_party/abseil-cpp/absl/time/time.h
index 37f6131..7250803 100644
--- a/third_party/abseil-cpp/absl/time/time.h
+++ b/third_party/abseil-cpp/absl/time/time.h
@@ -639,7 +639,7 @@
   // Deprecated. Use `absl::TimeZone::CivilInfo`.
   struct
       Breakdown {
-    int64_t year;          // year (e.g., 2013)
+    int64_t year;        // year (e.g., 2013)
     int month;           // month of year [1:12]
     int day;             // day of month [1:31]
     int hour;            // hour of day [0:23]
@@ -1494,12 +1494,10 @@
 constexpr bool operator<(Duration lhs, Duration rhs) {
   return time_internal::GetRepHi(lhs) != time_internal::GetRepHi(rhs)
              ? time_internal::GetRepHi(lhs) < time_internal::GetRepHi(rhs)
-             : time_internal::GetRepHi(lhs) ==
-                       (std::numeric_limits<int64_t>::min)()
-                   ? time_internal::GetRepLo(lhs) + 1 <
-                         time_internal::GetRepLo(rhs) + 1
-                   : time_internal::GetRepLo(lhs) <
-                         time_internal::GetRepLo(rhs);
+         : time_internal::GetRepHi(lhs) == (std::numeric_limits<int64_t>::min)()
+             ? time_internal::GetRepLo(lhs) + 1 <
+                   time_internal::GetRepLo(rhs) + 1
+             : time_internal::GetRepLo(lhs) < time_internal::GetRepLo(rhs);
 }
 
 constexpr bool operator==(Duration lhs, Duration rhs) {
diff --git a/third_party/abseil-cpp/absl/time/time_test.cc b/third_party/abseil-cpp/absl/time/time_test.cc
index b28a99f..cde9423 100644
--- a/third_party/abseil-cpp/absl/time/time_test.cc
+++ b/third_party/abseil-cpp/absl/time/time_test.cc
@@ -1070,7 +1070,8 @@
   EXPECT_EQ("292277026596-12-04T15:30:07+00:00",
             absl::FormatTime(absl::RFC3339_full, t, utc));
   EXPECT_EQ(
-      absl::UnixEpoch() + absl::Seconds(std::numeric_limits<int64_t>::max()), t);
+      absl::UnixEpoch() + absl::Seconds(std::numeric_limits<int64_t>::max()),
+      t);
 
   // Checks that we can also get the maximal Time value for a far-east zone.
   const absl::TimeZone plus14 = absl::FixedTimeZone(14 * 60 * 60);
@@ -1078,7 +1079,8 @@
   EXPECT_EQ("292277026596-12-05T05:30:07+14:00",
             absl::FormatTime(absl::RFC3339_full, t, plus14));
   EXPECT_EQ(
-      absl::UnixEpoch() + absl::Seconds(std::numeric_limits<int64_t>::max()), t);
+      absl::UnixEpoch() + absl::Seconds(std::numeric_limits<int64_t>::max()),
+      t);
 
   // One second later should push us to infinity.
   t = absl::FromCivil(absl::CivilSecond(292277026596, 12, 4, 15, 30, 8), utc);
@@ -1092,7 +1094,8 @@
   EXPECT_EQ("-292277022657-01-27T08:29:52+00:00",
             absl::FormatTime(absl::RFC3339_full, t, utc));
   EXPECT_EQ(
-      absl::UnixEpoch() + absl::Seconds(std::numeric_limits<int64_t>::min()), t);
+      absl::UnixEpoch() + absl::Seconds(std::numeric_limits<int64_t>::min()),
+      t);
 
   // Checks that we can also get the minimal Time value for a far-west zone.
   const absl::TimeZone minus12 = absl::FixedTimeZone(-12 * 60 * 60);
@@ -1101,7 +1104,8 @@
   EXPECT_EQ("-292277022657-01-26T20:29:52-12:00",
             absl::FormatTime(absl::RFC3339_full, t, minus12));
   EXPECT_EQ(
-      absl::UnixEpoch() + absl::Seconds(std::numeric_limits<int64_t>::min()), t);
+      absl::UnixEpoch() + absl::Seconds(std::numeric_limits<int64_t>::min()),
+      t);
 
   // One second before should push us to -infinity.
   t = absl::FromCivil(absl::CivilSecond(-292277022657, 1, 27, 8, 29, 51), utc);
diff --git a/third_party/abseil-cpp/absl/types/internal/variant.h b/third_party/abseil-cpp/absl/types/internal/variant.h
index d404e80c..772008c 100644
--- a/third_party/abseil-cpp/absl/types/internal/variant.h
+++ b/third_party/abseil-cpp/absl/types/internal/variant.h
@@ -45,7 +45,7 @@
 template <class... Types>
 class variant;
 
-ABSL_INTERNAL_INLINE_CONSTEXPR(size_t, variant_npos, -1);
+ABSL_INTERNAL_INLINE_CONSTEXPR(size_t, variant_npos, static_cast<size_t>(-1));
 
 template <class T>
 struct variant_size;
diff --git a/third_party/abseil-cpp/absl/types/variant_test.cc b/third_party/abseil-cpp/absl/types/variant_test.cc
index cf8f7f337..cf23733 100644
--- a/third_party/abseil-cpp/absl/types/variant_test.cc
+++ b/third_party/abseil-cpp/absl/types/variant_test.cc
@@ -2311,7 +2311,8 @@
   ASSERT_TRUE(absl::holds_alternative<int32_t>(variant2));
   EXPECT_EQ(42, absl::get<int32_t>(variant2));
 
-  variant2 = ConvertVariantTo<variant<int32_t, uint32_t>>(variant<uint32_t>(42));
+  variant2 =
+      ConvertVariantTo<variant<int32_t, uint32_t>>(variant<uint32_t>(42));
   ASSERT_TRUE(absl::holds_alternative<uint32_t>(variant2));
   EXPECT_EQ(42, absl::get<uint32_t>(variant2));
 #endif  // !ABSL_USES_STD_VARIANT
@@ -2453,7 +2454,8 @@
       ConvertVariantTo<variant<int32_t, uint32_t>>(variant<int32_t>(42)));
   EXPECT_THAT(absl::get_if<int32_t>(&variant2), Pointee(42));
 
-  variant2 = ConvertVariantTo<variant<int32_t, uint32_t>>(variant<uint32_t>(42));
+  variant2 =
+      ConvertVariantTo<variant<int32_t, uint32_t>>(variant<uint32_t>(42));
   EXPECT_THAT(absl::get_if<uint32_t>(&variant2), Pointee(42));
 #endif
 
diff --git a/third_party/abseil-cpp/ci/linux_docker_containers.sh b/third_party/abseil-cpp/ci/linux_docker_containers.sh
index e42fa58..752b572 100644
--- a/third_party/abseil-cpp/ci/linux_docker_containers.sh
+++ b/third_party/abseil-cpp/ci/linux_docker_containers.sh
@@ -16,6 +16,6 @@
 # Test scripts should source this file to get the identifiers.
 
 readonly LINUX_ALPINE_CONTAINER="gcr.io/google.com/absl-177019/alpine:20191016"
-readonly LINUX_CLANG_LATEST_CONTAINER="gcr.io/google.com/absl-177019/linux_hybrid-latest:20200909"
-readonly LINUX_GCC_LATEST_CONTAINER="gcr.io/google.com/absl-177019/linux_hybrid-latest:20200909"
+readonly LINUX_CLANG_LATEST_CONTAINER="gcr.io/google.com/absl-177019/linux_hybrid-latest:20201008"
+readonly LINUX_GCC_LATEST_CONTAINER="gcr.io/google.com/absl-177019/linux_hybrid-latest:20201008"
 readonly LINUX_GCC_49_CONTAINER="gcr.io/google.com/absl-177019/linux_gcc-4.9:20191018"
diff --git a/third_party/blink/common/features.cc b/third_party/blink/common/features.cc
index 172680c8..fd5bb30 100644
--- a/third_party/blink/common/features.cc
+++ b/third_party/blink/common/features.cc
@@ -663,13 +663,14 @@
 // Enables the device-memory, resource-width, viewport-width and DPR client
 // hints to be sent to third-party origins if the first-party has opted in to
 // receiving client hints, regardless of Feature Policy.
+const base::Feature kAllowClientHintsToThirdParty{
+  "AllowClientHintsToThirdParty",
 #if defined(OS_ANDROID)
-const base::Feature kAllowClientHintsToThirdParty{
-    "AllowClientHintsToThirdParty", base::FEATURE_ENABLED_BY_DEFAULT};
+      base::FEATURE_ENABLED_BY_DEFAULT
 #else
-const base::Feature kAllowClientHintsToThirdParty{
-    "AllowClientHintsToThirdParty", base::FEATURE_DISABLED_BY_DEFAULT};
+      base::FEATURE_DISABLED_BY_DEFAULT
 #endif
+};
 
 const base::Feature kFilteringScrollPrediction{
     "FilteringScrollPrediction", base::FEATURE_DISABLED_BY_DEFAULT};
diff --git a/third_party/blink/public/common/BUILD.gn b/third_party/blink/public/common/BUILD.gn
index b4ff6b5a..a3eed68 100644
--- a/third_party/blink/public/common/BUILD.gn
+++ b/third_party/blink/public/common/BUILD.gn
@@ -9,6 +9,10 @@
 import("//third_party/protobuf/proto_library.gni")
 import("//third_party/webrtc/webrtc.gni")
 
+if (is_android) {
+  import("//build/config/android/rules.gni")
+}
+
 # Public common API headers, mojom and libraries that can be linked and
 # referenced both by browser-side and renderer-side components.
 component("common") {
@@ -260,3 +264,18 @@
 proto_library("font_enumeration_table_proto") {
   sources = [ "font_access/font_enumeration_table.proto" ]
 }
+
+if (is_android) {
+  java_cpp_features("java_features_srcjar") {
+    # External code should depend on ":common_java" instead.
+    visibility = [ ":*" ]
+    sources = [ "//third_party/blink/common/features.cc" ]
+    template = "//third_party/blink/public/common/android/java_templates/BlinkFeatures.java.tmpl"
+  }
+
+  android_library("common_java") {
+    # Right now, this only includes the Java features. But if we need more Java
+    # files, they should be added here as necessary.
+    srcjar_deps = [ ":java_features_srcjar" ]
+  }
+}
diff --git a/third_party/blink/public/common/android/java_templates/BlinkFeatures.java.tmpl b/third_party/blink/public/common/android/java_templates/BlinkFeatures.java.tmpl
new file mode 100644
index 0000000..aeca158
--- /dev/null
+++ b/third_party/blink/public/common/android/java_templates/BlinkFeatures.java.tmpl
@@ -0,0 +1,16 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.blink_public.common;
+
+/**
+ * Constants for the names of Blink Features.
+ */
+public final class BlinkFeatures {{
+
+{NATIVE_FEATURES}
+
+    // Do not instantiate this class.
+    private BlinkFeatures() {{}}
+}}
diff --git a/third_party/blink/public/mojom/dwrite_font_proxy/dwrite_font_proxy.mojom b/third_party/blink/public/mojom/dwrite_font_proxy/dwrite_font_proxy.mojom
index a5d5ad16..0c5fc3b8f 100644
--- a/third_party/blink/public/mojom/dwrite_font_proxy/dwrite_font_proxy.mojom
+++ b/third_party/blink/public/mojom/dwrite_font_proxy/dwrite_font_proxy.mojom
@@ -4,8 +4,8 @@
 
 module blink.mojom;
 
-import "mojo/public/mojom/base/file.mojom";
 import "mojo/public/mojom/base/file_path.mojom";
+import "mojo/public/mojom/base/read_only_file.mojom";
 import "mojo/public/mojom/base/shared_memory.mojom";
 import "mojo/public/mojom/base/string16.mojom";
 
@@ -61,7 +61,7 @@
   [Sync]
   GetFontFiles(uint32 family_index)
      => (array<mojo_base.mojom.FilePath> file_paths,
-         array<mojo_base.mojom.File> file_handles);
+         array<mojo_base.mojom.ReadOnlyFile> file_handles);
 
   // Returns which font unique name matching lookup mode is to be used on the
   // current machine. On DirectWrite 10 and above, single lookups can be
diff --git a/third_party/blink/public/web/web_ax_object.h b/third_party/blink/public/web/web_ax_object.h
index 91b822f..d6202fd5 100644
--- a/third_party/blink/public/web/web_ax_object.h
+++ b/third_party/blink/public/web/web_ax_object.h
@@ -176,7 +176,6 @@
   BLINK_EXPORT WebAXObject AriaActiveDescendant() const;
   BLINK_EXPORT WebString AutoComplete() const;
   BLINK_EXPORT ax::mojom::AriaCurrentState AriaCurrentState() const;
-  BLINK_EXPORT bool IsEditableRoot() const;
   BLINK_EXPORT bool IsEditable() const;
   BLINK_EXPORT bool AriaOwns(WebVector<WebAXObject>& owns_elements) const;
   BLINK_EXPORT WebString FontFamily() const;
@@ -258,13 +257,6 @@
                               int& focus_offset,
                               ax::mojom::TextAffinity& focus_affinity) const;
 
-  // The following selection functions return text offsets calculated starting
-  // from the current object. They only report on a selection that is placed on
-  // the current object or on any of its descendants.
-
-  BLINK_EXPORT unsigned SelectionEnd() const;
-  BLINK_EXPORT unsigned SelectionStart() const;
-
   // 1-based position in set & Size of set.
   BLINK_EXPORT int PosInSet() const;
   BLINK_EXPORT int SetSize() const;
diff --git a/third_party/blink/renderer/bindings/core/v8/v8_embedder_graph_builder.cc b/third_party/blink/renderer/bindings/core/v8/v8_embedder_graph_builder.cc
index ef136c73..86780b6d 100644
--- a/third_party/blink/renderer/bindings/core/v8/v8_embedder_graph_builder.cc
+++ b/third_party/blink/renderer/bindings/core/v8/v8_embedder_graph_builder.cc
@@ -169,7 +169,7 @@
   void VisitRoot(const void*, TraceDescriptor, const base::Location&) final;
   void Visit(const TraceWrapperV8Reference<v8::Value>&) final;
   void Visit(const void*, TraceDescriptor) final;
-  void VisitEphemeron(const void*, const void*, TraceCallback) final;
+  void VisitEphemeron(const void*, TraceDescriptor) final;
   void VisitWeakContainer(const void*,
                           const void* const*,
                           TraceDescriptor,
@@ -599,10 +599,10 @@
 
 void V8EmbedderGraphBuilder::VisitEphemeron(
     const void* key,
-    const void* value,
-    TraceCallback value_trace_callback) {
-  ephemeron_worklist_.push_back(
-      std::make_unique<EphemeronItem>(key, value, value_trace_callback));
+    TraceDescriptor value_trace_descriptor) {
+  ephemeron_worklist_.push_back(std::make_unique<EphemeronItem>(
+      key, value_trace_descriptor.base_object_payload,
+      value_trace_descriptor.callback));
 }
 
 void V8EmbedderGraphBuilder::VisitPendingActivities() {
diff --git a/third_party/blink/renderer/controller/BUILD.gn b/third_party/blink/renderer/controller/BUILD.gn
index 87c15e50..c5647d2 100644
--- a/third_party/blink/renderer/controller/BUILD.gn
+++ b/third_party/blink/renderer/controller/BUILD.gn
@@ -24,6 +24,7 @@
   ]
 
   configs += [
+    "//build/config/compiler:noshadowing",
     "//build/config/compiler:wexit_time_destructors",
     "//third_party/blink/renderer:config",
     "//third_party/blink/renderer:inside_blink",
diff --git a/third_party/blink/renderer/core/BUILD.gn b/third_party/blink/renderer/core/BUILD.gn
index a8fadcd..e329fa3 100644
--- a/third_party/blink/renderer/core/BUILD.gn
+++ b/third_party/blink/renderer/core/BUILD.gn
@@ -1380,6 +1380,7 @@
     "paint/paint_property_tree_update_tests.cc",
     "paint/paint_timing_test_helper.h",
     "paint/pre_paint_tree_walk_test.cc",
+    "paint/selection_painting_utils_test.cc",
     "paint/svg_container_painter_test.cc",
     "paint/table_painter_test.cc",
     "paint/text_paint_timing_detector_test.cc",
diff --git a/third_party/blink/renderer/core/animation/basic_shape_interpolation_functions.cc b/third_party/blink/renderer/core/animation/basic_shape_interpolation_functions.cc
index ed8acf1..d549899 100644
--- a/third_party/blink/renderer/core/animation/basic_shape_interpolation_functions.cc
+++ b/third_party/blink/renderer/core/animation/basic_shape_interpolation_functions.cc
@@ -537,6 +537,9 @@
     case BasicShape::kBasicShapePolygonType:
       return polygon_functions::ConvertBasicShape(To<BasicShapePolygon>(*shape),
                                                   zoom);
+    // Handled by PathInterpolationFunction.
+    case BasicShape::kStylePathType:
+      return nullptr;
     default:
       NOTREACHED();
       return nullptr;
diff --git a/third_party/blink/renderer/core/animation/css_basic_shape_interpolation_type.cc b/third_party/blink/renderer/core/animation/css_basic_shape_interpolation_type.cc
index f6e7f98..1bb38aa 100644
--- a/third_party/blink/renderer/core/animation/css_basic_shape_interpolation_type.cc
+++ b/third_party/blink/renderer/core/animation/css_basic_shape_interpolation_type.cc
@@ -33,12 +33,21 @@
       if (style.ShapeOutside()->CssBox() != CSSBoxType::kMissing)
         return nullptr;
       return style.ShapeOutside()->Shape();
-    case CSSPropertyID::kClipPath:
+    case CSSPropertyID::kClipPath: {
       if (!style.ClipPath())
         return nullptr;
-      if (style.ClipPath()->GetType() != ClipPathOperation::SHAPE)
+      auto* clip_path_operation =
+          DynamicTo<ShapeClipPathOperation>(style.ClipPath());
+      if (!clip_path_operation)
         return nullptr;
-      return To<ShapeClipPathOperation>(style.ClipPath())->GetBasicShape();
+      auto* shape = clip_path_operation->GetBasicShape();
+
+      // Path shape is handled by PathInterpolationType.
+      if (shape->GetType() == BasicShape::kStylePathType)
+        return nullptr;
+
+      return shape;
+    }
     default:
       NOTREACHED();
       return nullptr;
diff --git a/third_party/blink/renderer/core/animation/css_interpolation_types_map.cc b/third_party/blink/renderer/core/animation/css_interpolation_types_map.cc
index 0dbbc62..71ea57ec 100644
--- a/third_party/blink/renderer/core/animation/css_interpolation_types_map.cc
+++ b/third_party/blink/renderer/core/animation/css_interpolation_types_map.cc
@@ -343,6 +343,11 @@
             std::make_unique<CSSImageSliceInterpolationType>(used_property));
         break;
       case CSSPropertyID::kClipPath:
+        applicable_types->push_back(
+            std::make_unique<CSSBasicShapeInterpolationType>(used_property));
+        applicable_types->push_back(
+            std::make_unique<CSSPathInterpolationType>(used_property));
+        break;
       case CSSPropertyID::kShapeOutside:
         applicable_types->push_back(
             std::make_unique<CSSBasicShapeInterpolationType>(used_property));
diff --git a/third_party/blink/renderer/core/animation/css_path_interpolation_type.cc b/third_party/blink/renderer/core/animation/css_path_interpolation_type.cc
index 37c5b4d2..d60b395 100644
--- a/third_party/blink/renderer/core/animation/css_path_interpolation_type.cc
+++ b/third_party/blink/renderer/core/animation/css_path_interpolation_type.cc
@@ -12,6 +12,7 @@
 #include "third_party/blink/renderer/core/css/css_path_value.h"
 #include "third_party/blink/renderer/core/css/resolver/style_resolver_state.h"
 #include "third_party/blink/renderer/core/style/computed_style.h"
+#include "third_party/blink/renderer/core/style/shape_clip_path_operation.h"
 
 namespace blink {
 
@@ -24,11 +25,13 @@
   switch (property.PropertyID()) {
     case CSSPropertyID::kD:
       return style.SvgStyle().D();
-    case CSSPropertyID::kOffsetPath: {
-      BasicShape* offset_path = style.OffsetPath();
-      if (!offset_path || offset_path->GetType() != BasicShape::kStylePathType)
+    case CSSPropertyID::kOffsetPath:
+      return DynamicTo<StylePath>(style.OffsetPath());
+    case CSSPropertyID::kClipPath: {
+      auto* shape = DynamicTo<ShapeClipPathOperation>(style.ClipPath());
+      if (!shape)
         return nullptr;
-      return To<StylePath>(style.OffsetPath());
+      return DynamicTo<StylePath>(shape->GetBasicShape());
     }
     default:
       NOTREACHED();
@@ -47,6 +50,9 @@
     case CSSPropertyID::kOffsetPath:
       style.SetOffsetPath(std::move(path));
       return;
+    case CSSPropertyID::kClipPath:
+      style.SetClipPath(ShapeClipPathOperation::Create(std::move(path)));
+      return;
     default:
       NOTREACHED();
       return;
@@ -59,15 +65,9 @@
     const InterpolableValue& interpolable_value,
     const NonInterpolableValue* non_interpolable_value,
     StyleResolverState& state) const {
-  std::unique_ptr<SVGPathByteStream> path_byte_stream =
-      PathInterpolationFunctions::AppliedValue(interpolable_value,
-                                               non_interpolable_value);
-  if (path_byte_stream->IsEmpty()) {
-    SetPath(CssProperty(), *state.Style(), nullptr);
-    return;
-  }
   SetPath(CssProperty(), *state.Style(),
-          StylePath::Create(std::move(path_byte_stream)));
+          PathInterpolationFunctions::AppliedValue(interpolable_value,
+                                                   non_interpolable_value));
 }
 
 void CSSPathInterpolationType::Composite(
@@ -125,13 +125,13 @@
 InterpolationValue CSSPathInterpolationType::MaybeConvertValue(
     const CSSValue& value,
     const StyleResolverState*,
-    ConversionCheckers& conversion_checkers) const {
+    ConversionCheckers&) const {
   auto* path_value = DynamicTo<cssvalue::CSSPathValue>(value);
-  if (!path_value) {
+  if (!path_value)
     return nullptr;
-  }
+
   return PathInterpolationFunctions::ConvertValue(
-      path_value->ByteStream(), PathInterpolationFunctions::ForceAbsolute);
+      path_value->GetStylePath(), PathInterpolationFunctions::ForceAbsolute);
 }
 
 InterpolationValue
diff --git a/third_party/blink/renderer/core/animation/path_interpolation_functions.cc b/third_party/blink/renderer/core/animation/path_interpolation_functions.cc
index 4331bcc..f3d696942e 100644
--- a/third_party/blink/renderer/core/animation/path_interpolation_functions.cc
+++ b/third_party/blink/renderer/core/animation/path_interpolation_functions.cc
@@ -24,20 +24,26 @@
   ~SVGPathNonInterpolableValue() override = default;
 
   static scoped_refptr<SVGPathNonInterpolableValue> Create(
-      Vector<SVGPathSegType>& path_seg_types) {
-    return base::AdoptRef(new SVGPathNonInterpolableValue(path_seg_types));
+      Vector<SVGPathSegType>& path_seg_types,
+      WindRule wind_rule = RULE_NONZERO) {
+    return base::AdoptRef(
+        new SVGPathNonInterpolableValue(path_seg_types, wind_rule));
   }
 
   const Vector<SVGPathSegType>& PathSegTypes() const { return path_seg_types_; }
+  WindRule GetWindRule() const { return wind_rule_; }
 
   DECLARE_NON_INTERPOLABLE_VALUE_TYPE();
 
  private:
-  SVGPathNonInterpolableValue(Vector<SVGPathSegType>& path_seg_types) {
+  SVGPathNonInterpolableValue(Vector<SVGPathSegType>& path_seg_types,
+                              WindRule wind_rule)
+      : wind_rule_(wind_rule) {
     path_seg_types_.swap(path_seg_types);
   }
 
   Vector<SVGPathSegType> path_seg_types_;
+  WindRule wind_rule_;
 };
 
 DEFINE_NON_INTERPOLABLE_VALUE_TYPE(SVGPathNonInterpolableValue);
@@ -58,9 +64,12 @@
 };
 
 InterpolationValue PathInterpolationFunctions::ConvertValue(
-    const SVGPathByteStream& byte_stream,
+    const StylePath* style_path,
     CoordinateConversion coordinateConversion) {
-  SVGPathByteStreamSource path_source(byte_stream);
+  if (!style_path)
+    return nullptr;
+
+  SVGPathByteStreamSource path_source(style_path->ByteStream());
   wtf_size_t length = 0;
   PathCoordinates current_coordinates;
   Vector<std::unique_ptr<InterpolableValue>> interpolable_path_segs;
@@ -86,19 +95,9 @@
   result->Set(kPathArgsIndex, std::move(path_args));
   result->Set(kPathNeutralIndex, std::make_unique<InterpolableNumber>(0));
 
-  return InterpolationValue(
-      std::move(result), SVGPathNonInterpolableValue::Create(path_seg_types));
-}
-
-InterpolationValue PathInterpolationFunctions::ConvertValue(
-    const StylePath* style_path,
-    CoordinateConversion coordinateConversion) {
-  if (style_path)
-    return ConvertValue(style_path->ByteStream(), coordinateConversion);
-
-  std::unique_ptr<SVGPathByteStream> empty_path =
-      std::make_unique<SVGPathByteStream>();
-  return ConvertValue(*empty_path, ForceAbsolute);
+  return InterpolationValue(std::move(result),
+                            SVGPathNonInterpolableValue::Create(
+                                path_seg_types, style_path->GetWindRule()));
 }
 
 class UnderlyingPathSegTypesChecker
@@ -108,13 +107,14 @@
 
   static std::unique_ptr<UnderlyingPathSegTypesChecker> Create(
       const InterpolationValue& underlying) {
-    return base::WrapUnique(
-        new UnderlyingPathSegTypesChecker(GetPathSegTypes(underlying)));
+    return base::WrapUnique(new UnderlyingPathSegTypesChecker(
+        GetPathSegTypes(underlying), GetWindRule(underlying)));
   }
 
  private:
-  UnderlyingPathSegTypesChecker(const Vector<SVGPathSegType>& path_seg_types)
-      : path_seg_types_(path_seg_types) {}
+  UnderlyingPathSegTypesChecker(const Vector<SVGPathSegType>& path_seg_types,
+                                WindRule wind_rule)
+      : path_seg_types_(path_seg_types), wind_rule_(wind_rule) {}
 
   static const Vector<SVGPathSegType>& GetPathSegTypes(
       const InterpolationValue& underlying) {
@@ -122,12 +122,19 @@
         .PathSegTypes();
   }
 
+  static WindRule GetWindRule(const InterpolationValue& underlying) {
+    return To<SVGPathNonInterpolableValue>(*underlying.non_interpolable_value)
+        .GetWindRule();
+  }
+
   bool IsValid(const InterpolationEnvironment&,
                const InterpolationValue& underlying) const final {
-    return path_seg_types_ == GetPathSegTypes(underlying);
+    return path_seg_types_ == GetPathSegTypes(underlying) &&
+           wind_rule_ == GetWindRule(underlying);
   }
 
   Vector<SVGPathSegType> path_seg_types_;
+  WindRule wind_rule_;
 };
 
 InterpolationValue PathInterpolationFunctions::MaybeConvertNeutral(
@@ -161,12 +168,15 @@
 PairwiseInterpolationValue PathInterpolationFunctions::MaybeMergeSingles(
     InterpolationValue&& start,
     InterpolationValue&& end) {
-  const Vector<SVGPathSegType>& start_types =
-      To<SVGPathNonInterpolableValue>(*start.non_interpolable_value)
-          .PathSegTypes();
-  const Vector<SVGPathSegType>& end_types =
-      To<SVGPathNonInterpolableValue>(*end.non_interpolable_value)
-          .PathSegTypes();
+  auto& start_path =
+      To<SVGPathNonInterpolableValue>(*start.non_interpolable_value);
+  auto& end_path = To<SVGPathNonInterpolableValue>(*end.non_interpolable_value);
+
+  if (start_path.GetWindRule() != end_path.GetWindRule())
+    return nullptr;
+
+  const Vector<SVGPathSegType>& start_types = start_path.PathSegTypes();
+  const Vector<SVGPathSegType>& end_types = end_path.PathSegTypes();
   if (start_types.size() == 0 || !PathSegTypesMatch(start_types, end_types))
     return nullptr;
 
@@ -201,18 +211,23 @@
       value.non_interpolable_value.get();
 }
 
-std::unique_ptr<SVGPathByteStream> PathInterpolationFunctions::AppliedValue(
+scoped_refptr<StylePath> PathInterpolationFunctions::AppliedValue(
     const InterpolableValue& interpolable_value,
     const NonInterpolableValue* non_interpolable_value) {
   std::unique_ptr<SVGPathByteStream> path_byte_stream =
       std::make_unique<SVGPathByteStream>();
+
+  auto* non_interpolable_path_value =
+      To<SVGPathNonInterpolableValue>(non_interpolable_value);
   InterpolatedSVGPathSource source(
       To<InterpolableList>(
           *To<InterpolableList>(interpolable_value).Get(kPathArgsIndex)),
-      To<SVGPathNonInterpolableValue>(non_interpolable_value)->PathSegTypes());
+      non_interpolable_path_value->PathSegTypes());
   SVGPathByteStreamBuilder builder(*path_byte_stream);
   svg_path_parser::ParsePath(source, builder);
-  return path_byte_stream;
+
+  return StylePath::Create(std::move(path_byte_stream),
+                           non_interpolable_path_value->GetWindRule());
 }
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/animation/path_interpolation_functions.h b/third_party/blink/renderer/core/animation/path_interpolation_functions.h
index a545f023..dddce78 100644
--- a/third_party/blink/renderer/core/animation/path_interpolation_functions.h
+++ b/third_party/blink/renderer/core/animation/path_interpolation_functions.h
@@ -20,18 +20,14 @@
  public:
   enum CoordinateConversion { PreserveCoordinates, ForceAbsolute };
 
-  static std::unique_ptr<SVGPathByteStream> AppliedValue(
-      const InterpolableValue&,
-      const NonInterpolableValue*);
+  static scoped_refptr<StylePath> AppliedValue(const InterpolableValue&,
+                                               const NonInterpolableValue*);
 
   static void Composite(UnderlyingValueOwner&,
                         double underlying_fraction,
                         const InterpolationType&,
                         const InterpolationValue&);
 
-  static InterpolationValue ConvertValue(const SVGPathByteStream&,
-                                         CoordinateConversion);
-
   static InterpolationValue ConvertValue(const StylePath*,
                                          CoordinateConversion);
 
diff --git a/third_party/blink/renderer/core/animation/svg_path_interpolation_type.cc b/third_party/blink/renderer/core/animation/svg_path_interpolation_type.cc
index 7fa8e96..9c256e7 100644
--- a/third_party/blink/renderer/core/animation/svg_path_interpolation_type.cc
+++ b/third_party/blink/renderer/core/animation/svg_path_interpolation_type.cc
@@ -16,7 +16,7 @@
     return nullptr;
 
   return PathInterpolationFunctions::ConvertValue(
-      To<SVGPath>(svg_value).ByteStream(),
+      To<SVGPath>(svg_value).GetStylePath(),
       PathInterpolationFunctions::PreserveCoordinates);
 }
 
diff --git a/third_party/blink/renderer/core/css/basic_shape_functions.cc b/third_party/blink/renderer/core/css/basic_shape_functions.cc
index f6418d3..0ab751f 100644
--- a/third_party/blink/renderer/core/css/basic_shape_functions.cc
+++ b/third_party/blink/renderer/core/css/basic_shape_functions.cc
@@ -32,6 +32,7 @@
 #include "third_party/blink/renderer/core/css/css_basic_shape_values.h"
 #include "third_party/blink/renderer/core/css/css_identifier_value.h"
 #include "third_party/blink/renderer/core/css/css_numeric_literal_value.h"
+#include "third_party/blink/renderer/core/css/css_path_value.h"
 #include "third_party/blink/renderer/core/css/css_primitive_value_mappings.h"
 #include "third_party/blink/renderer/core/css/css_ray_value.h"
 #include "third_party/blink/renderer/core/css/css_value_pair.h"
@@ -358,6 +359,9 @@
     StyleRay::RaySize size = KeywordToRaySize(ray_value->Size().GetValueID());
     bool contain = !!ray_value->Contain();
     basic_shape = StyleRay::Create(angle, size, contain);
+  } else if (const auto* path_value =
+                 DynamicTo<cssvalue::CSSPathValue>(basic_shape_value)) {
+    basic_shape = path_value->GetStylePath();
   } else {
     NOTREACHED();
   }
diff --git a/third_party/blink/renderer/core/css/css_path_value.cc b/third_party/blink/renderer/core/css/css_path_value.cc
index 3c1ae0b..d4f7425 100644
--- a/third_party/blink/renderer/core/css/css_path_value.cc
+++ b/third_party/blink/renderer/core/css/css_path_value.cc
@@ -8,6 +8,7 @@
 #include "third_party/blink/renderer/core/style/style_path.h"
 #include "third_party/blink/renderer/core/svg/svg_path_utilities.h"
 #include "third_party/blink/renderer/platform/heap/persistent.h"
+#include "third_party/blink/renderer/platform/wtf/text/string_builder.h"
 
 namespace blink {
 
@@ -22,8 +23,9 @@
 }
 
 CSSPathValue::CSSPathValue(std::unique_ptr<SVGPathByteStream> path_byte_stream,
+                           WindRule wind_rule,
                            PathSerializationFormat serialization_format)
-    : CSSPathValue(StylePath::Create(std::move(path_byte_stream)),
+    : CSSPathValue(StylePath::Create(std::move(path_byte_stream), wind_rule),
                    serialization_format) {}
 
 namespace {
@@ -45,8 +47,14 @@
 }
 
 String CSSPathValue::CustomCSSText() const {
-  return "path(\"" +
-         BuildStringFromByteStream(ByteStream(), serialization_format_) + "\")";
+  StringBuilder result;
+  result.Append("path(");
+  if (style_path_->GetWindRule() == RULE_EVENODD)
+    result.Append("evenodd, ");
+  result.Append("\"");
+  result.Append(BuildStringFromByteStream(ByteStream(), serialization_format_));
+  result.Append("\")");
+  return result.ToString();
 }
 
 bool CSSPathValue::Equals(const CSSPathValue& other) const {
diff --git a/third_party/blink/renderer/core/css/css_path_value.h b/third_party/blink/renderer/core/css/css_path_value.h
index ee3d8128..2642b31 100644
--- a/third_party/blink/renderer/core/css/css_path_value.h
+++ b/third_party/blink/renderer/core/css/css_path_value.h
@@ -26,6 +26,7 @@
   explicit CSSPathValue(scoped_refptr<StylePath>,
                         PathSerializationFormat = kNoTransformation);
   explicit CSSPathValue(std::unique_ptr<SVGPathByteStream>,
+                        WindRule wind_rule = RULE_NONZERO,
                         PathSerializationFormat = kNoTransformation);
 
   StylePath* GetStylePath() const { return style_path_.get(); }
diff --git a/third_party/blink/renderer/core/css/properties/css_parsing_utils.cc b/third_party/blink/renderer/core/css/properties/css_parsing_utils.cc
index c9dd2a0..a72cce67 100644
--- a/third_party/blink/renderer/core/css/properties/css_parsing_utils.cc
+++ b/third_party/blink/renderer/core/css/properties/css_parsing_utils.cc
@@ -4386,7 +4386,43 @@
   return false;
 }
 
-CSSValue* ConsumePath(CSSParserTokenRange& range) {
+std::unique_ptr<SVGPathByteStream> ConsumePathStringArg(
+    CSSParserTokenRange& args) {
+  if (args.Peek().GetType() != kStringToken)
+    return nullptr;
+
+  StringView path_string = args.ConsumeIncludingWhitespace().Value();
+  std::unique_ptr<SVGPathByteStream> byte_stream =
+      std::make_unique<SVGPathByteStream>();
+  if (BuildByteStreamFromString(path_string, *byte_stream) !=
+      SVGParseStatus::kNoError) {
+    return nullptr;
+  }
+
+  return byte_stream;
+}
+
+cssvalue::CSSPathValue* ConsumeBasicShapePath(CSSParserTokenRange& args) {
+  auto wind_rule = RULE_NONZERO;
+
+  if (IdentMatches<CSSValueID::kEvenodd, CSSValueID::kNonzero>(
+          args.Peek().Id())) {
+    wind_rule = args.ConsumeIncludingWhitespace().Id() == CSSValueID::kEvenodd
+                    ? RULE_EVENODD
+                    : RULE_NONZERO;
+    if (!ConsumeCommaIncludingWhitespace(args))
+      return nullptr;
+  }
+
+  auto byte_stream = ConsumePathStringArg(args);
+  if (!byte_stream || !args.AtEnd())
+    return nullptr;
+
+  return MakeGarbageCollected<cssvalue::CSSPathValue>(std::move(byte_stream),
+                                                      wind_rule);
+}
+
+CSSValue* ConsumePathFunction(CSSParserTokenRange& range) {
   // FIXME: Add support for <url>, <basic-shape>, <geometry-box>.
   if (range.Peek().FunctionId() != CSSValueID::kPath)
     return nullptr;
@@ -4394,16 +4430,9 @@
   CSSParserTokenRange function_range = range;
   CSSParserTokenRange function_args = ConsumeFunction(function_range);
 
-  if (function_args.Peek().GetType() != kStringToken)
+  auto byte_stream = ConsumePathStringArg(function_args);
+  if (!byte_stream || !function_args.AtEnd())
     return nullptr;
-  StringView path_string = function_args.ConsumeIncludingWhitespace().Value();
-  std::unique_ptr<SVGPathByteStream> byte_stream =
-      std::make_unique<SVGPathByteStream>();
-  if (BuildByteStreamFromString(path_string, *byte_stream) !=
-          SVGParseStatus::kNoError ||
-      !function_args.AtEnd()) {
-    return nullptr;
-  }
 
   range = function_range;
   if (byte_stream->IsEmpty())
@@ -4505,7 +4534,7 @@
   if (id == CSSValueID::kNone)
     return ConsumeIdent(range);
 
-  return ConsumePath(range);
+  return ConsumePathFunction(range);
 }
 
 CSSValue* ConsumeOffsetRotate(CSSParserTokenRange& range,
@@ -4574,7 +4603,8 @@
 }
 
 CSSValue* ConsumeBasicShape(CSSParserTokenRange& range,
-                            const CSSParserContext& context) {
+                            const CSSParserContext& context,
+                            AllowPathValue allow_path) {
   CSSValue* shape = nullptr;
   if (range.Peek().GetType() != kFunctionToken)
     return nullptr;
@@ -4589,6 +4619,8 @@
     shape = ConsumeBasicShapePolygon(args, context);
   else if (id == CSSValueID::kInset)
     shape = ConsumeBasicShapeInset(args, context);
+  else if (id == CSSValueID::kPath && allow_path == AllowPathValue::kAllow)
+    shape = ConsumeBasicShapePath(args);
   if (!shape || !args.AtEnd())
     return nullptr;
 
diff --git a/third_party/blink/renderer/core/css/properties/css_parsing_utils.h b/third_party/blink/renderer/core/css/properties/css_parsing_utils.h
index b051a17..543a8615 100644
--- a/third_party/blink/renderer/core/css/properties/css_parsing_utils.h
+++ b/third_party/blink/renderer/core/css/properties/css_parsing_utils.h
@@ -45,6 +45,7 @@
 
 enum class AllowInsetAndSpread { kAllow, kForbid };
 enum class AllowTextValue { kAllow, kForbid };
+enum class AllowPathValue { kAllow, kForbid };
 enum class DefaultFill { kFill, kNoFill };
 enum class ParsingStyle { kLegacy, kNotLegacy };
 enum class TrackListType { kGridTemplate, kGridTemplateNoRepeat, kGridAuto };
@@ -416,7 +417,9 @@
 CSSValue* ConsumePathOrNone(CSSParserTokenRange&);
 CSSValue* ConsumeOffsetRotate(CSSParserTokenRange&, const CSSParserContext&);
 
-CSSValue* ConsumeBasicShape(CSSParserTokenRange&, const CSSParserContext&);
+CSSValue* ConsumeBasicShape(CSSParserTokenRange&,
+                            const CSSParserContext&,
+                            AllowPathValue);
 bool ConsumeRadii(CSSValue* horizontal_radii[4],
                   CSSValue* vertical_radii[4],
                   CSSParserTokenRange&,
diff --git a/third_party/blink/renderer/core/css/properties/longhands/longhands_custom.cc b/third_party/blink/renderer/core/css/properties/longhands/longhands_custom.cc
index f7cdcad..41e88676 100644
--- a/third_party/blink/renderer/core/css/properties/longhands/longhands_custom.cc
+++ b/third_party/blink/renderer/core/css/properties/longhands/longhands_custom.cc
@@ -1455,7 +1455,8 @@
   if (cssvalue::CSSURIValue* url =
           css_parsing_utils::ConsumeUrl(range, context))
     return url;
-  return css_parsing_utils::ConsumeBasicShape(range, context);
+  return css_parsing_utils::ConsumeBasicShape(
+      range, context, css_parsing_utils::AllowPathValue::kAllow);
 }
 
 const CSSValue* ClipPath::CSSValueFromComputedStyleInternal(
@@ -5791,8 +5792,8 @@
     return image_value;
   CSSValueList* list = CSSValueList::CreateSpaceSeparated();
   CSSValue* box_value = css_parsing_utils::ConsumeShapeBox(range);
-  if (CSSValue* shape_value =
-          css_parsing_utils::ConsumeBasicShape(range, context)) {
+  if (CSSValue* shape_value = css_parsing_utils::ConsumeBasicShape(
+          range, context, css_parsing_utils::AllowPathValue::kForbid)) {
     list->Append(*shape_value);
     if (!box_value) {
       box_value = css_parsing_utils::ConsumeShapeBox(range);
diff --git a/third_party/blink/renderer/core/css/resolver/style_builder_converter.cc b/third_party/blink/renderer/core/css/resolver/style_builder_converter.cc
index df82a83a..35eb45c 100644
--- a/third_party/blink/renderer/core/css/resolver/style_builder_converter.cc
+++ b/third_party/blink/renderer/core/css/resolver/style_builder_converter.cc
@@ -147,8 +147,9 @@
 scoped_refptr<ClipPathOperation> StyleBuilderConverter::ConvertClipPath(
     StyleResolverState& state,
     const CSSValue& value) {
-  if (value.IsBasicShapeValue())
+  if (value.IsBasicShapeValue() || value.IsPathValue())
     return ShapeClipPathOperation::Create(BasicShapeForValue(state, value));
+
   if (const auto* url_value = DynamicTo<cssvalue::CSSURIValue>(value)) {
     SVGResource* resource =
         state.GetElementStyleResources().GetSVGResourceFromValue(
diff --git a/third_party/blink/renderer/core/layout/svg/svg_layout_support.cc b/third_party/blink/renderer/core/layout/svg/svg_layout_support.cc
index f002404..27e3f04 100644
--- a/third_party/blink/renderer/core/layout/svg/svg_layout_support.cc
+++ b/third_party/blink/renderer/core/layout/svg/svg_layout_support.cc
@@ -453,7 +453,7 @@
   if (clip_path_operation->GetType() == ClipPathOperation::SHAPE) {
     ShapeClipPathOperation& clip_path =
         To<ShapeClipPathOperation>(*clip_path_operation);
-    return clip_path.GetPath(reference_box)
+    return clip_path.GetPath(reference_box, 1)
         .Contains(location.TransformedPoint());
   }
   DCHECK_EQ(clip_path_operation->GetType(), ClipPathOperation::REFERENCE);
diff --git a/third_party/blink/renderer/core/mathml/mathml_operator_element.cc b/third_party/blink/renderer/core/mathml/mathml_operator_element.cc
index fca4f281..c2dfdca 100644
--- a/third_party/blink/renderer/core/mathml/mathml_operator_element.cc
+++ b/third_party/blink/renderer/core/mathml/mathml_operator_element.cc
@@ -4,6 +4,7 @@
 
 #include "third_party/blink/renderer/core/mathml/mathml_operator_element.h"
 
+#include "third_party/blink/renderer/core/css/style_change_reason.h"
 #include "third_party/blink/renderer/core/layout/layout_object.h"
 #include "third_party/blink/renderer/core/style/computed_style.h"
 #include "third_party/blink/renderer/platform/text/mathml_operator_dictionary.h"
@@ -138,6 +139,14 @@
   } else if (param.name == mathml_names::kMovablelimitsAttr) {
     SetOperatorPropertyDirtyFlagIfNeeded(
         param, MathMLOperatorElement::kMovableLimits, needs_layout);
+  } else if (param.name == mathml_names::kLspaceAttr ||
+             param.name == mathml_names::kRspaceAttr) {
+    needs_layout = param.new_value != param.old_value;
+    if (needs_layout && GetLayoutObject()) {
+      SetNeedsStyleRecalc(
+          kLocalStyleChange,
+          StyleChangeReasonForTracing::Create(style_change_reason::kAttribute));
+    }
   }
   if (needs_layout && GetLayoutObject() && GetLayoutObject()->IsMathML()) {
     GetLayoutObject()
diff --git a/third_party/blink/renderer/core/page/print_context.cc b/third_party/blink/renderer/core/page/print_context.cc
index fa2aa23..14bcc73 100644
--- a/third_party/blink/renderer/core/page/print_context.cc
+++ b/third_party/blink/renderer/core/page/print_context.cc
@@ -25,7 +25,9 @@
 #include "third_party/blink/public/web/web_print_page_description.h"
 #include "third_party/blink/renderer/core/frame/local_frame.h"
 #include "third_party/blink/renderer/core/frame/local_frame_view.h"
+#include "third_party/blink/renderer/core/frame/page_scale_constraints_set.h"
 #include "third_party/blink/renderer/core/layout/layout_view.h"
+#include "third_party/blink/renderer/core/page/page.h"
 #include "third_party/blink/renderer/core/paint/paint_layer_scrollable_area.h"
 #include "third_party/blink/renderer/platform/graphics/graphics_context.h"
 
@@ -164,8 +166,14 @@
 void PrintContext::EndPrintMode() {
   DCHECK(is_printing_);
   is_printing_ = false;
-  if (IsFrameValid())
+  if (IsFrameValid()) {
     frame_->EndPrinting();
+
+    // Printing changes the viewport and content size which may result in
+    // changing the page scale factor. Call SetNeedsReset() so that we reset
+    // back to the initial page scale factor when we exit printing mode.
+    frame_->GetPage()->GetPageScaleConstraintsSet().SetNeedsReset(true);
+  }
   linked_destinations_.clear();
   linked_destinations_valid_ = false;
 }
diff --git a/third_party/blink/renderer/core/page/scrolling/text_fragment_anchor_metrics.cc b/third_party/blink/renderer/core/page/scrolling/text_fragment_anchor_metrics.cc
index e1009570..e34d2966 100644
--- a/third_party/blink/renderer/core/page/scrolling/text_fragment_anchor_metrics.cc
+++ b/third_party/blink/renderer/core/page/scrolling/text_fragment_anchor_metrics.cc
@@ -5,7 +5,7 @@
 #include "third_party/blink/renderer/core/page/scrolling/text_fragment_anchor_metrics.h"
 
 #include "base/check.h"
-#include "base/metrics/histogram_macros.h"
+#include "base/metrics/histogram_functions.h"
 #include "base/time/default_tick_clock.h"
 #include "base/trace_event/trace_event.h"
 #include "third_party/blink/renderer/core/frame/web_feature.h"
@@ -71,8 +71,8 @@
 
   base::TimeDelta time_to_scroll_to_top(scroll_to_top_time -
                                         first_scroll_into_view_time_);
-  UMA_HISTOGRAM_TIMES("TextFragmentAnchor.TimeToScrollToTop",
-                      time_to_scroll_to_top);
+  base::UmaHistogramTimes("TextFragmentAnchor.TimeToScrollToTop",
+                          time_to_scroll_to_top);
   TRACE_EVENT_INSTANT1("blink", "TextFragmentAnchorMetrics::ReportMetrics",
                        TRACE_EVENT_SCOPE_THREAD, "time_to_scroll_to_top",
                        time_to_scroll_to_top.InMilliseconds());
@@ -90,20 +90,22 @@
     UseCounter::Count(document_, WebFeature::kTextFragmentAnchorMatchFound);
   }
 
-  UMA_HISTOGRAM_COUNTS_100("TextFragmentAnchor.SelectorCount", selector_count_);
+  base::UmaHistogramCounts100("TextFragmentAnchor.SelectorCount",
+                              selector_count_);
   TRACE_EVENT_INSTANT1("blink", "TextFragmentAnchorMetrics::ReportMetrics",
                        TRACE_EVENT_SCOPE_THREAD, "selector_count",
                        selector_count_);
 
-  UMA_HISTOGRAM_COUNTS_1000("TextFragmentAnchor.DirectiveLength",
-                            directive_length_);
+  base::UmaHistogramCounts1000("TextFragmentAnchor.DirectiveLength",
+                               directive_length_);
   TRACE_EVENT_INSTANT1("blink", "TextFragmentAnchorMetrics::ReportMetrics",
                        TRACE_EVENT_SCOPE_THREAD, "directive_length",
                        directive_length_);
 
   const int match_rate_percent =
       static_cast<int>(100 * ((matches_.size() + 0.0) / selector_count_));
-  UMA_HISTOGRAM_PERCENTAGE("TextFragmentAnchor.MatchRate", match_rate_percent);
+  base::UmaHistogramPercentage("TextFragmentAnchor.MatchRate",
+                               match_rate_percent);
   TRACE_EVENT_INSTANT1("blink", "TextFragmentAnchorMetrics::ReportMetrics",
                        TRACE_EVENT_SCOPE_THREAD, "match_rate",
                        match_rate_percent);
@@ -116,31 +118,31 @@
         match.text.length());
 
     if (match.selector.Type() == TextFragmentSelector::kExact) {
-      UMA_HISTOGRAM_COUNTS_1000("TextFragmentAnchor.ExactTextLength",
-                                match.text.length());
+      base::UmaHistogramCounts1000("TextFragmentAnchor.ExactTextLength",
+                                   match.text.length());
       TRACE_EVENT_INSTANT1("blink", "TextFragmentAnchorMetrics::ReportMetrics",
                            TRACE_EVENT_SCOPE_THREAD, "exact_text_length",
                            match.text.length());
 
-      UMA_HISTOGRAM_BOOLEAN("TextFragmentAnchor.ListItemMatch",
-                            match.is_list_item);
-      UMA_HISTOGRAM_BOOLEAN("TextFragmentAnchor.TableCellMatch",
-                            match.is_table_cell);
+      base::UmaHistogramBoolean("TextFragmentAnchor.ListItemMatch",
+                                match.is_list_item);
+      base::UmaHistogramBoolean("TextFragmentAnchor.TableCellMatch",
+                                match.is_table_cell);
     } else if (match.selector.Type() == TextFragmentSelector::kRange) {
-      UMA_HISTOGRAM_COUNTS_1000("TextFragmentAnchor.RangeMatchLength",
-                                match.text.length());
+      base::UmaHistogramCounts1000("TextFragmentAnchor.RangeMatchLength",
+                                   match.text.length());
       TRACE_EVENT_INSTANT1("blink", "TextFragmentAnchorMetrics::ReportMetrics",
                            TRACE_EVENT_SCOPE_THREAD, "range_match_length",
                            match.text.length());
 
-      UMA_HISTOGRAM_COUNTS_1000("TextFragmentAnchor.StartTextLength",
-                                match.selector.Start().length());
+      base::UmaHistogramCounts1000("TextFragmentAnchor.StartTextLength",
+                                   match.selector.Start().length());
       TRACE_EVENT_INSTANT1("blink", "TextFragmentAnchorMetrics::ReportMetrics",
                            TRACE_EVENT_SCOPE_THREAD, "start_text_length",
                            match.selector.Start().length());
 
-      UMA_HISTOGRAM_COUNTS_1000("TextFragmentAnchor.EndTextLength",
-                                match.selector.End().length());
+      base::UmaHistogramCounts1000("TextFragmentAnchor.EndTextLength",
+                                   match.selector.End().length());
       TRACE_EVENT_INSTANT1("blink", "TextFragmentAnchorMetrics::ReportMetrics",
                            TRACE_EVENT_SCOPE_THREAD, "end_text_length",
                            match.selector.End().length());
@@ -149,17 +151,18 @@
       DCHECK(!match.is_list_item && !match.is_table_cell);
     }
 
-    UMA_HISTOGRAM_ENUMERATION("TextFragmentAnchor.Parameters",
-                              GetParametersForSelector(match.selector));
+    base::UmaHistogramEnumeration("TextFragmentAnchor.Parameters",
+                                  GetParametersForSelector(match.selector));
   }
 
-  UMA_HISTOGRAM_BOOLEAN("TextFragmentAnchor.AmbiguousMatch", ambiguous_match_);
+  base::UmaHistogramBoolean("TextFragmentAnchor.AmbiguousMatch",
+                            ambiguous_match_);
   TRACE_EVENT_INSTANT1("blink", "TextFragmentAnchorMetrics::ReportMetrics",
                        TRACE_EVENT_SCOPE_THREAD, "ambiguous_match",
                        ambiguous_match_);
 
-  UMA_HISTOGRAM_BOOLEAN("TextFragmentAnchor.ScrollCancelled",
-                        scroll_cancelled_);
+  base::UmaHistogramBoolean("TextFragmentAnchor.ScrollCancelled",
+                            scroll_cancelled_);
   TRACE_EVENT_INSTANT1("blink", "TextFragmentAnchorMetrics::ReportMetrics",
                        TRACE_EVENT_SCOPE_THREAD, "scroll_cancelled",
                        scroll_cancelled_);
@@ -167,23 +170,25 @@
   if (!first_scroll_into_view_time_.is_null()) {
     DCHECK(first_scroll_into_view_time_ >= search_start_time_);
 
-    UMA_HISTOGRAM_BOOLEAN("TextFragmentAnchor.DidScrollIntoView",
-                          did_non_zero_scroll_);
+    base::UmaHistogramBoolean("TextFragmentAnchor.DidScrollIntoView",
+                              did_non_zero_scroll_);
     TRACE_EVENT_INSTANT1("blink", "TextFragmentAnchorMetrics::ReportMetrics",
                          TRACE_EVENT_SCOPE_THREAD, "did_scroll_into_view",
                          did_non_zero_scroll_);
 
     base::TimeDelta time_to_scroll_into_view(first_scroll_into_view_time_ -
                                              search_start_time_);
-    UMA_HISTOGRAM_TIMES("TextFragmentAnchor.TimeToScrollIntoView",
-                        time_to_scroll_into_view);
+    base::UmaHistogramTimes("TextFragmentAnchor.TimeToScrollIntoView",
+                            time_to_scroll_into_view);
     TRACE_EVENT_INSTANT1("blink", "TextFragmentAnchorMetrics::ReportMetrics",
                          TRACE_EVENT_SCOPE_THREAD, "time_to_scroll_into_view",
                          time_to_scroll_into_view.InMilliseconds());
   }
 
-  UMA_HISTOGRAM_BOOLEAN("TextFragmentAnchor.LinkOpenSource",
-                        has_search_engine_source_);
+  base::UmaHistogramEnumeration("TextFragmentAnchor.LinkOpenSource",
+                                has_search_engine_source_
+                                    ? TextFragmentLinkOpenSource::kSearchEngine
+                                    : TextFragmentLinkOpenSource::kUnknown);
 #ifndef NDEBUG
   metrics_reported_ = true;
 #endif
diff --git a/third_party/blink/renderer/core/page/scrolling/text_fragment_anchor_metrics.h b/third_party/blink/renderer/core/page/scrolling/text_fragment_anchor_metrics.h
index 616beb85..99820c9 100644
--- a/third_party/blink/renderer/core/page/scrolling/text_fragment_anchor_metrics.h
+++ b/third_party/blink/renderer/core/page/scrolling/text_fragment_anchor_metrics.h
@@ -40,6 +40,14 @@
     kMaxValue = kTextRangeWithContext,
   };
 
+  // Update corresponding |TextFragmentLinkOpenSource| in enums.xml.
+  enum class TextFragmentLinkOpenSource {
+    kUnknown,
+    kSearchEngine,
+
+    kMaxValue = kSearchEngine,
+  };
+
   explicit TextFragmentAnchorMetrics(Document* document);
 
   static TextFragmentAnchorParameters GetParametersForSelector(
diff --git a/third_party/blink/renderer/core/paint/clip_path_clipper.cc b/third_party/blink/renderer/core/paint/clip_path_clipper.cc
index cd34316..efe54d6 100644
--- a/third_party/blink/renderer/core/paint/clip_path_clipper.cc
+++ b/third_party/blink/renderer/core/paint/clip_path_clipper.cc
@@ -75,7 +75,9 @@
     ShapeClipPathOperation& shape = To<ShapeClipPathOperation>(clip_path);
     if (!shape.IsValid())
       return base::nullopt;
-    FloatRect bounding_box = shape.GetPath(reference_box).BoundingRect();
+    auto zoom =
+        UsesZoomedReferenceBox(object) ? object.StyleRef().EffectiveZoom() : 1;
+    FloatRect bounding_box = shape.GetPath(reference_box, zoom).BoundingRect();
     bounding_box.Intersect(LayoutRect::InfiniteIntRect());
     return bounding_box;
   }
@@ -160,7 +162,10 @@
 
   DCHECK_EQ(clip_path.GetType(), ClipPathOperation::SHAPE);
   auto& shape = To<ShapeClipPathOperation>(clip_path);
-  return shape.GetPath(reference_box);
+  float zoom = uses_zoomed_reference_box
+                   ? clip_path_owner.StyleRef().EffectiveZoom()
+                   : 1;
+  return shape.GetPath(reference_box, zoom);
 }
 
 void ClipPathClipper::PaintClipPathAsMaskImage(
diff --git a/third_party/blink/renderer/core/paint/paint_layer.cc b/third_party/blink/renderer/core/paint/paint_layer.cc
index 32f79ae..d99f1d0d 100644
--- a/third_party/blink/renderer/core/paint/paint_layer.cc
+++ b/third_party/blink/renderer/core/paint/paint_layer.cc
@@ -2544,7 +2544,10 @@
   if (clip_path_operation->GetType() == ClipPathOperation::SHAPE) {
     ShapeClipPathOperation* clip_path =
         To<ShapeClipPathOperation>(clip_path_operation);
-    return !clip_path->GetPath(reference_box).Contains(point);
+    return !clip_path
+                ->GetPath(reference_box,
+                          GetLayoutObject().StyleRef().EffectiveZoom())
+                .Contains(point);
   }
   DCHECK_EQ(clip_path_operation->GetType(), ClipPathOperation::REFERENCE);
   LayoutSVGResourceClipper* clipper = GetSVGResourceAsType(clip_path_operation);
diff --git a/third_party/blink/renderer/core/paint/selection_painting_utils.cc b/third_party/blink/renderer/core/paint/selection_painting_utils.cc
index 81b491f..7f4bca0c 100644
--- a/third_party/blink/renderer/core/paint/selection_painting_utils.cc
+++ b/third_party/blink/renderer/core/paint/selection_painting_utils.cc
@@ -5,14 +5,17 @@
 #include "third_party/blink/renderer/core/paint/selection_painting_utils.h"
 
 #include "third_party/blink/renderer/core/css/pseudo_style_request.h"
+#include "third_party/blink/renderer/core/css/style_engine.h"
 #include "third_party/blink/renderer/core/dom/element.h"
 #include "third_party/blink/renderer/core/dom/element_traversal.h"
 #include "third_party/blink/renderer/core/dom/node.h"
+#include "third_party/blink/renderer/core/dom/node_computed_style.h"
 #include "third_party/blink/renderer/core/dom/shadow_root.h"
 #include "third_party/blink/renderer/core/dom/v0_insertion_point.h"
 #include "third_party/blink/renderer/core/editing/frame_selection.h"
 #include "third_party/blink/renderer/core/frame/local_frame.h"
 #include "third_party/blink/renderer/core/layout/layout_theme.h"
+#include "third_party/blink/renderer/core/page/focus_controller.h"
 #include "third_party/blink/renderer/core/paint/paint_info.h"
 #include "third_party/blink/renderer/core/paint/text_paint_style.h"
 #include "third_party/blink/renderer/core/style/computed_style.h"
@@ -27,23 +30,20 @@
                                style.UserModify() == EUserModify::kReadOnly);
 }
 
-scoped_refptr<ComputedStyle> GetUncachedSelectionStyle(Node* node) {
+scoped_refptr<const ComputedStyle> SelectionPseudoStyle(Node* node) {
   if (!node)
     return nullptr;
 
+  Element* element = nullptr;
+
   // In Blink, ::selection only applies to direct children of the element on
   // which ::selection is matched. In order to be able to style ::selection
   // inside elements implemented with a UA shadow tree, like input::selection,
   // we calculate ::selection style on the shadow host for elements inside the
   // UA shadow.
-  if (ShadowRoot* root = node->ContainingShadowRoot()) {
-    if (root->IsUserAgent()) {
-      if (Element* shadow_host = node->OwnerShadowHost()) {
-        return shadow_host->StyleForPseudoElement(
-            PseudoElementStyleRequest(kPseudoIdSelection));
-      }
-    }
-  }
+  ShadowRoot* root = node->ContainingShadowRoot();
+  if (root && root->IsUserAgent())
+    element = node->OwnerShadowHost();
 
   // If we request ::selection style for LayoutText, query ::selection style on
   // the parent element instead, as that is the node for which ::selection
@@ -51,7 +51,8 @@
   // don't implement inheritance of ::selection styles, it would probably break
   // cases where you style a shadow host with ::selection and expect light tree
   // text children to be affected by that style.
-  Element* element = Traversal<Element>::FirstAncestorOrSelf(*node);
+  if (!element)
+    element = Traversal<Element>::FirstAncestorOrSelf(*node);
 
   // <content> and <shadow> elements do not have ComputedStyle, hence they will
   // return null for StyleForPseudoElement(). Return early to avoid DCHECK
@@ -61,8 +62,16 @@
     return nullptr;
   }
 
-  return element->StyleForPseudoElement(
-      PseudoElementStyleRequest(kPseudoIdSelection));
+  PseudoElementStyleRequest request(kPseudoIdSelection);
+  // ::selection and ::selection:window-inactive styles may be different. Only
+  // cache the styles for ::selection if there are no :window-inactive selector,
+  // or if the page is active.
+  if (element->GetDocument().GetStyleEngine().UsesWindowInactiveSelector() &&
+      !element->GetDocument().GetPage()->GetFocusController().IsActive()) {
+    return element->StyleForPseudoElement(request, element->GetComputedStyle());
+  }
+
+  return element->CachedStyleForPseudoElement(request);
 }
 
 Color SelectionColor(const Document& document,
@@ -76,8 +85,8 @@
       (global_paint_flags & kGlobalPaintSelectionDragImageOnly))
     return style.VisitedDependentColor(color_property);
 
-  if (scoped_refptr<ComputedStyle> pseudo_style =
-          GetUncachedSelectionStyle(node)) {
+  if (scoped_refptr<const ComputedStyle> pseudo_style =
+          SelectionPseudoStyle(node)) {
     if (document.InForcedColorsMode() &&
         pseudo_style->ForcedColorAdjust() != EForcedColorAdjust::kNone) {
       return LayoutTheme::GetTheme().SystemColor(CSSValueID::kHighlighttext,
@@ -100,16 +109,6 @@
                    style.UsedColorScheme());
 }
 
-const ComputedStyle* SelectionPseudoStyle(Node* node) {
-  if (!node)
-    return nullptr;
-  Element* element = Traversal<Element>::FirstAncestorOrSelf(*node);
-  if (!element)
-    return nullptr;
-  return element->CachedStyleForPseudoElement(
-      PseudoElementStyleRequest(kPseudoIdSelection));
-}
-
 }  // anonymous namespace
 
 Color SelectionPaintingUtils::SelectionBackgroundColor(
@@ -119,8 +118,8 @@
   if (node && !NodeIsSelectable(style, node))
     return Color::kTransparent;
 
-  if (scoped_refptr<ComputedStyle> pseudo_style =
-          GetUncachedSelectionStyle(node)) {
+  if (scoped_refptr<const ComputedStyle> pseudo_style =
+          SelectionPseudoStyle(node)) {
     if (document.InForcedColorsMode() &&
         pseudo_style->ForcedColorAdjust() != EForcedColorAdjust::kNone) {
       return LayoutTheme::GetTheme().SystemColor(CSSValueID::kHighlight,
@@ -211,7 +210,8 @@
           SelectionEmphasisMarkColor(document, style, node, global_paint_flags);
     }
 
-    if (const ComputedStyle* pseudo_style = SelectionPseudoStyle(node)) {
+    if (scoped_refptr<const ComputedStyle> pseudo_style =
+            SelectionPseudoStyle(node)) {
       selection_style.stroke_color =
           uses_text_as_clip ? Color::kBlack
                             : pseudo_style->VisitedDependentColor(
diff --git a/third_party/blink/renderer/core/paint/selection_painting_utils_test.cc b/third_party/blink/renderer/core/paint/selection_painting_utils_test.cc
new file mode 100644
index 0000000..ee1d61b
--- /dev/null
+++ b/third_party/blink/renderer/core/paint/selection_painting_utils_test.cc
@@ -0,0 +1,179 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "third_party/blink/renderer/core/paint/selection_painting_utils.h"
+
+#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/blink/renderer/core/dom/document.h"
+#include "third_party/blink/renderer/core/dom/node_computed_style.h"
+#include "third_party/blink/renderer/core/editing/dom_selection.h"
+#include "third_party/blink/renderer/core/frame/local_dom_window.h"
+#include "third_party/blink/renderer/core/html/forms/html_input_element.h"
+#include "third_party/blink/renderer/core/html/html_element.h"
+#include "third_party/blink/renderer/core/paint/paint_info.h"
+#include "third_party/blink/renderer/core/paint/text_paint_style.h"
+#include "third_party/blink/renderer/core/testing/sim/sim_compositor.h"
+#include "third_party/blink/renderer/core/testing/sim/sim_request.h"
+#include "third_party/blink/renderer/core/testing/sim/sim_test.h"
+
+namespace blink {
+
+class SelectionPaintingUtilsTest : public SimTest {};
+
+TEST_F(SelectionPaintingUtilsTest, CachedPseudoStylesWindowInactive) {
+  // Test that we are only caching active selection styles as so that we don't
+  // incorrectly use a cached ComputedStyle when the active state changes.
+
+  SimRequest main_resource("https://example.com/test.html", "text/html");
+
+  LoadURL("https://example.com/test.html");
+
+  main_resource.Complete(R"HTML(
+    <!doctype html>
+    <style>
+      ::selection:window-inactive {color: red }
+      ::selection { color: green }
+    </style>
+    <body>Text to select.</body>
+  )HTML");
+
+  auto* body = GetDocument().body();
+  auto* text_node = body->firstChild();
+  GlobalPaintFlags flags{0};
+
+  Compositor().BeginFrame();
+
+  const ComputedStyle& body_style = body->ComputedStyleRef();
+  const ComputedStyle& text_style = text_node->ComputedStyleRef();
+
+  EXPECT_FALSE(body_style.GetCachedPseudoElementStyle(kPseudoIdSelection));
+
+  // Select some text.
+  Window().getSelection()->setBaseAndExtent(body, 0, body, 1);
+  Compositor().BeginFrame();
+
+  // We don't cache ::selection styles for :window-inactive.
+  EXPECT_FALSE(body_style.GetCachedPseudoElementStyle(kPseudoIdSelection));
+
+  EXPECT_FALSE(GetPage().IsActive());
+  EXPECT_EQ(Color(255, 0, 0), SelectionPaintingUtils::SelectionForegroundColor(
+                                  GetDocument(), text_style, text_node, flags));
+
+  // Focus the window.
+  GetPage().SetActive(true);
+  Compositor().BeginFrame();
+  EXPECT_EQ(Color(0, 128, 0), SelectionPaintingUtils::SelectionForegroundColor(
+                                  GetDocument(), text_style, text_node, flags));
+  const ComputedStyle* active_style =
+      body_style.GetCachedPseudoElementStyle(kPseudoIdSelection);
+  EXPECT_TRUE(active_style);
+
+  // Unfocus the window.
+  GetPage().SetActive(false);
+  Compositor().BeginFrame();
+  EXPECT_EQ(Color(255, 0, 0), SelectionPaintingUtils::SelectionForegroundColor(
+                                  GetDocument(), text_style, text_node, flags));
+  EXPECT_EQ(active_style,
+            body_style.GetCachedPseudoElementStyle(kPseudoIdSelection));
+}
+
+TEST_F(SelectionPaintingUtilsTest, CachedPseudoStylesNoWindowInactive) {
+  // Test that we share a cached ComputedStyle for active and inactive
+  // selections when there are no :window-inactive styles.
+
+  SimRequest main_resource("https://example.com/test.html", "text/html");
+
+  LoadURL("https://example.com/test.html");
+
+  main_resource.Complete(R"HTML(
+    <!doctype html>
+    <style>
+      ::selection { color: green }
+    </style>
+    <body>Text to select.</body>
+  )HTML");
+
+  auto* body = GetDocument().body();
+  auto* text_node = body->firstChild();
+  GlobalPaintFlags flags{0};
+
+  Compositor().BeginFrame();
+
+  const ComputedStyle& body_style = body->ComputedStyleRef();
+  const ComputedStyle& text_style = text_node->ComputedStyleRef();
+
+  EXPECT_FALSE(body_style.GetCachedPseudoElementStyle(kPseudoIdSelection));
+
+  // Select some text.
+  Window().getSelection()->setBaseAndExtent(body, 0, body, 1);
+  Compositor().BeginFrame();
+
+  // We cache inactive ::selection styles when there are no :window-inactive
+  // selectors.
+  const ComputedStyle* active_style =
+      body_style.GetCachedPseudoElementStyle(kPseudoIdSelection);
+  EXPECT_TRUE(active_style);
+
+  EXPECT_FALSE(GetPage().IsActive());
+  EXPECT_EQ(Color(0, 128, 0), SelectionPaintingUtils::SelectionForegroundColor(
+                                  GetDocument(), text_style, text_node, flags));
+
+  // Focus the window.
+  GetPage().SetActive(true);
+  Compositor().BeginFrame();
+  EXPECT_EQ(Color(0, 128, 0), SelectionPaintingUtils::SelectionForegroundColor(
+                                  GetDocument(), text_style, text_node, flags));
+  EXPECT_EQ(active_style,
+            body_style.GetCachedPseudoElementStyle(kPseudoIdSelection));
+
+  // Unfocus the window.
+  GetPage().SetActive(false);
+  Compositor().BeginFrame();
+  EXPECT_EQ(Color(0, 128, 0), SelectionPaintingUtils::SelectionForegroundColor(
+                                  GetDocument(), text_style, text_node, flags));
+  EXPECT_EQ(active_style,
+            body_style.GetCachedPseudoElementStyle(kPseudoIdSelection));
+}
+
+TEST_F(SelectionPaintingUtilsTest, SelectedTextInputShadow) {
+  // Test that we apply input ::selection style to the value text.
+
+  SimRequest main_resource("https://example.com/test.html", "text/html");
+
+  LoadURL("https://example.com/test.html");
+
+  main_resource.Complete(R"HTML(
+    <!doctype html>
+    <style>
+      input::selection {
+        color: green;
+        text-shadow: 2px 2px;
+      }
+    </style>
+    <input type="text" value="Selected">
+  )HTML");
+
+  Compositor().BeginFrame();
+
+  auto* text_node = To<HTMLInputElement>(GetDocument().QuerySelector("input"))
+                        ->InnerEditorElement()
+                        ->firstChild();
+  const ComputedStyle& text_style = text_node->ComputedStyleRef();
+
+  std::unique_ptr<PaintController> controller{
+      std::make_unique<PaintController>()};
+  GraphicsContext context(*controller);
+  PaintInfo paint_info(context, IntRect(), PaintPhase::kForeground,
+                       kGlobalPaintNormalPhase, 0 /* paint_flags */);
+  TextPaintStyle paint_style;
+
+  paint_style = SelectionPaintingUtils::SelectionPaintingStyle(
+      GetDocument(), text_style, text_node, true /* have_selection */,
+      paint_style, paint_info);
+
+  EXPECT_EQ(Color(0, 128, 0), paint_style.fill_color);
+  EXPECT_TRUE(paint_style.shadow);
+}
+
+}  // namespace blink
diff --git a/third_party/blink/renderer/core/style/basic_shapes.cc b/third_party/blink/renderer/core/style/basic_shapes.cc
index a2abd9c..a847bfc 100644
--- a/third_party/blink/renderer/core/style/basic_shapes.cc
+++ b/third_party/blink/renderer/core/style/basic_shapes.cc
@@ -64,7 +64,9 @@
                   std::max(center.Y(), height_delta));
 }
 
-void BasicShapeCircle::GetPath(Path& path, const FloatRect& bounding_box) {
+void BasicShapeCircle::GetPath(Path& path,
+                               const FloatRect& bounding_box,
+                               float) {
   DCHECK(path.IsEmpty());
   FloatPoint center =
       FloatPointForCenterCoordinate(center_x_, center_y_, bounding_box.Size());
@@ -97,7 +99,9 @@
   return std::max(center, width_or_height_delta);
 }
 
-void BasicShapeEllipse::GetPath(Path& path, const FloatRect& bounding_box) {
+void BasicShapeEllipse::GetPath(Path& path,
+                                const FloatRect& bounding_box,
+                                float) {
   DCHECK(path.IsEmpty());
   FloatPoint center =
       FloatPointForCenterCoordinate(center_x_, center_y_, bounding_box.Size());
@@ -110,7 +114,9 @@
                             radius_x * 2, radius_y * 2));
 }
 
-void BasicShapePolygon::GetPath(Path& path, const FloatRect& bounding_box) {
+void BasicShapePolygon::GetPath(Path& path,
+                                const FloatRect& bounding_box,
+                                float) {
   DCHECK(path.IsEmpty());
   DCHECK(!(values_.size() % 2));
   wtf_size_t length = values_.size();
@@ -140,7 +146,9 @@
   return wind_rule_ == other.wind_rule_ && values_ == other.values_;
 }
 
-void BasicShapeInset::GetPath(Path& path, const FloatRect& bounding_box) {
+void BasicShapeInset::GetPath(Path& path,
+                              const FloatRect& bounding_box,
+                              float) {
   DCHECK(path.IsEmpty());
   float left = FloatValueForLength(left_, bounding_box.Width());
   float top = FloatValueForLength(top_, bounding_box.Height());
diff --git a/third_party/blink/renderer/core/style/basic_shapes.h b/third_party/blink/renderer/core/style/basic_shapes.h
index d73aa6e..c7ec083 100644
--- a/third_party/blink/renderer/core/style/basic_shapes.h
+++ b/third_party/blink/renderer/core/style/basic_shapes.h
@@ -65,7 +65,7 @@
     return GetType() == other.GetType();
   }
 
-  virtual void GetPath(Path&, const FloatRect&) = 0;
+  virtual void GetPath(Path&, const FloatRect&, float zoom) = 0;
   virtual WindRule GetWindRule() const { return RULE_NONZERO; }
   virtual bool operator==(const BasicShape&) const = 0;
 
@@ -146,7 +146,7 @@
   void SetCenterY(BasicShapeCenterCoordinate center_y) { center_y_ = center_y; }
   void SetRadius(BasicShapeRadius radius) { radius_ = radius; }
 
-  void GetPath(Path&, const FloatRect&) override;
+  void GetPath(Path&, const FloatRect&, float) override;
   bool operator==(const BasicShape&) const override;
 
   ShapeType GetType() const override { return kBasicShapeCircleType; }
@@ -185,7 +185,7 @@
   void SetRadiusX(BasicShapeRadius radius_x) { radius_x_ = radius_x; }
   void SetRadiusY(BasicShapeRadius radius_y) { radius_y_ = radius_y; }
 
-  void GetPath(Path&, const FloatRect&) override;
+  void GetPath(Path&, const FloatRect&, float) override;
   bool operator==(const BasicShape&) const override;
 
   ShapeType GetType() const override { return kBasicShapeEllipseType; }
@@ -220,7 +220,7 @@
     values_.push_back(y);
   }
 
-  void GetPath(Path&, const FloatRect&) override;
+  void GetPath(Path&, const FloatRect&, float) override;
   bool operator==(const BasicShape&) const override;
 
   WindRule GetWindRule() const override { return wind_rule_; }
@@ -273,7 +273,7 @@
     bottom_left_radius_ = radius;
   }
 
-  void GetPath(Path&, const FloatRect&) override;
+  void GetPath(Path&, const FloatRect&, float) override;
   bool operator==(const BasicShape&) const override;
 
   ShapeType GetType() const override { return kBasicShapeInsetType; }
diff --git a/third_party/blink/renderer/core/style/computed_style.h b/third_party/blink/renderer/core/style/computed_style.h
index 42e0601..a4a275c 100644
--- a/third_party/blink/renderer/core/style/computed_style.h
+++ b/third_party/blink/renderer/core/style/computed_style.h
@@ -395,7 +395,7 @@
   }
   void SetStyleType(PseudoId style_type) { SetStyleTypeInternal(style_type); }
 
-  const ComputedStyle* GetCachedPseudoElementStyle(PseudoId) const;
+  CORE_EXPORT const ComputedStyle* GetCachedPseudoElementStyle(PseudoId) const;
   const ComputedStyle* AddCachedPseudoElementStyle(
       scoped_refptr<const ComputedStyle>) const;
   void ClearCachedPseudoElementStyles() const {
diff --git a/third_party/blink/renderer/core/style/shape_clip_path_operation.h b/third_party/blink/renderer/core/style/shape_clip_path_operation.h
index 03d4c447..ae51942 100644
--- a/third_party/blink/renderer/core/style/shape_clip_path_operation.h
+++ b/third_party/blink/renderer/core/style/shape_clip_path_operation.h
@@ -45,10 +45,10 @@
 
   const BasicShape* GetBasicShape() const { return shape_.get(); }
   bool IsValid() const { return shape_.get(); }
-  Path GetPath(const FloatRect& bounding_rect) const {
+  Path GetPath(const FloatRect& bounding_rect, float zoom) const {
     DCHECK(shape_);
     Path path;
-    shape_->GetPath(path, bounding_rect);
+    shape_->GetPath(path, bounding_rect, zoom);
     path.SetWindRule(shape_->GetWindRule());
     return path;
   }
diff --git a/third_party/blink/renderer/core/style/style_aspect_ratio.h b/third_party/blink/renderer/core/style/style_aspect_ratio.h
index 607654f9..f451519 100644
--- a/third_party/blink/renderer/core/style/style_aspect_ratio.h
+++ b/third_party/blink/renderer/core/style/style_aspect_ratio.h
@@ -25,6 +25,12 @@
   EAspectRatioType GetType() const {
     if (ratio_.Width() == 0 || ratio_.Height() == 0)
       return EAspectRatioType::kAuto;
+    // Since we do calculations on LayoutUnits, also check that our width/height
+    // doesn't convert to zero.
+    if (ratio_.Width() < LayoutUnit::Epsilon() ||
+        ratio_.Height() < LayoutUnit::Epsilon()) {
+      return EAspectRatioType::kAuto;
+    }
     return GetTypeForComputedStyle();
   }
 
diff --git a/third_party/blink/renderer/core/style/style_path.cc b/third_party/blink/renderer/core/style/style_path.cc
index 41ccc527..4bcf5b2a 100644
--- a/third_party/blink/renderer/core/style/style_path.cc
+++ b/third_party/blink/renderer/core/style/style_path.cc
@@ -13,20 +13,24 @@
 #include "third_party/blink/renderer/core/svg/svg_path_utilities.h"
 #include "third_party/blink/renderer/platform/graphics/path.h"
 #include "third_party/blink/renderer/platform/heap/heap.h"
+#include "third_party/blink/renderer/platform/transforms/affine_transform.h"
 
 namespace blink {
 
-StylePath::StylePath(std::unique_ptr<SVGPathByteStream> path_byte_stream)
+StylePath::StylePath(std::unique_ptr<SVGPathByteStream> path_byte_stream,
+                     WindRule wind_rule)
     : byte_stream_(std::move(path_byte_stream)),
-      path_length_(std::numeric_limits<float>::quiet_NaN()) {
+      path_length_(std::numeric_limits<float>::quiet_NaN()),
+      wind_rule_(wind_rule) {
   DCHECK(byte_stream_);
 }
 
 StylePath::~StylePath() = default;
 
 scoped_refptr<StylePath> StylePath::Create(
-    std::unique_ptr<SVGPathByteStream> path_byte_stream) {
-  return base::AdoptRef(new StylePath(std::move(path_byte_stream)));
+    std::unique_ptr<SVGPathByteStream> path_byte_stream,
+    WindRule wind_rule) {
+  return base::AdoptRef(new StylePath(std::move(path_byte_stream), wind_rule));
 }
 
 const StylePath* StylePath::EmptyPath() {
@@ -62,12 +66,13 @@
   if (!IsSameType(o))
     return false;
   const StylePath& other = To<StylePath>(o);
-  return *byte_stream_ == *other.byte_stream_;
+  return wind_rule_ == other.wind_rule_ && *byte_stream_ == *other.byte_stream_;
 }
 
-void StylePath::GetPath(Path&, const FloatRect&) {
-  // Callers should use GetPath() overload, which avoids making a copy.
-  NOTREACHED();
+void StylePath::GetPath(Path& path, const FloatRect& offset_rect, float zoom) {
+  path = GetPath();
+  path.Transform(AffineTransform::Translation(offset_rect.X(), offset_rect.Y())
+                     .Scale(zoom));
 }
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/style/style_path.h b/third_party/blink/renderer/core/style/style_path.h
index b25f308..52d7b300 100644
--- a/third_party/blink/renderer/core/style/style_path.h
+++ b/third_party/blink/renderer/core/style/style_path.h
@@ -18,7 +18,8 @@
 
 class StylePath final : public BasicShape {
  public:
-  static scoped_refptr<StylePath> Create(std::unique_ptr<SVGPathByteStream>);
+  static scoped_refptr<StylePath> Create(std::unique_ptr<SVGPathByteStream>,
+                                         WindRule wind_rule = RULE_NONZERO);
   ~StylePath() override;
 
   static const StylePath* EmptyPath();
@@ -31,17 +32,20 @@
 
   CSSValue* ComputedCSSValue() const;
 
-  void GetPath(Path&, const FloatRect&) override;
+  void GetPath(Path&, const FloatRect&, float zoom) override;
+  WindRule GetWindRule() const override { return wind_rule_; }
+
   bool operator==(const BasicShape&) const override;
 
   ShapeType GetType() const override { return kStylePathType; }
 
  private:
-  explicit StylePath(std::unique_ptr<SVGPathByteStream>);
+  explicit StylePath(std::unique_ptr<SVGPathByteStream>, WindRule wind_rule);
 
   std::unique_ptr<SVGPathByteStream> byte_stream_;
   mutable std::unique_ptr<Path> path_;
   mutable float path_length_;
+  WindRule wind_rule_;
 };
 
 template <>
diff --git a/third_party/blink/renderer/core/style/style_ray.cc b/third_party/blink/renderer/core/style/style_ray.cc
index 3d6b5d6a..b8dc0fa 100644
--- a/third_party/blink/renderer/core/style/style_ray.cc
+++ b/third_party/blink/renderer/core/style/style_ray.cc
@@ -25,7 +25,7 @@
          contain_ == other.contain_;
 }
 
-void StyleRay::GetPath(Path&, const FloatRect&) {
+void StyleRay::GetPath(Path&, const FloatRect&, float) {
   // ComputedStyle::ApplyMotionPathTransform cannot call GetPath
   // for rays as they may have infinite length.
   NOTREACHED();
diff --git a/third_party/blink/renderer/core/style/style_ray.h b/third_party/blink/renderer/core/style/style_ray.h
index 636b4d6..7e3dd53 100644
--- a/third_party/blink/renderer/core/style/style_ray.h
+++ b/third_party/blink/renderer/core/style/style_ray.h
@@ -27,7 +27,7 @@
   RaySize Size() const { return size_; }
   bool Contain() const { return contain_; }
 
-  void GetPath(Path&, const FloatRect&) override;
+  void GetPath(Path&, const FloatRect&, float) override;
   bool operator==(const BasicShape&) const override;
 
   ShapeType GetType() const override { return kStyleRayType; }
diff --git a/third_party/blink/renderer/core/testing/sim/sim_page.cc b/third_party/blink/renderer/core/testing/sim/sim_page.cc
index cf6da0a0d..13fdfeb79 100644
--- a/third_party/blink/renderer/core/testing/sim/sim_page.cc
+++ b/third_party/blink/renderer/core/testing/sim/sim_page.cc
@@ -25,4 +25,12 @@
   return page_->GetFocusController().IsFocused();
 }
 
+void SimPage::SetActive(bool value) {
+  page_->GetFocusController().SetActive(value);
+}
+
+bool SimPage::IsActive() const {
+  return page_->GetFocusController().IsActive();
+}
+
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/testing/sim/sim_page.h b/third_party/blink/renderer/core/testing/sim/sim_page.h
index efd9c0e..b29aa6f 100644
--- a/third_party/blink/renderer/core/testing/sim/sim_page.h
+++ b/third_party/blink/renderer/core/testing/sim/sim_page.h
@@ -22,6 +22,9 @@
   void SetFocused(bool);
   bool IsFocused() const;
 
+  void SetActive(bool);
+  bool IsActive() const;
+
  private:
   Persistent<Page> page_;
 };
diff --git a/third_party/blink/renderer/modules/accessibility/ax_object.cc b/third_party/blink/renderer/modules/accessibility/ax_object.cc
index dfa72dcc..6e60ddd 100644
--- a/third_party/blink/renderer/modules/accessibility/ax_object.cc
+++ b/third_party/blink/renderer/modules/accessibility/ax_object.cc
@@ -67,6 +67,7 @@
 #include "third_party/blink/renderer/modules/accessibility/ax_menu_list_popup.h"
 #include "third_party/blink/renderer/modules/accessibility/ax_object_cache_impl.h"
 #include "third_party/blink/renderer/modules/accessibility/ax_range.h"
+#include "third_party/blink/renderer/modules/accessibility/ax_selection.h"
 #include "third_party/blink/renderer/modules/accessibility/ax_sparse_attribute_setter.h"
 #include "third_party/blink/renderer/platform/instrumentation/tracing/trace_event.h"
 #include "third_party/blink/renderer/platform/language.h"
@@ -949,6 +950,33 @@
                                       GetEquivalentAriaRoleString(RoleValue()));
       }
     }
+
+    if (IsEditable()) {
+      if (IsEditableRoot()) {
+        node_data->AddBoolAttribute(
+            ax::mojom::blink::BoolAttribute::kEditableRoot, true);
+      }
+
+      if (IsNativeTextControl()) {
+        // Selection offsets are only used for plain text controls, (input of a
+        // text field type, and textarea). Rich editable areas, such as
+        // contenteditables, use AXTreeData.
+        //
+        // TODO(nektar): Remove kTextSelStart and kTextSelEnd from the renderer.
+        const auto ax_selection =
+            AXSelection::FromCurrentSelection(ToTextControl(*element));
+        int start = ax_selection.Base().IsTextPosition()
+                        ? ax_selection.Base().TextOffset()
+                        : ax_selection.Base().ChildIndex();
+        int end = ax_selection.Extent().IsTextPosition()
+                      ? ax_selection.Extent().TextOffset()
+                      : ax_selection.Extent().ChildIndex();
+        node_data->AddIntAttribute(
+            ax::mojom::blink::IntAttribute::kTextSelStart, start);
+        node_data->AddIntAttribute(ax::mojom::blink::IntAttribute::kTextSelEnd,
+                                   end);
+      }
+    }
   }
 }
 
diff --git a/third_party/blink/renderer/modules/exported/web_ax_object.cc b/third_party/blink/renderer/modules/exported/web_ax_object.cc
index f343fa4..eeb6fcba 100644
--- a/third_party/blink/renderer/modules/exported/web_ax_object.cc
+++ b/third_party/blink/renderer/modules/exported/web_ax_object.cc
@@ -454,13 +454,6 @@
   return private_->IsEditable();
 }
 
-bool WebAXObject::IsEditableRoot() const {
-  if (IsDetached())
-    return false;
-
-  return private_->IsEditableRoot();
-}
-
 int WebAXObject::PosInSet() const {
   if (IsDetached())
     return 0;
@@ -889,48 +882,6 @@
   return ax_selection.Select();
 }
 
-unsigned WebAXObject::SelectionEnd() const {
-  if (IsDetached() || GetDocument().IsNull())
-    return 0;
-
-  WebAXObject focus = FromWebDocumentFocused(GetDocument(), false);
-  if (focus.IsDetached())
-    return 0;
-
-  const auto ax_selection =
-      focus.private_->IsNativeTextControl()
-          ? AXSelection::FromCurrentSelection(
-                ToTextControl(*focus.private_->GetNode()))
-          : AXSelection::FromCurrentSelection(*focus.private_->GetDocument());
-  if (!ax_selection)
-    return 0;
-
-  if (ax_selection.Extent().IsTextPosition())
-    return ax_selection.Extent().TextOffset();
-  return ax_selection.Extent().ChildIndex();
-}
-
-unsigned WebAXObject::SelectionStart() const {
-  if (IsDetached() || GetDocument().IsNull())
-    return 0;
-
-  WebAXObject focus = FromWebDocumentFocused(GetDocument(), false);
-  if (focus.IsDetached())
-    return 0;
-
-  const auto ax_selection =
-      focus.private_->IsNativeTextControl()
-          ? AXSelection::FromCurrentSelection(
-                ToTextControl(*focus.private_->GetNode()))
-          : AXSelection::FromCurrentSelection(*focus.private_->GetDocument());
-  if (!ax_selection)
-    return 0;
-
-  if (ax_selection.Base().IsTextPosition())
-    return ax_selection.Base().TextOffset();
-  return ax_selection.Base().ChildIndex();
-}
-
 bool WebAXObject::Focus() const {
   if (IsDetached())
     return false;
diff --git a/third_party/blink/renderer/modules/service_worker/service_worker_event_queue.cc b/third_party/blink/renderer/modules/service_worker/service_worker_event_queue.cc
index 85e31311..21e6bbc 100644
--- a/third_party/blink/renderer/modules/service_worker/service_worker_event_queue.cc
+++ b/third_party/blink/renderer/modules/service_worker/service_worker_event_queue.cc
@@ -4,7 +4,6 @@
 
 #include "third_party/blink/renderer/modules/service_worker/service_worker_event_queue.h"
 
-#include "base/atomic_sequence_num.h"
 #include "base/bind.h"
 #include "base/stl_util.h"
 #include "base/time/default_tick_clock.h"
@@ -14,19 +13,6 @@
 
 namespace blink {
 
-namespace {
-
-int NextEventId() {
-  // Event id should not start from zero since HashMap in Blink requires
-  // non-zero keys.
-  static base::AtomicSequenceNumber s_event_id_sequence;
-  int next_event_id = s_event_id_sequence.GetNext() + 1;
-  CHECK_LT(next_event_id, std::numeric_limits<int>::max());
-  return next_event_id;
-}
-
-}  // namespace
-
 // static
 constexpr base::TimeDelta ServiceWorkerEventQueue::kEventTimeout;
 constexpr base::TimeDelta ServiceWorkerEventQueue::kUpdateInterval;
@@ -71,9 +57,8 @@
       tick_clock_(tick_clock) {}
 
 ServiceWorkerEventQueue::~ServiceWorkerEventQueue() {
-  in_dtor_ = true;
   // Abort all callbacks.
-  for (auto& event : id_event_map_) {
+  for (auto& event : all_events_) {
     std::move(event.value->abort_callback)
         .Run(blink::mojom::ServiceWorkerEventStatus::ABORTED);
   }
@@ -91,45 +76,79 @@
 }
 
 void ServiceWorkerEventQueue::EnqueueNormal(
+    int event_id,
     StartCallback start_callback,
     AbortCallback abort_callback,
     base::Optional<base::TimeDelta> custom_timeout) {
   EnqueueEvent(std::make_unique<Event>(
-      Event::Type::Normal, std::move(start_callback), std::move(abort_callback),
-      std::move(custom_timeout)));
+      event_id, Event::Type::Normal, std::move(start_callback),
+      std::move(abort_callback), std::move(custom_timeout)));
 }
 
 void ServiceWorkerEventQueue::EnqueuePending(
+    int event_id,
     StartCallback start_callback,
     AbortCallback abort_callback,
     base::Optional<base::TimeDelta> custom_timeout) {
   EnqueueEvent(std::make_unique<Event>(
-      Event::Type::Pending, std::move(start_callback),
+      event_id, Event::Type::Pending, std::move(start_callback),
       std::move(abort_callback), std::move(custom_timeout)));
 }
 
 void ServiceWorkerEventQueue::EnqueueOffline(
+    int event_id,
     StartCallback start_callback,
     AbortCallback abort_callback,
     base::Optional<base::TimeDelta> custom_timeout) {
   EnqueueEvent(std::make_unique<ServiceWorkerEventQueue::Event>(
-      ServiceWorkerEventQueue::Event::Type::Offline, std::move(start_callback),
-      std::move(abort_callback), std::move(custom_timeout)));
+      event_id, ServiceWorkerEventQueue::Event::Type::Offline,
+      std::move(start_callback), std::move(abort_callback),
+      std::move(custom_timeout)));
 }
 
 bool ServiceWorkerEventQueue::CanStartEvent(const Event& event) const {
-  if (!HasInflightEvent())
+  if (running_event_type_ == RunningEventType::kNone) {
+    DCHECK(!HasInflightEvent());
     return true;
+  }
   if (event.type == Event::Type::Offline)
-    return running_offline_events_;
-  return !running_offline_events_;
+    return running_event_type_ == RunningEventType::kOffline;
+  return running_event_type_ == RunningEventType::kOnline;
+}
+
+std::map<int, std::unique_ptr<ServiceWorkerEventQueue::Event>>&
+ServiceWorkerEventQueue::GetActiveEventQueue() {
+  if (running_event_type_ == RunningEventType::kNone) {
+    // Either online events or offline events can be started when inflight
+    // events don't exist. If online events exist in the queue, prioritize
+    // online events.
+    return queued_online_events_.empty() ? queued_offline_events_
+                                         : queued_online_events_;
+  }
+  if (running_event_type_ == RunningEventType::kOffline)
+    return queued_offline_events_;
+  return queued_online_events_;
 }
 
 void ServiceWorkerEventQueue::EnqueueEvent(std::unique_ptr<Event> event) {
   DCHECK(event->type != Event::Type::Pending || did_idle_timeout());
+  DCHECK(!HasEvent(event->event_id));
+  DCHECK(!HasEventInQueue(event->event_id));
+
   bool can_start_processing_events =
       !processing_events_ && event->type != Event::Type::Pending;
-  queue_.emplace_back(std::move(event));
+
+  // Start counting the timer when an event is enqueued.
+  all_events_.insert(
+      event->event_id,
+      std::make_unique<EventInfo>(
+          tick_clock_->NowTicks() +
+              event->custom_timeout.value_or(kEventTimeout),
+          WTF::Bind(std::move(event->abort_callback), event->event_id)));
+
+  auto& queue = event->type == Event::Type::Offline ? queued_offline_events_
+                                                    : queued_online_events_;
+  queue.emplace(event->event_id, std::move(event));
 
   if (!can_start_processing_events)
     return;
@@ -141,8 +160,12 @@
 void ServiceWorkerEventQueue::ProcessEvents() {
   DCHECK(!processing_events_);
   processing_events_ = true;
-  while (!queue_.IsEmpty() && CanStartEvent(*queue_.front())) {
-    StartEvent(queue_.TakeFirst());
+  auto& queue = GetActiveEventQueue();
+  while (!queue.empty() && CanStartEvent(*queue.begin()->second)) {
+    int event_id = queue.begin()->first;
+    std::unique_ptr<Event> event = std::move(queue.begin()->second);
+    queue.erase(queue.begin());
+    StartEvent(event_id, std::move(event));
   }
   processing_events_ = false;
 
@@ -154,16 +177,12 @@
     OnNoInflightEvent();
 }
 
-void ServiceWorkerEventQueue::StartEvent(std::unique_ptr<Event> event) {
-  DCHECK(CanStartEvent(*event));
-  running_offline_events_ = event->type == Event::Type::Offline;
-  const int event_id = NextEventId();
-  DCHECK(!HasEvent(event_id));
-  id_event_map_.insert(
-      event_id, std::make_unique<EventInfo>(
-                    tick_clock_->NowTicks() +
-                        event->custom_timeout.value_or(kEventTimeout),
-                    WTF::Bind(std::move(event->abort_callback), event_id)));
+void ServiceWorkerEventQueue::StartEvent(int event_id,
+                                         std::unique_ptr<Event> event) {
+  DCHECK(HasEvent(event_id));
+  running_event_type_ = event->type == Event::Type::Offline
+                            ? RunningEventType::kOffline
+                            : RunningEventType::kOnline;
   if (before_start_event_callback_)
     before_start_event_callback_.Run(event->type == Event::Type::Offline);
   std::move(event->start_callback).Run(event_id);
@@ -171,7 +190,7 @@
 
 void ServiceWorkerEventQueue::EndEvent(int event_id) {
   DCHECK(HasEvent(event_id));
-  id_event_map_.erase(event_id);
+  all_events_.erase(event_id);
   // Check |processing_events_| here because EndEvent() can be called
   // synchronously in StartEvent(). We don't want to trigger
   // OnNoInflightEvent() while ProcessEvents() is running.
@@ -180,7 +199,12 @@
 }
 
 bool ServiceWorkerEventQueue::HasEvent(int event_id) const {
-  return id_event_map_.find(event_id) != id_event_map_.end();
+  return all_events_.find(event_id) != all_events_.end();
+}
+
+bool ServiceWorkerEventQueue::HasEventInQueue(int event_id) const {
+  return (base::Contains(queued_online_events_, event_id) ||
+          base::Contains(queued_offline_events_, event_id));
 }
 
 std::unique_ptr<ServiceWorkerEventQueue::StayAwakeToken>
@@ -226,21 +250,36 @@
 void ServiceWorkerEventQueue::UpdateStatus() {
   base::TimeTicks now = tick_clock_->NowTicks();
 
-  HashMap<int /* event_id */, std::unique_ptr<EventInfo>> new_id_event_map;
+  // Construct a new map because WTF::HashMap doesn't support deleting elements
+  // while iterating.
+  HashMap<int /* event_id */, std::unique_ptr<EventInfo>> new_all_events;
 
   bool should_idle_delay_to_be_zero = false;
-  // Abort all events exceeding |kEventTimeout|.
-  for (auto& it : id_event_map_) {
-    auto& event_info = it.value;
+
+  // Time out all events exceeding `kEventTimeout`.
+  for (auto& it : all_events_) {
+    // Check if the event has timed out.
+    int event_id = it.key;
+    std::unique_ptr<EventInfo>& event_info = it.value;
     if (event_info->expiration_time > now) {
-      new_id_event_map.insert(it.key, std::move(event_info));
+      new_all_events.insert(event_id, std::move(event_info));
       continue;
     }
+
+    // The event may still be in one of the queues when it timed out. Try to
+    // remove the event from both.
+    queued_online_events_.erase(event_id);
+    queued_offline_events_.erase(event_id);
+
+    // Run the abort callback.
     std::move(event_info->abort_callback)
         .Run(blink::mojom::ServiceWorkerEventStatus::TIMEOUT);
+
     should_idle_delay_to_be_zero = true;
   }
-  id_event_map_.swap(new_id_event_map);
+  all_events_.swap(new_all_events);
+
+  // Set idle delay to zero if needed.
   if (should_idle_delay_to_be_zero) {
     // Inflight events might be timed out and there might be no inflight event
     // at this point.
@@ -277,10 +316,11 @@
 
 void ServiceWorkerEventQueue::OnNoInflightEvent() {
   DCHECK(!HasInflightEvent());
-  running_offline_events_ = false;
+  running_event_type_ = RunningEventType::kNone;
   // There might be events in the queue because offline (or non-offline) events
   // can be enqueued during running non-offline (or offline) events.
-  if (!queue_.IsEmpty()) {
+  auto& queue = GetActiveEventQueue();
+  if (!queue.empty()) {
     ProcessEvents();
     return;
   }
@@ -289,7 +329,11 @@
 }
 
 bool ServiceWorkerEventQueue::HasInflightEvent() const {
-  return !id_event_map_.IsEmpty() || num_of_stay_awake_tokens_ > 0;
+  size_t num_queued_events =
+      queued_online_events_.size() + queued_offline_events_.size();
+  DCHECK_LE(num_queued_events, all_events_.size());
+  return all_events_.size() - num_queued_events > 0 ||
+         num_of_stay_awake_tokens_ > 0;
 }
 
 void ServiceWorkerEventQueue::ResetIdleTimeout() {
@@ -302,12 +346,19 @@
   return idle_callback_handle_.IsActive();
 }
 
+int ServiceWorkerEventQueue::NextEventId() {
+  CHECK_LT(next_event_id_, std::numeric_limits<int>::max());
+  return next_event_id_++;
+}
+
 ServiceWorkerEventQueue::Event::Event(
+    int event_id,
     ServiceWorkerEventQueue::Event::Type type,
     StartCallback start_callback,
     AbortCallback abort_callback,
     base::Optional<base::TimeDelta> custom_timeout)
-    : type(type),
+    : event_id(event_id),
+      type(type),
       start_callback(std::move(start_callback)),
       abort_callback(std::move(abort_callback)),
       custom_timeout(custom_timeout) {}
diff --git a/third_party/blink/renderer/modules/service_worker/service_worker_event_queue.h b/third_party/blink/renderer/modules/service_worker/service_worker_event_queue.h
index 5557cf7..9b7eb00 100644
--- a/third_party/blink/renderer/modules/service_worker/service_worker_event_queue.h
+++ b/third_party/blink/renderer/modules/service_worker/service_worker_event_queue.h
@@ -90,23 +90,29 @@
 
   // Enqueues a Normal event. See ServiceWorkerEventQueue::Event to know the
   // meaning of each parameter.
-  void EnqueueNormal(StartCallback start_callback,
+  void EnqueueNormal(int event_id,
+                     StartCallback start_callback,
                      AbortCallback abort_callback,
                      base::Optional<base::TimeDelta> custom_timeout);
 
   // Similar to EnqueueNormal(), but enqueues a Pending event.
-  void EnqueuePending(StartCallback start_callback,
+  void EnqueuePending(int event_id,
+                      StartCallback start_callback,
                       AbortCallback abort_callback,
                       base::Optional<base::TimeDelta> custom_timeout);
 
   // Similar to EnqueueNormal(), but enqueues an Offline event.
-  void EnqueueOffline(StartCallback start_callback,
+  void EnqueueOffline(int event_id,
+                      StartCallback start_callback,
                       AbortCallback abort_callback,
                       base::Optional<base::TimeDelta> custom_timeout);
 
-  // Returns true if |event_id| was started and hasn't ended.
+  // Returns true if |event_id| was enqueued and hasn't ended.
   bool HasEvent(int event_id) const;
 
+  // Returns true if |event_id| was enqueued and hasn't started.
+  bool HasEventInQueue(int event_id) const;
+
   // Creates a StayAwakeToken to ensure that the idle callback won't be
   // triggered while any of these are alive.
   std::unique_ptr<StayAwakeToken> CreateStayAwakeToken();
@@ -121,6 +127,9 @@
   // false again when StartEvent() is called.
   bool did_idle_timeout() const { return did_idle_timeout_; }
 
+  // Returns the next event id, which is a monotonically increasing number.
+  int NextEventId();
+
   // Duration of the long standing event timeout since StartEvent() has been
   // called.
   static constexpr base::TimeDelta kEventTimeout =
@@ -128,7 +137,7 @@
   // ServiceWorkerEventQueue periodically updates the timeout state by
   // kUpdateInterval.
   static constexpr base::TimeDelta kUpdateInterval =
-      base::TimeDelta::FromSeconds(30);
+      base::TimeDelta::FromSeconds(10);
 
  private:
   // Represents an event dispatch, which can be queued into |queue_|.
@@ -153,11 +162,13 @@
       Offline,
     };
 
-    Event(Type type,
+    Event(int event_id,
+          Type type,
           StartCallback start_callback,
           AbortCallback abort_callback,
           base::Optional<base::TimeDelta> custom_timeout);
     ~Event();
+    const int event_id;
     Type type;
     // Callback which is run when the event queue starts this event. The
     // callback receives |event_id|. When an event finishes,
@@ -169,6 +180,13 @@
     base::Optional<base::TimeDelta> custom_timeout;
   };
 
+  // Represents the type of the currently running events.
+  enum class RunningEventType {
+    kNone = 0,
+    kOnline,
+    kOffline,
+  };
+
   // Enqueues the event to |queue_|, and run events in the queue or sometimes
   // later synchronously, depending on the type of events.
   void EnqueueEvent(std::unique_ptr<Event> event);
@@ -177,7 +195,7 @@
   bool CanStartEvent(const Event& event) const;
 
   // Starts a single event.
-  void StartEvent(std::unique_ptr<Event> event);
+  void StartEvent(int event_id, std::unique_ptr<Event> event);
 
   // Updates the internal states and fires the event timeout callbacks if any.
   // TODO(shimazu): re-implement it by delayed tasks and cancelable callbacks.
@@ -205,6 +223,10 @@
   // True if the idle callback is scheduled to run.
   bool HasScheduledIdleCallback() const;
 
+  // Returns either of `queued_online_events_` or `queued_offline_events_` to be
+  // executed depending on the currently running event type.
+  std::map<int, std::unique_ptr<Event>>& GetActiveEventQueue();
+
   struct EventInfo {
     EventInfo(base::TimeTicks expiration_time,
               base::OnceCallback<void(mojom::blink::ServiceWorkerEventStatus)>
@@ -219,7 +241,7 @@
 
   // For long standing event timeouts. This is used to look up an EventInfo
   // by event id.
-  HashMap<int /* event_id */, std::unique_ptr<EventInfo>> id_event_map_;
+  HashMap<int /* event_id */, std::unique_ptr<EventInfo>> all_events_;
 
   // Callback which is run just before starting an event.
   BeforeStartEventCallback before_start_event_callback_;
@@ -245,16 +267,24 @@
   // StartEvent() is called.
   bool did_idle_timeout_ = false;
 
-  // Event queue to where all events are enqueued.
-  Deque<std::unique_ptr<Event>> queue_;
+  // Event queue to where all online events (normal and pending events) are
+  // enqueued. We use std::map as a task queue because it's ordered by the
+  // `event_id` and the entries can be effectively erased in random order.
+  std::map<int /* event_id */, std::unique_ptr<Event>> queued_online_events_;
+
+  // Event queue to where offline events are enqueued. We use std::map as a task
+  // queue because it's ordered by the `event_id` and the entries can be
+  // effectively erased in random order.
+  std::map<int /* event_id */, std::unique_ptr<Event>> queued_offline_events_;
 
   // Set to true during running ProcessEvents(). This is used for avoiding to
   // invoke |idle_callback_| or to re-enter ProcessEvents() when calling
   // ProcessEvents().
   bool processing_events_ = false;
 
-  // Set to true during running offline events.
-  bool running_offline_events_ = false;
+  // Type of the currently running events. kNone if inflight events do not
+  // exist.
+  RunningEventType running_event_type_ = RunningEventType::kNone;
 
   // The number of the living StayAwakeToken. See also class comments.
   int num_of_stay_awake_tokens_ = 0;
@@ -265,7 +295,9 @@
   // |tick_clock_| outlives |this|.
   const base::TickClock* const tick_clock_;
 
-  bool in_dtor_ = false;
+  // Monotonically increasing number. Event id should not start from zero since
+  // HashMap in Blink requires non-zero keys.
+  int next_event_id_ = 1;
 
   base::WeakPtrFactory<ServiceWorkerEventQueue> weak_factory_{this};
 };
diff --git a/third_party/blink/renderer/modules/service_worker/service_worker_event_queue_test.cc b/third_party/blink/renderer/modules/service_worker/service_worker_event_queue_test.cc
index fafe57a..b3b4fa1 100644
--- a/third_party/blink/renderer/modules/service_worker/service_worker_event_queue_test.cc
+++ b/third_party/blink/renderer/modules/service_worker/service_worker_event_queue_test.cc
@@ -30,41 +30,56 @@
     return status_;
   }
 
-  bool Started() const { return event_id_.has_value(); }
+  bool Started() const { return started_; }
 
   void EnqueueTo(ServiceWorkerEventQueue* event_queue) {
+    event_id_ = event_queue->NextEventId();
     event_queue->EnqueueNormal(
-        WTF::Bind(&MockEvent::Start, weak_factory_.GetWeakPtr()),
+        *event_id_, WTF::Bind(&MockEvent::Start, weak_factory_.GetWeakPtr()),
         WTF::Bind(&MockEvent::Abort, weak_factory_.GetWeakPtr()),
         base::nullopt);
   }
 
   void EnqueuePendingTo(ServiceWorkerEventQueue* event_queue) {
+    event_id_ = event_queue->NextEventId();
     event_queue->EnqueuePending(
-        WTF::Bind(&MockEvent::Start, weak_factory_.GetWeakPtr()),
+        *event_id_, WTF::Bind(&MockEvent::Start, weak_factory_.GetWeakPtr()),
         WTF::Bind(&MockEvent::Abort, weak_factory_.GetWeakPtr()),
         base::nullopt);
   }
 
   void EnqueueWithCustomTimeoutTo(ServiceWorkerEventQueue* event_queue,
                                   base::TimeDelta custom_timeout) {
+    event_id_ = event_queue->NextEventId();
     event_queue->EnqueueNormal(
-        WTF::Bind(&MockEvent::Start, weak_factory_.GetWeakPtr()),
+        *event_id_, WTF::Bind(&MockEvent::Start, weak_factory_.GetWeakPtr()),
         WTF::Bind(&MockEvent::Abort, weak_factory_.GetWeakPtr()),
         custom_timeout);
   }
 
   void EnqueueOfflineTo(ServiceWorkerEventQueue* event_queue) {
+    event_id_ = event_queue->NextEventId();
     event_queue->EnqueueOffline(
-        WTF::Bind(&MockEvent::Start, weak_factory_.GetWeakPtr()),
+        *event_id_, WTF::Bind(&MockEvent::Start, weak_factory_.GetWeakPtr()),
         WTF::Bind(&MockEvent::Abort, weak_factory_.GetWeakPtr()),
         base::nullopt);
   }
 
+  void EnqueueOfflineWithCustomTimeoutTo(ServiceWorkerEventQueue* event_queue,
+                                         base::TimeDelta custom_timeout) {
+    event_id_ = event_queue->NextEventId();
+    event_queue->EnqueueOffline(
+        *event_id_, WTF::Bind(&MockEvent::Start, weak_factory_.GetWeakPtr()),
+        WTF::Bind(&MockEvent::Abort, weak_factory_.GetWeakPtr()),
+        custom_timeout);
+  }
+
   void EnqueuePendingDispatchingEventTo(ServiceWorkerEventQueue* event_queue,
                                         String tag,
                                         Vector<String>* out_tags) {
+    event_id_ = event_queue->NextEventId();
     event_queue->EnqueuePending(
+        *event_id_,
         WTF::Bind(
             [](ServiceWorkerEventQueue* event_queue, MockEvent* event,
                String tag, Vector<String>* out_tags, int /* event id */) {
@@ -84,7 +99,8 @@
  private:
   void Start(int event_id) {
     EXPECT_FALSE(Started());
-    event_id_ = event_id;
+    EXPECT_EQ(event_id_, event_id);
+    started_ = true;
   }
 
   void Abort(int event_id, mojom::blink::ServiceWorkerEventStatus status) {
@@ -95,6 +111,7 @@
 
   base::Optional<int> event_id_;
   base::Optional<mojom::blink::ServiceWorkerEventStatus> status_;
+  bool started_ = false;
   base::WeakPtrFactory<MockEvent> weak_factory_{this};
 };
 
@@ -351,11 +368,37 @@
   pending_event.EnqueuePendingTo(&event_queue);
   EXPECT_FALSE(pending_event.Started());
 
-  // Start a new event. PushTask() should run the pending tasks.
+  // Start a new event. EnqueueEvent() should run the pending tasks.
   MockEvent event;
   event.EnqueueTo(&event_queue);
   EXPECT_FALSE(event_queue.did_idle_timeout());
   EXPECT_TRUE(pending_event.Started());
+  EXPECT_TRUE(event.Started());
+}
+
+TEST_F(ServiceWorkerEventQueueTest, PushPendingTaskWithOfflineEvent) {
+  ServiceWorkerEventQueue event_queue(base::DoNothing(), base::DoNothing(),
+                                      task_runner(),
+                                      task_runner()->GetMockTickClock());
+  event_queue.Start();
+  task_runner()->FastForwardBy(base::TimeDelta::FromSeconds(
+      mojom::blink::kServiceWorkerDefaultIdleDelayInSeconds));
+  EXPECT_TRUE(event_queue.did_idle_timeout());
+
+  MockEvent pending_event;
+  pending_event.EnqueuePendingTo(&event_queue);
+  EXPECT_FALSE(pending_event.Started());
+
+  // Start a new event. EnqueueEvent() should run the pending tasks.
+  MockEvent offline_event;
+  offline_event.EnqueueOfflineTo(&event_queue);
+  EXPECT_FALSE(event_queue.did_idle_timeout());
+  EXPECT_TRUE(pending_event.Started());
+  EXPECT_FALSE(offline_event.Started());
+
+  // EndEvent() should start the offline tasks.
+  event_queue.EndEvent(pending_event.event_id());
+  EXPECT_TRUE(offline_event.Started());
 }
 
 // Test that pending tasks are run when StartEvent() is called while there the
@@ -375,7 +418,7 @@
   event2.EnqueuePendingDispatchingEventTo(&event_queue, "2", &handled_tasks);
   EXPECT_TRUE(handled_tasks.IsEmpty());
 
-  // Start a new event. PushTask() should run the pending tasks.
+  // Start a new event. EnqueueEvent() should run the pending tasks.
   MockEvent event;
   event.EnqueueTo(&event_queue);
   EXPECT_FALSE(event_queue.did_idle_timeout());
@@ -474,7 +517,7 @@
   }
 }
 
-TEST_F(ServiceWorkerEventQueueTest, EnqueuOffline) {
+TEST_F(ServiceWorkerEventQueueTest, EnqueueOffline) {
   ServiceWorkerEventQueue event_queue(base::DoNothing(), base::DoNothing(),
                                       task_runner(),
                                       task_runner()->GetMockTickClock());
@@ -517,50 +560,67 @@
 
   MockEvent event_5;
   event_5.EnqueueTo(&event_queue);
-  // |event_queue| should not start a normal |event_5| because an offline event
-  // is already enqueued.
+  // |event_queue| starts a normal |event_5| because the type of |event_5| is
+  // the same as the events currently running.
   //
   // State:
-  // - inflight_events: {1 (normal), 2 (normal)}
-  // - queue: [3 (offline), 4 (offline), 5 (normal)]
+  // - inflight_events: {1 (normal), 2 (normal), 5 (normal)}
+  // - queue: [3 (offline), 4 (offline)]
   EXPECT_FALSE(event_3.Started());
   EXPECT_FALSE(event_4.Started());
-  EXPECT_FALSE(event_5.Started());
+  EXPECT_TRUE(event_5.Started());
 
   event_queue.EndEvent(event_1.event_id());
-  // |event_1| is finished, but there ia still an inflight event, |event_2|.
+  // |event_1| is finished, but there are still inflight events, |event_2| and
+  // |event_5|. Events in the queue are not processed.
+  //
+  // State:
+  // - inflight_events: {2 (normal), 5 (normal)}
+  // - queue: [3 (offline), 4 (offline)]
+  EXPECT_FALSE(event_3.Started());
+  EXPECT_FALSE(event_4.Started());
+  EXPECT_TRUE(event_5.Started());
+
+  event_queue.EndEvent(event_2.event_id());
+  // |event_2| is finished, but there is still an inflight event, |event_5|.
   // Events in the queue are not processed.
   //
   // State:
-  // - inflight_events: {2 (normal)}
-  // - queue: [3 (offline), 4 (offline), 5 (normal)]
+  // - inflight_events: {5 (normal)}
+  // - queue: [3 (offline), 4 (offline)]
   EXPECT_FALSE(event_3.Started());
   EXPECT_FALSE(event_4.Started());
-  EXPECT_FALSE(event_5.Started());
+  EXPECT_TRUE(event_5.Started());
 
-  event_queue.EndEvent(event_2.event_id());
+  event_queue.EndEvent(event_5.event_id());
   // All inflight events are finished. |event_queue| starts processing
-  // events in the queue. As a result, |event_3| and |event_4| are started, but
-  // |event_5| are not.
+  // events in the queue. As a result, |event_3| and |event_4| are started.
   //
   // State:
   // - inflight_events: {3 (offline), 4 (offline)}
-  // - queue: [5 (normal)]
+  // - queue: []
   EXPECT_TRUE(event_3.Started());
   EXPECT_TRUE(event_4.Started());
-  EXPECT_FALSE(event_5.Started());
+
+  MockEvent event_6;
+  event_6.EnqueueTo(&event_queue);
+  // If an inflight offline event exists, a normal event in the queue is not
+  // processed.
+  //
+  // State:
+  // - inflight_events: {3 (offline), 4 (offline)}
+  // - queue: [6 (normal)]
+  EXPECT_FALSE(event_6.Started());
 
   event_queue.EndEvent(event_3.event_id());
-  // State:
-  // - inflight_events: {4 (offline)}
-  // - queue: [5 (normal)]
-  EXPECT_FALSE(event_5.Started());
-
   event_queue.EndEvent(event_4.event_id());
+  // All inflight offline events are finished. |event_queue| starts processing
+  // events in the queue. As a result, |event_6| is started.
+  //
   // State:
-  // - inflight_events: {5 (normal)}
+  // - inflight_events: {6 (normal)}
   // - queue: []
-  EXPECT_TRUE(event_5.Started());
+  EXPECT_TRUE(event_6.Started());
 }
 
 TEST_F(ServiceWorkerEventQueueTest, IdleTimerWithOfflineEvents) {
@@ -609,4 +669,71 @@
   EXPECT_TRUE(is_idle);
 }
 
+// Inflight or queued events must be aborted when event queue is destructed.
+TEST_F(ServiceWorkerEventQueueTest, AbortNotStartedEventOnDestruction) {
+  MockEvent event1, event2;
+  {
+    ServiceWorkerEventQueue event_queue(base::DoNothing(), base::DoNothing(),
+                                        task_runner(),
+                                        task_runner()->GetMockTickClock());
+    event_queue.Start();
+
+    event1.EnqueueTo(&event_queue);
+    event2.EnqueueOfflineTo(&event_queue);
+
+    // State:
+    // - inflight_events: {1 (normal)}
+    // - queue: [2 (offline)]
+    EXPECT_TRUE(event1.Started());
+    EXPECT_FALSE(event2.Started());
+
+    EXPECT_FALSE(event1.status().has_value());
+    EXPECT_FALSE(event2.status().has_value());
+  }
+
+  EXPECT_TRUE(event1.status().has_value());
+  EXPECT_EQ(mojom::blink::ServiceWorkerEventStatus::ABORTED,
+            event1.status().value());
+  EXPECT_TRUE(event2.status().has_value());
+  EXPECT_EQ(mojom::blink::ServiceWorkerEventStatus::ABORTED,
+            event2.status().value());
+  EXPECT_FALSE(event2.Started());
+}
+
+// Timer for timeout of each event starts when the event is queued.
+TEST_F(ServiceWorkerEventQueueTest, TimeoutNotStartedEvent) {
+  ServiceWorkerEventQueue event_queue(base::DoNothing(), base::DoNothing(),
+                                      task_runner(),
+                                      task_runner()->GetMockTickClock());
+  event_queue.Start();
+
+  MockEvent event1, event2;
+  event1.EnqueueWithCustomTimeoutTo(&event_queue,
+                                    ServiceWorkerEventQueue::kUpdateInterval -
+                                        base::TimeDelta::FromSeconds(1));
+  event2.EnqueueOfflineWithCustomTimeoutTo(
+      &event_queue, ServiceWorkerEventQueue::kUpdateInterval -
+                        base::TimeDelta::FromSeconds(1));
+
+  // State:
+  // - inflight_events: {1 (normal)}
+  // - queue: [2 (offline)]
+  EXPECT_TRUE(event1.Started());
+  EXPECT_FALSE(event2.Started());
+
+  task_runner()->FastForwardBy(ServiceWorkerEventQueue::kUpdateInterval +
+                               base::TimeDelta::FromSeconds(1));
+
+  EXPECT_TRUE(event1.status().has_value());
+  EXPECT_EQ(mojom::blink::ServiceWorkerEventStatus::TIMEOUT,
+            event1.status().value());
+  EXPECT_TRUE(event2.status().has_value());
+  EXPECT_EQ(mojom::blink::ServiceWorkerEventStatus::TIMEOUT,
+            event2.status().value());
+  EXPECT_FALSE(event_queue.HasEvent(event1.event_id()));
+  EXPECT_FALSE(event_queue.HasEventInQueue(event1.event_id()));
+  EXPECT_FALSE(event_queue.HasEvent(event2.event_id()));
+  EXPECT_FALSE(event_queue.HasEventInQueue(event2.event_id()));
+}
+
 }  // namespace blink
diff --git a/third_party/blink/renderer/modules/service_worker/service_worker_global_scope.cc b/third_party/blink/renderer/modules/service_worker/service_worker_global_scope.cc
index 16d36958..d8b37cd96 100644
--- a/third_party/blink/renderer/modules/service_worker/service_worker_global_scope.cc
+++ b/third_party/blink/renderer/modules/service_worker/service_worker_global_scope.cc
@@ -1371,7 +1371,8 @@
 
   // Push a dummy task to run all of queued tasks. This updates the
   // idle timer too.
-  event_queue_->EnqueueNormal(WTF::Bind(&ServiceWorkerEventQueue::EndEvent,
+  event_queue_->EnqueueNormal(event_queue_->NextEventId(),
+                              WTF::Bind(&ServiceWorkerEventQueue::EndEvent,
                                         WTF::Unretained(event_queue_.get())),
                               base::DoNothing(), base::nullopt);
 }
@@ -1474,7 +1475,6 @@
     base::WeakPtr<CrossOriginResourcePolicyChecker> corp_checker,
     mojo::PendingRemote<mojom::blink::ServiceWorkerFetchResponseCallback>
         response_callback,
-    DispatchFetchEventInternalCallback callback,
     base::Optional<base::TimeTicks> created_time,
     int event_id) {
   DCHECK(IsContextThread());
@@ -1482,7 +1482,6 @@
     RecordQueuingTime(created_time.value());
   }
 
-  fetch_event_callbacks_.Set(event_id, std::move(callback));
   HeapMojoRemote<mojom::blink::ServiceWorkerFetchResponseCallback,
                  HeapMojoWrapperMode::kWithoutContextObserver>
       remote(this);
@@ -1574,19 +1573,25 @@
                RequestedTermination() ? "true" : "false");
   base::WeakPtr<CrossOriginResourcePolicyChecker> corp_checker =
       controller_receivers_.current_context()->GetWeakPtr();
+
+  const int event_id = event_queue_->NextEventId();
+  fetch_event_callbacks_.Set(event_id, std::move(callback));
+
   if (RequestedTermination()) {
     event_queue_->EnqueuePending(
+        event_id,
         WTF::Bind(&ServiceWorkerGlobalScope::StartFetchEvent,
                   WrapWeakPersistent(this), std::move(params),
                   std::move(corp_checker), std::move(response_callback),
-                  std::move(callback), base::TimeTicks::Now()),
+                  base::TimeTicks::Now()),
         CreateAbortCallback(&fetch_event_callbacks_), base::nullopt);
   } else {
     event_queue_->EnqueueNormal(
+        event_id,
         WTF::Bind(&ServiceWorkerGlobalScope::StartFetchEvent,
                   WrapWeakPersistent(this), std::move(params),
                   std::move(corp_checker), std::move(response_callback),
-                  std::move(callback), base::TimeTicks::Now()),
+                  base::TimeTicks::Now()),
         CreateAbortCallback(&fetch_event_callbacks_), base::nullopt);
   }
 }
@@ -1675,9 +1680,13 @@
 void ServiceWorkerGlobalScope::DispatchInstallEvent(
     DispatchInstallEventCallback callback) {
   DCHECK(IsContextThread());
+  const int event_id = event_queue_->NextEventId();
+  install_event_callbacks_.Set(event_id, std::move(callback));
+
   event_queue_->EnqueueNormal(
+      event_id,
       WTF::Bind(&ServiceWorkerGlobalScope::StartInstallEvent,
-                WrapWeakPersistent(this), std::move(callback)),
+                WrapWeakPersistent(this)),
       WTF::Bind(&ServiceWorkerGlobalScope::AbortInstallEvent,
                 WrapWeakPersistent(this)),
       base::nullopt);
@@ -1694,11 +1703,8 @@
   install_event_callbacks_.erase(iter);
 }
 
-void ServiceWorkerGlobalScope::StartInstallEvent(
-    DispatchInstallEventCallback callback,
-    int event_id) {
+void ServiceWorkerGlobalScope::StartInstallEvent(int event_id) {
   DCHECK(IsContextThread());
-  install_event_callbacks_.Set(event_id, std::move(callback));
   TRACE_EVENT_WITH_FLOW0(
       "ServiceWorker", "ServiceWorkerGlobalScope::DispatchInstallEvent",
       TRACE_ID_WITH_SCOPE(kServiceWorkerGlobalScopeTraceScope,
@@ -1717,17 +1723,18 @@
 void ServiceWorkerGlobalScope::DispatchActivateEvent(
     DispatchActivateEventCallback callback) {
   DCHECK(IsContextThread());
+  const int event_id = event_queue_->NextEventId();
+  activate_event_callbacks_.Set(event_id, std::move(callback));
+
   event_queue_->EnqueueNormal(
+      event_id,
       WTF::Bind(&ServiceWorkerGlobalScope::StartActivateEvent,
-                WrapWeakPersistent(this), std::move(callback)),
+                WrapWeakPersistent(this)),
       CreateAbortCallback(&activate_event_callbacks_), base::nullopt);
 }
 
-void ServiceWorkerGlobalScope::StartActivateEvent(
-    DispatchActivateEventCallback callback,
-    int event_id) {
+void ServiceWorkerGlobalScope::StartActivateEvent(int event_id) {
   DCHECK(IsContextThread());
-  activate_event_callbacks_.Set(event_id, std::move(callback));
   TRACE_EVENT_WITH_FLOW0(
       "ServiceWorker", "ServiceWorkerGlobalScope::DispatchActivateEvent",
       TRACE_ID_WITH_SCOPE(kServiceWorkerGlobalScopeTraceScope,
@@ -1745,20 +1752,21 @@
     mojom::blink::BackgroundFetchRegistrationPtr registration,
     DispatchBackgroundFetchAbortEventCallback callback) {
   DCHECK(IsContextThread());
+  const int event_id = event_queue_->NextEventId();
+  background_fetch_abort_event_callbacks_.Set(event_id, std::move(callback));
+
   event_queue_->EnqueueNormal(
+      event_id,
       WTF::Bind(&ServiceWorkerGlobalScope::StartBackgroundFetchAbortEvent,
-                WrapWeakPersistent(this), std::move(registration),
-                std::move(callback)),
+                WrapWeakPersistent(this), std::move(registration)),
       CreateAbortCallback(&background_fetch_abort_event_callbacks_),
       base::nullopt);
 }
 
 void ServiceWorkerGlobalScope::StartBackgroundFetchAbortEvent(
     mojom::blink::BackgroundFetchRegistrationPtr registration,
-    DispatchBackgroundFetchAbortEventCallback callback,
     int event_id) {
   DCHECK(IsContextThread());
-  background_fetch_abort_event_callbacks_.Set(event_id, std::move(callback));
   TRACE_EVENT_WITH_FLOW0(
       "ServiceWorker",
       "ServiceWorkerGlobalScope::DispatchBackgroundFetchAbortEvent",
@@ -1788,20 +1796,21 @@
     mojom::blink::BackgroundFetchRegistrationPtr registration,
     DispatchBackgroundFetchClickEventCallback callback) {
   DCHECK(IsContextThread());
+  const int event_id = event_queue_->NextEventId();
+  background_fetch_click_event_callbacks_.Set(event_id, std::move(callback));
+
   event_queue_->EnqueueNormal(
+      event_id,
       WTF::Bind(&ServiceWorkerGlobalScope::StartBackgroundFetchClickEvent,
-                WrapWeakPersistent(this), std::move(registration),
-                std::move(callback)),
+                WrapWeakPersistent(this), std::move(registration)),
       CreateAbortCallback(&background_fetch_click_event_callbacks_),
       base::nullopt);
 }
 
 void ServiceWorkerGlobalScope::StartBackgroundFetchClickEvent(
     mojom::blink::BackgroundFetchRegistrationPtr registration,
-    DispatchBackgroundFetchClickEventCallback callback,
     int event_id) {
   DCHECK(IsContextThread());
-  background_fetch_click_event_callbacks_.Set(event_id, std::move(callback));
   TRACE_EVENT_WITH_FLOW0(
       "ServiceWorker",
       "ServiceWorkerGlobalScope::DispatchBackgroundFetchClickEvent",
@@ -1826,20 +1835,21 @@
     mojom::blink::BackgroundFetchRegistrationPtr registration,
     DispatchBackgroundFetchFailEventCallback callback) {
   DCHECK(IsContextThread());
+  const int event_id = event_queue_->NextEventId();
+  background_fetch_fail_event_callbacks_.Set(event_id, std::move(callback));
+
   event_queue_->EnqueueNormal(
+      event_id,
       WTF::Bind(&ServiceWorkerGlobalScope::StartBackgroundFetchFailEvent,
-                WrapWeakPersistent(this), std::move(registration),
-                std::move(callback)),
+                WrapWeakPersistent(this), std::move(registration)),
       CreateAbortCallback(&background_fetch_fail_event_callbacks_),
       base::nullopt);
 }
 
 void ServiceWorkerGlobalScope::StartBackgroundFetchFailEvent(
     mojom::blink::BackgroundFetchRegistrationPtr registration,
-    DispatchBackgroundFetchFailEventCallback callback,
     int event_id) {
   DCHECK(IsContextThread());
-  background_fetch_fail_event_callbacks_.Set(event_id, std::move(callback));
   TRACE_EVENT_WITH_FLOW0(
       "ServiceWorker",
       "ServiceWorkerGlobalScope::DispatchBackgroundFetchFailEvent",
@@ -1870,19 +1880,20 @@
     mojom::blink::BackgroundFetchRegistrationPtr registration,
     DispatchBackgroundFetchSuccessEventCallback callback) {
   DCHECK(IsContextThread());
+  const int event_id = event_queue_->NextEventId();
+  background_fetched_event_callbacks_.Set(event_id, std::move(callback));
+
   event_queue_->EnqueueNormal(
+      event_id,
       WTF::Bind(&ServiceWorkerGlobalScope::StartBackgroundFetchSuccessEvent,
-                WrapWeakPersistent(this), std::move(registration),
-                std::move(callback)),
+                WrapWeakPersistent(this), std::move(registration)),
       CreateAbortCallback(&background_fetched_event_callbacks_), base::nullopt);
 }
 
 void ServiceWorkerGlobalScope::StartBackgroundFetchSuccessEvent(
     mojom::blink::BackgroundFetchRegistrationPtr registration,
-    DispatchBackgroundFetchSuccessEventCallback callback,
     int event_id) {
   DCHECK(IsContextThread());
-  background_fetched_event_callbacks_.Set(event_id, std::move(callback));
   TRACE_EVENT_WITH_FLOW0(
       "ServiceWorker",
       "ServiceWorkerGlobalScope::DispatchBackgroundFetchSuccessEvent",
@@ -1913,19 +1924,20 @@
     mojom::blink::ExtendableMessageEventPtr event,
     DispatchExtendableMessageEventCallback callback) {
   DCHECK(IsContextThread());
+  const int event_id = event_queue_->NextEventId();
+  message_event_callbacks_.Set(event_id, std::move(callback));
+
   event_queue_->EnqueueNormal(
+      event_id,
       WTF::Bind(&ServiceWorkerGlobalScope::StartExtendableMessageEvent,
-                WrapWeakPersistent(this), std::move(event),
-                std::move(callback)),
+                WrapWeakPersistent(this), std::move(event)),
       CreateAbortCallback(&message_event_callbacks_), base::nullopt);
 }
 
 void ServiceWorkerGlobalScope::StartExtendableMessageEvent(
     mojom::blink::ExtendableMessageEventPtr event,
-    DispatchExtendableMessageEventCallback callback,
     int event_id) {
   DCHECK(IsContextThread());
-  message_event_callbacks_.Set(event_id, std::move(callback));
   TRACE_EVENT_WITH_FLOW0(
       "ServiceWorker",
       "ServiceWorkerGlobalScope::DispatchExtendableMessageEvent",
@@ -1947,22 +1959,27 @@
   static const base::FeatureParam<int> kCustomTimeoutForOfflineEvent{
       &features::kCheckOfflineCapability, "timeout_second", 5 * 60};
 
+  const int event_id = event_queue_->NextEventId();
+  fetch_event_callbacks_.Set(event_id, std::move(callback));
+
   // We can use nullptr as a |corp_checker| for the main resource because it
   // must be the same origin.
   if (params->is_offline_capability_check) {
     event_queue_->EnqueueOffline(
+        event_id,
         WTF::Bind(&ServiceWorkerGlobalScope::StartFetchEvent,
                   WrapWeakPersistent(this), std::move(params),
                   /*corp_checker=*/nullptr, std::move(response_callback),
-                  std::move(callback), base::nullopt),
+                  base::nullopt),
         CreateAbortCallback(&fetch_event_callbacks_),
         base::TimeDelta::FromSeconds(kCustomTimeoutForOfflineEvent.Get()));
   } else {
     event_queue_->EnqueueNormal(
+        event_id,
         WTF::Bind(&ServiceWorkerGlobalScope::StartFetchEvent,
                   WrapWeakPersistent(this), std::move(params),
                   /*corp_checker=*/nullptr, std::move(response_callback),
-                  std::move(callback), base::TimeTicks::Now()),
+                  base::TimeTicks::Now()),
         CreateAbortCallback(&fetch_event_callbacks_), base::nullopt);
   }
 }
@@ -1974,11 +1991,15 @@
     const String& reply,
     DispatchNotificationClickEventCallback callback) {
   DCHECK(IsContextThread());
+
+  const int event_id = event_queue_->NextEventId();
+  notification_click_event_callbacks_.Set(event_id, std::move(callback));
+
   event_queue_->EnqueueNormal(
+      event_id,
       WTF::Bind(&ServiceWorkerGlobalScope::StartNotificationClickEvent,
                 WrapWeakPersistent(this), notification_id,
-                std::move(notification_data), action_index, reply,
-                std::move(callback)),
+                std::move(notification_data), action_index, reply),
       CreateAbortCallback(&notification_click_event_callbacks_), base::nullopt);
 }
 
@@ -1987,9 +2008,7 @@
     mojom::blink::NotificationDataPtr notification_data,
     int action_index,
     String reply,
-    DispatchNotificationClickEventCallback callback,
     int event_id) {
-  notification_click_event_callbacks_.Set(event_id, std::move(callback));
   TRACE_EVENT_WITH_FLOW0(
       "ServiceWorker",
       "ServiceWorkerGlobalScope::DispatchNotificationClickEvent",
@@ -2017,20 +2036,22 @@
     mojom::blink::NotificationDataPtr notification_data,
     DispatchNotificationCloseEventCallback callback) {
   DCHECK(IsContextThread());
+  const int event_id = event_queue_->NextEventId();
+  notification_close_event_callbacks_.Set(event_id, std::move(callback));
+
   event_queue_->EnqueueNormal(
+      event_id,
       WTF::Bind(&ServiceWorkerGlobalScope::StartNotificationCloseEvent,
                 WrapWeakPersistent(this), notification_id,
-                std::move(notification_data), std::move(callback)),
+                std::move(notification_data)),
       CreateAbortCallback(&notification_close_event_callbacks_), base::nullopt);
 }
 
 void ServiceWorkerGlobalScope::StartNotificationCloseEvent(
     String notification_id,
     mojom::blink::NotificationDataPtr notification_data,
-    DispatchNotificationCloseEventCallback callback,
     int event_id) {
   DCHECK(IsContextThread());
-  notification_close_event_callbacks_.Set(event_id, std::move(callback));
   TRACE_EVENT_WITH_FLOW0(
       "ServiceWorker",
       "ServiceWorkerGlobalScope::DispatchNotificationCloseEvent",
@@ -2053,20 +2074,21 @@
     const String& payload,
     DispatchPushEventCallback callback) {
   DCHECK(IsContextThread());
+  const int event_id = event_queue_->NextEventId();
+  push_event_callbacks_.Set(event_id, std::move(callback));
+
   event_queue_->EnqueueNormal(
+      event_id,
       WTF::Bind(&ServiceWorkerGlobalScope::StartPushEvent,
-                WrapWeakPersistent(this), std::move(payload),
-                std::move(callback)),
+                WrapWeakPersistent(this), std::move(payload)),
       CreateAbortCallback(&push_event_callbacks_),
       base::TimeDelta::FromSeconds(mojom::blink::kPushEventTimeoutSeconds));
 }
 
 void ServiceWorkerGlobalScope::StartPushEvent(
     String payload,
-    DispatchPushEventCallback callback,
     int event_id) {
   DCHECK(IsContextThread());
-  push_event_callbacks_.Set(event_id, std::move(callback));
   TRACE_EVENT_WITH_FLOW0(
       "ServiceWorker", "ServiceWorkerGlobalScope::DispatchPushEvent",
       TRACE_ID_WITH_SCOPE(kServiceWorkerGlobalScopeTraceScope,
@@ -2085,10 +2107,14 @@
     mojom::blink::PushSubscriptionPtr new_subscription,
     DispatchPushSubscriptionChangeEventCallback callback) {
   DCHECK(IsContextThread());
+  const int event_id = event_queue_->NextEventId();
+  push_subscription_change_event_callbacks_.Set(event_id, std::move(callback));
+
   event_queue_->EnqueueNormal(
+      event_id,
       WTF::Bind(&ServiceWorkerGlobalScope::StartPushSubscriptionChangeEvent,
                 WrapWeakPersistent(this), std::move(old_subscription),
-                std::move(new_subscription), std::move(callback)),
+                std::move(new_subscription)),
       CreateAbortCallback(&push_subscription_change_event_callbacks_),
       base::TimeDelta::FromSeconds(mojom::blink::kPushEventTimeoutSeconds));
 }
@@ -2096,10 +2122,8 @@
 void ServiceWorkerGlobalScope::StartPushSubscriptionChangeEvent(
     mojom::blink::PushSubscriptionPtr old_subscription,
     mojom::blink::PushSubscriptionPtr new_subscription,
-    DispatchPushSubscriptionChangeEventCallback callback,
     int event_id) {
   DCHECK(IsContextThread());
-  push_subscription_change_event_callbacks_.Set(event_id, std::move(callback));
   TRACE_EVENT_WITH_FLOW0(
       "ServiceWorker",
       "ServiceWorkerGlobalScope::DispatchPushSubscriptionChangeEvent",
@@ -2127,20 +2151,21 @@
     base::TimeDelta timeout,
     DispatchSyncEventCallback callback) {
   DCHECK(IsContextThread());
+  const int event_id = event_queue_->NextEventId();
+  sync_event_callbacks_.Set(event_id, std::move(callback));
+
   event_queue_->EnqueueNormal(
+      event_id,
       WTF::Bind(&ServiceWorkerGlobalScope::StartSyncEvent,
-                WrapWeakPersistent(this), std::move(tag), last_chance,
-                std::move(callback)),
+                WrapWeakPersistent(this), std::move(tag), last_chance),
       CreateAbortCallback(&sync_event_callbacks_), timeout);
 }
 
 void ServiceWorkerGlobalScope::StartSyncEvent(
     String tag,
     bool last_chance,
-    DispatchSyncEventCallback callback,
     int event_id) {
   DCHECK(IsContextThread());
-  sync_event_callbacks_.Set(event_id, std::move(callback));
   TRACE_EVENT_WITH_FLOW0(
       "ServiceWorker", "ServiceWorkerGlobalScope::DispatchSyncEvent",
       TRACE_ID_WITH_SCOPE(kServiceWorkerGlobalScopeTraceScope,
@@ -2159,18 +2184,20 @@
     base::TimeDelta timeout,
     DispatchPeriodicSyncEventCallback callback) {
   DCHECK(IsContextThread());
+  const int event_id = event_queue_->NextEventId();
+  periodic_sync_event_callbacks_.Set(event_id, std::move(callback));
+
   event_queue_->EnqueueNormal(
+      event_id,
       WTF::Bind(&ServiceWorkerGlobalScope::StartPeriodicSyncEvent,
-                WrapWeakPersistent(this), std::move(tag), std::move(callback)),
+                WrapWeakPersistent(this), std::move(tag)),
       CreateAbortCallback(&periodic_sync_event_callbacks_), timeout);
 }
 
 void ServiceWorkerGlobalScope::StartPeriodicSyncEvent(
     String tag,
-    DispatchPeriodicSyncEventCallback callback,
     int event_id) {
   DCHECK(IsContextThread());
-  periodic_sync_event_callbacks_.Set(event_id, std::move(callback));
   TRACE_EVENT_WITH_FLOW0(
       "ServiceWorker", "ServiceWorkerGlobalScope::DispatchPeriodicSyncEvent",
       TRACE_ID_WITH_SCOPE(kServiceWorkerGlobalScopeTraceScope,
@@ -2189,20 +2216,21 @@
         response_callback,
     DispatchAbortPaymentEventCallback callback) {
   DCHECK(IsContextThread());
+  const int event_id = event_queue_->NextEventId();
+  abort_payment_event_callbacks_.Set(event_id, std::move(callback));
+
   event_queue_->EnqueueNormal(
+      event_id,
       WTF::Bind(&ServiceWorkerGlobalScope::StartAbortPaymentEvent,
-                WrapWeakPersistent(this), std::move(response_callback),
-                std::move(callback)),
+                WrapWeakPersistent(this), std::move(response_callback)),
       CreateAbortCallback(&abort_payment_event_callbacks_), base::nullopt);
 }
 
 void ServiceWorkerGlobalScope::StartAbortPaymentEvent(
     mojo::PendingRemote<payments::mojom::blink::PaymentHandlerResponseCallback>
         response_callback,
-    DispatchAbortPaymentEventCallback callback,
     int event_id) {
   DCHECK(IsContextThread());
-  abort_payment_event_callbacks_.Set(event_id, std::move(callback));
   HeapMojoRemote<payments::mojom::blink::PaymentHandlerResponseCallback,
                  HeapMojoWrapperMode::kWithoutContextObserver>
       remote(this);
@@ -2240,10 +2268,14 @@
         response_callback,
     DispatchCanMakePaymentEventCallback callback) {
   DCHECK(IsContextThread());
+  const int event_id = event_queue_->NextEventId();
+  can_make_payment_event_callbacks_.Set(event_id, std::move(callback));
+
   event_queue_->EnqueueNormal(
+      event_id,
       WTF::Bind(&ServiceWorkerGlobalScope::StartCanMakePaymentEvent,
                 WrapWeakPersistent(this), std::move(event_data),
-                std::move(response_callback), std::move(callback)),
+                std::move(response_callback)),
       CreateAbortCallback(&can_make_payment_event_callbacks_), base::nullopt);
 }
 
@@ -2251,10 +2283,8 @@
     payments::mojom::blink::CanMakePaymentEventDataPtr event_data,
     mojo::PendingRemote<payments::mojom::blink::PaymentHandlerResponseCallback>
         response_callback,
-    DispatchCanMakePaymentEventCallback callback,
     int event_id) {
   DCHECK(IsContextThread());
-  can_make_payment_event_callbacks_.Set(event_id, std::move(callback));
   HeapMojoRemote<payments::mojom::blink::PaymentHandlerResponseCallback,
                  HeapMojoWrapperMode::kWithoutContextObserver>
       remote(this);
@@ -2294,10 +2324,14 @@
         response_callback,
     DispatchPaymentRequestEventCallback callback) {
   DCHECK(IsContextThread());
+  const int event_id = event_queue_->NextEventId();
+  payment_request_event_callbacks_.Set(event_id, std::move(callback));
+
   event_queue_->EnqueueNormal(
+      event_id,
       WTF::Bind(&ServiceWorkerGlobalScope::StartPaymentRequestEvent,
                 WrapWeakPersistent(this), std::move(event_data),
-                std::move(response_callback), std::move(callback)),
+                std::move(response_callback)),
       CreateAbortCallback(&payment_request_event_callbacks_), base::nullopt);
 }
 
@@ -2305,10 +2339,8 @@
     payments::mojom::blink::PaymentRequestEventDataPtr event_data,
     mojo::PendingRemote<payments::mojom::blink::PaymentHandlerResponseCallback>
         response_callback,
-    DispatchPaymentRequestEventCallback callback,
     int event_id) {
   DCHECK(IsContextThread());
-  payment_request_event_callbacks_.Set(event_id, std::move(callback));
   HeapMojoRemote<payments::mojom::blink::PaymentHandlerResponseCallback,
                  HeapMojoWrapperMode::kWithoutContextObserver>
       remote(this);
@@ -2361,19 +2393,20 @@
 void ServiceWorkerGlobalScope::DispatchCookieChangeEvent(
     network::mojom::blink::CookieChangeInfoPtr change,
     DispatchCookieChangeEventCallback callback) {
+  const int event_id = event_queue_->NextEventId();
+  cookie_change_event_callbacks_.Set(event_id, std::move(callback));
+
   event_queue_->EnqueueNormal(
+      event_id,
       WTF::Bind(&ServiceWorkerGlobalScope::StartCookieChangeEvent,
-                WrapWeakPersistent(this), std::move(change),
-                std::move(callback)),
+                WrapWeakPersistent(this), std::move(change)),
       CreateAbortCallback(&cookie_change_event_callbacks_), base::nullopt);
 }
 
 void ServiceWorkerGlobalScope::StartCookieChangeEvent(
     network::mojom::blink::CookieChangeInfoPtr change,
-    DispatchCookieChangeEventCallback callback,
     int event_id) {
   DCHECK(IsContextThread());
-  cookie_change_event_callbacks_.Set(event_id, std::move(callback));
   TRACE_EVENT_WITH_FLOW0(
       "ServiceWorker", "ServiceWorkerGlobalScope::DispatchCookieChangeEvent",
       TRACE_ID_WITH_SCOPE(kServiceWorkerGlobalScopeTraceScope,
@@ -2400,18 +2433,20 @@
 void ServiceWorkerGlobalScope::DispatchContentDeleteEvent(
     const String& id,
     DispatchContentDeleteEventCallback callback) {
+  const int event_id = event_queue_->NextEventId();
+  content_delete_callbacks_.Set(event_id, std::move(callback));
+
   event_queue_->EnqueueNormal(
+      event_id,
       WTF::Bind(&ServiceWorkerGlobalScope::StartContentDeleteEvent,
-                WrapWeakPersistent(this), id, std::move(callback)),
+                WrapWeakPersistent(this), id),
       CreateAbortCallback(&content_delete_callbacks_), base::nullopt);
 }
 
 void ServiceWorkerGlobalScope::StartContentDeleteEvent(
     String id,
-    DispatchContentDeleteEventCallback callback,
     int event_id) {
   DCHECK(IsContextThread());
-  content_delete_callbacks_.Set(event_id, std::move(callback));
   TRACE_EVENT_WITH_FLOW0(
       "ServiceWorker", "ServiceWorkerGlobalScope::DispatchContentDeleteEvent",
       TRACE_ID_WITH_SCOPE(kServiceWorkerGlobalScopeTraceScope,
diff --git a/third_party/blink/renderer/modules/service_worker/service_worker_global_scope.h b/third_party/blink/renderer/modules/service_worker/service_worker_global_scope.h
index bdf8041..720408c 100644
--- a/third_party/blink/renderer/modules/service_worker/service_worker_global_scope.h
+++ b/third_party/blink/renderer/modules/service_worker/service_worker_global_scope.h
@@ -506,88 +506,66 @@
       base::WeakPtr<CrossOriginResourcePolicyChecker> corp_checker,
       mojo::PendingRemote<mojom::blink::ServiceWorkerFetchResponseCallback>
           response_callback,
-      DispatchFetchEventInternalCallback callback,
       base::Optional<base::TimeTicks> created_time,
       int event_id);
-  void StartInstallEvent(DispatchInstallEventCallback callback, int event_id);
-  void StartActivateEvent(DispatchActivateEventCallback callback, int event_id);
+  void StartInstallEvent(int event_id);
+  void StartActivateEvent(int event_id);
   void StartBackgroundFetchAbortEvent(
       mojom::blink::BackgroundFetchRegistrationPtr registration,
-      DispatchBackgroundFetchAbortEventCallback callback,
       int event_id);
   void StartBackgroundFetchClickEvent(
       mojom::blink::BackgroundFetchRegistrationPtr registration,
-      DispatchBackgroundFetchClickEventCallback callback,
       int event_id);
   void StartBackgroundFetchFailEvent(
       mojom::blink::BackgroundFetchRegistrationPtr registration,
-      DispatchBackgroundFetchFailEventCallback callback,
       int event_id);
   void StartBackgroundFetchSuccessEvent(
       mojom::blink::BackgroundFetchRegistrationPtr registration,
-      DispatchBackgroundFetchSuccessEventCallback callback,
       int event_id);
   void StartExtendableMessageEvent(
       mojom::blink::ExtendableMessageEventPtr event,
-      DispatchExtendableMessageEventCallback callback,
-      int event_id);
-  void StartFetchEventForMainResource(
-      mojom::blink::DispatchFetchEventParamsPtr params,
-      mojo::PendingRemote<mojom::blink::ServiceWorkerFetchResponseCallback>
-          response_callback,
       int event_id);
   void StartNotificationClickEvent(
       String notification_id,
       mojom::blink::NotificationDataPtr notification_data,
       int action_index,
       String reply,
-      DispatchNotificationClickEventCallback callback,
       int event_id);
   void StartNotificationCloseEvent(
       String notification_id,
       mojom::blink::NotificationDataPtr notification_data,
-      DispatchNotificationCloseEventCallback callback,
       int event_id);
   void StartPushEvent(String payload,
-                      DispatchPushEventCallback callback,
                       int event_id);
   void StartPushSubscriptionChangeEvent(
       mojom::blink::PushSubscriptionPtr old_subscription,
       mojom::blink::PushSubscriptionPtr new_subscription,
-      DispatchPushSubscriptionChangeEventCallback callback,
       int event_id);
   void StartSyncEvent(String tag,
                       bool last_chance,
-                      DispatchSyncEventCallback callback,
                       int event_id);
   void StartPeriodicSyncEvent(String tag,
-                              DispatchPeriodicSyncEventCallback callback,
                               int event_id);
   void StartAbortPaymentEvent(
       mojo::PendingRemote<
           payments::mojom::blink::PaymentHandlerResponseCallback>
           response_callback,
-      DispatchAbortPaymentEventCallback callback,
       int event_id);
   void StartCanMakePaymentEvent(
       payments::mojom::blink::CanMakePaymentEventDataPtr event_data,
       mojo::PendingRemote<
           payments::mojom::blink::PaymentHandlerResponseCallback>
           response_callback,
-      DispatchCanMakePaymentEventCallback callback,
       int event_id);
   void StartPaymentRequestEvent(
       payments::mojom::blink::PaymentRequestEventDataPtr event_data,
       mojo::PendingRemote<
           payments::mojom::blink::PaymentHandlerResponseCallback>
           response_callback,
-      DispatchPaymentRequestEventCallback callback,
       int event_id);
   void StartCookieChangeEvent(network::mojom::blink::CookieChangeInfoPtr change,
-                              DispatchCookieChangeEventCallback callback,
                               int event_id);
   void StartContentDeleteEvent(String id,
-                               DispatchContentDeleteEventCallback callback,
                                int event_id);
 
   // Records the time that a fetch event was queued in the
diff --git a/third_party/blink/renderer/modules/webgpu/dawn_conversions.cc b/third_party/blink/renderer/modules/webgpu/dawn_conversions.cc
index 550a547d..22bab49 100644
--- a/third_party/blink/renderer/modules/webgpu/dawn_conversions.cc
+++ b/third_party/blink/renderer/modules/webgpu/dawn_conversions.cc
@@ -222,11 +222,18 @@
   }
 
   // Packed 32 bit formats
+  if (webgpu_enum == "rgb9e5ufloat") {
+    return WGPUTextureFormat_RGB9E5Ufloat;
+  }
   if (webgpu_enum == "rgb10a2unorm") {
     return WGPUTextureFormat_RGB10A2Unorm;
   }
   if (webgpu_enum == "rg11b10float") {
-    return WGPUTextureFormat_RG11B10Float;
+    // Deprecated.
+    return WGPUTextureFormat_RG11B10Ufloat;
+  }
+  if (webgpu_enum == "rg11b10ufloat") {
+    return WGPUTextureFormat_RG11B10Ufloat;
   }
 
   // Normal 64 bit formats
@@ -305,8 +312,12 @@
   if (webgpu_enum == "bc6h-rgb-ufloat") {
     return WGPUTextureFormat_BC6HRGBUfloat;
   }
+  if (webgpu_enum == "bc6h-rgb-float") {
+    return WGPUTextureFormat_BC6HRGBFloat;
+  }
   if (webgpu_enum == "bc6h-rgb-sfloat") {
-    return WGPUTextureFormat_BC6HRGBSfloat;
+    // Deprecated.
+    return WGPUTextureFormat_BC6HRGBFloat;
   }
   if (webgpu_enum == "bc7-rgba-unorm") {
     return WGPUTextureFormat_BC7RGBAUnorm;
diff --git a/third_party/blink/renderer/modules/webgpu/gpu_texture.cc b/third_party/blink/renderer/modules/webgpu/gpu_texture.cc
index 3a23131..8c98c6f 100644
--- a/third_party/blink/renderer/modules/webgpu/gpu_texture.cc
+++ b/third_party/blink/renderer/modules/webgpu/gpu_texture.cc
@@ -27,6 +27,14 @@
   dawn_desc.dimension =
       AsDawnEnum<WGPUTextureDimension>(webgpu_desc->dimension());
   dawn_desc.size = AsDawnType(&webgpu_desc->size());
+  if (webgpu_desc->format() == "rg11b10float") {
+    device->AddConsoleWarning(
+        "rg11b10float is deprecated. Use rg11b10ufloat instead.");
+  }
+  if (webgpu_desc->format() == "bc6h-rgb-sfloat") {
+    device->AddConsoleWarning(
+        "bc6h-rgb-sfloat is deprecated. Use bc6h-rgb-float instead.");
+  }
   dawn_desc.format = AsDawnEnum<WGPUTextureFormat>(webgpu_desc->format());
   dawn_desc.mipLevelCount = webgpu_desc->mipLevelCount();
   dawn_desc.sampleCount = webgpu_desc->sampleCount();
diff --git a/third_party/blink/renderer/modules/webgpu/gpu_texture_descriptor.idl b/third_party/blink/renderer/modules/webgpu/gpu_texture_descriptor.idl
index 0371a8b0..820b341 100644
--- a/third_party/blink/renderer/modules/webgpu/gpu_texture_descriptor.idl
+++ b/third_party/blink/renderer/modules/webgpu/gpu_texture_descriptor.idl
@@ -48,8 +48,10 @@
     "bgra8unorm",
     "bgra8unorm-srgb",
     /* Packed 32 bit formats */
+    "rgb9e5ufloat",
     "rgb10a2unorm",
     "rg11b10float",
+    "rg11b10ufloat",
     /* Normal 64 bit formats */
     "rg32uint",
     "rg32sint",
@@ -77,6 +79,7 @@
     "bc5-rg-unorm",
     "bc5-rg-snorm",
     "bc6h-rgb-ufloat",
+    "bc6h-rgb-float",
     "bc6h-rgb-sfloat",
     "bc7-rgba-unorm",
     "bc7-rgba-unorm-srgb"
diff --git a/third_party/blink/renderer/platform/bindings/trace_wrapper_v8_reference.h b/third_party/blink/renderer/platform/bindings/trace_wrapper_v8_reference.h
index ad4a382..d68b79f4 100644
--- a/third_party/blink/renderer/platform/bindings/trace_wrapper_v8_reference.h
+++ b/third_party/blink/renderer/platform/bindings/trace_wrapper_v8_reference.h
@@ -13,6 +13,9 @@
 
 namespace blink {
 
+template <typename T>
+struct TraceTrait;
+
 /**
  * TraceWrapperV8Reference is used to hold references from Blink to V8 that are
  * known to both garbage collectors. The reference is a regular traced reference
@@ -119,6 +122,21 @@
   v8::TracedReference<T> handle_;
 };
 
+template <typename T>
+struct TraceTrait<TraceWrapperV8Reference<T>> {
+  STATIC_ONLY(TraceTrait);
+
+ public:
+  static TraceDescriptor GetTraceDescriptor(
+      const TraceWrapperV8Reference<T>* ref) {
+    return {ref, TraceTrait<TraceWrapperV8Reference<T>>::Trace};
+  }
+
+  static void Trace(Visitor* visitor, const void* ref) {
+    visitor->Trace(*static_cast<const TraceWrapperV8Reference<T>*>(ref));
+  }
+};
+
 }  // namespace blink
 
 namespace WTF {
diff --git a/third_party/blink/renderer/platform/heap/collection_support/heap_hash_table_backing.h b/third_party/blink/renderer/platform/heap/collection_support/heap_hash_table_backing.h
index e91e2e1..0d4a826 100644
--- a/third_party/blink/renderer/platform/heap/collection_support/heap_hash_table_backing.h
+++ b/third_party/blink/renderer/platform/heap/collection_support/heap_hash_table_backing.h
@@ -339,11 +339,7 @@
       // The following passes on kNoWeakHandling for tracing value as the value
       // callback is only invoked to keep value alive iff key is alive,
       // following ephemeron semantics.
-      visitor->TraceEphemeron(
-          *helper.key, helper.value,
-          blink::TraceCollectionIfEnabled<
-              kNoWeakHandling, typename EphemeronHelper::ValueType,
-              typename EphemeronHelper::ValueTraits>::Trace);
+      visitor->TraceEphemeron(*helper.key, helper.value);
     }
   };
 
diff --git a/third_party/blink/renderer/platform/heap/heap.cc b/third_party/blink/renderer/platform/heap/heap.cc
index 2a5b1790..e550136 100644
--- a/third_party/blink/renderer/platform/heap/heap.cc
+++ b/third_party/blink/renderer/platform/heap/heap.cc
@@ -376,8 +376,7 @@
   return DrainWorklistWithDeadline(
       deadline, ephemeron_pairs_to_process_worklist_.get(),
       [visitor](EphemeronPairItem& item) {
-        visitor->VisitEphemeron(item.key, item.value,
-                                item.value_trace_callback);
+        visitor->VisitEphemeron(item.key, item.value_desc);
       },
       WorklistTaskId::MutatorThread);
 }
@@ -579,14 +578,12 @@
       // Callbacks found by the concurrent marking will be flushed eventually
       // by the mutator thread and then invoked either concurrently or by the
       // mutator thread (in the atomic pause at latest).
-      finished =
-          DrainWorklist<kDefaultConcurrentDeadlineCheckInterval>(
-              ephemeron_pairs_to_process_worklist_.get(),
-              [visitor](EphemeronPairItem& item) {
-                visitor->VisitEphemeron(item.key, item.value,
-                                        item.value_trace_callback);
-              },
-              should_yield_callback, visitor->task_id());
+      finished = DrainWorklist<kDefaultConcurrentDeadlineCheckInterval>(
+          ephemeron_pairs_to_process_worklist_.get(),
+          [visitor](EphemeronPairItem& item) {
+            visitor->VisitEphemeron(item.key, item.value_desc);
+          },
+          should_yield_callback, visitor->task_id());
       if (!finished)
         break;
     }
diff --git a/third_party/blink/renderer/platform/heap/heap.h b/third_party/blink/renderer/platform/heap/heap.h
index f27916b..cc62ead 100644
--- a/third_party/blink/renderer/platform/heap/heap.h
+++ b/third_party/blink/renderer/platform/heap/heap.h
@@ -69,8 +69,7 @@
 
 struct EphemeronPairItem {
   const void* key;
-  const void* value;
-  TraceCallback value_trace_callback;
+  TraceDescriptor value_desc;
 };
 
 struct CustomCallbackItem {
diff --git a/third_party/blink/renderer/platform/heap/marking_visitor.cc b/third_party/blink/renderer/platform/heap/marking_visitor.cc
index df3d97ef..931c814 100644
--- a/third_party/blink/renderer/platform/heap/marking_visitor.cc
+++ b/third_party/blink/renderer/platform/heap/marking_visitor.cc
@@ -69,19 +69,17 @@
 }
 
 void MarkingVisitorBase::VisitEphemeron(const void* key,
-                                        const void* value,
-                                        TraceCallback value_trace_callback) {
+                                        TraceDescriptor value_desc) {
   HeapObjectHeader* key_header = HeapObjectHeader::FromPayload(key);
   if (!key_header->IsInConstruction<HeapObjectHeader::AccessMode::kAtomic>() &&
       !key_header->IsMarked<HeapObjectHeader::AccessMode::kAtomic>()) {
     // In construction keys are considered as marked because they are
     // guaranteed to be marked by the end of GC (e.g. by write barrier
     // on insertion to HashTable).
-    discovered_ephemeron_pairs_worklist_.Push(
-        {key, value, value_trace_callback});
+    discovered_ephemeron_pairs_worklist_.Push({key, value_desc});
     return;
   }
-  value_trace_callback(this, value);
+  value_desc.callback(this, value_desc.base_object_payload);
 }
 
 void MarkingVisitorBase::VisitWeakContainer(
diff --git a/third_party/blink/renderer/platform/heap/marking_visitor.h b/third_party/blink/renderer/platform/heap/marking_visitor.h
index 6b472bd..0936bf4 100644
--- a/third_party/blink/renderer/platform/heap/marking_visitor.h
+++ b/third_party/blink/renderer/platform/heap/marking_visitor.h
@@ -42,7 +42,7 @@
                           TraceDescriptor,
                           WeakCallback,
                           const void*) final;
-  void VisitEphemeron(const void*, const void*, TraceCallback) final;
+  void VisitEphemeron(const void*, TraceDescriptor) final;
 
   // Marks an object dynamically using any address within its body and adds a
   // tracing callback for processing of the object. The object is not allowed
diff --git a/third_party/blink/renderer/platform/heap/member.h b/third_party/blink/renderer/platform/heap/member.h
index 6567c77f..d2ffd56 100644
--- a/third_party/blink/renderer/platform/heap/member.h
+++ b/third_party/blink/renderer/platform/heap/member.h
@@ -463,6 +463,26 @@
   }
 };
 
+template <typename T>
+struct MemberTraceTraits {
+  STATIC_ONLY(MemberTraceTraits);
+
+ public:
+  static TraceDescriptor GetTraceDescriptor(const T* ref) {
+    return {ref, TraceTrait<T>::Trace};
+  }
+
+  static void Trace(Visitor* visitor, const void* ref) {
+    visitor->Trace(*static_cast<const T*>(ref));
+  }
+};
+
+template <typename T>
+struct TraceTrait<Member<T>> : public MemberTraceTraits<Member<T>> {};
+
+template <typename T>
+struct TraceTrait<WeakMember<T>> : public MemberTraceTraits<WeakMember<T>> {};
+
 }  // namespace blink
 
 namespace WTF {
diff --git a/third_party/blink/renderer/platform/heap/test/incremental_marking_test.cc b/third_party/blink/renderer/platform/heap/test/incremental_marking_test.cc
index 7bab2c4..a180315 100644
--- a/third_party/blink/renderer/platform/heap/test/incremental_marking_test.cc
+++ b/third_party/blink/renderer/platform/heap/test/incremental_marking_test.cc
@@ -55,12 +55,10 @@
       EXPECT_TRUE(header->TryMark());
   }
 
-  void VisitEphemeron(const void* key,
-                      const void* value,
-                      TraceCallback value_trace_callback) final {
+  void VisitEphemeron(const void* key, TraceDescriptor value_desc) final {
     if (!HeapObjectHeader::FromPayload(key)->IsMarked())
       return;
-    value_trace_callback(this, value);
+    value_desc.callback(this, value_desc.base_object_payload);
   }
 
  private:
diff --git a/third_party/blink/renderer/platform/heap/trace_traits.h b/third_party/blink/renderer/platform/heap/trace_traits.h
index 59c97fe..7bfab484 100644
--- a/third_party/blink/renderer/platform/heap/trace_traits.h
+++ b/third_party/blink/renderer/platform/heap/trace_traits.h
@@ -280,31 +280,10 @@
 };
 
 template <typename T, typename Traits>
-struct TraceInCollectionTrait<kNoWeakHandling, blink::Member<T>, Traits> {
-  static bool IsAlive(const blink::LivenessBroker& info,
-                      const blink::Member<T>& t) {
-    return true;
-  }
-  static void Trace(blink::Visitor* visitor, const blink::Member<T>& t) {
-    visitor->TraceMaybeDeleted(t);
-  }
-};
-
-template <typename T, typename Traits>
-struct TraceInCollectionTrait<kWeakHandling, blink::Member<T>, Traits> {
-  static bool IsAlive(const blink::LivenessBroker& info,
-                      const blink::Member<T>& t) {
-    return true;
-  }
-  static void Trace(blink::Visitor* visitor, const blink::Member<T>& t) {
-    visitor->TraceMaybeDeleted(t);
-  }
-};
-
-template <typename T, typename Traits>
 struct TraceInCollectionTrait<kNoWeakHandling, blink::WeakMember<T>, Traits> {
   static void Trace(blink::Visitor* visitor, const blink::WeakMember<T>& t) {
-    visitor->TraceMaybeDeleted(t);
+    // Extract raw pointer to avoid using the WeakMember<> overload in Visitor.
+    visitor->TraceStrongly(t);
   }
 };
 
diff --git a/third_party/blink/renderer/platform/heap/visitor.h b/third_party/blink/renderer/platform/heap/visitor.h
index 7ca6427b..3d2cc0d 100644
--- a/third_party/blink/renderer/platform/heap/visitor.h
+++ b/third_party/blink/renderer/platform/heap/visitor.h
@@ -118,27 +118,15 @@
     Trace(value);
   }
 
+  // TraceStrongly strongifies WeakMembers.
   template <typename T>
-  ALWAYS_INLINE void TraceMaybeDeleted(const Member<T>& t) {
+  ALWAYS_INLINE void TraceStrongly(const WeakMember<T>& t) {
     const T* value = t.GetSafe();
 
-    if (Member<T>::IsMemberHashTableDeletedValue(value))
-      return;
+    DCHECK(!WeakMember<T>::IsMemberHashTableDeletedValue(value));
 
     Trace<T>(value);
   }
-
-  // TraceMayBeDeleted strongifies WeakMembers.
-  template <typename T>
-  ALWAYS_INLINE void TraceMaybeDeleted(const WeakMember<T>& t) {
-    const T* value = t.GetSafe();
-
-    if (WeakMember<T>::IsMemberHashTableDeletedValue(value))
-      return;
-
-    Trace<T>(value);
-  }
-
   // Fallback methods used only when we need to trace raw pointers of T. This is
   // the case when a member is a union where we do not support members.
   template <typename T>
@@ -196,15 +184,13 @@
     TraceTrait<T>::Trace(this, &t);
   }
 
-  template <typename T>
-  void TraceEphemeron(const WeakMember<T>& key,
-                      const void* value,
-                      TraceCallback value_trace_callback) {
+  template <typename T, typename U>
+  void TraceEphemeron(const WeakMember<T>& key, const U* value) {
     const T* t = key.GetSafe();
     if (!t)
       return;
-    VisitEphemeron(TraceDescriptorFor(t).base_object_payload, value,
-                   value_trace_callback);
+    VisitEphemeron(TraceDescriptorFor(t).base_object_payload,
+                   TraceDescriptorFor(value));
   }
 
   template <typename T>
@@ -292,7 +278,7 @@
 
   // Visits ephemeron pairs which are a combination of weak and strong keys and
   // values.
-  virtual void VisitEphemeron(const void*, const void*, TraceCallback) {}
+  virtual void VisitEphemeron(const void*, TraceDescriptor) {}
 
   // Visits a container |object| holding ephemeron pairs held from |slot|.  The
   // descriptor |strong_desc| can be used to enforce strong treatment of
diff --git a/third_party/blink/web_tests/TestExpectations b/third_party/blink/web_tests/TestExpectations
index 2f6d8d5..94d04e57 100644
--- a/third_party/blink/web_tests/TestExpectations
+++ b/third_party/blink/web_tests/TestExpectations
@@ -1212,7 +1212,6 @@
 
 crbug.com/626703 external/wpt/mathml/presentation-markup/fractions/frac-invalid-2.html [ Failure ]
 crbug.com/626703 external/wpt/mathml/presentation-markup/fractions/frac-invalid-3.html [ Failure ]
-crbug.com/626703 external/wpt/mathml/presentation-markup/operators/mo-lspace-rspace-dynamic.html [ Failure ]
 crbug.com/6606 external/wpt/mathml/presentation-markup/direction/direction-006.html [ Failure ]
 crbug.com/6606 external/wpt/mathml/presentation-markup/direction/direction-009.html [ Failure ]
 crbug.com/6606 external/wpt/mathml/presentation-markup/direction/direction.html [ Failure ]
@@ -2960,11 +2959,7 @@
 crbug.com/626703 external/wpt/html/rendering/non-replaced-elements/the-fieldset-and-legend-elements/legend-display-rendering.html [ Failure ]
 crbug.com/626703 external/wpt/html/rendering/non-replaced-elements/the-fieldset-and-legend-elements/legend-tall.html [ Failure ]
 crbug.com/626703 external/wpt/speech-api/SpeechSynthesis-pause-resume.tentative.html [ Timeout ]
-crbug.com/880983 external/wpt/css/css-masking/clip-path/clip-path-path-interpolation-001.html [ Failure ]
-crbug.com/880983 external/wpt/css/css-masking/clip-path/clip-path-path-interpolation-002.html [ Failure ]
 crbug.com/891944 external/wpt/css/css-scrollbars/textarea-scrollbar-width-none.html [ Failure ]
-crbug.com/880983 external/wpt/css/css-masking/clip-path/clip-path-path-002.html [ Failure ]
-crbug.com/880983 external/wpt/css/css-masking/clip-path/clip-path-path-001.html [ Failure ]
 crbug.com/432153 external/wpt/css/css-masking/mask-image/mask-image-url-local-mask.html [ Failure ]
 crbug.com/432153 external/wpt/css/css-masking/mask-image/mask-image-url-image.html [ Failure ]
 crbug.com/432153 external/wpt/css/css-masking/mask-image/mask-image-url-remote-mask.html [ Failure ]
diff --git a/third_party/blink/web_tests/external/wpt/css/css-masking/clip-path/clip-path-path-interpolation-with-zoom.html b/third_party/blink/web_tests/external/wpt/css/css-masking/clip-path/clip-path-path-interpolation-with-zoom.html
new file mode 100644
index 0000000..4d54708
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-masking/clip-path/clip-path-path-interpolation-with-zoom.html
@@ -0,0 +1,27 @@
+<!DOCTYPE html>
+<html>
+  <title>CSS Masking: Test clip-path nonzero path interpolation with zoom</title>
+  <link rel="help" href="https://drafts.csswg.org/css-shapes-2/#funcdef-path">
+  <link rel="match" href="reference/clip-path-path-interpolation-with-zoom-ref.html">
+  <meta name="assert" content="The clip-path property takes the basic shape
+	'path()' for clipping. Test the interpolation of nonzero
+        path function.">
+  <style>
+    @keyframes anim {
+      from {
+        clip-path: path(nonzero, 'M20,20h60 v60 h-60z M30,30 h40 v40 h-40z');
+      }
+      to {
+        clip-path: path(nonzero, 'M50,50h50 v50 h-50z M20,20 h50 v50 h-50z');
+      }
+    }
+    #rect {
+      width: 100px;
+      zoom: 3;
+      height: 100px;
+      background-color: green;
+      animation: anim 10s -5s paused linear;
+    }
+  </style>
+  <div id="rect"></div>
+</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-masking/clip-path/clip-path-path-with-zoom-hittest.html b/third_party/blink/web_tests/external/wpt/css/css-masking/clip-path/clip-path-path-with-zoom-hittest.html
new file mode 100644
index 0000000..30ceefcb
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-masking/clip-path/clip-path-path-with-zoom-hittest.html
@@ -0,0 +1,25 @@
+<!DOCTYPE html>
+<title>CSS Masking: Test clip-path property hit-testing when the page is zoomed</title>
+<link rel="author" title="Noam Rosenthal" href="mailto:noam@webkit.org">
+<link rel="help" href="https://drafts.csswg.org/css-shapes-2/#funcdef-path">
+<meta name="assert" content="The zoomed path is hit-tested correctly">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<style>
+  #triangle {
+    width: 100px;
+    height: 100px;
+    background-color: green;
+    clip-path: path(nonzero, 'M0 0, L100 0, L0 100, L 0 0');
+    zoom: 2;
+  }
+</style>
+<div id="triangle"></div>
+<script>
+  test(() => {
+    assert_equals(document.elementFromPoint(20, 20).id, 'triangle')
+    assert_equals(document.elementFromPoint(150, 20).id, 'triangle')
+    assert_equals(document.elementFromPoint(180, 180).tagName, 'BODY')
+  }, 'clip-path: path() hit-test takes zoom into account');
+
+</script>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-masking/clip-path/clip-path-path-with-zoom.html b/third_party/blink/web_tests/external/wpt/css/css-masking/clip-path/clip-path-path-with-zoom.html
new file mode 100644
index 0000000..5879917f
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-masking/clip-path/clip-path-path-with-zoom.html
@@ -0,0 +1,23 @@
+<!DOCTYPE html>
+<title>CSS Masking: Test clip-path property when the page is zoomed</title>
+<link rel="author" title="Noam Rosenthal" href="mailto:noam@webkit.org">
+<link rel="help" href="https://drafts.csswg.org/css-shapes-2/#funcdef-path">
+<link rel="match" href="reference/clip-path-path-with-zoom-ref.html">
+<meta name="assert" content="The path gets zoomed together with the content">
+<style>
+  #red {
+    position: absolute;
+    width: 100px;
+    height: 100px;
+    background: red;
+  }
+  #rect {
+    width: 100px;
+    height: 100px;
+    background-color: green;
+    clip-path: path(nonzero, 'M0 0, L100 0, L0 100, L 0 0');
+    zoom: 2;
+  }
+</style>
+<div id="red"></div>
+<div id="rect"></div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-masking/clip-path/reference/clip-path-path-interpolation-with-zoom-ref.html b/third_party/blink/web_tests/external/wpt/css/css-masking/clip-path/reference/clip-path-path-interpolation-with-zoom-ref.html
new file mode 100644
index 0000000..7e0d2a54
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-masking/clip-path/reference/clip-path-path-interpolation-with-zoom-ref.html
@@ -0,0 +1,12 @@
+<!DOCTYPE html>
+<title>CSS Masking: Test clip-path nonzero path interpolation with zoom</title>
+<style type="text/css">
+  #rect {
+    width: 300px;
+    height: 300px;
+    background-color: green;
+    clip-path: path('M105,105 H270 V270 H105Z M75,75 H210 V210 H75Z');
+  }
+
+</style>
+<div id="rect"></div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-masking/clip-path/reference/clip-path-path-with-zoom-ref.html b/third_party/blink/web_tests/external/wpt/css/css-masking/clip-path/reference/clip-path-path-with-zoom-ref.html
new file mode 100644
index 0000000..ef91c619
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-masking/clip-path/reference/clip-path-path-with-zoom-ref.html
@@ -0,0 +1,13 @@
+<!DOCTYPE html>
+<html>
+  <title>CSS Masking: Test clip-path property when the page is zoomed</title>
+  <style>
+    #rect {
+      width: 200px;
+      height: 200px;
+      background: green;
+      clip-path: path(nonzero, 'M0 0, L200 0, L0 200');
+    }
+  </style>
+  <div id="rect"></div>
+</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-masking/parsing/clip-path-valid-expected.txt b/third_party/blink/web_tests/external/wpt/css/css-masking/parsing/clip-path-valid-expected.txt
index 16463615..60c4fb0 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-masking/parsing/clip-path-valid-expected.txt
+++ b/third_party/blink/web_tests/external/wpt/css/css-masking/parsing/clip-path-valid-expected.txt
@@ -23,11 +23,11 @@
 PASS e.style['clip-path'] = "polygon(1% 2%)" should set the property value
 PASS e.style['clip-path'] = "polygon(nonzero, 1px 2px, 3em 4em)" should set the property value
 PASS e.style['clip-path'] = "polygon(evenodd, 1px 2px, 3em 4em, 5pt 6%)" should set the property value
-FAIL e.style['clip-path'] = "path(\"m 20 0 h -100\")" should set the property value assert_not_equals: property should be set got disallowed value ""
-FAIL e.style['clip-path'] = "path(evenodd, \"M 20 20 h 60 v 60 h -60 Z M 30 30 h 40 v 40 h -40 Z\")" should set the property value assert_not_equals: property should be set got disallowed value ""
-FAIL e.style['clip-path'] = "path(nonzero, \"M20,20h60 v60 h-60z M30,30 h40 v40 h-40z\")" should set the property value assert_not_equals: property should be set got disallowed value ""
-FAIL e.style['clip-path'] = "path(\" \")" should set the property value assert_not_equals: property should be set got disallowed value ""
-FAIL e.style['clip-path'] = "path(evenodd, \"\")" should set the property value assert_not_equals: property should be set got disallowed value ""
+PASS e.style['clip-path'] = "path(\"m 20 0 h -100\")" should set the property value
+PASS e.style['clip-path'] = "path(evenodd, \"M 20 20 h 60 v 60 h -60 Z M 30 30 h 40 v 40 h -40 Z\")" should set the property value
+PASS e.style['clip-path'] = "path(nonzero, \"M20,20h60 v60 h-60z M30,30 h40 v40 h-40z\")" should set the property value
+PASS e.style['clip-path'] = "path(\" \")" should set the property value
+PASS e.style['clip-path'] = "path(evenodd, \"\")" should set the property value
 FAIL e.style['clip-path'] = "border-box" should set the property value assert_not_equals: property should be set got disallowed value ""
 FAIL e.style['clip-path'] = "padding-box" should set the property value assert_not_equals: property should be set got disallowed value ""
 FAIL e.style['clip-path'] = "content-box" should set the property value assert_not_equals: property should be set got disallowed value ""
diff --git a/third_party/blink/web_tests/external/wpt/css/css-sizing/aspect-ratio/small-aspect-ratio-crash.html b/third_party/blink/web_tests/external/wpt/css/css-sizing/aspect-ratio/small-aspect-ratio-crash.html
new file mode 100644
index 0000000..0771254
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-sizing/aspect-ratio/small-aspect-ratio-crash.html
@@ -0,0 +1,5 @@
+<!DOCTYPE html>
+<title>CSS aspect-ratio: Doesn't crash with small but nonzero width/height in ratio</title>
+<link rel="help" href="https://drafts.csswg.org/css-sizing-4/#aspect-ratio">
+<div style="aspect-ratio: 1/0.00000000000001"></div>
+<div style="aspect-ratio: 0.00000000000001/1"></div>
diff --git a/third_party/blink/web_tests/http/tests/fetch/script-tests/fetch_upload.js b/third_party/blink/web_tests/http/tests/fetch/script-tests/fetch_upload.js
index 40d8fb58..9e123d6 100644
--- a/third_party/blink/web_tests/http/tests/fetch/script-tests/fetch_upload.js
+++ b/third_party/blink/web_tests/http/tests/fetch/script-tests/fetch_upload.js
@@ -69,27 +69,57 @@
   return crypto.subtle.digest('SHA-256', array);
 }
 
+function compare(a, b) {
+  if (a.length != b.length)
+    return [false, 'length is not equal'];
+  for (let i = 0; - 1 < i; i -= 1) {
+    if ((a[i] !== b[i]))
+      return [false, `a[${i}](${a[i]}) != b[${i}](${b[i]})`];
+  }
+  return [true, ''];
+}
+
+async function compare_long_array(a, b, description) {
+  const a_hash = await hash256(a);
+  const b_hash = await hash256(b);
+  const [eq, fail_reason] = compare(a_hash, b_hash);
+  if (eq)
+    return;
+
+  const [raw_eq, raw_fail_reason] = compare(a, b);
+  assert_false(raw_eq);
+  assert_(false, description + ': ' + raw_fail_reason);
+}
+
+async function test_echo_long_array(upload_body, expected_array) {
+  const response = await fetch_echo(upload_body);
+  const reader = response.body.getReader();
+  let index = 0;
+  while (index < expected_array.length) {
+    const chunk = await reader.read();
+    assert_false(chunk.done, `chunk.done@${index}/${expected_array.length}`);
+    const chunk_length = chunk.value.length;
+    await compare_long_array(
+        chunk.value, expected_array.subarray(index, index + chunk_length),
+        `Array of [${index}, ${index + chunk_length - 1}] should be same.`);
+    index += chunk_length;
+  }
+  const final_chunk = await reader.read();
+  assert_true(final_chunk.done, 'final_chunk.done');
+}
+
 promise_test(async () => {
   const length = 1000 * 1000;  // 1Mbytes
   const array = random_values_array(length);
   const stream = create_stream([array]);
-  const response = await fetch_echo(stream);
-  const reader = response.body.getReader();
-  let index = 0;
-  while (index < length) {
-    const chunk = await reader.read();
-    assert_false(chunk.done);
-    const chunk_length = chunk.value.length;
-    const chunk_hash = await hash256(chunk.value);
-    const src_hash = await hash256(array.subarray(index, index + chunk_length));
-    assert_array_equals(
-        new Uint8Array(chunk_hash), new Uint8Array(src_hash),
-        `Array of [${index}, ${index + length - 1}] should be same.`);
-    index += chunk_length;
-  }
-  const final_chunk = await reader.read();
-  assert_true(final_chunk.done);
-}, 'Fetch with ReadableStream body with long Uint8Array');
+  await test_echo_long_array(stream, array);
+}, 'Fetch with ReadableStream body with 1Mbytes Uint8Array');
+
+promise_test(async () => {
+  const length = 1000 * 1000;  // 1 Mbytes
+  const array = random_values_array(length);
+  await test_echo_long_array(array, array);
+}, 'Fetch with Array body with 1 Mbytes Uint8Array');
 
 promise_test(async (t) => {
   const stream = create_stream(['Foobar']);
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml
index 452188ed..261c229 100644
--- a/tools/metrics/histograms/enums.xml
+++ b/tools/metrics/histograms/enums.xml
@@ -14176,26 +14176,6 @@
   <int value="3" label="Failed VM Started"/>
 </enum>
 
-<enum name="CrostiniFailureClasses">
-  <int value="0" label="Concierge"/>
-  <int value="1" label="Cicerone"/>
-  <int value="2" label="Seneschal"/>
-  <int value="3" label="Chunneld"/>
-  <int value="4" label="VM hypervisor"/>
-  <int value="5" label="In-VM syslog daemon"/>
-  <int value="6" label="VM ssh daemon"/>
-  <int value="7" label="LXCFS daemon"/>
-  <int value="8" label="Tremplin"/>
-  <int value="9" label="Ndproxyd"/>
-  <int value="10" label="Mcastd"/>
-  <int value="11" label="Lxd"/>
-  <int value="12" label="Garcon"/>
-  <int value="13" label="Sommelier wayland proxy"/>
-  <int value="14" label="Sommelier X11 proxy"/>
-  <int value="15" label="Cros-Sftp"/>
-  <int value="16" label="Cros-Notificationd"/>
-</enum>
-
 <enum name="CrostiniImportContainerResult">
   <int value="0" label="Success"/>
   <int value="1" label="Failed"/>
@@ -22241,6 +22221,7 @@
   <int value="791" label="BrowsingDataLifetime"/>
   <int value="792" label="IntranetRedirectBehavior"/>
   <int value="793" label="LacrosAllowed"/>
+  <int value="794" label="DeviceArcDataSnapshotHours"/>
 </enum>
 
 <enum name="EnterprisePolicyDeviceIdValidity">
@@ -35422,6 +35403,26 @@
   <int value="1" label="Broadcast"/>
 </enum>
 
+<enum name="GuestOsFailureClasses">
+  <int value="0" label="Concierge"/>
+  <int value="1" label="Cicerone"/>
+  <int value="2" label="Seneschal"/>
+  <int value="3" label="Chunneld"/>
+  <int value="4" label="VM hypervisor"/>
+  <int value="5" label="In-VM syslog daemon"/>
+  <int value="6" label="VM ssh daemon"/>
+  <int value="7" label="LXCFS daemon"/>
+  <int value="8" label="Tremplin"/>
+  <int value="9" label="Ndproxyd"/>
+  <int value="10" label="Mcastd"/>
+  <int value="11" label="Lxd"/>
+  <int value="12" label="Garcon"/>
+  <int value="13" label="Sommelier wayland proxy"/>
+  <int value="14" label="Sommelier X11 proxy"/>
+  <int value="15" label="Cros-Sftp"/>
+  <int value="16" label="Cros-Notificationd"/>
+</enum>
+
 <enum name="GwpAsanCrashAnalysisResult">
   <int value="0" label="The crash is not caused by GWP-ASan"/>
   <int value="1" label="The crash is caused by GWP-ASan"/>
@@ -38093,6 +38094,12 @@
              PackageManager"/>
 </enum>
 
+<enum name="InstalledVersionPollType">
+  <int value="0" label="Process startup"/>
+  <int value="1" label="InstalledVersionMonitor notification"/>
+  <int value="2" label="Periodic poll"/>
+</enum>
+
 <enum name="InstallStatus">
   <int value="0" label="FIRST_INSTALL_SUCCESS"/>
   <int value="1" label="INSTALL_REPAIRED"/>
@@ -43836,6 +43843,7 @@
       label="InterestFeedV2ClickAndViewActionsConditionalUpload:disabled"/>
   <int value="288755982"
       label="AutofillEnableLocalCardMigrationForNonSyncUser:enabled"/>
+  <int value="289465857" label="ClipboardHistorySimpleRender:disabled"/>
   <int value="291389947" label="PercentBasedScrolling:disabled"/>
   <int value="291482671" label="ExperimentalFlingAnimation:disabled"/>
   <int value="291866104" label="WebAuthenticationPhoneSupport:enabled"/>
@@ -44883,6 +44891,7 @@
   <int value="1325459977" label="HandwritingGestureEditing:disabled"/>
   <int value="1327883321"
       label="OmniboxHistoryQuickProviderAllowMidwordContinuations:enabled"/>
+  <int value="1327928774" label="ClipboardHistorySimpleRender:enabled"/>
   <int value="1330264457" label="OmniboxUIExperimentVerticalLayout:disabled"/>
   <int value="1331098784" label="ReducedReferrerGranularity:enabled"/>
   <int value="1331513360" label="SafetyCheckAndroid:disabled"/>
diff --git a/tools/metrics/histograms/histograms_index.txt b/tools/metrics/histograms/histograms_index.txt
index b7148793..a60f353 100644
--- a/tools/metrics/histograms/histograms_index.txt
+++ b/tools/metrics/histograms/histograms_index.txt
@@ -12,6 +12,7 @@
 tools/metrics/histograms/histograms_xml/background/histograms.xml
 tools/metrics/histograms/histograms_xml/blink/histograms.xml
 tools/metrics/histograms/histograms_xml/bluetooth/histograms.xml
+tools/metrics/histograms/histograms_xml/borealis/histograms.xml
 tools/metrics/histograms/histograms_xml/browser/histograms.xml
 tools/metrics/histograms/histograms_xml/chrome/histograms.xml
 tools/metrics/histograms/histograms_xml/chromeos/histograms.xml
diff --git a/tools/metrics/histograms/histograms_xml/borealis/histograms.xml b/tools/metrics/histograms/histograms_xml/borealis/histograms.xml
new file mode 100644
index 0000000..169d6a35
--- /dev/null
+++ b/tools/metrics/histograms/histograms_xml/borealis/histograms.xml
@@ -0,0 +1,36 @@
+<!--
+Copyright 2020 The Chromium Authors. All rights reserved.
+Use of this source code is governed by a BSD-style license that can be
+found in the LICENSE file.
+-->
+
+<!--
+This file is used to generate a comprehensive list of Borealis histograms
+along with a detailed description for each histogram.
+
+For best practices on writing histogram descriptions, see
+https://chromium.googlesource.com/chromium/src.git/+/HEAD/tools/metrics/histograms/README.md
+
+Please send CLs to chromium-metrics-reviews@google.com rather than to specific
+individuals. These CLs will be automatically reassigned to a reviewer within
+about 5 minutes. This approach helps the metrics team to load-balance incoming
+reviews. Googlers can read more about this at go/gwsq-gerrit.
+-->
+
+<histogram-configuration>
+
+<histograms>
+
+<histogram name="Borealis.Stability" enum="GuestOsFailureClasses"
+    expires_after="2021-10-09">
+  <owner>cpelling@google.com</owner>
+  <summary>
+    A record of post-startup failures in Borealis components. Buckets are
+    recorded to when we become aware that the corresponding component has
+    failed.
+  </summary>
+</histogram>
+
+</histograms>
+
+</histogram-configuration>
diff --git a/tools/metrics/histograms/histograms_xml/chromeos/histograms.xml b/tools/metrics/histograms/histograms_xml/chromeos/histograms.xml
index 17bc808..6ccc73e 100644
--- a/tools/metrics/histograms/histograms_xml/chromeos/histograms.xml
+++ b/tools/metrics/histograms/histograms_xml/chromeos/histograms.xml
@@ -499,7 +499,7 @@
 </histogram>
 
 <histogram name="ChromeOS.SAML.SamlChallengeKeyHandlerResult"
-    enum="SamlChallengeKeyHandlerResult" expires_after="2020-12-01">
+    enum="SamlChallengeKeyHandlerResult" expires_after="2021-06-01">
   <owner>miersh@google.com</owner>
   <owner>pmarko@chromium.org</owner>
   <summary>
diff --git a/tools/metrics/histograms/histograms_xml/crostini/histograms.xml b/tools/metrics/histograms/histograms_xml/crostini/histograms.xml
index b39ba3b..9514b53 100644
--- a/tools/metrics/histograms/histograms_xml/crostini/histograms.xml
+++ b/tools/metrics/histograms/histograms_xml/crostini/histograms.xml
@@ -316,7 +316,7 @@
   </summary>
 </histogram>
 
-<histogram name="Crostini.Stability" enum="CrostiniFailureClasses"
+<histogram name="Crostini.Stability" enum="GuestOsFailureClasses"
     expires_after="2021-06-09">
   <owner>clumptini@google.com</owner>
   <owner>tbuckley@chromium.org</owner>
diff --git a/tools/metrics/histograms/histograms_xml/histogram_suffixes_list.xml b/tools/metrics/histograms/histograms_xml/histogram_suffixes_list.xml
index 721136b2..814a018 100644
--- a/tools/metrics/histograms/histograms_xml/histogram_suffixes_list.xml
+++ b/tools/metrics/histograms/histograms_xml/histogram_suffixes_list.xml
@@ -14095,6 +14095,9 @@
 </histogram_suffixes>
 
 <histogram_suffixes name="PpapiPluginName" separator="_">
+  <obsolete>
+    Removed Oct 14 2020.
+  </obsolete>
   <suffix name="libpepflashplayer.so" label="Flash player on Linux or Cros"/>
   <suffix name="libwidevinecdmadapter.so" label="Widevine CDM on Linux or Cros">
     <obsolete>
diff --git a/tools/metrics/histograms/histograms_xml/others/histograms.xml b/tools/metrics/histograms/histograms_xml/others/histograms.xml
index c42b419e..021a71c5 100644
--- a/tools/metrics/histograms/histograms_xml/others/histograms.xml
+++ b/tools/metrics/histograms/histograms_xml/others/histograms.xml
@@ -15601,6 +15601,17 @@
   </summary>
 </histogram>
 
+<histogram name="UpgradeDetector.PollType" enum="InstalledVersionPollType"
+    expires_after="M89">
+  <owner>grt@chromium.org</owner>
+  <owner>ydago@chromium.org</owner>
+  <summary>
+    Records the type of poll that first detected an installed version change.
+    Note that a browser that is running while multiple updates are applied will
+    only record this metric once.
+  </summary>
+</histogram>
+
 <histogram name="UpgradeDetector.RollbackReason"
     enum="UpgradeDetectorRollbackReason" expires_after="2021-01-01">
   <owner>mpolzer@google.com</owner>
diff --git a/tools/metrics/histograms/histograms_xml/plugin/histograms.xml b/tools/metrics/histograms/histograms_xml/plugin/histograms.xml
index 43be6034..b3dddbd 100644
--- a/tools/metrics/histograms/histograms_xml/plugin/histograms.xml
+++ b/tools/metrics/histograms/histograms_xml/plugin/histograms.xml
@@ -44,6 +44,9 @@
 
 <histogram name="Plugin.PpapiBrokerLoadErrorCode" enum="WinGetLastError"
     expires_after="M88">
+  <obsolete>
+    Deprecated Oct 14 2020.
+  </obsolete>
   <owner>xhwang@chromium.org</owner>
   <owner>media-dev@chromium.org</owner>
   <summary>
@@ -53,12 +56,18 @@
 
 <histogram name="Plugin.PpapiBrokerLoadResult" enum="PluginLoadResult"
     expires_after="M88">
+  <obsolete>
+    Deprecated Oct 14 2020.
+  </obsolete>
   <owner>xhwang@chromium.org</owner>
   <owner>media-dev@chromium.org</owner>
   <summary>The result from an attempt to load a PPAPI broker.</summary>
 </histogram>
 
 <histogram name="Plugin.PpapiBrokerLoadTime" units="ms" expires_after="M88">
+  <obsolete>
+    Deprecated Oct 14 2020.
+  </obsolete>
   <owner>xhwang@chromium.org</owner>
   <owner>media-dev@chromium.org</owner>
   <summary>The time spent to load a PPAPI broker.</summary>
@@ -66,6 +75,9 @@
 
 <histogram name="Plugin.PpapiPluginLoadErrorCode" enum="WinGetLastError"
     expires_after="M88">
+  <obsolete>
+    Deprecated Oct 14 2020.
+  </obsolete>
   <owner>xhwang@chromium.org</owner>
   <owner>media-dev@chromium.org</owner>
   <summary>
@@ -75,12 +87,18 @@
 
 <histogram name="Plugin.PpapiPluginLoadResult" enum="PluginLoadResult"
     expires_after="M88">
+  <obsolete>
+    Deprecated Oct 14 2020.
+  </obsolete>
   <owner>xhwang@chromium.org</owner>
   <owner>media-dev@chromium.org</owner>
   <summary>The result from an attempt to load a PPAPI plugin.</summary>
 </histogram>
 
 <histogram name="Plugin.PpapiPluginLoadTime" units="ms" expires_after="M88">
+  <obsolete>
+    Deprecated Oct 14 2020.
+  </obsolete>
   <owner>xhwang@chromium.org</owner>
   <owner>media-dev@chromium.org</owner>
   <summary>The time spent to load a PPAPI plugin.</summary>
diff --git a/tools/perf/cli_tools/validate_tbmv3_metric/validate_tbmv3_metric.py b/tools/perf/cli_tools/validate_tbmv3_metric/validate_tbmv3_metric.py
index 7361ac9..b558a64 100644
--- a/tools/perf/cli_tools/validate_tbmv3_metric/validate_tbmv3_metric.py
+++ b/tools/perf/cli_tools/validate_tbmv3_metric/validate_tbmv3_metric.py
@@ -60,7 +60,8 @@
                       default=None,
                       help=('Path to a csv file containing links to HTML '
                             'traces in CloudStorage in chrome-telemetry-output '
-                            'bucket. '
+                            'bucket. Go to go/get-tbm-traces and follow '
+                            'instructions there to generate the CSV. '
                             'Default: {--traces-dir}/trace_links.csv'))
   parser.add_argument('--trace-processor-path',
                       type=str,
@@ -78,6 +79,8 @@
   trace_link_extension = os.path.splitext(trace_link)[1]
   if trace_link.startswith('/'):
     trace_link = trace_link[1:]
+  if not os.path.exists(traces_dir):
+    os.mkdir(traces_dir, 0755)
   with tempfile.NamedTemporaryFile(dir=traces_dir,
                                    suffix='_trace%s' % trace_link_extension,
                                    delete=False) as trace_file:
@@ -88,15 +91,6 @@
     return trace_file.name
 
 
-def GSLinkExists(link):
-  try:
-    cloud_storage.List(cloud_storage.TELEMETRY_OUTPUT, link)
-    return True
-  except Exception, e:
-    logging.info('GS link %s does not exist: %s' % (link, str(e)))
-    return False
-
-
 def GetProtoTraceLinkFromTraceEventsDir(link_prefix):
   proto_link_prefix = '/'.join([link_prefix, 'trace/traceEvents/**'])
   proto_link = None
@@ -111,7 +105,7 @@
     raise cloud_storage.NotFoundError(
         'Proto trace link not found in cloud storage. Path: %s.' %
         proto_link_prefix)
-  except Exception, e:
+  except cloud_storage.NotFoundError, e:
     raise cloud_storage.NotFoundError('No URLs match the prefix %s: %s' %
                                       (proto_link_prefix, str(e)))
 
@@ -140,31 +134,23 @@
   retry_0/trace/traceEvents/tmpTq5XNv.pb.gz
   """
   html_link_suffix = '/trace.html'
-  assert http_link.endswith(
-      html_link_suffix), ('Link passed to ParseGSLinksFromHTTPLink is invalid. '
-                          'The link must end with "%s".') % html_link_suffix
+  assert http_link.endswith(html_link_suffix), (
+      'Link passed to ParseGSLinksFromHTTPLink ("%s") is '
+      ' invalid. The link must end with "%s".') % (http_link, html_link_suffix)
 
   html_link = http_link.split('/o/')[1]
-  if not GSLinkExists(html_link):
+  if not cloud_storage.Exists(cloud_storage.TELEMETRY_OUTPUT, html_link):
     raise cloud_storage.NotFoundError(
         'HTML trace link %s not found in cloud storage.' % html_link)
 
   proto_link = os.path.splitext(html_link)[0] + '.pb'
 
-  if not GSLinkExists(proto_link):
+  if not cloud_storage.Exists(cloud_storage.TELEMETRY_OUTPUT, proto_link):
     link_prefix = html_link[:-len(html_link_suffix)]
     proto_link = GetProtoTraceLinkFromTraceEventsDir(link_prefix)
   return html_link, proto_link
 
 
-def ParseBotFromTestName(test_name):
-  return test_name.split('/')[1]
-
-
-def ParseBenchmarkFromMeasurement(measurement):
-  return measurement.split('/')[0]
-
-
 def RunTBMv2Metric(tbmv2_name, html_trace_filename, traces_dir):
   metrics = [tbmv2_name]
   TEN_MINUTES = 60 * 10
@@ -214,11 +200,10 @@
   return sorted(sample_values)
 
 
-def CalculateTBMv3Metric(tbmv3_name, tbmv3_histogram, tbmv3_json_filename):
+def CalculateTBMv3Metric(tbmv3_histogram, tbmv3_json_filename):
   # TODO(crbug.com/1128919): Add conversion of sample values based on their
   # units.
-  return GetSortedSampleValuesFromJson('%s::%s' % (tbmv3_name, tbmv3_histogram),
-                                       tbmv3_json_filename)
+  return GetSortedSampleValuesFromJson(tbmv3_histogram, tbmv3_json_filename)
 
 
 def CalculateTBMv2Metric(tbmv2_histogram, tbmv2_json_filename):
@@ -232,15 +217,15 @@
   debug_info_for_failed_comparisons = []
 
   for trace_info in reader:
-    bot = ParseBotFromTestName(trace_info['test'])
-    benchmark = ParseBenchmarkFromMeasurement(trace_info['measurement'])
-    html_link, proto_link = ParseGSLinksFromHTTPLink(trace_info['trace_link'])
+    bot = trace_info['Bot']
+    benchmark = trace_info['Benchmark']
+    html_link, proto_link = ParseGSLinksFromHTTPLink(trace_info['Trace Link'])
     html_trace = DownloadTraceFile(html_link, args.traces_dir)
     proto_trace = DownloadTraceFile(proto_link, args.traces_dir)
     tbmv3_out_filename = RunTBMv3Metric(args.tbmv3_name, proto_trace,
                                         args.traces_dir,
                                         args.trace_processor_path)
-    tbmv3_metric = CalculateTBMv3Metric(args.tbmv3_name, args.tbmv3_histogram,
+    tbmv3_metric = CalculateTBMv3Metric(args.tbmv3_histogram,
                                         tbmv3_out_filename)
     tbmv2_out_filename = RunTBMv2Metric(args.tbmv2_name, html_trace,
                                         args.traces_dir)
diff --git a/tools/win/DebugVisualizers/README.md b/tools/win/DebugVisualizers/README.md
new file mode 100644
index 0000000..c9859c01
--- /dev/null
+++ b/tools/win/DebugVisualizers/README.md
@@ -0,0 +1,59 @@
+This directory contains "natvis" (Native Visualization) files,
+that provide custom views in the Visual Studio debugger.
+The official Natvis documentation is located at
+[Create custom views of C++ objects in the debugger using the Natvis
+framework](https://docs.microsoft.com/en-us/visualstudio/debugger/create-custom-views-of-native-objects).
+
+We have not found a good way to automate testing these files.
+The following process is recommended before updating these files.
+
+## Preparations
+
+These files are embedded in `.lib`, `.dll`, or `.exe` so that the debugger can
+use them without referring to the original `.natvis` files.
+
+When you edit them, you can run a full build to update all of them, but
+following steps will help to avoid the full build, and to benefit from Visual
+Studio's dynamic reloading feature.
+
+1. Comment out the `.natvis` you want to edit in `BUILD.gn`. You can find them
+by [Chromium Code Search](https://source.chromium.org/search?q=.natvis%20file:BUILD.gn&ss=chromium).
+2. Create a directory "`Visual Studio 2019\Visualizers`" in your Documents
+folder if it does not exist.
+3. Copy the `.natvis` files you want to edit to the directory.
+
+With these steps done, if you save the `.natvis` files in your Documents folder
+while you are debugging, Visual Studio will automatically reload them, run
+diagnostic and show messages to Output window if any, and update
+Auto/Local/Watch windows without stopping the current debug session.
+
+## Diagnostic
+
+1. Go to Tools - Options, Debugging, Output Window.
+Select "Warning" for "Natvis diagnostic messages (C++ only)".
+
+With this set, Visual Studio shows diagnostic warning and error messages to the
+Output window when it reads `.natvis` files.
+
+## Testing
+
+It is recommended to do at least following tests before updating these files.
+
+1. Enable the diagnostic warnings above.
+2. Start the debugger and break somewhere where you can watch variables of the
+types you're interested.
+3. Check the Output window and verify that there are no errors or warnings for
+the files you edit.
+4. Check the types you modified are displayed correctly in Auto/Local/Watch
+windows.
+5. If the type has `Condition` or `IncludeView` attributes, they are like
+"if"-statements. Please make sure that your test function exercises all
+conditions and views.
+
+If there is not a good test that uses the variables of interest then a test
+should be created. It can be a test that does nothing except declare the
+variables of interest (using base::debug::Alias to prevent them from being
+optimized away). Whether it is a new or existing test it should be listed in the
+commit message to aid reviewers in doing an actual verification that the changes
+work. As an example, consider `TEST(ValuesTest, TakeList)` which is very helpful
+for testing `base::Value visualizers`.
\ No newline at end of file
diff --git a/ui/base/dragdrop/os_exchange_data_provider.h b/ui/base/dragdrop/os_exchange_data_provider.h
index ccd29e06..e6529cf8 100644
--- a/ui/base/dragdrop/os_exchange_data_provider.h
+++ b/ui/base/dragdrop/os_exchange_data_provider.h
@@ -71,7 +71,7 @@
   virtual bool HasFile() const = 0;
   virtual bool HasCustomFormat(const ClipboardFormatType& format) const = 0;
 
-#if defined(OS_LINUX) || defined(OS_WIN)
+#if defined(OS_LINUX) || defined(OS_CHROMEOS) || defined(OS_WIN)
   virtual void SetFileContents(const base::FilePath& filename,
                                const std::string& file_contents) = 0;
 #endif
diff --git a/ui/base/dragdrop/os_exchange_data_provider_non_backed.cc b/ui/base/dragdrop/os_exchange_data_provider_non_backed.cc
index 4b06044..9d5cb80 100644
--- a/ui/base/dragdrop/os_exchange_data_provider_non_backed.cc
+++ b/ui/base/dragdrop/os_exchange_data_provider_non_backed.cc
@@ -84,14 +84,14 @@
 }
 
 bool OSExchangeDataProviderNonBacked::GetString(base::string16* data) const {
-#if defined(OS_LINUX)
+#if defined(OS_LINUX) || defined(OS_CHROMEOS)
   if (HasFile()) {
     // Various Linux file managers both pass a list of file:// URIs and set the
     // string representation to the URI. We explicitly don't want to return use
     // this representation.
     return false;
   }
-#endif  // defined(OS_LINUX)
+#endif  // defined(OS_LINUX) || defined(OS_CHROMEOS)
 
   if ((formats_ & OSExchangeData::STRING) == 0)
     return false;
@@ -168,7 +168,7 @@
   return base::Contains(pickle_data_, format);
 }
 
-#if defined(OS_LINUX)
+#if defined(OS_LINUX) || defined(OS_CHROMEOS)
 void OSExchangeDataProviderNonBacked::SetFileContents(
     const base::FilePath& filename,
     const std::string& file_contents) {
diff --git a/ui/base/dragdrop/os_exchange_data_provider_non_backed.h b/ui/base/dragdrop/os_exchange_data_provider_non_backed.h
index ac3b068..201aa5c 100644
--- a/ui/base/dragdrop/os_exchange_data_provider_non_backed.h
+++ b/ui/base/dragdrop/os_exchange_data_provider_non_backed.h
@@ -59,7 +59,7 @@
   bool HasURL(FilenameToURLPolicy policy) const override;
   bool HasFile() const override;
   bool HasCustomFormat(const ClipboardFormatType& format) const override;
-#if defined(OS_LINUX)
+#if defined(OS_LINUX) || defined(OS_CHROMEOS)
   void SetFileContents(const base::FilePath& filename,
                        const std::string& file_contents) override;
 #endif
diff --git a/ui/ozone/platform/wayland/ozone_platform_wayland.cc b/ui/ozone/platform/wayland/ozone_platform_wayland.cc
index 9e14654..14ca3fa 100644
--- a/ui/ozone/platform/wayland/ozone_platform_wayland.cc
+++ b/ui/ozone/platform/wayland/ozone_platform_wayland.cc
@@ -190,7 +190,7 @@
 
     menu_utils_ = std::make_unique<WaylandMenuUtils>(connection_.get());
 
-    // TODO(crbug.com/1097007): report which Wayland compositor is used.
+    // TODO(crbug.com/1138740): report which Wayland compositor is used.
   }
 
   void InitializeGPU(const InitParams& args) override {
diff --git a/ui/views/widget/desktop_aura/x11_topmost_window_finder_interactive_uitest.cc b/ui/views/widget/desktop_aura/x11_topmost_window_finder_interactive_uitest.cc
index 515cf7b..7bac6d2 100644
--- a/ui/views/widget/desktop_aura/x11_topmost_window_finder_interactive_uitest.cc
+++ b/ui/views/widget/desktop_aura/x11_topmost_window_finder_interactive_uitest.cc
@@ -380,7 +380,7 @@
 
 // Test that setting a Null shape removes the shape.
 // crbug.com/955316: flaky on Linux
-#if defined(OS_LINUX)
+#if defined(OS_LINUX) || defined(OS_CHROMEOS)
 #define MAYBE_NonRectangularNullShape DISABLED_NonRectangularNullShape
 #else
 #define MAYBE_NonRectangularNullShape NonRectangularNullShape
diff --git a/weblayer/BUILD.gn b/weblayer/BUILD.gn
index 63e972a..be8d517 100644
--- a/weblayer/BUILD.gn
+++ b/weblayer/BUILD.gn
@@ -139,6 +139,10 @@
     "app/main.cc",
     "browser/autofill_client_impl.cc",
     "browser/autofill_client_impl.h",
+    "browser/background_sync/background_sync_controller_factory.cc",
+    "browser/background_sync/background_sync_controller_factory.h",
+    "browser/background_sync/background_sync_delegate_impl.cc",
+    "browser/background_sync/background_sync_delegate_impl.h",
     "browser/browser_context_impl.cc",
     "browser/browser_context_impl.h",
     "browser/browser_impl.cc",
@@ -357,6 +361,7 @@
     "//components/autofill/content/renderer",
     "//components/autofill/core/browser",
     "//components/autofill/core/common",
+    "//components/background_sync",
     "//components/base32",
     "//components/blocked_content",
     "//components/browsing_data/content",
diff --git a/weblayer/browser/DEPS b/weblayer/browser/DEPS
index fe3b8f3b..7387737 100644
--- a/weblayer/browser/DEPS
+++ b/weblayer/browser/DEPS
@@ -5,6 +5,7 @@
   "+components/autofill/content/common",
   "+components/autofill/core/browser",
   "+components/autofill/core/common",
+  "+components/background_sync",
   "+components/base32",
   "+components/blocked_content",
   "+components/browsing_data/content",
diff --git a/weblayer/browser/background_sync/background_sync_browsertest.cc b/weblayer/browser/background_sync/background_sync_browsertest.cc
new file mode 100644
index 0000000..c9ec64f6
--- /dev/null
+++ b/weblayer/browser/background_sync/background_sync_browsertest.cc
@@ -0,0 +1,120 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/run_loop.h"
+#include "base/time/time.h"
+#include "build/build_config.h"
+#include "components/background_sync/background_sync_controller_impl.h"
+#include "components/content_settings/core/browser/host_content_settings_map.h"
+#include "components/content_settings/core/common/content_settings.h"
+#include "content/public/browser/background_sync_parameters.h"
+#include "weblayer/browser/background_sync/background_sync_controller_factory.h"
+#include "weblayer/browser/background_sync/background_sync_delegate_impl.h"
+#include "weblayer/browser/host_content_settings_map_factory.h"
+#include "weblayer/test/weblayer_browser_test.h"
+
+namespace {
+const char kExampleUrl[] = "https://www.example.com/";
+const char kTag[] = "test_tag";
+}  // namespace
+namespace weblayer {
+
+class BackgroundSyncBrowserTest : public WebLayerBrowserTest {};
+
+IN_PROC_BROWSER_TEST_F(BackgroundSyncBrowserTest, GetBackgroundSyncController) {
+  EXPECT_TRUE(BackgroundSyncControllerFactory::GetForBrowserContext(
+      GetBrowserContext()));
+}
+
+IN_PROC_BROWSER_TEST_F(BackgroundSyncBrowserTest, ZeroSiteEngagementPenalty) {
+  // TODO(crbug.com/1091211): Update when we add support for Periodic Background
+  // Sync.
+  auto* controller = BackgroundSyncControllerFactory::GetForBrowserContext(
+      GetBrowserContext());
+  ASSERT_TRUE(controller);
+
+  url::Origin origin = url::Origin::Create(GURL(kExampleUrl));
+  content::BackgroundSyncRegistration registration;
+  registration.set_origin(origin);
+
+  // min interval >=0 implies Periodic Background Sync.
+  blink::mojom::SyncRegistrationOptions options(
+      kTag,
+      /* min_interval= */ base::TimeDelta::FromHours(12).InMilliseconds());
+  *registration.options() = std::move(options);
+  // First attempt.
+  registration.set_num_attempts(0);
+
+  content::BackgroundSyncParameters parameters;
+
+  base::TimeDelta delay = controller->GetNextEventDelay(
+      registration, &parameters,
+      /* time_till_soonest_scheduled_event_for_origin= */
+      base::TimeDelta::Max());
+  EXPECT_EQ(delay, base::TimeDelta::Max());
+}
+
+#if defined(OS_ANDROID)
+IN_PROC_BROWSER_TEST_F(BackgroundSyncBrowserTest, BackgroundSyncNotDisabled) {
+  auto* controller = BackgroundSyncControllerFactory::GetForBrowserContext(
+      GetBrowserContext());
+  ASSERT_TRUE(controller);
+
+  // TODO(crbug.com/1087486, 1091211): Update logic here if we need to support
+  // Android L when we add browser wakeup logic.
+  content::BackgroundSyncParameters parameters;
+  controller->GetParameterOverrides(&parameters);
+  EXPECT_FALSE(parameters.disable);
+}
+#endif  // defined (OS_ANDROID)
+
+IN_PROC_BROWSER_TEST_F(BackgroundSyncBrowserTest, ContentSettings) {
+  auto* browser_context = GetBrowserContext();
+  auto* controller =
+      BackgroundSyncControllerFactory::GetForBrowserContext(browser_context);
+  ASSERT_TRUE(controller);
+
+  url::Origin origin = url::Origin::Create(GURL(kExampleUrl));
+  controller->AddToTrackedOrigins(origin);
+  ASSERT_TRUE(controller->IsOriginTracked(origin));
+
+  auto* host_content_settings_map =
+      HostContentSettingsMapFactory::GetForBrowserContext(browser_context);
+  ASSERT_TRUE(host_content_settings_map);
+
+  host_content_settings_map->SetContentSettingDefaultScope(
+      /* primary_url= */ GURL(kExampleUrl),
+      /* secondary_url= */ GURL(kExampleUrl),
+      ContentSettingsType::BACKGROUND_SYNC,
+      /* resource_identifier= */ std::string(), CONTENT_SETTING_BLOCK);
+  base::RunLoop().RunUntilIdle();
+  EXPECT_FALSE(controller->IsOriginTracked(origin));
+}
+
+IN_PROC_BROWSER_TEST_F(BackgroundSyncBrowserTest, NormalProfile) {
+  // TODO(crbug.com/1087486, 1091211): Make this use
+  // BackgroundSyncController::ScheduleBrowserWakeup() once we support waking
+  // the browser up.
+  auto delegate =
+      std::make_unique<BackgroundSyncDelegateImpl>(GetBrowserContext());
+  ASSERT_TRUE(delegate);
+  EXPECT_FALSE(delegate->IsProfileOffTheRecord());
+}
+
+class IncognitoBackgroundSyncBrowserTest : public BackgroundSyncBrowserTest {
+ public:
+  IncognitoBackgroundSyncBrowserTest() { SetShellStartsInIncognitoMode(); }
+};
+
+IN_PROC_BROWSER_TEST_F(IncognitoBackgroundSyncBrowserTest,
+                       OffTheRecordProfile) {
+  // TODO(crbug.com/1087486, 1091211): Make this use
+  // BackgroundSyncController::ScheduleBrowserWakeup() once we support waking
+  // the browser up.
+  auto delegate =
+      std::make_unique<BackgroundSyncDelegateImpl>(GetBrowserContext());
+  EXPECT_TRUE(delegate->IsProfileOffTheRecord());
+}
+
+}  // namespace weblayer
\ No newline at end of file
diff --git a/weblayer/browser/background_sync/background_sync_controller_factory.cc b/weblayer/browser/background_sync/background_sync_controller_factory.cc
new file mode 100644
index 0000000..8745490a
--- /dev/null
+++ b/weblayer/browser/background_sync/background_sync_controller_factory.cc
@@ -0,0 +1,54 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "weblayer/browser/background_sync/background_sync_controller_factory.h"
+
+#include "components/background_sync/background_sync_controller_impl.h"
+#include "components/keyed_service/content/browser_context_dependency_manager.h"
+#include "weblayer/browser/background_sync/background_sync_delegate_impl.h"
+#include "weblayer/browser/host_content_settings_map_factory.h"
+
+namespace weblayer {
+
+// static
+BackgroundSyncControllerImpl*
+BackgroundSyncControllerFactory::GetForBrowserContext(
+    content::BrowserContext* browser_context) {
+  // This is safe because BuildServiceInstanceFor(), which this method calls,
+  // returns a pointer to a BackgroundSyncControllerImpl object.
+  return static_cast<BackgroundSyncControllerImpl*>(
+      GetInstance()->GetServiceForBrowserContext(browser_context, true));
+}
+
+// static
+BackgroundSyncControllerFactory*
+BackgroundSyncControllerFactory::GetInstance() {
+  static base::NoDestructor<BackgroundSyncControllerFactory> factory;
+  return factory.get();
+}
+
+BackgroundSyncControllerFactory::BackgroundSyncControllerFactory()
+    : BrowserContextKeyedServiceFactory(
+          "BackgroundSyncService",
+          BrowserContextDependencyManager::GetInstance()) {
+  DependsOn(HostContentSettingsMapFactory::GetInstance());
+}
+
+BackgroundSyncControllerFactory::~BackgroundSyncControllerFactory() = default;
+
+KeyedService* BackgroundSyncControllerFactory::BuildServiceInstanceFor(
+    content::BrowserContext* context) const {
+  return new BackgroundSyncControllerImpl(
+      context, std::make_unique<BackgroundSyncDelegateImpl>(context));
+}
+
+content::BrowserContext*
+BackgroundSyncControllerFactory::GetBrowserContextToUse(
+    content::BrowserContext* context) const {
+  // Background sync operates in incognito mode, and as incognito profiles in
+  // Weblayer are not tied to regular profiles, return |context| itself.
+  return context;
+}
+
+}  // namespace weblayer
diff --git a/weblayer/browser/background_sync/background_sync_controller_factory.h b/weblayer/browser/background_sync/background_sync_controller_factory.h
new file mode 100644
index 0000000..b04f8e9
--- /dev/null
+++ b/weblayer/browser/background_sync/background_sync_controller_factory.h
@@ -0,0 +1,47 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef WEBLAYER_BROWSER_BACKGROUND_SYNC_BACKGROUND_SYNC_CONTROLLER_FACTORY_H_
+#define WEBLAYER_BROWSER_BACKGROUND_SYNC_BACKGROUND_SYNC_CONTROLLER_FACTORY_H_
+
+#include "base/no_destructor.h"
+#include "components/keyed_service/content/browser_context_keyed_service_factory.h"
+
+class BackgroundSyncControllerImpl;
+
+namespace content {
+class BrowserContext;
+}
+
+namespace weblayer {
+
+// Creates and maintains a BackgroundSyncController instance per BrowserContext.
+class BackgroundSyncControllerFactory
+    : public BrowserContextKeyedServiceFactory {
+ public:
+  static BackgroundSyncControllerImpl* GetForBrowserContext(
+      content::BrowserContext* browser_context);
+  static BackgroundSyncControllerFactory* GetInstance();
+
+  BackgroundSyncControllerFactory(const BackgroundSyncControllerFactory&) =
+      delete;
+  BackgroundSyncControllerFactory& operator=(
+      const BackgroundSyncControllerFactory&) = delete;
+
+ private:
+  friend class base::NoDestructor<BackgroundSyncControllerFactory>;
+
+  BackgroundSyncControllerFactory();
+  ~BackgroundSyncControllerFactory() override;
+
+  // BrowserContextKeyedServiceFactory methods:
+  KeyedService* BuildServiceInstanceFor(
+      content::BrowserContext* context) const override;
+  content::BrowserContext* GetBrowserContextToUse(
+      content::BrowserContext* context) const override;
+};
+
+}  // namespace weblayer
+
+#endif  // WEBLAYER_BROWSER_BACKGROUND_SYNC_BACKGROUND_SYNC_CONTROLLER_FACTORY_H_
diff --git a/weblayer/browser/background_sync/background_sync_delegate_impl.cc b/weblayer/browser/background_sync/background_sync_delegate_impl.cc
new file mode 100644
index 0000000..f8624db3
--- /dev/null
+++ b/weblayer/browser/background_sync/background_sync_delegate_impl.cc
@@ -0,0 +1,92 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "weblayer/browser/background_sync/background_sync_delegate_impl.h"
+
+#include "base/metrics/ukm_source_id.h"
+#include "build/build_config.h"
+#include "content/public/browser/browser_context.h"
+#include "content/public/browser/web_contents.h"
+#include "services/metrics/public/cpp/ukm_recorder.h"
+#include "services/metrics/public/cpp/ukm_source_id.h"
+#include "weblayer/browser/host_content_settings_map_factory.h"
+
+namespace weblayer {
+
+BackgroundSyncDelegateImpl::BackgroundSyncDelegateImpl(
+    content::BrowserContext* browser_context)
+    : browser_context_(browser_context) {
+  DCHECK(browser_context_);
+}
+
+BackgroundSyncDelegateImpl::~BackgroundSyncDelegateImpl() = default;
+
+void BackgroundSyncDelegateImpl::GetUkmSourceId(
+    const url::Origin& origin,
+    base::OnceCallback<void(base::Optional<ukm::SourceId>)> callback) {
+  // The exact URL which registered the Background Sync event is not saved,
+  // and the current main frame URL might not correspond to |origin|. Thus, we
+  // associate a new source ID with the origin.
+  // The only way WebLayer can lose history information is through the
+  // clearBrowsingHistory() API which also deletes all existing service workers.
+  // Therefore, if this method is called, it's safe to assume that the origin
+  // associated with the Background Sync registration is in WebLayer's browsing
+  // history. It's okay to log UKM for it.
+  ukm::SourceId source_id = ukm::ConvertToSourceId(
+      ukm::AssignNewSourceId(), ukm::SourceIdType::HISTORY_ID);
+  ukm::UkmRecorder* recorder = ukm::UkmRecorder::Get();
+  DCHECK(recorder);
+  recorder->UpdateSourceURL(source_id, origin.GetURL());
+
+  std::move(callback).Run(source_id);
+}
+
+void BackgroundSyncDelegateImpl::Shutdown() {
+  // Clear the BrowserContext as we're not supposed to use it anymore.
+  browser_context_ = nullptr;
+}
+
+HostContentSettingsMap*
+BackgroundSyncDelegateImpl::GetHostContentSettingsMap() {
+  return HostContentSettingsMapFactory::GetForBrowserContext(browser_context_);
+}
+
+bool BackgroundSyncDelegateImpl::IsProfileOffTheRecord() {
+  DCHECK(browser_context_);
+  return browser_context_->IsOffTheRecord();
+}
+
+void BackgroundSyncDelegateImpl::NoteSuspendedPeriodicSyncOrigins(
+    std::set<url::Origin> suspended_origins) {
+  // TODO(crbug.com/1091211): Consider site engagement when adding support for
+  // Periodic Background Sync.
+}
+
+int BackgroundSyncDelegateImpl::GetSiteEngagementPenalty(const GURL& url) {
+  // TODO(crbug.com/1091211): Consider site engagement when adding support for
+  // Periodic Background Sync.
+  return 0;
+}
+
+#if defined(OS_ANDROID)
+
+void BackgroundSyncDelegateImpl::ScheduleBrowserWakeUpWithDelay(
+    blink::mojom::BackgroundSyncType sync_type,
+    base::TimeDelta delay) {
+  // TODO(crbug.com/1087486, 1091211): Add logic to wake up the browser.
+}
+
+void BackgroundSyncDelegateImpl::CancelBrowserWakeup(
+    blink::mojom::BackgroundSyncType sync_type) {
+  // TODO(crbug.com/1087486, 1091211): Add logic to wake up the browser.
+}
+
+bool BackgroundSyncDelegateImpl::ShouldDisableBackgroundSync() {
+  // TODO(crbug.com/1087486, 1091211): Add logic here if we need to support
+  // Android L.
+  return false;
+}
+#endif  // defined(OS_ANDROID)
+
+}  // namespace weblayer
diff --git a/weblayer/browser/background_sync/background_sync_delegate_impl.h b/weblayer/browser/background_sync/background_sync_delegate_impl.h
new file mode 100644
index 0000000..3a7927c7
--- /dev/null
+++ b/weblayer/browser/background_sync/background_sync_delegate_impl.h
@@ -0,0 +1,48 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef WEBLAYER_BROWSER_BACKGROUND_SYNC_BACKGROUND_SYNC_DELEGATE_IMPL_H_
+#define WEBLAYER_BROWSER_BACKGROUND_SYNC_BACKGROUND_SYNC_DELEGATE_IMPL_H_
+
+#include "build/build_config.h"
+#include "components/background_sync/background_sync_delegate.h"
+#include "url/origin.h"
+
+namespace content {
+class BrowserContext;
+}  // namespace content
+
+namespace weblayer {
+
+// WebLayer's customization of the logic in components/background_sync.
+class BackgroundSyncDelegateImpl
+    : public background_sync::BackgroundSyncDelegate {
+ public:
+  explicit BackgroundSyncDelegateImpl(content::BrowserContext* browser_context);
+  ~BackgroundSyncDelegateImpl() override;
+
+  void GetUkmSourceId(const url::Origin& origin,
+                      base::OnceCallback<void(base::Optional<ukm::SourceId>)>
+                          callback) override;
+  void Shutdown() override;
+  HostContentSettingsMap* GetHostContentSettingsMap() override;
+  bool IsProfileOffTheRecord() override;
+  void NoteSuspendedPeriodicSyncOrigins(
+      std::set<url::Origin> suspended_origins) override;
+  int GetSiteEngagementPenalty(const GURL& url) override;
+#if defined(OS_ANDROID)
+  void ScheduleBrowserWakeUpWithDelay(
+      blink::mojom::BackgroundSyncType sync_type,
+      base::TimeDelta delay) override;
+  void CancelBrowserWakeup(blink::mojom::BackgroundSyncType sync_type) override;
+  bool ShouldDisableBackgroundSync() override;
+#endif  // defined(OS_ANDROID)
+
+ private:
+  content::BrowserContext* browser_context_;
+};
+
+}  // namespace weblayer
+
+#endif  // WEBLAYER_BROWSER_BACKGROUND_SYNC_BACKGROUND_SYNC_DELEGATE_IMPL_H_
\ No newline at end of file
diff --git a/weblayer/test/BUILD.gn b/weblayer/test/BUILD.gn
index 34c37e65..f12edd5 100644
--- a/weblayer/test/BUILD.gn
+++ b/weblayer/test/BUILD.gn
@@ -96,6 +96,7 @@
     "//components/autofill/core/browser",
     "//components/autofill/core/browser:test_support",
     "//components/autofill/core/common",
+    "//components/background_sync",
     "//components/blocked_content",
     "//components/content_settings/core/browser",
     "//components/error_page/content/browser",
@@ -129,6 +130,7 @@
 
   sources = [
     "../browser/autofill_browsertest.cc",
+    "../browser/background_sync/background_sync_browsertest.cc",
     "../browser/client_hints_browsertest.cc",
     "../browser/content_settings_browsertest.cc",
     "../browser/cookie_manager_browsertest.cc",
diff --git a/weblayer/test/DEPS b/weblayer/test/DEPS
index 9dfe23d..c14b9ab3 100644
--- a/weblayer/test/DEPS
+++ b/weblayer/test/DEPS
@@ -2,6 +2,7 @@
   "+components/autofill/core/browser",
   "+components/security_interstitials",
   "+content/public/common",
+  "+content/public/browser",
   "+content/public/test",
   "+net/test",
 ]
diff --git a/weblayer/test/weblayer_browser_test.cc b/weblayer/test/weblayer_browser_test.cc
index a987eab..9cf1e92 100644
--- a/weblayer/test/weblayer_browser_test.cc
+++ b/weblayer/test/weblayer_browser_test.cc
@@ -5,6 +5,7 @@
 #include "weblayer/test/weblayer_browser_test.h"
 
 #include "base/base_paths.h"
+#include "content/public/browser/browser_context.h"
 #include "weblayer/browser/browser_context_impl.h"
 #include "weblayer/browser/profile_impl.h"
 #include "weblayer/browser/tab_impl.h"
@@ -67,4 +68,8 @@
   return static_cast<TabImpl*>(shell_->tab())->profile();
 }
 
+content::BrowserContext* WebLayerBrowserTest::GetBrowserContext() {
+  return GetProfile()->GetBrowserContext();
+}
+
 }  // namespace weblayer
diff --git a/weblayer/test/weblayer_browser_test.h b/weblayer/test/weblayer_browser_test.h
index 654be0d..040636f8 100644
--- a/weblayer/test/weblayer_browser_test.h
+++ b/weblayer/test/weblayer_browser_test.h
@@ -10,6 +10,10 @@
 #include "content/public/test/browser_test.h"
 #include "content/public/test/browser_test_base.h"
 
+namespace content {
+class BrowserContext;
+}
+
 namespace weblayer {
 class ProfileImpl;
 class Shell;
@@ -32,6 +36,7 @@
   Shell* shell() const { return shell_; }
 
   ProfileImpl* GetProfile();
+  content::BrowserContext* GetBrowserContext();
 
  private:
   Shell* shell_ = nullptr;