diff --git a/DEPS b/DEPS
index f0897ee..a1ee168 100644
--- a/DEPS
+++ b/DEPS
@@ -162,11 +162,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': '3c8f9cb45ddefe1e06d75c33a83472ab95ddcfd2',
+  'skia_revision': 'f01008997555274463e3616c5b3898d4c97bdfa9',
   # 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': '861de80c1df35894c6a4c8b6873593c76af8042a',
+  'v8_revision': 'd7cac7cb6a468995c1ec48611af283be8fb6c1ab',
   # 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.
@@ -174,7 +174,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': '2697f1f03de1b06410dd3f2a6a2e16787be7894d',
+  'angle_revision': '76a93c3325f5b1a2a17749dce30ca8ea38622bb6',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling SwiftShader
   # and whatever else without interference from each other.
@@ -297,7 +297,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': 'e25a3aede047111f023bfef2ccd8ff84814b5fe5',
+  'dawn_revision': 'b9b088f57e3d4567b9441251170cf1719125b2d1',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling feed
   # and whatever else without interference from each other.
@@ -1105,6 +1105,12 @@
       'condition': 'checkout_linux',
   },
 
+  # The library for IPP protocol (Chrome OS).
+  'src/third_party/libipp/libipp': {
+      'url': Var('chromium_git') + '/chromiumos/platform2/libipp.git' + '@' + '6c45a4f3a05cb5dd700414fe4d94cf685159d3ce',
+      'condition': 'checkout_linux',
+  },
+
   'src/third_party/libjpeg_turbo':
     Var('chromium_git') + '/chromium/deps/libjpeg_turbo.git' + '@' + 'd460d6b1cb965c3363f36f7ed716f13d60cdb65d',
 
@@ -1240,7 +1246,7 @@
   },
 
   'src/third_party/perfetto':
-    Var('android_git') + '/platform/external/perfetto.git' + '@' + '9c411655515457eb69de44a20697a3d8f7ac2701',
+    Var('android_git') + '/platform/external/perfetto.git' + '@' + 'a203388eab27c235e47d0dee32b52484beaf08bf',
 
   'src/third_party/perl': {
       'url': Var('chromium_git') + '/chromium/deps/perl.git' + '@' + '6f3e5028eb65d0b4c5fdd792106ac4c84eee1eb3',
@@ -1408,7 +1414,7 @@
     Var('chromium_git') + '/external/khronosgroup/webgl.git' + '@' + 'abaae129d9a0c6e1e092067e0b105475df43352e',
 
   'src/third_party/webrtc':
-    Var('webrtc_git') + '/src.git' + '@' + '0c141c591ae829277053bc1192d136d8a9cb47b2',
+    Var('webrtc_git') + '/src.git' + '@' + '44bd29a3b068363e013cd425c68fd00dba21d633',
 
   'src/third_party/xdg-utils': {
       'url': Var('chromium_git') + '/chromium/deps/xdg-utils.git' + '@' + 'd80274d5869b17b8c9067a1022e4416ee7ed5e0d',
@@ -1449,7 +1455,7 @@
     Var('chromium_git') + '/v8/v8.git' + '@' +  Var('v8_revision'),
 
   'src-internal': {
-    'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@e7c14e9bac04af07d15aeaaf6624f449be1ebb96',
+    'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@9f4081b4ef9bfe0c26c7ffeb33032384562cd8f2',
     'condition': 'checkout_src_internal',
   },
 
diff --git a/android_webview/browser/aw_content_browser_client.cc b/android_webview/browser/aw_content_browser_client.cc
index 3a8de30..eb47030 100644
--- a/android_webview/browser/aw_content_browser_client.cc
+++ b/android_webview/browser/aw_content_browser_client.cc
@@ -984,11 +984,12 @@
   mojo::PendingReceiver<network::mojom::RestrictedCookieManager> orig_receiver =
       std::move(*receiver);
 
-  network::mojom::RestrictedCookieManagerPtrInfo target_rcm_info;
-  *receiver = mojo::MakeRequest(&target_rcm_info);
+  mojo::PendingRemote<network::mojom::RestrictedCookieManager>
+      target_rcm_remote;
+  *receiver = target_rcm_remote.InitWithNewPipeAndPassReceiver();
 
   AwProxyingRestrictedCookieManager::CreateAndBind(
-      std::move(target_rcm_info), is_service_worker, process_id, routing_id,
+      std::move(target_rcm_remote), is_service_worker, process_id, routing_id,
       std::move(orig_receiver));
 
   return false;  // only made a proxy, still need the actual impl to be made.
diff --git a/android_webview/browser/network_service/aw_proxying_restricted_cookie_manager.cc b/android_webview/browser/network_service/aw_proxying_restricted_cookie_manager.cc
index 6d8a030..628c8ddd 100644
--- a/android_webview/browser/network_service/aw_proxying_restricted_cookie_manager.cc
+++ b/android_webview/browser/network_service/aw_proxying_restricted_cookie_manager.cc
@@ -46,7 +46,7 @@
 
 // static
 void AwProxyingRestrictedCookieManager::CreateAndBind(
-    network::mojom::RestrictedCookieManagerPtrInfo underlying_rcm,
+    mojo::PendingRemote<network::mojom::RestrictedCookieManager> underlying_rcm,
     bool is_service_worker,
     int process_id,
     int frame_id,
@@ -163,7 +163,7 @@
 }
 
 AwProxyingRestrictedCookieManager::AwProxyingRestrictedCookieManager(
-    network::mojom::RestrictedCookieManagerPtr
+    mojo::PendingRemote<network::mojom::RestrictedCookieManager>
         underlying_restricted_cookie_manager,
     bool is_service_worker,
     int process_id,
@@ -178,15 +178,14 @@
 
 // static
 void AwProxyingRestrictedCookieManager::CreateAndBindOnIoThread(
-    network::mojom::RestrictedCookieManagerPtrInfo underlying_rcm,
+    mojo::PendingRemote<network::mojom::RestrictedCookieManager> underlying_rcm,
     bool is_service_worker,
     int process_id,
     int frame_id,
     mojo::PendingReceiver<network::mojom::RestrictedCookieManager> receiver) {
   DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
   auto wrapper = base::WrapUnique(new AwProxyingRestrictedCookieManager(
-      network::mojom::RestrictedCookieManagerPtr(std::move(underlying_rcm)),
-      is_service_worker, process_id, frame_id));
+      std::move(underlying_rcm), is_service_worker, process_id, frame_id));
   mojo::MakeSelfOwnedReceiver(std::move(wrapper), std::move(receiver));
 }
 
diff --git a/android_webview/browser/network_service/aw_proxying_restricted_cookie_manager.h b/android_webview/browser/network_service/aw_proxying_restricted_cookie_manager.h
index fa0d774..27308f4 100644
--- a/android_webview/browser/network_service/aw_proxying_restricted_cookie_manager.h
+++ b/android_webview/browser/network_service/aw_proxying_restricted_cookie_manager.h
@@ -7,6 +7,7 @@
 
 #include "base/macros.h"
 #include "base/memory/weak_ptr.h"
+#include "mojo/public/cpp/bindings/remote.h"
 #include "services/network/public/mojom/restricted_cookie_manager.mojom.h"
 #include "url/gurl.h"
 
@@ -24,7 +25,8 @@
   //
   // Expects to be called on the UI thread.
   static void CreateAndBind(
-      network::mojom::RestrictedCookieManagerPtrInfo underlying_rcm,
+      mojo::PendingRemote<network::mojom::RestrictedCookieManager>
+          underlying_rcm,
       bool is_service_worker,
       int process_id,
       int frame_id,
@@ -70,20 +72,22 @@
   bool AllowCookies(const GURL& url, const GURL& site_for_cookies) const;
 
  private:
-  AwProxyingRestrictedCookieManager(network::mojom::RestrictedCookieManagerPtr
-                                        underlying_restricted_cookie_manager,
-                                    bool is_service_worker,
-                                    int process_id,
-                                    int frame_id);
+  AwProxyingRestrictedCookieManager(
+      mojo::PendingRemote<network::mojom::RestrictedCookieManager>
+          underlying_restricted_cookie_manager,
+      bool is_service_worker,
+      int process_id,
+      int frame_id);
 
   static void CreateAndBindOnIoThread(
-      network::mojom::RestrictedCookieManagerPtrInfo underlying_rcm,
+      mojo::PendingRemote<network::mojom::RestrictedCookieManager>
+          underlying_rcm,
       bool is_service_worker,
       int process_id,
       int frame_id,
       mojo::PendingReceiver<network::mojom::RestrictedCookieManager> receiver);
 
-  network::mojom::RestrictedCookieManagerPtr
+  mojo::Remote<network::mojom::RestrictedCookieManager>
       underlying_restricted_cookie_manager_;
   bool is_service_worker_;
   int process_id_;
diff --git a/android_webview/browser/state_serializer_unittest.cc b/android_webview/browser/state_serializer_unittest.cc
index 5cdf3b6..f066cb4 100644
--- a/android_webview/browser/state_serializer_unittest.cc
+++ b/android_webview/browser/state_serializer_unittest.cc
@@ -33,8 +33,6 @@
   referrer.url = GURL("http://referrer_url");
   referrer.policy = network::mojom::ReferrerPolicy::kOrigin;
   const base::string16 title(base::UTF8ToUTF16("title"));
-  const content::PageState page_state =
-      content::PageState::CreateFromEncodedData("completely bogus state");
   const bool has_post_data = true;
   const GURL original_request_url("http://original_request_url");
   const GURL base_url_for_data_url("http://base_url");
@@ -47,7 +45,6 @@
   entry->SetVirtualURL(virtual_url);
   entry->SetReferrer(referrer);
   entry->SetTitle(title);
-  entry->SetPageState(page_state);
   entry->SetHasPostData(has_post_data);
   entry->SetOriginalRequestURL(original_request_url);
   entry->SetBaseURLForDataURL(base_url_for_data_url);
diff --git a/ash/public/cpp/wallpaper_controller_observer.h b/ash/public/cpp/wallpaper_controller_observer.h
index 6d58154..c019fa0 100644
--- a/ash/public/cpp/wallpaper_controller_observer.h
+++ b/ash/public/cpp/wallpaper_controller_observer.h
@@ -15,6 +15,9 @@
  public:
   WallpaperControllerObserver();
 
+  // Invoked when the wallpaper is about to change.
+  virtual void OnWallpaperChanging() {}
+
   // Invoked when the wallpaper is changed.
   virtual void OnWallpaperChanged() {}
 
diff --git a/ash/wallpaper/wallpaper_controller_impl.cc b/ash/wallpaper/wallpaper_controller_impl.cc
index a333d5b..ebe749c 100644
--- a/ash/wallpaper/wallpaper_controller_impl.cc
+++ b/ash/wallpaper/wallpaper_controller_impl.cc
@@ -675,12 +675,16 @@
     for (auto& observer : observers_)
       observer.OnFirstWallpaperShown();
   }
+
   for (auto& observer : observers_)
-    observer.OnWallpaperChanged();
+    observer.OnWallpaperChanging();
 
   wallpaper_mode_ = WALLPAPER_IMAGE;
   InstallDesktopControllerForAllWindows();
   ++wallpaper_count_for_testing_;
+
+  for (auto& observer : observers_)
+    observer.OnWallpaperChanged();
 }
 
 bool WallpaperControllerImpl::IsPolicyControlled(
@@ -1710,10 +1714,9 @@
       CustomWallpaperElement(base::FilePath(), image);
 }
 
-void WallpaperControllerImpl::SetWallpaperFromInfo(
-    const AccountId& account_id,
-    const WallpaperInfo& info,
-    bool show_wallpaper) {
+void WallpaperControllerImpl::SetWallpaperFromInfo(const AccountId& account_id,
+                                                   const WallpaperInfo& info,
+                                                   bool show_wallpaper) {
   if (info.type != ONLINE && info.type != DEFAULT) {
     // This method is meant to be used for ONLINE and DEFAULT types. In
     // unexpected cases, revert to default wallpaper to fail safely. See
@@ -1850,12 +1853,11 @@
       CustomWallpaperElement(wallpaper_path, image);
 }
 
-void WallpaperControllerImpl::OnWallpaperDecoded(
-    const AccountId& account_id,
-    const base::FilePath& path,
-    const WallpaperInfo& info,
-    bool show_wallpaper,
-    const gfx::ImageSkia& image) {
+void WallpaperControllerImpl::OnWallpaperDecoded(const AccountId& account_id,
+                                                 const base::FilePath& path,
+                                                 const WallpaperInfo& info,
+                                                 bool show_wallpaper,
+                                                 const gfx::ImageSkia& image) {
   // Empty image indicates decode failure. Use default wallpaper in this case.
   if (image.isNull()) {
     LOG(ERROR) << "Failed to decode user wallpaper at " << path.value()
diff --git a/ash/wm/overview/overview_grid.cc b/ash/wm/overview/overview_grid.cc
index 804307e..c15fa5e 100644
--- a/ash/wm/overview/overview_grid.cc
+++ b/ash/wm/overview/overview_grid.cc
@@ -21,6 +21,7 @@
 #include "ash/shelf/shelf.h"
 #include "ash/shelf/shelf_constants.h"
 #include "ash/shell.h"
+#include "ash/wallpaper/wallpaper_controller_impl.h"
 #include "ash/wm/desks/desk_mini_view.h"
 #include "ash/wm/desks/desks_bar_view.h"
 #include "ash/wm/desks/desks_util.h"
@@ -70,9 +71,11 @@
 // Additional vertical inset reserved for windows in overview mode.
 constexpr float kOverviewVerticalInset = 0.1f;
 
-// Number of columns and rows for windows in tablet overview mode.
+// Number of rows for windows in tablet overview mode.
 constexpr int kTabletLayoutRow = 2;
 
+constexpr int kMinimumItemsForNewLayout = 6;
+
 // Histogram names for overview enter/exit smoothness in clamshell,
 // tablet mode and splitview.
 constexpr char kOverviewEnterClamshellHistogram[] =
@@ -376,6 +379,7 @@
 
 void OverviewGrid::Shutdown() {
   ScreenRotationAnimator::GetForRootWindow(root_window_)->RemoveObserver(this);
+  Shell::Get()->wallpaper_controller()->RemoveObserver(this);
   grid_pre_event_handler_.reset();
 
   bool has_non_cover_animating = false;
@@ -420,6 +424,7 @@
   }
 
   grid_pre_event_handler_ = std::make_unique<OverviewGridPreEventHandler>(this);
+  Shell::Get()->wallpaper_controller()->AddObserver(this);
 }
 
 void OverviewGrid::PositionWindows(
@@ -432,7 +437,9 @@
   DCHECK_NE(transition, OverviewSession::OverviewTransition::kExit);
 
   std::vector<gfx::RectF> rects =
-      ShouldUseTabletModeGridLayout()
+      ShouldUseTabletModeGridLayout() &&
+              (window_list_.size() - ignored_items.size() >=
+               kMinimumItemsForNewLayout)
           ? GetWindowRectsForTabletModeLayout(ignored_items)
           : GetWindowRects(ignored_items);
 
@@ -883,6 +890,14 @@
   Shell::Get()->overview_controller()->DelayedUpdateRoundedCornersAndShadow();
 }
 
+void OverviewGrid::OnWallpaperChanging() {
+  grid_pre_event_handler_.reset();
+}
+
+void OverviewGrid::OnWallpaperChanged() {
+  grid_pre_event_handler_ = std::make_unique<OverviewGridPreEventHandler>(this);
+}
+
 void OverviewGrid::OnStartingAnimationComplete(bool canceled) {
   fps_counter_.reset();
   if (canceled)
@@ -1319,13 +1334,18 @@
       kOverviewScrollHistogram, kOverviewScrollMaxLatencyHistogram);
 }
 
-void OverviewGrid::UpdateScrollOffset(float delta) {
+bool OverviewGrid::UpdateScrollOffset(float delta) {
+  const float previous_scroll_offset = scroll_offset_;
   scroll_offset_ += delta;
-  scroll_offset_ = base::ClampToRange(scroll_offset_, scroll_offset_min_, 0.0f);
-  PositionWindows(false);
+  scroll_offset_ = base::ClampToRange(scroll_offset_, scroll_offset_min_, 0.f);
+  if (scroll_offset_ == previous_scroll_offset)
+    return false;
+
+  PositionWindows(/*animate=*/false);
 
   DCHECK(presentation_time_recorder_);
   presentation_time_recorder_->RequestNext();
+  return true;
 }
 
 void OverviewGrid::EndScroll() {
diff --git a/ash/wm/overview/overview_grid.h b/ash/wm/overview/overview_grid.h
index 3d55a15e..30314330 100644
--- a/ash/wm/overview/overview_grid.h
+++ b/ash/wm/overview/overview_grid.h
@@ -10,6 +10,7 @@
 #include <memory>
 #include <vector>
 
+#include "ash/public/cpp/wallpaper_controller_observer.h"
 #include "ash/rotator/screen_rotation_animator_observer.h"
 #include "ash/wm/overview/overview_session.h"
 #include "ash/wm/window_state_observer.h"
@@ -53,7 +54,8 @@
 // it reaches the end of its movement sequence.
 class ASH_EXPORT OverviewGrid : public aura::WindowObserver,
                                 public WindowStateObserver,
-                                public ScreenRotationAnimatorObserver {
+                                public ScreenRotationAnimatorObserver,
+                                public WallpaperControllerObserver {
  public:
   OverviewGrid(aura::Window* root_window,
                const std::vector<aura::Window*>& window_list,
@@ -182,6 +184,10 @@
   void OnScreenRotationAnimationFinished(ScreenRotationAnimator* animator,
                                          bool canceled) override;
 
+  // WallpaperControllerObserver:
+  void OnWallpaperChanging() override;
+  void OnWallpaperChanged() override;
+
   // Called when overview starting animation completes.
   void OnStartingAnimationComplete(bool canceled);
 
@@ -272,8 +278,9 @@
   void StartScroll();
 
   // |delta| is used for updating |scroll_offset_| with new scroll values so
-  // that windows in tablet overview mode get positioned accordingly.
-  void UpdateScrollOffset(float delta);
+  // that windows in tablet overview mode get positioned accordingly. Returns
+  // true if the grid was scrolled.
+  bool UpdateScrollOffset(float delta);
 
   void EndScroll();
 
diff --git a/ash/wm/overview/overview_grid_pre_event_handler.cc b/ash/wm/overview/overview_grid_pre_event_handler.cc
index 577c213..8742676 100644
--- a/ash/wm/overview/overview_grid_pre_event_handler.cc
+++ b/ash/wm/overview/overview_grid_pre_event_handler.cc
@@ -38,10 +38,12 @@
 }
 
 OverviewGridPreEventHandler::~OverviewGridPreEventHandler() {
+  EndFling();
+  grid_->EndScroll();
+
   auto* wallpaper_view = GetWallpaperViewForRoot(grid_->root_window());
   if (wallpaper_view)
     wallpaper_view->RemovePreTargetHandler(this);
-  EndFling();
 }
 
 void OverviewGridPreEventHandler::OnMouseEvent(ui::MouseEvent* event) {
@@ -96,13 +98,18 @@
   gfx::Vector2dF offset;
 
   // As a fling progresses, the velocity degenerates, and the difference in
-  // offset is passed into |grid_| as an updated scroll value.
-  bool fling =
+  // offset is passed into |grid_| as an updated scroll value. Stop flinging if
+  // the API for fling says to finish, or we reach one of the edges of the
+  // overview grid.
+  bool continue_fling =
       fling_curve_->ComputeScrollOffset(timestamp, &offset, &fling_velocity_);
-  grid_->UpdateScrollOffset(offset.x() - fling_last_offset_.x());
-  fling_last_offset_ = offset;
+  if (!continue_fling) {
+    continue_fling = grid_->UpdateScrollOffset(
+        fling_last_offset_ ? offset.x() - fling_last_offset_->x() : offset.x());
+  }
+  fling_last_offset_ = base::make_optional(offset);
 
-  if (!fling)
+  if (!continue_fling)
     EndFling();
 }
 
@@ -137,6 +144,7 @@
   observed_compositor_->RemoveAnimationObserver(this);
   observed_compositor_ = nullptr;
   fling_curve_.reset();
+  fling_last_offset_ = base::nullopt;
   grid_->EndScroll();
 }
 
diff --git a/ash/wm/overview/overview_grid_pre_event_handler.h b/ash/wm/overview/overview_grid_pre_event_handler.h
index 8ef02f6..81568b09 100644
--- a/ash/wm/overview/overview_grid_pre_event_handler.h
+++ b/ash/wm/overview/overview_grid_pre_event_handler.h
@@ -6,6 +6,7 @@
 #define ASH_WM_OVERVIEW_OVERVIEW_GRID_PRE_EVENT_HANDLER_H_
 
 #include "base/macros.h"
+#include "base/optional.h"
 #include "ui/compositor/compositor_animation_observer.h"
 #include "ui/events/event_handler.h"
 #include "ui/gfx/geometry/point.h"
@@ -61,7 +62,7 @@
 
   // Cached value of an earlier offset that determines values to scroll through
   // overview mode by being compared to an updated offset.
-  gfx::Vector2dF fling_last_offset_;
+  base::Optional<gfx::Vector2dF> fling_last_offset_;
 
   // The compositor we are observing when a fling is underway.
   ui::Compositor* observed_compositor_ = nullptr;
diff --git a/ash/wm/overview/overview_item.cc b/ash/wm/overview/overview_item.cc
index 3bb58b52..3eaa7e2 100644
--- a/ash/wm/overview/overview_item.cc
+++ b/ash/wm/overview/overview_item.cc
@@ -780,6 +780,7 @@
     HandleGestureEventForTabletModeLayout(event);
     return;
   }
+
   const gfx::PointF location = event->details().bounding_box_f().CenterPoint();
   switch (event->type()) {
     case ui::ET_GESTURE_TAP_DOWN:
@@ -820,8 +821,12 @@
         overview_grid()->grid_pre_event_handler()->OnGestureEvent(event);
       break;
     case ui::ET_SCROLL_FLING_START:
-      HandleFlingStartEvent(location, event->details().velocity_x(),
-                            event->details().velocity_y());
+      if (IsDragItem()) {
+        HandleFlingStartEvent(location, event->details().velocity_x(),
+                              event->details().velocity_y());
+      } else {
+        overview_grid()->grid_pre_event_handler()->OnGestureEvent(event);
+      }
       break;
     case ui::ET_GESTURE_SCROLL_END:
       if (IsDragItem())
diff --git a/ash/wm/overview/overview_session.cc b/ash/wm/overview/overview_session.cc
index 9a65621..b56adb9 100644
--- a/ash/wm/overview/overview_session.cc
+++ b/ash/wm/overview/overview_session.cc
@@ -67,6 +67,11 @@
     SkColorSetA(SK_ColorBLACK, 204);
 constexpr SkColor kNoItemsIndicatorTextColor = SK_ColorWHITE;
 
+// Values for scrolling the grid by using the keyboard.
+// TODO(sammiequon): See if we can use the same values used for web scrolling.
+constexpr int kKeyboardPressScrollingDp = 25;
+constexpr int kKeyboardHoldScrollingDp = 5;
+
 // Returns the bounds for the overview window grid according to the split view
 // state. If split view mode is active, the overview window should open on the
 // opposite side of the default snap window. If |divider_changed| is true, maybe
@@ -840,7 +845,11 @@
     return;
   }
 
-  if (event->type() != ui::ET_KEY_PRESSED)
+  const bool process_released_key_event =
+      (event->key_code() == ui::VKEY_LEFT ||
+       event->key_code() == ui::VKEY_RIGHT) &&
+      ShouldUseTabletModeGridLayout();
+  if (event->type() != ui::ET_KEY_PRESSED && !process_released_key_event)
     return;
 
   switch (event->key_code()) {
@@ -857,17 +866,22 @@
       Move(/*reverse=*/false);
       break;
     case ui::VKEY_RIGHT:
-    case ui::VKEY_TAB:
-      if (event->key_code() == ui::VKEY_RIGHT ||
-          !(event->flags() & ui::EF_SHIFT_DOWN)) {
+      if (!ProcessForScrolling(*event)) {
         ++num_key_presses_;
         Move(/*reverse=*/false);
-        break;
       }
-      FALLTHROUGH;
-    case ui::VKEY_LEFT:
+      break;
+    case ui::VKEY_TAB: {
+      const bool reverse = event->flags() & ui::EF_SHIFT_DOWN;
       ++num_key_presses_;
-      Move(/*reverse=*/true);
+      Move(reverse);
+      break;
+    }
+    case ui::VKEY_LEFT:
+      if (!ProcessForScrolling(*event)) {
+        ++num_key_presses_;
+        Move(/*reverse=*/true);
+      }
       break;
     case ui::VKEY_W: {
       if (!(event->flags() & ui::EF_CONTROL_DOWN))
@@ -986,6 +1000,37 @@
   highlight_controller_->MoveHighlight(reverse);
 }
 
+bool OverviewSession::ProcessForScrolling(const ui::KeyEvent& event) {
+  if (!ShouldUseTabletModeGridLayout() ||
+      !(event.flags() & ui::EF_CONTROL_DOWN)) {
+    return false;
+  }
+
+  const bool press = (event.type() == ui::ET_KEY_PRESSED);
+  const bool repeat = event.is_repeat();
+  DCHECK(event.key_code() == ui::VKEY_LEFT ||
+         event.key_code() == ui::VKEY_RIGHT);
+  const bool reverse = event.key_code() == ui::VKEY_LEFT;
+
+  // TODO(sammiequon): This only works for tablet mode at the moment, so using
+  // the primary display works. If this feature is adapted for multi display
+  // then this needs to be revisited.
+  auto* grid = GetGridWithRootWindow(Shell::GetPrimaryRootWindow());
+  if (press && !repeat) {
+    grid->StartScroll();
+    grid->UpdateScrollOffset(kKeyboardPressScrollingDp * (reverse ? 1 : -1));
+    return true;
+  }
+
+  if (press && repeat) {
+    grid->UpdateScrollOffset(kKeyboardHoldScrollingDp * (reverse ? 1 : -1));
+    return true;
+  }
+
+  grid->EndScroll();
+  return true;
+}
+
 void OverviewSession::RemoveAllObservers() {
   for (auto* window : observed_windows_)
     window->RemoveObserver(this);
diff --git a/ash/wm/overview/overview_session.h b/ash/wm/overview/overview_session.h
index eb0cdd4..5432b9a 100644
--- a/ash/wm/overview/overview_session.h
+++ b/ash/wm/overview/overview_session.h
@@ -311,6 +311,10 @@
   // the corresponding window grid.
   void Move(bool reverse);
 
+  // Helper function that processes a key event and maybe scrolls the overview
+  // grid on the primary display.
+  bool ProcessForScrolling(const ui::KeyEvent& event);
+
   // Removes all observers that were registered during construction and/or
   // initialization.
   void RemoveAllObservers();
diff --git a/ash/wm/overview/overview_session_unittest.cc b/ash/wm/overview/overview_session_unittest.cc
index afe2a8f..ce3f9551 100644
--- a/ash/wm/overview/overview_session_unittest.cc
+++ b/ash/wm/overview/overview_session_unittest.cc
@@ -2813,6 +2813,15 @@
     GetEventGenerator()->Dispatch(&long_press);
   }
 
+  // Creates |n| test windows. They are created in reverse order, so that the
+  // first window in the vector is the MRU window.
+  std::vector<std::unique_ptr<aura::Window>> CreateTestWindows(int n) {
+    std::vector<std::unique_ptr<aura::Window>> windows(n);
+    for (int i = n - 1; i >= 0; --i)
+      windows[i] = CreateTestWindow();
+    return windows;
+  }
+
   // TODO(sammiequon): Investigate simulating fling event for testing inertial
   // scrolling.
 
@@ -2824,23 +2833,14 @@
 
 // Tests that windows are in proper positions in the new overview layout.
 TEST_F(OverviewSessionNewLayoutTest, CheckNewLayoutWindowPositions) {
-  // Windows are created in this order because overview orders windows in terms
-  // of most recently used. |window4| will be created first, but will be
-  // determined last recently used. |window1| will be created last, but will be
-  // determined most recently used. Thus this order will be reflected in
-  // overview mode.
-  std::unique_ptr<aura::Window> window4 = CreateTestWindow();
-  std::unique_ptr<aura::Window> window3 = CreateTestWindow();
-  std::unique_ptr<aura::Window> window2 = CreateTestWindow();
-  std::unique_ptr<aura::Window> window1 = CreateTestWindow();
-
+  auto windows = CreateTestWindows(6);
   ToggleOverview();
   ASSERT_TRUE(InOverviewSession());
 
-  OverviewItem* item1 = GetOverviewItemForWindow(window1.get());
-  OverviewItem* item2 = GetOverviewItemForWindow(window2.get());
-  OverviewItem* item3 = GetOverviewItemForWindow(window3.get());
-  OverviewItem* item4 = GetOverviewItemForWindow(window4.get());
+  OverviewItem* item1 = GetOverviewItemForWindow(windows[0].get());
+  OverviewItem* item2 = GetOverviewItemForWindow(windows[1].get());
+  OverviewItem* item3 = GetOverviewItemForWindow(windows[2].get());
+  OverviewItem* item4 = GetOverviewItemForWindow(windows[3].get());
 
   const gfx::RectF item1_bounds = item1->target_bounds();
   const gfx::RectF item2_bounds = item2->target_bounds();
@@ -2864,15 +2864,7 @@
 }
 
 TEST_F(OverviewSessionNewLayoutTest, CheckOffscreenWindows) {
-  // Windows are created in this order because overview orders windows in terms
-  // of most recently used. |window|7|| will be created first, but will be
-  // determined last recently used. |window|0|| will be created last, but will
-  // be determined most recently used. Thus this order will be reflected in
-  // overview mode.
-  std::vector<std::unique_ptr<aura::Window>> windows(8);
-  for (int i = 7; i >= 0; --i)
-    windows[i] = CreateTestWindow();
-
+  auto windows = CreateTestWindows(8);
   ToggleOverview();
   ASSERT_TRUE(InOverviewSession());
 
@@ -2901,10 +2893,7 @@
 // Tests to see if windows are not shifted if all already available windows
 // fit on screen.
 TEST_F(OverviewSessionNewLayoutTest, CheckNoOverviewItemShift) {
-  std::vector<std::unique_ptr<aura::Window>> windows(4);
-  for (int i = 3; i >= 0; --i)
-    windows[i] = CreateTestWindow();
-
+  auto windows = CreateTestWindows(4);
   ToggleOverview();
   ASSERT_TRUE(InOverviewSession());
 
@@ -2918,10 +2907,7 @@
 // Tests to see if windows are shifted if at least one window is
 // partially/completely positioned offscreen.
 TEST_F(OverviewSessionNewLayoutTest, CheckOverviewItemShift) {
-  std::vector<std::unique_ptr<aura::Window>> windows(7);
-  for (int i = 6; i >= 0; --i)
-    windows[i] = CreateTestWindow();
-
+  auto windows = CreateTestWindows(7);
   ToggleOverview();
   ASSERT_TRUE(InOverviewSession());
 
@@ -2934,15 +2920,12 @@
 
 // Tests to see if windows remain in bounds after scrolling extremely far.
 TEST_F(OverviewSessionNewLayoutTest, CheckOverviewItemScrollingBounds) {
-  std::vector<std::unique_ptr<aura::Window>> windows(8);
-  for (int i = 7; i >= 0; --i)
-    windows[i] = CreateTestWindow();
-
+  auto windows = CreateTestWindows(8);
   ToggleOverview();
   ASSERT_TRUE(InOverviewSession());
 
   // Scroll an extreme amount to see if windows on the far left are still in
-  // bounds. First, align the left-most window (|windows|0||) to the left-hand
+  // bounds. First, align the left-most window (|windows[0]|) to the left-hand
   // bound and store the item's location. Then, scroll a far amount and check to
   // see if the item moved at all.
   OverviewItem* leftmost_window = GetOverviewItemForWindow(windows[0].get());
@@ -2953,7 +2936,7 @@
   EXPECT_EQ(left_bounds, leftmost_window->target_bounds());
 
   // Scroll an extreme amount to see if windows on the far right are still in
-  // bounds. First, align the right-most window (|windows|7||) to the right-hand
+  // bounds. First, align the right-most window (|windows[7]|) to the right-hand
   // bound and store the item's location. Then, scroll a far amount and check to
   // see if the item moved at all.
   OverviewItem* rightmost_window = GetOverviewItemForWindow(windows[7].get());
@@ -2996,10 +2979,7 @@
 // Test that scrolling occurs if started on top of a window using the window's
 // center-point as a start.
 TEST_F(OverviewSessionNewLayoutTest, CheckScrollingOnWindowItems) {
-  std::vector<std::unique_ptr<aura::Window>> windows(8);
-  for (int i = 7; i >= 0; --i)
-    windows[i] = CreateTestWindow();
-
+  auto windows = CreateTestWindows(8);
   ToggleOverview();
   ASSERT_TRUE(InOverviewSession());
 
@@ -3012,24 +2992,35 @@
   EXPECT_LT(leftmost_window->target_bounds(), left_bounds);
 }
 
+// Test that scrolling occurs if we hit the associated keyboard shortcut.
+TEST_F(OverviewSessionNewLayoutTest, CheckScrollingWithKeyboardShortcut) {
+  auto windows = CreateTestWindows(8);
+  ToggleOverview();
+  ASSERT_TRUE(InOverviewSession());
+
+  OverviewItem* leftmost_window = GetOverviewItemForWindow(windows[0].get());
+  const gfx::RectF left_bounds = leftmost_window->target_bounds();
+
+  SendKey(ui::VKEY_RIGHT, ui::EF_CONTROL_DOWN);
+  EXPECT_LT(leftmost_window->target_bounds(), left_bounds);
+}
+
 // Test that tapping a window in overview closes overview mode.
 TEST_F(OverviewSessionNewLayoutTest, CheckWindowActivateOnTap) {
   base::UserActionTester user_action_tester;
-  std::vector<std::unique_ptr<aura::Window>> windows(8);
-  for (int i = 7; i >= 0; --i)
-    windows[i] = CreateTestWindow();
+  auto windows = CreateTestWindows(8);
   wm::ActivateWindow(windows[1].get());
 
   ToggleOverview();
   ASSERT_TRUE(InOverviewSession());
 
-  // Tap on |windows|1|| to exit overview.
+  // Tap on |windows[1]| to exit overview.
   GetEventGenerator()->GestureTapAt(
       GetTransformedTargetBounds(windows[1].get()).CenterPoint());
   EXPECT_EQ(
       0, user_action_tester.GetActionCount(kActiveWindowChangedFromOverview));
 
-  // |windows|1|| remains active. Click on it to exit overview.
+  // |windows[1]| remains active. Click on it to exit overview.
   ASSERT_EQ(windows[1].get(), window_util::GetFocusedWindow());
   ToggleOverview();
   ClickWindow(windows[1].get());
diff --git a/base/BUILD.gn b/base/BUILD.gn
index 824dfad3..973cc6f 100644
--- a/base/BUILD.gn
+++ b/base/BUILD.gn
@@ -1061,6 +1061,8 @@
     "win/event_trace_controller.h",
     "win/event_trace_provider.cc",
     "win/event_trace_provider.h",
+    "win/file_pre_reader.cc",
+    "win/file_pre_reader.h",
     "win/hstring_compare.cc",
     "win/hstring_compare.h",
     "win/hstring_reference.cc",
@@ -2259,7 +2261,10 @@
   ]
   if (!is_ios) {
     # iOS doesn't use the partition allocator, therefore it can't run this test.
-    sources += [ "allocator/partition_allocator/partition_alloc_perftest.cc" ]
+    sources += [
+      "allocator/partition_allocator/partition_alloc_perftest.cc",
+      "allocator/partition_allocator/spin_lock_perftest.cc",
+    ]
   }
   deps = [
     ":base",
diff --git a/base/allocator/partition_allocator/page_allocator_internals_posix.h b/base/allocator/partition_allocator/page_allocator_internals_posix.h
index c3b668b..b49b80a3 100644
--- a/base/allocator/partition_allocator/page_allocator_internals_posix.h
+++ b/base/allocator/partition_allocator/page_allocator_internals_posix.h
@@ -16,18 +16,39 @@
 
 #include <mach/mach.h>
 #endif
+#if defined(OS_ANDROID)
+#include <sys/prctl.h>
+#endif
 #if defined(OS_LINUX)
 #include <sys/resource.h>
 
 #include <algorithm>
 #endif
 
+#include "base/allocator/partition_allocator/page_allocator.h"
+
 #ifndef MAP_ANONYMOUS
 #define MAP_ANONYMOUS MAP_ANON
 #endif
 
 namespace base {
 
+#if defined(OS_ANDROID)
+namespace {
+const char* PageTagToName(PageTag tag) {
+  switch (tag) {
+    case PageTag::kChromium:
+      return "chromium";
+    case PageTag::kV8:
+      return "v8";
+    default:
+      DCHECK(false);
+      return "";
+  }
+}
+}  // namespace
+#endif  // defined(OS_ANDROID)
+
 // |mmap| uses a nearby address if the hint address is blocked.
 constexpr bool kHintIsAdvisory = true;
 std::atomic<int32_t> s_allocPageErrorCode{0};
@@ -91,6 +112,17 @@
     s_allocPageErrorCode = errno;
     ret = nullptr;
   }
+
+#if defined(OS_ANDROID)
+  // On Android, anonymous mappings can have a name attached to them. This is
+  // useful for debugging, and double-checking memory attribution.
+  if (ret) {
+    // No error checking on purpose, testing only.
+    prctl(PR_SET_VMA, PR_SET_VMA_ANON_NAME, ret, length,
+          PageTagToName(page_tag));
+  }
+#endif
+
   return ret;
 }
 
diff --git a/base/allocator/partition_allocator/page_allocator_unittest.cc b/base/allocator/partition_allocator/page_allocator_unittest.cc
index 3f162fd..7612ad2 100644
--- a/base/allocator/partition_allocator/page_allocator_unittest.cc
+++ b/base/allocator/partition_allocator/page_allocator_unittest.cc
@@ -6,9 +6,15 @@
 
 #include <stdlib.h>
 #include <string.h>
+#include <algorithm>
+#include <string>
+#include <vector>
 
 #include "base/allocator/partition_allocator/address_space_randomization.h"
 #include "build/build_config.h"
+#if defined(OS_ANDROID)
+#include "base/debug/proc_maps_linux.h"
+#endif  // defined(OS_ANDROID)
 #include "testing/gtest/include/gtest/gtest.h"
 
 #if defined(OS_POSIX)
@@ -219,6 +225,32 @@
 
 #endif  // defined(OS_POSIX)
 
+#if defined(OS_ANDROID)
+TEST(PageAllocatorTest, PageTagging) {
+  void* buffer = AllocPages(nullptr, kPageAllocationGranularity,
+                            kPageAllocationGranularity, PageInaccessible,
+                            PageTag::kChromium, true);
+  EXPECT_TRUE(buffer);
+
+  std::string proc_maps;
+  EXPECT_TRUE(debug::ReadProcMaps(&proc_maps));
+  std::vector<debug::MappedMemoryRegion> regions;
+  EXPECT_TRUE(debug::ParseProcMaps(proc_maps, &regions));
+
+  bool found = false;
+  for (const auto& region : regions) {
+    if (region.start == reinterpret_cast<uintptr_t>(buffer)) {
+      found = true;
+      EXPECT_EQ("[anon:chromium]", region.path);
+      break;
+    }
+  }
+
+  FreePages(buffer, kPageAllocationGranularity);
+  EXPECT_TRUE(found);
+}
+#endif  // defined(OS_ANDROID)
+
 }  // namespace base
 
 #endif  // !defined(MEMORY_TOOL_REPLACES_ALLOCATOR)
diff --git a/base/allocator/partition_allocator/spin_lock_perftest.cc b/base/allocator/partition_allocator/spin_lock_perftest.cc
new file mode 100644
index 0000000..49811cb
--- /dev/null
+++ b/base/allocator/partition_allocator/spin_lock_perftest.cc
@@ -0,0 +1,86 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/allocator/partition_allocator/spin_lock.h"
+#include "base/threading/platform_thread.h"
+#include "base/time/time.h"
+#include "base/timer/lap_timer.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "testing/perf/perf_test.h"
+
+namespace base {
+namespace {
+
+constexpr int kWarmupRuns = 1;
+constexpr TimeDelta kTimeLimit = TimeDelta::FromSeconds(1);
+constexpr int kTimeCheckInterval = 100000;
+
+class Spin : public PlatformThread::Delegate {
+ public:
+  Spin(subtle::SpinLock* lock, size_t* data)
+      : lock_(lock), data_(data), should_stop_(false) {}
+  ~Spin() override = default;
+
+  void ThreadMain() override {
+    while (!should_stop_.load(std::memory_order_relaxed)) {
+      lock_->lock();
+      (*data_)++;
+      lock_->unlock();
+    }
+  }
+
+  void Stop() { should_stop_ = true; }
+
+ private:
+  subtle::SpinLock* lock_;
+  size_t* data_;
+  std::atomic<bool> should_stop_;
+};
+
+}  // namespace
+
+TEST(SpinLockPerfTest, Simple) {
+  LapTimer timer(kWarmupRuns, kTimeLimit, kTimeCheckInterval);
+  size_t data = 0;
+
+  subtle::SpinLock lock;
+
+  do {
+    lock.lock();
+    data += 1;
+    lock.unlock();
+    timer.NextLap();
+  } while (!timer.HasTimeLimitExpired());
+
+  perf_test::PrintResult("SpinLockPerfTest", " lock()/unlock()", "",
+                         timer.LapsPerSecond(), "runs/s", true);
+}
+
+TEST(SpinLockPerfTest, WithCompetingThread) {
+  LapTimer timer(kWarmupRuns, kTimeLimit, kTimeCheckInterval);
+  size_t data = 0;
+
+  subtle::SpinLock lock;
+
+  // Starts a competing thread executing the same loop as this thread.
+  Spin thread_main(&lock, &data);
+  PlatformThreadHandle thread_handle;
+  ASSERT_TRUE(PlatformThread::Create(0, &thread_main, &thread_handle));
+
+  do {
+    lock.lock();
+    data += 1;
+    lock.unlock();
+    timer.NextLap();
+  } while (!timer.HasTimeLimitExpired());
+
+  thread_main.Stop();
+  PlatformThread::Join(thread_handle);
+
+  perf_test::PrintResult("SpinLockPerfTest.WithCompetingThread",
+                         " lock()/unlock()", "", timer.LapsPerSecond(),
+                         "runs/s", true);
+}
+
+}  // namespace base
diff --git a/base/process/launch.h b/base/process/launch.h
index 5b9612d0..24fb4273 100644
--- a/base/process/launch.h
+++ b/base/process/launch.h
@@ -254,6 +254,10 @@
   // child process' namespace. Paths installed by |paths_to_clone| will be
   // overridden by these entries.
   std::vector<PathToTransfer> paths_to_transfer;
+
+  // Suffix that will be added to the process name. When specified process name
+  // will be set to "<binary_name><process_suffix>".
+  std::string process_name_suffix;
 #endif  // defined(OS_FUCHSIA)
 
 #if defined(OS_POSIX)
diff --git a/base/process/launch_fuchsia.cc b/base/process/launch_fuchsia.cc
index 34cbaad7..dea0fce 100644
--- a/base/process/launch_fuchsia.cc
+++ b/base/process/launch_fuchsia.cc
@@ -91,6 +91,12 @@
   return action;
 }
 
+fdio_spawn_action_t FdioSpawnActionSetName(const char* name) {
+  fdio_spawn_action_t action = FdioSpawnAction(FDIO_SPAWN_ACTION_SET_NAME);
+  action.name.data = name;
+  return action;
+}
+
 }  // namespace
 
 // static
@@ -206,6 +212,15 @@
         FdioSpawnActionCloneFd(src_target.first, src_target.second));
   }
 
+  // If |process_name_suffix| is specified then set process name as
+  // "<file_name><suffix>", otherwise leave the default value.
+  std::string process_name;
+  if (!options.process_name_suffix.empty()) {
+    process_name = base::FilePath(argv[0]).BaseName().value() +
+                   options.process_name_suffix;
+    spawn_actions.push_back(FdioSpawnActionSetName(process_name.c_str()));
+  }
+
   zx::process process_handle;
   // fdio_spawn_etc() will write a null-terminated scring to |error_message| in
   // case of failure, so we avoid unnecessarily initializing it here.
diff --git a/base/process/process_util_unittest.cc b/base/process/process_util_unittest.cc
index 621aec5..cee182c 100644
--- a/base/process/process_util_unittest.cc
+++ b/base/process/process_util_unittest.cc
@@ -476,6 +476,22 @@
   EXPECT_EQ(ZX_ERR_BAD_HANDLE, zx_handle_close(handles[0].get()));
   ignore_result(handles[0].release());
 }
+
+TEST_F(ProcessUtilTest, FuchsiaProcessNameSuffix) {
+  LaunchOptions options;
+  options.process_name_suffix = "#test";
+  Process process(SpawnChildWithOptions("SimpleChildProcess", options));
+
+  char name[256] = {};
+  size_t name_size = sizeof(name);
+  zx_status_t status =
+      zx_object_get_property(process.Handle(), ZX_PROP_NAME, name, name_size);
+  ASSERT_EQ(status, ZX_OK);
+  EXPECT_EQ(std::string(name),
+            CommandLine::ForCurrentProcess()->GetProgram().BaseName().value() +
+                "#test");
+}
+
 #endif  // defined(OS_FUCHSIA)
 
 // On Android SpawnProcess() doesn't use LaunchProcess() and doesn't support
diff --git a/base/task/post_job.cc b/base/task/post_job.cc
index e57b32e..df0a981 100644
--- a/base/task/post_job.cc
+++ b/base/task/post_job.cc
@@ -5,49 +5,16 @@
 #include "base/task/post_job.h"
 
 #include "base/task/thread_pool/job_task_source.h"
-#include "base/task/thread_pool/pooled_task_runner_delegate.h"
 
 namespace base {
 namespace experimental {
 
-JobDelegate::JobDelegate(
-    internal::JobTaskSource* task_source,
-    internal::PooledTaskRunnerDelegate* pooled_task_runner_delegate)
-    : task_source_(task_source),
-      pooled_task_runner_delegate_(pooled_task_runner_delegate) {
-  DCHECK(task_source_);
-  DCHECK(pooled_task_runner_delegate_);
-#if DCHECK_IS_ON()
-  recorded_increase_version_ = task_source_->GetConcurrencyIncreaseVersion();
-  // Record max concurrency before running the worker task.
-  recorded_max_concurrency_ = task_source_->GetMaxConcurrency();
-#endif  // DCHECK_IS_ON()
-}
-
-JobDelegate::~JobDelegate() {
-#if DCHECK_IS_ON()
-  // When ShouldYield() returns false, the worker task is expected to do
-  // work before returning.
-  size_t expected_max_concurrency = recorded_max_concurrency_;
-  if (!last_should_yield_ && expected_max_concurrency > 0)
-    --expected_max_concurrency;
-  AssertExpectedConcurrency(expected_max_concurrency);
-#endif  // DCHECK_IS_ON()
-}
+JobDelegate::JobDelegate(internal::JobTaskSource* task_source)
+    : task_source_(task_source) {}
 
 bool JobDelegate::ShouldYield() {
-#if DCHECK_IS_ON()
-  // ShouldYield() shouldn't be called again after returning true.
-  DCHECK(!last_should_yield_);
-  AssertExpectedConcurrency(recorded_max_concurrency_);
-#endif  // DCHECK_IS_ON()
-  const bool should_yield =
-      pooled_task_runner_delegate_->ShouldYield(task_source_);
-
-#if DCHECK_IS_ON()
-  last_should_yield_ = should_yield;
-#endif  // DCHECK_IS_ON()
-  return should_yield;
+  // TODO(crbug.com/839091): Implement this.
+  return false;
 }
 
 void JobDelegate::YieldIfNeeded() {
@@ -58,45 +25,5 @@
   task_source_->NotifyConcurrencyIncrease();
 }
 
-void JobDelegate::AssertExpectedConcurrency(size_t expected_max_concurrency) {
-  // In dcheck builds, verify that max concurrency falls in one of the following
-  // cases:
-  // 1) max concurrency behaves normally and is below or equals the expected
-  //    value.
-  // 2) max concurrency increased above the expected value, which implies
-  //    there are new work items that the associated worker task didn't see and
-  //    NotifyConcurrencyIncrease() should be called to adjust the number of
-  //    worker.
-  //   a) NotifyConcurrencyIncrease() was already called and the recorded
-  //      concurrency version is out of date, i.e. less than the actual version.
-  //   b) NotifyConcurrencyIncrease() has not yet been called, in which case the
-  //      function waits for an imminent increase of the concurrency version.
-  // This prevent ill-formed GetMaxConcurrency() implementations that:
-  // - Don't decrease with the number of remaining work items.
-  // - Don't return an up-to-date value.
-#if DCHECK_IS_ON()
-  // Case 1:
-  const size_t max_concurrency = task_source_->GetMaxConcurrency();
-  if (max_concurrency <= expected_max_concurrency)
-    return;
-
-  // Case 2a:
-  const size_t actual_version = task_source_->GetConcurrencyIncreaseVersion();
-  DCHECK_LE(recorded_increase_version_, actual_version);
-  if (recorded_increase_version_ < actual_version)
-    return;
-
-  // Case 2b:
-  const bool updated = task_source_->WaitForConcurrencyIncreaseUpdate(
-      recorded_increase_version_);
-  DCHECK(updated)
-      << "Value returned by |max_concurrency_callback| is expected to "
-         "decrease, unless NotifyConcurrencyIncrease() is called.";
-
-  recorded_increase_version_ = task_source_->GetConcurrencyIncreaseVersion();
-  recorded_max_concurrency_ = task_source_->GetMaxConcurrency();
-#endif  // DCHECK_IS_ON()
-}
-
 }  // namespace experimental
 }  // namespace base
\ No newline at end of file
diff --git a/base/task/post_job.h b/base/task/post_job.h
index de6b2d6..94ab75c 100644
--- a/base/task/post_job.h
+++ b/base/task/post_job.h
@@ -6,14 +6,12 @@
 #define BASE_TASK_POST_JOB_H_
 
 #include "base/base_export.h"
-#include "base/logging.h"
 #include "base/macros.h"
 #include "base/time/time.h"
 
 namespace base {
 namespace internal {
 class JobTaskSource;
-class PooledTaskRunnerDelegate;
 }
 namespace experimental {
 
@@ -21,13 +19,7 @@
 // communicate with the scheduler.
 class BASE_EXPORT JobDelegate {
  public:
-  // A JobDelegate is instantiated for each worker task that is run.
-  // |task_source| is the task source whose worker task is running with this
-  // delegate and |pooled_task_runner_delegate| provides communication with the
-  // thread pool.
-  JobDelegate(internal::JobTaskSource* task_source,
-              internal::PooledTaskRunnerDelegate* pooled_task_runner_delegate);
-  ~JobDelegate();
+  explicit JobDelegate(internal::JobTaskSource* task_source);
 
   // Returns true if this thread should return from the worker task on the
   // current thread ASAP. Workers should periodically invoke ShouldYield (or
@@ -46,25 +38,7 @@
   void NotifyConcurrencyIncrease();
 
  private:
-  // Verifies that either max concurrency is lower or equal to
-  // |expected_max_concurrency|, or there is an increase version update
-  // triggered by NotifyConcurrencyIncrease().
-  void AssertExpectedConcurrency(size_t expected_max_concurrency);
-
   internal::JobTaskSource* const task_source_;
-  internal::PooledTaskRunnerDelegate* const pooled_task_runner_delegate_;
-
-#if DCHECK_IS_ON()
-  // Used in AssertExpectedConcurrency(), see that method's impl for details.
-  // Value of max concurrency recorded before running the worker task.
-  size_t recorded_max_concurrency_;
-  // Value of the increase version recorded before running the worker task.
-  size_t recorded_increase_version_;
-  // Value returned by the last call to ShouldYield().
-  bool last_should_yield_ = false;
-#endif
-
-  DISALLOW_COPY_AND_ASSIGN(JobDelegate);
 };
 
 }  // namespace experimental
diff --git a/base/task/thread_pool/job_task_source.cc b/base/task/thread_pool/job_task_source.cc
index c6e5f97..25ff987 100644
--- a/base/task/thread_pool/job_task_source.cc
+++ b/base/task/thread_pool/job_task_source.cc
@@ -11,10 +11,7 @@
 #include "base/logging.h"
 #include "base/memory/ptr_util.h"
 #include "base/task/task_features.h"
-#include "base/task/thread_pool/pooled_task_runner_delegate.h"
-#include "base/threading/thread_restrictions.h"
 #include "base/time/time.h"
-#include "base/time/time_override.h"
 
 namespace base {
 namespace internal {
@@ -23,8 +20,7 @@
     const Location& from_here,
     const TaskTraits& traits,
     RepeatingCallback<void(experimental::JobDelegate*)> worker_task,
-    RepeatingCallback<size_t()> max_concurrency_callback,
-    PooledTaskRunnerDelegate* delegate)
+    RepeatingCallback<size_t()> max_concurrency_callback)
     : TaskSource(traits, nullptr, TaskSourceExecutionMode::kJob),
       from_here_(from_here),
       max_concurrency_callback_(std::move(max_concurrency_callback)),
@@ -33,15 +29,14 @@
              const RepeatingCallback<void(experimental::JobDelegate*)>&
                  worker_task) {
             // Each worker task has its own delegate with associated state.
-            experimental::JobDelegate job_delegate{self, self->delegate_};
+            // TODO(crbug.com/839091): Implement assertions on max concurrency
+            // increase in the delegate.
+            experimental::JobDelegate job_delegate{self};
             worker_task.Run(&job_delegate);
           },
           base::Unretained(this),
           std::move(worker_task))),
-      queue_time_(TimeTicks::Now()),
-      delegate_(delegate) {
-  DCHECK(delegate_);
-}
+      queue_time_(TimeTicks::Now()) {}
 
 JobTaskSource::~JobTaskSource() {
 #if DCHECK_IS_ON()
@@ -105,52 +100,16 @@
 }
 
 void JobTaskSource::NotifyConcurrencyIncrease() {
-#if DCHECK_IS_ON()
-  {
-    AutoLock auto_lock(version_lock_);
-    ++increase_version_;
-    version_condition_.Broadcast();
-  }
-#endif  // DCHECK_IS_ON()
-  // Make sure the task source is in the queue if not already.
-  // Caveat: it's possible but unlikely that the task source has already reached
-  // its intended concurrency and doesn't need to be enqueued if there
-  // previously were too many worker. For simplicity, the task source is always
-  // enqueued and will get discarded if already saturated when it is popped from
-  // the priority queue.
-  delegate_->EnqueueJobTaskSource(this);
+  // TODO(839091): Implement this.
 }
 
 size_t JobTaskSource::GetMaxConcurrency() const {
   return max_concurrency_callback_.Run();
 }
 
-#if DCHECK_IS_ON()
-
-size_t JobTaskSource::GetConcurrencyIncreaseVersion() const {
-  AutoLock auto_lock(version_lock_);
-  return increase_version_;
-}
-
-bool JobTaskSource::WaitForConcurrencyIncreaseUpdate(size_t recorded_version) {
-  AutoLock auto_lock(version_lock_);
-  constexpr TimeDelta timeout = TimeDelta::FromSeconds(1);
-  const base::TimeTicks start_time = subtle::TimeTicksNowIgnoringOverride();
-  do {
-    DCHECK_LE(recorded_version, increase_version_);
-    if (recorded_version != increase_version_)
-      return true;
-    // Waiting is acceptable because it is in DCHECK-only code.
-    ScopedAllowBaseSyncPrimitivesOutsideBlockingScope
-        allow_base_sync_primitives;
-    version_condition_.TimedWait(timeout);
-  } while (subtle::TimeTicksNowIgnoringOverride() - start_time < timeout);
-  return false;
-}
-
-#endif  // DCHECK_IS_ON()
-
 Optional<Task> JobTaskSource::TakeTask(TaskSource::Transaction* transaction) {
+  // JobTaskSource members are not lock-protected so no need to acquire a lock
+  // if |transaction| is nullptr.
   DCHECK_GT(worker_count_.load(std::memory_order_relaxed), 0U);
   DCHECK(worker_task_);
   return base::make_optional<Task>(from_here_, worker_task_, TimeDelta());
diff --git a/base/task/thread_pool/job_task_source.h b/base/task/thread_pool/job_task_source.h
index ddaca19..58000b0 100644
--- a/base/task/thread_pool/job_task_source.h
+++ b/base/task/thread_pool/job_task_source.h
@@ -14,8 +14,6 @@
 #include "base/callback.h"
 #include "base/macros.h"
 #include "base/optional.h"
-#include "base/synchronization/condition_variable.h"
-#include "base/synchronization/lock.h"
 #include "base/task/post_job.h"
 #include "base/task/task_traits.h"
 #include "base/task/thread_pool/sequence_sort_key.h"
@@ -25,8 +23,6 @@
 namespace base {
 namespace internal {
 
-class PooledTaskRunnerDelegate;
-
 // A JobTaskSource generates many Tasks from a single RepeatingClosure.
 //
 // Derived classes control the intended concurrency with GetMaxConcurrency().
@@ -35,8 +31,7 @@
   JobTaskSource(const Location& from_here,
                 const TaskTraits& traits,
                 RepeatingCallback<void(experimental::JobDelegate*)> worker_task,
-                RepeatingCallback<size_t()> max_concurrency_callback,
-                PooledTaskRunnerDelegate* delegate);
+                RepeatingCallback<size_t()> max_concurrency_callback);
 
   // Notifies this task source that max concurrency was increased, and the
   // number of worker should be adjusted.
@@ -46,23 +41,17 @@
   ExecutionEnvironment GetExecutionEnvironment() override;
   size_t GetRemainingConcurrency() const override;
 
-  // Returns the maximum number of tasks from this TaskSource that can run
-  // concurrently.
-  size_t GetMaxConcurrency() const;
-
-#if DCHECK_IS_ON()
-  size_t GetConcurrencyIncreaseVersion() const;
-  // Returns true if the concurrency version was updated above
-  // |recorded_version|, or false on timeout.
-  bool WaitForConcurrencyIncreaseUpdate(size_t recorded_version);
-#endif  // DCHECK_IS_ON()
-
  private:
   static constexpr size_t kInvalidWorkerCount =
       std::numeric_limits<size_t>::max();
 
   ~JobTaskSource() override;
 
+  // Returns the maximum number of tasks from this TaskSource that can run
+  // concurrently. The implementation can only return values lower than or equal
+  // to previously returned values.
+  size_t GetMaxConcurrency() const;
+
   // TaskSource:
   RunStatus WillRunTask() override;
   Optional<Task> TakeTask(TaskSource::Transaction* transaction) override;
@@ -78,16 +67,6 @@
   base::RepeatingCallback<size_t()> max_concurrency_callback_;
   base::RepeatingClosure worker_task_;
   const TimeTicks queue_time_;
-  PooledTaskRunnerDelegate* delegate_;
-
-#if DCHECK_IS_ON()
-  // Synchronizes accesses to |increase_version_|.
-  mutable Lock version_lock_;
-  // Signaled whenever increase_version_ is updated.
-  ConditionVariable version_condition_{&version_lock_};
-  // Incremented every time max concurrency is increased.
-  size_t increase_version_ GUARDED_BY(version_lock_) = 0;
-#endif  // DCHECK_IS_ON()
 
   DISALLOW_COPY_AND_ASSIGN(JobTaskSource);
 };
diff --git a/base/task/thread_pool/job_task_source_unittest.cc b/base/task/thread_pool/job_task_source_unittest.cc
index 8d911a5..0483011 100644
--- a/base/task/thread_pool/job_task_source_unittest.cc
+++ b/base/task/thread_pool/job_task_source_unittest.cc
@@ -8,45 +8,20 @@
 
 #include "base/bind_helpers.h"
 #include "base/memory/ptr_util.h"
-#include "base/task/thread_pool/pooled_task_runner_delegate.h"
 #include "base/task/thread_pool/test_utils.h"
 #include "base/test/bind_test_util.h"
 #include "base/test/gtest_util.h"
-#include "base/test/test_timeouts.h"
-#include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
-using ::testing::_;
-using ::testing::Return;
-
 namespace base {
 namespace internal {
 
-class MockPooledTaskRunnerDelegate : public PooledTaskRunnerDelegate {
- public:
-  MOCK_METHOD2(PostTaskWithSequence,
-               bool(Task task, scoped_refptr<Sequence> sequence));
-  MOCK_CONST_METHOD1(ShouldYield, bool(TaskSource* task_source));
-  MOCK_METHOD1(EnqueueJobTaskSource,
-               bool(scoped_refptr<JobTaskSource> task_source));
-  MOCK_CONST_METHOD1(IsRunningPoolWithTraits, bool(const TaskTraits& traits));
-  MOCK_METHOD2(UpdatePriority,
-               void(scoped_refptr<TaskSource> task_source,
-                    TaskPriority priority));
-};
-
-class ThreadPoolJobTaskSourceTest : public testing::Test {
- protected:
-  testing::StrictMock<MockPooledTaskRunnerDelegate>
-      pooled_task_runner_delegate_;
-};
-
 // Verifies the normal flow of running 2 tasks one after the other.
-TEST_F(ThreadPoolJobTaskSourceTest, RunTasks) {
+TEST(ThreadPoolJobTaskSourceTest, RunTasks) {
   auto job_task = base::MakeRefCounted<test::MockJobTask>(
       DoNothing(), /* num_tasks_to_run */ 2);
   scoped_refptr<JobTaskSource> task_source = job_task->GetJobTaskSource(
-      FROM_HERE, ThreadPool(), &pooled_task_runner_delegate_);
+      FROM_HERE, {ThreadPool(), TaskPriority::BEST_EFFORT});
   auto registered_task_source =
       RegisteredTaskSource::CreateForTesting(task_source);
 
@@ -80,11 +55,11 @@
 
 // Verifies that a job task source doesn't allow any new RunStatus after Clear()
 // is called.
-TEST_F(ThreadPoolJobTaskSourceTest, Clear) {
+TEST(ThreadPoolJobTaskSourceTest, Clear) {
   auto job_task = base::MakeRefCounted<test::MockJobTask>(
       DoNothing(), /* num_tasks_to_run */ 5);
   scoped_refptr<JobTaskSource> task_source = job_task->GetJobTaskSource(
-      FROM_HERE, ThreadPool(), &pooled_task_runner_delegate_);
+      FROM_HERE, {ThreadPool(), TaskPriority::BEST_EFFORT});
 
   EXPECT_EQ(5U, task_source->GetRemainingConcurrency());
   auto registered_task_source_a =
@@ -141,11 +116,11 @@
 }
 
 // Verifies that multiple tasks can run in parallel up to |max_concurrency|.
-TEST_F(ThreadPoolJobTaskSourceTest, RunTasksInParallel) {
+TEST(ThreadPoolJobTaskSourceTest, RunTasksInParallel) {
   auto job_task = base::MakeRefCounted<test::MockJobTask>(
       DoNothing(), /* num_tasks_to_run */ 2);
   scoped_refptr<JobTaskSource> task_source = job_task->GetJobTaskSource(
-      FROM_HERE, ThreadPool(), &pooled_task_runner_delegate_);
+      FROM_HERE, {ThreadPool(), TaskPriority::BEST_EFFORT});
 
   auto registered_task_source_a =
       RegisteredTaskSource::CreateForTesting(task_source);
@@ -183,138 +158,12 @@
   EXPECT_FALSE(registered_task_source_c.DidProcessTask());
 }
 
-// Verifies that a call to NotifyConcurrencyIncrease() calls the delegate
-// and allows to run additional tasks.
-TEST_F(ThreadPoolJobTaskSourceTest, NotifyConcurrencyIncrease) {
-  auto job_task = base::MakeRefCounted<test::MockJobTask>(
-      DoNothing(), /* num_tasks_to_run */ 1);
-  scoped_refptr<JobTaskSource> task_source = job_task->GetJobTaskSource(
-      FROM_HERE, ThreadPool(), &pooled_task_runner_delegate_);
-
-  auto registered_task_source_a =
-      RegisteredTaskSource::CreateForTesting(task_source);
-  EXPECT_EQ(registered_task_source_a.WillRunTask(),
-            TaskSource::RunStatus::kAllowedSaturated);
-  auto task_a = registered_task_source_a.TakeTask();
-  EXPECT_EQ(RegisteredTaskSource::CreateForTesting(task_source).WillRunTask(),
-            TaskSource::RunStatus::kDisallowed);
-
-  job_task->SetNumTasksToRun(2);
-  EXPECT_CALL(pooled_task_runner_delegate_, EnqueueJobTaskSource(_)).Times(1);
-  task_source->NotifyConcurrencyIncrease();
-
-  auto registered_task_source_b =
-      RegisteredTaskSource::CreateForTesting(task_source);
-  // WillRunTask() should return a valid RunStatus because max concurrency was
-  // increased to 2.
-  EXPECT_EQ(registered_task_source_b.WillRunTask(),
-            TaskSource::RunStatus::kAllowedSaturated);
-  auto task_b = registered_task_source_b.TakeTask();
-  EXPECT_EQ(RegisteredTaskSource::CreateForTesting(task_source).WillRunTask(),
-            TaskSource::RunStatus::kDisallowed);
-
-  std::move(task_a->task).Run();
-  EXPECT_FALSE(registered_task_source_a.DidProcessTask());
-
-  std::move(task_b->task).Run();
-  EXPECT_FALSE(registered_task_source_b.DidProcessTask());
-}
-
-// Verifies that ShouldYield() calls the delegate.
-TEST_F(ThreadPoolJobTaskSourceTest, ShouldYield) {
-  auto job_task = base::MakeRefCounted<test::MockJobTask>(
-      BindLambdaForTesting([](experimental::JobDelegate* delegate) {
-        // As set up below, the mock will return false once and true the second
-        // time.
-        EXPECT_FALSE(delegate->ShouldYield());
-        EXPECT_TRUE(delegate->ShouldYield());
-      }),
-      /* num_tasks_to_run */ 1);
-  scoped_refptr<JobTaskSource> task_source = job_task->GetJobTaskSource(
-      FROM_HERE, ThreadPool(), &pooled_task_runner_delegate_);
-
-  auto registered_task_source =
-      RegisteredTaskSource::CreateForTesting(task_source);
-  ASSERT_EQ(registered_task_source.WillRunTask(),
-            TaskSource::RunStatus::kAllowedSaturated);
-
-  auto task = registered_task_source.TakeTask();
-
-  EXPECT_CALL(pooled_task_runner_delegate_, ShouldYield(_))
-      .Times(2)
-      .WillOnce(Return(false))
-      .WillOnce(Return(true));
-
-  std::move(task->task).Run();
-  EXPECT_FALSE(registered_task_source.DidProcessTask());
-}
-
-// Verifies that max concurrency is allowed to stagnate when ShouldYield returns
-// true.
-TEST_F(ThreadPoolJobTaskSourceTest, MaxConcurrencyStagnateIfShouldYield) {
-  scoped_refptr<JobTaskSource> task_source =
-      base::MakeRefCounted<JobTaskSource>(
-          FROM_HERE, ThreadPool(),
-          BindRepeating([](experimental::JobDelegate* delegate) {
-            // As set up below, the mock will return true once.
-            ASSERT_TRUE(delegate->ShouldYield());
-          }),
-          BindRepeating([]() -> size_t {
-            return 1;  // max concurrency is always 1.
-          }),
-          &pooled_task_runner_delegate_);
-
-  EXPECT_CALL(pooled_task_runner_delegate_, ShouldYield(_))
-      .WillOnce(Return(true));
-
-  auto registered_task_source =
-      RegisteredTaskSource::CreateForTesting(task_source);
-  ASSERT_EQ(registered_task_source.WillRunTask(),
-            TaskSource::RunStatus::kAllowedSaturated);
-  auto task = registered_task_source.TakeTask();
-
-  // Running the task should not fail even though max concurrency remained at 1,
-  // since ShouldYield() returned true.
-  std::move(task->task).Run();
-  registered_task_source.DidProcessTask();
-}
-
-// Verifies that a missing call to NotifyConcurrencyIncrease() causes a DCHECK
-// death after a timeout.
-TEST_F(ThreadPoolJobTaskSourceTest, InvalidConcurrency) {
-  testing::FLAGS_gtest_death_test_style = "threadsafe";
-
-  scoped_refptr<test::MockJobTask> job_task;
-  job_task = base::MakeRefCounted<test::MockJobTask>(
-      BindLambdaForTesting([&](experimental::JobDelegate* delegate) {
-        EXPECT_FALSE(delegate->ShouldYield());
-        job_task->SetNumTasksToRun(2);
-        EXPECT_FALSE(delegate->ShouldYield());
-
-        // After returning, a DCHECK should trigger because we never called
-        // NotifyConcurrencyIncrease().
-      }),
-      /* num_tasks_to_run */ 1);
-  scoped_refptr<JobTaskSource> task_source = job_task->GetJobTaskSource(
-      FROM_HERE, ThreadPool(), &pooled_task_runner_delegate_);
-
-  auto registered_task_source =
-      RegisteredTaskSource::CreateForTesting(task_source);
-  ASSERT_EQ(registered_task_source.WillRunTask(),
-            TaskSource::RunStatus::kAllowedSaturated);
-  auto task = registered_task_source.TakeTask();
-
-  EXPECT_DCHECK_DEATH(std::move(task->task).Run());
-
-  registered_task_source.DidProcessTask();
-}
-
-TEST_F(ThreadPoolJobTaskSourceTest, InvalidTakeTask) {
+TEST(ThreadPoolJobTaskSourceTest, InvalidTakeTask) {
   auto job_task =
       base::MakeRefCounted<test::MockJobTask>(DoNothing(),
                                               /* num_tasks_to_run */ 1);
   scoped_refptr<JobTaskSource> task_source = job_task->GetJobTaskSource(
-      FROM_HERE, ThreadPool(), &pooled_task_runner_delegate_);
+      FROM_HERE, {ThreadPool(), TaskPriority::BEST_EFFORT});
 
   auto registered_task_source_a =
       RegisteredTaskSource::CreateForTesting(task_source);
@@ -333,12 +182,12 @@
   registered_task_source_a.DidProcessTask();
 }
 
-TEST_F(ThreadPoolJobTaskSourceTest, InvalidDidProcessTask) {
+TEST(ThreadPoolJobTaskSourceTest, InvalidDidProcessTask) {
   auto job_task =
       base::MakeRefCounted<test::MockJobTask>(DoNothing(),
                                               /* num_tasks_to_run */ 1);
   scoped_refptr<JobTaskSource> task_source = job_task->GetJobTaskSource(
-      FROM_HERE, ThreadPool(), &pooled_task_runner_delegate_);
+      FROM_HERE, {ThreadPool(), TaskPriority::BEST_EFFORT});
 
   auto registered_task_source =
       RegisteredTaskSource::CreateForTesting(task_source);
diff --git a/base/task/thread_pool/pooled_task_runner_delegate.h b/base/task/thread_pool/pooled_task_runner_delegate.h
index f6687bd..46dbe39 100644
--- a/base/task/thread_pool/pooled_task_runner_delegate.h
+++ b/base/task/thread_pool/pooled_task_runner_delegate.h
@@ -27,11 +27,6 @@
   // outlives the ThreadPoolInstance that created it.
   static bool Exists();
 
-  // Returns true if |task_source| currently running must return ASAP.
-  // Thread-safe but may return an outdated result (if a task unnecessarily
-  // yields due to this, it will simply be re-scheduled).
-  virtual bool ShouldYield(TaskSource* task_source) const = 0;
-
   // Invoked when a |task| is posted to the PooledParallelTaskRunner or
   // PooledSequencedTaskRunner. The implementation must post |task| to
   // |sequence| within the appropriate priority queue, depending on |sequence|
@@ -41,8 +36,7 @@
 
   // Invoked when a task is posted as a Job. The implementation must add
   // |task_source| to the appropriate priority queue, depending on |task_source|
-  // traits, if it's not there already. Returns true if task source was
-  // successfully enqueued or was already enqueued.
+  // traits. Returns true if task source was successfully enqueued.
   virtual bool EnqueueJobTaskSource(
       scoped_refptr<JobTaskSource> task_source) = 0;
 
diff --git a/base/task/thread_pool/task_source.cc b/base/task/thread_pool/task_source.cc
index 271988c..1cf36d5 100644
--- a/base/task/thread_pool/task_source.cc
+++ b/base/task/thread_pool/task_source.cc
@@ -40,8 +40,6 @@
   if (FeatureList::IsEnabled(kAllTasksUserBlocking))
     return;
   task_source_->traits_.UpdatePriority(priority);
-  task_source_->priority_racy_.store(task_source_->traits_.priority(),
-                                     std::memory_order_relaxed);
 }
 
 void TaskSource::SetHeapHandle(const HeapHandle& handle) {
@@ -56,7 +54,6 @@
                        TaskRunner* task_runner,
                        TaskSourceExecutionMode execution_mode)
     : traits_(traits),
-      priority_racy_(traits.priority()),
       task_runner_(task_runner),
       execution_mode_(execution_mode) {
   DCHECK(task_runner_ ||
diff --git a/base/task/thread_pool/task_source.h b/base/task/thread_pool/task_source.h
index e56b42e..df8bebe 100644
--- a/base/task/thread_pool/task_source.h
+++ b/base/task/thread_pool/task_source.h
@@ -160,14 +160,6 @@
   TaskShutdownBehavior shutdown_behavior() const {
     return traits_.shutdown_behavior();
   }
-  // Returns a racy priority of the TaskSource. Can be accessed without a
-  // Transaction but may return an outdated result.
-  TaskPriority priority_racy() const {
-    return priority_racy_.load(std::memory_order_relaxed);
-  }
-  // Returns the thread policy of the TaskSource. Can be accessed without a
-  // Transaction because it is never mutated.
-  ThreadPolicy thread_policy() const { return traits_.thread_policy(); }
 
   // A reference to TaskRunner is only retained between PushTask() and when
   // DidProcessTask() returns false, guaranteeing it is safe to dereference this
@@ -201,9 +193,6 @@
   // The TaskTraits of all Tasks in the TaskSource.
   TaskTraits traits_;
 
-  // The cached priority for atomic access.
-  std::atomic<TaskPriority> priority_racy_;
-
   // Synchronizes access to all members.
   mutable CheckedLock lock_{UniversalPredecessor()};
 
diff --git a/base/task/thread_pool/test_utils.cc b/base/task/thread_pool/test_utils.cc
index 02ae793..3d7a2bb 100644
--- a/base/task/thread_pool/test_utils.cc
+++ b/base/task/thread_pool/test_utils.cc
@@ -56,8 +56,8 @@
     return false;
 
   auto job_task = base::MakeRefCounted<MockJobTask>(std::move(closure));
-  scoped_refptr<JobTaskSource> task_source = job_task->GetJobTaskSource(
-      from_here, traits_, pooled_task_runner_delegate_);
+  scoped_refptr<JobTaskSource> task_source =
+      job_task->GetJobTaskSource(from_here, traits_);
   return pooled_task_runner_delegate_->EnqueueJobTaskSource(
       std::move(task_source));
 }
@@ -217,10 +217,6 @@
   }
 }
 
-bool MockPooledTaskRunnerDelegate::ShouldYield(TaskSource* task_source) const {
-  return thread_group_->ShouldYield(task_source->priority_racy());
-}
-
 bool MockPooledTaskRunnerDelegate::EnqueueJobTaskSource(
     scoped_refptr<JobTaskSource> task_source) {
   // |thread_group_| must be initialized with SetThreadGroup() before
@@ -281,6 +277,8 @@
 }
 
 void MockJobTask::Run(experimental::JobDelegate* delegate) {
+  if (delegate->ShouldYield())
+    return;
   worker_task_.Run(delegate);
   size_t before = remaining_num_tasks_to_run_.fetch_sub(1);
   DCHECK_GT(before, 0U);
@@ -288,12 +286,10 @@
 
 scoped_refptr<JobTaskSource> MockJobTask::GetJobTaskSource(
     const Location& from_here,
-    const TaskTraits& traits,
-    PooledTaskRunnerDelegate* delegate) {
+    const TaskTraits& traits) {
   return MakeRefCounted<JobTaskSource>(
       from_here, traits, base::BindRepeating(&test::MockJobTask::Run, this),
-      base::BindRepeating(&test::MockJobTask::GetMaxConcurrency, this),
-      delegate);
+      base::BindRepeating(&test::MockJobTask::GetMaxConcurrency, this));
 }
 
 RegisteredTaskSource QueueAndRunTaskSource(
diff --git a/base/task/thread_pool/test_utils.h b/base/task/thread_pool/test_utils.h
index cc378fc..554c205 100644
--- a/base/task/thread_pool/test_utils.h
+++ b/base/task/thread_pool/test_utils.h
@@ -62,7 +62,6 @@
   bool PostTaskWithSequence(Task task,
                             scoped_refptr<Sequence> sequence) override;
   bool EnqueueJobTaskSource(scoped_refptr<JobTaskSource> task_source) override;
-  bool ShouldYield(TaskSource* task_source) const override;
   bool IsRunningPoolWithTraits(const TaskTraits& traits) const override;
   void UpdatePriority(scoped_refptr<TaskSource> task_source,
                       TaskPriority priority) override;
@@ -82,6 +81,8 @@
 class MockJobTask : public base::RefCountedThreadSafe<MockJobTask> {
  public:
   // Gives |worker_task| to requesting workers |num_tasks_to_run| times.
+  // ShouldYield() is automatically called on JobDelegate before running
+  // |worker_task| so that DoNothing() may be passed.
   MockJobTask(
       base::RepeatingCallback<void(experimental::JobDelegate*)> worker_task,
       size_t num_tasks_to_run);
@@ -98,10 +99,8 @@
   size_t GetMaxConcurrency() const;
   void Run(experimental::JobDelegate* delegate);
 
-  scoped_refptr<JobTaskSource> GetJobTaskSource(
-      const Location& from_here,
-      const TaskTraits& traits,
-      PooledTaskRunnerDelegate* delegate);
+  scoped_refptr<JobTaskSource> GetJobTaskSource(const Location& from_here,
+                                                const TaskTraits& traits);
 
  private:
   friend class base::RefCountedThreadSafe<MockJobTask>;
diff --git a/base/task/thread_pool/thread_group_impl_unittest.cc b/base/task/thread_pool/thread_group_impl_unittest.cc
index 50baf9ab..771b3ff 100644
--- a/base/task/thread_pool/thread_group_impl_unittest.cc
+++ b/base/task/thread_pool/thread_group_impl_unittest.cc
@@ -311,8 +311,7 @@
       }),
       /* num_tasks_to_run */ kMaxTasks);
   scoped_refptr<JobTaskSource> task_source = job_task->GetJobTaskSource(
-      FROM_HERE, {ThreadPool(), TaskPriority::USER_VISIBLE},
-      &mock_pooled_task_runner_delegate_);
+      FROM_HERE, {ThreadPool(), TaskPriority::USER_VISIBLE});
 
   auto registered_task_source = task_tracker_.RegisterTaskSource(task_source);
   ASSERT_TRUE(registered_task_source);
diff --git a/base/task/thread_pool/thread_group_unittest.cc b/base/task/thread_pool/thread_group_unittest.cc
index cb4481c..4bb81dc 100644
--- a/base/task/thread_pool/thread_group_unittest.cc
+++ b/base/task/thread_pool/thread_group_unittest.cc
@@ -596,8 +596,8 @@
         test::WaitWithoutBlockingObserver(&threads_continue);
       }),
       /* num_tasks_to_run */ kMaxTasks);
-  scoped_refptr<JobTaskSource> task_source = job_task->GetJobTaskSource(
-      FROM_HERE, ThreadPool(), &mock_pooled_task_runner_delegate_);
+  scoped_refptr<JobTaskSource> task_source =
+      job_task->GetJobTaskSource(FROM_HERE, {ThreadPool()});
 
   auto registered_task_source =
       task_tracker_.RegisterTaskSource(std::move(task_source));
@@ -614,95 +614,6 @@
   task_tracker_.FlushForTesting();
 }
 
-// Verify that tasks from a JobTaskSource run at the intended concurrency.
-TEST_P(ThreadGroupTest, ScheduleJobTaskSourceMultipleTime) {
-  StartThreadGroup();
-
-  WaitableEvent thread_running;
-  WaitableEvent thread_continue;
-  auto job_task = base::MakeRefCounted<test::MockJobTask>(
-      BindLambdaForTesting(
-          [&thread_running, &thread_continue](experimental::JobDelegate*) {
-            DCHECK(!thread_running.IsSignaled());
-            thread_running.Signal();
-            test::WaitWithoutBlockingObserver(&thread_continue);
-          }),
-      /* num_tasks_to_run */ 1);
-  scoped_refptr<JobTaskSource> task_source = job_task->GetJobTaskSource(
-      FROM_HERE, ThreadPool(), &mock_pooled_task_runner_delegate_);
-
-  thread_group_->PushTaskSourceAndWakeUpWorkers(
-      TransactionWithRegisteredTaskSource::FromTaskSource(
-          task_tracker_.RegisterTaskSource(task_source)));
-
-  // Enqueuing the task source again shouldn't affect the number of time it's
-  // run.
-  thread_group_->PushTaskSourceAndWakeUpWorkers(
-      TransactionWithRegisteredTaskSource::FromTaskSource(
-          task_tracker_.RegisterTaskSource(task_source)));
-
-  thread_running.Wait();
-  thread_continue.Signal();
-
-  // Once the worker task ran, enqueuing the task source has no effect.
-  thread_group_->PushTaskSourceAndWakeUpWorkers(
-      TransactionWithRegisteredTaskSource::FromTaskSource(
-          task_tracker_.RegisterTaskSource(task_source)));
-
-  // Flush the task tracker to be sure that no local variables are accessed by
-  // tasks after the end of the scope.
-  task_tracker_.FlushForTesting();
-}
-
-// Verify that calling JobTaskSource::NotifyConcurrencyIncrease() (re-)schedule
-// tasks with the intended concurrency.
-TEST_P(ThreadGroupTest, JobTaskSourceConcurrencyIncrease) {
-  StartThreadGroup();
-
-  WaitableEvent threads_running_a;
-  WaitableEvent threads_continue;
-
-  // Initially schedule half the tasks.
-  RepeatingClosure threads_running_barrier = BarrierClosure(
-      kMaxTasks / 2,
-      BindOnce(&WaitableEvent::Signal, Unretained(&threads_running_a)));
-
-  auto job_state = base::MakeRefCounted<test::MockJobTask>(
-      BindLambdaForTesting([&threads_running_barrier,
-                            &threads_continue](experimental::JobDelegate*) {
-        threads_running_barrier.Run();
-        test::WaitWithoutBlockingObserver(&threads_continue);
-      }),
-      /* num_tasks_to_run */ kMaxTasks / 2);
-  auto task_source = job_state->GetJobTaskSource(
-      FROM_HERE, ThreadPool(), &mock_pooled_task_runner_delegate_);
-
-  auto registered_task_source = task_tracker_.RegisterTaskSource(task_source);
-  EXPECT_TRUE(registered_task_source);
-  thread_group_->PushTaskSourceAndWakeUpWorkers(
-      TransactionWithRegisteredTaskSource::FromTaskSource(
-          std::move(registered_task_source)));
-
-  threads_running_a.Wait();
-  // Reset |threads_running_barrier| for the remaining tasks.
-  WaitableEvent threads_running_b;
-  threads_running_barrier = BarrierClosure(
-      kMaxTasks / 2,
-      BindOnce(&WaitableEvent::Signal, Unretained(&threads_running_b)));
-  job_state->SetNumTasksToRun(kMaxTasks);
-
-  // Unblocks tasks to let them racily wait for NotifyConcurrencyIncrease() to
-  // be called.
-  threads_continue.Signal();
-  task_source->NotifyConcurrencyIncrease();
-  // Wait for the remaining tasks. This should not block forever.
-  threads_running_b.Wait();
-
-  // Flush the task tracker to be sure that no local variables are accessed by
-  // tasks after the end of the scope.
-  task_tracker_.FlushForTesting();
-}
-
 // Verify that a JobTaskSource that becomes empty while in the queue eventually
 // gets discarded.
 TEST_P(ThreadGroupTest, ScheduleEmptyJobTaskSource) {
@@ -713,8 +624,8 @@
   auto job_task = base::MakeRefCounted<test::MockJobTask>(
       BindRepeating([](experimental::JobDelegate*) { ShouldNotRun(); }),
       /* num_tasks_to_run */ 1);
-  scoped_refptr<JobTaskSource> task_source = job_task->GetJobTaskSource(
-      FROM_HERE, ThreadPool(), &mock_pooled_task_runner_delegate_);
+  scoped_refptr<JobTaskSource> task_source =
+      job_task->GetJobTaskSource(FROM_HERE, {ThreadPool()});
 
   auto registered_task_source =
       task_tracker_.RegisterTaskSource(std::move(task_source));
@@ -763,8 +674,7 @@
       }),
       /* num_tasks_to_run */ kMaxTasks);
   scoped_refptr<JobTaskSource> task_source = job_task->GetJobTaskSource(
-      FROM_HERE, {ThreadPool(), TaskPriority::BEST_EFFORT},
-      &mock_pooled_task_runner_delegate_);
+      FROM_HERE, {ThreadPool(), TaskPriority::BEST_EFFORT});
 
   auto registered_task_source = task_tracker_.RegisterTaskSource(task_source);
   EXPECT_TRUE(registered_task_source);
diff --git a/base/task/thread_pool/thread_pool_impl.cc b/base/task/thread_pool/thread_pool_impl.cc
index fcb783c..6953de1 100644
--- a/base/task/thread_pool/thread_pool_impl.cc
+++ b/base/task/thread_pool/thread_pool_impl.cc
@@ -18,7 +18,6 @@
 #include "base/metrics/field_trial_params.h"
 #include "base/stl_util.h"
 #include "base/strings/string_util.h"
-#include "base/task/scoped_set_task_priority_for_current_thread.h"
 #include "base/task/task_features.h"
 #include "base/task/thread_pool/pooled_parallel_task_runner.h"
 #include "base/task/thread_pool/pooled_sequenced_task_runner.h"
@@ -397,19 +396,6 @@
   return true;
 }
 
-bool ThreadPoolImpl::ShouldYield(TaskSource* task_source) const {
-  const TaskPriority priority = task_source->priority_racy();
-  auto* const thread_group = GetThreadGroupForTraits(
-      {ThreadPool(), priority, task_source->thread_policy()});
-  // A task whose priority changed and is now running in the wrong thread group
-  // should yield so it's rescheduled in the right one.
-  if (!thread_group->IsBoundToCurrentThread())
-    return true;
-  return GetThreadGroupForTraits(
-             {ThreadPool(), priority, task_source->thread_policy()})
-      ->ShouldYield(priority);
-}
-
 bool ThreadPoolImpl::EnqueueJobTaskSource(
     scoped_refptr<JobTaskSource> task_source) {
   auto registered_task_source =
diff --git a/base/task/thread_pool/thread_pool_impl.h b/base/task/thread_pool/thread_pool_impl.h
index d66f0a6..75d72f05 100644
--- a/base/task/thread_pool/thread_pool_impl.h
+++ b/base/task/thread_pool/thread_pool_impl.h
@@ -103,8 +103,6 @@
 
   // PooledTaskRunnerDelegate:
   bool EnqueueJobTaskSource(scoped_refptr<JobTaskSource> task_source) override;
-  void UpdatePriority(scoped_refptr<TaskSource> task_source,
-                      TaskPriority priority) override;
 
   // Returns the TimeTicks of the next task scheduled on ThreadPool (Now() if
   // immediate, nullopt if none). This is thread-safe, i.e., it's safe if tasks
@@ -141,7 +139,8 @@
   bool PostTaskWithSequence(Task task,
                             scoped_refptr<Sequence> sequence) override;
   bool IsRunningPoolWithTraits(const TaskTraits& traits) const override;
-  bool ShouldYield(TaskSource* task_source) const override;
+  void UpdatePriority(scoped_refptr<TaskSource> task_source,
+                      TaskPriority priority) override;
 
   const std::unique_ptr<TaskTrackerImpl> task_tracker_;
   std::unique_ptr<Thread> service_thread_;
diff --git a/base/task/thread_pool/thread_pool_impl_unittest.cc b/base/task/thread_pool/thread_pool_impl_unittest.cc
index 7e1cb29..337eb73d 100644
--- a/base/task/thread_pool/thread_pool_impl_unittest.cc
+++ b/base/task/thread_pool/thread_pool_impl_unittest.cc
@@ -1087,47 +1087,12 @@
       }),
       /* num_tasks_to_run */ 1);
   scoped_refptr<JobTaskSource> task_source =
-      job_task->GetJobTaskSource(FROM_HERE, ThreadPool(), thread_pool_.get());
+      job_task->GetJobTaskSource(FROM_HERE, {ThreadPool()});
 
   thread_pool_->EnqueueJobTaskSource(task_source);
   threads_running.Wait();
 }
 
-// Verify that calling ShouldYield() returns true for a job task source that
-// needs to change thread group because of a priority update.
-TEST_P(ThreadPoolImplTest, ThreadGroupChangeShouldYield) {
-  StartThreadPool();
-
-  WaitableEvent threads_running;
-  WaitableEvent threads_continue;
-
-  auto job_task = base::MakeRefCounted<test::MockJobTask>(
-      BindLambdaForTesting([&threads_running, &threads_continue](
-                               experimental::JobDelegate* delegate) {
-        EXPECT_FALSE(delegate->ShouldYield());
-
-        threads_running.Signal();
-        test::WaitWithoutBlockingObserver(&threads_continue);
-
-        // The task source needs to yield if background thread groups exist.
-        EXPECT_EQ(delegate->ShouldYield(),
-                  CanUseBackgroundPriorityForWorkerThread());
-      }),
-      /* num_tasks_to_run */ 1);
-  scoped_refptr<JobTaskSource> task_source = job_task->GetJobTaskSource(
-      FROM_HERE, {ThreadPool(), TaskPriority::USER_VISIBLE},
-      thread_pool_.get());
-
-  thread_pool_->EnqueueJobTaskSource(task_source);
-  threads_running.Wait();
-  thread_pool_->UpdatePriority(task_source, TaskPriority::BEST_EFFORT);
-  threads_continue.Signal();
-
-  // Flush the task tracker to be sure that no local variables are accessed by
-  // tasks after the end of the scope.
-  thread_pool_->FlushForTesting();
-}
-
 namespace {
 
 class MustBeDestroyed {
diff --git a/base/threading/thread_restrictions.h b/base/threading/thread_restrictions.h
index 98e316ac..09e7d73 100644
--- a/base/threading/thread_restrictions.h
+++ b/base/threading/thread_restrictions.h
@@ -275,7 +275,6 @@
 }
 
 namespace internal {
-class JobTaskSource;
 class TaskTracker;
 }
 
@@ -451,7 +450,6 @@
   friend class audio::OutputDevice;
   friend class base::sequence_manager::internal::TaskQueueImpl;
   friend class base::FileDescriptorWatcher;
-  friend class base::internal::JobTaskSource;
   friend class base::MessageLoopImpl;
   friend class base::ScopedAllowThreadRecallForStackSamplingProfiler;
   friend class base::StackSamplingProfiler;
diff --git a/chrome/app/file_pre_reader_win.cc b/base/win/file_pre_reader.cc
similarity index 76%
rename from chrome/app/file_pre_reader_win.cc
rename to base/win/file_pre_reader.cc
index b3453009..581745f 100644
--- a/chrome/app/file_pre_reader_win.cc
+++ b/base/win/file_pre_reader.cc
@@ -2,16 +2,20 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "chrome/app/file_pre_reader_win.h"
+#include "base/win/file_pre_reader.h"
 
 #include <windows.h>
 
 #include <memoryapi.h>  // NOLINT(build/include_order)
 
 #include "base/files/file.h"
+#include "base/files/file_path.h"
 #include "base/files/memory_mapped_file.h"
 
-void PreReadFile(const base::FilePath& file_path) {
+namespace base {
+namespace win {
+
+void PreReadFile(const FilePath& file_path, bool is_executable) {
   // On Win8 and higher use ::PrefetchVirtualMemory(). This is better than
   // a simple data file read, more from a RAM perspective than CPU. This is
   // because reading the file as data results in double mapping to
@@ -31,8 +35,8 @@
 
     constexpr DWORD kStepSize = 1024 * 1024;
 
-    base::File file(file_path, base::File::FLAG_OPEN | base::File::FLAG_READ |
-                                   base::File::FLAG_SEQUENTIAL_SCAN);
+    File file(file_path,
+              File::FLAG_OPEN | File::FLAG_READ | File::FLAG_SEQUENTIAL_SCAN);
     if (!file.IsValid())
       return;
 
@@ -51,9 +55,12 @@
     // loadlibrary the file while we are doing the mapping and prefetching or
     // the process will get a private copy of the DLL via COW.
 
-    base::MemoryMappedFile mapped_file;
-    if (mapped_file.Initialize(file_path,
-                               base::MemoryMappedFile::READ_CODE_IMAGE)) {
+    MemoryMappedFile mapped_file;
+    MemoryMappedFile::Access access = is_executable
+                                          ? MemoryMappedFile::READ_CODE_IMAGE
+                                          : MemoryMappedFile::READ_ONLY;
+
+    if (mapped_file.Initialize(file_path, access)) {
       _WIN32_MEMORY_RANGE_ENTRY address_range = {mapped_file.data(),
                                                  mapped_file.length()};
 
@@ -64,3 +71,6 @@
     }
   }
 }
+
+}  // namespace win
+}  // namespace base
\ No newline at end of file
diff --git a/base/win/file_pre_reader.h b/base/win/file_pre_reader.h
new file mode 100644
index 0000000..72fefe4
--- /dev/null
+++ b/base/win/file_pre_reader.h
@@ -0,0 +1,28 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This file defines a function to pre-read a file in order to avoid touching
+// the disk when it is subsequently used.
+
+#include "base/base_export.h"
+
+#ifndef BASE_WIN_FILE_PRE_READER_H_
+#define BASE_WIN_FILE_PRE_READER_H_
+
+namespace base {
+
+class FilePath;
+
+namespace win {
+
+// Pre-reads |file_path| to avoid touching the disk when the file is actually
+// used. |is_executable| specifies whether the file is to be prefetched as
+// executable code or as data. Windows treats the file backed pages in RAM
+// differently and specifying the wrong one results in two copies in RAM.
+BASE_EXPORT void PreReadFile(const FilePath& file_path, bool is_executable);
+
+}  // namespace win
+}  // namespace base
+
+#endif  // BASE_WIN_FILE_PRE_READER_H_
diff --git a/build/fuchsia/linux.sdk.sha1 b/build/fuchsia/linux.sdk.sha1
index e6b3730..210a876d 100644
--- a/build/fuchsia/linux.sdk.sha1
+++ b/build/fuchsia/linux.sdk.sha1
@@ -1 +1 @@
-8903989905342745168
\ No newline at end of file
+8903962831524890912
\ No newline at end of file
diff --git a/build/fuchsia/mac.sdk.sha1 b/build/fuchsia/mac.sdk.sha1
index 14e8590..a684367 100644
--- a/build/fuchsia/mac.sdk.sha1
+++ b/build/fuchsia/mac.sdk.sha1
@@ -1 +1 @@
-8903994421773374304
\ No newline at end of file
+8903961994040181600
\ No newline at end of file
diff --git a/chrome/BUILD.gn b/chrome/BUILD.gn
index a9814f1..dd3a0986 100644
--- a/chrome/BUILD.gn
+++ b/chrome/BUILD.gn
@@ -195,7 +195,6 @@
           ":chrome_dll",
           ":chrome_exe_version",
           ":copy_first_run",
-          ":file_pre_reader",
           ":visual_elements_resources",
           "//base",
           "//chrome/app/version_assembly:chrome_exe_manifest",
@@ -1493,16 +1492,6 @@
     ]
     output = "$target_gen_dir/other_version.rc"
   }
-
-  source_set("file_pre_reader") {
-    sources = [
-      "app/file_pre_reader_win.cc",
-      "app/file_pre_reader_win.h",
-    ]
-    deps = [
-      "//base",
-    ]
-  }
 }
 
 copy("visual_elements_resources") {
diff --git a/chrome/android/features/keyboard_accessory/internal/java/src/org/chromium/chrome/browser/keyboard_accessory/bar_component/KeyboardAccessoryIPHUtils.java b/chrome/android/features/keyboard_accessory/internal/java/src/org/chromium/chrome/browser/keyboard_accessory/bar_component/KeyboardAccessoryIPHUtils.java
index 553ce46..7f3b425 100644
--- a/chrome/android/features/keyboard_accessory/internal/java/src/org/chromium/chrome/browser/keyboard_accessory/bar_component/KeyboardAccessoryIPHUtils.java
+++ b/chrome/android/features/keyboard_accessory/internal/java/src/org/chromium/chrome/browser/keyboard_accessory/bar_component/KeyboardAccessoryIPHUtils.java
@@ -14,6 +14,7 @@
 import org.chromium.components.feature_engagement.EventConstants;
 import org.chromium.components.feature_engagement.FeatureConstants;
 import org.chromium.components.feature_engagement.Tracker;
+import org.chromium.ui.widget.ChipView;
 import org.chromium.ui.widget.ViewRectProvider;
 
 /**
@@ -51,7 +52,7 @@
      * @param feature A String identifying the IPH feature and its appropriate help text.
      * @param view The {@link View} providing context and the Rect to which the bubble will point.
      */
-    static void showHelpBubble(String feature, View view) {
+    static void showHelpBubble(String feature, ChipView view) {
         final Tracker tracker = TrackerFactory.getTrackerForProfile(Profile.getLastUsedProfile());
         if (!tracker.isInitialized()) return;
         if (!tracker.shouldTriggerHelpUI(feature)) return; // This call records the IPH intent.
@@ -61,7 +62,13 @@
                 helpText, true, new ViewRectProvider(view), R.drawable.ic_chrome);
         helpBubble.setDismissOnTouchInteraction(true);
         helpBubble.show();
-        helpBubble.addOnDismissListener(() -> tracker.dismissed(feature));
+        // To emphasize which chip is pointed to, set selected to true for the built-in highlight.
+        // Prefer ViewHighlighter for views without a LayerDrawable background.
+        view.setSelected(true);
+        helpBubble.addOnDismissListener(() -> {
+            tracker.dismissed(feature);
+            view.setSelected(false);
+        });
     }
 
     /**
diff --git a/chrome/android/features/keyboard_accessory/javatests/src/org/chromium/chrome/browser/keyboard_accessory/bar_component/KeyboardAccessoryModernViewTest.java b/chrome/android/features/keyboard_accessory/javatests/src/org/chromium/chrome/browser/keyboard_accessory/bar_component/KeyboardAccessoryModernViewTest.java
index 68ac271..282af258 100644
--- a/chrome/android/features/keyboard_accessory/javatests/src/org/chromium/chrome/browser/keyboard_accessory/bar_component/KeyboardAccessoryModernViewTest.java
+++ b/chrome/android/features/keyboard_accessory/javatests/src/org/chromium/chrome/browser/keyboard_accessory/bar_component/KeyboardAccessoryModernViewTest.java
@@ -6,8 +6,11 @@
 
 import static android.support.test.espresso.Espresso.onView;
 import static android.support.test.espresso.action.ViewActions.click;
+import static android.support.test.espresso.assertion.ViewAssertions.matches;
 import static android.support.test.espresso.matcher.ViewMatchers.assertThat;
 import static android.support.test.espresso.matcher.ViewMatchers.isRoot;
+import static android.support.test.espresso.matcher.ViewMatchers.isSelected;
+import static android.support.test.espresso.matcher.ViewMatchers.withChild;
 import static android.support.test.espresso.matcher.ViewMatchers.withText;
 
 import static org.hamcrest.Matchers.is;
@@ -246,11 +249,13 @@
 
         onView(isRoot()).check((root, e) -> waitForView((ViewGroup) root, withText("Johnathan")));
         waitForHelpBubble(withText(R.string.iph_keyboard_accessory_fill_password));
+        onView(withChild(withText("Johnathan"))).check(matches(isSelected()));
         onView(withText("Johnathan")).perform(click());
 
         assertThat(tracker.wasDismissed(), is(true));
         assertThat(tracker.getLastEmittedEvent(),
                 is(EventConstants.KEYBOARD_ACCESSORY_PASSWORD_AUTOFILLED));
+        onView(withChild(withText("Johnathan"))).check(matches(not(isSelected())));
     }
 
     @Test
diff --git a/chrome/android/features/tab_ui/BUILD.gn b/chrome/android/features/tab_ui/BUILD.gn
index 1287a31..0959d58 100644
--- a/chrome/android/features/tab_ui/BUILD.gn
+++ b/chrome/android/features/tab_ui/BUILD.gn
@@ -130,6 +130,10 @@
     "java/src/org/chromium/chrome/browser/tasks/tab_management/TabSwitcherCoordinator.java",
     "java/src/org/chromium/chrome/browser/tasks/tab_management/TabSwitcherMediator.java",
     "java/src/org/chromium/chrome/browser/tasks/tab_management/UndoGroupSnackbarController.java",
+    "java/src/org/chromium/chrome/browser/tasks/tab_management/suggestions/TabSuggestionProvider.java",
+    "java/src/org/chromium/chrome/browser/tasks/tab_management/suggestions/StaleTabSuggestionProvider.java",
+    "java/src/org/chromium/chrome/browser/tasks/tab_management/suggestions/TabSuggestionsRanker.java",
+    "java/src/org/chromium/chrome/browser/tasks/tab_management/suggestions/TabSuggestionProviderConfiguration.java",
   ]
 
   deps = [
diff --git a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/suggestions/StaleTabSuggestionProvider.java b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/suggestions/StaleTabSuggestionProvider.java
new file mode 100644
index 0000000..fffd8f0
--- /dev/null
+++ b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/suggestions/StaleTabSuggestionProvider.java
@@ -0,0 +1,41 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.chrome.browser.tasks.tab_management.suggestions;
+
+import org.chromium.chrome.browser.ChromeFeatureList;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * Provider which returns tabs which have not been used beyond a time threshold.
+ */
+public class StaleTabSuggestionProvider implements TabSuggestionProvider {
+    private static final int DEFAULT_THRESHOLD = (int) TimeUnit.DAYS.toMillis(1);
+
+    @Override
+    public List<TabSuggestion> suggest(TabContext tabContext) {
+        if (tabContext == null || tabContext.getUngroupedTabs() == null
+                || tabContext.getUngroupedTabs().size() < 1) {
+            return null;
+        }
+
+        long staleThreshold = ChromeFeatureList.getFieldTrialParamByFeatureAsInt(
+                ChromeFeatureList.CLOSE_TAB_SUGGESTIONS_STALE,
+                "close_tab_suggestions_stale_time_ms", DEFAULT_THRESHOLD);
+
+        long now = System.currentTimeMillis();
+        List<TabContext.TabInfo> staleTabs = new ArrayList<>();
+        for (TabContext.TabInfo tab : tabContext.getUngroupedTabs()) {
+            if (now - tab.timestampMillis > staleThreshold) {
+                staleTabs.add(tab);
+            }
+        }
+        return Arrays.asList(new TabSuggestion(staleTabs, TabSuggestion.TabSuggestionAction.CLOSE,
+                TabSuggestionsRanker.SuggestionProviders.STALE_TABS_SUGGESTION_PROVIDER));
+    }
+}
diff --git a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/suggestions/TabContext.java b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/suggestions/TabContext.java
new file mode 100644
index 0000000..2138818
--- /dev/null
+++ b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/suggestions/TabContext.java
@@ -0,0 +1,206 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.chrome.browser.tasks.tab_management.suggestions;
+
+import android.text.TextUtils;
+
+import org.chromium.chrome.browser.tab.Tab;
+import org.chromium.chrome.browser.tabmodel.TabModelFilter;
+import org.chromium.chrome.browser.tabmodel.TabModelSelector;
+import org.chromium.content_public.browser.NavigationEntry;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * Represents a snapshot of the current tabs and tab groups.
+ */
+public class TabContext {
+    /**
+     * Holds basic information about a tab group.
+     */
+    public static class TabGroupInfo {
+        public final int rootId;
+        public final List<TabInfo> tabs;
+
+        public TabGroupInfo(int rootId, List<TabInfo> tabs) {
+            this.rootId = rootId;
+            this.tabs = Collections.unmodifiableList(tabs);
+        }
+
+        @Override
+        public boolean equals(Object other) {
+            if (this == other) return true;
+            if (other == null) return false;
+            if (other instanceof TabGroupInfo) {
+                TabGroupInfo otherGroupInfo = (TabGroupInfo) other;
+                return rootId == otherGroupInfo.rootId && tabs == null
+                        ? otherGroupInfo.tabs == null
+                        : tabs.equals(otherGroupInfo.tabs);
+            }
+            return false;
+        }
+
+        @Override
+        public int hashCode() {
+            int result = 31 * (tabs == null ? 0 : tabs.hashCode());
+            result = 31 * result + rootId;
+            return result;
+        }
+    }
+
+    /**
+     * Holds basic information about a tab.
+     */
+    public static class TabInfo implements Comparable<TabInfo> {
+        // equals() and hashCode() only include url and id
+        public final String url;
+        public final String referrerUrl;
+        public final long timestampMillis;
+        public final int id;
+        public final String title;
+        public final String originalUrl;
+
+        /**
+         * Constructs a new TabInfo object
+         */
+        protected TabInfo(int id, String title, String url, String originalUrl, String referrerUrl,
+                long timestampMillis) {
+            this.id = id;
+            this.title = title;
+            this.url = url;
+            this.originalUrl = originalUrl;
+            this.referrerUrl = referrerUrl;
+            this.timestampMillis = timestampMillis;
+        }
+
+        /**
+         * Creates a new TabInfo object from {@link Tab}
+         */
+        public static TabInfo createFromTab(Tab tab) {
+            String referrerUrl = getReferrerUrlFromTab(tab);
+            return new TabInfo(tab.getId(), tab.getTitle(), tab.getUrl(), tab.getOriginalUrl(),
+                    referrerUrl != null ? referrerUrl : "", tab.getTimestampMillis());
+        }
+
+        private static String getReferrerUrlFromTab(Tab tab) {
+            if (tab.getWebContents() == null) {
+                return null;
+            }
+            if (tab.getWebContents().getNavigationController() == null) {
+                return null;
+            }
+            int lastCommittedIndex =
+                    tab.getWebContents().getNavigationController().getLastCommittedEntryIndex();
+            NavigationEntry lastCommittedEntry =
+                    tab.getWebContents().getNavigationController().getEntryAtIndex(
+                            lastCommittedIndex);
+            if (lastCommittedEntry == null) {
+                return null;
+            }
+            return lastCommittedEntry.getReferrerUrl();
+        }
+
+        @Override
+        public boolean equals(Object other) {
+            if (this == other) return true;
+            if (other == null) return false;
+            if (other instanceof TabInfo) {
+                TabInfo otherTabInfo = (TabInfo) other;
+                return id == otherTabInfo.id && TextUtils.equals(url, otherTabInfo.url);
+            }
+            return false;
+        }
+
+        @Override
+        public int hashCode() {
+            int result = 17;
+            result = 31 * result + id;
+            result = 31 * result + url == null ? 0 : url.hashCode();
+            return result;
+        }
+
+        @Override
+        public int compareTo(TabInfo other) {
+            return Integer.compare(id, other.id);
+        }
+    }
+
+    private final List<TabInfo> mUngroupedTabs;
+    private final List<TabGroupInfo> mTabGroups;
+
+    protected TabContext(List<TabInfo> ungroupedTabs, List<TabGroupInfo> groups) {
+        mUngroupedTabs = Collections.unmodifiableList(ungroupedTabs);
+        mTabGroups = Collections.unmodifiableList(groups);
+    }
+
+    public List<TabInfo> getUngroupedTabs() {
+        return mUngroupedTabs;
+    }
+
+    public List<TabGroupInfo> getTabGroups() {
+        return mTabGroups;
+    }
+
+    @Override
+    public boolean equals(Object other) {
+        if (this == other) return true;
+        if (other == null) return false;
+        if (other instanceof TabContext) {
+            TabContext otherTabContext = (TabContext) other;
+            return (mTabGroups == null ? otherTabContext.getTabGroups() == null
+                                       : mTabGroups.equals(otherTabContext.getTabGroups()))
+                    && (mUngroupedTabs == null
+                                    ? otherTabContext.getUngroupedTabs() == null
+                                    : mUngroupedTabs.equals(otherTabContext.getUngroupedTabs()));
+        }
+        return false;
+    }
+
+    @Override
+    public int hashCode() {
+        int result = 17;
+        result = 31 * result + (mTabGroups == null ? 0 : mTabGroups.hashCode());
+        result = 31 * result + (mUngroupedTabs == null ? 0 : mUngroupedTabs.hashCode());
+        return result;
+    }
+
+    /**
+     * Creates an instance of TabContext based on the provided {@link TabModelSelector}.
+     * @param tabModelSelector TabModelSelector for which the TabContext will be derived
+     * @return an instance of TabContext
+     */
+    public static TabContext createCurrentContext(TabModelSelector tabModelSelector) {
+        TabModelFilter tabModelFilter =
+                tabModelSelector.getTabModelFilterProvider().getCurrentTabModelFilter();
+        List<TabInfo> ungroupedTabs = new ArrayList<>();
+        List<TabGroupInfo> existingGroups = new ArrayList<>();
+
+        // Examine each tab in the current model and either add it to the list of ungrouped tabs or
+        // add it to a group it belongs to.
+        for (int i = 0; i < tabModelFilter.getCount(); i++) {
+            Tab currentTab = tabModelFilter.getTabAt(i);
+            List<Tab> relatedTabs = tabModelFilter.getRelatedTabList(currentTab.getId());
+
+            if (relatedTabs != null && relatedTabs.size() > 1) {
+                existingGroups.add(
+                        new TabGroupInfo(currentTab.getRootId(), createTabInfoList(relatedTabs)));
+            } else {
+                ungroupedTabs.add(TabInfo.createFromTab(currentTab));
+            }
+        }
+
+        return new TabContext(ungroupedTabs, existingGroups);
+    }
+
+    private static List<TabInfo> createTabInfoList(List<Tab> tabs) {
+        List<TabInfo> tabInfoList = new ArrayList<>();
+        for (Tab tab : tabs) {
+            tabInfoList.add(TabInfo.createFromTab(tab));
+        }
+        return tabInfoList;
+    }
+}
diff --git a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/suggestions/TabSuggestion.java b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/suggestions/TabSuggestion.java
new file mode 100644
index 0000000..5a0124ac
--- /dev/null
+++ b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/suggestions/TabSuggestion.java
@@ -0,0 +1,81 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.chrome.browser.tasks.tab_management.suggestions;
+
+import android.support.annotation.IntDef;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * Represents the output of the {@link TabSuggestions} pipeline.
+ */
+public final class TabSuggestion {
+    /** Types of Suggestion Actions */
+    @IntDef({TabSuggestion.TabSuggestionAction.GROUP, TabSuggestion.TabSuggestionAction.CLOSE})
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface TabSuggestionAction {
+        int GROUP = 0;
+        int CLOSE = 1;
+    }
+
+    private final List<TabContext.TabInfo> mTabsInfo;
+    private final @TabSuggestionAction int mAction;
+    private final String mProviderName;
+    private final Integer mTabGroupId;
+
+    public TabSuggestion(List<TabContext.TabInfo> tabsInfo, @TabSuggestionAction int action,
+            String providerName) {
+        this(tabsInfo, action, providerName, null);
+    }
+
+    public TabSuggestion(List<TabContext.TabInfo> tabsInfo, @TabSuggestionAction int action,
+            String providerName, Integer tabGroupId) {
+        mTabsInfo = Collections.unmodifiableList(tabsInfo);
+        mAction = action;
+        mProviderName = providerName;
+        mTabGroupId = tabGroupId;
+    }
+
+    /**
+     * Returns the list of the suggested tabs
+     */
+    public List<TabContext.TabInfo> getTabsInfo() {
+        return mTabsInfo;
+    }
+
+    /**
+     * Returns the suggested action
+     */
+    public @TabSuggestionAction int getAction() {
+        return mAction;
+    }
+
+    /**
+     * Returns the provider's name
+     */
+    public String getProviderName() {
+        return mProviderName;
+    }
+
+    /**
+     * Checks if the suggestion is for an existing group
+     * @return true if the suggestion updates an existing group
+     */
+    public boolean hasExistingGroupId() {
+        return getExistingTabGroupId() != null;
+    }
+
+    /**
+     * If the suggestion is for an existing group, this will return the group id. Call @{link
+     * hasExistingGroupId} before calling this getter.
+     * @return existing group Id
+     */
+    public Integer getExistingTabGroupId() {
+        return mTabGroupId;
+    }
+}
diff --git a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/suggestions/TabSuggestionProvider.java b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/suggestions/TabSuggestionProvider.java
new file mode 100644
index 0000000..22e6a8d
--- /dev/null
+++ b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/suggestions/TabSuggestionProvider.java
@@ -0,0 +1,13 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.chrome.browser.tasks.tab_management.suggestions;
+
+import java.util.List;
+
+/**
+ * Defines the contract between {@link TabSuggestionsFetcher} and all the client-side suggestion
+ * providers.
+ */
+public interface TabSuggestionProvider { List<TabSuggestion> suggest(TabContext tabContext); }
diff --git a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/suggestions/TabSuggestionProviderConfiguration.java b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/suggestions/TabSuggestionProviderConfiguration.java
new file mode 100644
index 0000000..0e8bd24
--- /dev/null
+++ b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/suggestions/TabSuggestionProviderConfiguration.java
@@ -0,0 +1,19 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.chrome.browser.tasks.tab_management.suggestions;
+
+/**
+ * Encapsulates signals indicating how useful the suggestions from a suggestions
+ * provider are. Used for aggregating and determining which suggestions to use
+ */
+class TabSuggestionProviderConfiguration {
+    public final int score;
+    public final boolean isEnabled;
+
+    TabSuggestionProviderConfiguration(int score, boolean isEnabled) {
+        this.score = score;
+        this.isEnabled = isEnabled;
+    }
+}
diff --git a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/suggestions/TabSuggestionsRanker.java b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/suggestions/TabSuggestionsRanker.java
new file mode 100644
index 0000000..2180e27b
--- /dev/null
+++ b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/suggestions/TabSuggestionsRanker.java
@@ -0,0 +1,58 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.chrome.browser.tasks.tab_management.suggestions;
+
+import android.support.annotation.StringDef;
+
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Ranker which ranks all suggestions based on static rules.
+ */
+public final class TabSuggestionsRanker {
+    /**
+     * List of all known providers (server & client).
+     * TODO(crbug.com/970933) decouple server providers from client.
+     */
+    @StringDef({SuggestionProviders.STALE_TABS_SUGGESTION_PROVIDER})
+    public @interface SuggestionProviders {
+        String STALE_TABS_SUGGESTION_PROVIDER = "StaleTabSuggestionProvider";
+    }
+
+    /**
+     * Ranks suggestions based on the number of tabs first and the score of the provider in case of
+     * a tie. This logic is subject to change in the future.
+     * @param suggestions to be ranked
+     * @param providerConfigs per-provider configurations
+     * @return sorted suggestions list where first suggestion in the list is the most preferred
+     */
+    public static List<TabSuggestion> getRankedSuggestions(List<TabSuggestion> suggestions,
+            Map<String, TabSuggestionProviderConfiguration> providerConfigs) {
+        if (suggestions.isEmpty()) {
+            return suggestions;
+        }
+
+        Collections.sort(suggestions, (a, b) -> {
+            if (a == b) return 0;
+
+            if (a.getTabsInfo().size() == b.getTabsInfo().size()) {
+                int aScore = providerConfigs.containsKey(a.getProviderName())
+                        ? providerConfigs.get(a.getProviderName()).score
+                        : 0;
+                int bScore = providerConfigs.containsKey(b.getProviderName())
+                        ? providerConfigs.get(b.getProviderName()).score
+                        : 0;
+
+                return Integer.compare(bScore, aScore);
+            }
+
+            return Integer.compare(b.getTabsInfo().size(), a.getTabsInfo().size());
+        });
+
+        return suggestions;
+    }
+}
diff --git a/chrome/android/features/tab_ui/junit/src/org/chromium/chrome/browser/tasks/tab_management/suggestions/StaleTabSuggestionProviderTest.java b/chrome/android/features/tab_ui/junit/src/org/chromium/chrome/browser/tasks/tab_management/suggestions/StaleTabSuggestionProviderTest.java
new file mode 100644
index 0000000..551ec39
--- /dev/null
+++ b/chrome/android/features/tab_ui/junit/src/org/chromium/chrome/browser/tasks/tab_management/suggestions/StaleTabSuggestionProviderTest.java
@@ -0,0 +1,78 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.chrome.browser.tasks.tab_management.suggestions;
+
+import static org.mockito.Mockito.doReturn;
+
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.TestRule;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.robolectric.annotation.Config;
+
+import org.chromium.base.test.util.CommandLineFlags;
+import org.chromium.base.test.util.Feature;
+import org.chromium.chrome.browser.ChromeFeatureList;
+import org.chromium.chrome.browser.ChromeSwitches;
+import org.chromium.chrome.test.util.browser.Features;
+import org.chromium.testing.local.LocalRobolectricTestRunner;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * Tests the provider which identifies Tabs which have not been used in a long time
+ */
+@RunWith(LocalRobolectricTestRunner.class)
+@Config(manifest = Config.NONE)
+public class StaleTabSuggestionProviderTest {
+    @Rule
+    public TestRule mProcessor = new Features.JUnitProcessor();
+
+    @Mock
+    TabContext mTabContext;
+
+    @Before
+    public void setUp() throws Exception {
+        MockitoAnnotations.initMocks(this);
+    }
+
+    /**
+     * Test identification of Tabs which have not been used in a long time (threshold set to 1 day)
+     * and recommend to close them
+     */
+    @Test
+    @Feature({"StaleTabSuggestionProvider"})
+    @CommandLineFlags.Add({ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE,
+            "enable-features=" + ChromeFeatureList.CLOSE_TAB_SUGGESTIONS_STALE + "<FakeStudyName",
+            "force-fieldtrials=FakeStudyName/Enabled",
+            "force-fieldtrial-params=FakeStudyName.Enabled:"
+                    + "close_tab_suggestions_stale_time_ms/86400000"})
+    // 86400000 milliseconds = 1 day
+    public void
+    testIdentifyStaleTabs() throws Exception {
+        StaleTabSuggestionProvider staleSuggestionsProvider = new StaleTabSuggestionProvider();
+        List<TabContext.TabInfo> tabInfos = new ArrayList<>();
+        tabInfos.add(new TabContext.TabInfo(3, "mock_recent_title", "mock_recent_url",
+                "mock_recent_original_url", "mock_recent_url",
+                System.currentTimeMillis() - TimeUnit.MINUTES.toMillis(5)));
+        tabInfos.add(new TabContext.TabInfo(3, "mock_stale_title", "mock_stale_url",
+                "mock_stale_original_url", "mock_stale_referrer_url",
+                System.currentTimeMillis() - TimeUnit.DAYS.toMillis(2)));
+        doReturn(tabInfos).when(mTabContext).getUngroupedTabs();
+        List<TabSuggestion> staleSuggestions = staleSuggestionsProvider.suggest(mTabContext);
+        Assert.assertTrue(staleSuggestions.size() == 1);
+        TabSuggestion staleSuggestion = staleSuggestions.get(0);
+        Assert.assertEquals("mock_stale_title", staleSuggestion.getTabsInfo().get(0).title);
+        Assert.assertEquals(TabSuggestion.TabSuggestionAction.CLOSE, staleSuggestion.getAction());
+        Assert.assertEquals(TabSuggestionsRanker.SuggestionProviders.STALE_TABS_SUGGESTION_PROVIDER,
+                staleSuggestion.getProviderName());
+    }
+}
diff --git a/chrome/android/features/tab_ui/junit/src/org/chromium/chrome/browser/tasks/tab_management/suggestions/TabContextTests.java b/chrome/android/features/tab_ui/junit/src/org/chromium/chrome/browser/tasks/tab_management/suggestions/TabContextTests.java
new file mode 100644
index 0000000..37a78c7b
--- /dev/null
+++ b/chrome/android/features/tab_ui/junit/src/org/chromium/chrome/browser/tasks/tab_management/suggestions/TabContextTests.java
@@ -0,0 +1,131 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.chrome.browser.tasks.tab_management.suggestions;
+
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.eq;
+import static org.mockito.Mockito.mock;
+
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.TestRule;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.robolectric.annotation.Config;
+
+import org.chromium.chrome.browser.tab.Tab;
+import org.chromium.chrome.browser.tabmodel.TabModelFilter;
+import org.chromium.chrome.browser.tabmodel.TabModelFilterProvider;
+import org.chromium.chrome.browser.tabmodel.TabModelSelector;
+import org.chromium.chrome.test.util.browser.Features;
+import org.chromium.content_public.browser.NavigationController;
+import org.chromium.content_public.browser.NavigationEntry;
+import org.chromium.content_public.browser.WebContents;
+import org.chromium.testing.local.LocalRobolectricTestRunner;
+
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * Tests functionality related to TabContext
+ */
+@RunWith(LocalRobolectricTestRunner.class)
+@Config(manifest = Config.NONE)
+public class TabContextTests {
+    private static final int TAB_0_ID = 0;
+    private static final int RELATED_TAB_0_ID = 1;
+    private static final int RELATED_TAB_1_ID = 2;
+    private static final int LAST_COMMITTED_INDEX = 1;
+
+    @Rule
+    public TestRule mProcessor = new Features.JUnitProcessor();
+
+    @Mock
+    private TabModelSelector mTabModelSelector;
+
+    @Mock
+    private TabModelFilterProvider mTabModelFilterProvider;
+
+    @Mock
+    private TabModelFilter mTabModelFilter;
+
+    private static Tab sTab0 = mockTab(TAB_0_ID, 6, "mock_title_tab_0", "mock_url_tab_0",
+            "mock_original_url_tab_0", "mock_referrer_url_tab_0", 100);
+    private static Tab sRelatedTab0 =
+            mockTab(RELATED_TAB_0_ID, 6, "mock_title_related_tab_0", "mock_url_related_tab_0",
+                    "mock_original_url_related_tab_0", "mock_referrer_url_related_tab_0", 200);
+    private static Tab sRelatedTab1 =
+            mockTab(RELATED_TAB_1_ID, 6, "mock_title_related_tab_1", "mock_url_related_tab_1",
+                    "mock_original_url_related_tab_1", "mock_referrer_url_related_tab_1", 300);
+
+    @Before
+    public void setUp() throws Exception {
+        MockitoAnnotations.initMocks(this);
+        doReturn(mTabModelFilterProvider).when(mTabModelSelector).getTabModelFilterProvider();
+        doReturn(mTabModelFilter).when(mTabModelFilterProvider).getCurrentTabModelFilter();
+    }
+
+    private static Tab mockTab(int id, int rootId, String title, String url, String originalUrl,
+            String referrerUrl, long getTimestampMillis) {
+        Tab tab = mock(Tab.class);
+        doReturn(id).when(tab).getId();
+        doReturn(rootId).when(tab).getRootId();
+        doReturn(title).when(tab).getTitle();
+        doReturn(url).when(tab).getUrl();
+        doReturn(originalUrl).when(tab).getOriginalUrl();
+        WebContents webContents = mock(WebContents.class);
+        doReturn(webContents).when(tab).getWebContents();
+        NavigationController navigationController = mock(NavigationController.class);
+        doReturn(navigationController).when(webContents).getNavigationController();
+        doReturn(LAST_COMMITTED_INDEX).when(navigationController).getLastCommittedEntryIndex();
+        NavigationEntry navigationEntry = mock(NavigationEntry.class);
+        doReturn(navigationEntry)
+                .when(navigationController)
+                .getEntryAtIndex(eq(LAST_COMMITTED_INDEX));
+        doReturn(referrerUrl).when(navigationEntry).getReferrerUrl();
+        return tab;
+    }
+
+    /**
+     * Test finding related tabs
+     */
+    @Test
+    public void testRelatedTabsExist() throws Exception {
+        doReturn(sTab0).when(mTabModelFilter).getTabAt(eq(TAB_0_ID));
+        doReturn(1).when(mTabModelFilter).getCount();
+        doReturn(Arrays.asList(sTab0, sRelatedTab0, sRelatedTab1))
+                .when(mTabModelFilter)
+                .getRelatedTabList(eq(TAB_0_ID));
+        TabContext tabContext = TabContext.createCurrentContext(mTabModelSelector);
+        Assert.assertEquals(tabContext.getUngroupedTabs().size(), 0);
+        List<TabContext.TabGroupInfo> tabGroupInfo = tabContext.getTabGroups();
+        Assert.assertEquals(1, tabGroupInfo.size());
+        List<TabContext.TabInfo> groupedTabs = tabGroupInfo.get(0).tabs;
+        Assert.assertEquals(3, groupedTabs.size());
+        Assert.assertEquals(TAB_0_ID, groupedTabs.get(0).id);
+        Assert.assertEquals(RELATED_TAB_0_ID, groupedTabs.get(1).id);
+        Assert.assertEquals(RELATED_TAB_1_ID, groupedTabs.get(2).id);
+    }
+
+    /**
+     * Test finding no related tabs
+     */
+    @Test
+    public void testFindNoRelatedTabs() throws Exception {
+        doReturn(sTab0).when(mTabModelFilter).getTabAt(eq(TAB_0_ID));
+        doReturn(1).when(mTabModelFilter).getCount();
+        doReturn(Arrays.asList(sTab0)).when(mTabModelFilter).getRelatedTabList(eq(TAB_0_ID));
+        TabContext tabContext = TabContext.createCurrentContext(mTabModelSelector);
+        Assert.assertEquals(tabContext.getUngroupedTabs().size(), 1);
+        List<TabContext.TabGroupInfo> tabGroups = tabContext.getTabGroups();
+        Assert.assertEquals(0, tabGroups.size());
+        List<TabContext.TabInfo> ungroupedTabs = tabContext.getUngroupedTabs();
+        Assert.assertEquals(1, ungroupedTabs.size());
+        Assert.assertEquals(TAB_0_ID, ungroupedTabs.get(0).id);
+    }
+}
diff --git a/chrome/android/features/tab_ui/tab_management_java_sources.gni b/chrome/android/features/tab_ui/tab_management_java_sources.gni
index 2cd74b7..39da8ec 100644
--- a/chrome/android/features/tab_ui/tab_management_java_sources.gni
+++ b/chrome/android/features/tab_ui/tab_management_java_sources.gni
@@ -14,6 +14,8 @@
   "//chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabManagementDelegate.java",
   "//chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabManagementModuleProvider.java",
   "//chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabSwitcher.java",
+  "//chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/suggestions/TabContext.java",
+  "//chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/suggestions/TabSuggestion.java",
 ]
 
 public_tab_management_java_sources += start_surface_public_java_sources
@@ -33,4 +35,6 @@
   "//chrome/android/features/tab_ui/junit/src/org/chromium/chrome/browser/tasks/tab_management/TabGridItemTouchHelperCallbackUnitTest.java",
   "//chrome/android/features/tab_ui/junit/src/org/chromium/chrome/browser/tasks/tab_management/TabGroupUiMediatorUnitTest.java",
   "//chrome/android/features/tab_ui/junit/src/org/chromium/chrome/browser/tasks/tab_management/TabListMediatorUnitTest.java",
+  "//chrome/android/features/tab_ui/junit/src/org/chromium/chrome/browser/tasks/tab_management/suggestions/TabContextTests.java",
+  "//chrome/android/features/tab_ui/junit/src/org/chromium/chrome/browser/tasks/tab_management/suggestions/StaleTabSuggestionProviderTest.java",
 ]
diff --git a/chrome/android/java/res/layout/contact_view.xml b/chrome/android/java/res/layout/contact_view.xml
index b8bad92..724b9c14 100644
--- a/chrome/android/java/res/layout/contact_view.xml
+++ b/chrome/android/java/res/layout/contact_view.xml
@@ -16,7 +16,7 @@
         android:id="@+id/content"
         style="@style/ListItemContainer">
 
-        <include layout="@layout/modern_list_item_view" />
+        <include layout="@layout/contacts_list_item_view" />
 
     </LinearLayout>
 </org.chromium.chrome.browser.contacts_picker.ContactView>
diff --git a/chrome/android/java/res/layout/contacts_list_item_view.xml b/chrome/android/java/res/layout/contacts_list_item_view.xml
new file mode 100644
index 0000000..00c8976
--- /dev/null
+++ b/chrome/android/java/res/layout/contacts_list_item_view.xml
@@ -0,0 +1,77 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright 2019 The Chromium Authors. All rights reserved.
+     Use of this source code is governed by a BSD-style license that can be
+     found in the LICENSE file. -->
+
+<merge
+    xmlns:android="http://schemas.android.com/apk/res/android">
+
+    <org.chromium.ui.widget.ChromeImageView
+        android:id="@+id/icon_view"
+        style="@style/ListItemStartIcon" />
+
+    <LinearLayout
+        android:layout_width="0dp"
+        android:layout_height="wrap_content"
+        android:layout_weight="1"
+        android:orientation="vertical"
+        android:layout_gravity="center_vertical" >
+
+        <TextView
+            android:id="@+id/title"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:maxLines="1"
+            android:ellipsize="end"
+            android:textAppearance="@style/TextAppearance.BlackTitle1" />
+
+        <LinearLayout
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:orientation="horizontal" >
+
+            <TextView
+                android:id="@+id/email"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:maxLines="1"
+                android:ellipsize="end"
+                android:textAppearance="@style/TextAppearance.BlackBody" />
+
+            <TextView
+                android:id="@+id/email_overflow_count"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:clickable="true"
+                android:maxLines="1"
+                android:paddingStart="4dp"
+                android:ellipsize="end"
+                android:textAppearance="@style/TextAppearance.ContactsPickerMoreDetails" />
+        </LinearLayout>
+
+        <LinearLayout
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:orientation="horizontal" >
+
+            <TextView
+                android:id="@+id/telephone_number"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:maxLines="1"
+                android:ellipsize="end"
+                android:textAppearance="@style/TextAppearance.BlackBody" />
+
+            <TextView
+                android:id="@+id/telephone_number_overflow_count"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:clickable="true"
+                android:maxLines="1"
+                android:paddingStart="4dp"
+                android:ellipsize="end"
+                android:textAppearance="@style/TextAppearance.ContactsPickerMoreDetails" />
+        </LinearLayout>
+    </LinearLayout>
+
+</merge>
diff --git a/chrome/android/java/res/values-v17/styles.xml b/chrome/android/java/res/values-v17/styles.xml
index b479863..ff630e4 100644
--- a/chrome/android/java/res/values-v17/styles.xml
+++ b/chrome/android/java/res/values-v17/styles.xml
@@ -776,6 +776,9 @@
         <item name="android:textColor">@color/default_text_color</item>
         <item name="android:textSize">@dimen/text_size_large</item>
     </style>
+    <style name="TextAppearance.ContactsPickerMoreDetails" parent="TextAppearance.BlackBody">
+        <item name="android:textColor">@color/default_text_color_link</item>
+    </style>
     <style name="TextAppearance.PageInfoPermissionSubtitle" parent="TextAppearance.BlackBody">
         <item name="android:textColor">@color/secondary_text_default_material_light</item>
     </style>
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ChromeFeatureList.java b/chrome/android/java/src/org/chromium/chrome/browser/ChromeFeatureList.java
index 302e0c36..6b52477 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ChromeFeatureList.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ChromeFeatureList.java
@@ -191,6 +191,7 @@
     public static final String CCT_REPORT_PARALLEL_REQUEST_STATUS =
             "CCTReportParallelRequestStatus";
     public static final String CCT_TARGET_TRANSLATE_LANGUAGE = "CCTTargetTranslateLanguage";
+    public static final String CLOSE_TAB_SUGGESTIONS_STALE = "CloseTabSuggestionsStale";
     public static final String CHROME_DUET = "ChromeDuet";
     public static final String CHROME_DUET_ADAPTIVE = "ChromeDuetAdaptive";
     public static final String DONT_AUTO_HIDE_BROWSER_CONTROLS = "DontAutoHideBrowserControls";
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/contacts_picker/ContactDetails.java b/chrome/android/java/src/org/chromium/chrome/browser/contacts_picker/ContactDetails.java
index 04998a0..d8a2762 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/contacts_picker/ContactDetails.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/contacts_picker/ContactDetails.java
@@ -17,6 +17,18 @@
  * A class to keep track of the metadata associated with a contact.
  */
 public class ContactDetails implements Comparable<ContactDetails> {
+    /**
+     * A container class for delivering contact details in abbreviated form
+     * (where only the first email and phone numbers are returned and the rest
+     * is indicated with "+n more" strings).
+     */
+    public static class AbbreviatedContactDetails {
+        public String primaryEmail;
+        public String overflowEmailCount;
+        public String primaryTelephoneNumber;
+        public String overflowTelephoneNumberCount;
+    }
+
     // The unique id for the contact.
     private final String mId;
 
@@ -87,16 +99,11 @@
     /**
      * Accessor for the list of contact details (emails and phone numbers). Returned as strings
      * separated by newline).
-     * @param longVersion Whether to get all the details (for emails and phone numbers) or only what
-     *                    will fit in the allotted space on the dialog.
      * @param includeEmails Whether to include emails in the returned results.
      * @param includeTels Whether to include telephones in the returned results.
-     * @param resources The resources to use for fetching the string. Must be provided if
-     *                  longVersion is false, otherwise it can be null.
      * @return A string containing all the contact details registered for this contact.
      */
-    public String getContactDetailsAsString(boolean longVersion, boolean includeEmails,
-            boolean includeTels, @Nullable Resources resources) {
+    public String getContactDetailsAsString(boolean includeEmails, boolean includeTels) {
         int count = 0;
         StringBuilder builder = new StringBuilder();
         if (includeEmails) {
@@ -105,12 +112,6 @@
                     builder.append("\n");
                 }
                 builder.append(email);
-                if (!longVersion && mEmails.size() > 1) {
-                    int size = mEmails.size() - 1;
-                    builder.append(resources.getQuantityString(
-                            R.plurals.contacts_picker_more_details, size, size));
-                    break;
-                }
             }
         }
         if (includeTels) {
@@ -119,12 +120,6 @@
                     builder.append("\n");
                 }
                 builder.append(phoneNumber);
-                if (!longVersion && mPhoneNumbers.size() > 1) {
-                    int size = mPhoneNumbers.size() - 1;
-                    builder.append(resources.getQuantityString(
-                            R.plurals.contacts_picker_more_details, size, size));
-                    break;
-                }
             }
         }
 
@@ -132,6 +127,42 @@
     }
 
     /**
+     * Accessor for the list of contact details (emails and phone numbers).
+     * @param includeEmails Whether to include emails in the returned results.
+     * @param includeTels Whether to include telephones in the returned results.
+     * @param resources The resources to use for fetching the string. Must be provided.
+     * @return The contact details registered for this contact.
+     */
+    public AbbreviatedContactDetails getAbbreviatedContactDetails(
+            boolean includeEmails, boolean includeTels, @Nullable Resources resources) {
+        AbbreviatedContactDetails results = new AbbreviatedContactDetails();
+
+        results.overflowEmailCount = "";
+        if (!includeEmails || mEmails.size() == 0) {
+            results.primaryEmail = "";
+        } else {
+            results.primaryEmail = mEmails.get(0);
+            if (mEmails.size() > 1) {
+                results.overflowEmailCount = resources.getQuantityString(
+                        R.plurals.contacts_picker_more_details, (mEmails.size() - 1));
+            }
+        }
+
+        results.overflowTelephoneNumberCount = "";
+        if (!includeTels || mPhoneNumbers.size() == 0) {
+            results.primaryTelephoneNumber = "";
+        } else {
+            results.primaryTelephoneNumber = mPhoneNumbers.get(0);
+            if (mPhoneNumbers.size() > 1) {
+                results.overflowTelephoneNumberCount = resources.getQuantityString(
+                        R.plurals.contacts_picker_more_details, (mPhoneNumbers.size() - 1));
+            }
+        }
+
+        return results;
+    }
+
+    /**
      * A comparison function (results in a full name ascending sorting).
      * @param other The other ContactDetails object to compare it with.
      * @return 0, 1, or -1, depending on which is bigger.
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/contacts_picker/ContactView.java b/chrome/android/java/src/org/chromium/chrome/browser/contacts_picker/ContactView.java
index bf07c6c..9a95eafb 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/contacts_picker/ContactView.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/contacts_picker/ContactView.java
@@ -10,6 +10,7 @@
 import android.graphics.drawable.BitmapDrawable;
 import android.support.v4.graphics.drawable.RoundedBitmapDrawable;
 import android.support.v4.graphics.drawable.RoundedBitmapDrawableFactory;
+import android.text.TextUtils;
 import android.util.AttributeSet;
 import android.view.View;
 import android.widget.TextView;
@@ -40,10 +41,13 @@
     private ContactDetails mContactDetails;
 
     // The display name of the contact.
-    public TextView mDisplayName;
+    private TextView mDisplayName;
 
     // The contact details for the contact.
-    public TextView mDetailsView;
+    private TextView mEmail;
+    private TextView mEmailOverflowCount;
+    private TextView mPhoneNumber;
+    private TextView mPhoneNumberOverflowCount;
 
     // The dialog manager to use to show contact details.
     private ModalDialogManager mManager;
@@ -66,8 +70,23 @@
         super.onFinishInflate();
 
         mDisplayName = findViewById(R.id.title);
-        mDetailsView = findViewById(R.id.description);
-        mDetailsView.setMaxLines(2);
+        mEmail = findViewById(R.id.email);
+        mEmailOverflowCount = findViewById(R.id.email_overflow_count);
+        mPhoneNumber = findViewById(R.id.telephone_number);
+        mPhoneNumberOverflowCount = findViewById(R.id.telephone_number_overflow_count);
+
+        mEmailOverflowCount.setOnClickListener(this);
+        mPhoneNumberOverflowCount.setOnClickListener(this);
+    }
+
+    @Override
+    public void onClick(View view) {
+        int id = view.getId();
+        if (id == R.id.email_overflow_count || id == R.id.telephone_number_overflow_count) {
+            onLongClick(this);
+        } else {
+            super.onClick(view);
+        }
     }
 
     @Override
@@ -94,9 +113,9 @@
                          .with(ModalDialogProperties.CONTROLLER, controller)
                          .with(ModalDialogProperties.TITLE, mContactDetails.getDisplayName())
                          .with(ModalDialogProperties.MESSAGE,
-                                 mContactDetails.getContactDetailsAsString(true,
+                                 mContactDetails.getContactDetailsAsString(
                                          PickerAdapter.includesEmails(),
-                                         PickerAdapter.includesTelephones(), null))
+                                         PickerAdapter.includesTelephones()))
                          .with(ModalDialogProperties.POSITIVE_BUTTON_TEXT, mContext.getResources(),
                                  R.string.close)
                          .build();
@@ -130,6 +149,11 @@
         setSelectionDelegate(mSelectionDelegate);
     }
 
+    private void updateTextViewVisibilityAndContent(TextView view, String text) {
+        view.setVisibility(TextUtils.isEmpty(text) ? View.GONE : View.VISIBLE);
+        view.setText(text);
+    }
+
     /**
      * Completes the initialization of the ContactView. Must be called before the
      * {@link ContactView} can respond to click events.
@@ -145,11 +169,17 @@
         String displayName = contactDetails.getDisplayName();
         mDisplayName.setText(displayName);
 
-        String details = contactDetails.getContactDetailsAsString(
-                /*longVersion=*/false, /*includeEmails=*/PickerAdapter.includesEmails(),
-                /*includeTels=*/PickerAdapter.includesTelephones(), mContext.getResources());
-        mDetailsView.setText(details);
-        mDetailsView.setVisibility(details.isEmpty() ? View.GONE : View.VISIBLE);
+        ContactDetails.AbbreviatedContactDetails details =
+                contactDetails.getAbbreviatedContactDetails(
+                        /*includeEmails=*/PickerAdapter.includesEmails(),
+                        /*includeTels=*/PickerAdapter.includesTelephones(),
+                        mContext.getResources());
+
+        updateTextViewVisibilityAndContent(mEmail, details.primaryEmail);
+        updateTextViewVisibilityAndContent(mEmailOverflowCount, details.overflowEmailCount);
+        updateTextViewVisibilityAndContent(mPhoneNumber, details.primaryTelephoneNumber);
+        updateTextViewVisibilityAndContent(
+                mPhoneNumberOverflowCount, details.overflowTelephoneNumberCount);
 
         if (icon == null) {
             icon = mCategoryView.getIconGenerator().generateIconForText(
@@ -178,6 +208,9 @@
     private void resetTile() {
         setIconDrawable(null);
         mDisplayName.setText("");
-        mDetailsView.setText("");
+        mEmail.setText("");
+        mEmailOverflowCount.setText("");
+        mPhoneNumber.setText("");
+        mPhoneNumberOverflowCount.setText("");
     }
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/contacts_picker/PickerAdapter.java b/chrome/android/java/src/org/chromium/chrome/browser/contacts_picker/PickerAdapter.java
index 263e4dc..5d79682 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/contacts_picker/PickerAdapter.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/contacts_picker/PickerAdapter.java
@@ -155,9 +155,7 @@
             String query_lower = query.toLowerCase(Locale.getDefault());
             for (ContactDetails contact : mContactDetails) {
                 if (contact.getDisplayName().toLowerCase(Locale.getDefault()).contains(query_lower)
-                        || contact.getContactDetailsAsString(
-                                          /*longVersion=*/true, includesEmails(),
-                                          includesTelephones(), /*resources=*/null)
+                        || contact.getContactDetailsAsString(includesEmails(), includesTelephones())
                                    .toLowerCase(Locale.getDefault())
                                    .contains(query_lower)) {
                     mSearchResults.add(count);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/signin/SigninFragment.java b/chrome/android/java/src/org/chromium/chrome/browser/signin/SigninFragment.java
index b505c73..9fa39d50 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/signin/SigninFragment.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/signin/SigninFragment.java
@@ -4,6 +4,7 @@
 
 package org.chromium.chrome.browser.signin;
 
+import android.app.Activity;
 import android.os.Bundle;
 import android.support.annotation.IntDef;
 import android.support.annotation.Nullable;
@@ -145,7 +146,10 @@
                         }
 
                         recordSigninCompletedHistogramAccountInfo();
-                        getActivity().finish();
+
+                        Activity activity = getActivity();
+                        if (activity != null) activity.finish();
+
                         callback.run();
                     }
 
diff --git a/chrome/android/java/strings/android_chrome_strings.grd b/chrome/android/java/strings/android_chrome_strings.grd
index 06b54bb..bdaba8a6d 100644
--- a/chrome/android/java/strings/android_chrome_strings.grd
+++ b/chrome/android/java/strings/android_chrome_strings.grd
@@ -3539,10 +3539,10 @@
       <message name="IDS_TOP_VIEW_TELEPHONE_FILTER_LABEL" desc="The label shown for the telephone filter toggle button (allowing the user to exclude emails).">
         Phone numbers
       </message>
-      <message name="IDS_CONTACTS_PICKER_MORE_DETAILS" desc="Label describing that the user has one or more telephone/emails (used for either). The leading space is a word separator, for those languages that use space as a separator.">
+      <message name="IDS_CONTACTS_PICKER_MORE_DETAILS" desc="Label describing that the user has one or more telephone/emails (used for either).">
         {DETAIL_COUNT, plural,
-          =1 { (+ 1 more)}
-          other { (+ # more)}}
+          =1 {(+ 1 more)}
+          other {(+ # more)}}
       </message>
       <message name="IDS_DISCLAIMER_SHARING_CONTACT_DETAILS" desc="Label describing what will happen with the contact details that are being shared.">
         The contacts you select will be shared with <ph name="BEGIN_BOLD">&lt;b&gt;</ph><ph name="SITE">%1$s<ex>https://www.google.com</ex></ph><ph name="END_BOLD">&lt;/b&gt;</ph>.
diff --git a/chrome/app/file_pre_reader_win.h b/chrome/app/file_pre_reader_win.h
deleted file mode 100644
index dcd596c..0000000
--- a/chrome/app/file_pre_reader_win.h
+++ /dev/null
@@ -1,19 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-// This file defines a function to pre-read a file in order to avoid touching
-// the disk when it is subsequently used.
-
-#ifndef CHROME_APP_FILE_PRE_READER_WIN_H_
-#define CHROME_APP_FILE_PRE_READER_WIN_H_
-
-namespace base {
-class FilePath;
-}
-
-// Pre-reads |file_path| to avoid touching the disk when the file is actually
-// used.
-void PreReadFile(const base::FilePath& file_path);
-
-#endif  // CHROME_APP_FILE_PRE_READER_WIN_H_
diff --git a/chrome/app/generated_resources.grd b/chrome/app/generated_resources.grd
index ecf95aa..90ec9ba 100644
--- a/chrome/app/generated_resources.grd
+++ b/chrome/app/generated_resources.grd
@@ -5972,9 +5972,6 @@
       <message name="IDS_PICTURE_IN_PICTURE_PLAY_PAUSE_CONTROL_ACCESSIBLE_TEXT" desc="Accessible text label used for the controls button in the Picture-in-Picture window. The button toggles between play and pause controls.">
         Toggle video to play or pause
       </message>
-      <message name="IDS_PICTURE_IN_PICTURE_MUTE_CONTROL_ACCESSIBLE_TEXT" desc="Accessible text label used for the controls button in the Picture-in-Picture window. The button toggles mute state.">
-        Toggle mute
-      </message>
       <message name="IDS_PICTURE_IN_PICTURE_NEXT_TRACK_CONTROL_ACCESSIBLE_TEXT" desc="Accessible text label used for the controls button in the Picture-in-Picture window. The button invokes next track action.">
         Next track
       </message>
diff --git a/chrome/app/main_dll_loader_win.cc b/chrome/app/main_dll_loader_win.cc
index b5f9eb4b..a6d4064 100644
--- a/chrome/app/main_dll_loader_win.cc
+++ b/chrome/app/main_dll_loader_win.cc
@@ -27,12 +27,12 @@
 #include "base/strings/string_util.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/trace_event/trace_event.h"
+#include "base/win/file_pre_reader.h"
 #include "base/win/scoped_handle.h"
 #include "base/win/shlwapi.h"
 #include "base/win/windows_version.h"
 #include "chrome/app/chrome_watcher_client_win.h"
 #include "chrome/app/chrome_watcher_command_line_win.h"
-#include "chrome/app/file_pre_reader_win.h"
 #include "chrome/browser/active_use_util.h"
 #include "chrome/chrome_watcher/chrome_watcher_main_api.h"
 #include "chrome/common/chrome_constants.h"
@@ -57,7 +57,7 @@
 // reference to the loaded module on success, or null on error.
 HMODULE LoadModuleWithDirectory(const base::FilePath& module) {
   ::SetCurrentDirectoryW(module.DirName().value().c_str());
-  PreReadFile(module);
+  base::win::PreReadFile(module, true);
   return ::LoadLibraryExW(module.value().c_str(), nullptr,
                           LOAD_WITH_ALTERED_SEARCH_PATH);
 }
diff --git a/chrome/app/settings_strings.grdp b/chrome/app/settings_strings.grdp
index be474a74..c215e76a 100644
--- a/chrome/app/settings_strings.grdp
+++ b/chrome/app/settings_strings.grdp
@@ -3870,9 +3870,6 @@
     <message name="IDS_SETTINGS_PEOPLE_LOCK_SCREEN_NEW_FINGERPRINT_DEFAULT_NAME" desc="The default name (plus a number for a newly added fingerprint).">
       Finger <ph name="NEW_FINGER_NUMBER">$1<ex>1</ex></ph>
     </message>
-    <message name="IDS_SETTINGS_PEOPLE_LOCK_SCREEN_MEDIA_CONTROLS" desc="Label for the checkbox which enables or disables media controls on the lock screen.">
-      Enable Chrome media playback at lock screen
-    </message>
     <message name="IDS_SETTINGS_ACCOUNT_MANAGER_ADD_ACCOUNT_LABEL" desc="Label of the Add account button in Account Manager.">
       Add account
     </message>
diff --git a/chrome/browser/BUILD.gn b/chrome/browser/BUILD.gn
index f57cef5..e30168b 100644
--- a/chrome/browser/BUILD.gn
+++ b/chrome/browser/BUILD.gn
@@ -489,6 +489,7 @@
     "engagement/site_engagement_service.h",
     "engagement/site_engagement_service_factory.cc",
     "engagement/site_engagement_service_factory.h",
+    "expired_flags_list.h",
     "external_protocol/external_protocol_handler.cc",
     "external_protocol/external_protocol_handler.h",
     "external_protocol/external_protocol_observer.cc",
@@ -1813,6 +1814,8 @@
     "translate/translate_service.h",
     "undo/bookmark_undo_service_factory.cc",
     "undo/bookmark_undo_service_factory.h",
+    "unexpire_flags.cc",
+    "unexpire_flags.h",
     "unified_consent/unified_consent_service_factory.cc",
     "unified_consent/unified_consent_service_factory.h",
     "update_client/chrome_update_query_params_delegate.cc",
@@ -1919,6 +1922,7 @@
   deps = [
     ":active_use_util",
     ":availability_protos",
+    ":expired_flags_list",
     ":ntp_background_proto",
     ":resource_prefetch_predictor_proto",
     "//base:i18n",
@@ -3755,7 +3759,6 @@
     ]
     deps += [
       ":chrome_process_finder",
-      "//chrome:file_pre_reader",
       "//chrome/browser/safe_browsing/chrome_cleaner",
       "//chrome/browser/safe_browsing/chrome_cleaner:public",
       "//chrome/browser/win/conflicts:module_info",
@@ -5373,6 +5376,27 @@
   }
 }
 
+action("expired_flags_list_gen") {
+  script = "//tools/flags/generate_expired_list.py"
+  sources = [
+    "flag-metadata.json",
+  ]
+  outputs = [
+    "$root_gen_dir/chrome/browser/expired_flags_list.cc",
+  ]
+  args = rebase_path(sources, root_build_dir) +
+         rebase_path(outputs, root_build_dir)
+}
+
+source_set("expired_flags_list") {
+  deps = [
+    ":expired_flags_list_gen",
+  ]
+  sources = [
+    "$root_gen_dir/chrome/browser/expired_flags_list.cc",
+  ]
+}
+
 # Use a static library here because many test binaries depend on this but don't
 # require many files from it. This makes linking more efficient.
 static_library("test_support") {
diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc
index d9bfea6d..b9f6c71d1 100644
--- a/chrome/browser/about_flags.cc
+++ b/chrome/browser/about_flags.cc
@@ -43,6 +43,7 @@
 #include "chrome/browser/signin/account_consistency_mode_manager.h"
 #include "chrome/browser/ssl/chrome_ssl_host_state_delegate.h"
 #include "chrome/browser/ui/ui_features.h"
+#include "chrome/browser/unexpire_flags.h"
 #include "chrome/common/buildflags.h"
 #include "chrome/common/channel_info.h"
 #include "chrome/common/chrome_content_client.h"
@@ -467,6 +468,23 @@
      kForceDark_SelectiveGeneralInversion,
      base::size(kForceDark_SelectiveGeneralInversion), nullptr}};
 
+#if defined(OS_ANDROID)
+const FeatureEntry::FeatureParam kCloseTabSuggestionsStale_4Hours[] = {
+    {"close_tab_suggestions_stale_time_ms", "14400000"}};
+const FeatureEntry::FeatureParam kCloseTabSuggestionsStale_8Hours[] = {
+    {"close_tab_suggestions_stale_time_ms", "28800000"}};
+const FeatureEntry::FeatureParam kCloseTabSuggestionsStale_7Days[] = {
+    {"close_tab_suggestions_stale_time_ms", "604800000"}};
+const FeatureEntry::FeatureVariation kCloseTabSuggestionsStaleVariations[] = {
+    {"4 hours", kCloseTabSuggestionsStale_4Hours,
+     base::size(kCloseTabSuggestionsStale_4Hours), nullptr},
+    {"8 hours", kCloseTabSuggestionsStale_8Hours,
+     base::size(kCloseTabSuggestionsStale_8Hours), nullptr},
+    {"7 days", kCloseTabSuggestionsStale_7Days,
+     base::size(kCloseTabSuggestionsStale_7Days), nullptr},
+};
+#endif  // OS_ANDROID
+
 const FeatureEntry::Choice kEnableGpuRasterizationChoices[] = {
     {flags_ui::kGenericExperimentChoiceDefault, "", ""},
     {flags_ui::kGenericExperimentChoiceEnabled,
@@ -3213,6 +3231,13 @@
                                     kStartSurfaceAndroidVariations,
                                     "StartSurfaceAndroid")},
 
+    {"enable-close-tab-suggestions-stale",
+     flag_descriptions::kCloseTabSuggestionsStaleName,
+     flag_descriptions::kCloseTabSuggestionsStaleDescription, kOsAndroid,
+     FEATURE_WITH_PARAMS_VALUE_TYPE(chrome::android::kCloseTabSuggestionsStale,
+                                    kCloseTabSuggestionsStaleVariations,
+                                    "CloseSuggestionsStaleTab")},
+
     {"enable-horizontal-tab-switcher",
      flag_descriptions::kHorizontalTabSwitcherAndroidName,
      flag_descriptions::kHorizontalTabSwitcherAndroidDescription, kOsAndroid,
@@ -4333,9 +4358,9 @@
 
     // This set of flags is used to temporary reinstate expired flags; see
     // //docs/flag_expiry.md for details.
-    {"temporary-unexpire-flags-m78", flag_descriptions::kUnexpireFlagsM78Name,
-     flag_descriptions::kUnexpireFlagsM78Description, kOsAll,
-     FEATURE_VALUE_TYPE(flags_ui::kUnexpireFlagsM78)},
+    {"temporary-unexpire-flags-m76", flag_descriptions::kUnexpireFlagsM76Name,
+     flag_descriptions::kUnexpireFlagsM76Description, kOsAll,
+     FEATURE_VALUE_TYPE(flags::kUnexpireFlagsM76)},
 
 #if defined(OS_CHROMEOS)
     {"lock-screen-media-controls",
@@ -4483,6 +4508,9 @@
     return true;
   }
 
+  if (flags::IsFlagExpired(entry.internal_name))
+    return true;
+
   return false;
 }
 
diff --git a/chrome/browser/about_flags_browsertest.cc b/chrome/browser/about_flags_browsertest.cc
index f7b80538..cc00a28 100644
--- a/chrome/browser/about_flags_browsertest.cc
+++ b/chrome/browser/about_flags_browsertest.cc
@@ -5,13 +5,14 @@
 #include "base/command_line.h"
 #include "base/strings/stringprintf.h"
 #include "base/strings/utf_string_conversions.h"
+#include "base/test/scoped_feature_list.h"
 #include "build/build_config.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
+#include "chrome/browser/unexpire_flags.h"
 #include "chrome/test/base/in_process_browser_test.h"
 #include "chrome/test/base/interactive_test_utils.h"
 #include "chrome/test/base/ui_test_utils.h"
-#include "components/flags_ui/flags_state.h"
 #include "content/public/browser/web_contents.h"
 #include "content/public/test/browser_test_utils.h"
 #include "ui/base/window_open_disposition.h"
@@ -105,7 +106,7 @@
                               public testing::WithParamInterface<bool> {
  public:
   AboutFlagsBrowserTest() {
-    feature_list_.InitWithFeatures({flags_ui::kUnexpireFlagsM78}, {});
+    feature_list_.InitWithFeatures({flags::kUnexpireFlagsM76}, {});
   }
 
   void SetUpCommandLine(base::CommandLine* command_line) override {
diff --git a/chrome/browser/android/chrome_feature_list.cc b/chrome/browser/android/chrome_feature_list.cc
index f05b6ec..b636d6ad 100644
--- a/chrome/browser/android/chrome_feature_list.cc
+++ b/chrome/browser/android/chrome_feature_list.cc
@@ -92,6 +92,7 @@
     &kAndroidSiteSettingsUIRefresh,
     &kBackgroundTaskSchedulerForBackgroundSync,
     &kCastDeviceFilter,
+    &kCloseTabSuggestionsStale,
     &kCCTBackgroundTab,
     &kCCTExternalLinkHandling,
     &kCCTModule,
@@ -282,6 +283,9 @@
 const base::Feature kCastDeviceFilter{"CastDeviceFilter",
                                       base::FEATURE_DISABLED_BY_DEFAULT};
 
+const base::Feature kCloseTabSuggestionsStale{
+    "CloseTabSuggestionsStale", base::FEATURE_DISABLED_BY_DEFAULT};
+
 const base::Feature kCCTBackgroundTab{"CCTBackgroundTab",
                                       base::FEATURE_ENABLED_BY_DEFAULT};
 
diff --git a/chrome/browser/android/chrome_feature_list.h b/chrome/browser/android/chrome_feature_list.h
index a295cb5..17d5d62 100644
--- a/chrome/browser/android/chrome_feature_list.h
+++ b/chrome/browser/android/chrome_feature_list.h
@@ -25,6 +25,7 @@
 extern const base::Feature kAndroidSiteSettingsUIRefresh;
 extern const base::Feature kBackgroundTaskComponentUpdate;
 extern const base::Feature kBackgroundTaskSchedulerForBackgroundSync;
+extern const base::Feature kCloseTabSuggestionsStale;
 extern const base::Feature kCastDeviceFilter;
 extern const base::Feature kCCTBackgroundTab;
 extern const base::Feature kCCTExternalLinkHandling;
diff --git a/chrome/browser/chromeos/account_manager/account_manager_migrator.cc b/chrome/browser/chromeos/account_manager/account_manager_migrator.cc
index e15b27da..85545ab2 100644
--- a/chrome/browser/chromeos/account_manager/account_manager_migrator.cc
+++ b/chrome/browser/chromeos/account_manager/account_manager_migrator.cc
@@ -472,6 +472,12 @@
   if (!chromeos::IsAccountManagerAvailable(profile_))
     return;
 
+  if (migration_runner_ && (migration_runner_->GetStatus() ==
+                            AccountMigrationRunner::Status::kRunning)) {
+    return;
+  }
+  migration_runner_ = std::make_unique<AccountMigrationRunner>();
+
   ran_migration_steps_ = false;
   if (ShouldRunMigrations()) {
     ran_migration_steps_ = true;
@@ -481,7 +487,7 @@
   // Cleanup tasks (like re-enabling Chrome account reconciliation) rely on the
   // migration being run, even if they were no-op. Check
   // |OnMigrationRunComplete| and |RunCleanupTasks|.
-  migration_runner_.Run(
+  migration_runner_->Run(
       base::BindOnce(&AccountManagerMigrator::OnMigrationRunComplete,
                      weak_factory_.GetWeakPtr()));
 }
@@ -524,7 +530,7 @@
   signin::IdentityManager* identity_manager =
       IdentityManagerFactory::GetForProfile(profile_);
 
-  migration_runner_.AddStep(std::make_unique<DeviceAccountMigration>(
+  migration_runner_->AddStep(std::make_unique<DeviceAccountMigration>(
       GetDeviceAccount(profile_),
       ProfileHelper::Get()
           ->GetUserByProfile(profile_)
@@ -538,14 +544,14 @@
           chromeos::prefs::kSecondaryGoogleAccountSigninAllowed);
 
   if (is_secondary_google_account_signin_allowed) {
-    migration_runner_.AddStep(std::make_unique<ContentAreaAccountsMigration>(
+    migration_runner_->AddStep(std::make_unique<ContentAreaAccountsMigration>(
         account_manager, identity_manager));
 
     if (arc::IsArcProvisioned(profile_)) {
       // Add a migration step for ARC only if ARC has been provisioned. If ARC
       // has not been provisioned yet, there cannot be any accounts that need to
       // be migrated.
-      migration_runner_.AddStep(std::make_unique<ArcAccountsMigration>(
+      migration_runner_->AddStep(std::make_unique<ArcAccountsMigration>(
           account_manager, identity_manager,
           arc::ArcAuthService::GetForBrowserContext(
               profile_) /* arc_auth_service */));
@@ -557,22 +563,32 @@
 
   // This MUST be the last step. Check the class level documentation of
   // |SuccessStorage| for the reason.
-  migration_runner_.AddStep(
+  migration_runner_->AddStep(
       std::make_unique<SuccessStorage>(profile_->GetPrefs()));
 
   // TODO(sinhak): Verify Device Account LST state.
 }
 
 AccountMigrationRunner::Status AccountManagerMigrator::GetStatus() const {
-  return migration_runner_.GetStatus();
+  if (!migration_runner_)
+    return AccountMigrationRunner::Status::kNotStarted;
+
+  return migration_runner_->GetStatus();
+}
+
+base::Optional<AccountMigrationRunner::MigrationResult>
+AccountManagerMigrator::GetLastMigrationRunResult() const {
+  return last_migration_run_result_;
 }
 
 void AccountManagerMigrator::OnMigrationRunComplete(
     const AccountMigrationRunner::MigrationResult& result) {
   DCHECK_NE(AccountMigrationRunner::Status::kNotStarted,
-            migration_runner_.GetStatus());
+            migration_runner_->GetStatus());
   DCHECK_NE(AccountMigrationRunner::Status::kRunning,
-            migration_runner_.GetStatus());
+            migration_runner_->GetStatus());
+
+  last_migration_run_result_ = base::make_optional(result);
 
   VLOG(1) << "Account migrations completed with result: "
           << static_cast<int>(result.final_status);
diff --git a/chrome/browser/chromeos/account_manager/account_manager_migrator.h b/chrome/browser/chromeos/account_manager/account_manager_migrator.h
index 9530dae..614bea9 100644
--- a/chrome/browser/chromeos/account_manager/account_manager_migrator.h
+++ b/chrome/browser/chromeos/account_manager/account_manager_migrator.h
@@ -5,8 +5,11 @@
 #ifndef CHROME_BROWSER_CHROMEOS_ACCOUNT_MANAGER_ACCOUNT_MANAGER_MIGRATOR_H_
 #define CHROME_BROWSER_CHROMEOS_ACCOUNT_MANAGER_ACCOUNT_MANAGER_MIGRATOR_H_
 
+#include <memory>
+
 #include "base/macros.h"
 #include "base/memory/weak_ptr.h"
+#include "base/optional.h"
 #include "chrome/browser/chromeos/account_manager/account_migration_runner.h"
 #include "components/keyed_service/content/browser_context_keyed_service_factory.h"
 #include "components/keyed_service/core/keyed_service.h"
@@ -31,6 +34,11 @@
   // Gets the current status of migration.
   AccountMigrationRunner::Status GetStatus() const;
 
+  // Gets the result of the last migration run. If migrations have not been run
+  // before, the optional will be empty.
+  base::Optional<AccountMigrationRunner::MigrationResult>
+  GetLastMigrationRunResult() const;
+
  private:
   // Returns whether migrations should be run or skipped.
   bool ShouldRunMigrations() const;
@@ -49,12 +57,17 @@
   Profile* const profile_;
 
   // Used for running migration steps.
-  chromeos::AccountMigrationRunner migration_runner_;
+  std::unique_ptr<AccountMigrationRunner> migration_runner_ = nullptr;
 
   // Stores if any migration steps were actually run. It is possible for the
   // migration flow to be a no-op, in which case this will be |false|.
   bool ran_migration_steps_ = false;
 
+  // Result of the last migration run. Empty if migrations have not been run
+  // before.
+  base::Optional<AccountMigrationRunner::MigrationResult>
+      last_migration_run_result_;
+
   base::WeakPtrFactory<AccountManagerMigrator> weak_factory_{this};
   DISALLOW_COPY_AND_ASSIGN(AccountManagerMigrator);
 };
diff --git a/chrome/browser/chromeos/arc/pip/arc_picture_in_picture_window_controller_impl.cc b/chrome/browser/chromeos/arc/pip/arc_picture_in_picture_window_controller_impl.cc
index 2028cce..322e4f2 100644
--- a/chrome/browser/chromeos/arc/pip/arc_picture_in_picture_window_controller_impl.cc
+++ b/chrome/browser/chromeos/arc/pip/arc_picture_in_picture_window_controller_impl.cc
@@ -50,11 +50,6 @@
   return false;
 }
 
-bool ArcPictureInPictureWindowControllerImpl::IsPlayerMuted() {
-  // Should be a no-op on ARC. This is managed on the Android side.
-  return false;
-}
-
 content::WebContents*
 ArcPictureInPictureWindowControllerImpl::GetInitiatorWebContents() {
   // Should be a no-op on ARC. This is managed on the Android side.
@@ -67,30 +62,16 @@
   // Should be a no-op on ARC. This is managed on the Android side.
 }
 
-void ArcPictureInPictureWindowControllerImpl::UpdateMutedState() {
-  // Should be a no-op on ARC. This is managed on the Android side.
-}
-
 bool ArcPictureInPictureWindowControllerImpl::TogglePlayPause() {
   // Should be a no-op on ARC. This is managed on the Android side.
   return false;
 }
 
-bool ArcPictureInPictureWindowControllerImpl::ToggleMute() {
-  // Should be a no-op on ARC. This is managed on the Android side.
-  return false;
-}
-
 void ArcPictureInPictureWindowControllerImpl::SetAlwaysHidePlayPauseButton(
     bool is_visible) {
   // Should be a no-op on ARC. This is managed on the Android side.
 }
 
-void ArcPictureInPictureWindowControllerImpl::SetAlwaysHideMuteButton(
-    bool is_visible) {
-  // Should be a no-op on ARC. This is managed on the Android side.
-}
-
 void ArcPictureInPictureWindowControllerImpl::SkipAd() {
   // Should be a no-op on ARC. This is managed on the Android side.
 }
diff --git a/chrome/browser/chromeos/arc/pip/arc_picture_in_picture_window_controller_impl.h b/chrome/browser/chromeos/arc/pip/arc_picture_in_picture_window_controller_impl.h
index b3dc339..f71c45c 100644
--- a/chrome/browser/chromeos/arc/pip/arc_picture_in_picture_window_controller_impl.h
+++ b/chrome/browser/chromeos/arc/pip/arc_picture_in_picture_window_controller_impl.h
@@ -37,15 +37,11 @@
   content::OverlayWindow* GetWindowForTesting() override;
   void UpdateLayerBounds() override;
   bool IsPlayerActive() override;
-  bool IsPlayerMuted() override;
   content::WebContents* GetInitiatorWebContents() override;
   bool TogglePlayPause() override;
-  bool ToggleMute() override;
   void UpdatePlaybackState(bool is_playing,
                            bool reached_end_of_stream) override;
-  void UpdateMutedState() override;
   void SetAlwaysHidePlayPauseButton(bool is_visible) override;
-  void SetAlwaysHideMuteButton(bool is_visible) override;
   void SkipAd() override;
   void NextTrack() override;
   void PreviousTrack() override;
diff --git a/chrome/browser/chromeos/crostini/crostini_manager.cc b/chrome/browser/chromeos/crostini/crostini_manager.cc
index b8f2ad3..0f5fccf9 100644
--- a/chrome/browser/chromeos/crostini/crostini_manager.cc
+++ b/chrome/browser/chromeos/crostini/crostini_manager.cc
@@ -534,6 +534,30 @@
   }
 }
 
+void CrostiniManager::SetContainerOsRelease(
+    std::string vm_name,
+    std::string container_name,
+    const vm_tools::cicerone::OsRelease& os_release) {
+  container_os_releases_.emplace(ContainerId(vm_name, container_name),
+                                 os_release);
+  VLOG(1) << "vm_name: " << vm_name << " container_name: " << container_name;
+  VLOG(1) << "os_release.pretty_name " << os_release.pretty_name();
+  VLOG(1) << "os_release.name " << os_release.name();
+  VLOG(1) << "os_release.version " << os_release.version();
+  VLOG(1) << "os_release.version_id " << os_release.version_id();
+  VLOG(1) << "os_release.id " << os_release.id();
+}
+
+const vm_tools::cicerone::OsRelease* CrostiniManager::GetContainerOsRelease(
+    std::string vm_name,
+    std::string container_name) {
+  auto it = container_os_releases_.find(ContainerId(vm_name, container_name));
+  if (it != container_os_releases_.end()) {
+    return &it->second;
+  }
+  return nullptr;
+}
+
 base::Optional<ContainerInfo> CrostiniManager::GetContainerInfo(
     std::string vm_name,
     std::string container_name) {
@@ -2117,6 +2141,9 @@
       NOTREACHED();
       break;
   }
+  if (response->has_os_release()) {
+    SetContainerOsRelease(vm_name, container_name, response->os_release());
+  }
 }
 
 void CrostiniManager::OnSetUpLxdContainerUser(
@@ -2257,6 +2284,10 @@
     VLOG(1) << "Awaiting ContainerStarted signal from Garcon";
     return;
   }
+  if (signal.has_os_release()) {
+    SetContainerOsRelease(signal.vm_name(), signal.container_name(),
+                          signal.os_release());
+  }
   // Find the callbacks to call, then erase them from the map.
   auto range = start_container_callbacks_.equal_range(
       std::make_tuple(signal.vm_name(), signal.container_name()));
diff --git a/chrome/browser/chromeos/crostini/crostini_manager.h b/chrome/browser/chromeos/crostini/crostini_manager.h
index d900f0f..c4dafd6e 100644
--- a/chrome/browser/chromeos/crostini/crostini_manager.h
+++ b/chrome/browser/chromeos/crostini/crostini_manager.h
@@ -481,6 +481,12 @@
   void SetContainerSshfsMounted(std::string vm_name,
                                 std::string container_name,
                                 bool is_mounted);
+  void SetContainerOsRelease(std::string vm_name,
+                             std::string container_name,
+                             const vm_tools::cicerone::OsRelease& os_release);
+  const vm_tools::cicerone::OsRelease* GetContainerOsRelease(
+      std::string vm_name,
+      std::string container_name);
   // Returns null if VM or container is not running.
   base::Optional<ContainerInfo> GetContainerInfo(std::string vm_name,
                                                  std::string container_name);
@@ -731,6 +737,10 @@
   // Running containers as keyed by vm name.
   std::multimap<std::string, ContainerInfo> running_containers_;
 
+  // OsRelease protos keyed by ContainerId. We populate this map even if a
+  // container fails to start normally.
+  std::map<ContainerId, vm_tools::cicerone::OsRelease> container_os_releases_;
+
   std::vector<RemoveCrostiniCallback> remove_crostini_callbacks_;
 
   base::ObserverList<LinuxPackageOperationProgressObserver>::Unchecked
diff --git a/chrome/browser/chromeos/crostini/crostini_manager_unittest.cc b/chrome/browser/chromeos/crostini/crostini_manager_unittest.cc
index ee8f7e0..16e9aade 100644
--- a/chrome/browser/chromeos/crostini/crostini_manager_unittest.cc
+++ b/chrome/browser/chromeos/crostini/crostini_manager_unittest.cc
@@ -3,7 +3,9 @@
 // found in the LICENSE file.
 
 #include "chrome/browser/chromeos/crostini/crostini_manager.h"
+
 #include <memory>
+
 #include "base/base64.h"
 #include "base/bind.h"
 #include "base/memory/ptr_util.h"
@@ -928,6 +930,28 @@
   EXPECT_FALSE(crostini_manager()->GetContainerInfo(kVmName, kContainerName));
 }
 
+TEST_F(CrostiniManagerRestartTest, OsReleaseSetCorrectly) {
+  vm_tools::cicerone::OsRelease os_release;
+  os_release.set_pretty_name("Debian GNU/Linux 10 (buster)");
+  fake_cicerone_client_->set_lxd_container_os_release(os_release);
+
+  restart_id_ = crostini_manager()->RestartCrostini(
+      kVmName, kContainerName,
+      base::BindOnce(&CrostiniManagerRestartTest::RestartCrostiniCallback,
+                     base::Unretained(this), run_loop()->QuitClosure()),
+      this);
+  EXPECT_TRUE(crostini_manager()->IsRestartPending(restart_id_));
+  run_loop()->Run();
+
+  const auto* stored_os_release =
+      crostini_manager()->GetContainerOsRelease(kVmName, kContainerName);
+  EXPECT_NE(stored_os_release, nullptr);
+  // Sadly, we can't use MessageDifferencer here because we're using the LITE
+  // API in our protos.
+  EXPECT_EQ(os_release.SerializeAsString(),
+            stored_os_release->SerializeAsString());
+}
+
 TEST_F(CrostiniManagerRestartTest, RestartThenUninstall) {
   restart_id_ = crostini_manager()->RestartCrostini(
       kVmName, kContainerName,
diff --git a/chrome/browser/chromeos/wilco_dtc_supportd/wilco_dtc_supportd_bridge.h b/chrome/browser/chromeos/wilco_dtc_supportd/wilco_dtc_supportd_bridge.h
index 469fb2c..ab94a63 100644
--- a/chrome/browser/chromeos/wilco_dtc_supportd/wilco_dtc_supportd_bridge.h
+++ b/chrome/browser/chromeos/wilco_dtc_supportd/wilco_dtc_supportd_bridge.h
@@ -135,7 +135,7 @@
   wilco_dtc_supportd::mojom::WilcoDtcSupportdServicePtr
       wilco_dtc_supportd_service_mojo_ptr_;
 
-  // The service to perform diagnostics_processor's web requests.
+  // The service to perform wilco_dtc_supportd's web requests.
   WilcoDtcSupportdWebRequestService web_request_service_;
 
   // The wilco_dtc_supportd notification controller in charge of sending
diff --git a/chrome/browser/chromeos/wilco_dtc_supportd/wilco_dtc_supportd_messaging.h b/chrome/browser/chromeos/wilco_dtc_supportd/wilco_dtc_supportd_messaging.h
index d3e3dbeb..ff186c4f7 100644
--- a/chrome/browser/chromeos/wilco_dtc_supportd/wilco_dtc_supportd_messaging.h
+++ b/chrome/browser/chromeos/wilco_dtc_supportd/wilco_dtc_supportd_messaging.h
@@ -29,13 +29,14 @@
 extern const int kWilcoDtcSupportdUiMessageMaxSize;
 
 // Creates an extensions native message host that talks to the
-// diagnostics_processor daemon. This should be used when the communication is
-// initiated by the extension (i.e., not the daemon).
+// wilco_dtc_supportd daemon.
+// This should be used when the communication is initiated by the extension
+// (i.e., not the daemon).
 std::unique_ptr<extensions::NativeMessageHost>
 CreateExtensionOwnedWilcoDtcSupportdMessageHost();
 
-// Delivers the UI message |json_message| from the diagnostics_processor daemon
-// to the extensions that are allowed to receive it. The delivery is done via
+// Delivers the UI message |json_message| from the wilco_dtc_supportd daemon to
+// the extensions that are allowed to receive it. The delivery is done via
 // creating extensions native message hosts. |send_response_callback| will be
 // called with the response from the extension (the first non-empty one in case
 // of multiple extensions providing some responses).
diff --git a/chrome/browser/chromeos/wilco_dtc_supportd/wilco_dtc_supportd_web_request_service.cc b/chrome/browser/chromeos/wilco_dtc_supportd/wilco_dtc_supportd_web_request_service.cc
index 576dc4d..a7063820 100644
--- a/chrome/browser/chromeos/wilco_dtc_supportd/wilco_dtc_supportd_web_request_service.cc
+++ b/chrome/browser/chromeos/wilco_dtc_supportd/wilco_dtc_supportd_web_request_service.cc
@@ -190,9 +190,9 @@
             sender: "WilcoDtcSupportd"
             description: "Perform a web request."
             trigger:
-                "diagnostics_processor performs a web request to their server."
+                "wilco_dtc_supportd performs a web request to their server."
             data:
-                "diagnostics_processor's proprietary data."
+                "wilco_dtc_supportd's proprietary data."
             destination: OTHER
           }
           policy {
diff --git a/chrome/browser/expired_flags_list.h b/chrome/browser/expired_flags_list.h
new file mode 100644
index 0000000..cc2ae77
--- /dev/null
+++ b/chrome/browser/expired_flags_list.h
@@ -0,0 +1,24 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_EXPIRED_FLAGS_LIST_H_
+#define CHROME_BROWSER_EXPIRED_FLAGS_LIST_H_
+
+// This header file declares a data structure that is generated at compile time
+// by //tools/flags/generate_expired_list.py - also see the
+// //chrome/browser:expired_flags_list target.
+
+namespace flags {
+
+struct ExpiredFlag {
+  const char* name;
+  int mstone;
+};
+
+// This array of names is terminated with a flag whose name is nullptr.
+extern const ExpiredFlag kExpiredFlags[];
+
+}  // namespace flags
+
+#endif  // CHROME_BROWSER_EXPIRED_FLAGS_LIST_H_
diff --git a/chrome/browser/extensions/api/settings_private/generated_time_zone_pref_base.cc b/chrome/browser/extensions/api/settings_private/generated_time_zone_pref_base.cc
index 620e7fa6..9e1dae7 100644
--- a/chrome/browser/extensions/api/settings_private/generated_time_zone_pref_base.cc
+++ b/chrome/browser/extensions/api/settings_private/generated_time_zone_pref_base.cc
@@ -42,11 +42,14 @@
           IsTimeZoneResolutionPolicyControlled()) {
     out_pref->controlled_by = settings_api::CONTROLLED_BY_DEVICE_POLICY;
     out_pref->enforcement = settings_api::ENFORCEMENT_ENFORCED;
-  } else if (profile_->IsChild() &&
-             !base::FeatureList::IsEnabled(
-                 features::kParentAccessCodeForTimeChange)) {
-    out_pref->controlled_by = settings_api::ControlledBy::CONTROLLED_BY_PARENT;
-    out_pref->enforcement = settings_api::ENFORCEMENT_ENFORCED;
+  } else if (profile_->IsChild()) {
+    out_pref->controlled_by = settings_api::CONTROLLED_BY_PARENT;
+    if (base::FeatureList::IsEnabled(
+            features::kParentAccessCodeForTimeChange)) {
+      out_pref->enforcement = settings_api::ENFORCEMENT_PARENT_SUPERVISED;
+    } else {
+      out_pref->enforcement = settings_api::ENFORCEMENT_ENFORCED;
+    }
   } else if (!profile_->IsSameProfile(
                  ProfileManager::GetPrimaryUserProfile())) {
     out_pref->controlled_by = settings_api::CONTROLLED_BY_PRIMARY_USER;
diff --git a/chrome/browser/extensions/api/settings_private/prefs_util.cc b/chrome/browser/extensions/api/settings_private/prefs_util.cc
index 9e59c6e..4882c773 100644
--- a/chrome/browser/extensions/api/settings_private/prefs_util.cc
+++ b/chrome/browser/extensions/api/settings_private/prefs_util.cc
@@ -477,8 +477,6 @@
       settings_api::PrefType::PREF_TYPE_BOOLEAN;
   (*s_whitelist)[prefs::kRestoreLastLockScreenNote] =
       settings_api::PrefType::PREF_TYPE_BOOLEAN;
-  (*s_whitelist)[ash::prefs::kLockScreenMediaControlsEnabled] =
-      settings_api::PrefType::PREF_TYPE_BOOLEAN;
   (*s_whitelist)[::prefs::kSettingsShowBrowserBanner] =
       settings_api::PrefType::PREF_TYPE_BOOLEAN;
 
diff --git a/chrome/browser/extensions/api/webstore_private/webstore_private_apitest.cc b/chrome/browser/extensions/api/webstore_private/webstore_private_apitest.cc
index b544f0d..dcbc0a9 100644
--- a/chrome/browser/extensions/api/webstore_private/webstore_private_apitest.cc
+++ b/chrome/browser/extensions/api/webstore_private/webstore_private_apitest.cc
@@ -42,6 +42,7 @@
 #include "ui/gl/gl_switches.h"
 
 #if BUILDFLAG(ENABLE_SUPERVISED_USERS)
+#include "chrome/browser/supervised_user/logged_in_user_mixin.h"
 #include "chrome/browser/supervised_user/supervised_user_constants.h"
 
 #if defined(OS_CHROMEOS)
@@ -375,23 +376,97 @@
 class ExtensionWebstorePrivateApiTestChild
     : public ExtensionWebstorePrivateApiTest {
  public:
-  void SetUpCommandLine(base::CommandLine* command_line) override {
-    ExtensionWebstorePrivateApiTest::SetUpCommandLine(command_line);
-    command_line->AppendSwitchASCII(switches::kSupervisedUserId,
-                                    supervised_users::kChildAccountSUID);
-#if defined(OS_CHROMEOS)
-    command_line->AppendSwitchASCII(
-        chromeos::switches::kLoginUser,
-        "supervised_user@locally-managed.localhost");
-    command_line->AppendSwitchASCII(chromeos::switches::kLoginProfile, "hash");
-#endif
+  ExtensionWebstorePrivateApiTestChild()
+      : embedded_test_server_(std::make_unique<net::EmbeddedTestServer>()),
+        logged_in_user_mixin_(&mixin_host_,
+                              chromeos::LoggedInUserMixin::LogInType::kChild,
+                              embedded_test_server_.get()) {
+    // Suppress regular user login to enable child user login.
+    set_chromeos_user_ = false;
+    // Launch a browser instance after logging in.
+    logged_in_user_mixin_.set_should_launch_browser(true);
   }
+
+  void SetUp() override {
+    mixin_host_.SetUp();
+    ExtensionWebstorePrivateApiTest::SetUp();
+  }
+
+  void SetUpCommandLine(base::CommandLine* command_line) override {
+    mixin_host_.SetUpCommandLine(command_line);
+    ExtensionWebstorePrivateApiTest::SetUpCommandLine(command_line);
+    // Shortens the merge session timeout from 20 to 1 seconds to speed up the
+    // test by about 19 seconds.
+    // TODO (crbug.com/995575): figure out why this switch speeds up the test,
+    // and fix the test setup so this is not required.
+    command_line->AppendSwitch(switches::kShortMergeSessionTimeoutForTest);
+  }
+
+  void SetUpDefaultCommandLine(base::CommandLine* command_line) override {
+    mixin_host_.SetUpDefaultCommandLine(command_line);
+    ExtensionWebstorePrivateApiTest::SetUpDefaultCommandLine(command_line);
+  }
+
+  bool SetUpUserDataDirectory() override {
+    return mixin_host_.SetUpUserDataDirectory() &&
+           ExtensionWebstorePrivateApiTest::SetUpUserDataDirectory();
+  }
+
+  void SetUpInProcessBrowserTestFixture() override {
+    mixin_host_.SetUpInProcessBrowserTestFixture();
+    ExtensionWebstorePrivateApiTest::SetUpInProcessBrowserTestFixture();
+  }
+
+  void CreatedBrowserMainParts(
+      content::BrowserMainParts* browser_main_parts) override {
+    mixin_host_.CreatedBrowserMainParts(browser_main_parts);
+    ExtensionWebstorePrivateApiTest::CreatedBrowserMainParts(
+        browser_main_parts);
+  }
+
+  void SetUpOnMainThread() override {
+    mixin_host_.SetUpOnMainThread();
+    ExtensionWebstorePrivateApiTest::SetUpOnMainThread();
+    // Needed for resolving FakeGaiaMixin token requests.
+    // Otherwise the test times out.
+    host_resolver()->AddRule("*", "127.0.0.1");
+    logged_in_user_mixin_.LogInUser(true /* issue_any_scope_token */);
+    // Set the private |browser_| member in InProcessBrowserTest.
+    // Otherwise calls to InProcessBrowserTest::browser() returns null and leads
+    // to segmentation faults.
+    SelectFirstBrowser();
+  }
+
+  void TearDownOnMainThread() override {
+    mixin_host_.TearDownOnMainThread();
+    ExtensionWebstorePrivateApiTest::TearDownOnMainThread();
+  }
+
+  void TearDownInProcessBrowserTestFixture() override {
+    mixin_host_.TearDownInProcessBrowserTestFixture();
+    ExtensionWebstorePrivateApiTest::TearDownInProcessBrowserTestFixture();
+  }
+
+  void TearDown() override {
+    mixin_host_.TearDown();
+    ExtensionWebstorePrivateApiTest::TearDown();
+  }
+
+ private:
+  // Replicate what MixinBasedInProcessBrowserTest does since inheriting from
+  // that class is inconvenient here.
+  InProcessBrowserTestMixinHost mixin_host_;
+  // Create another embedded test server to avoid starting the same one twice.
+  std::unique_ptr<net::EmbeddedTestServer> embedded_test_server_;
+
+  chromeos::LoggedInUserMixin logged_in_user_mixin_;
 };
 
 // Tests that extension installation is blocked for child accounts, and
 // attempting to do so produces a special error code.
 // Note: This will have to be updated when we enable child-initiated installs.
 IN_PROC_BROWSER_TEST_F(ExtensionWebstorePrivateApiTestChild, InstallBlocked) {
+  ASSERT_TRUE(browser());
   ASSERT_TRUE(RunInstallTest("begin_install_fail_child.html", "extension.crx"));
 }
 
diff --git a/chrome/browser/flag-metadata.json b/chrome/browser/flag-metadata.json
index 3aa3e4e..37d0215 100644
--- a/chrome/browser/flag-metadata.json
+++ b/chrome/browser/flag-metadata.json
@@ -1018,6 +1018,11 @@
     "expiry_milestone": 79
   },
   {
+    "name": "enable-close-tab-suggestions-stale",
+    "owners": [ "memex-team@google.com" ],
+    "expiry_milestone": 82
+  },
+  {
     "name": "enable-cloud-print-xps",
     "owners": [ "//printing/OWNERS" ],
     "expiry_milestone": 76
@@ -1279,7 +1284,7 @@
   {
     "name": "enable-implicit-root-scroller",
     "owners": [ "bokan", "input-dev" ],
-    "expiry_milestone": 75
+    "expiry_milestone": 80
   },
   {
     "name": "enable-incognito-window-counter",
@@ -1736,7 +1741,7 @@
   {
     "name": "enable-text-fragment-anchor",
     "owners": [ "bokan", "input-dev" ],
-    "expiry_milestone": 77
+    "expiry_milestone": 80
   },
   {
     "name": "enable-tls13-early-data",
@@ -3077,9 +3082,9 @@
     "expiry_milestone": 81
   },
   {
-    "name": "temporary-unexpire-flags-m78",
+    "name": "temporary-unexpire-flags-m76",
     "owners": [ "ellyjones", "flags-dev" ],
-    "expiry_milestone": 81
+    "expiry_milestone": 80
   },
   {
     "name": "terminal-system-app",
diff --git a/chrome/browser/flag_descriptions.cc b/chrome/browser/flag_descriptions.cc
index f0009590..adae9fa1 100644
--- a/chrome/browser/flag_descriptions.cc
+++ b/chrome/browser/flag_descriptions.cc
@@ -1982,9 +1982,9 @@
     "Insecure origins treated as secure";
 const char kTreatInsecureOriginAsSecureDescription[] =
     "Treat given (insecure) origins as secure origins. Multiple origins can be "
-    "supplied as a comma-separated list. For the definition of secure "
-    "contexts, "
-    "see https://w3c.github.io/webappsec-secure-contexts/";
+    "supplied as a comma-separated list. Origins must have their protocol "
+    "specified e.g. \"http://example.com\". For the definition of secure "
+    "contexts, see https://w3c.github.io/webappsec-secure-contexts/";
 
 const char kTreatUnsafeDownloadsAsActiveName[] =
     "Treat risky downloads over insecure connections as active mixed content";
@@ -2008,9 +2008,9 @@
     "Reduces disk activity during media playback, which can result in "
     "power savings.";
 
-const char kUnexpireFlagsM78Name[] = "Temporarily unexpire M78 flags.";
-const char kUnexpireFlagsM78Description[] =
-    "Temporarily unexpire flags that are expired as of M78. These flags will "
+const char kUnexpireFlagsM76Name[] = "Temporarily unexpire M76 flags.";
+const char kUnexpireFlagsM76Description[] =
+    "Temporarily unexpire flags that are expired as of M76. These flags will "
     "be removed soon.";
 
 const char kUnifiedConsentName[] = "Unified Consent";
@@ -2284,6 +2284,10 @@
 const char kClickToCallOpenDialerDirectlyDescription[] =
     "Enables opening the dialer directly instead of displaying a notification. "
     "Only available on Android P- and when the screen is on and unlocked.";
+const char kCloseTabSuggestionsStaleName[] = "Suggest to close stale Tabs";
+const char kCloseTabSuggestionsStaleDescription[] =
+    "Suggests to the user to close Tabs that have not been used above a "
+    "threshold such as 1 day. The threshold is configurable.";
 
 const char kClickToCallReceiverName[] =
     "Enable receiver device to handle click to call feature";
diff --git a/chrome/browser/flag_descriptions.h b/chrome/browser/flag_descriptions.h
index 8304670..8f5262a 100644
--- a/chrome/browser/flag_descriptions.h
+++ b/chrome/browser/flag_descriptions.h
@@ -1195,8 +1195,8 @@
 extern const char kTurnOffStreamingMediaCachingName[];
 extern const char kTurnOffStreamingMediaCachingDescription[];
 
-extern const char kUnexpireFlagsM78Name[];
-extern const char kUnexpireFlagsM78Description[];
+extern const char kUnexpireFlagsM76Name[];
+extern const char kUnexpireFlagsM76Description[];
 
 extern const char kUnifiedConsentName[];
 extern const char kUnifiedConsentDescription[];
@@ -1361,6 +1361,9 @@
 extern const char kClickToCallOpenDialerDirectlyName[];
 extern const char kClickToCallOpenDialerDirectlyDescription[];
 
+extern const char kCloseTabSuggestionsStaleName[];
+extern const char kCloseTabSuggestionsStaleDescription[];
+
 extern const char kClickToCallReceiverName[];
 extern const char kClickToCallReceiverDescription[];
 
diff --git a/chrome/browser/media/encrypted_media_browsertest.cc b/chrome/browser/media/encrypted_media_browsertest.cc
index c3f12f0..8d1be4a 100644
--- a/chrome/browser/media/encrypted_media_browsertest.cc
+++ b/chrome/browser/media/encrypted_media_browsertest.cc
@@ -829,7 +829,8 @@
                        kEmeSessionClosedAndError);
 }
 
-IN_PROC_BROWSER_TEST_P(ECKEncryptedMediaTest, FileIOTest) {
+// Flaky: crbug.com/997953
+IN_PROC_BROWSER_TEST_P(ECKEncryptedMediaTest, DISABLED_FileIOTest) {
   TestNonPlaybackCases(kExternalClearKeyFileIOTestKeySystem, kUnitTestSuccess);
 }
 
diff --git a/chrome/browser/picture_in_picture/DEPS b/chrome/browser/picture_in_picture/DEPS
index 8e81e30..3196882 100644
--- a/chrome/browser/picture_in_picture/DEPS
+++ b/chrome/browser/picture_in_picture/DEPS
@@ -1,6 +1,5 @@
 specific_include_rules = {
   "picture_in_picture_window_controller_browsertest\.cc": [
-    "+chrome/browser/ui/views/overlay/mute_image_button.h",
     "+chrome/browser/ui/views/overlay/overlay_window_views.h",
     "+chrome/browser/ui/views/overlay/playback_image_button.h",
     "+chrome/browser/ui/views/overlay/skip_ad_label_button.h",
diff --git a/chrome/browser/picture_in_picture/picture_in_picture_window_controller_browsertest.cc b/chrome/browser/picture_in_picture/picture_in_picture_window_controller_browsertest.cc
index b520626..44776b9e 100644
--- a/chrome/browser/picture_in_picture/picture_in_picture_window_controller_browsertest.cc
+++ b/chrome/browser/picture_in_picture/picture_in_picture_window_controller_browsertest.cc
@@ -18,7 +18,6 @@
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/browser_commands.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
-#include "chrome/browser/ui/views/overlay/mute_image_button.h"
 #include "chrome/browser/ui/views/overlay/overlay_window_views.h"
 #include "chrome/browser/ui/views/overlay/playback_image_button.h"
 #include "chrome/browser/ui/views/overlay/skip_ad_label_button.h"
@@ -76,14 +75,10 @@
   MOCK_METHOD0(GetWindowForTesting, content::OverlayWindow*());
   MOCK_METHOD0(UpdateLayerBounds, void());
   MOCK_METHOD0(IsPlayerActive, bool());
-  MOCK_METHOD0(IsPlayerMuted, bool());
   MOCK_METHOD0(GetInitiatorWebContents, content::WebContents*());
   MOCK_METHOD2(UpdatePlaybackState, void(bool, bool));
-  MOCK_METHOD0(UpdateMutedState, void());
   MOCK_METHOD0(TogglePlayPause, bool());
-  MOCK_METHOD0(ToggleMute, bool());
   MOCK_METHOD1(SetAlwaysHidePlayPauseButton, void(bool));
-  MOCK_METHOD1(SetAlwaysHideMuteButton, void(bool));
   MOCK_METHOD0(SkipAd, void());
   MOCK_METHOD0(NextTrack, void());
   MOCK_METHOD0(PreviousTrack, void());
@@ -1674,7 +1669,7 @@
   EXPECT_FALSE(is_paused);
 }
 
-// Tests that the back-to-tab, close, mute and resize controls move properly as
+// Tests that the back-to-tab, close, and resize controls move properly as
 // the window changes quadrants.
 IN_PROC_BROWSER_TEST_F(PictureInPictureWindowControllerBrowserTest,
                        MovingQuadrantsMovesBackToTabAndResizeControls) {
@@ -2934,198 +2929,6 @@
                 .WaitAndGetTitle());
 }
 
-class MuteButtonPictureInPictureWindowControllerBrowserTest
-    : public PictureInPictureWindowControllerBrowserTest {
- public:
-  void SetUpCommandLine(base::CommandLine* command_line) override {
-    PictureInPictureWindowControllerBrowserTest::SetUpCommandLine(command_line);
-    command_line->AppendSwitchASCII("enable-blink-features", "MuteButton");
-  }
-};
-
-// Tests the mute button and its state in the Picture-in-Picture window when
-// experimental feature MuteButton is enabled.
-IN_PROC_BROWSER_TEST_F(MuteButtonPictureInPictureWindowControllerBrowserTest,
-                       MuteButtonEnabled) {
-  LoadTabAndEnterPictureInPicture(
-      browser(), base::FilePath(kPictureInPictureWindowSizePage));
-
-  OverlayWindowViews* overlay_window = static_cast<OverlayWindowViews*>(
-      window_controller()->GetWindowForTesting());
-  EXPECT_EQ(overlay_window->muted_state_for_testing(),
-            OverlayWindowViews::MutedState::kUnmuted);
-
-  content::WebContents* active_web_contents =
-      browser()->tab_strip_model()->GetActiveWebContents();
-
-  // Play video-only mediastream.
-  bool result = false;
-  ASSERT_TRUE(content::ExecuteScriptAndExtractBool(
-      active_web_contents, "changeVideoSrcToMediaStream();", &result));
-  EXPECT_TRUE(result);
-  base::RunLoop().RunUntilIdle();
-  EXPECT_EQ(overlay_window->muted_state_for_testing(),
-            OverlayWindowViews::MutedState::kNoAudio);
-
-  // Play back video.
-  ASSERT_TRUE(content::ExecuteScriptAndExtractBool(
-      active_web_contents, "changeVideoSrc();", &result));
-  EXPECT_TRUE(result);
-  base::RunLoop().RunUntilIdle();
-  EXPECT_EQ(overlay_window->muted_state_for_testing(),
-            OverlayWindowViews::MutedState::kUnmuted);
-
-  // Play no-audio track video.
-  ASSERT_TRUE(content::ExecuteScriptAndExtractBool(
-      active_web_contents, "changeVideoSrcToNoAudioTrackVideo();", &result));
-  EXPECT_TRUE(result);
-  base::RunLoop().RunUntilIdle();
-  EXPECT_EQ(overlay_window->muted_state_for_testing(),
-            OverlayWindowViews::MutedState::kNoAudio);
-
-  // Play back video.
-  ASSERT_TRUE(content::ExecuteScriptAndExtractBool(
-      active_web_contents, "changeVideoSrc();", &result));
-  EXPECT_TRUE(result);
-  base::RunLoop().RunUntilIdle();
-  EXPECT_EQ(overlay_window->muted_state_for_testing(),
-            OverlayWindowViews::MutedState::kUnmuted);
-
-  // Mute second video and enter Picture-in-Picture for second video.
-  EXPECT_TRUE(
-      content::ExecuteScript(active_web_contents, "secondVideo.muted = true;"));
-  ASSERT_TRUE(
-      content::ExecuteScript(active_web_contents, "secondPictureInPicture();"));
-  base::string16 expected_title = base::ASCIIToUTF16("leavepictureinpicture");
-  EXPECT_EQ(expected_title,
-            content::TitleWatcher(active_web_contents, expected_title)
-                .WaitAndGetTitle());
-  base::RunLoop().RunUntilIdle();
-  EXPECT_EQ(overlay_window->muted_state_for_testing(),
-            OverlayWindowViews::MutedState::kMuted);
-
-  // Re-enter Picture-in-Picture for first video.
-  ASSERT_TRUE(content::ExecuteScriptAndExtractBool(
-      active_web_contents, "enterPictureInPicture();", &result));
-  EXPECT_TRUE(result);
-  base::RunLoop().RunUntilIdle();
-  EXPECT_EQ(overlay_window->muted_state_for_testing(),
-            OverlayWindowViews::MutedState::kUnmuted);
-
-  // Mute video from website.
-  EXPECT_TRUE(
-      content::ExecuteScript(active_web_contents, "video.muted = true;"));
-  base::RunLoop().RunUntilIdle();
-  EXPECT_EQ(overlay_window->muted_state_for_testing(),
-            OverlayWindowViews::MutedState::kMuted);
-
-  // Unmute video from website.
-  EXPECT_TRUE(
-      content::ExecuteScript(active_web_contents, "video.muted = false;"));
-  base::RunLoop().RunUntilIdle();
-  EXPECT_EQ(overlay_window->muted_state_for_testing(),
-            OverlayWindowViews::MutedState::kUnmuted);
-
-  ASSERT_TRUE(content::ExecuteScript(active_web_contents,
-                                     "addVolumeChangeEventListener();"));
-
-  // Simulates user clicking mute button.
-  window_controller()->ToggleMute();
-  expected_title = base::ASCIIToUTF16("muted: true");
-  EXPECT_EQ(expected_title,
-            content::TitleWatcher(active_web_contents, expected_title)
-                .WaitAndGetTitle());
-  base::RunLoop().RunUntilIdle();
-  EXPECT_EQ(overlay_window->muted_state_for_testing(),
-            OverlayWindowViews::MutedState::kMuted);
-
-  // Simulates user clicking unmute button.
-  window_controller()->ToggleMute();
-  expected_title = base::ASCIIToUTF16("muted: false");
-  EXPECT_EQ(expected_title,
-            content::TitleWatcher(active_web_contents, expected_title)
-                .WaitAndGetTitle());
-  base::RunLoop().RunUntilIdle();
-  EXPECT_EQ(overlay_window->muted_state_for_testing(),
-            OverlayWindowViews::MutedState::kUnmuted);
-
-  // Umute second video and enter Picture-in-Picture for second video.
-  EXPECT_TRUE(content::ExecuteScript(active_web_contents,
-                                     "secondVideo.muted = false;"));
-  ASSERT_TRUE(
-      content::ExecuteScript(active_web_contents, "secondPictureInPicture();"));
-  expected_title = base::ASCIIToUTF16("leavepictureinpicture");
-  EXPECT_EQ(expected_title,
-            content::TitleWatcher(active_web_contents, expected_title)
-                .WaitAndGetTitle());
-  base::RunLoop().RunUntilIdle();
-  EXPECT_EQ(overlay_window->muted_state_for_testing(),
-            OverlayWindowViews::MutedState::kUnmuted);
-}
-
-// Tests the mute button and its state in the Picture-in-Picture window when
-// experimental feature MuteButton is disabled.
-IN_PROC_BROWSER_TEST_F(PictureInPictureWindowControllerBrowserTest,
-                       MuteButtonDisabled) {
-  LoadTabAndEnterPictureInPicture(
-      browser(), base::FilePath(kPictureInPictureWindowSizePage));
-
-  OverlayWindowViews* overlay_window = static_cast<OverlayWindowViews*>(
-      window_controller()->GetWindowForTesting());
-  EXPECT_EQ(overlay_window->muted_state_for_testing(),
-            OverlayWindowViews::MutedState::kNoAudio);
-
-  content::WebContents* active_web_contents =
-      browser()->tab_strip_model()->GetActiveWebContents();
-
-  // Play video-only mediastream.
-  bool result = false;
-  ASSERT_TRUE(content::ExecuteScriptAndExtractBool(
-      active_web_contents, "changeVideoSrcToMediaStream();", &result));
-  EXPECT_TRUE(result);
-  base::RunLoop().RunUntilIdle();
-  EXPECT_EQ(overlay_window->muted_state_for_testing(),
-            OverlayWindowViews::MutedState::kNoAudio);
-
-  // Play back video.
-  ASSERT_TRUE(content::ExecuteScriptAndExtractBool(
-      active_web_contents, "changeVideoSrc();", &result));
-  EXPECT_TRUE(result);
-  base::RunLoop().RunUntilIdle();
-  EXPECT_EQ(overlay_window->muted_state_for_testing(),
-            OverlayWindowViews::MutedState::kNoAudio);
-
-  // Play no-audio track video.
-  ASSERT_TRUE(content::ExecuteScriptAndExtractBool(
-      active_web_contents, "changeVideoSrcToNoAudioTrackVideo();", &result));
-  EXPECT_TRUE(result);
-  base::RunLoop().RunUntilIdle();
-  EXPECT_EQ(overlay_window->muted_state_for_testing(),
-            OverlayWindowViews::MutedState::kNoAudio);
-
-  // Play back video.
-  ASSERT_TRUE(content::ExecuteScriptAndExtractBool(
-      active_web_contents, "changeVideoSrc();", &result));
-  EXPECT_TRUE(result);
-  base::RunLoop().RunUntilIdle();
-  EXPECT_EQ(overlay_window->muted_state_for_testing(),
-            OverlayWindowViews::MutedState::kNoAudio);
-
-  // Mute video from website.
-  EXPECT_TRUE(
-      content::ExecuteScript(active_web_contents, "video.muted = true;"));
-  base::RunLoop().RunUntilIdle();
-  EXPECT_EQ(overlay_window->muted_state_for_testing(),
-            OverlayWindowViews::MutedState::kNoAudio);
-
-  // Unmute video from website.
-  EXPECT_TRUE(
-      content::ExecuteScript(active_web_contents, "video.muted = false;"));
-  base::RunLoop().RunUntilIdle();
-  EXPECT_EQ(overlay_window->muted_state_for_testing(),
-            OverlayWindowViews::MutedState::kNoAudio);
-}
-
 // Tests that when closing the window after the player was reset, the <video>
 // element is still notified.
 IN_PROC_BROWSER_TEST_F(PictureInPictureWindowControllerBrowserTest,
diff --git a/chrome/browser/predictors/predictor_database.cc b/chrome/browser/predictors/predictor_database.cc
index 8e9072b..7c3b48d 100644
--- a/chrome/browser/predictors/predictor_database.cc
+++ b/chrome/browser/predictors/predictor_database.cc
@@ -103,6 +103,7 @@
   }
 
   bool success = db_->Open(db_path_);
+  db_->Preload();
 
   if (!success)
     return;
diff --git a/chrome/browser/previews/defer_all_script_browsertest.cc b/chrome/browser/previews/defer_all_script_browsertest.cc
index 70f7c53..fe49f68a 100644
--- a/chrome/browser/previews/defer_all_script_browsertest.cc
+++ b/chrome/browser/previews/defer_all_script_browsertest.cc
@@ -312,8 +312,6 @@
                                       true);
 }
 
-// Disable flake on Linux too (via only Android) until crbug/997697 resolved.
-#if defined(OS_ANDROID)
 IN_PROC_BROWSER_TEST_F(
     DeferAllScriptBrowserTest,
     DISABLE_ON_WIN_MAC_CHROMESOS(DeferAllScriptClientRedirectLoopStopped)) {
@@ -333,8 +331,8 @@
   ui_test_utils::NavigateToURL(browser(), client_redirect_url());
 
   RetryForHistogramUntilCountReached(
-      &histogram_tester, "PageLoad.DocumentTiming.NavigationToLoadEventFired",
-      1);
+      &histogram_tester, "Navigation.ClientRedirectCycle.RedirectToReferrer",
+      2);
 
   // Client redirect loop is broken on 2nd pass around the loop so expect 3
   // previews before previews turned off to stop loop.
@@ -342,4 +340,3 @@
       "Navigation.ClientRedirectCycle.RedirectToReferrer", 2);
   histogram_tester.ExpectTotalCount("Previews.PageEndReason.DeferAllScript", 3);
 }
-#endif  // defined(OS_ANDROID)
diff --git a/chrome/browser/resources/local_ntp/customize.js b/chrome/browser/resources/local_ntp/customize.js
index b08315b..3e0beb3f 100644
--- a/chrome/browser/resources/local_ntp/customize.js
+++ b/chrome/browser/resources/local_ntp/customize.js
@@ -2279,6 +2279,7 @@
       } else {
         $(customize.IDS.COLORS_DEFAULT_ICON).focus();
       }
+      event.preventDefault();
     }
   };
 
diff --git a/chrome/browser/resources/settings/controls/pref_control_behavior.js b/chrome/browser/resources/settings/controls/pref_control_behavior.js
index 51bbe01..8db2d75d 100644
--- a/chrome/browser/resources/settings/controls/pref_control_behavior.js
+++ b/chrome/browser/resources/settings/controls/pref_control_behavior.js
@@ -37,6 +37,10 @@
         }
         error += ' in ' + this.domHost.tagName;
         console.error(error);
+      } else if (
+          this.pref.enforcement ==
+          chrome.settingsPrivate.Enforcement.PARENT_SUPERVISED) {
+        console.error('PARENT_SUPERVISED is not enforced by pref controls');
       }
     });
   },
diff --git a/chrome/browser/resources/settings/date_time_page/date_time_page.html b/chrome/browser/resources/settings/date_time_page/date_time_page.html
index 735549d..1575327 100644
--- a/chrome/browser/resources/settings/date_time_page/date_time_page.html
+++ b/chrome/browser/resources/settings/date_time_page/date_time_page.html
@@ -65,7 +65,11 @@
         </settings-toggle-button>
         <cr-link-row class="hr" id="setDateTime"
             on-click="onSetDateTimeTap_" hidden$="[[!canSetDateTime_]]"
-            label="$i18n{setDateTime}"></cr-link-row>
+            label="$i18n{setDateTime}">
+          <template is="dom-if" if="[[displayManagedByParentIcon_]]">
+            <cr-policy-indicator indicator-type="parent"></cr-policy-indicator>
+          </template>
+        </cr-link-row>
       </div>
       <template is="dom-if" route-path="/dateTime/timeZone">
         <settings-subpage data-route="DATETIME_TIMEZONE_SUBPAGE"
diff --git a/chrome/browser/resources/settings/date_time_page/date_time_page.js b/chrome/browser/resources/settings/date_time_page/date_time_page.js
index 186c536e..f5f8a8f 100644
--- a/chrome/browser/resources/settings/date_time_page/date_time_page.js
+++ b/chrome/browser/resources/settings/date_time_page/date_time_page.js
@@ -58,6 +58,17 @@
 
     /** @private */
     isChild_: {type: Boolean, value: loadTimeData.getBoolean('isChild')},
+
+    /**
+     * Whether the icon informing that this action is managed by a parent is
+     * displayed.
+     * @private
+     */
+    displayManagedByParentIcon_: {
+      type: Boolean,
+      value: loadTimeData.getBoolean('isChild') &&
+          loadTimeData.getBoolean('timeActionsProtectedForChild')
+    },
   },
 
   /** @override */
diff --git a/chrome/browser/resources/settings/internet_page/BUILD.gn b/chrome/browser/resources/settings/internet_page/BUILD.gn
index ed2f559..0dde307 100644
--- a/chrome/browser/resources/settings/internet_page/BUILD.gn
+++ b/chrome/browser/resources/settings/internet_page/BUILD.gn
@@ -68,7 +68,7 @@
     "..:route",
     "//ui/webui/resources/cr_elements/chromeos/network:cr_network_listener_behavior",
     "//ui/webui/resources/cr_elements/chromeos/network:cr_onc_types",
-    "//ui/webui/resources/cr_elements/policy:cr_policy_network_behavior",
+    "//ui/webui/resources/cr_elements/policy:cr_policy_network_behavior_mojo",
     "//ui/webui/resources/js:assert",
     "//ui/webui/resources/js:i18n_behavior",
   ]
@@ -96,7 +96,7 @@
     ":internet_page_browser_proxy",
     "..:route",
     "//ui/webui/resources/cr_elements/chromeos/network:cr_network_listener_behavior",
-    "//ui/webui/resources/cr_elements/policy:cr_policy_network_behavior",
+    "//ui/webui/resources/cr_elements/policy:cr_policy_network_behavior_mojo",
     "//ui/webui/resources/js:assert",
     "//ui/webui/resources/js:i18n_behavior",
     "//ui/webui/resources/js/chromeos:onc_mojo",
@@ -123,7 +123,6 @@
   deps = [
     "//ui/webui/resources/cr_elements/chromeos/network:cr_network_listener_behavior",
     "//ui/webui/resources/cr_elements/chromeos/network:cr_onc_types",
-    "//ui/webui/resources/cr_elements/policy:cr_policy_network_behavior",
     "//ui/webui/resources/js:assert",
     "//ui/webui/resources/js/chromeos:onc_mojo",
   ]
@@ -133,7 +132,7 @@
 js_library("network_summary_item") {
   deps = [
     "//ui/webui/resources/cr_elements/chromeos/network:cr_onc_types",
-    "//ui/webui/resources/cr_elements/policy:cr_policy_network_behavior",
+    "//ui/webui/resources/cr_elements/policy:cr_policy_network_behavior_mojo",
     "//ui/webui/resources/js:assert",
     "//ui/webui/resources/js:i18n_behavior",
     "//ui/webui/resources/js/chromeos:onc_mojo",
diff --git a/chrome/browser/resources/settings/internet_page/internet_known_networks_page.html b/chrome/browser/resources/settings/internet_page/internet_known_networks_page.html
index ccac30a..b0d29715 100644
--- a/chrome/browser/resources/settings/internet_page/internet_known_networks_page.html
+++ b/chrome/browser/resources/settings/internet_page/internet_known_networks_page.html
@@ -36,7 +36,7 @@
         <div class="list-item">
           <cr-link-row embedded label="[[getNetworkDisplayName_(item)]]"
               on-click="fireShowDetails_">
-            <template is="dom-if" if="[[isPolicySourceMojo(item.source))]]">
+            <template is="dom-if" if="[[isPolicySource(item.source))]]">
               <cr-policy-indicator on-click="doNothing_"
                   indicator-type="[[getIndicatorTypeForSource(item.source)]]">
               </cr-policy-indicator>
@@ -60,7 +60,7 @@
         <div class="list-item">
           <cr-link-row embedded label="[[getNetworkDisplayName_(item)]]"
               on-click="fireShowDetails_">
-            <template is="dom-if" if="[[isPolicySourceMojo(item.source))]]">
+            <template is="dom-if" if="[[isPolicySource(item.source))]]">
               <cr-policy-indicator on-click="doNothing_"
                   indicator-type="[[getIndicatorTypeForSource(item.source)]]">
               </cr-policy-indicator>
diff --git a/chrome/browser/resources/settings/internet_page/internet_subpage.html b/chrome/browser/resources/settings/internet_page/internet_subpage.html
index dae41691..2f61b3f 100644
--- a/chrome/browser/resources/settings/internet_page/internet_subpage.html
+++ b/chrome/browser/resources/settings/internet_page/internet_subpage.html
@@ -5,6 +5,7 @@
 <link rel="import" href="chrome://resources/cr_elements/cr_icon_button/cr_icon_button.html">
 <link rel="import" href="chrome://resources/cr_elements/cr_link_row/cr_link_row.html">
 <link rel="import" href="chrome://resources/cr_elements/cr_toggle/cr_toggle.html">
+<link rel="import" href="chrome://resources/cr_elements/policy/cr_policy_network_behavior_mojo.html">
 <link rel="import" href="chrome://resources/cr_elements/shared_vars_css.html">
 <link rel="import" href="chrome://resources/html/chromeos/onc_mojo.html">
 <link rel="import" href="chrome://resources/html/i18n_behavior.html">
diff --git a/chrome/browser/resources/settings/internet_page/internet_subpage.js b/chrome/browser/resources/settings/internet_page/internet_subpage.js
index 2ff0dc08..c5ad6a0 100644
--- a/chrome/browser/resources/settings/internet_page/internet_subpage.js
+++ b/chrome/browser/resources/settings/internet_page/internet_subpage.js
@@ -16,7 +16,7 @@
 
   behaviors: [
     CrNetworkListenerBehavior,
-    CrPolicyNetworkBehavior,
+    CrPolicyNetworkBehaviorMojo,
     settings.RouteObserverBehavior,
     I18nBehavior,
   ],
@@ -577,7 +577,7 @@
    */
   isBlockedByPolicy_: function(state) {
     if (state.type != mojom.NetworkType.kWiFi ||
-        this.isPolicySourceMojo(state.source) || !this.globalPolicy) {
+        this.isPolicySource(state.source) || !this.globalPolicy) {
       return false;
     }
     return !!this.globalPolicy.AllowOnlyPolicyNetworksToConnect ||
diff --git a/chrome/browser/resources/settings/internet_page/network_summary.html b/chrome/browser/resources/settings/internet_page/network_summary.html
index 1dfcd0b..2ceba97 100644
--- a/chrome/browser/resources/settings/internet_page/network_summary.html
+++ b/chrome/browser/resources/settings/internet_page/network_summary.html
@@ -1,7 +1,6 @@
 <link rel="import" href="chrome://resources/html/polymer.html">
 
 <link rel="import" href="chrome://resources/cr_elements/chromeos/network/cr_network_listener_behavior.html">
-<link rel="import" href="chrome://resources/cr_elements/policy/cr_policy_network_behavior.html">
 <link rel="import" href="chrome://resources/html/chromeos/onc_mojo.html">
 <link rel="import" href="network_summary_item.html">
 
diff --git a/chrome/browser/resources/settings/internet_page/network_summary.js b/chrome/browser/resources/settings/internet_page/network_summary.js
index d8a2a016..67ed004 100644
--- a/chrome/browser/resources/settings/internet_page/network_summary.js
+++ b/chrome/browser/resources/settings/internet_page/network_summary.js
@@ -16,7 +16,6 @@
 
   behaviors: [
     CrNetworkListenerBehavior,
-    CrPolicyNetworkBehavior,
   ],
 
   properties: {
diff --git a/chrome/browser/resources/settings/internet_page/network_summary_item.html b/chrome/browser/resources/settings/internet_page/network_summary_item.html
index 3574931d..5b26c96 100644
--- a/chrome/browser/resources/settings/internet_page/network_summary_item.html
+++ b/chrome/browser/resources/settings/internet_page/network_summary_item.html
@@ -6,6 +6,7 @@
 <link rel="import" href="chrome://resources/cr_elements/cr_icon_button/cr_icon_button.html">
 <link rel="import" href="chrome://resources/cr_elements/cr_toggle/cr_toggle.html">
 <link rel="import" href="chrome://resources/cr_elements/policy/cr_policy_indicator.html">
+<link rel="import" href="chrome://resources/cr_elements/policy/cr_policy_network_behavior_mojo.html">
 <link rel="import" href="chrome://resources/cr_elements/shared_vars_css.html">
 <link rel="import" href="chrome://resources/html/chromeos/onc_mojo.html">
 <link rel="import" href="chrome://resources/html/i18n_behavior.html">
@@ -59,7 +60,7 @@
         </template>
 
         <template is="dom-if" if="[[showPolicyIndicator_(activeNetworkState)]]">
-          <cr-policy-indicator indicator-type="[[getIndicatorTypeForSourceMojo(
+          <cr-policy-indicator indicator-type="[[getIndicatorTypeForSource(
               activeNetworkState.source)]]" on-click="doNothing_">
           </cr-policy-indicator>
         </template>
diff --git a/chrome/browser/resources/settings/internet_page/network_summary_item.js b/chrome/browser/resources/settings/internet_page/network_summary_item.js
index 8f37d8dc..12ba1e3 100644
--- a/chrome/browser/resources/settings/internet_page/network_summary_item.js
+++ b/chrome/browser/resources/settings/internet_page/network_summary_item.js
@@ -16,7 +16,10 @@
 Polymer({
   is: 'network-summary-item',
 
-  behaviors: [CrPolicyNetworkBehavior, I18nBehavior],
+  behaviors: [
+    CrPolicyNetworkBehaviorMojo,
+    I18nBehavior,
+  ],
 
   properties: {
     /**
@@ -153,7 +156,7 @@
     return (activeNetworkState !== undefined &&
             OncMojo.connectionStateIsConnected(
                 activeNetworkState.connectionState)) ||
-        this.isPolicySourceMojo(activeNetworkState.source);
+        this.isPolicySource(activeNetworkState.source);
   },
 
   /**
diff --git a/chrome/browser/resources/settings/people_page/lock_screen.html b/chrome/browser/resources/settings/people_page/lock_screen.html
index a16743f6..56fa177 100644
--- a/chrome/browser/resources/settings/people_page/lock_screen.html
+++ b/chrome/browser/resources/settings/people_page/lock_screen.html
@@ -66,12 +66,6 @@
           label="$i18n{enableScreenlock}">
       </settings-toggle-button>
 
-      <settings-toggle-button id="enableLockScreenMediaControls"
-          hidden="[[!lockScreenMediaControlsPreferenceEnabled_]]"
-          pref="{{prefs.ash.lock_screen_media_controls_enabled}}"
-          label="$i18n{lockScreenMediaControls}">
-      </settings-toggle-button>
-
       <template is="dom-if" if="[[quickUnlockEnabled_]]">
         <div id="lockOptionsDiv">
           <div class="settings-box">
diff --git a/chrome/browser/resources/settings/people_page/lock_screen.js b/chrome/browser/resources/settings/people_page/lock_screen.js
index b2f7116ce..f0584fe 100644
--- a/chrome/browser/resources/settings/people_page/lock_screen.js
+++ b/chrome/browser/resources/settings/people_page/lock_screen.js
@@ -130,19 +130,6 @@
       readOnly: true,
     },
 
-    /**
-     * Whether the lock screen media controls preference is enabled by the
-     * feature flag.
-     * @private
-     */
-    lockScreenMediaControlsPreferenceEnabled_: {
-      type: Boolean,
-      value: function() {
-        return loadTimeData.getBoolean('lockScreenMediaControlsEnabled');
-      },
-      readOnly: true,
-    },
-
     /** @private */
     showPasswordPromptDialog_: Boolean,
 
diff --git a/chrome/browser/safe_browsing/download_protection/download_item_request.cc b/chrome/browser/safe_browsing/download_protection/download_item_request.cc
index 4690ae19..40b7f26 100644
--- a/chrome/browser/safe_browsing/download_protection/download_item_request.cc
+++ b/chrome/browser/safe_browsing/download_protection/download_item_request.cc
@@ -17,6 +17,9 @@
 
 std::string GetFileContentsBlocking(base::FilePath path) {
   base::File file(path, base::File::FLAG_OPEN | base::File::FLAG_READ);
+  if (!file.IsValid())
+    return "";
+
   int64_t file_size = file.GetLength();
   std::string contents;
   contents.resize(file_size);
@@ -38,7 +41,10 @@
 
 DownloadItemRequest::DownloadItemRequest(download::DownloadItem* item,
                                          BinaryUploadService::Callback callback)
-    : Request(std::move(callback)), item_(item), weakptr_factory_(this) {
+    : Request(std::move(callback)),
+      item_(item),
+      download_item_renamed_(false),
+      weakptr_factory_(this) {
   item_->AddObserver(this);
 }
 
@@ -54,18 +60,38 @@
     return;
   }
 
-  base::PostTaskAndReplyWithResult(
-      FROM_HERE,
-      {base::ThreadPool(), base::TaskPriority::USER_VISIBLE, base::MayBlock()},
-      base::BindOnce(&GetFileContentsBlocking, item_->GetFullPath()),
-      base::BindOnce(&DownloadItemRequest::OnGotFileContents,
-                     weakptr_factory_.GetWeakPtr(), std::move(callback)));
+  pending_callbacks_.push_back(std::move(callback));
+
+  if (download_item_renamed_)
+    RunPendingGetFileContentsCallbacks();
+}
+
+void DownloadItemRequest::RunPendingGetFileContentsCallbacks() {
+  for (auto it = pending_callbacks_.begin(); it != pending_callbacks_.end();
+       it++) {
+    base::PostTaskAndReplyWithResult(
+        FROM_HERE,
+        {base::ThreadPool(), base::TaskPriority::USER_VISIBLE,
+         base::MayBlock()},
+        base::BindOnce(&GetFileContentsBlocking, item_->GetFullPath()),
+        base::BindOnce(&DownloadItemRequest::OnGotFileContents,
+                       weakptr_factory_.GetWeakPtr(), std::move(*it)));
+  }
+
+  pending_callbacks_.clear();
 }
 
 size_t DownloadItemRequest::GetFileSize() {
   return item_ == nullptr ? 0 : item_->GetTotalBytes();
 }
 
+void DownloadItemRequest::OnDownloadUpdated(download::DownloadItem* download) {
+  if (download == item_ && item_->GetFullPath() == item_->GetTargetFilePath()) {
+    download_item_renamed_ = true;
+    RunPendingGetFileContentsCallbacks();
+  }
+}
+
 void DownloadItemRequest::OnDownloadDestroyed(
     download::DownloadItem* download) {
   if (download == item_)
diff --git a/chrome/browser/safe_browsing/download_protection/download_item_request.h b/chrome/browser/safe_browsing/download_protection/download_item_request.h
index 1ff518b..2f28b2e 100644
--- a/chrome/browser/safe_browsing/download_protection/download_item_request.h
+++ b/chrome/browser/safe_browsing/download_protection/download_item_request.h
@@ -33,15 +33,27 @@
 
   // download::DownloadItem::Observer implementation.
   void OnDownloadDestroyed(download::DownloadItem* download) override;
+  void OnDownloadUpdated(download::DownloadItem* download) override;
 
  private:
   void OnGotFileContents(base::OnceCallback<void(const std::string&)> callback,
                          const std::string& contents);
 
+  // Calls to GetFileContents can be deferred if the download item is not yet
+  // renamed to its final location. When ready, this method runs those
+  // callbacks.
+  void RunPendingGetFileContentsCallbacks();
+
   // Pointer the download item for upload. This must be accessed only the UI
-  // thread.
+  // thread. Unowned.
   download::DownloadItem* item_;
 
+  // Whether the download item has been renamed to its final destination yet.
+  bool download_item_renamed_;
+
+  // All pending callbacks to GetFileContents before the download item is ready.
+  std::vector<base::OnceCallback<void(const std::string&)>> pending_callbacks_;
+
   base::WeakPtrFactory<DownloadItemRequest> weakptr_factory_;
 };
 }  // namespace safe_browsing
diff --git a/chrome/browser/safe_browsing/download_protection/download_item_request_unittest.cc b/chrome/browser/safe_browsing/download_protection/download_item_request_unittest.cc
new file mode 100644
index 0000000..9a11b5d5
--- /dev/null
+++ b/chrome/browser/safe_browsing/download_protection/download_item_request_unittest.cc
@@ -0,0 +1,78 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/safe_browsing/download_protection/download_item_request.h"
+
+#include "base/bind_helpers.h"
+#include "base/files/scoped_temp_dir.h"
+#include "components/download/public/common/mock_download_item.h"
+#include "content/public/test/browser_task_environment.h"
+#include "content/public/test/test_utils.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace safe_browsing {
+
+using ::testing::Return;
+using ::testing::ReturnRef;
+
+class DownloadItemRequestTest : public ::testing::Test {
+ public:
+  DownloadItemRequestTest() : item_(), request_(&item_, base::DoNothing()) {}
+
+  void SetUp() override {
+    ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
+    download_path_ = temp_dir_.GetPath().AppendASCII("download_location");
+    download_temporary_path_ =
+        temp_dir_.GetPath().AppendASCII("temporary_location");
+
+    base::File file(download_path_,
+                    base::File::FLAG_CREATE | base::File::FLAG_WRITE);
+    ASSERT_TRUE(file.IsValid());
+
+    download_contents_ = "download contents";
+    file.Write(0, download_contents_.c_str(), download_contents_.size());
+    file.Close();
+
+    ON_CALL(item_, GetTotalBytes())
+        .WillByDefault(Return(download_contents_.size()));
+    ON_CALL(item_, GetTargetFilePath())
+        .WillByDefault(ReturnRef(download_path_));
+  }
+
+ protected:
+  content::TestBrowserThreadBundle thread_bundle_;
+  download::MockDownloadItem item_;
+  DownloadItemRequest request_;
+  base::ScopedTempDir temp_dir_;
+  base::FilePath download_path_;
+  base::FilePath download_temporary_path_;
+  std::string download_contents_;
+};
+
+TEST_F(DownloadItemRequestTest, GetsSize) {
+  EXPECT_EQ(request_.GetFileSize(), download_contents_.size());
+}
+
+TEST_F(DownloadItemRequestTest, GetsContentsWaitsUntilRename) {
+  ON_CALL(item_, GetFullPath())
+      .WillByDefault(ReturnRef(download_temporary_path_));
+
+  std::string download_contents = "";
+  request_.GetFileContents(base::BindOnce(
+      [](std::string* target_contents, const std::string& contents) {
+        *target_contents = contents;
+      },
+      &download_contents));
+  content::RunAllTasksUntilIdle();
+  EXPECT_EQ(download_contents, "");
+
+  ON_CALL(item_, GetFullPath()).WillByDefault(ReturnRef(download_path_));
+  item_.NotifyObserversDownloadUpdated();
+
+  content::RunAllTasksUntilIdle();
+  EXPECT_EQ(download_contents, "download contents");
+}
+
+}  // namespace safe_browsing
diff --git a/chrome/browser/sessions/session_service_unittest.cc b/chrome/browser/sessions/session_service_unittest.cc
index 855909b9..ea3fd13e 100644
--- a/chrome/browser/sessions/session_service_unittest.cc
+++ b/chrome/browser/sessions/session_service_unittest.cc
@@ -35,6 +35,7 @@
 #include "chrome/test/base/testing_browser_process.h"
 #include "chrome/test/base/testing_profile.h"
 #include "chrome/test/base/testing_profile_manager.h"
+#include "components/sessions/content/content_serialized_navigation_builder.h"
 #include "components/sessions/content/content_test_helper.h"
 #include "components/sessions/core/serialized_navigation_entry_test_helper.h"
 #include "components/sessions/core/session_command.h"
@@ -910,26 +911,30 @@
   SessionID tab_id = SessionID::NewUnique();
   ASSERT_NE(window_id, tab_id);
 
-  // Create a page state representing a HTTP body without posted passwords.
-  content::PageState page_state =
-      content::PageState::CreateForTesting(GURL(), false, "data", NULL);
-
   // Create a TabNavigation containing page_state and representing a POST
   // request.
+  std::string post_data = "data";
+  std::unique_ptr<content::NavigationEntry> entry1 =
+      content::NavigationEntry::Create();
+  entry1->SetURL(GURL("http://google.com"));
+  entry1->SetTitle(base::UTF8ToUTF16("title1"));
+  entry1->SetHasPostData(true);
+  entry1->SetPostData(network::ResourceRequestBody::CreateFromBytes(
+      post_data.data(), post_data.size()));
   SerializedNavigationEntry nav1 =
-      ContentTestHelper::CreateNavigation("http://google.com", "title");
-  SerializedNavigationEntryTestHelper::SetEncodedPageState(
-      page_state.ToEncodedData(), &nav1);
-  SerializedNavigationEntryTestHelper::SetHasPostData(true, &nav1);
-  nav1.set_index(0);
+      sessions::ContentSerializedNavigationBuilder::FromNavigationEntry(
+          0 /* == index*/, entry1.get());
 
   // Create a TabNavigation containing page_state and representing a normal
   // request.
+  std::unique_ptr<content::NavigationEntry> entry2 =
+      content::NavigationEntry::Create();
+  entry2->SetURL(GURL("http://google.com/nopost"));
+  entry2->SetTitle(base::UTF8ToUTF16("title2"));
+  entry2->SetHasPostData(false);
   SerializedNavigationEntry nav2 =
-      ContentTestHelper::CreateNavigation("http://google.com/nopost", "title");
-  SerializedNavigationEntryTestHelper::SetEncodedPageState(
-      page_state.ToEncodedData(), &nav2);
-  nav2.set_index(1);
+      sessions::ContentSerializedNavigationBuilder::FromNavigationEntry(
+          1 /* == index*/, entry2.get());
 
   helper_.PrepareTabInWindow(window_id, tab_id, 0, true);
   UpdateNavigation(window_id, tab_id, nav1, true);
diff --git a/chrome/browser/sharing/sharing_ui_controller.cc b/chrome/browser/sharing/sharing_ui_controller.cc
index 89f16e5b..34cc0b6 100644
--- a/chrome/browser/sharing/sharing_ui_controller.cc
+++ b/chrome/browser/sharing/sharing_ui_controller.cc
@@ -87,6 +87,11 @@
   UpdateIcon();
 }
 
+void SharingUiController::MaybeShowErrorDialog() {
+  if (send_failed_ && web_contents_ == GetCurrentWebContents(web_contents_))
+    ShowNewDialog();
+}
+
 void SharingUiController::SendMessageToDevice(
     const syncer::DeviceInfo& device,
     chrome_browser_sharing::SharingMessage sharing_message) {
@@ -110,9 +115,6 @@
   is_loading_ = false;
   send_failed_ = result != SharingSendMessageResult::kSuccessful;
   UpdateIcon();
-
-  if (send_failed_ && web_contents_ == GetCurrentWebContents(web_contents_))
-    ShowNewDialog();
 }
 
 void SharingUiController::UpdateAndShowDialog() {
diff --git a/chrome/browser/sharing/sharing_ui_controller.h b/chrome/browser/sharing/sharing_ui_controller.h
index 235f98f..c5fe821 100644
--- a/chrome/browser/sharing/sharing_ui_controller.h
+++ b/chrome/browser/sharing/sharing_ui_controller.h
@@ -89,6 +89,8 @@
     devices_ = std::move(devices);
   }
 
+  void MaybeShowErrorDialog();
+
  protected:
   virtual SharingDialog* DoShowDialog(BrowserWindow* window) = 0;
 
diff --git a/chrome/browser/supervised_user/logged_in_user_mixin.cc b/chrome/browser/supervised_user/logged_in_user_mixin.cc
index cb69584..bf54e04c 100644
--- a/chrome/browser/supervised_user/logged_in_user_mixin.cc
+++ b/chrome/browser/supervised_user/logged_in_user_mixin.cc
@@ -38,12 +38,12 @@
 
 LoggedInUserMixin::~LoggedInUserMixin() = default;
 
-void LoggedInUserMixin::LogInUser() {
+void LoggedInUserMixin::LogInUser(bool issue_any_scope_token) {
   UserContext user_context = LoginManagerMixin::CreateDefaultUserContext(user_);
   if (user_.user_type == user_manager::USER_TYPE_CHILD) {
     fake_gaia_.SetupFakeGaiaForChildUser(
         user_.account_id.GetUserEmail(), user_.account_id.GetGaiaId(),
-        FakeGaiaMixin::kFakeRefreshToken, false /*issue_any_scope_token*/);
+        FakeGaiaMixin::kFakeRefreshToken, issue_any_scope_token);
   } else {
     fake_gaia_.SetupFakeGaiaForLogin(user_.account_id.GetUserEmail(),
                                      user_.account_id.GetGaiaId(),
@@ -53,4 +53,8 @@
   login_manager_.LoginAndWaitForActiveSession(user_context);
 }
 
+void LoggedInUserMixin::set_should_launch_browser(bool value) {
+  login_manager_.set_should_launch_browser(value);
+}
+
 }  // namespace chromeos
diff --git a/chrome/browser/supervised_user/logged_in_user_mixin.h b/chrome/browser/supervised_user/logged_in_user_mixin.h
index ddfcaf5..6809cf9 100644
--- a/chrome/browser/supervised_user/logged_in_user_mixin.h
+++ b/chrome/browser/supervised_user/logged_in_user_mixin.h
@@ -27,7 +27,16 @@
                     net::EmbeddedTestServer* embedded_test_server);
   ~LoggedInUserMixin();
 
-  void LogInUser();
+  // Log in as regular or child account depending on the |type| argument passed
+  // to the constructor.
+  // * If |issue_any_scope_token|, FakeGaiaMixin will issue a special all-access
+  // token associated with the test refresh token. Only matters for child login.
+  void LogInUser(bool issue_any_scope_token = false);
+
+  // By default, LoginManagerMixin will set up user session manager not to
+  // launch browser as part of user session setup - use this to override that
+  // behavior.
+  void set_should_launch_browser(bool value);
 
  private:
   LoginManagerMixin::TestUserInfo user_;
diff --git a/chrome/browser/sync/chrome_sync_client.cc b/chrome/browser/sync/chrome_sync_client.cc
index e54bfc98..b70f805 100644
--- a/chrome/browser/sync/chrome_sync_client.cc
+++ b/chrome/browser/sync/chrome_sync_client.cc
@@ -50,7 +50,6 @@
 #include "components/autofill/core/browser/webdata/autocomplete_sync_bridge.h"
 #include "components/autofill/core/browser/webdata/autofill_profile_sync_bridge.h"
 #include "components/autofill/core/browser/webdata/autofill_wallet_metadata_sync_bridge.h"
-#include "components/autofill/core/browser/webdata/autofill_wallet_metadata_syncable_service.h"
 #include "components/autofill/core/browser/webdata/autofill_wallet_sync_bridge.h"
 #include "components/autofill/core/browser/webdata/autofill_webdata_service.h"
 #include "components/autofill/core/common/autofill_features.h"
@@ -444,13 +443,6 @@
       return PrefServiceSyncableFromProfile(profile_)
           ->GetSyncableService(syncer::PRIORITY_PREFERENCES)
           ->AsWeakPtr();
-    case syncer::AUTOFILL_WALLET_METADATA:
-      if (profile_web_data_service_) {
-        return autofill::AutofillWalletMetadataSyncableService::
-            FromWebDataService(profile_web_data_service_.get())
-                ->AsWeakPtr();
-      }
-      return nullptr;
     case syncer::SEARCH_ENGINES:
       return GetWeakPtrOrNull(
           TemplateURLServiceFactory::GetForProfile(profile_));
diff --git a/chrome/browser/sync/test/integration/single_client_apps_sync_test.cc b/chrome/browser/sync/test/integration/single_client_apps_sync_test.cc
index 8f4764f..cb4b37fee 100644
--- a/chrome/browser/sync/test/integration/single_client_apps_sync_test.cc
+++ b/chrome/browser/sync/test/integration/single_client_apps_sync_test.cc
@@ -25,7 +25,7 @@
 };
 
 // crbug.com/997984
-#if defined(MEMORY_SANITIZER)
+#if defined(MEMORY_SANITIZER) || defined(ADDRESS_SANITIZER)
 #define MAYBE_StartWithNoApps DISABLED_StartWithNoApps
 #define MAYBE_StartWithSomeLegacyApps DISABLED_StartWithSomeLegacyApps
 #define MAYBE_StartWithSomePlatformApps DISABLED_StartWithSomePlatformApps
diff --git a/chrome/browser/sync/test/integration/single_client_wallet_sync_test.cc b/chrome/browser/sync/test/integration/single_client_wallet_sync_test.cc
index 603892c..933d6f9 100644
--- a/chrome/browser/sync/test/integration/single_client_wallet_sync_test.cc
+++ b/chrome/browser/sync/test/integration/single_client_wallet_sync_test.cc
@@ -611,7 +611,14 @@
 
 // If the server sends the same cards and addresses again, they should not
 // change on the client. We should also not overwrite existing metadata.
-IN_PROC_BROWSER_TEST_F(SingleClientWalletSyncTest, SameUpdatesAreIgnored) {
+// Flaky on ASan/TSan only. http://crbug.com/997912
+#if defined(ADDRESS_SANITIZER) || defined(THREAD_SANITIZER)
+#define MAYBE_SameUpdatesAreIgnored DISABLED_SameUpdatesAreIgnored
+#else
+#define MAYBE_SameUpdatesAreIgnored SameUpdatesAreIgnored
+#endif
+IN_PROC_BROWSER_TEST_F(SingleClientWalletSyncTest,
+                       MAYBE_SameUpdatesAreIgnored) {
   GetFakeServer()->SetWalletData(
       {CreateSyncWalletCard(/*name=*/"card-1", /*last_four=*/"0001",
                             kDefaultBillingAddressID),
diff --git a/chrome/browser/ui/BUILD.gn b/chrome/browser/ui/BUILD.gn
index aa26cce..60410fc 100644
--- a/chrome/browser/ui/BUILD.gn
+++ b/chrome/browser/ui/BUILD.gn
@@ -929,10 +929,8 @@
       "global_error/global_error_service.h",
       "global_error/global_error_service_factory.cc",
       "global_error/global_error_service_factory.h",
-      "global_media_controls/media_dialog_controller.cc",
-      "global_media_controls/media_dialog_controller.h",
-      "global_media_controls/media_dialog_controller_delegate.cc",
-      "global_media_controls/media_dialog_controller_delegate.h",
+      "global_media_controls/media_dialog_delegate.cc",
+      "global_media_controls/media_dialog_delegate.h",
       "global_media_controls/media_toolbar_button_controller.cc",
       "global_media_controls/media_toolbar_button_controller.h",
       "global_media_controls/media_toolbar_button_controller_delegate.cc",
@@ -2890,8 +2888,6 @@
       "views/overlay/back_to_tab_image_button.h",
       "views/overlay/close_image_button.cc",
       "views/overlay/close_image_button.h",
-      "views/overlay/mute_image_button.cc",
-      "views/overlay/mute_image_button.h",
       "views/overlay/overlay_window_views.cc",
       "views/overlay/overlay_window_views.h",
       "views/overlay/playback_image_button.cc",
@@ -3212,8 +3208,6 @@
 
     if (is_linux) {
       sources += [
-        "views/frame/browser_command_handler_linux.cc",
-        "views/frame/browser_command_handler_linux.h",
         "views/process_singleton_dialog_linux.cc",
         "views/status_icons/status_tray_linux.cc",
         "views/status_icons/status_tray_linux.h",
diff --git a/chrome/browser/ui/android/overlay/overlay_window_android.h b/chrome/browser/ui/android/overlay/overlay_window_android.h
index 794be57..44b8d24 100644
--- a/chrome/browser/ui/android/overlay/overlay_window_android.h
+++ b/chrome/browser/ui/android/overlay/overlay_window_android.h
@@ -62,7 +62,6 @@
   void UpdateVideoSize(const gfx::Size& natural_size) override;
   void SetPlaybackState(PlaybackState playback_state) override {}
   void SetAlwaysHidePlayPauseButton(bool is_visible) override {}
-  void SetMutedState(MutedState muted_state) override {}
   void SetSkipAdButtonVisibility(bool is_visible) override {}
   void SetNextTrackButtonVisibility(bool is_visible) override {}
   void SetPreviousTrackButtonVisibility(bool is_visible) override {}
diff --git a/chrome/browser/ui/global_media_controls/media_dialog_controller.cc b/chrome/browser/ui/global_media_controls/media_dialog_controller.cc
deleted file mode 100644
index 762d71c..0000000
--- a/chrome/browser/ui/global_media_controls/media_dialog_controller.cc
+++ /dev/null
@@ -1,115 +0,0 @@
-// Copyright 2019 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chrome/browser/ui/global_media_controls/media_dialog_controller.h"
-
-#include "base/bind.h"
-#include "base/containers/adapters.h"
-#include "chrome/browser/ui/global_media_controls/media_dialog_controller_delegate.h"
-#include "components/media_message_center/media_notification_item.h"
-#include "services/media_session/public/mojom/constants.mojom.h"
-#include "services/service_manager/public/cpp/connector.h"
-
-using media_session::mojom::MediaSessionAction;
-
-MediaDialogController::MediaDialogController(
-    service_manager::Connector* connector,
-    MediaDialogControllerDelegate* delegate)
-    : connector_(connector), delegate_(delegate) {
-  DCHECK(delegate_);
-}
-
-MediaDialogController::~MediaDialogController() = default;
-
-void MediaDialogController::Initialize() {
-  // |connector| can be null in tests.
-  if (!connector_)
-    return;
-
-  // Connect to the controller manager so we can create media controllers for
-  // media sessions.
-  connector_->Connect(media_session::mojom::kServiceName,
-                      controller_manager_remote_.BindNewPipeAndPassReceiver());
-
-  // Connect to receive audio focus events.
-  connector_->Connect(media_session::mojom::kServiceName,
-                      audio_focus_remote_.BindNewPipeAndPassReceiver());
-  audio_focus_remote_->AddObserver(
-      audio_focus_observer_receiver_.BindNewPipeAndPassRemote());
-
-  audio_focus_remote_->GetFocusRequests(
-      base::BindOnce(&MediaDialogController::OnReceivedAudioFocusRequests,
-                     weak_ptr_factory_.GetWeakPtr()));
-}
-
-void MediaDialogController::OnFocusGained(
-    media_session::mojom::AudioFocusRequestStatePtr session) {
-  const std::string id = session->request_id->ToString();
-
-  // If we have an existing unfrozen item then this is a duplicate call and
-  // we should ignore it.
-  auto it = sessions_.find(id);
-  if (it != sessions_.end() && !it->second.frozen())
-    return;
-
-  mojo::Remote<media_session::mojom::MediaController> controller;
-
-  // |controller_manager_remote_| may be null in tests where connector is
-  // unavailable.
-  if (controller_manager_remote_) {
-    controller_manager_remote_->CreateMediaControllerForSession(
-        controller.BindNewPipeAndPassReceiver(), *session->request_id);
-  }
-
-  if (it != sessions_.end()) {
-    // If the notification was previously frozen then we should reset the
-    // controller because the mojo pipe would have been reset.
-    it->second.SetController(std::move(controller),
-                             std::move(session->session_info));
-  } else {
-    sessions_.emplace(
-        std::piecewise_construct, std::forward_as_tuple(id),
-        std::forward_as_tuple(
-            this, id, session->source_name.value_or(std::string()),
-            std::move(controller), std::move(session->session_info)));
-  }
-}
-
-void MediaDialogController::OnFocusLost(
-    media_session::mojom::AudioFocusRequestStatePtr session) {
-  auto it = sessions_.find(session->request_id->ToString());
-  if (it == sessions_.end())
-    return;
-
-  it->second.Freeze();
-}
-
-void MediaDialogController::ShowNotification(const std::string& id) {
-  base::WeakPtr<media_message_center::MediaNotificationItem> item;
-
-  auto it = sessions_.find(id);
-  if (it != sessions_.end())
-    item = it->second.GetWeakPtr();
-
-  delegate_->ShowMediaSession(id, item);
-}
-
-void MediaDialogController::HideNotification(const std::string& id) {
-  delegate_->HideMediaSession(id);
-}
-
-void MediaDialogController::RemoveItem(const std::string& id) {
-  sessions_.erase(id);
-}
-
-scoped_refptr<base::SequencedTaskRunner> MediaDialogController::GetTaskRunner()
-    const {
-  return task_runner_for_testing_;
-}
-
-void MediaDialogController::OnReceivedAudioFocusRequests(
-    std::vector<media_session::mojom::AudioFocusRequestStatePtr> sessions) {
-  for (auto& session : sessions)
-    OnFocusGained(std::move(session));
-}
diff --git a/chrome/browser/ui/global_media_controls/media_dialog_controller.h b/chrome/browser/ui/global_media_controls/media_dialog_controller.h
deleted file mode 100644
index a5c13b4..0000000
--- a/chrome/browser/ui/global_media_controls/media_dialog_controller.h
+++ /dev/null
@@ -1,84 +0,0 @@
-// Copyright 2019 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROME_BROWSER_UI_GLOBAL_MEDIA_CONTROLS_MEDIA_DIALOG_CONTROLLER_H_
-#define CHROME_BROWSER_UI_GLOBAL_MEDIA_CONTROLS_MEDIA_DIALOG_CONTROLLER_H_
-
-#include <vector>
-
-#include "base/macros.h"
-#include "base/memory/weak_ptr.h"
-#include "components/media_message_center/media_notification_controller.h"
-#include "mojo/public/cpp/bindings/receiver.h"
-#include "mojo/public/cpp/bindings/remote.h"
-#include "services/media_session/public/mojom/audio_focus.mojom.h"
-#include "services/media_session/public/mojom/media_controller.mojom.h"
-
-namespace media_message_center {
-class MediaNotificationItem;
-}  // namespace media_message_center
-
-namespace service_manager {
-class Connector;
-}  // namespace service_manager
-
-class MediaDialogControllerDelegate;
-
-// Controller for the MediaDialogView that updates the view when the active
-// media session changes.
-class MediaDialogController
-    : public media_session::mojom::AudioFocusObserver,
-      public media_message_center::MediaNotificationController {
- public:
-  MediaDialogController(service_manager::Connector* connector,
-                        MediaDialogControllerDelegate* delegate);
-  ~MediaDialogController() override;
-
-  void Initialize();
-
-  // media_session::mojom::AudioFocusObserver implementation.
-  void OnFocusGained(
-      media_session::mojom::AudioFocusRequestStatePtr session) override;
-  void OnFocusLost(
-      media_session::mojom::AudioFocusRequestStatePtr session) override;
-
-  // media_message_center::MediaNotificationController implementation.
-  void ShowNotification(const std::string& id) override;
-  void HideNotification(const std::string& id) override;
-  void RemoveItem(const std::string& id) override;
-  scoped_refptr<base::SequencedTaskRunner> GetTaskRunner() const override;
-
- private:
-  friend class MediaDialogControllerTest;
-
-  // Called when we receive all currently active media sessions for the audio
-  // focus manager. Used to initialize the list of sessions.
-  void OnReceivedAudioFocusRequests(
-      std::vector<media_session::mojom::AudioFocusRequestStatePtr> sessions);
-
-  service_manager::Connector* const connector_;
-  MediaDialogControllerDelegate* const delegate_;
-
-  // Stores a |media_message_center::MediaNotificationItem| for each media
-  // session keyed by its |request_id| in string format.
-  std::map<const std::string, media_message_center::MediaNotificationItem>
-      sessions_;
-
-  mojo::Remote<media_session::mojom::AudioFocusManager> audio_focus_remote_;
-  mojo::Remote<media_session::mojom::MediaControllerManager>
-      controller_manager_remote_;
-
-  // Used to receive updates to the active media controller.
-  mojo::Receiver<media_session::mojom::AudioFocusObserver>
-      audio_focus_observer_receiver_{this};
-
-  // Task runner used for testing.
-  scoped_refptr<base::SequencedTaskRunner> task_runner_for_testing_;
-
-  base::WeakPtrFactory<MediaDialogController> weak_ptr_factory_{this};
-
-  DISALLOW_COPY_AND_ASSIGN(MediaDialogController);
-};
-
-#endif  // CHROME_BROWSER_UI_GLOBAL_MEDIA_CONTROLS_MEDIA_DIALOG_CONTROLLER_H_
diff --git a/chrome/browser/ui/global_media_controls/media_dialog_controller_delegate.cc b/chrome/browser/ui/global_media_controls/media_dialog_controller_delegate.cc
deleted file mode 100644
index 97d12fe..0000000
--- a/chrome/browser/ui/global_media_controls/media_dialog_controller_delegate.cc
+++ /dev/null
@@ -1,7 +0,0 @@
-// Copyright 2019 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chrome/browser/ui/global_media_controls/media_dialog_controller_delegate.h"
-
-MediaDialogControllerDelegate::~MediaDialogControllerDelegate() = default;
diff --git a/chrome/browser/ui/global_media_controls/media_dialog_controller_unittest.cc b/chrome/browser/ui/global_media_controls/media_dialog_controller_unittest.cc
deleted file mode 100644
index 54c6acab..0000000
--- a/chrome/browser/ui/global_media_controls/media_dialog_controller_unittest.cc
+++ /dev/null
@@ -1,172 +0,0 @@
-// Copyright 2019 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chrome/browser/ui/global_media_controls/media_dialog_controller.h"
-
-#include <memory>
-
-#include "base/strings/utf_string_conversions.h"
-#include "base/test/test_mock_time_task_runner.h"
-#include "base/unguessable_token.h"
-#include "chrome/browser/ui/global_media_controls/media_dialog_controller_delegate.h"
-#include "components/media_message_center/media_notification_item.h"
-#include "services/media_session/public/mojom/audio_focus.mojom.h"
-#include "services/media_session/public/mojom/media_session.mojom.h"
-#include "testing/gmock/include/gmock/gmock.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-using media_session::mojom::AudioFocusRequestState;
-using media_session::mojom::AudioFocusRequestStatePtr;
-using media_session::mojom::MediaSessionInfo;
-using media_session::mojom::MediaSessionInfoPtr;
-using testing::_;
-
-namespace {
-
-class MockMediaDialogControllerDelegate : public MediaDialogControllerDelegate {
- public:
-  MockMediaDialogControllerDelegate() = default;
-  ~MockMediaDialogControllerDelegate() override = default;
-
-  // MediaDialogControllerDelegate implementation.
-  MOCK_METHOD2(
-      ShowMediaSession,
-      void(const std::string& id,
-           base::WeakPtr<media_message_center::MediaNotificationItem> item));
-  MOCK_METHOD1(HideMediaSession, void(const std::string& id));
-};
-
-}  // anonymous namespace
-
-class MediaDialogControllerTest : public testing::Test {
- public:
-  MediaDialogControllerTest()
-      : task_runner_(new base::TestMockTimeTaskRunner(
-            base::TestMockTimeTaskRunner::Type::kStandalone)) {}
-
-  ~MediaDialogControllerTest() override = default;
-
-  void SetUp() override {
-    controller_ = std::make_unique<MediaDialogController>(nullptr, &delegate_);
-    controller_->task_runner_for_testing_ = task_runner_.get();
-  }
-
- protected:
-  AudioFocusRequestStatePtr CreateFocusRequest(const base::UnguessableToken& id,
-                                               bool controllable) {
-    MediaSessionInfoPtr session_info(MediaSessionInfo::New());
-    session_info->is_controllable = controllable;
-
-    AudioFocusRequestStatePtr focus(AudioFocusRequestState::New());
-    focus->request_id = id;
-    focus->session_info = std::move(session_info);
-    return focus;
-  }
-
-  void SimulateFocusGained(const base::UnguessableToken& id,
-                           bool controllable) {
-    controller_->OnFocusGained(CreateFocusRequest(id, controllable));
-  }
-
-  void SimulateFocusLost(const base::UnguessableToken& id) {
-    AudioFocusRequestStatePtr focus(AudioFocusRequestState::New());
-    focus->request_id = id;
-    controller_->OnFocusLost(std::move(focus));
-  }
-
-  void SimulateNecessaryMetadata(const base::UnguessableToken& id) {
-    // In order for the MediaNotificationItem to tell the MediaDialogController
-    // to show a media session, that session needs a title and artist. Typically
-    // this would happen through the media session service, but since the
-    // service doesn't run for this test, we'll manually grab the
-    // MediaNotificationItem from the MediaDialogController and set the
-    // metadata.
-    auto item_itr = controller_->sessions_.find(id.ToString());
-    ASSERT_NE(controller_->sessions_.end(), item_itr);
-
-    media_session::MediaMetadata metadata;
-    metadata.title = base::ASCIIToUTF16("title");
-    metadata.artist = base::ASCIIToUTF16("artist");
-    item_itr->second.MediaSessionMetadataChanged(std::move(metadata));
-  }
-
-  void SimulateReceivedAudioFocusRequests(
-      std::vector<AudioFocusRequestStatePtr> requests) {
-    controller_->OnReceivedAudioFocusRequests(std::move(requests));
-  }
-
-  void SimulateFreezeTimerExpired() {
-    task_runner_->FastForwardBy(base::TimeDelta::FromMilliseconds(2500));
-  }
-
-  bool IsSessionFrozen(const base::UnguessableToken& id) const {
-    auto item_itr = controller_->sessions_.find(id.ToString());
-    EXPECT_NE(controller_->sessions_.end(), item_itr);
-    return item_itr->second.frozen();
-  }
-
-  MockMediaDialogControllerDelegate& delegate() { return delegate_; }
-
- private:
-  scoped_refptr<base::TestMockTimeTaskRunner> task_runner_;
-
-  MockMediaDialogControllerDelegate delegate_;
-  std::unique_ptr<MediaDialogController> controller_;
-
-  DISALLOW_COPY_AND_ASSIGN(MediaDialogControllerTest);
-};
-
-TEST_F(MediaDialogControllerTest, ShowControllableOnGainAndHideOnLoss) {
-  base::UnguessableToken id = base::UnguessableToken::Create();
-
-  EXPECT_CALL(delegate(), ShowMediaSession(id.ToString(), _));
-
-  SimulateFocusGained(id, true);
-  SimulateNecessaryMetadata(id);
-  EXPECT_FALSE(IsSessionFrozen(id));
-
-  // Ensure that the session was shown.
-  testing::Mock::VerifyAndClearExpectations(&delegate());
-
-  EXPECT_CALL(delegate(), HideMediaSession(id.ToString())).Times(0);
-  SimulateFocusLost(id);
-  EXPECT_TRUE(IsSessionFrozen(id));
-
-  // Ensure that the session was not hidden.
-  testing::Mock::VerifyAndClearExpectations(&delegate());
-
-  EXPECT_CALL(delegate(), HideMediaSession(id.ToString()));
-  SimulateFreezeTimerExpired();
-}
-
-TEST_F(MediaDialogControllerTest, DoesNotShowUncontrollableSession) {
-  base::UnguessableToken id = base::UnguessableToken::Create();
-
-  EXPECT_CALL(delegate(), ShowMediaSession(_, _)).Times(0);
-
-  SimulateFocusGained(id, false);
-  SimulateNecessaryMetadata(id);
-}
-
-TEST_F(MediaDialogControllerTest, ShowsAllInitialControllableSessions) {
-  base::UnguessableToken controllable1_id = base::UnguessableToken::Create();
-  base::UnguessableToken uncontrollable_id = base::UnguessableToken::Create();
-  base::UnguessableToken controllable2_id = base::UnguessableToken::Create();
-
-  EXPECT_CALL(delegate(), ShowMediaSession(controllable1_id.ToString(), _));
-  EXPECT_CALL(delegate(), ShowMediaSession(uncontrollable_id.ToString(), _))
-      .Times(0);
-  EXPECT_CALL(delegate(), ShowMediaSession(controllable2_id.ToString(), _));
-
-  std::vector<AudioFocusRequestStatePtr> requests;
-  requests.push_back(CreateFocusRequest(controllable1_id, true));
-  requests.push_back(CreateFocusRequest(uncontrollable_id, false));
-  requests.push_back(CreateFocusRequest(controllable2_id, true));
-
-  SimulateReceivedAudioFocusRequests(std::move(requests));
-
-  SimulateNecessaryMetadata(controllable1_id);
-  SimulateNecessaryMetadata(uncontrollable_id);
-  SimulateNecessaryMetadata(controllable2_id);
-}
diff --git a/chrome/browser/ui/global_media_controls/media_dialog_delegate.cc b/chrome/browser/ui/global_media_controls/media_dialog_delegate.cc
new file mode 100644
index 0000000..10cf438
--- /dev/null
+++ b/chrome/browser/ui/global_media_controls/media_dialog_delegate.cc
@@ -0,0 +1,7 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/ui/global_media_controls/media_dialog_delegate.h"
+
+MediaDialogDelegate::~MediaDialogDelegate() = default;
diff --git a/chrome/browser/ui/global_media_controls/media_dialog_controller_delegate.h b/chrome/browser/ui/global_media_controls/media_dialog_delegate.h
similarity index 62%
rename from chrome/browser/ui/global_media_controls/media_dialog_controller_delegate.h
rename to chrome/browser/ui/global_media_controls/media_dialog_delegate.h
index 3b3eca3..6188d7b 100644
--- a/chrome/browser/ui/global_media_controls/media_dialog_controller_delegate.h
+++ b/chrome/browser/ui/global_media_controls/media_dialog_delegate.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 CHROME_BROWSER_UI_GLOBAL_MEDIA_CONTROLS_MEDIA_DIALOG_CONTROLLER_DELEGATE_H_
-#define CHROME_BROWSER_UI_GLOBAL_MEDIA_CONTROLS_MEDIA_DIALOG_CONTROLLER_DELEGATE_H_
+#ifndef CHROME_BROWSER_UI_GLOBAL_MEDIA_CONTROLS_MEDIA_DIALOG_DELEGATE_H_
+#define CHROME_BROWSER_UI_GLOBAL_MEDIA_CONTROLS_MEDIA_DIALOG_DELEGATE_H_
 
 #include <string>
 
@@ -13,9 +13,9 @@
 class MediaNotificationItem;
 }  // namespace media_message_center
 
-// Delegate for MediaDialogController that is told when to display or hide a
-// media session.
-class MediaDialogControllerDelegate {
+// Delegate for MediaToolbarButtonController that is told when to display or
+// hide a media session.
+class MediaDialogDelegate {
  public:
   virtual void ShowMediaSession(
       const std::string& id,
@@ -23,7 +23,7 @@
   virtual void HideMediaSession(const std::string& id) = 0;
 
  protected:
-  virtual ~MediaDialogControllerDelegate();
+  virtual ~MediaDialogDelegate();
 };
 
-#endif  // CHROME_BROWSER_UI_GLOBAL_MEDIA_CONTROLS_MEDIA_DIALOG_CONTROLLER_DELEGATE_H_
+#endif  // CHROME_BROWSER_UI_GLOBAL_MEDIA_CONTROLS_MEDIA_DIALOG_DELEGATE_H_
diff --git a/chrome/browser/ui/global_media_controls/media_toolbar_button_controller.cc b/chrome/browser/ui/global_media_controls/media_toolbar_button_controller.cc
index a0a769aa..99b8737 100644
--- a/chrome/browser/ui/global_media_controls/media_toolbar_button_controller.cc
+++ b/chrome/browser/ui/global_media_controls/media_toolbar_button_controller.cc
@@ -4,18 +4,13 @@
 
 #include "chrome/browser/ui/global_media_controls/media_toolbar_button_controller.h"
 
+#include "chrome/browser/ui/global_media_controls/media_dialog_delegate.h"
 #include "chrome/browser/ui/global_media_controls/media_toolbar_button_controller_delegate.h"
+#include "components/media_message_center/media_notification_item.h"
 #include "services/media_session/public/mojom/constants.mojom.h"
 #include "services/media_session/public/mojom/media_session.mojom.h"
 #include "services/service_manager/public/cpp/connector.h"
 
-namespace {
-
-constexpr base::TimeDelta kHideTimerDelay =
-    base::TimeDelta::FromMilliseconds(2500);
-
-}  // anonymous namespace
-
 MediaToolbarButtonController::MediaToolbarButtonController(
     service_manager::Connector* connector,
     MediaToolbarButtonControllerDelegate* delegate)
@@ -26,37 +21,161 @@
   if (!connector_)
     return;
 
-  // Connect to the MediaControllerManager and create a MediaController that
-  // controls the active session so we can observe it.
-  media_session::mojom::MediaControllerManagerPtr controller_manager_ptr;
-  connector_->BindInterface(media_session::mojom::kServiceName,
-                            mojo::MakeRequest(&controller_manager_ptr));
-  controller_manager_ptr->CreateActiveMediaController(
-      mojo::MakeRequest(&media_controller_ptr_));
+  // Connect to the controller manager so we can create media controllers for
+  // media sessions.
+  connector_->Connect(media_session::mojom::kServiceName,
+                      controller_manager_remote_.BindNewPipeAndPassReceiver());
 
-  // Observe the active media controller for changes to playback state and
-  // supported actions.
-  media_controller_ptr_->AddObserver(
-      media_controller_observer_receiver_.BindNewPipeAndPassRemote());
+  // Connect to receive audio focus events.
+  connector_->Connect(media_session::mojom::kServiceName,
+                      audio_focus_remote_.BindNewPipeAndPassReceiver());
+  audio_focus_remote_->AddObserver(
+      audio_focus_observer_receiver_.BindNewPipeAndPassRemote());
+
+  audio_focus_remote_->GetFocusRequests(base::BindOnce(
+      &MediaToolbarButtonController::OnReceivedAudioFocusRequests,
+      weak_ptr_factory_.GetWeakPtr()));
 }
 
 MediaToolbarButtonController::~MediaToolbarButtonController() = default;
 
-void MediaToolbarButtonController::MediaSessionInfoChanged(
-    media_session::mojom::MediaSessionInfoPtr session_info) {
-  if (session_info && session_info->is_controllable) {
-    hide_icon_timer_.Stop();
-    delegate_->Enable();
-    delegate_->Show();
+void MediaToolbarButtonController::OnFocusGained(
+    media_session::mojom::AudioFocusRequestStatePtr session) {
+  const std::string id = session->request_id->ToString();
+
+  // If we have an existing unfrozen item then this is a duplicate call and
+  // we should ignore it.
+  auto it = sessions_.find(id);
+  if (it != sessions_.end() && !it->second.frozen())
+    return;
+
+  mojo::Remote<media_session::mojom::MediaController> controller;
+
+  // |controller_manager_remote_| may be null in tests where connector is
+  // unavailable.
+  if (controller_manager_remote_) {
+    controller_manager_remote_->CreateMediaControllerForSession(
+        controller.BindNewPipeAndPassReceiver(), *session->request_id);
+  }
+
+  if (it != sessions_.end()) {
+    // If the notification was previously frozen then we should reset the
+    // controller because the mojo pipe would have been reset.
+    it->second.SetController(std::move(controller),
+                             std::move(session->session_info));
+    active_controllable_session_ids_.insert(id);
+    frozen_session_ids_.erase(id);
+    UpdateToolbarButtonState();
   } else {
-    delegate_->Disable();
-    hide_icon_timer_.Start(
-        FROM_HERE, kHideTimerDelay,
-        base::BindOnce(&MediaToolbarButtonController::OnHideTimerFired,
-                       base::Unretained(this)));
+    sessions_.emplace(
+        std::piecewise_construct, std::forward_as_tuple(id),
+        std::forward_as_tuple(
+            this, id, session->source_name.value_or(std::string()),
+            std::move(controller), std::move(session->session_info)));
   }
 }
 
-void MediaToolbarButtonController::OnHideTimerFired() {
-  delegate_->Hide();
+void MediaToolbarButtonController::OnFocusLost(
+    media_session::mojom::AudioFocusRequestStatePtr session) {
+  const std::string id = session->request_id->ToString();
+
+  auto it = sessions_.find(id);
+  if (it == sessions_.end())
+    return;
+
+  it->second.Freeze();
+  active_controllable_session_ids_.erase(id);
+  frozen_session_ids_.insert(id);
+  UpdateToolbarButtonState();
+}
+
+void MediaToolbarButtonController::ShowNotification(const std::string& id) {
+  active_controllable_session_ids_.insert(id);
+  UpdateToolbarButtonState();
+
+  if (!dialog_delegate_)
+    return;
+
+  base::WeakPtr<media_message_center::MediaNotificationItem> item;
+
+  auto it = sessions_.find(id);
+  if (it != sessions_.end())
+    item = it->second.GetWeakPtr();
+
+  dialog_delegate_->ShowMediaSession(id, item);
+}
+
+void MediaToolbarButtonController::HideNotification(const std::string& id) {
+  active_controllable_session_ids_.erase(id);
+  frozen_session_ids_.erase(id);
+  UpdateToolbarButtonState();
+
+  if (!dialog_delegate_)
+    return;
+
+  dialog_delegate_->HideMediaSession(id);
+}
+
+scoped_refptr<base::SequencedTaskRunner>
+MediaToolbarButtonController::GetTaskRunner() const {
+  return nullptr;
+}
+
+void MediaToolbarButtonController::RemoveItem(const std::string& id) {
+  active_controllable_session_ids_.erase(id);
+  frozen_session_ids_.erase(id);
+  sessions_.erase(id);
+
+  UpdateToolbarButtonState();
+}
+
+void MediaToolbarButtonController::SetDialogDelegate(
+    MediaDialogDelegate* delegate) {
+  DCHECK(!delegate || !dialog_delegate_);
+  dialog_delegate_ = delegate;
+
+  UpdateToolbarButtonState();
+
+  if (!dialog_delegate_)
+    return;
+
+  for (const std::string& id : active_controllable_session_ids_) {
+    base::WeakPtr<media_message_center::MediaNotificationItem> item;
+
+    auto it = sessions_.find(id);
+    if (it != sessions_.end())
+      item = it->second.GetWeakPtr();
+
+    dialog_delegate_->ShowMediaSession(id, item);
+  }
+}
+
+void MediaToolbarButtonController::OnReceivedAudioFocusRequests(
+    std::vector<media_session::mojom::AudioFocusRequestStatePtr> sessions) {
+  for (auto& session : sessions)
+    OnFocusGained(std::move(session));
+}
+
+void MediaToolbarButtonController::UpdateToolbarButtonState() {
+  if (!active_controllable_session_ids_.empty()) {
+    if (delegate_display_state_ != DisplayState::kShown) {
+      delegate_->Enable();
+      delegate_->Show();
+    }
+    delegate_display_state_ = DisplayState::kShown;
+    return;
+  }
+
+  if (frozen_session_ids_.empty()) {
+    if (delegate_display_state_ != DisplayState::kHidden)
+      delegate_->Hide();
+    delegate_display_state_ = DisplayState::kHidden;
+    return;
+  }
+
+  if (!dialog_delegate_) {
+    if (delegate_display_state_ != DisplayState::kDisabled)
+      delegate_->Disable();
+    delegate_display_state_ = DisplayState::kDisabled;
+  }
 }
diff --git a/chrome/browser/ui/global_media_controls/media_toolbar_button_controller.h b/chrome/browser/ui/global_media_controls/media_toolbar_button_controller.h
index d4112bd..f639d98 100644
--- a/chrome/browser/ui/global_media_controls/media_toolbar_button_controller.h
+++ b/chrome/browser/ui/global_media_controls/media_toolbar_button_controller.h
@@ -5,55 +5,99 @@
 #ifndef CHROME_BROWSER_UI_GLOBAL_MEDIA_CONTROLS_MEDIA_TOOLBAR_BUTTON_CONTROLLER_H_
 #define CHROME_BROWSER_UI_GLOBAL_MEDIA_CONTROLS_MEDIA_TOOLBAR_BUTTON_CONTROLLER_H_
 
+#include <map>
+#include <string>
+#include <vector>
+
 #include "base/macros.h"
-#include "base/timer/timer.h"
+#include "base/memory/weak_ptr.h"
+#include "components/media_message_center/media_notification_controller.h"
 #include "mojo/public/cpp/bindings/receiver.h"
+#include "mojo/public/cpp/bindings/remote.h"
+#include "services/media_session/public/mojom/audio_focus.mojom.h"
 #include "services/media_session/public/mojom/media_controller.mojom.h"
 
+namespace media_message_center {
+class MediaNotificationItem;
+}  // namespace media_message_center
+
 namespace service_manager {
 class Connector;
 }  // namespace service_manager
 
+class MediaDialogDelegate;
 class MediaToolbarButtonControllerDelegate;
 
 // Controller for the MediaToolbarButtonView that decides when to show or hide
-// the icon from the toolbar.
+// the icon from the toolbar. Also passes MediaNotificationItems to the
+// MediaDialogView to display.
 class MediaToolbarButtonController
-    : public media_session::mojom::MediaControllerObserver {
+    : public media_session::mojom::AudioFocusObserver,
+      public media_message_center::MediaNotificationController {
  public:
   MediaToolbarButtonController(service_manager::Connector* connector,
                                MediaToolbarButtonControllerDelegate* delegate);
   ~MediaToolbarButtonController() override;
 
-  // media_session::mojom::MediaControllerObserver implementation.
-  void MediaSessionInfoChanged(
-      media_session::mojom::MediaSessionInfoPtr session_info) override;
-  void MediaSessionMetadataChanged(
-      const base::Optional<media_session::MediaMetadata>& metadata) override {}
-  void MediaSessionActionsChanged(
-      const std::vector<media_session::mojom::MediaSessionAction>& actions)
-      override {}
-  void MediaSessionChanged(
-      const base::Optional<base::UnguessableToken>& request_id) override {}
-  void MediaSessionPositionChanged(
-      const base::Optional<media_session::MediaPosition>& position) override {}
+  // media_session::mojom::AudioFocusObserver implementation.
+  void OnFocusGained(
+      media_session::mojom::AudioFocusRequestStatePtr session) override;
+  void OnFocusLost(
+      media_session::mojom::AudioFocusRequestStatePtr session) override;
+
+  // media_message_center::MediaNotificationController implementation.
+  void ShowNotification(const std::string& id) override;
+  void HideNotification(const std::string& id) override;
+  void RemoveItem(const std::string& id) override;
+  scoped_refptr<base::SequencedTaskRunner> GetTaskRunner() const override;
+
+  void SetDialogDelegate(MediaDialogDelegate* delegate);
 
  private:
-  void OnHideTimerFired();
+  friend class MediaToolbarButtonControllerTest;
+
+  // Tracks the current display state of the toolbar button delegate.
+  enum class DisplayState {
+    kShown,
+    kDisabled,
+    kHidden,
+  };
+
+  void OnReceivedAudioFocusRequests(
+      std::vector<media_session::mojom::AudioFocusRequestStatePtr> sessions);
+
+  void UpdateToolbarButtonState();
 
   service_manager::Connector* const connector_;
   MediaToolbarButtonControllerDelegate* const delegate_;
+  MediaDialogDelegate* dialog_delegate_ = nullptr;
 
-  // We hide the toolbar button when there's no active and controllable media
-  // session. We use this timer to avoid flashing when a media session changes.
-  base::OneShotTimer hide_icon_timer_;
+  // The delegate starts hidden and isn't shown until media playback starts.
+  DisplayState delegate_display_state_ = DisplayState::kHidden;
 
-  // Tracks current media session state/metadata.
-  media_session::mojom::MediaControllerPtr media_controller_ptr_;
+  // Used to track whether there are any active controllable media sessions. If
+  // not, then there's nothing to show in the dialog and we can hide the toolbar
+  // icon.
+  std::unordered_set<std::string> active_controllable_session_ids_;
 
-  // Used to receive updates to the active media controller.
-  mojo::Receiver<media_session::mojom::MediaControllerObserver>
-      media_controller_observer_receiver_{this};
+  // Tracks the sessions that are currently frozen. If there are only frozen
+  // sessions, we will disable the toolbar icon and wait to hide it.
+  std::unordered_set<std::string> frozen_session_ids_;
+
+  // Stores a |media_message_center::MediaNotificationItem| for each media
+  // session keyed by its |request_id| in string format.
+  std::map<const std::string, media_message_center::MediaNotificationItem>
+      sessions_;
+
+  // Connections with the media session service to listen for audio focus
+  // updates and control media sessions.
+  mojo::Remote<media_session::mojom::AudioFocusManager> audio_focus_remote_;
+  mojo::Remote<media_session::mojom::MediaControllerManager>
+      controller_manager_remote_;
+  mojo::Receiver<media_session::mojom::AudioFocusObserver>
+      audio_focus_observer_receiver_{this};
+
+  base::WeakPtrFactory<MediaToolbarButtonController> weak_ptr_factory_{this};
 
   DISALLOW_COPY_AND_ASSIGN(MediaToolbarButtonController);
 };
diff --git a/chrome/browser/ui/global_media_controls/media_toolbar_button_controller_unittest.cc b/chrome/browser/ui/global_media_controls/media_toolbar_button_controller_unittest.cc
index 57ab723..962b8c3 100644
--- a/chrome/browser/ui/global_media_controls/media_toolbar_button_controller_unittest.cc
+++ b/chrome/browser/ui/global_media_controls/media_toolbar_button_controller_unittest.cc
@@ -6,14 +6,22 @@
 
 #include <memory>
 
+#include "base/strings/utf_string_conversions.h"
 #include "base/test/task_environment.h"
+#include "base/unguessable_token.h"
+#include "chrome/browser/ui/global_media_controls/media_dialog_delegate.h"
 #include "chrome/browser/ui/global_media_controls/media_toolbar_button_controller_delegate.h"
+#include "components/media_message_center/media_notification_item.h"
+#include "services/media_session/public/mojom/audio_focus.mojom.h"
 #include "services/media_session/public/mojom/media_session.mojom.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
+using media_session::mojom::AudioFocusRequestState;
+using media_session::mojom::AudioFocusRequestStatePtr;
 using media_session::mojom::MediaSessionInfo;
 using media_session::mojom::MediaSessionInfoPtr;
+using testing::_;
 
 namespace {
 
@@ -30,6 +38,38 @@
   MOCK_METHOD0(Disable, void());
 };
 
+class MockMediaDialogDelegate : public MediaDialogDelegate {
+ public:
+  MockMediaDialogDelegate() = default;
+  ~MockMediaDialogDelegate() override { Close(); }
+
+  void Open(MediaToolbarButtonController* controller) {
+    ASSERT_NE(nullptr, controller);
+    controller_ = controller;
+    controller_->SetDialogDelegate(this);
+  }
+
+  void Close() {
+    if (!controller_)
+      return;
+
+    controller_->SetDialogDelegate(nullptr);
+    controller_ = nullptr;
+  }
+
+  // MediaDialogDelegate implementation.
+  MOCK_METHOD2(
+      ShowMediaSession,
+      void(const std::string& id,
+           base::WeakPtr<media_message_center::MediaNotificationItem> item));
+  MOCK_METHOD1(HideMediaSession, void(const std::string& id));
+
+ private:
+  MediaToolbarButtonController* controller_;
+
+  DISALLOW_COPY_AND_ASSIGN(MockMediaDialogDelegate);
+};
+
 }  // anonymous namespace
 
 class MediaToolbarButtonControllerTest : public testing::Test {
@@ -45,53 +85,174 @@
   }
 
  protected:
-  void SimulatePlayingControllableMedia() {
-    MediaSessionInfoPtr session_info(MediaSessionInfo::New());
-    session_info->is_controllable = true;
-    controller_->MediaSessionInfoChanged(std::move(session_info));
-  }
-
-  void SimulateMediaStopped() { controller_->MediaSessionInfoChanged(nullptr); }
-
   void AdvanceClockMilliseconds(int milliseconds) {
     task_environment_.FastForwardBy(
         base::TimeDelta::FromMilliseconds(milliseconds));
   }
 
+  base::UnguessableToken SimulatePlayingControllableMedia() {
+    base::UnguessableToken id = base::UnguessableToken::Create();
+    SimulateFocusGained(id, true);
+    SimulateNecessaryMetadata(id);
+    return id;
+  }
+
+  AudioFocusRequestStatePtr CreateFocusRequest(const base::UnguessableToken& id,
+                                               bool controllable) {
+    MediaSessionInfoPtr session_info(MediaSessionInfo::New());
+    session_info->is_controllable = controllable;
+
+    AudioFocusRequestStatePtr focus(AudioFocusRequestState::New());
+    focus->request_id = id;
+    focus->session_info = std::move(session_info);
+    return focus;
+  }
+
+  void SimulateFocusGained(const base::UnguessableToken& id,
+                           bool controllable) {
+    controller_->OnFocusGained(CreateFocusRequest(id, controllable));
+  }
+
+  void SimulateFocusLost(const base::UnguessableToken& id) {
+    AudioFocusRequestStatePtr focus(AudioFocusRequestState::New());
+    focus->request_id = id;
+    controller_->OnFocusLost(std::move(focus));
+  }
+
+  void SimulateNecessaryMetadata(const base::UnguessableToken& id) {
+    // In order for the MediaNotificationItem to tell the
+    // MediaToolbarButtonController to show a media session, that session needs
+    // a title and artist. Typically this would happen through the media session
+    // service, but since the service doesn't run for this test, we'll manually
+    // grab the MediaNotificationItem from the MediaToolbarButtonController and
+    // set the metadata.
+    auto item_itr = controller_->sessions_.find(id.ToString());
+    ASSERT_NE(controller_->sessions_.end(), item_itr);
+
+    media_session::MediaMetadata metadata;
+    metadata.title = base::ASCIIToUTF16("title");
+    metadata.artist = base::ASCIIToUTF16("artist");
+    item_itr->second.MediaSessionMetadataChanged(std::move(metadata));
+  }
+
+  void SimulateReceivedAudioFocusRequests(
+      std::vector<AudioFocusRequestStatePtr> requests) {
+    controller_->OnReceivedAudioFocusRequests(std::move(requests));
+  }
+
+  bool IsSessionFrozen(const base::UnguessableToken& id) const {
+    auto item_itr = controller_->sessions_.find(id.ToString());
+    EXPECT_NE(controller_->sessions_.end(), item_itr);
+    return item_itr->second.frozen();
+  }
+
+  void SimulateDialogOpened(MockMediaDialogDelegate* delegate) {
+    delegate->Open(controller_.get());
+  }
+
   MockMediaToolbarButtonControllerDelegate& delegate() { return delegate_; }
 
  private:
   base::test::TaskEnvironment task_environment_;
-  std::unique_ptr<MediaToolbarButtonController> controller_;
   MockMediaToolbarButtonControllerDelegate delegate_;
+  std::unique_ptr<MediaToolbarButtonController> controller_;
 
   DISALLOW_COPY_AND_ASSIGN(MediaToolbarButtonControllerTest);
 };
 
-TEST_F(MediaToolbarButtonControllerTest, CallsShowForControllableMedia) {
+TEST_F(MediaToolbarButtonControllerTest, ShowControllableOnGainAndHideOnLoss) {
+  // Simulate a new active, controllable media session.
   EXPECT_CALL(delegate(), Show());
-  SimulatePlayingControllableMedia();
+  base::UnguessableToken id = SimulatePlayingControllableMedia();
+  EXPECT_FALSE(IsSessionFrozen(id));
+
+  // Ensure that the toolbar button was shown.
+  testing::Mock::VerifyAndClearExpectations(&delegate());
+
+  // Simulate opening a MediaDialogView.
+  MockMediaDialogDelegate dialog_delegate;
+  EXPECT_CALL(dialog_delegate, ShowMediaSession(id.ToString(), _));
+  SimulateDialogOpened(&dialog_delegate);
+
+  // Ensure that the session was shown.
+  testing::Mock::VerifyAndClearExpectations(&dialog_delegate);
+
+  // Simulate the active session ending.
+  EXPECT_CALL(dialog_delegate, HideMediaSession(id.ToString())).Times(0);
+  SimulateFocusLost(id);
+
+  // Ensure that the session was frozen and not hidden.
+  EXPECT_TRUE(IsSessionFrozen(id));
+  testing::Mock::VerifyAndClearExpectations(&dialog_delegate);
+
+  // Once the freeze timer fires, we should hide the media session.
+  EXPECT_CALL(dialog_delegate, HideMediaSession(id.ToString()));
+  AdvanceClockMilliseconds(2500);
+}
+
+TEST_F(MediaToolbarButtonControllerTest, DoesNotShowUncontrollableSession) {
+  base::UnguessableToken id = base::UnguessableToken::Create();
+
+  EXPECT_CALL(delegate(), Show()).Times(0);
+
+  SimulateFocusGained(id, false);
+  SimulateNecessaryMetadata(id);
+}
+
+TEST_F(MediaToolbarButtonControllerTest, ShowsAllInitialControllableSessions) {
+  base::UnguessableToken controllable1_id = base::UnguessableToken::Create();
+  base::UnguessableToken uncontrollable_id = base::UnguessableToken::Create();
+  base::UnguessableToken controllable2_id = base::UnguessableToken::Create();
+
+  std::vector<AudioFocusRequestStatePtr> requests;
+  requests.push_back(CreateFocusRequest(controllable1_id, true));
+  requests.push_back(CreateFocusRequest(uncontrollable_id, false));
+  requests.push_back(CreateFocusRequest(controllable2_id, true));
+
+  // Having active, controllable sessions should show the toolbar button.
+  EXPECT_CALL(delegate(), Show());
+
+  SimulateReceivedAudioFocusRequests(std::move(requests));
+
+  SimulateNecessaryMetadata(controllable1_id);
+  SimulateNecessaryMetadata(uncontrollable_id);
+  SimulateNecessaryMetadata(controllable2_id);
+
+  testing::Mock::VerifyAndClearExpectations(&delegate());
+
+  // If we open a dialog, it should be told to show the controllable sessions,
+  // but not the uncontrollable one.
+  MockMediaDialogDelegate dialog_delegate;
+
+  EXPECT_CALL(dialog_delegate,
+              ShowMediaSession(controllable1_id.ToString(), _));
+  EXPECT_CALL(dialog_delegate,
+              ShowMediaSession(uncontrollable_id.ToString(), _))
+      .Times(0);
+  EXPECT_CALL(dialog_delegate,
+              ShowMediaSession(controllable2_id.ToString(), _));
+  SimulateDialogOpened(&dialog_delegate);
 }
 
 TEST_F(MediaToolbarButtonControllerTest, HidesAfterTimeoutAndShowsAgainOnPlay) {
   // First, show the button.
   EXPECT_CALL(delegate(), Show());
-  SimulatePlayingControllableMedia();
+  base::UnguessableToken id = SimulatePlayingControllableMedia();
   testing::Mock::VerifyAndClearExpectations(&delegate());
 
   // Then, stop playing media so the button is disabled, but hasn't been hidden
   // yet.
   EXPECT_CALL(delegate(), Disable());
   EXPECT_CALL(delegate(), Hide()).Times(0);
-  SimulateMediaStopped();
+  SimulateFocusLost(id);
   testing::Mock::VerifyAndClearExpectations(&delegate());
 
-  // If the time hasn't elapsed yet, we should still not be hidden.
+  // If the time hasn't elapsed yet, the button should still not be hidden.
   EXPECT_CALL(delegate(), Hide()).Times(0);
   AdvanceClockMilliseconds(2400);
   testing::Mock::VerifyAndClearExpectations(&delegate());
 
-  // Once the time is elapsed, we should be hidden.
+  // Once the time is elapsed, the button should be hidden.
   EXPECT_CALL(delegate(), Hide());
   AdvanceClockMilliseconds(200);
   testing::Mock::VerifyAndClearExpectations(&delegate());
@@ -103,18 +264,37 @@
   testing::Mock::VerifyAndClearExpectations(&delegate());
 }
 
+TEST_F(MediaToolbarButtonControllerTest, DoesNotDisableButtonIfDialogIsOpen) {
+  // First, show the button.
+  EXPECT_CALL(delegate(), Show());
+  base::UnguessableToken id = SimulatePlayingControllableMedia();
+  testing::Mock::VerifyAndClearExpectations(&delegate());
+
+  // Then, open a dialog.
+  MockMediaDialogDelegate dialog_delegate;
+  EXPECT_CALL(dialog_delegate, ShowMediaSession(id.ToString(), _));
+  SimulateDialogOpened(&dialog_delegate);
+
+  // Then, have the session lose focus. This should not disable the button when
+  // a dialog is present (since the button can still be used to close the
+  // dialog).
+  EXPECT_CALL(delegate(), Disable()).Times(0);
+  SimulateFocusLost(id);
+  testing::Mock::VerifyAndClearExpectations(&delegate());
+}
+
 TEST_F(MediaToolbarButtonControllerTest,
        DoesNotHideIfMediaStartsPlayingWithinTimeout) {
   // First, show the button.
   EXPECT_CALL(delegate(), Show());
-  SimulatePlayingControllableMedia();
+  base::UnguessableToken id = SimulatePlayingControllableMedia();
   testing::Mock::VerifyAndClearExpectations(&delegate());
 
   // Then, stop playing media so the button is disabled, but hasn't been hidden
   // yet.
   EXPECT_CALL(delegate(), Disable());
   EXPECT_CALL(delegate(), Hide()).Times(0);
-  SimulateMediaStopped();
+  SimulateFocusLost(id);
   testing::Mock::VerifyAndClearExpectations(&delegate());
 
   // If the time hasn't elapsed yet, we should still not be hidden.
@@ -128,3 +308,32 @@
   SimulatePlayingControllableMedia();
   testing::Mock::VerifyAndClearExpectations(&delegate());
 }
+
+TEST_F(MediaToolbarButtonControllerTest, NewMediaSessionWhileDialogOpen) {
+  // First, show the button.
+  EXPECT_CALL(delegate(), Show());
+  base::UnguessableToken id = SimulatePlayingControllableMedia();
+  testing::Mock::VerifyAndClearExpectations(&delegate());
+
+  // Then, open a dialog.
+  MockMediaDialogDelegate dialog_delegate;
+  EXPECT_CALL(dialog_delegate, ShowMediaSession(id.ToString(), _));
+  SimulateDialogOpened(&dialog_delegate);
+  testing::Mock::VerifyAndClearExpectations(&dialog_delegate);
+
+  // Then, have a new media session start while the dialog is opened. This
+  // should update the dialog.
+  base::UnguessableToken new_id = base::UnguessableToken::Create();
+  EXPECT_CALL(dialog_delegate, ShowMediaSession(new_id.ToString(), _));
+  SimulateFocusGained(new_id, true);
+  SimulateNecessaryMetadata(new_id);
+  testing::Mock::VerifyAndClearExpectations(&dialog_delegate);
+
+  // If we close this dialog and open a new one, the new one should receive both
+  // media sessions immediately.
+  dialog_delegate.Close();
+  MockMediaDialogDelegate new_dialog;
+  EXPECT_CALL(new_dialog, ShowMediaSession(id.ToString(), _));
+  EXPECT_CALL(new_dialog, ShowMediaSession(new_id.ToString(), _));
+  SimulateDialogOpened(&new_dialog);
+}
diff --git a/chrome/browser/ui/views/critical_notification_bubble_view.cc b/chrome/browser/ui/views/critical_notification_bubble_view.cc
index 8bedf94..a4c7c4c 100644
--- a/chrome/browser/ui/views/critical_notification_bubble_view.cc
+++ b/chrome/browser/ui/views/critical_notification_bubble_view.cc
@@ -10,6 +10,7 @@
 #include "chrome/browser/lifetime/application_lifetime.h"
 #include "chrome/browser/ui/browser_dialogs.h"
 #include "chrome/browser/ui/views/chrome_layout_provider.h"
+#include "chrome/browser/ui/views/chrome_typography.h"
 #include "chrome/browser/upgrade_detector/upgrade_detector.h"
 #include "chrome/common/pref_names.h"
 #include "chrome/grit/chromium_strings.h"
@@ -23,6 +24,7 @@
 #include "ui/views/bubble/bubble_frame_view.h"
 #include "ui/views/controls/label.h"
 #include "ui/views/layout/fill_layout.h"
+#include "ui/views/style/typography.h"
 #include "ui/views/widget/widget.h"
 
 using base::UserMetricsAction;
@@ -125,15 +127,16 @@
 
   SetLayoutManager(std::make_unique<views::FillLayout>());
 
-  views::Label* message = new views::Label();
+  auto message = std::make_unique<views::Label>(
+      l10n_util::GetStringUTF16(IDS_CRITICAL_NOTIFICATION_TEXT),
+      views::style::CONTEXT_MESSAGE_BOX_BODY_TEXT, STYLE_SECONDARY);
   message->SetMultiLine(true);
   message->SetHorizontalAlignment(gfx::ALIGN_LEFT);
-  message->SetText(l10n_util::GetStringUTF16(IDS_CRITICAL_NOTIFICATION_TEXT));
   message->SizeToFit(
       ChromeLayoutProvider::Get()->GetDistanceMetric(
           ChromeDistanceMetric::DISTANCE_BUBBLE_PREFERRED_WIDTH) -
       margins().width());
-  AddChildView(message);
+  AddChildView(std::move(message));
 
   refresh_timer_.Start(FROM_HERE,
       base::TimeDelta::FromMilliseconds(kRefreshBubbleEvery),
diff --git a/chrome/browser/ui/views/frame/browser_command_handler_linux.cc b/chrome/browser/ui/views/frame/browser_command_handler_linux.cc
deleted file mode 100644
index 2c4d7e85..0000000
--- a/chrome/browser/ui/views/frame/browser_command_handler_linux.cc
+++ /dev/null
@@ -1,81 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chrome/browser/ui/views/frame/browser_command_handler_linux.h"
-
-#include "chrome/browser/ui/browser.h"
-#include "chrome/browser/ui/tabs/tab_strip_model.h"
-#include "chrome/browser/ui/views/frame/browser_view.h"
-#include "content/public/browser/navigation_controller.h"
-#include "content/public/browser/web_contents.h"
-#include "content/public/common/content_features.h"
-#include "ui/aura/window.h"
-#include "ui/events/event.h"
-
-BrowserCommandHandlerLinux::BrowserCommandHandlerLinux(
-    BrowserView* browser_view)
-    : browser_view_(browser_view) {
-  aura::Window* window = browser_view_->frame()->GetNativeWindow();
-  DCHECK(window);
-  window->AddObserver(this);
-  window->AddPreTargetHandler(this);
-}
-
-BrowserCommandHandlerLinux::~BrowserCommandHandlerLinux() {
-  aura::Window* window = browser_view_->frame()->GetNativeWindow();
-  if (window)
-    RemoveObservers(window);
-}
-
-void BrowserCommandHandlerLinux::RemoveObservers(aura::Window* window) {
-  window->RemoveObserver(this);
-  window->RemovePreTargetHandler(this);
-}
-
-void BrowserCommandHandlerLinux::OnMouseEvent(ui::MouseEvent* event) {
-  // Handle standard Linux mouse buttons for going back and forward.
-  // Mouse press events trigger the navigations, while mouse release events are
-  // consumed and ignored so they aren't forwarded as unpaired events (which may
-  // trigger navigations as well)
-  bool mouse_pressed = (event->type() == ui::ET_MOUSE_PRESSED);
-  bool mouse_released = (event->type() == ui::ET_MOUSE_RELEASED);
-  if (!mouse_pressed && !mouse_released)
-    return;
-
-  // If extended mouse buttons are supported handle them in the renderer.
-  if (base::FeatureList::IsEnabled(features::kExtendedMouseButtons))
-    return;
-
-  bool back_button_toggled =
-      (event->changed_button_flags() == ui::EF_BACK_MOUSE_BUTTON);
-  bool forward_button_toggled =
-      (event->changed_button_flags() == ui::EF_FORWARD_MOUSE_BUTTON);
-  if (!back_button_toggled && !forward_button_toggled)
-    return;
-
-  content::WebContents* contents =
-      browser_view_->browser()->tab_strip_model()->GetActiveWebContents();
-  if (!contents)
-    return;
-
-  // Always consume the event, whether a navigation is successful or not.
-  //
-  // TODO(mustaq): Perhaps we should mark "handled" only for successful
-  //   navigation above but a bug in the past didn't allow it:
-  //   https://codereview.chromium.org/2763313002/#msg19
-  event->SetHandled();
-
-  if (!mouse_pressed)
-    return;
-
-  content::NavigationController& controller = contents->GetController();
-  if (back_button_toggled && controller.CanGoBack())
-    controller.GoBack();
-  else if (forward_button_toggled && controller.CanGoForward())
-    controller.GoForward();
-}
-
-void BrowserCommandHandlerLinux::OnWindowDestroying(aura::Window* window) {
-  RemoveObservers(window);
-}
diff --git a/chrome/browser/ui/views/frame/browser_command_handler_linux.h b/chrome/browser/ui/views/frame/browser_command_handler_linux.h
deleted file mode 100644
index d195fa07..0000000
--- a/chrome/browser/ui/views/frame/browser_command_handler_linux.h
+++ /dev/null
@@ -1,34 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROME_BROWSER_UI_VIEWS_FRAME_BROWSER_COMMAND_HANDLER_LINUX_H_
-#define CHROME_BROWSER_UI_VIEWS_FRAME_BROWSER_COMMAND_HANDLER_LINUX_H_
-
-#include "base/macros.h"
-#include "ui/aura/window_observer.h"
-#include "ui/events/event_handler.h"
-
-class BrowserView;
-
-class BrowserCommandHandlerLinux : public ui::EventHandler,
-                                   public aura::WindowObserver {
- public:
-  explicit BrowserCommandHandlerLinux(BrowserView* browser_view);
-  ~BrowserCommandHandlerLinux() override;
-
- private:
-  void RemoveObservers(aura::Window* window);
-
-  // ui::EventHandler:
-  void OnMouseEvent(ui::MouseEvent* event) override;
-
-  // aura::WindowObserver:
-  void OnWindowDestroying(aura::Window* window) override;
-
-  BrowserView* browser_view_;
-
-  DISALLOW_COPY_AND_ASSIGN(BrowserCommandHandlerLinux);
-};
-
-#endif  // CHROME_BROWSER_UI_VIEWS_FRAME_BROWSER_COMMAND_HANDLER_LINUX_H_
diff --git a/chrome/browser/ui/views/frame/browser_frame.cc b/chrome/browser/ui/views/frame/browser_frame.cc
index e38037d3..fc26532 100644
--- a/chrome/browser/ui/views/frame/browser_frame.cc
+++ b/chrome/browser/ui/views/frame/browser_frame.cc
@@ -39,10 +39,6 @@
 #include "components/user_manager/user_manager.h"
 #endif
 
-#if defined(OS_LINUX)
-#include "chrome/browser/ui/views/frame/browser_command_handler_linux.h"
-#endif
-
 #if defined(USE_X11)
 #include "ui/views/widget/desktop_aura/x11_desktop_handler.h"
 #endif
@@ -110,11 +106,6 @@
     DCHECK(non_client_view());
     non_client_view()->set_context_menu_controller(this);
   }
-
-#if defined(OS_LINUX)
-  browser_command_handler_ =
-      std::make_unique<BrowserCommandHandlerLinux>(browser_view_);
-#endif
 }
 
 int BrowserFrame::GetMinimizeButtonOffset() const {
diff --git a/chrome/browser/ui/views/frame/browser_frame.h b/chrome/browser/ui/views/frame/browser_frame.h
index 5e7f0c87..d168479 100644
--- a/chrome/browser/ui/views/frame/browser_frame.h
+++ b/chrome/browser/ui/views/frame/browser_frame.h
@@ -32,7 +32,6 @@
 }
 
 namespace ui {
-class EventHandler;
 class MenuModel;
 }
 
@@ -153,8 +152,6 @@
   // NativeBrowserFrame::UsesNativeSystemMenu() returns false.
   std::unique_ptr<views::MenuRunner> menu_runner_;
 
-  std::unique_ptr<ui::EventHandler> browser_command_handler_;
-
   ScopedObserver<ui::MaterialDesignController,
                  ui::MaterialDesignControllerObserver>
       md_observer_{this};
diff --git a/chrome/browser/ui/views/global_media_controls/media_dialog_view.cc b/chrome/browser/ui/views/global_media_controls/media_dialog_view.cc
index 71dee05..1398eac2 100644
--- a/chrome/browser/ui/views/global_media_controls/media_dialog_view.cc
+++ b/chrome/browser/ui/views/global_media_controls/media_dialog_view.cc
@@ -5,6 +5,7 @@
 #include "chrome/browser/ui/views/global_media_controls/media_dialog_view.h"
 
 #include "base/strings/utf_string_conversions.h"
+#include "chrome/browser/ui/global_media_controls/media_toolbar_button_controller.h"
 #include "chrome/browser/ui/views/chrome_layout_provider.h"
 #include "chrome/browser/ui/views/global_media_controls/media_notification_container_impl.h"
 #include "chrome/browser/ui/views/global_media_controls/media_notification_list_view.h"
@@ -27,9 +28,11 @@
 
 // static
 void MediaDialogView::ShowDialog(views::View* anchor_view,
+                                 MediaToolbarButtonController* controller,
                                  service_manager::Connector* connector) {
   DCHECK(!instance_);
-  instance_ = new MediaDialogView(anchor_view, connector);
+  DCHECK(controller);
+  instance_ = new MediaDialogView(anchor_view, controller, connector);
 
   views::Widget* widget =
       views::BubbleDialogDelegateView::CreateBubble(instance_);
@@ -38,8 +41,10 @@
 
 // static
 void MediaDialogView::HideDialog() {
-  if (IsShowing())
+  if (IsShowing()) {
+    instance_->controller_->SetDialogDelegate(nullptr);
     instance_->GetWidget()->Close();
+  }
 
   // Set |instance_| to nullptr so that |IsShowing()| returns false immediately.
   // We also set to nullptr in |WindowClosing()| (which happens asynchronously),
@@ -77,6 +82,8 @@
   views::BubbleFrameView* frame = GetBubbleFrameView();
   if (frame)
     frame->SetCornerRadius(kMediaDialogCornerRadius);
+
+  controller_->SetDialogDelegate(this);
 }
 
 gfx::Size MediaDialogView::CalculatePreferredSize() const {
@@ -91,11 +98,14 @@
 }
 
 MediaDialogView::MediaDialogView(views::View* anchor_view,
+                                 MediaToolbarButtonController* controller,
                                  service_manager::Connector* connector)
     : BubbleDialogDelegateView(anchor_view, views::BubbleBorder::TOP_RIGHT),
-      controller_(connector, this),
+      controller_(controller),
       active_sessions_view_(
-          AddChildView(std::make_unique<MediaNotificationListView>())) {}
+          AddChildView(std::make_unique<MediaNotificationListView>())) {
+  DCHECK(controller_);
+}
 
 MediaDialogView::~MediaDialogView() = default;
 
@@ -104,11 +114,11 @@
   set_margins(gfx::Insets());
 
   SetLayoutManager(std::make_unique<views::FillLayout>());
-
-  controller_.Initialize();
 }
 
 void MediaDialogView::WindowClosing() {
-  if (instance_ == this)
+  if (instance_ == this) {
     instance_ = nullptr;
+    controller_->SetDialogDelegate(nullptr);
+  }
 }
diff --git a/chrome/browser/ui/views/global_media_controls/media_dialog_view.h b/chrome/browser/ui/views/global_media_controls/media_dialog_view.h
index 344c1851..172cc5b 100644
--- a/chrome/browser/ui/views/global_media_controls/media_dialog_view.h
+++ b/chrome/browser/ui/views/global_media_controls/media_dialog_view.h
@@ -6,8 +6,7 @@
 #define CHROME_BROWSER_UI_VIEWS_GLOBAL_MEDIA_CONTROLS_MEDIA_DIALOG_VIEW_H_
 
 #include "base/optional.h"
-#include "chrome/browser/ui/global_media_controls/media_dialog_controller.h"
-#include "chrome/browser/ui/global_media_controls/media_dialog_controller_delegate.h"
+#include "chrome/browser/ui/global_media_controls/media_dialog_delegate.h"
 #include "ui/views/bubble/bubble_dialog_delegate_view.h"
 
 namespace service_manager {
@@ -15,17 +14,19 @@
 }  // namespace service_manager
 
 class MediaNotificationListView;
+class MediaToolbarButtonController;
 
 // Dialog that shows media controls that control the active media session.
 class MediaDialogView : public views::BubbleDialogDelegateView,
-                        public MediaDialogControllerDelegate {
+                        public MediaDialogDelegate {
  public:
   static void ShowDialog(views::View* anchor_view,
+                         MediaToolbarButtonController* controller,
                          service_manager::Connector* connector);
   static void HideDialog();
   static bool IsShowing();
 
-  // MediaDialogControllerDelegate implementation.
+  // MediaDialogDelegate implementation.
   void ShowMediaSession(
       const std::string& id,
       base::WeakPtr<media_message_center::MediaNotificationItem> item) override;
@@ -41,6 +42,7 @@
 
  private:
   explicit MediaDialogView(views::View* anchor_view,
+                           MediaToolbarButtonController* controller,
                            service_manager::Connector* connector);
   ~MediaDialogView() override;
 
@@ -50,7 +52,7 @@
   void Init() override;
   void WindowClosing() override;
 
-  MediaDialogController controller_;
+  MediaToolbarButtonController* const controller_;
 
   MediaNotificationListView* const active_sessions_view_;
 
diff --git a/chrome/browser/ui/views/global_media_controls/media_toolbar_button_view.cc b/chrome/browser/ui/views/global_media_controls/media_toolbar_button_view.cc
index 6608f03..38db83b 100644
--- a/chrome/browser/ui/views/global_media_controls/media_toolbar_button_view.cc
+++ b/chrome/browser/ui/views/global_media_controls/media_toolbar_button_view.cc
@@ -38,7 +38,7 @@
   if (MediaDialogView::IsShowing())
     MediaDialogView::HideDialog();
   else
-    MediaDialogView::ShowDialog(this, connector_);
+    MediaDialogView::ShowDialog(this, &controller_, connector_);
 }
 
 void MediaToolbarButtonView::Show() {
diff --git a/chrome/browser/ui/views/global_media_controls/media_toolbar_button_view.h b/chrome/browser/ui/views/global_media_controls/media_toolbar_button_view.h
index 87b9f55..4b002e3 100644
--- a/chrome/browser/ui/views/global_media_controls/media_toolbar_button_view.h
+++ b/chrome/browser/ui/views/global_media_controls/media_toolbar_button_view.h
@@ -6,6 +6,7 @@
 #define CHROME_BROWSER_UI_VIEWS_GLOBAL_MEDIA_CONTROLS_MEDIA_TOOLBAR_BUTTON_VIEW_H_
 
 #include "base/macros.h"
+#include "base/unguessable_token.h"
 #include "chrome/browser/ui/global_media_controls/media_toolbar_button_controller.h"
 #include "chrome/browser/ui/global_media_controls/media_toolbar_button_controller_delegate.h"
 #include "chrome/browser/ui/views/toolbar/toolbar_button.h"
@@ -37,7 +38,7 @@
   void UpdateIcon();
 
  private:
-  service_manager::Connector* connector_;
+  service_manager::Connector* const connector_;
   MediaToolbarButtonController controller_;
 
   DISALLOW_COPY_AND_ASSIGN(MediaToolbarButtonView);
diff --git a/chrome/browser/ui/views/outdated_upgrade_bubble_view.cc b/chrome/browser/ui/views/outdated_upgrade_bubble_view.cc
index eb3a907cc..d71ea49 100644
--- a/chrome/browser/ui/views/outdated_upgrade_bubble_view.cc
+++ b/chrome/browser/ui/views/outdated_upgrade_bubble_view.cc
@@ -12,6 +12,7 @@
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/ui/browser_dialogs.h"
 #include "chrome/browser/ui/views/chrome_layout_provider.h"
+#include "chrome/browser/ui/views/chrome_typography.h"
 #include "chrome/browser/upgrade_detector/upgrade_detector.h"
 #include "chrome/common/pref_names.h"
 #include "chrome/grit/chromium_strings.h"
@@ -21,6 +22,7 @@
 #include "ui/base/l10n/l10n_util.h"
 #include "ui/views/controls/label.h"
 #include "ui/views/layout/fill_layout.h"
+#include "ui/views/style/typography.h"
 #include "ui/views/widget/widget.h"
 #include "url/gurl.h"
 
@@ -152,15 +154,16 @@
 
 void OutdatedUpgradeBubbleView::Init() {
   SetLayoutManager(std::make_unique<views::FillLayout>());
-  views::Label* text_label =
-      new views::Label(l10n_util::GetStringUTF16(IDS_UPGRADE_BUBBLE_TEXT));
+  auto text_label = std::make_unique<views::Label>(
+      l10n_util::GetStringUTF16(IDS_UPGRADE_BUBBLE_TEXT),
+      views::style::CONTEXT_MESSAGE_BOX_BODY_TEXT, STYLE_SECONDARY);
   text_label->SetMultiLine(true);
   text_label->SetHorizontalAlignment(gfx::ALIGN_LEFT);
   text_label->SizeToFit(
       ChromeLayoutProvider::Get()->GetDistanceMetric(
           ChromeDistanceMetric::DISTANCE_BUBBLE_PREFERRED_WIDTH) -
       margins().width());
-  AddChildView(text_label);
+  AddChildView(std::move(text_label));
 }
 
 OutdatedUpgradeBubbleView::OutdatedUpgradeBubbleView(
diff --git a/chrome/browser/ui/views/overlay/mute_image_button.cc b/chrome/browser/ui/views/overlay/mute_image_button.cc
deleted file mode 100644
index 8c88ef08..0000000
--- a/chrome/browser/ui/views/overlay/mute_image_button.cc
+++ /dev/null
@@ -1,82 +0,0 @@
-// Copyright 2019 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chrome/browser/ui/views/overlay/mute_image_button.h"
-
-#include "chrome/app/vector_icons/vector_icons.h"
-#include "chrome/grit/generated_resources.h"
-#include "components/vector_icons/vector_icons.h"
-#include "third_party/skia/include/core/SkColor.h"
-#include "ui/base/l10n/l10n_util.h"
-#include "ui/gfx/color_palette.h"
-#include "ui/gfx/paint_vector_icon.h"
-#include "ui/views/vector_icons.h"
-
-namespace {
-
-const int kMuteImageSize = 22;
-
-constexpr SkColor kMuteIconColor = SK_ColorWHITE;
-
-}  // namespace
-
-namespace views {
-
-MuteImageButton::MuteImageButton(ButtonListener* listener)
-    : ImageButton(listener),
-      mute_image_(
-          gfx::CreateVectorIcon(kTabAudioIcon, kMuteImageSize, kMuteIconColor)),
-      unmute_image_(gfx::CreateVectorIcon(kTabAudioMutingIcon,
-                                          kMuteImageSize,
-                                          kMuteIconColor)) {
-  SetImageHorizontalAlignment(views::ImageButton::ALIGN_CENTER);
-  SetImageVerticalAlignment(views::ImageButton::ALIGN_MIDDLE);
-
-  // Accessibility.
-  SetFocusForPlatform();
-  const base::string16 mute_button_label(l10n_util::GetStringUTF16(
-      IDS_PICTURE_IN_PICTURE_MUTE_CONTROL_ACCESSIBLE_TEXT));
-  SetAccessibleName(mute_button_label);
-  SetInstallFocusRingOnFocus(true);
-}
-
-void MuteImageButton::SetMutedState(
-    OverlayWindowViews::MutedState muted_state) {
-  muted_state_ = muted_state;
-  switch (muted_state_) {
-    case OverlayWindowViews::kMuted:
-      SetImage(views::Button::STATE_NORMAL, unmute_image_);
-      SetTooltipText(l10n_util::GetStringUTF16(
-          IDS_PICTURE_IN_PICTURE_UNMUTE_CONTROL_TEXT));
-      break;
-    case OverlayWindowViews::kUnmuted:
-      SetImage(views::Button::STATE_NORMAL, mute_image_);
-      SetTooltipText(
-          l10n_util::GetStringUTF16(IDS_PICTURE_IN_PICTURE_MUTE_CONTROL_TEXT));
-      break;
-    case OverlayWindowViews::kNoAudio:
-      ToggleVisibility(false);
-  }
-  SchedulePaint();
-}
-
-gfx::Size MuteImageButton::GetLastVisibleSize() const {
-  return size().IsEmpty() ? last_visible_size_ : size();
-}
-
-void MuteImageButton::OnBoundsChanged(const gfx::Rect&) {
-  if (!size().IsEmpty())
-    last_visible_size_ = size();
-}
-
-void MuteImageButton::ToggleVisibility(bool is_visible) {
-  if (muted_state_ == OverlayWindowViews::kNoAudio && is_visible)
-    return;
-
-  layer()->SetVisible(is_visible);
-  SetEnabled(is_visible);
-  SetSize(is_visible ? GetLastVisibleSize() : gfx::Size());
-}
-
-}  // namespace views
diff --git a/chrome/browser/ui/views/overlay/mute_image_button.h b/chrome/browser/ui/views/overlay/mute_image_button.h
deleted file mode 100644
index c1bbcdc..0000000
--- a/chrome/browser/ui/views/overlay/mute_image_button.h
+++ /dev/null
@@ -1,46 +0,0 @@
-// Copyright 2019 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROME_BROWSER_UI_VIEWS_OVERLAY_MUTE_IMAGE_BUTTON_H_
-#define CHROME_BROWSER_UI_VIEWS_OVERLAY_MUTE_IMAGE_BUTTON_H_
-
-#include "chrome/browser/ui/views/overlay/overlay_window_views.h"
-#include "ui/views/controls/button/image_button.h"
-
-namespace views {
-
-// An image button representing a mute button.
-class MuteImageButton : public views::ImageButton {
- public:
-  explicit MuteImageButton(ButtonListener*);
-  ~MuteImageButton() override = default;
-
-  // Show mute/unmute image and update tooltip based on video muted status.
-  void SetMutedState(OverlayWindowViews::MutedState);
-
-  // Get button size when visible.
-  gfx::Size GetLastVisibleSize() const;
-
-  // Toggle visibility.
-  void ToggleVisibility(bool is_visible);
-
- protected:
-  // Overridden from views::View.
-  void OnBoundsChanged(const gfx::Rect& previous_bounds) override;
-
- private:
-  const gfx::ImageSkia mute_image_;
-  const gfx::ImageSkia unmute_image_;
-
-  OverlayWindowViews::MutedState muted_state_;
-
-  // Last visible size of the image button.
-  gfx::Size last_visible_size_;
-
-  DISALLOW_COPY_AND_ASSIGN(MuteImageButton);
-};
-
-}  // namespace views
-
-#endif  // CHROME_BROWSER_UI_VIEWS_OVERLAY_MUTE_IMAGE_BUTTON_H_
diff --git a/chrome/browser/ui/views/overlay/overlay_window_views.cc b/chrome/browser/ui/views/overlay/overlay_window_views.cc
index 049a0dc..39d6339 100644
--- a/chrome/browser/ui/views/overlay/overlay_window_views.cc
+++ b/chrome/browser/ui/views/overlay/overlay_window_views.cc
@@ -15,7 +15,6 @@
 #include "chrome/app/vector_icons/vector_icons.h"
 #include "chrome/browser/ui/views/overlay/back_to_tab_image_button.h"
 #include "chrome/browser/ui/views/overlay/close_image_button.h"
-#include "chrome/browser/ui/views/overlay/mute_image_button.h"
 #include "chrome/browser/ui/views/overlay/playback_image_button.h"
 #include "chrome/browser/ui/views/overlay/resize_handle_button.h"
 #include "chrome/browser/ui/views/overlay/skip_ad_label_button.h"
@@ -135,7 +134,6 @@
     OverlayWindowViews* window = static_cast<OverlayWindowViews*>(widget_);
     if (window->AreControlsVisible() &&
         (window->GetBackToTabControlsBounds().Contains(point) ||
-         window->GetMuteControlsBounds().Contains(point) ||
          window->GetSkipAdControlsBounds().Contains(point) ||
          window->GetCloseControlsBounds().Contains(point) ||
          window->GetPlayPauseControlsBounds().Contains(point) ||
@@ -343,7 +341,6 @@
       this, vector_icons::kMediaNextTrackIcon,
       l10n_util::GetStringUTF16(
           IDS_PICTURE_IN_PICTURE_NEXT_TRACK_CONTROL_ACCESSIBLE_TEXT));
-  auto mute_controls_view = std::make_unique<views::MuteImageButton>(this);
   auto skip_ad_controls_view = std::make_unique<views::SkipAdLabelButton>(this);
 #if defined(OS_CHROMEOS)
   auto resize_handle_view = std::make_unique<views::ResizeHandleButton>(this);
@@ -398,12 +395,6 @@
   next_track_controls_view->layer()->SetFillsBoundsOpaquely(false);
   next_track_controls_view->layer()->set_name("NextTrackControlsView");
 
-  // views::View that holds the mute image button. ----------------------------
-  mute_controls_view->SetPaintToLayer(ui::LAYER_TEXTURED);
-  mute_controls_view->layer()->SetFillsBoundsOpaquely(false);
-  mute_controls_view->layer()->set_name("MuteControlsView");
-  mute_controls_view->SetMutedState(kNoAudio);
-
   // views::View that holds the skip-ad label button. -------------------------
   skip_ad_controls_view->SetPaintToLayer(ui::LAYER_TEXTURED);
   skip_ad_controls_view->layer()->SetFillsBoundsOpaquely(true);
@@ -433,8 +424,6 @@
       GetContentsView()->AddChildView(std::move(play_pause_controls_view));
   next_track_controls_view_ =
       GetContentsView()->AddChildView(std::move(next_track_controls_view));
-  mute_controls_view_ =
-      GetContentsView()->AddChildView(std::move(mute_controls_view));
   skip_ad_controls_view_ =
       GetContentsView()->AddChildView(std::move(skip_ad_controls_view));
 #if defined(OS_CHROMEOS)
@@ -499,7 +488,6 @@
 
   // We need to do more than usual visibility change because otherwise control
   // is accessible via accessibility tools.
-  mute_controls_view_->ToggleVisibility(is_visible);
   skip_ad_controls_view_->ToggleVisibility(is_visible && show_skip_ad_button_);
 
 #if defined(OS_CHROMEOS)
@@ -545,7 +533,6 @@
   // #2 Previous track
   // #3 Play/Pause
   // #4 Next track
-  // #5 Mute
   std::vector<views::ImageButton*> visible_controls_views;
   visible_controls_views.push_back(back_to_tab_controls_view_);
   if (show_previous_track_button_)
@@ -554,8 +541,6 @@
     visible_controls_views.push_back(play_pause_controls_view_);
   if (show_next_track_button_)
     visible_controls_views.push_back(next_track_controls_view_);
-  if (show_mute_button_)
-    visible_controls_views.push_back(mute_controls_view_);
 
   int mid_window_x = GetBounds().size().width() / 2;
   int primary_control_y = GetBounds().size().height() -
@@ -640,36 +625,6 @@
           secondary_control_y));
       return;
     }
-    case 5: {
-      /* | [ ] [ ] [ ] [ ] [ ] | */
-      visible_controls_views[0]->SetSize(kSecondaryControlSize);
-      visible_controls_views[0]->SetPosition(
-          gfx::Point(mid_window_x - kPrimaryControlSize.width() / 2 -
-                         kControlMargin * 2 - kSecondaryControlSize.width() * 2,
-                     secondary_control_y));
-
-      visible_controls_views[1]->SetSize(kSecondaryControlSize);
-      visible_controls_views[1]->SetPosition(
-          gfx::Point(mid_window_x - kPrimaryControlSize.width() / 2 -
-                         kControlMargin - kSecondaryControlSize.width(),
-                     secondary_control_y));
-
-      visible_controls_views[2]->SetSize(kPrimaryControlSize);
-      visible_controls_views[2]->SetPosition(gfx::Point(
-          mid_window_x - kPrimaryControlSize.width() / 2, primary_control_y));
-
-      visible_controls_views[3]->SetSize(kSecondaryControlSize);
-      visible_controls_views[3]->SetPosition(gfx::Point(
-          mid_window_x + kPrimaryControlSize.width() / 2 + kControlMargin,
-          secondary_control_y));
-
-      visible_controls_views[4]->SetSize(kSecondaryControlSize);
-      visible_controls_views[4]->SetPosition(
-          gfx::Point(mid_window_x + kPrimaryControlSize.width() / 2 +
-                         kControlMargin * 2 + kSecondaryControlSize.width(),
-                     secondary_control_y));
-      return;
-    }
   }
   DCHECK(false);
 }
@@ -754,16 +709,6 @@
   UpdateControlsBounds();
 }
 
-void OverlayWindowViews::SetMutedState(MutedState muted_state) {
-  if (muted_state_for_testing_ == muted_state)
-    return;
-
-  muted_state_for_testing_ = muted_state;
-  show_mute_button_ = (muted_state != kNoAudio);
-  mute_controls_view_->SetMutedState(muted_state);
-  UpdateControlsBounds();
-}
-
 void OverlayWindowViews::SetSkipAdButtonVisibility(bool is_visible) {
   show_skip_ad_button_ = is_visible;
 }
@@ -950,10 +895,6 @@
     controller_->CloseAndFocusInitiator();
     RecordTapGesture(OverlayWindowControl::kBackToTab);
     event->SetHandled();
-  } else if (GetMuteControlsBounds().Contains(event->location())) {
-    ToggleMute();
-    RecordTapGesture(OverlayWindowControl::kMute);
-    event->SetHandled();
   } else if (GetSkipAdControlsBounds().Contains(event->location())) {
     controller_->SkipAd();
     RecordTapGesture(OverlayWindowControl::kSkipAd);
@@ -984,11 +925,6 @@
     RecordButtonPressed(OverlayWindowControl::kBackToTab);
   }
 
-  if (sender == mute_controls_view_) {
-    ToggleMute();
-    RecordButtonPressed(OverlayWindowControl::kMute);
-  }
-
   if (sender == skip_ad_controls_view_) {
     controller_->SkipAd();
     RecordButtonPressed(OverlayWindowControl::kSkipAd);
@@ -1030,10 +966,6 @@
   return back_to_tab_controls_view_->GetMirroredBounds();
 }
 
-gfx::Rect OverlayWindowViews::GetMuteControlsBounds() {
-  return mute_controls_view_->GetMirroredBounds();
-}
-
 gfx::Rect OverlayWindowViews::GetSkipAdControlsBounds() {
   return skip_ad_controls_view_->GetMirroredBounds();
 }
@@ -1078,10 +1010,6 @@
   return back_to_tab_controls_view_->layer();
 }
 
-ui::Layer* OverlayWindowViews::GetMuteControlsLayer() {
-  return mute_controls_view_->layer();
-}
-
 ui::Layer* OverlayWindowViews::GetCloseControlsLayer() {
   return close_controls_view_->layer();
 }
@@ -1124,14 +1052,6 @@
   play_pause_controls_view_->SetPlaybackState(is_active ? kPlaying : kPaused);
 }
 
-void OverlayWindowViews::ToggleMute() {
-  // Retrieve expected active state based on what command was sent in
-  // ToggleMute() since the IPC message may not have been propagated
-  // the media player yet.
-  bool muted = controller_->ToggleMute();
-  mute_controls_view_->SetMutedState(muted ? kMuted : kUnmuted);
-}
-
 views::PlaybackImageButton*
 OverlayWindowViews::play_pause_controls_view_for_testing() const {
   return play_pause_controls_view_;
@@ -1160,10 +1080,6 @@
   return close_controls_view_->origin();
 }
 
-gfx::Point OverlayWindowViews::mute_image_position_for_testing() const {
-  return mute_controls_view_->origin();
-}
-
 #if defined(OS_CHROMEOS)
 gfx::Point OverlayWindowViews::resize_handle_position_for_testing() const {
   return resize_handle_view_->origin();
@@ -1175,11 +1091,6 @@
   return playback_state_for_testing_;
 }
 
-OverlayWindowViews::MutedState OverlayWindowViews::muted_state_for_testing()
-    const {
-  return muted_state_for_testing_;
-}
-
 ui::Layer* OverlayWindowViews::video_layer_for_testing() const {
   return video_view_->layer();
 }
diff --git a/chrome/browser/ui/views/overlay/overlay_window_views.h b/chrome/browser/ui/views/overlay/overlay_window_views.h
index 84fe557..a34d2197 100644
--- a/chrome/browser/ui/views/overlay/overlay_window_views.h
+++ b/chrome/browser/ui/views/overlay/overlay_window_views.h
@@ -19,7 +19,6 @@
 namespace views {
 class BackToTabImageButton;
 class CloseImageButton;
-class MuteImageButton;
 class PlaybackImageButton;
 class ResizeHandleButton;
 class SkipAdLabelButton;
@@ -49,7 +48,6 @@
   void UpdateVideoSize(const gfx::Size& natural_size) override;
   void SetPlaybackState(PlaybackState playback_state) override;
   void SetAlwaysHidePlayPauseButton(bool is_visible) override;
-  void SetMutedState(MutedState muted) override;
   void SetSkipAdButtonVisibility(bool is_visible) override;
   void SetNextTrackButtonVisibility(bool is_visible) override;
   void SetPreviousTrackButtonVisibility(bool is_visible) override;
@@ -74,7 +72,6 @@
 
   // Gets the bounds of the controls.
   gfx::Rect GetBackToTabControlsBounds();
-  gfx::Rect GetMuteControlsBounds();
   gfx::Rect GetSkipAdControlsBounds();
   gfx::Rect GetCloseControlsBounds();
   gfx::Rect GetResizeHandleControlsBounds();
@@ -96,10 +93,8 @@
   views::SkipAdLabelButton* skip_ad_controls_view_for_testing() const;
   gfx::Point back_to_tab_image_position_for_testing() const;
   gfx::Point close_image_position_for_testing() const;
-  gfx::Point mute_image_position_for_testing() const;
   gfx::Point resize_handle_position_for_testing() const;
   OverlayWindowViews::PlaybackState playback_state_for_testing() const;
-  OverlayWindowViews::MutedState muted_state_for_testing() const;
   ui::Layer* video_layer_for_testing() const;
   cc::Layer* GetLayerForTesting() override;
 
@@ -144,7 +139,6 @@
 
   ui::Layer* GetControlsScrimLayer();
   ui::Layer* GetBackToTabControlsLayer();
-  ui::Layer* GetMuteControlsLayer();
   ui::Layer* GetCloseControlsLayer();
   ui::Layer* GetResizeHandleLayer();
   ui::Layer* GetControlsParentLayer();
@@ -153,7 +147,7 @@
   // numeric values should never be reused.
   enum class OverlayWindowControl {
     kBackToTab = 0,
-    kMute,
+    kMuteDeprecated,
     kSkipAd,
     kClose,
     kPlayPause,
@@ -169,11 +163,6 @@
   // state.
   void TogglePlayPause();
 
-  // Toggles the mute control through the |controller_| and updates the
-  // |mute_controls_view_| toggled state to reflect the current muted
-  // state.
-  void ToggleMute();
-
   // Returns the current frame sink id for the surface displayed in the
   // |video_view_]. If |video_view_| is not currently displaying a surface then
   // returns nullptr.
@@ -222,7 +211,6 @@
   views::TrackImageButton* previous_track_controls_view_ = nullptr;
   views::PlaybackImageButton* play_pause_controls_view_ = nullptr;
   views::TrackImageButton* next_track_controls_view_ = nullptr;
-  views::MuteImageButton* mute_controls_view_ = nullptr;
   views::SkipAdLabelButton* skip_ad_controls_view_ = nullptr;
   views::ResizeHandleButton* resize_handle_view_ = nullptr;
 #if defined(OS_CHROMEOS)
@@ -239,14 +227,6 @@
   // used to toggle play/pause/replay button.
   PlaybackState playback_state_for_testing_ = kEndOfVideo;
 
-  // Current muted state on the video in Picture-in-Picture window. It is
-  // used to toggle mute button.
-  MutedState muted_state_for_testing_ = kNoAudio;
-
-  // Whether or not the mute button will be shown. This is not the case when
-  // there is no audio track.
-  bool show_mute_button_ = false;
-
   // Whether or not the skip ad button will be shown. This is the
   // case when Media Session "skipad" action is handled by the website.
   bool show_skip_ad_button_ = false;
diff --git a/chrome/browser/ui/views/sharing/click_to_call/click_to_call_icon_view.cc b/chrome/browser/ui/views/sharing/click_to_call/click_to_call_icon_view.cc
index e71ae5f..832c30d 100644
--- a/chrome/browser/ui/views/sharing/click_to_call/click_to_call_icon_view.cc
+++ b/chrome/browser/ui/views/sharing/click_to_call/click_to_call_icon_view.cc
@@ -40,10 +40,6 @@
   return ClickToCallUiController::GetOrCreateFromWebContents(web_contents);
 }
 
-base::Optional<int> ClickToCallIconView::GetSuccessMessageId() const {
-  return IDS_BROWSER_SHARING_CLICK_TO_CALL_DIALOG_SEND_SUCCESS;
-}
-
 base::string16 ClickToCallIconView::GetTextForTooltipAndAccessibleName() const {
   return l10n_util::GetStringUTF16(
       IDS_BROWSER_SHARING_CLICK_TO_CALL_DIALOG_TITLE_LABEL);
diff --git a/chrome/browser/ui/views/sharing/click_to_call/click_to_call_icon_view.h b/chrome/browser/ui/views/sharing/click_to_call/click_to_call_icon_view.h
index 737238a..57736b9 100644
--- a/chrome/browser/ui/views/sharing/click_to_call/click_to_call_icon_view.h
+++ b/chrome/browser/ui/views/sharing/click_to_call/click_to_call_icon_view.h
@@ -29,7 +29,6 @@
 
   // SharingIconView
   SharingUiController* GetController() const override;
-  base::Optional<int> GetSuccessMessageId() const override;
 
   DISALLOW_COPY_AND_ASSIGN(ClickToCallIconView);
 };
diff --git a/chrome/browser/ui/views/sharing/sharing_icon_view.cc b/chrome/browser/ui/views/sharing/sharing_icon_view.cc
index 54ec002..cc14924 100644
--- a/chrome/browser/ui/views/sharing/sharing_icon_view.cc
+++ b/chrome/browser/ui/views/sharing/sharing_icon_view.cc
@@ -5,18 +5,16 @@
 #include "chrome/browser/ui/views/sharing/sharing_icon_view.h"
 #include "chrome/app/vector_icons/vector_icons.h"
 #include "ui/gfx/paint_vector_icon.h"
-#include "ui/gfx/scoped_canvas.h"
+#include "ui/strings/grit/ui_strings.h"
 #include "ui/views/animation/ink_drop.h"
 
 namespace {
-// Height of the loader bar in DIP.
-constexpr float kLoaderHeight = 4.0f;
-// Width of the loader bar in percent of its range.
-constexpr float kLoaderWidth = 0.2f;
-
 // TODO(knollr): move these into IconLabelBubbleView.
 constexpr int kIconTextSpacing = 8;
 constexpr int kIconTextSpacingTouch = 10;
+
+// Progress state when the full length of the animation text is visible.
+constexpr double kAnimationTextFullLengthShownProgressState = 0.5;
 }  // namespace
 
 SharingIconView::SharingIconView(PageActionIconView::Delegate* delegate)
@@ -24,7 +22,6 @@
                          /*command_id=*/0,
                          delegate) {
   SetVisible(false);
-  UpdateLoaderColor();
   SetUpForInOutAnimation();
 }
 
@@ -33,30 +30,31 @@
 void SharingIconView::StartLoadingAnimation() {
   if (loading_animation_)
     return;
-  loading_animation_ = std::make_unique<gfx::ThrobAnimation>(this);
-  loading_animation_->SetTweenType(gfx::Tween::LINEAR);
-  loading_animation_->SetThrobDuration(750);
-  loading_animation_->StartThrobbing(-1);
+
+  loading_animation_ = true;
+  AnimateIn(IDS_BROWSER_SHARING_OMNIBOX_SENDING_LABEL);
   SchedulePaint();
 }
 
-void SharingIconView::StopLoadingAnimation(base::Optional<int> string_id) {
+void SharingIconView::StopLoadingAnimation() {
   if (!loading_animation_)
     return;
 
-  if (!should_show_error_)
-    AnimateIn(string_id);
-
-  loading_animation_.reset();
+  loading_animation_ = false;
+  UnpauseAnimation();
   SchedulePaint();
 }
 
+// TODO(knollr): Introduce IconState / ControllerState {eg, Hidden, Success,
+// Sending} to define the various cases instead of a number of if else
+// statements.
 bool SharingIconView::Update() {
   auto* controller = GetController();
   if (!controller)
     return false;
 
-  if (should_show_error() != controller->send_failed()) {
+  // To ensure that we reset error icon badge.
+  if (!GetVisible()) {
     set_should_show_error(controller->send_failed());
     UpdateIconImage();
   }
@@ -64,17 +62,15 @@
   if (controller->is_loading())
     StartLoadingAnimation();
   else
-    StopLoadingAnimation(GetSuccessMessageId());
+    StopLoadingAnimation();
 
-  const bool is_bubble_showing = IsBubbleShowing();
-
-  if (is_bubble_showing || IsLoadingAnimationVisible() ||
-      last_controller_ != controller) {
+  if (last_controller_ != controller) {
     ResetSlideAnimation(/*show=*/false);
   }
 
   last_controller_ = controller;
 
+  const bool is_bubble_showing = IsBubbleShowing();
   const bool is_visible =
       is_bubble_showing || IsLoadingAnimationVisible() || label()->GetVisible();
   const bool visibility_changed = GetVisible() != is_visible;
@@ -84,50 +80,6 @@
   return visibility_changed;
 }
 
-void SharingIconView::UpdateLoaderColor() {
-  loader_color_ = GetNativeTheme()->GetSystemColor(
-      ui::NativeTheme::kColorId_ProminentButtonColor);
-}
-
-void SharingIconView::OnThemeChanged() {
-  PageActionIconView::OnThemeChanged();
-  UpdateLoaderColor();
-}
-
-void SharingIconView::PaintButtonContents(gfx::Canvas* canvas) {
-  PageActionIconView::PaintButtonContents(canvas);
-  if (!loading_animation_)
-    return;
-
-  // TODO(knollr): Add support for this animation to PageActionIconView if other
-  // features need it as well.
-
-  gfx::ScopedCanvas scoped_canvas(canvas);
-  const float scale = canvas->UndoDeviceScaleFactor();
-  const gfx::Rect icon_bounds =
-      gfx::ScaleToEnclosedRect(image()->bounds(), scale);
-  const float progress = loading_animation_->GetCurrentValue();
-  const float range = icon_bounds.width();
-  const float offset = icon_bounds.x();
-
-  // Calculate start and end in percent of range.
-  float start = std::max(0.0f, (progress - kLoaderWidth) / (1 - kLoaderWidth));
-  float end = std::min(1.0f, progress / (1 - kLoaderWidth));
-  // Convert percentages to actual location.
-  const float size = kLoaderHeight * scale;
-  start = start * (range - size);
-  end = end * (range - size) + size;
-
-  gfx::RectF bounds(start + offset, icon_bounds.bottom() - size, end - start,
-                    size);
-
-  cc::PaintFlags flags;
-  flags.setAntiAlias(true);
-  flags.setStyle(cc::PaintFlags::kFill_Style);
-  flags.setColor(loader_color_);
-  canvas->DrawRoundRect(bounds, bounds.height() / 2, flags);
-}
-
 double SharingIconView::WidthMultiplier() const {
   double multiplier = PageActionIconView::WidthMultiplier();
 
@@ -145,16 +97,25 @@
 }
 
 void SharingIconView::AnimationProgressed(const gfx::Animation* animation) {
-  if (animation != loading_animation_.get()) {
-    UpdateOpacity();
-    return PageActionIconView::AnimationProgressed(animation);
+  if (animation->is_animating() &&
+      GetAnimationValue() >= kAnimationTextFullLengthShownProgressState &&
+      loading_animation_) {
+    PauseAnimation();
   }
-  SchedulePaint();
+  UpdateOpacity();
+  return PageActionIconView::AnimationProgressed(animation);
 }
 
 void SharingIconView::AnimationEnded(const gfx::Animation* animation) {
   PageActionIconView::AnimationEnded(animation);
   UpdateOpacity();
+
+  auto* controller = GetController();
+  if (controller && should_show_error() != controller->send_failed()) {
+    set_should_show_error(controller->send_failed());
+    UpdateIconImage();
+    controller->MaybeShowErrorDialog();
+  }
   Update();
 }
 
@@ -194,5 +155,5 @@
     PageActionIconView::ExecuteSource execute_source) {}
 
 bool SharingIconView::IsLoadingAnimationVisible() {
-  return loading_animation_.get();
+  return loading_animation_;
 }
diff --git a/chrome/browser/ui/views/sharing/sharing_icon_view.h b/chrome/browser/ui/views/sharing/sharing_icon_view.h
index d035357d..b3fe88c 100644
--- a/chrome/browser/ui/views/sharing/sharing_icon_view.h
+++ b/chrome/browser/ui/views/sharing/sharing_icon_view.h
@@ -9,10 +9,6 @@
 #include "chrome/browser/ui/views/page_action/page_action_icon_view.h"
 #include "third_party/skia/include/core/SkColor.h"
 
-namespace gfx {
-class Canvas;
-class ThrobAnimation;
-}  // namespace gfx
 
 // The location bar icon to show the sharing features bubble.
 class SharingIconView : public PageActionIconView {
@@ -21,13 +17,7 @@
   ~SharingIconView() override;
 
   void StartLoadingAnimation();
-  void StopLoadingAnimation(base::Optional<int> string_id);
-
-  // views::View:
-  void OnThemeChanged() override;
-
-  // views::Button:
-  void PaintButtonContents(gfx::Canvas* canvas) override;
+  void StopLoadingAnimation();
 
  protected:
   // PageActionIconView:
@@ -43,7 +33,6 @@
 
   void UpdateInkDrop(bool activate);
   void UpdateOpacity();
-  void UpdateLoaderColor();
   bool IsLoadingAnimationVisible();
   bool should_show_error() { return should_show_error_; }
   void set_should_show_error(bool should_show_error) {
@@ -52,14 +41,11 @@
 
   // Get the supporting controller for this icon view.
   virtual SharingUiController* GetController() const = 0;
-  // Return the success delivery message Id.
-  virtual base::Optional<int> GetSuccessMessageId() const = 0;
 
  private:
   SharingUiController* last_controller_ = nullptr;
-  std::unique_ptr<gfx::ThrobAnimation> loading_animation_;
+  bool loading_animation_ = false;
   bool should_show_error_ = false;
-  SkColor loader_color_;
 
   DISALLOW_COPY_AND_ASSIGN(SharingIconView);
 };
diff --git a/chrome/browser/ui/webui/settings/chromeos/date_time_handler.cc b/chrome/browser/ui/webui/settings/chromeos/date_time_handler.cc
index 087d86a..e2de1a9 100644
--- a/chrome/browser/ui/webui/settings/chromeos/date_time_handler.cc
+++ b/chrome/browser/ui/webui/settings/chromeos/date_time_handler.cc
@@ -16,6 +16,7 @@
 #include "chrome/browser/chromeos/set_time_dialog.h"
 #include "chrome/browser/chromeos/system/timezone_resolver_manager.h"
 #include "chrome/browser/chromeos/system/timezone_util.h"
+#include "chrome/common/chrome_features.h"
 #include "chrome/common/pref_names.h"
 #include "chromeos/constants/chromeos_switches.h"
 #include "chromeos/dbus/system_clock/system_clock_client.h"
@@ -76,6 +77,9 @@
   html_source->AddString(
       "timeZoneID",
       system::TimezoneSettings::GetInstance()->GetCurrentTimezoneID());
+  html_source->AddBoolean(
+      "timeActionsProtectedForChild",
+      base::FeatureList::IsEnabled(features::kParentAccessCodeForTimeChange));
 
   return new DateTimeHandler;
 }
diff --git a/chrome/browser/ui/webui/settings/settings_localized_strings_provider.cc b/chrome/browser/ui/webui/settings/settings_localized_strings_provider.cc
index 158ff09..61d1e49 100644
--- a/chrome/browser/ui/webui/settings/settings_localized_strings_provider.cc
+++ b/chrome/browser/ui/webui/settings/settings_localized_strings_provider.cc
@@ -1973,7 +1973,6 @@
      IDS_SETTINGS_PEOPLE_LOCK_SCREEN_FINGERPRINT_LESS_SECURE},
     {"lockScreenDeleteFingerprintLabel",
      IDS_SETTINGS_PEOPLE_LOCK_SCREEN_DELETE_FINGERPRINT_ARIA_LABEL},
-    {"lockScreenMediaControls", IDS_SETTINGS_PEOPLE_LOCK_SCREEN_MEDIA_CONTROLS},
     {"lockScreenNotificationHide",
      IDS_ASH_SETTINGS_LOCK_SCREEN_NOTIFICATION_HIDE},
     {"lockScreenNotificationHideSensitive",
diff --git a/chrome/browser/ui/webui/settings/settings_ui.cc b/chrome/browser/ui/webui/settings/settings_ui.cc
index a2d73594..3ea47f5 100644
--- a/chrome/browser/ui/webui/settings/settings_ui.cc
+++ b/chrome/browser/ui/webui/settings/settings_ui.cc
@@ -487,9 +487,6 @@
   html_source->AddBoolean(
       "lockScreenHideSensitiveNotificationsSupported",
       ash::features::IsLockScreenHideSensitiveNotificationsSupported());
-  html_source->AddBoolean(
-      "lockScreenMediaControlsEnabled",
-      base::FeatureList::IsEnabled(ash::features::kLockScreenMediaControls));
   html_source->AddBoolean("showTechnologyBadge",
                           !ash::features::IsSeparateNetworkIconsEnabled());
   html_source->AddBoolean("hasInternalStylus",
diff --git a/chrome/browser/unexpire_flags.cc b/chrome/browser/unexpire_flags.cc
new file mode 100644
index 0000000..d92c873
--- /dev/null
+++ b/chrome/browser/unexpire_flags.cc
@@ -0,0 +1,46 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/unexpire_flags.h"
+
+#include "chrome/browser/expired_flags_list.h"
+
+namespace flags {
+
+const base::Feature kUnexpireFlagsM76{"TemporaryUnexpireFlagsM76",
+                                      base::FEATURE_DISABLED_BY_DEFAULT};
+
+bool ExpiryEnabledForMstone(int mstone) {
+  // generate_expired_list.py will never emit flags with expiry milestone -1, to
+  // keep binary size down. However, if a bug *did* cause that to happen, and
+  // this function did not handle that case, disaster could ensue: all the -1
+  // flags that are supposed to never expire would in fact expire instantly,
+  // since -1 < x for any valid mstone x.
+  // As such, there's an extra error-check here: never allow flags with mstone
+  // -1 to expire.
+  DCHECK(mstone != -1);
+  if (mstone == -1)
+    return false;
+
+  // Currently expiration targets flags expiring in M76 or earlier. In M79 this
+  // will become M78 or earlier; in M80 it will become M80 or earlier, and in
+  // all future milestones Mx it will be Mx or earlier, so this logic will cease
+  // to hardcode a milestone and instead target the current major version.
+  if (mstone < 76)
+    return true;
+  if (mstone == 76)
+    return !base::FeatureList::IsEnabled(kUnexpireFlagsM76);
+  return false;
+}
+
+bool IsFlagExpired(const char* internal_name) {
+  for (int i = 0; kExpiredFlags[i].name; ++i) {
+    const ExpiredFlag* f = &kExpiredFlags[i];
+    if (!strcmp(f->name, internal_name) && ExpiryEnabledForMstone(f->mstone))
+      return true;
+  }
+  return false;
+}
+
+}  // namespace flags
diff --git a/chrome/browser/unexpire_flags.h b/chrome/browser/unexpire_flags.h
new file mode 100644
index 0000000..4ee8513
--- /dev/null
+++ b/chrome/browser/unexpire_flags.h
@@ -0,0 +1,18 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_UNEXPIRE_FLAGS_H_
+#define CHROME_BROWSER_UNEXPIRE_FLAGS_H_
+
+#include "base/feature_list.h"
+
+namespace flags {
+
+extern const base::Feature kUnexpireFlagsM76;
+
+bool IsFlagExpired(const char* internal_name);
+
+}  // namespace flags
+
+#endif  // CHROME_BROWSER_UNEXPIRE_FLAGS_H_
diff --git a/chrome/common/extensions/api/settings_private.idl b/chrome/common/extensions/api/settings_private.idl
index 68c058b..b4a1848d 100644
--- a/chrome/common/extensions/api/settings_private.idl
+++ b/chrome/common/extensions/api/settings_private.idl
@@ -23,7 +23,16 @@
     CHILD_RESTRICTION
   };
 
-  enum Enforcement { ENFORCED, RECOMMENDED };
+  enum Enforcement {
+    // Value cannot be changed by user.
+    ENFORCED,
+    // Value can be changed, but the administrator recommends a default.
+    RECOMMENDED,
+    // Value is protected by a code that only parents can access. The logic to
+    // require the code is NOT automatically added to a preference using this
+    // enforcement. This is only used to display the correct pref indicator.
+    PARENT_SUPERVISED
+  };
 
   dictionary PrefObject {
     // The key for the pref.
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn
index d02280c..b2dacade 100644
--- a/chrome/test/BUILD.gn
+++ b/chrome/test/BUILD.gn
@@ -3763,7 +3763,6 @@
       "../browser/ui/extensions/extension_action_view_controller_unittest.cc",
       "../browser/ui/extensions/extension_message_bubble_bridge_unittest.cc",
       "../browser/ui/global_error/global_error_service_unittest.cc",
-      "../browser/ui/global_media_controls/media_dialog_controller_unittest.cc",
       "../browser/ui/global_media_controls/media_toolbar_button_controller_unittest.cc",
       "../browser/ui/hid/hid_chooser_controller_unittest.cc",
       "../browser/ui/in_product_help/active_tab_tracker_unittest.cc",
@@ -4575,6 +4574,7 @@
       "../browser/safe_browsing/download_protection/binary_upload_service_unittest.cc",
       "../browser/safe_browsing/download_protection/download_feedback_service_unittest.cc",
       "../browser/safe_browsing/download_protection/download_feedback_unittest.cc",
+      "../browser/safe_browsing/download_protection/download_item_request_unittest.cc",
       "../browser/safe_browsing/download_protection/download_protection_service_unittest.cc",
       "../browser/safe_browsing/download_protection/file_analyzer_unittest.cc",
       "../browser/safe_browsing/download_protection/multipart_uploader_unittest.cc",
diff --git a/chrome/test/base/in_process_browser_test.cc b/chrome/test/base/in_process_browser_test.cc
index c96476c..6ec296d 100644
--- a/chrome/test/base/in_process_browser_test.cc
+++ b/chrome/test/base/in_process_browser_test.cc
@@ -450,6 +450,12 @@
 }
 #endif  // !defined(OS_MACOSX)
 
+void InProcessBrowserTest::SelectFirstBrowser() {
+  const BrowserList* browser_list = BrowserList::GetInstance();
+  if (!browser_list->empty())
+    browser_ = browser_list->get(0);
+}
+
 void InProcessBrowserTest::AddBlankTabAndShow(Browser* browser) {
   content::WindowedNotificationObserver observer(
       content::NOTIFICATION_LOAD_STOP,
@@ -498,9 +504,8 @@
   // Pump startup related events.
   content::RunAllPendingInMessageLoop();
 
-  const BrowserList* active_browser_list = BrowserList::GetInstance();
-  if (!active_browser_list->empty()) {
-    browser_ = active_browser_list->get(0);
+  SelectFirstBrowser();
+  if (browser_) {
 #if defined(OS_CHROMEOS)
     // There are cases where windows get created maximized by default.
     if (browser_->window()->IsMaximized())
diff --git a/chrome/test/base/in_process_browser_test.h b/chrome/test/base/in_process_browser_test.h
index db51b8d..020d928f 100644
--- a/chrome/test/base/in_process_browser_test.h
+++ b/chrome/test/base/in_process_browser_test.h
@@ -147,6 +147,9 @@
   }
 
   // Returns the browser created by BrowserMain().
+  // If no browser is created in BrowserMain(), this will return nullptr unless
+  // another browser instance is created at a later time and
+  // SelectFirstBrowser() is called.
   Browser* browser() const { return browser_; }
 
  protected:
@@ -223,6 +226,12 @@
   // the browser.
   Browser* CreateBrowserForApp(const std::string& app_name, Profile* profile);
 
+  // Set |browser_| to the first browser on the browser list.
+  // Call this when your test subclass wants to access a non-null browser
+  // instance through browser() but browser creation is delayed until after
+  // PreRunTestOnMainThread().
+  void SelectFirstBrowser();
+
   // Called from the various CreateBrowser methods to add a blank tab, wait for
   // the navigation to complete, and show the browser's window.
   void AddBlankTabAndShow(Browser* browser);
@@ -263,7 +272,10 @@
 
   static SetUpBrowserFunction* global_browser_set_up_function_;
 
-  // Browser created in BrowserMain().
+  // Usually references the browser created in BrowserMain().
+  // If no browser is created in BrowserMain(), then |browser_| will remain
+  // nullptr unless SelectFirstBrowser() is called after the creation of the
+  // first browser instance at a later time.
   Browser* browser_ = nullptr;
 
   // Used to run the process until the BrowserProcess signals the test to quit.
diff --git a/chrome/test/data/media/picture-in-picture/pixel_expected_pause_control.png b/chrome/test/data/media/picture-in-picture/pixel_expected_pause_control.png
index abb13a8..45f3e44 100644
--- a/chrome/test/data/media/picture-in-picture/pixel_expected_pause_control.png
+++ b/chrome/test/data/media/picture-in-picture/pixel_expected_pause_control.png
Binary files differ
diff --git a/chrome/test/data/media/picture-in-picture/pixel_expected_pause_control_crop.png b/chrome/test/data/media/picture-in-picture/pixel_expected_pause_control_crop.png
index 877f104..8107134 100644
--- a/chrome/test/data/media/picture-in-picture/pixel_expected_pause_control_crop.png
+++ b/chrome/test/data/media/picture-in-picture/pixel_expected_pause_control_crop.png
Binary files differ
diff --git a/chrome/test/data/media/picture-in-picture/pixel_expected_play_control.png b/chrome/test/data/media/picture-in-picture/pixel_expected_play_control.png
index c6e9b757b..45a6e1c4 100644
--- a/chrome/test/data/media/picture-in-picture/pixel_expected_play_control.png
+++ b/chrome/test/data/media/picture-in-picture/pixel_expected_play_control.png
Binary files differ
diff --git a/chrome/test/data/media/picture-in-picture/pixel_expected_play_control_crop.png b/chrome/test/data/media/picture-in-picture/pixel_expected_play_control_crop.png
index a055df07..5bfbcd2d 100644
--- a/chrome/test/data/media/picture-in-picture/pixel_expected_play_control_crop.png
+++ b/chrome/test/data/media/picture-in-picture/pixel_expected_play_control_crop.png
Binary files differ
diff --git a/chrome/test/data/media/picture-in-picture/window-size.html b/chrome/test/data/media/picture-in-picture/window-size.html
index d795263..5e82c24 100644
--- a/chrome/test/data/media/picture-in-picture/window-size.html
+++ b/chrome/test/data/media/picture-in-picture/window-size.html
@@ -123,12 +123,6 @@
     navigator.mediaSession.setActionHandler(name, null);
   }
 
-  function addVolumeChangeEventListener() {
-    video.addEventListener('volumechange', () => {
-      document.title = 'muted: ' + video.muted;
-    });
-  }
-
   function addPictureInPictureEventListeners() {
     video.addEventListener('enterpictureinpicture', () => {
       document.title = 'enterpictureinpicture';
diff --git a/chrome/test/data/webui/cr_elements/cr_elements_focus_test.js b/chrome/test/data/webui/cr_elements/cr_elements_focus_test.js
index f2b9377..1c3bc7b4 100644
--- a/chrome/test/data/webui/cr_elements/cr_elements_focus_test.js
+++ b/chrome/test/data/webui/cr_elements/cr_elements_focus_test.js
@@ -94,7 +94,8 @@
   ]),
 };
 
-TEST_F('CrElementsCheckboxTest', 'All', function() {
+// crbug.com/997943.
+TEST_F('CrElementsCheckboxTest', 'DISABLED_All', function() {
   mocha.run();
 });
 
diff --git a/chrome/test/data/webui/cr_elements/cr_elements_v3_focus_test.js b/chrome/test/data/webui/cr_elements/cr_elements_v3_focus_test.js
index e257c4c..f440d45 100644
--- a/chrome/test/data/webui/cr_elements/cr_elements_v3_focus_test.js
+++ b/chrome/test/data/webui/cr_elements/cr_elements_v3_focus_test.js
@@ -60,6 +60,6 @@
   }
 };
 
-TEST_F('CrElementsInputV3Test', 'All', function() {
+TEST_F('CrElementsInputV3Test', 'DISABLED_All', function() {
   mocha.run();
 });
diff --git a/chrome/test/data/webui/cr_elements/cr_policy_pref_indicator_tests.js b/chrome/test/data/webui/cr_elements/cr_policy_pref_indicator_tests.js
index 7bbdc96..b6af9ca 100644
--- a/chrome/test/data/webui/cr_elements/cr_policy_pref_indicator_tests.js
+++ b/chrome/test/data/webui/cr_elements/cr_policy_pref_indicator_tests.js
@@ -58,5 +58,13 @@
     indicator.set('pref.value', 'bar');
     Polymer.dom.flush();
     assertEquals('matches', icon.tooltipText);
+
+    indicator.set(
+        'pref.enforcement',
+        chrome.settingsPrivate.Enforcement.PARENT_SUPERVISED);
+    Polymer.dom.flush();
+    assertFalse(icon.hidden);
+    assertEquals('cr20:kite', icon.iconClass);
+    assertEquals(CrPolicyStrings.controlledSettingParent, icon.tooltipText);
   });
 });
diff --git a/chrome/test/data/webui/cr_elements/settings_private_test_constants.js b/chrome/test/data/webui/cr_elements/settings_private_test_constants.js
index cb281b1..00789b54 100644
--- a/chrome/test/data/webui/cr_elements/settings_private_test_constants.js
+++ b/chrome/test/data/webui/cr_elements/settings_private_test_constants.js
@@ -20,6 +20,7 @@
 chrome.settingsPrivate.Enforcement = {
   ENFORCED: 'ENFORCED',
   RECOMMENDED: 'RECOMMENDED',
+  PARENT_SUPERVISED: 'PARENT_SUPERVISED',
 };
 
 /** @enum {string} */
diff --git a/chrome/test/data/webui/settings/chromeos/quick_unlock_authenticate_browsertest_chromeos.js b/chrome/test/data/webui/settings/chromeos/quick_unlock_authenticate_browsertest_chromeos.js
index dc75ad8..5b71068 100644
--- a/chrome/test/data/webui/settings/chromeos/quick_unlock_authenticate_browsertest_chromeos.js
+++ b/chrome/test/data/webui/settings/chromeos/quick_unlock_authenticate_browsertest_chromeos.js
@@ -272,11 +272,6 @@
             key: 'ash.message_center.lock_screen_mode',
             type: chrome.settingsPrivate.PrefType.STRING,
             value: 'hide'
-          },
-          {
-            key: 'ash.lock_screen_media_controls_enabled',
-            type: chrome.settingsPrivate.PrefType.BOOLEAN,
-            value: true
           }
         ];
         fakeSettings = new settings.FakeSettingsPrivate(fakePrefs);
diff --git a/chromecast/media/cma/backend/android/java/src/org/chromium/chromecast/cma/backend/android/AudioSinkAudioTrackImpl.java b/chromecast/media/cma/backend/android/java/src/org/chromium/chromecast/cma/backend/android/AudioSinkAudioTrackImpl.java
index b4d01d8..25ac84b 100644
--- a/chromecast/media/cma/backend/android/java/src/org/chromium/chromecast/cma/backend/android/AudioSinkAudioTrackImpl.java
+++ b/chromecast/media/cma/backend/android/java/src/org/chromium/chromecast/cma/backend/android/AudioSinkAudioTrackImpl.java
@@ -137,6 +137,9 @@
     // Additional padding for minimum buffer time, determined experimentally.
     private static final long MIN_BUFFERED_TIME_PADDING_USEC = 120000;
 
+    // Max retries for AudioTrackBuilder
+    private static final int MAX_RETRIES_FOR_AUDIO_TRACKS = 1;
+
     private static AudioManager sAudioManager;
 
     private static int sSessionIdMedia = AudioManager.ERROR;
@@ -344,20 +347,24 @@
                         + " with session-id=" + sessionId);
 
         if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
-            AudioTrack.Builder builder = new AudioTrack.Builder();
-            builder.setBufferSizeInBytes(bufferSizeInBytes)
-                    .setTransferMode(AUDIO_MODE)
-                    .setAudioAttributes(new AudioAttributes.Builder()
-                                                .setUsage(usageType)
-                                                .setContentType(contentType)
-                                                .build())
-                    .setAudioFormat(new AudioFormat.Builder()
-                                            .setEncoding(AUDIO_FORMAT)
-                                            .setSampleRate(mSampleRateInHz)
-                                            .setChannelMask(CHANNEL_CONFIG)
-                                            .build());
-            if (sessionId != AudioManager.ERROR) builder.setSessionId(sessionId);
-            mAudioTrack = builder.build();
+            // Retry if AudioTrack creation fails.
+            int retries = 0;
+            do {
+                AudioTrack.Builder builder = new AudioTrack.Builder();
+                builder.setBufferSizeInBytes(bufferSizeInBytes)
+                        .setTransferMode(AUDIO_MODE)
+                        .setAudioAttributes(new AudioAttributes.Builder()
+                                                    .setUsage(usageType)
+                                                    .setContentType(contentType)
+                                                    .build())
+                        .setAudioFormat(new AudioFormat.Builder()
+                                                .setEncoding(AUDIO_FORMAT)
+                                                .setSampleRate(mSampleRateInHz)
+                                                .setChannelMask(CHANNEL_CONFIG)
+                                                .build());
+                if (sessionId != AudioManager.ERROR) builder.setSessionId(sessionId);
+                mAudioTrack = builder.build();
+            } while (mAudioTrack == null && retries++ < MAX_RETRIES_FOR_AUDIO_TRACKS);
         } else {
             // Using pre-M API.
             if (sessionId == AudioManager.ERROR) {
diff --git a/chromeos/dbus/fake_cicerone_client.cc b/chromeos/dbus/fake_cicerone_client.cc
index 83ea391..45fe2f7 100644
--- a/chromeos/dbus/fake_cicerone_client.cc
+++ b/chromeos/dbus/fake_cicerone_client.cc
@@ -192,6 +192,8 @@
     const vm_tools::cicerone::StartLxdContainerRequest& request,
     DBusMethodCallback<vm_tools::cicerone::StartLxdContainerResponse>
         callback) {
+  start_lxd_container_response_.mutable_os_release()->CopyFrom(
+      lxd_container_os_release_);
   base::ThreadTaskRunnerHandle::Get()->PostTask(
       FROM_HERE,
       base::BindOnce(std::move(callback), start_lxd_container_response_));
@@ -202,6 +204,7 @@
     signal.set_vm_name(request.vm_name());
     signal.set_container_name(request.container_name());
     signal.set_status(lxd_container_starting_signal_status_);
+    signal.mutable_os_release()->CopyFrom(lxd_container_os_release_);
     base::ThreadTaskRunnerHandle::Get()->PostTask(
         FROM_HERE,
         base::BindOnce(&FakeCiceroneClient::NotifyLxdContainerStarting,
diff --git a/chromeos/dbus/fake_cicerone_client.h b/chromeos/dbus/fake_cicerone_client.h
index 693ee0ef..23729c4f8 100644
--- a/chromeos/dbus/fake_cicerone_client.h
+++ b/chromeos/dbus/fake_cicerone_client.h
@@ -342,6 +342,10 @@
         std::move(cancel_import_lxd_container_response);
   }
 
+  void set_lxd_container_os_release(vm_tools::cicerone::OsRelease os_release) {
+    lxd_container_os_release_ = std::move(os_release);
+  }
+
   // Additional functions to allow tests to trigger Signals.
   void NotifyLxdContainerCreated(
       const vm_tools::cicerone::LxdContainerCreatedSignal& signal);
@@ -418,6 +422,8 @@
   vm_tools::cicerone::CancelImportLxdContainerResponse
       cancel_import_lxd_container_response_;
 
+  vm_tools::cicerone::OsRelease lxd_container_os_release_;
+
   UninstallPackageOwningFileCallback uninstall_package_owning_file_callback_;
 
   base::ObserverList<Observer>::Unchecked observer_list_;
diff --git a/components/BUILD.gn b/components/BUILD.gn
index 33773d1..2c3a0cae 100644
--- a/components/BUILD.gn
+++ b/components/BUILD.gn
@@ -558,7 +558,7 @@
 
     if (is_android) {
       sources += [
-        "autofill_assistant/browser/web_controller_browsertest.cc",
+        "autofill_assistant/browser/web/web_controller_browsertest.cc",
         "test/android/browsertests_apk/components_browser_tests_jni_onload.cc",
       ]
       sources -= [ "autofill/content/browser/risk/fingerprint_browsertest.cc" ]
diff --git a/components/autofill/core/browser/BUILD.gn b/components/autofill/core/browser/BUILD.gn
index 6a2ccc63..44b0525 100644
--- a/components/autofill/core/browser/BUILD.gn
+++ b/components/autofill/core/browser/BUILD.gn
@@ -162,8 +162,6 @@
     "metrics/form_event_logger_base.h",
     "metrics/form_events.h",
     "payments/account_info_getter.h",
-    "payments/autofill_wallet_data_type_controller.cc",
-    "payments/autofill_wallet_data_type_controller.h",
     "payments/autofill_wallet_model_type_controller.cc",
     "payments/autofill_wallet_model_type_controller.h",
     "payments/card_unmask_delegate.cc",
@@ -264,8 +262,6 @@
     "webdata/autofill_table_encryptor_factory.h",
     "webdata/autofill_wallet_metadata_sync_bridge.cc",
     "webdata/autofill_wallet_metadata_sync_bridge.h",
-    "webdata/autofill_wallet_metadata_syncable_service.cc",
-    "webdata/autofill_wallet_metadata_syncable_service.h",
     "webdata/autofill_wallet_sync_bridge.cc",
     "webdata/autofill_wallet_sync_bridge.h",
     "webdata/autofill_webdata_backend.h",
@@ -572,7 +568,6 @@
     "logging/log_buffer_unittest.cc",
     "logging/log_manager_unittest.cc",
     "logging/log_router_unittest.cc",
-    "payments/autofill_wallet_data_type_controller_unittest.cc",
     "payments/credit_card_access_manager_unittest.cc",
     "payments/credit_card_cvc_authenticator_unittest.cc",
     "payments/credit_card_save_manager_unittest.cc",
@@ -600,7 +595,6 @@
     "webdata/autofill_sync_bridge_util_unittest.cc",
     "webdata/autofill_table_unittest.cc",
     "webdata/autofill_wallet_metadata_sync_bridge_unittest.cc",
-    "webdata/autofill_wallet_metadata_syncable_service_unittest.cc",
     "webdata/autofill_wallet_sync_bridge_unittest.cc",
     "webdata/web_data_service_unittest.cc",
   ]
diff --git a/components/autofill/core/browser/payments/autofill_wallet_data_type_controller.cc b/components/autofill/core/browser/payments/autofill_wallet_data_type_controller.cc
deleted file mode 100644
index e10ace0..0000000
--- a/components/autofill/core/browser/payments/autofill_wallet_data_type_controller.cc
+++ /dev/null
@@ -1,105 +0,0 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "components/autofill/core/browser/payments/autofill_wallet_data_type_controller.h"
-
-#include <utility>
-
-#include "base/bind.h"
-#include "components/autofill/core/browser/personal_data_manager.h"
-#include "components/autofill/core/browser/webdata/autofill_webdata_service.h"
-#include "components/autofill/core/common/autofill_prefs.h"
-#include "components/prefs/pref_service.h"
-#include "components/sync/base/data_type_histogram.h"
-#include "components/sync/driver/sync_client.h"
-#include "components/sync/driver/sync_service.h"
-#include "components/sync/model/sync_error.h"
-#include "components/sync/model/syncable_service.h"
-
-namespace browser_sync {
-
-AutofillWalletDataTypeController::AutofillWalletDataTypeController(
-    syncer::ModelType type,
-    scoped_refptr<base::SequencedTaskRunner> db_thread,
-    const base::RepeatingClosure& dump_stack,
-    syncer::SyncService* sync_service,
-    syncer::SyncClient* sync_client,
-    const PersonalDataManagerProvider& pdm_provider,
-    const scoped_refptr<autofill::AutofillWebDataService>& web_data_service)
-    : AsyncDirectoryTypeController(type,
-                                   dump_stack,
-                                   sync_service,
-                                   sync_client,
-                                   syncer::GROUP_DB,
-                                   std::move(db_thread)),
-      pdm_provider_(pdm_provider),
-      callback_registered_(false),
-      web_data_service_(web_data_service),
-      currently_enabled_(IsEnabled()) {
-  DCHECK(type == syncer::AUTOFILL_WALLET_METADATA);
-  pref_registrar_.Init(sync_client->GetPrefService());
-  pref_registrar_.Add(
-      autofill::prefs::kAutofillWalletImportEnabled,
-      base::BindRepeating(&AutofillWalletDataTypeController::OnUserPrefChanged,
-                          base::Unretained(this)));
-  pref_registrar_.Add(
-      autofill::prefs::kAutofillCreditCardEnabled,
-      base::BindRepeating(&AutofillWalletDataTypeController::OnUserPrefChanged,
-                          base::AsWeakPtr(this)));
-}
-
-AutofillWalletDataTypeController::~AutofillWalletDataTypeController() {}
-
-bool AutofillWalletDataTypeController::StartModels() {
-  DCHECK(CalledOnValidThread());
-  DCHECK_EQ(state(), MODEL_STARTING);
-
-  if (!IsEnabled())
-    return false;
-
-  if (!web_data_service_)
-    return false;
-
-  if (web_data_service_->IsDatabaseLoaded())
-    return true;
-
-  if (!callback_registered_) {
-    web_data_service_->RegisterDBLoadedCallback(
-        base::BindRepeating(&AutofillWalletDataTypeController::OnModelLoaded,
-                            base::AsWeakPtr(this)));
-    callback_registered_ = true;
-  }
-
-  return false;
-}
-
-syncer::DataTypeController::PreconditionState
-AutofillWalletDataTypeController::GetPreconditionState() const {
-  DCHECK(CalledOnValidThread());
-  return currently_enabled_ ? PreconditionState::kPreconditionsMet
-                            : PreconditionState::kMustStopAndClearData;
-}
-
-void AutofillWalletDataTypeController::OnUserPrefChanged() {
-  DCHECK(CalledOnValidThread());
-
-  bool new_enabled = IsEnabled();
-  if (currently_enabled_ == new_enabled)
-    return;  // No change to sync state.
-  currently_enabled_ = new_enabled;
-
-  sync_service()->DataTypePreconditionChanged(type());
-}
-
-bool AutofillWalletDataTypeController::IsEnabled() {
-  DCHECK(CalledOnValidThread());
-
-  // Require the user-visible pref to be enabled to sync Wallet data/metadata.
-  return sync_client()->GetPrefService()->GetBoolean(
-             autofill::prefs::kAutofillWalletImportEnabled) &&
-         sync_client()->GetPrefService()->GetBoolean(
-             autofill::prefs::kAutofillCreditCardEnabled);
-}
-
-}  // namespace browser_sync
diff --git a/components/autofill/core/browser/payments/autofill_wallet_data_type_controller.h b/components/autofill/core/browser/payments/autofill_wallet_data_type_controller.h
deleted file mode 100644
index aab8cc2..0000000
--- a/components/autofill/core/browser/payments/autofill_wallet_data_type_controller.h
+++ /dev/null
@@ -1,77 +0,0 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef COMPONENTS_AUTOFILL_CORE_BROWSER_PAYMENTS_AUTOFILL_WALLET_DATA_TYPE_CONTROLLER_H_
-#define COMPONENTS_AUTOFILL_CORE_BROWSER_PAYMENTS_AUTOFILL_WALLET_DATA_TYPE_CONTROLLER_H_
-
-#include "base/callback.h"
-#include "base/macros.h"
-#include "base/sequenced_task_runner.h"
-#include "components/prefs/pref_change_registrar.h"
-#include "components/sync/driver/async_directory_type_controller.h"
-
-namespace autofill {
-class AutofillWebDataService;
-class PersonalDataManager;
-}  // namespace autofill
-
-namespace syncer {
-class SyncClient;
-class SyncService;
-}  // namespace syncer
-
-namespace browser_sync {
-
-// Controls syncing of AUTOFILL_WALLET_METADATA.
-class AutofillWalletDataTypeController
-    : public syncer::AsyncDirectoryTypeController {
- public:
-  using PersonalDataManagerProvider =
-      base::RepeatingCallback<autofill::PersonalDataManager*()>;
-
-  // |type| should be AUTOFILL_WALLET_METADATA.
-  // |dump_stack| is called when an unrecoverable error occurs.
-  AutofillWalletDataTypeController(
-      syncer::ModelType type,
-      scoped_refptr<base::SequencedTaskRunner> db_thread,
-      const base::RepeatingClosure& dump_stack,
-      syncer::SyncService* sync_service,
-      syncer::SyncClient* sync_client,
-      const PersonalDataManagerProvider& pdm_provider,
-      const scoped_refptr<autofill::AutofillWebDataService>& web_data_service);
-  ~AutofillWalletDataTypeController() override;
-
-  // AsyncDirectoryTypeController implementation.
-  bool StartModels() override;
-  PreconditionState GetPreconditionState() const override;
-
- private:
-  // Callback for changes to the autofill pref.
-  void OnUserPrefChanged();
-
-  // Returns true if the prefs are set such that wallet sync should be enabled.
-  bool IsEnabled();
-
-  // Callback that allows accessing PersonalDataManager lazily.
-  const PersonalDataManagerProvider pdm_provider_;
-
-  // Whether the database loaded callback has been registered.
-  bool callback_registered_;
-
-  // A reference to the AutofillWebDataService for this controller.
-  scoped_refptr<autofill::AutofillWebDataService> web_data_service_;
-
-  // Stores whether we're currently syncing wallet data. This is the last
-  // value computed by IsEnabled.
-  bool currently_enabled_;
-
-  // Registrar for listening to kAutofillWalletSyncExperimentEnabled status.
-  PrefChangeRegistrar pref_registrar_;
-
-  DISALLOW_COPY_AND_ASSIGN(AutofillWalletDataTypeController);
-};
-
-}  // namespace browser_sync
-
-#endif  // COMPONENTS_AUTOFILL_CORE_BROWSER_PAYMENTS_AUTOFILL_WALLET_DATA_TYPE_CONTROLLER_H_
diff --git a/components/autofill/core/browser/payments/autofill_wallet_data_type_controller_unittest.cc b/components/autofill/core/browser/payments/autofill_wallet_data_type_controller_unittest.cc
deleted file mode 100644
index 4586d28..0000000
--- a/components/autofill/core/browser/payments/autofill_wallet_data_type_controller_unittest.cc
+++ /dev/null
@@ -1,257 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "components/autofill/core/browser/payments/autofill_wallet_data_type_controller.h"
-
-#include <memory>
-
-#include "base/bind.h"
-#include "base/bind_helpers.h"
-#include "base/callback.h"
-#include "base/memory/ref_counted.h"
-#include "base/memory/weak_ptr.h"
-#include "base/run_loop.h"
-#include "base/single_thread_task_runner.h"
-#include "base/test/task_environment.h"
-#include "base/threading/thread.h"
-#include "base/threading/thread_task_runner_handle.h"
-#include "components/autofill/core/browser/webdata/autofill_webdata_service.h"
-#include "components/autofill/core/common/autofill_prefs.h"
-#include "components/prefs/pref_registry_simple.h"
-#include "components/prefs/pref_service.h"
-#include "components/prefs/testing_pref_service.h"
-#include "components/sync/driver/configure_context.h"
-#include "components/sync/driver/data_type_controller_mock.h"
-#include "components/sync/driver/fake_generic_change_processor.h"
-#include "components/sync/driver/mock_sync_service.h"
-#include "components/sync/driver/sync_client_mock.h"
-#include "components/sync/driver/sync_service.h"
-#include "components/sync/model/fake_syncable_service.h"
-#include "components/sync/model/sync_error.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace browser_sync {
-
-namespace {
-
-using autofill::AutofillWebDataService;
-using testing::_;
-using testing::Return;
-
-// Fake WebDataService implementation that stubs out the database loading.
-class FakeWebDataService : public AutofillWebDataService {
- public:
-  FakeWebDataService(
-      const scoped_refptr<base::SingleThreadTaskRunner>& ui_task_runner,
-      const scoped_refptr<base::SingleThreadTaskRunner>& db_task_runner)
-      : AutofillWebDataService(ui_task_runner, db_task_runner),
-        is_database_loaded_(false),
-        db_loaded_callback_(base::RepeatingCallback<void(void)>()) {}
-
-  // Mark the database as loaded and send out the appropriate notification.
-  void LoadDatabase() {
-    is_database_loaded_ = true;
-
-    if (!db_loaded_callback_.is_null()) {
-      db_loaded_callback_.Run();
-      // Clear the callback here or the WDS and DTC will have refs to each other
-      // and create a memory leak.
-      // TODO(crbug.com/941530): Solve this with a OnceCallback. Note that
-      //     RegisterDBLoadedCallback overrides other functions that still use
-      //     base::[Repeating]Callbacks, so it would affect non-Autofill code.
-      db_loaded_callback_ = base::RepeatingCallback<void(void)>();
-    }
-  }
-
-  bool IsDatabaseLoaded() override { return is_database_loaded_; }
-
-  void RegisterDBLoadedCallback(
-      const base::RepeatingCallback<void(void)>& callback) override {
-    db_loaded_callback_ = callback;
-  }
-
- private:
-  ~FakeWebDataService() override {}
-
-  bool is_database_loaded_;
-  base::RepeatingCallback<void(void)> db_loaded_callback_;
-
-  DISALLOW_COPY_AND_ASSIGN(FakeWebDataService);
-};
-
-class AutofillWalletDataTypeControllerTest : public testing::Test {
- public:
-  AutofillWalletDataTypeControllerTest() : last_type_(syncer::UNSPECIFIED) {
-    ON_CALL(sync_service_, GetUserShare()).WillByDefault(Return(&user_share_));
-  }
-
-  ~AutofillWalletDataTypeControllerTest() override {}
-
-  void SetUp() override {
-    prefs_.registry()->RegisterBooleanPref(
-        autofill::prefs::kAutofillWalletImportEnabled, true);
-    prefs_.registry()->RegisterBooleanPref(
-        autofill::prefs::kAutofillCreditCardEnabled, true);
-
-    ON_CALL(sync_client_, GetPrefService()).WillByDefault(Return(&prefs_));
-    ON_CALL(sync_client_, GetSyncableServiceForType(_))
-        .WillByDefault(Return(syncable_service_.AsWeakPtr()));
-
-    web_data_service_ = base::MakeRefCounted<FakeWebDataService>(
-        base::ThreadTaskRunnerHandle::Get(),
-        base::ThreadTaskRunnerHandle::Get());
-    autofill_wallet_dtc_ = std::make_unique<AutofillWalletDataTypeController>(
-        syncer::AUTOFILL_WALLET_METADATA, base::ThreadTaskRunnerHandle::Get(),
-        /*dump_stack=*/base::DoNothing(), &sync_service_, &sync_client_,
-        AutofillWalletDataTypeController::PersonalDataManagerProvider(),
-        web_data_service_);
-
-    last_type_ = syncer::UNSPECIFIED;
-    last_error_ = syncer::SyncError();
-  }
-
-  void TearDown() override {
-    // Make sure WebDataService is shutdown properly on DB thread before we
-    // destroy it.
-    // Must be done before we pump the loop.
-    syncable_service_.StopSyncing(syncer::AUTOFILL_WALLET_METADATA);
-  }
-
- protected:
-  void SetStartExpectations() {
-    autofill_wallet_dtc_->SetGenericChangeProcessorFactoryForTest(
-        std::make_unique<syncer::FakeGenericChangeProcessorFactory>(
-            std::make_unique<syncer::FakeGenericChangeProcessor>(
-                syncer::AUTOFILL_WALLET_METADATA)));
-  }
-
-  bool Start() {
-    autofill_wallet_dtc_->LoadModels(
-        syncer::ConfigureContext(),
-        base::BindRepeating(
-            &AutofillWalletDataTypeControllerTest::OnLoadFinished,
-            base::Unretained(this)));
-    base::RunLoop().RunUntilIdle();
-    if (autofill_wallet_dtc_->state() !=
-        syncer::DataTypeController::MODEL_LOADED) {
-      return false;
-    }
-    autofill_wallet_dtc_->StartAssociating(base::BindRepeating(
-        &syncer::StartCallbackMock::Run, base::Unretained(&start_callback_)));
-    base::RunLoop().RunUntilIdle();
-    return true;
-  }
-
-  void OnLoadFinished(syncer::ModelType type, const syncer::SyncError& error) {
-    last_type_ = type;
-    last_error_ = error;
-  }
-
-  base::test::TaskEnvironment task_environment_;
-  TestingPrefServiceSimple prefs_;
-  syncer::UserShare user_share_;
-  testing::NiceMock<syncer::MockSyncService> sync_service_;
-  syncer::StartCallbackMock start_callback_;
-  syncer::FakeSyncableService syncable_service_;
-  std::unique_ptr<AutofillWalletDataTypeController> autofill_wallet_dtc_;
-  scoped_refptr<FakeWebDataService> web_data_service_;
-  testing::NiceMock<syncer::SyncClientMock> sync_client_;
-
-  syncer::ModelType last_type_;
-  syncer::SyncError last_error_;
-};
-
-TEST_F(AutofillWalletDataTypeControllerTest, StartDatatypeEnabled) {
-  SetStartExpectations();
-  web_data_service_->LoadDatabase();
-  EXPECT_CALL(start_callback_,
-              Run(syncer::DataTypeController::OK, testing::_, testing::_));
-
-  EXPECT_EQ(syncer::DataTypeController::NOT_RUNNING,
-            autofill_wallet_dtc_->state());
-  Start();
-  EXPECT_FALSE(last_error_.IsSet());
-  EXPECT_EQ(syncer::AUTOFILL_WALLET_METADATA, last_type_);
-  EXPECT_EQ(syncer::DataTypeController::RUNNING, autofill_wallet_dtc_->state());
-}
-
-TEST_F(AutofillWalletDataTypeControllerTest,
-       DatatypeDisabledByWalletImportWhileRunning) {
-  SetStartExpectations();
-  web_data_service_->LoadDatabase();
-  EXPECT_CALL(start_callback_,
-              Run(syncer::DataTypeController::OK, testing::_, testing::_));
-
-  EXPECT_EQ(syncer::DataTypeController::NOT_RUNNING,
-            autofill_wallet_dtc_->state());
-  Start();
-  EXPECT_EQ(syncer::DataTypeController::RUNNING, autofill_wallet_dtc_->state());
-  EXPECT_FALSE(last_error_.IsSet());
-  EXPECT_EQ(syncer::AUTOFILL_WALLET_METADATA, last_type_);
-
-  EXPECT_CALL(sync_service_,
-              DataTypePreconditionChanged(syncer::AUTOFILL_WALLET_METADATA));
-  autofill::prefs::SetPaymentsIntegrationEnabled(&prefs_, false);
-  autofill::prefs::SetCreditCardAutofillEnabled(&prefs_, true);
-  EXPECT_EQ(
-      syncer::DataTypeController::PreconditionState::kMustStopAndClearData,
-      autofill_wallet_dtc_->GetPreconditionState());
-  base::RunLoop().RunUntilIdle();
-}
-
-TEST_F(AutofillWalletDataTypeControllerTest,
-       DatatypeDisabledByCreditCardsWhileRunning) {
-  SetStartExpectations();
-  web_data_service_->LoadDatabase();
-  EXPECT_CALL(start_callback_,
-              Run(syncer::DataTypeController::OK, testing::_, testing::_));
-
-  EXPECT_EQ(syncer::DataTypeController::NOT_RUNNING,
-            autofill_wallet_dtc_->state());
-  Start();
-  EXPECT_EQ(syncer::DataTypeController::RUNNING, autofill_wallet_dtc_->state());
-  EXPECT_FALSE(last_error_.IsSet());
-  EXPECT_EQ(syncer::AUTOFILL_WALLET_METADATA, last_type_);
-
-  EXPECT_CALL(sync_service_,
-              DataTypePreconditionChanged(syncer::AUTOFILL_WALLET_METADATA));
-  autofill::prefs::SetPaymentsIntegrationEnabled(&prefs_, true);
-  autofill::prefs::SetCreditCardAutofillEnabled(&prefs_, false);
-  EXPECT_EQ(
-      syncer::DataTypeController::PreconditionState::kMustStopAndClearData,
-      autofill_wallet_dtc_->GetPreconditionState());
-  base::RunLoop().RunUntilIdle();
-}
-
-TEST_F(AutofillWalletDataTypeControllerTest,
-       DatatypeDisabledByWalletImportAtStartup) {
-  SetStartExpectations();
-  web_data_service_->LoadDatabase();
-  autofill::prefs::SetPaymentsIntegrationEnabled(&prefs_, false);
-  autofill::prefs::SetCreditCardAutofillEnabled(&prefs_, true);
-  EXPECT_EQ(syncer::DataTypeController::NOT_RUNNING,
-            autofill_wallet_dtc_->state());
-  Start();
-  base::RunLoop().RunUntilIdle();
-  // OnLoadFinished() should not have been called.
-  EXPECT_EQ(syncer::UNSPECIFIED, last_type_);
-}
-
-TEST_F(AutofillWalletDataTypeControllerTest,
-       DatatypeDisabledByCreditCardsAtStartup) {
-  SetStartExpectations();
-  web_data_service_->LoadDatabase();
-  autofill::prefs::SetPaymentsIntegrationEnabled(&prefs_, true);
-  autofill::prefs::SetCreditCardAutofillEnabled(&prefs_, false);
-  EXPECT_EQ(syncer::DataTypeController::NOT_RUNNING,
-            autofill_wallet_dtc_->state());
-  Start();
-  base::RunLoop().RunUntilIdle();
-  // OnLoadFinished() should not have been called.
-  EXPECT_EQ(syncer::UNSPECIFIED, last_type_);
-}
-
-}  // namespace
-
-}  // namespace browser_sync
diff --git a/components/autofill/core/browser/webdata/autofill_wallet_metadata_syncable_service.cc b/components/autofill/core/browser/webdata/autofill_wallet_metadata_syncable_service.cc
deleted file mode 100644
index 2d97e51..0000000
--- a/components/autofill/core/browser/webdata/autofill_wallet_metadata_syncable_service.cc
+++ /dev/null
@@ -1,808 +0,0 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "components/autofill/core/browser/webdata/autofill_wallet_metadata_syncable_service.h"
-
-#include <stddef.h>
-
-#include <utility>
-#include <vector>
-
-#include "base/base64.h"
-#include "base/bind.h"
-#include "base/location.h"
-#include "base/logging.h"
-#include "base/memory/ptr_util.h"
-#include "base/metrics/histogram_macros.h"
-#include "base/numerics/safe_conversions.h"
-#include "base/time/time.h"
-#include "components/autofill/core/browser/data_model/autofill_data_model.h"
-#include "components/autofill/core/browser/data_model/autofill_profile.h"
-#include "components/autofill/core/browser/data_model/credit_card.h"
-#include "components/autofill/core/browser/webdata/autofill_change.h"
-#include "components/autofill/core/browser/webdata/autofill_table.h"
-#include "components/autofill/core/browser/webdata/autofill_webdata_backend.h"
-#include "components/autofill/core/browser/webdata/autofill_webdata_service.h"
-#include "components/autofill/core/common/autofill_clock.h"
-#include "components/autofill/core/common/autofill_util.h"
-#include "components/sync/model/sync_change.h"
-#include "components/sync/model/sync_change_processor.h"
-#include "components/sync/model/sync_data.h"
-#include "components/sync/model/sync_error_factory.h"
-#include "components/sync/protocol/sync.pb.h"
-
-namespace autofill {
-
-namespace {
-
-void* AutofillWalletMetadataSyncableServiceUserDataKey() {
-  // Use the address of a static so that COMDAT folding won't ever fold
-  // with something else.
-  static int user_data_key = 0;
-  return reinterpret_cast<void*>(&user_data_key);
-}
-
-// Sets the common syncable |metadata| for the |local_data_model|.
-void SetCommonMetadata(sync_pb::WalletMetadataSpecifics::Type type,
-                       const std::string& server_id,
-                       const AutofillDataModel& local_data_model,
-                       sync_pb::WalletMetadataSpecifics* metadata) {
-  metadata->set_type(type);
-  metadata->set_id(server_id);
-  metadata->set_use_count(local_data_model.use_count());
-  metadata->set_use_date(local_data_model.use_date().ToInternalValue());
-}
-
-// Returns syncable metadata for the |local_profile|.
-syncer::SyncData BuildSyncData(sync_pb::WalletMetadataSpecifics::Type type,
-                               const std::string& server_id,
-                               const AutofillProfile& local_profile) {
-  sync_pb::EntitySpecifics entity;
-  sync_pb::WalletMetadataSpecifics* metadata = entity.mutable_wallet_metadata();
-  SetCommonMetadata(type, server_id, local_profile, metadata);
-  metadata->set_address_has_converted(local_profile.has_converted());
-  std::string sync_tag = "address-" + server_id;
-
-  return syncer::SyncData::CreateLocalData(sync_tag, sync_tag, entity);
-}
-
-// Returns syncable metadata for the |local_card|.
-syncer::SyncData BuildSyncData(sync_pb::WalletMetadataSpecifics::Type type,
-                               const std::string& server_id,
-                               const CreditCard& local_card) {
-  sync_pb::EntitySpecifics entity;
-  sync_pb::WalletMetadataSpecifics* metadata = entity.mutable_wallet_metadata();
-  SetCommonMetadata(type, server_id, local_card, metadata);
-  // The strings must be in valid UTF-8 to sync.
-  std::string billing_address_id;
-  base::Base64Encode(local_card.billing_address_id(), &billing_address_id);
-  metadata->set_card_billing_address_id(billing_address_id);
-  std::string sync_tag = "card-" + server_id;
-
-  return syncer::SyncData::CreateLocalData(sync_tag, sync_tag, entity);
-}
-
-// If the metadata exists locally, undelete it on the sync server.
-template <class DataType>
-void UndeleteMetadataIfExisting(
-    const std::string& server_id,
-    const sync_pb::WalletMetadataSpecifics::Type& metadata_type,
-    std::unordered_map<std::string, std::unique_ptr<DataType>>* locals,
-    syncer::SyncChangeList* changes_to_sync) {
-  const auto& it = locals->find(server_id);
-  if (it != locals->end()) {
-    std::unique_ptr<DataType> local_metadata = std::move(it->second);
-    locals->erase(it);
-    changes_to_sync->push_back(syncer::SyncChange(
-        FROM_HERE, syncer::SyncChange::ACTION_ADD,
-        BuildSyncData(metadata_type, server_id, *local_metadata)));
-  }
-}
-
-syncer::SyncDataList::iterator FindServerIdAndTypeInCache(
-    const std::string& server_id,
-    const sync_pb::WalletMetadataSpecifics::Type& type,
-    syncer::SyncDataList* cache) {
-  for (auto it = cache->begin(); it != cache->end(); ++it) {
-    if (server_id == it->GetSpecifics().wallet_metadata().id() &&
-        type == it->GetSpecifics().wallet_metadata().type()) {
-      return it;
-    }
-  }
-
-  return cache->end();
-}
-
-syncer::SyncDataList::iterator FindItemInCache(const syncer::SyncData& item,
-                                               syncer::SyncDataList* cache) {
-  return FindServerIdAndTypeInCache(
-      item.GetSpecifics().wallet_metadata().id(),
-      item.GetSpecifics().wallet_metadata().type(), cache);
-}
-
-void RemoveItemFromCache(const syncer::SyncData& item,
-                         syncer::SyncDataList* cache) {
-  auto it = FindItemInCache(item, cache);
-  if (it != cache->end())
-    cache->erase(it);
-}
-
-void AddOrUpdateItemInCache(const syncer::SyncData& item,
-                            syncer::SyncDataList* cache) {
-  auto it = FindItemInCache(item, cache);
-  if (it != cache->end())
-    *it = item;
-  else
-    cache->push_back(item);
-}
-
-void ApplyChangesToCache(const syncer::SyncChangeList& changes,
-                         syncer::SyncDataList* cache) {
-  for (const syncer::SyncChange& change : changes) {
-    switch (change.change_type()) {
-      case syncer::SyncChange::ACTION_ADD:
-      // Intentional fall through.
-      case syncer::SyncChange::ACTION_UPDATE:
-        AddOrUpdateItemInCache(change.sync_data(), cache);
-        break;
-
-      case syncer::SyncChange::ACTION_DELETE:
-        RemoveItemFromCache(change.sync_data(), cache);
-        break;
-
-      case syncer::SyncChange::ACTION_INVALID:
-        NOTREACHED();
-        break;
-    }
-  }
-}
-
-template <class DataType>
-bool AreLocalUseStatsUpdated(const sync_pb::WalletMetadataSpecifics& remote,
-                             const DataType& local) {
-  return base::checked_cast<size_t>(remote.use_count()) < local.use_count() &&
-         base::Time::FromInternalValue(remote.use_date()) < local.use_date();
-}
-
-bool IsLocalBillingAddressUpdated(
-    const sync_pb::WalletMetadataSpecifics& remote,
-    const CreditCard& local) {
-  std::string remote_billing_address_id;
-  base::Base64Decode(remote.card_billing_address_id(),
-                     &remote_billing_address_id);
-  return local.billing_address_id() != remote_billing_address_id;
-}
-
-bool IsLocalHasConvertedStatusUpdated(
-    const sync_pb::WalletMetadataSpecifics& remote,
-    const AutofillProfile& local) {
-  return remote.address_has_converted() != local.has_converted();
-}
-
-// Merges the metadata of the remote and local versions of the data model.
-void MergeCommonMetadata(
-    const sync_pb::WalletMetadataSpecifics& remote_metadata,
-    AutofillDataModel* local_model,
-    bool* is_remote_outdated,
-    bool* is_local_modified) {
-  size_t remote_use_count =
-      base::checked_cast<size_t>(remote_metadata.use_count());
-  base::Time remote_use_date =
-      base::Time::FromInternalValue(remote_metadata.use_date());
-
-  // If the two models have the same metadata, do nothing.
-  if (local_model->use_count() == remote_use_count &&
-      local_model->use_date() == remote_use_date) {
-    return;
-  }
-
-  // Special case for local models with a use_count of one. This means the local
-  // model was only created, never used. The remote model should always be
-  // preferred.
-  // This situation can happen for new Chromium instances where there is no data
-  // yet on disk, making the use_date artifically high. Once the metadata sync
-  // kicks in, we should use that value.
-  if (local_model->use_count() == 1) {
-    local_model->set_use_date(remote_use_date);
-    local_model->set_use_count(remote_use_count);
-    *is_local_modified = true;
-  } else {
-    // Otherwise, just keep the most recent use date and biggest use count.
-    if (local_model->use_date() < remote_use_date) {
-      local_model->set_use_date(remote_use_date);
-      *is_local_modified = true;
-    } else if (local_model->use_date() > remote_use_date) {
-      *is_remote_outdated = true;
-    }
-
-    if (local_model->use_count() < remote_use_count) {
-      local_model->set_use_count(remote_use_count);
-      *is_local_modified = true;
-    } else if (local_model->use_count() > remote_use_count) {
-      *is_remote_outdated = true;
-    }
-  }
-}
-
-// Merges the metadata of the remote and local versions of the profile.
-void MergeMetadata(const sync_pb::WalletMetadataSpecifics& remote_metadata,
-                   AutofillProfile* local_profile,
-                   bool* is_remote_outdated,
-                   bool* is_local_modified) {
-  // Merge the has_converted status.
-  if (local_profile->has_converted() !=
-      remote_metadata.address_has_converted()) {
-    if (!local_profile->has_converted()) {
-      local_profile->set_has_converted(true);
-      *is_local_modified = true;
-    } else {
-      *is_remote_outdated = true;
-    }
-  }
-
-  // Merge the use_count and use_date.
-  MergeCommonMetadata(remote_metadata, local_profile, is_remote_outdated,
-                      is_local_modified);
-}
-
-// Whether the |current_billing_address_id| is considered outdated compared to
-// the |proposed_billing_address_id|.
-bool IsBillingAddressOutdated(const std::string& current_billing_address_id,
-                              const std::string& proposed_billing_address_id) {
-  DCHECK(current_billing_address_id != proposed_billing_address_id);
-
-  // If the current billing address is empty, or if the current one refers to a
-  // server address and the proposed one refers to a local address, the current
-  // billing address is considered outdated.
-  return current_billing_address_id.empty() ||
-         (current_billing_address_id.size() != kLocalGuidSize &&
-          proposed_billing_address_id.size() == kLocalGuidSize);
-}
-
-// Merges the metadata of the remote and local versions of the credit card.
-void MergeMetadata(const sync_pb::WalletMetadataSpecifics& remote_metadata,
-                   CreditCard* local_card,
-                   bool* is_remote_outdated,
-                   bool* is_local_modified) {
-  // Merge the billing_address_id. Do this before updating the use_count
-  // because it may be used to determine what id to keep.
-  std::string remote_billing_address_id;
-  base::Base64Decode(remote_metadata.card_billing_address_id(),
-                     &remote_billing_address_id);
-
-  if (local_card->billing_address_id() != remote_billing_address_id) {
-    if (IsBillingAddressOutdated(local_card->billing_address_id(),
-                                 remote_billing_address_id)) {
-      local_card->set_billing_address_id(remote_billing_address_id);
-      *is_local_modified = true;
-    } else if (IsBillingAddressOutdated(remote_billing_address_id,
-                                        local_card->billing_address_id())) {
-      *is_remote_outdated = true;
-    } else {
-      // The cards have a different non-empty billing address id and both refer
-      // to the same type of address. Keep the billing address id of the most
-      // recently used card. If both have the same timestamp, the remote version
-      // should be kept in order to stabilize the values.
-      base::Time remote_use_date =
-          base::Time::FromInternalValue(remote_metadata.use_date());
-      if (local_card->use_date() <= remote_use_date) {
-        local_card->set_billing_address_id(remote_billing_address_id);
-        *is_local_modified = true;
-      } else {
-        *is_remote_outdated = true;
-      }
-    }
-  }
-
-  // Merge the use_count and use_date.
-  MergeCommonMetadata(remote_metadata, local_card, is_remote_outdated,
-                      is_local_modified);
-}
-
-// Merges |remote| metadata into a collection of metadata |locals|. Returns true
-// if the corresponding local metadata was found.
-//
-// Stores an "update" in |changes_to_sync| if |remote| corresponds to an item in
-// |locals| that has higher use count and later use date.
-template <class DataType>
-bool MergeRemote(
-    const syncer::SyncData& remote,
-    const base::Callback<bool(const DataType&)>& updater,
-    bool* is_any_local_modified,
-    std::unordered_map<std::string, std::unique_ptr<DataType>>* locals,
-    syncer::SyncChangeList* changes_to_sync) {
-  DCHECK(locals);
-  DCHECK(changes_to_sync);
-
-  const sync_pb::WalletMetadataSpecifics& remote_metadata =
-      remote.GetSpecifics().wallet_metadata();
-  auto it = locals->find(remote_metadata.id());
-  if (it == locals->end())
-    return false;
-
-  std::unique_ptr<DataType> local_metadata = std::move(it->second);
-  locals->erase(it);
-
-  bool is_local_modified = false;
-  bool is_remote_outdated = false;
-  MergeMetadata(remote_metadata, local_metadata.get(), &is_remote_outdated,
-                &is_local_modified);
-
-  if (is_remote_outdated) {
-    changes_to_sync->push_back(syncer::SyncChange(
-        FROM_HERE, syncer::SyncChange::ACTION_UPDATE,
-        BuildSyncData(remote_metadata.type(), remote_metadata.id(),
-                      *local_metadata)));
-  }
-
-  if (is_local_modified) {
-    updater.Run(*local_metadata);
-    *is_any_local_modified = true;
-  }
-
-  return true;
-}
-
-template <typename DataType>
-std::string GetServerId(const DataType& data) {
-  std::string server_id;
-  base::Base64Encode(data.server_id(), &server_id);
-  return server_id;
-}
-
-}  // namespace
-
-AutofillWalletMetadataSyncableService::
-    ~AutofillWalletMetadataSyncableService() {}
-
-void AutofillWalletMetadataSyncableService::OnWalletDataTrackingStateChanged(
-    bool is_tracking) {
-  DCHECK_NE(track_wallet_data_, is_tracking);
-  track_wallet_data_ = is_tracking;
-  if (is_tracking && sync_processor_) {
-    MergeData(cache_);
-  }
-}
-
-void AutofillWalletMetadataSyncableService::WaitUntilReadyToSync(
-    base::OnceClosure done) {
-  // Not used in the legacy directory-based architecture.
-  NOTREACHED();
-}
-
-syncer::SyncMergeResult
-AutofillWalletMetadataSyncableService::MergeDataAndStartSyncing(
-    syncer::ModelType type,
-    const syncer::SyncDataList& initial_sync_data,
-    std::unique_ptr<syncer::SyncChangeProcessor> sync_processor,
-    std::unique_ptr<syncer::SyncErrorFactory> sync_error_factory) {
-  DCHECK(thread_checker_.CalledOnValidThread());
-  DCHECK(!sync_processor_);
-  DCHECK(!sync_error_factory_);
-  DCHECK_EQ(syncer::AUTOFILL_WALLET_METADATA, type);
-
-  sync_processor_ = std::move(sync_processor);
-  sync_error_factory_ = std::move(sync_error_factory);
-
-  cache_ = initial_sync_data;
-
-  syncer::SyncMergeResult result(syncer::AUTOFILL_WALLET_METADATA);
-  if (track_wallet_data_) {
-    result = MergeData(initial_sync_data);
-  }
-
-  // Record ages for individual metadata entities to UMA.
-  for (const syncer::SyncData& data : cache_) {
-    const sync_pb::WalletMetadataSpecifics& specifics =
-        data.GetSpecifics().wallet_metadata();
-    base::Time use_date = base::Time::FromDeltaSinceWindowsEpoch(
-        base::TimeDelta::FromMicroseconds(specifics.use_date()));
-    switch (specifics.type()) {
-      case sync_pb::WalletMetadataSpecifics::ADDRESS:
-        // TODO(crbug.com/949034): Consider adding standard functions for
-        // recording large times in seconds/minutes.
-        UMA_HISTOGRAM_CUSTOM_COUNTS(
-            "Autofill.WalletUseDateInMinutes.Address",
-            /*sample=*/(AutofillClock::Now() - use_date).InMinutes(),
-            /*min=*/base::TimeDelta::FromMinutes(1).InMinutes(),
-            /*max=*/base::TimeDelta::FromDays(365).InMinutes(),
-            /*bucket_count=*/50);
-        break;
-      case sync_pb::WalletMetadataSpecifics::CARD:
-        // TODO(crbug.com/949034): Consider adding standard functions for
-        // recording large times in seconds/minutes.
-        UMA_HISTOGRAM_CUSTOM_COUNTS(
-            "Autofill.WalletUseDateInMinutes.Card",
-            /*sample=*/(AutofillClock::Now() - use_date).InMinutes(),
-            /*min=*/base::TimeDelta::FromMinutes(1).InMinutes(),
-            /*max=*/base::TimeDelta::FromDays(365).InMinutes(),
-            /*bucket_count=*/50);
-        break;
-      case sync_pb::WalletMetadataSpecifics::UNKNOWN:
-        NOTREACHED();
-        break;
-    }
-  }
-
-  // Notify that sync has started. This callback does not currently take into
-  // account whether we're actually tracking wallet data.
-  if (web_data_backend_)
-    web_data_backend_->NotifyThatSyncHasStarted(type);
-  return result;
-}
-
-void AutofillWalletMetadataSyncableService::StopSyncing(
-    syncer::ModelType type) {
-  DCHECK(thread_checker_.CalledOnValidThread());
-  DCHECK_EQ(syncer::AUTOFILL_WALLET_METADATA, type);
-
-  sync_processor_.reset();
-  sync_error_factory_.reset();
-  cache_.clear();
-}
-
-syncer::SyncDataList AutofillWalletMetadataSyncableService::GetAllSyncData(
-    syncer::ModelType type) const {
-  DCHECK(thread_checker_.CalledOnValidThread());
-  DCHECK_EQ(syncer::AUTOFILL_WALLET_METADATA, type);
-
-  syncer::SyncDataList data_list;
-  std::unordered_map<std::string, std::unique_ptr<AutofillProfile>> profiles;
-  std::unordered_map<std::string, std::unique_ptr<CreditCard>> cards;
-  if (GetLocalData(&profiles, &cards)) {
-    for (const auto& it : profiles) {
-      data_list.push_back(BuildSyncData(
-          sync_pb::WalletMetadataSpecifics::ADDRESS, it.first, *it.second));
-    }
-
-    for (const auto& it : cards) {
-      data_list.push_back(BuildSyncData(sync_pb::WalletMetadataSpecifics::CARD,
-                                        it.first, *it.second));
-    }
-  }
-
-  return data_list;
-}
-
-syncer::SyncError AutofillWalletMetadataSyncableService::ProcessSyncChanges(
-    const base::Location& from_here,
-    const syncer::SyncChangeList& changes_from_sync) {
-  DCHECK(thread_checker_.CalledOnValidThread());
-
-  ApplyChangesToCache(changes_from_sync, &cache_);
-
-  // If we're not tracking wallet data, we can't rely on the local wallet
-  // data being up-to-date, so we should not do any merging with local data.
-  if (!track_wallet_data_) {
-    return syncer::SyncError();
-  }
-
-  std::unordered_map<std::string, std::unique_ptr<AutofillProfile>> profiles;
-  std::unordered_map<std::string, std::unique_ptr<CreditCard>> cards;
-  GetLocalData(&profiles, &cards);
-
-  // base::Unretained is used because the callbacks are invoked synchronously.
-  base::Callback<bool(const AutofillProfile&)> address_updater =
-      base::Bind(&AutofillWalletMetadataSyncableService::UpdateAddressStats,
-                 base::Unretained(this));
-  base::Callback<bool(const CreditCard&)> card_updater =
-      base::Bind(&AutofillWalletMetadataSyncableService::UpdateCardStats,
-                 base::Unretained(this));
-
-  bool is_any_local_modified = false;
-
-  syncer::SyncChangeList changes_to_sync;
-  for (const syncer::SyncChange& change : changes_from_sync) {
-    const sync_pb::WalletMetadataSpecifics& remote_metadata =
-        change.sync_data().GetSpecifics().wallet_metadata();
-    switch (change.change_type()) {
-      case syncer::SyncChange::ACTION_ADD:
-      // Intentional fall through.
-      case syncer::SyncChange::ACTION_UPDATE:
-        switch (remote_metadata.type()) {
-          case sync_pb::WalletMetadataSpecifics::ADDRESS:
-            MergeRemote(change.sync_data(), address_updater,
-                        &is_any_local_modified, &profiles, &changes_to_sync);
-            break;
-
-          case sync_pb::WalletMetadataSpecifics::CARD:
-            MergeRemote(change.sync_data(), card_updater,
-                        &is_any_local_modified, &cards, &changes_to_sync);
-            break;
-
-          case sync_pb::WalletMetadataSpecifics::UNKNOWN:
-            NOTREACHED();
-            break;
-        }
-        break;
-
-      // Metadata should only be deleted when the underlying data is deleted.
-      case syncer::SyncChange::ACTION_DELETE:
-        switch (remote_metadata.type()) {
-          case sync_pb::WalletMetadataSpecifics::ADDRESS:
-            UndeleteMetadataIfExisting(
-                remote_metadata.id(), sync_pb::WalletMetadataSpecifics::ADDRESS,
-                &profiles, &changes_to_sync);
-            break;
-
-          case sync_pb::WalletMetadataSpecifics::CARD:
-            UndeleteMetadataIfExisting(remote_metadata.id(),
-                                       sync_pb::WalletMetadataSpecifics::CARD,
-                                       &cards, &changes_to_sync);
-            break;
-
-          case sync_pb::WalletMetadataSpecifics::UNKNOWN:
-            NOTREACHED();
-            break;
-        }
-        break;
-
-      case syncer::SyncChange::ACTION_INVALID:
-        NOTREACHED();
-        break;
-    }
-  }
-
-  syncer::SyncError status;
-  if (!changes_to_sync.empty())
-    status = SendChangesToSyncServer(changes_to_sync);
-  if (is_any_local_modified) {
-    // TODO(crbug.com/900607): Remove the need to listen to
-    // AutofillMultipleChangedBySync() in the new USS implementation so that we
-    // can get rid of this hack.
-    DCHECK(!ignore_multiple_changed_notification_);
-    ignore_multiple_changed_notification_ = true;
-    web_data_backend_->NotifyOfMultipleAutofillChanges();
-    ignore_multiple_changed_notification_ = false;
-  }
-
-  return status;
-}
-
-void AutofillWalletMetadataSyncableService::AutofillProfileChanged(
-    const AutofillProfileChange& change) {
-  DCHECK(thread_checker_.CalledOnValidThread());
-  DCHECK(change.data_model());
-  if (!track_wallet_data_) {
-    return;
-  }
-
-  if (sync_processor_ && change.type() == AutofillProfileChange::UPDATE &&
-      change.data_model()->record_type() != AutofillProfile::LOCAL_PROFILE) {
-    std::string server_id = GetServerId(*change.data_model());
-    auto it = FindServerIdAndTypeInCache(
-        server_id, sync_pb::WalletMetadataSpecifics::ADDRESS, &cache_);
-    if (it == cache_.end())
-      return;
-
-    const sync_pb::WalletMetadataSpecifics& remote =
-        it->GetSpecifics().wallet_metadata();
-    const AutofillProfile& local = *change.data_model();
-
-
-    if (!AreLocalUseStatsUpdated(remote, local) &&
-        !IsLocalHasConvertedStatusUpdated(remote, local)) {
-      return;
-    }
-
-    SendChangesToSyncServer(syncer::SyncChangeList(
-        1, syncer::SyncChange(
-               FROM_HERE, syncer::SyncChange::ACTION_UPDATE,
-               BuildSyncData(sync_pb::WalletMetadataSpecifics::ADDRESS,
-                             server_id, local))));
-  }
-}
-
-void AutofillWalletMetadataSyncableService::CreditCardChanged(
-    const CreditCardChange& change) {
-  DCHECK(thread_checker_.CalledOnValidThread());
-  if (!track_wallet_data_) {
-    return;
-  }
-
-  if (sync_processor_ && change.data_model() &&
-      change.data_model()->record_type() != CreditCard::LOCAL_CARD) {
-    std::string server_id = GetServerId(*change.data_model());
-    auto it = FindServerIdAndTypeInCache(
-        server_id, sync_pb::WalletMetadataSpecifics::CARD, &cache_);
-    if (it == cache_.end())
-      return;
-    // Deletions and creations are treated by Wallet data sync (and propagated
-    // here by AutofillMultipleChangedBySync()). We only treat updates here.
-    if (change.type() != AutofillProfileChange::UPDATE) {
-      return;
-    }
-
-    const sync_pb::WalletMetadataSpecifics& remote =
-        it->GetSpecifics().wallet_metadata();
-    const CreditCard& local = *change.data_model();
-    if (!AreLocalUseStatsUpdated(remote, local) &&
-        !IsLocalBillingAddressUpdated(remote, local)) {
-      return;
-    }
-
-    SendChangesToSyncServer(syncer::SyncChangeList(
-        1,
-        syncer::SyncChange(FROM_HERE, syncer::SyncChange::ACTION_UPDATE,
-                           BuildSyncData(sync_pb::WalletMetadataSpecifics::CARD,
-                                         server_id, local))));
-  }
-}
-
-void AutofillWalletMetadataSyncableService::AutofillMultipleChangedBySync() {
-  if (ignore_multiple_changed_notification_) {
-    // TODO(crbug.com/900607): Remove the need to listen to
-    // AutofillMultipleChangedBySync() in the new USS implementation so that we
-    // can get rid of this hack.
-    return;
-  }
-
-  if (sync_processor_ && track_wallet_data_)
-    MergeData(cache_);
-}
-
-// static
-void AutofillWalletMetadataSyncableService::CreateForWebDataServiceAndBackend(
-    AutofillWebDataService* web_data_service,
-    AutofillWebDataBackend* web_data_backend,
-    const std::string& app_locale) {
-  web_data_service->GetDBUserData()->SetUserData(
-      AutofillWalletMetadataSyncableServiceUserDataKey(),
-      std::make_unique<AutofillWalletMetadataSyncableService>(web_data_backend,
-                                                              app_locale));
-}
-
-// static
-AutofillWalletMetadataSyncableService*
-AutofillWalletMetadataSyncableService::FromWebDataService(
-    AutofillWebDataService* web_data_service) {
-  return static_cast<AutofillWalletMetadataSyncableService*>(
-      web_data_service->GetDBUserData()->GetUserData(
-          AutofillWalletMetadataSyncableServiceUserDataKey()));
-}
-
-AutofillWalletMetadataSyncableService::AutofillWalletMetadataSyncableService(
-    AutofillWebDataBackend* web_data_backend,
-    const std::string& app_locale)
-    : web_data_backend_(web_data_backend),
-      scoped_observer_(this),
-      track_wallet_data_(false),
-      ignore_multiple_changed_notification_(false) {
-  scoped_observer_.Add(web_data_backend_);
-}
-
-bool AutofillWalletMetadataSyncableService::GetLocalData(
-    std::unordered_map<std::string, std::unique_ptr<AutofillProfile>>* profiles,
-    std::unordered_map<std::string, std::unique_ptr<CreditCard>>* cards) const {
-  std::vector<std::unique_ptr<AutofillProfile>> profile_list;
-  bool success =
-      AutofillTable::FromWebDatabase(web_data_backend_->GetDatabase())
-          ->GetServerProfiles(&profile_list);
-  while (!profile_list.empty()) {
-    auto server_id = GetServerId(*profile_list.front());
-    (*profiles)[server_id] = std::move(profile_list.front());
-    profile_list.erase(profile_list.begin());
-  }
-
-  std::vector<std::unique_ptr<CreditCard>> card_list;
-  success &= AutofillTable::FromWebDatabase(web_data_backend_->GetDatabase())
-                 ->GetServerCreditCards(&card_list);
-  while (!card_list.empty()) {
-    auto server_id = GetServerId(*card_list.front());
-    (*cards)[server_id] = std::move(card_list.front());
-    card_list.erase(card_list.begin());
-  }
-
-  return success;
-}
-
-bool AutofillWalletMetadataSyncableService::UpdateAddressStats(
-    const AutofillProfile& profile) {
-  return AutofillTable::FromWebDatabase(web_data_backend_->GetDatabase())
-      ->UpdateServerAddressMetadata(profile);
-}
-
-bool AutofillWalletMetadataSyncableService::UpdateCardStats(
-    const CreditCard& credit_card) {
-  return AutofillTable::FromWebDatabase(web_data_backend_->GetDatabase())
-      ->UpdateServerCardMetadata(credit_card);
-}
-
-syncer::SyncError
-AutofillWalletMetadataSyncableService::SendChangesToSyncServer(
-    const syncer::SyncChangeList& changes_to_sync) {
-  DCHECK(sync_processor_);
-  ApplyChangesToCache(changes_to_sync, &cache_);
-  return sync_processor_->ProcessSyncChanges(FROM_HERE, changes_to_sync);
-}
-
-syncer::SyncMergeResult AutofillWalletMetadataSyncableService::MergeData(
-    const syncer::SyncDataList& sync_data) {
-  // If we're not tracking wallet data, we can't rely on the local wallet
-  // data being up-to-date, so we should not do any merging with local data.
-  DCHECK(track_wallet_data_);
-
-  std::unordered_map<std::string, std::unique_ptr<AutofillProfile>> profiles;
-  std::unordered_map<std::string, std::unique_ptr<CreditCard>> cards;
-  GetLocalData(&profiles, &cards);
-
-  syncer::SyncMergeResult result(syncer::AUTOFILL_WALLET_METADATA);
-  result.set_num_items_before_association(profiles.size() + cards.size());
-
-  // base::Unretained is used because the callbacks are invoked synchronously.
-  base::Callback<bool(const AutofillProfile&)> address_updater =
-      base::Bind(&AutofillWalletMetadataSyncableService::UpdateAddressStats,
-                 base::Unretained(this));
-  base::Callback<bool(const CreditCard&)> card_updater =
-      base::Bind(&AutofillWalletMetadataSyncableService::UpdateCardStats,
-                 base::Unretained(this));
-
-  bool is_any_local_modified = false;
-
-  syncer::SyncChangeList changes_to_sync;
-  for (const syncer::SyncData& remote : sync_data) {
-    DCHECK(remote.IsValid());
-    DCHECK_EQ(syncer::AUTOFILL_WALLET_METADATA, remote.GetDataType());
-    switch (remote.GetSpecifics().wallet_metadata().type()) {
-      case sync_pb::WalletMetadataSpecifics::ADDRESS:
-        if (!MergeRemote(remote, address_updater, &is_any_local_modified,
-                         &profiles, &changes_to_sync)) {
-          changes_to_sync.push_back(syncer::SyncChange(
-              FROM_HERE, syncer::SyncChange::ACTION_DELETE, remote));
-        }
-        break;
-
-      case sync_pb::WalletMetadataSpecifics::CARD:
-        if (!MergeRemote(remote, card_updater, &is_any_local_modified, &cards,
-                         &changes_to_sync)) {
-          changes_to_sync.push_back(syncer::SyncChange(
-              FROM_HERE, syncer::SyncChange::ACTION_DELETE, remote));
-        }
-        break;
-
-      case sync_pb::WalletMetadataSpecifics::UNKNOWN:
-        NOTREACHED();
-        break;
-    }
-  }
-
-  // The remainder of |profiles| were not listed in |sync_data|.
-  for (const auto& it : profiles) {
-    changes_to_sync.push_back(syncer::SyncChange(
-        FROM_HERE, syncer::SyncChange::ACTION_ADD,
-        BuildSyncData(sync_pb::WalletMetadataSpecifics::ADDRESS, it.first,
-                      *it.second)));
-  }
-
-  // The remainder of |cards| were not listed in |sync_data|.
-  for (const auto& it : cards) {
-    changes_to_sync.push_back(
-        syncer::SyncChange(FROM_HERE, syncer::SyncChange::ACTION_ADD,
-                           BuildSyncData(sync_pb::WalletMetadataSpecifics::CARD,
-                                         it.first, *it.second)));
-  }
-
-  // The only operation that is performed locally in response to a sync is an
-  // update. Adds and deletes are performed in response to changes to the Wallet
-  // data.
-  result.set_num_items_after_association(result.num_items_before_association());
-  result.set_num_items_added(0);
-  result.set_num_items_deleted(0);
-
-  if (!changes_to_sync.empty())
-    result.set_error(SendChangesToSyncServer(changes_to_sync));
-  if (is_any_local_modified) {
-    // TODO(crbug.com/900607): Remove the need to listen to
-    // AutofillMultipleChangedBySync() in the new USS implementation so that we
-    // can get rid of this hack.
-    DCHECK(!ignore_multiple_changed_notification_);
-    ignore_multiple_changed_notification_ = true;
-    web_data_backend_->NotifyOfMultipleAutofillChanges();
-    ignore_multiple_changed_notification_ = false;
-  }
-
-  return result;
-}
-
-}  // namespace autofill
diff --git a/components/autofill/core/browser/webdata/autofill_wallet_metadata_syncable_service.h b/components/autofill/core/browser/webdata/autofill_wallet_metadata_syncable_service.h
deleted file mode 100644
index 25845d1..0000000
--- a/components/autofill/core/browser/webdata/autofill_wallet_metadata_syncable_service.h
+++ /dev/null
@@ -1,162 +0,0 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef COMPONENTS_AUTOFILL_CORE_BROWSER_WEBDATA_AUTOFILL_WALLET_METADATA_SYNCABLE_SERVICE_H_
-#define COMPONENTS_AUTOFILL_CORE_BROWSER_WEBDATA_AUTOFILL_WALLET_METADATA_SYNCABLE_SERVICE_H_
-
-#include <memory>
-#include <string>
-#include <unordered_map>
-
-#include "base/callback_forward.h"
-#include "base/macros.h"
-#include "base/scoped_observer.h"
-#include "base/supports_user_data.h"
-#include "base/threading/thread_checker.h"
-#include "components/autofill/core/browser/webdata/autofill_change.h"
-#include "components/autofill/core/browser/webdata/autofill_webdata_service_observer.h"
-#include "components/sync/model/sync_error.h"
-#include "components/sync/model/sync_merge_result.h"
-#include "components/sync/model/syncable_service.h"
-#include "components/sync/protocol/autofill_specifics.pb.h"
-
-namespace base {
-class Location;
-}
-
-namespace syncer {
-class SyncChangeProcessor;
-class SyncErrorFactory;
-}
-
-namespace autofill {
-
-class AutofillProfile;
-class AutofillWebDataBackend;
-class AutofillWebDataService;
-class CreditCard;
-
-// Syncs usage counts and last use dates (metadata) for Wallet cards and
-// addresses (data).
-//
-// The sync server generates the data, and the client can only download it. No
-// data upload is possible. Chrome generates the corresponding metadata locally
-// and uses the sync server to propagate the metadata to the other instances of
-// Chrome. See the design doc at https://goo.gl/LS2y6M for more details.
-class AutofillWalletMetadataSyncableService
-    : public base::SupportsUserData::Data,
-      public syncer::SyncableService,
-      public AutofillWebDataServiceObserverOnDBSequence {
- public:
-  AutofillWalletMetadataSyncableService(
-      AutofillWebDataBackend* web_data_backend,
-      const std::string& app_locale);
-
-  ~AutofillWalletMetadataSyncableService() override;
-
-  // Determines whether this bridge should be monitoring the Wallet data. This
-  // should be called whenever the data bridge sync state changes.
-  void OnWalletDataTrackingStateChanged(bool is_tracking);
-
-  base::WeakPtr<AutofillWalletMetadataSyncableService> GetWeakPtr() {
-    return weak_ptr_factory_.GetWeakPtr();
-  }
-
-  // syncer::SyncableService implementation.
-  void WaitUntilReadyToSync(base::OnceClosure done) override;
-  syncer::SyncMergeResult MergeDataAndStartSyncing(
-      syncer::ModelType type,
-      const syncer::SyncDataList& initial_sync_data,
-      std::unique_ptr<syncer::SyncChangeProcessor> sync_processor,
-      std::unique_ptr<syncer::SyncErrorFactory> sync_error_factory) override;
-  void StopSyncing(syncer::ModelType type) override;
-  syncer::SyncDataList GetAllSyncData(syncer::ModelType type) const override;
-  syncer::SyncError ProcessSyncChanges(
-      const base::Location& from_here,
-      const syncer::SyncChangeList& changes_from_sync) override;
-
-  // AutofillWebDataServiceObserverOnDBSequence implementation.
-  void AutofillProfileChanged(const AutofillProfileChange& change) override;
-  void CreditCardChanged(const CreditCardChange& change) override;
-  void AutofillMultipleChangedBySync() override;
-
-  // Creates a new AutofillWalletMetadataSyncableService and hangs it off of
-  // |web_data_service|, which takes ownership. This method should only be
-  // called on |web_data_service|'s DB sequence. |web_data_backend| is expected
-  // to outlive this object.
-  static void CreateForWebDataServiceAndBackend(
-      AutofillWebDataService* web_data_service,
-      AutofillWebDataBackend* web_data_backend,
-      const std::string& app_locale);
-
-  // Retrieves the AutofillWalletMetadataSyncableService stored on
-  // |web_data_service|.
-  static AutofillWalletMetadataSyncableService* FromWebDataService(
-      AutofillWebDataService* web_data_service);
-
- protected:
-  // Populates the provided |profiles| and |cards| with mappings from server ID
-  // to server profiles and server cards read from disk. This data contains the
-  // usage stats. Returns true on success.
-  virtual bool GetLocalData(
-      std::unordered_map<std::string, std::unique_ptr<AutofillProfile>>*
-          profiles,
-      std::unordered_map<std::string, std::unique_ptr<CreditCard>>* cards)
-      const;
-
-  // Updates the stats for |profile| stored on disk. Does not trigger
-  // notifications that this profile was updated.
-  virtual bool UpdateAddressStats(const AutofillProfile& profile);
-
-  // Updates the stats for |credit_card| stored on disk. Does not trigger
-  // notifications that this credit card was updated.
-  virtual bool UpdateCardStats(const CreditCard& credit_card);
-
-  // Sends the |changes_to_sync| to the sync server.
-  virtual syncer::SyncError SendChangesToSyncServer(
-      const syncer::SyncChangeList& changes_to_sync);
-
- private:
-  // Merges local metadata with |sync_data|.
-  //
-  // Sends an "update" to the sync server if |sync_data| contains metadata that
-  // is present locally, but local metadata has higher use count and later use
-  // date.
-  //
-  // Sends a "create" to the sync server if |sync_data| does not have some local
-  // metadata.
-  //
-  // Sends a "delete" to the sync server if |sync_data| contains metadata that
-  // is not present locally.
-  syncer::SyncMergeResult MergeData(const syncer::SyncDataList& sync_data);
-
-  base::ThreadChecker thread_checker_;
-  AutofillWebDataBackend* web_data_backend_;  // Weak ref.
-  ScopedObserver<AutofillWebDataBackend, AutofillWalletMetadataSyncableService>
-      scoped_observer_;
-  std::unique_ptr<syncer::SyncChangeProcessor> sync_processor_;
-  std::unique_ptr<syncer::SyncErrorFactory> sync_error_factory_;
-
-  // Local metadata plus metadata for the data that hasn't synced down yet.
-  syncer::SyncDataList cache_;
-
-  // Indicates whether we should rely on wallet data being actively synced. If
-  // true, the service will prune metadata entries without corresponding wallet
-  // data entry.
-  bool track_wallet_data_;
-
-  // Indicates that we should ignore multiple changed notification. This is used
-  // to block reflection and not to act on notification that we've triggered
-  // ourselves.
-  bool ignore_multiple_changed_notification_;
-
-  base::WeakPtrFactory<AutofillWalletMetadataSyncableService> weak_ptr_factory_{
-      this};
-
-  DISALLOW_COPY_AND_ASSIGN(AutofillWalletMetadataSyncableService);
-};
-
-}  // namespace autofill
-
-#endif  // COMPONENTS_AUTOFILL_CORE_BROWSER_WEBDATA_AUTOFILL_WALLET_METADATA_SYNCABLE_SERVICE_H_
diff --git a/components/autofill/core/browser/webdata/autofill_wallet_metadata_syncable_service_unittest.cc b/components/autofill/core/browser/webdata/autofill_wallet_metadata_syncable_service_unittest.cc
deleted file mode 100644
index eda11ce..0000000
--- a/components/autofill/core/browser/webdata/autofill_wallet_metadata_syncable_service_unittest.cc
+++ /dev/null
@@ -1,1366 +0,0 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "components/autofill/core/browser/webdata/autofill_wallet_metadata_syncable_service.h"
-
-#include <stddef.h>
-#include <stdint.h>
-
-#include <memory>
-#include <utility>
-#include <vector>
-
-#include "base/base64.h"
-#include "base/location.h"
-#include "base/macros.h"
-#include "base/numerics/safe_conversions.h"
-#include "base/time/time.h"
-#include "components/autofill/core/browser/data_model/autofill_profile.h"
-#include "components/autofill/core/browser/data_model/credit_card.h"
-#include "components/autofill/core/browser/webdata/autofill_webdata_backend.h"
-#include "components/autofill/core/browser/webdata/mock_autofill_webdata_backend.h"
-#include "components/sync/model/sync_change.h"
-#include "components/sync/model/sync_change_processor_wrapper_for_test.h"
-#include "components/sync/model/sync_error_factory_mock.h"
-#include "components/sync/protocol/autofill_specifics.pb.h"
-#include "components/sync/protocol/sync.pb.h"
-#include "testing/gmock/include/gmock/gmock.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace autofill {
-namespace {
-
-using testing::DoAll;
-using testing::ElementsAre;
-using testing::Invoke;
-using testing::NiceMock;
-using testing::Return;
-using testing::Test;
-using testing::UnorderedElementsAre;
-using testing::Value;
-using testing::_;
-
-// Non-UTF8 server IDs.
-const char kAddr1[] = "addr1\xEF\xBF\xBE";
-const char kAddr2[] = "addr2\xEF\xBF\xBE";
-const char kCard1[] = "card1\xEF\xBF\xBE";
-const char kCard2[] = "card2\xEF\xBF\xBE";
-
-// Base64 encodings of the server IDs. These are suitable for syncing, because
-// they are valid UTF-8.
-const char kAddr1Utf8[] = "YWRkcjHvv74=";
-const char kAddr2Utf8[] = "YWRkcjLvv74=";
-const char kCard1Utf8[] = "Y2FyZDHvv74=";
-const char kCard2Utf8[] = "Y2FyZDLvv74=";
-
-// Unique sync tags for the server IDs.
-const char kAddr1SyncTag[] = "address-YWRkcjHvv74=";
-const char kAddr2SyncTag[] = "address-YWRkcjLvv74=";
-const char kCard1SyncTag[] = "card-Y2FyZDHvv74=";
-const char kCard2SyncTag[] = "card-Y2FyZDLvv74=";
-
-// Local profile GUID in UTF8 and non-UTF8.
-const char kLocalAddr1[] = "e171e3ed-858a-4dd5-9bf3-8517f14ba5fc";
-const char kLocalAddr2[] = "fa232b9a-f248-4e5a-8d76-d46f821c0c5f";
-const char kLocalAddr1Utf8[] =
-    "ZTE3MWUzZWQtODU4YS00ZGQ1LTliZjMtODUxN2YxNGJhNWZj";
-
-// Map values are owned by the caller to GetLocalData.
-ACTION_P2(GetCopiesOf, profiles, cards) {
-  for (const auto& profile : *profiles) {
-    std::string utf8_server_id;
-    base::Base64Encode(profile.server_id(), &utf8_server_id);
-    (*arg0)[utf8_server_id] = std::make_unique<AutofillProfile>(profile);
-  }
-
-  for (const auto& card : *cards) {
-    std::string utf8_server_id;
-    base::Base64Encode(card.server_id(), &utf8_server_id);
-    (*arg1)[utf8_server_id] = std::make_unique<CreditCard>(card);
-  }
-}
-
-ACTION_P(SaveDataIn, list) {
-  for (auto& item : *list) {
-    if (item.server_id() == arg0.server_id()) {
-      item = arg0;
-      return;
-    }
-  }
-
-  list->push_back(arg0);
-}
-
-// A syncable service for Wallet metadata that mocks out disk IO.
-class MockService : public AutofillWalletMetadataSyncableService {
- public:
-  MockService(AutofillWebDataBackend* web_data_backend)
-      : AutofillWalletMetadataSyncableService(web_data_backend, std::string()) {
-    ON_CALL(*this, GetLocalData(_, _))
-        .WillByDefault(DoAll(GetCopiesOf(&server_profiles_, &server_cards_),
-                             Return(true)));
-
-    ON_CALL(*this, UpdateAddressStats(_))
-        .WillByDefault(DoAll(SaveDataIn(&server_profiles_), Return(true)));
-
-    ON_CALL(*this, UpdateCardStats(_))
-        .WillByDefault(DoAll(SaveDataIn(&server_cards_), Return(true)));
-
-    ON_CALL(*this, SendChangesToSyncServer(_))
-        .WillByDefault(
-            Invoke(this, &MockService::SendChangesToSyncServerConcrete));
-  }
-
-  ~MockService() override {}
-
-  MOCK_METHOD1(UpdateAddressStats, bool(const AutofillProfile&));
-  MOCK_METHOD1(UpdateCardStats, bool(const CreditCard&));
-  MOCK_METHOD1(SendChangesToSyncServer,
-               syncer::SyncError(const syncer::SyncChangeList&));
-
-  void ClearServerData() {
-    server_profiles_.clear();
-    server_cards_.clear();
-  }
-
- private:
-  MOCK_CONST_METHOD2(
-      GetLocalData,
-      bool(std::unordered_map<std::string, std::unique_ptr<AutofillProfile>>*,
-           std::unordered_map<std::string, std::unique_ptr<CreditCard>>*));
-
-  syncer::SyncError SendChangesToSyncServerConcrete(
-      const syncer::SyncChangeList& changes) {
-    return AutofillWalletMetadataSyncableService::SendChangesToSyncServer(
-        changes);
-  }
-
-  syncer::SyncDataList GetAllSyncDataConcrete(syncer::ModelType type) const {
-    return AutofillWalletMetadataSyncableService::GetAllSyncData(type);
-  }
-
-  std::vector<AutofillProfile> server_profiles_;
-  std::vector<CreditCard> server_cards_;
-
-  DISALLOW_COPY_AND_ASSIGN(MockService);
-};
-
-class AutofillWalletMetadataSyncableServiceTest : public Test {
- public:
-  AutofillWalletMetadataSyncableServiceTest()
-      : local_(&backend_), remote_(&backend_) {}
-  ~AutofillWalletMetadataSyncableServiceTest() override {}
-
-  void SetUp() {
-    local_.OnWalletDataTrackingStateChanged(true);
-    remote_.OnWalletDataTrackingStateChanged(true);
-  }
-
-  // Outlives local_ and remote_.
-  NiceMock<MockAutofillWebDataBackend> backend_;
-
-  // Outlived by backend_.
-  NiceMock<MockService> local_;
-  NiceMock<MockService> remote_;
-
- private:
-  DISALLOW_COPY_AND_ASSIGN(AutofillWalletMetadataSyncableServiceTest);
-};
-
-// Verify that nothing is sent to the sync server when there's no metadata on
-// disk.
-TEST_F(AutofillWalletMetadataSyncableServiceTest, NoMetadataToReturn) {
-  EXPECT_TRUE(local_.GetAllSyncData(syncer::AUTOFILL_WALLET_METADATA).empty());
-}
-
-AutofillProfile BuildAddress(const std::string& server_id,
-                             int64_t use_count,
-                             int64_t use_date,
-                             bool has_converted) {
-  AutofillProfile profile(AutofillProfile::SERVER_PROFILE, server_id);
-  profile.set_use_count(use_count);
-  profile.set_use_date(base::Time::FromInternalValue(use_date));
-  profile.set_has_converted(has_converted);
-  return profile;
-}
-
-CreditCard BuildCard(const std::string& server_id,
-                     int64_t use_count,
-                     int64_t use_date,
-                     const std::string& billing_address_id) {
-  CreditCard card(CreditCard::MASKED_SERVER_CARD, server_id);
-  card.set_use_count(use_count);
-  card.set_use_date(base::Time::FromInternalValue(use_date));
-  card.set_billing_address_id(billing_address_id);
-  return card;
-}
-
-MATCHER_P6(SyncAddressDataMatches,
-           sync_tag,
-           metadata_type,
-           server_id,
-           use_count,
-           use_date,
-           has_converted,
-           "") {
-  return arg.IsValid() &&
-         syncer::AUTOFILL_WALLET_METADATA == arg.GetDataType() &&
-         sync_tag == syncer::SyncDataLocal(arg).GetTag() &&
-         metadata_type == arg.GetSpecifics().wallet_metadata().type() &&
-         server_id == arg.GetSpecifics().wallet_metadata().id() &&
-         use_count == arg.GetSpecifics().wallet_metadata().use_count() &&
-         use_date == arg.GetSpecifics().wallet_metadata().use_date() &&
-         has_converted ==
-             arg.GetSpecifics().wallet_metadata().address_has_converted();
-}
-
-MATCHER_P6(SyncCardDataMatches,
-           sync_tag,
-           metadata_type,
-           server_id,
-           use_count,
-           use_date,
-           billing_address_id,
-           "") {
-  return arg.IsValid() &&
-         syncer::AUTOFILL_WALLET_METADATA == arg.GetDataType() &&
-         sync_tag == syncer::SyncDataLocal(arg).GetTag() &&
-         metadata_type == arg.GetSpecifics().wallet_metadata().type() &&
-         server_id == arg.GetSpecifics().wallet_metadata().id() &&
-         use_count == arg.GetSpecifics().wallet_metadata().use_count() &&
-         use_date == arg.GetSpecifics().wallet_metadata().use_date() &&
-         billing_address_id ==
-             arg.GetSpecifics().wallet_metadata().card_billing_address_id();
-}
-
-// Verify that all metadata from disk is sent to the sync server.
-TEST_F(AutofillWalletMetadataSyncableServiceTest, ReturnAllMetadata) {
-  local_.UpdateAddressStats(BuildAddress(kAddr1, 1, 2, true));
-  local_.UpdateCardStats(BuildCard(kCard1, 3, 4, kAddr1));
-
-  EXPECT_THAT(local_.GetAllSyncData(syncer::AUTOFILL_WALLET_METADATA),
-              UnorderedElementsAre(
-                  SyncAddressDataMatches(
-                      kAddr1SyncTag, sync_pb::WalletMetadataSpecifics::ADDRESS,
-                      kAddr1Utf8, 1, 2, true),
-                  SyncCardDataMatches(kCard1SyncTag,
-                                      sync_pb::WalletMetadataSpecifics::CARD,
-                                      kCard1Utf8, 3, 4, kAddr1Utf8)));
-}
-
-void MergeMetadata(MockService* local, MockService* remote) {
-  // The wrapper for |remote| gives it a null change processor, so sending
-  // changes is not possible.
-  ON_CALL(*remote, SendChangesToSyncServer(_))
-      .WillByDefault(Return(syncer::SyncError()));
-
-  std::unique_ptr<syncer::SyncErrorFactoryMock> errors(
-      new syncer::SyncErrorFactoryMock);
-  EXPECT_CALL(*errors, CreateAndUploadError(_, _)).Times(0);
-  EXPECT_FALSE(
-      local
-          ->MergeDataAndStartSyncing(
-              syncer::AUTOFILL_WALLET_METADATA,
-              remote->GetAllSyncData(syncer::AUTOFILL_WALLET_METADATA),
-              std::unique_ptr<syncer::SyncChangeProcessor>(
-                  new syncer::SyncChangeProcessorWrapperForTest(remote)),
-              std::move(errors))
-          .error()
-          .IsSet());
-}
-
-// Verify that nothing is written to disk or sent to the sync server when two
-// empty clients are syncing.
-TEST_F(AutofillWalletMetadataSyncableServiceTest, TwoEmptyClients) {
-  EXPECT_CALL(local_, UpdateAddressStats(_)).Times(0);
-  EXPECT_CALL(local_, UpdateCardStats(_)).Times(0);
-  EXPECT_CALL(local_, SendChangesToSyncServer(_)).Times(0);
-
-  MergeMetadata(&local_, &remote_);
-}
-
-MATCHER_P2(SyncChangeMatches, change_type, sync_tag, "") {
-  return arg.IsValid() && change_type == arg.change_type() &&
-         sync_tag == syncer::SyncDataLocal(arg.sync_data()).GetTag() &&
-         syncer::AUTOFILL_WALLET_METADATA == arg.sync_data().GetDataType();
-}
-
-// Verify that remote data without local counterpart is deleted during the
-// initial merge.
-TEST_F(AutofillWalletMetadataSyncableServiceTest, DeleteFromServerOnMerge) {
-  remote_.UpdateAddressStats(BuildAddress(kAddr1, 1, 2, true));
-  remote_.UpdateCardStats(BuildCard(kCard1, 3, 4, kAddr1));
-
-  EXPECT_CALL(local_, UpdateAddressStats(_)).Times(0);
-  EXPECT_CALL(local_, UpdateCardStats(_)).Times(0);
-  EXPECT_CALL(
-      local_,
-      SendChangesToSyncServer(UnorderedElementsAre(
-          SyncChangeMatches(syncer::SyncChange::ACTION_DELETE, kAddr1SyncTag),
-          SyncChangeMatches(syncer::SyncChange::ACTION_DELETE,
-                            kCard1SyncTag))));
-
-  MergeMetadata(&local_, &remote_);
-}
-
-// Verify that remote data without local counterpart is kept when we're not
-// tracking wallet data.
-TEST_F(AutofillWalletMetadataSyncableServiceTest,
-       DeleteFromServerOnMerge_NotWhenNotTracking) {
-  local_.OnWalletDataTrackingStateChanged(false);
-
-  remote_.UpdateAddressStats(BuildAddress(kAddr1, 1, 2, true));
-  remote_.UpdateCardStats(BuildCard(kCard1, 3, 4, kAddr1));
-
-  EXPECT_CALL(local_, UpdateAddressStats(_)).Times(0);
-  EXPECT_CALL(local_, UpdateCardStats(_)).Times(0);
-  EXPECT_CALL(local_, SendChangesToSyncServer(_)).Times(0);
-
-  MergeMetadata(&local_, &remote_);
-}
-
-// Verify that remote data without local counterpart is deleted when we start
-// tracking wallet data after the initial merge happened.
-TEST_F(AutofillWalletMetadataSyncableServiceTest,
-       DeleteFromServerOnMerge_MergeBeforeTracking) {
-  local_.OnWalletDataTrackingStateChanged(false);
-
-  remote_.UpdateAddressStats(BuildAddress(kAddr1, 1, 2, true));
-  remote_.UpdateCardStats(BuildCard(kCard1, 3, 4, kAddr1));
-
-  EXPECT_CALL(local_, UpdateAddressStats(_)).Times(0);
-  EXPECT_CALL(local_, UpdateCardStats(_)).Times(0);
-  EXPECT_CALL(
-      local_,
-      SendChangesToSyncServer(UnorderedElementsAre(
-          SyncChangeMatches(syncer::SyncChange::ACTION_DELETE, kAddr1SyncTag),
-          SyncChangeMatches(syncer::SyncChange::ACTION_DELETE,
-                            kCard1SyncTag))));
-
-  MergeMetadata(&local_, &remote_);
-
-  local_.OnWalletDataTrackingStateChanged(true);
-}
-
-MATCHER_P7(SyncAddressChangeAndDataMatch,
-           change_type,
-           sync_tag,
-           metadata_type,
-           server_id,
-           use_count,
-           use_date,
-           has_converted,
-           "") {
-  return Value(arg, SyncChangeMatches(change_type, sync_tag)) &&
-         Value(arg.sync_data(),
-               SyncAddressDataMatches(sync_tag, metadata_type, server_id,
-                                      use_count, use_date, has_converted));
-}
-
-MATCHER_P7(SyncCardChangeAndDataMatch,
-           change_type,
-           sync_tag,
-           metadata_type,
-           server_id,
-           use_count,
-           use_date,
-           billing_address_id,
-           "") {
-  return Value(arg, SyncChangeMatches(change_type, sync_tag)) &&
-         Value(arg.sync_data(),
-               SyncCardDataMatches(sync_tag, metadata_type, server_id,
-                                   use_count, use_date, billing_address_id));
-}
-
-// Verify that local data is sent to the sync server during the initial merge,
-// if the server does not have the data already.
-TEST_F(AutofillWalletMetadataSyncableServiceTest, AddToServerOnMerge) {
-  local_.UpdateAddressStats(BuildAddress(kAddr1, 1, 2, true));
-  local_.UpdateCardStats(BuildCard(kCard1, 3, 4, kAddr1));
-
-  EXPECT_CALL(local_, UpdateAddressStats(_)).Times(0);
-  EXPECT_CALL(local_, UpdateCardStats(_)).Times(0);
-  EXPECT_CALL(local_, SendChangesToSyncServer(UnorderedElementsAre(
-                          SyncAddressChangeAndDataMatch(
-                              syncer::SyncChange::ACTION_ADD, kAddr1SyncTag,
-                              sync_pb::WalletMetadataSpecifics::ADDRESS,
-                              kAddr1Utf8, 1, 2, true),
-                          SyncCardChangeAndDataMatch(
-                              syncer::SyncChange::ACTION_ADD, kCard1SyncTag,
-                              sync_pb::WalletMetadataSpecifics::CARD,
-                              kCard1Utf8, 3, 4, kAddr1Utf8))));
-
-  MergeMetadata(&local_, &remote_);
-}
-
-// Verify that no data is written to disk or sent to the sync server if the
-// local and remote data are identical during the initial merge.
-TEST_F(AutofillWalletMetadataSyncableServiceTest,
-       IgnoreIdenticalValuesOnMerge) {
-  local_.UpdateAddressStats(BuildAddress(kAddr1, 1, 2, true));
-  local_.UpdateCardStats(BuildCard(kCard1, 3, 4, kAddr1));
-  remote_.UpdateAddressStats(BuildAddress(kAddr1, 1, 2, true));
-  remote_.UpdateCardStats(BuildCard(kCard1, 3, 4, kAddr1));
-
-  EXPECT_CALL(local_, UpdateAddressStats(_)).Times(0);
-  EXPECT_CALL(local_, UpdateCardStats(_)).Times(0);
-  EXPECT_CALL(local_, SendChangesToSyncServer(_)).Times(0);
-
-  MergeMetadata(&local_, &remote_);
-}
-
-MATCHER_P4(AutofillAddressMetadataMatches,
-           server_id,
-           use_count,
-           use_date,
-           has_converted,
-           "") {
-  return arg.server_id() == server_id &&
-         arg.use_count() == base::checked_cast<size_t>(use_count) &&
-         arg.use_date() == base::Time::FromInternalValue(use_date) &&
-         arg.has_converted() == has_converted;
-}
-
-MATCHER_P4(AutofillCardMetadataMatches,
-           server_id,
-           use_count,
-           use_date,
-           billing_address_id,
-           "") {
-  return arg.server_id() == server_id &&
-         arg.use_count() == base::checked_cast<size_t>(use_count) &&
-         arg.use_date() == base::Time::FromInternalValue(use_date) &&
-         arg.billing_address_id() == billing_address_id;
-}
-
-// Verify that remote data with higher values of use count and last use date is
-// saved to disk during the initial merge.
-TEST_F(AutofillWalletMetadataSyncableServiceTest,
-       SaveHigherValuesLocallyOnMerge) {
-  local_.UpdateAddressStats(BuildAddress(kAddr1, 1, 2, true));
-  local_.UpdateCardStats(BuildCard(kCard1, 3, 4, kAddr1));
-  remote_.UpdateAddressStats(BuildAddress(kAddr1, 10, 20, true));
-  remote_.UpdateCardStats(BuildCard(kCard1, 30, 40, kAddr1));
-
-  EXPECT_CALL(local_, UpdateAddressStats(AutofillAddressMetadataMatches(
-                          kAddr1, 10, 20, true)));
-  EXPECT_CALL(local_, UpdateCardStats(
-                          AutofillCardMetadataMatches(kCard1, 30, 40, kAddr1)));
-  EXPECT_CALL(local_, SendChangesToSyncServer(_)).Times(0);
-
-  MergeMetadata(&local_, &remote_);
-}
-
-// Verify that local data with higher values of use count and last use date is
-// sent to the sync server during the initial merge.
-TEST_F(AutofillWalletMetadataSyncableServiceTest,
-       SendHigherValuesToServerOnMerge) {
-  local_.UpdateAddressStats(BuildAddress(kAddr1, 10, 20, true));
-  local_.UpdateCardStats(BuildCard(kCard1, 30, 40, kAddr1));
-  remote_.UpdateAddressStats(BuildAddress(kAddr1, 1, 2, false));
-  remote_.UpdateCardStats(BuildCard(kCard1, 3, 4, kAddr2));
-
-  EXPECT_CALL(local_, UpdateAddressStats(_)).Times(0);
-  EXPECT_CALL(local_, UpdateCardStats(_)).Times(0);
-  EXPECT_CALL(local_, SendChangesToSyncServer(UnorderedElementsAre(
-                          SyncAddressChangeAndDataMatch(
-                              syncer::SyncChange::ACTION_UPDATE, kAddr1SyncTag,
-                              sync_pb::WalletMetadataSpecifics::ADDRESS,
-                              kAddr1Utf8, 10, 20, true),
-                          SyncCardChangeAndDataMatch(
-                              syncer::SyncChange::ACTION_UPDATE, kCard1SyncTag,
-                              sync_pb::WalletMetadataSpecifics::CARD,
-                              kCard1Utf8, 30, 40, kAddr1Utf8))));
-
-  MergeMetadata(&local_, &remote_);
-}
-
-// Verify that lower or equal values of metadata are not sent to the sync server
-// when local metadata is updated.
-TEST_F(AutofillWalletMetadataSyncableServiceTest,
-       DontSendLowerValueToServerOnSingleChange) {
-  local_.UpdateAddressStats(BuildAddress(kAddr1, 1, 2, true));
-  local_.UpdateCardStats(BuildCard(kCard1, 3, 4, kAddr1));
-  remote_.UpdateAddressStats(BuildAddress(kAddr1, 1, 2, true));
-  remote_.UpdateCardStats(BuildCard(kCard1, 3, 4, kAddr1));
-  MergeMetadata(&local_, &remote_);
-  AutofillProfile address = BuildAddress(kAddr1, 0, 0, true);
-  CreditCard card = BuildCard(kCard1, 3, 4, kAddr1);
-
-  EXPECT_CALL(local_, SendChangesToSyncServer(_)).Times(0);
-
-  local_.AutofillProfileChanged(AutofillProfileChange(
-      AutofillProfileChange::UPDATE, address.guid(), &address));
-  local_.CreditCardChanged(
-      CreditCardChange(CreditCardChange::UPDATE, card.guid(), &card));
-}
-
-// Verify that higher values of metadata are sent to the sync server when local
-// metadata is updated.
-TEST_F(AutofillWalletMetadataSyncableServiceTest,
-       SendHigherValuesToServerOnLocalSingleChange) {
-  local_.UpdateAddressStats(BuildAddress(kAddr1, 1, 2, false));
-  local_.UpdateCardStats(BuildCard(kCard1, 3, 4, kAddr1));
-  remote_.UpdateAddressStats(BuildAddress(kAddr1, 1, 2, false));
-  remote_.UpdateCardStats(BuildCard(kCard1, 3, 4, kAddr1));
-  MergeMetadata(&local_, &remote_);
-  AutofillProfile address = BuildAddress(kAddr1, 10, 20, true);
-  CreditCard card = BuildCard(kCard1, 30, 40, kAddr2);
-
-  EXPECT_CALL(local_,
-              SendChangesToSyncServer(ElementsAre(SyncAddressChangeAndDataMatch(
-                  syncer::SyncChange::ACTION_UPDATE, kAddr1SyncTag,
-                  sync_pb::WalletMetadataSpecifics::ADDRESS, kAddr1Utf8, 10, 20,
-                  true))));
-  EXPECT_CALL(local_,
-              SendChangesToSyncServer(ElementsAre(SyncCardChangeAndDataMatch(
-                  syncer::SyncChange::ACTION_UPDATE, kCard1SyncTag,
-                  sync_pb::WalletMetadataSpecifics::CARD, kCard1Utf8, 30, 40,
-                  kAddr2Utf8))));
-
-  local_.AutofillProfileChanged(AutofillProfileChange(
-      AutofillProfileChange::UPDATE, address.guid(), &address));
-  local_.CreditCardChanged(
-      CreditCardChange(CreditCardChange::UPDATE, card.guid(), &card));
-}
-
-// Verify that other changed metadata elements are sent to the sync server when
-// local metadata is updated.
-TEST_F(AutofillWalletMetadataSyncableServiceTest,
-       SendChangedMetadataToServerOnLocalSingleChange) {
-  local_.UpdateAddressStats(BuildAddress(kAddr1, 1, 2, false));
-  local_.UpdateCardStats(BuildCard(kCard1, 3, 4, kAddr1));
-  remote_.UpdateAddressStats(BuildAddress(kAddr1, 1, 2, false));
-  remote_.UpdateCardStats(BuildCard(kCard1, 3, 4, kAddr1));
-  MergeMetadata(&local_, &remote_);
-  AutofillProfile address = BuildAddress(kAddr1, 1, 2, true);
-  CreditCard card = BuildCard(kCard1, 3, 4, kAddr2);
-
-  EXPECT_CALL(
-      local_,
-      SendChangesToSyncServer(ElementsAre(SyncAddressChangeAndDataMatch(
-          syncer::SyncChange::ACTION_UPDATE, kAddr1SyncTag,
-          sync_pb::WalletMetadataSpecifics::ADDRESS, kAddr1Utf8, 1, 2, true))));
-  EXPECT_CALL(local_,
-              SendChangesToSyncServer(ElementsAre(SyncCardChangeAndDataMatch(
-                  syncer::SyncChange::ACTION_UPDATE, kCard1SyncTag,
-                  sync_pb::WalletMetadataSpecifics::CARD, kCard1Utf8, 3, 4,
-                  kAddr2Utf8))));
-
-  local_.AutofillProfileChanged(AutofillProfileChange(
-      AutofillProfileChange::UPDATE, address.guid(), &address));
-  local_.CreditCardChanged(
-      CreditCardChange(CreditCardChange::UPDATE, card.guid(), &card));
-}
-
-// Verify that one-off addition of metadata is not sent to the sync
-// server. Metadata add and delete trigger multiple changes notification
-// instead.
-TEST_F(AutofillWalletMetadataSyncableServiceTest,
-       DontAddToServerOnSingleChange) {
-  local_.UpdateAddressStats(BuildAddress(kAddr1, 1, 2, true));
-  local_.UpdateCardStats(BuildCard(kCard1, 3, 4, kAddr1));
-  remote_.UpdateAddressStats(BuildAddress(kAddr1, 1, 2, true));
-  remote_.UpdateCardStats(BuildCard(kCard1, 3, 4, kAddr1));
-  MergeMetadata(&local_, &remote_);
-  AutofillProfile address = BuildAddress(kAddr2, 5, 6, false);
-  CreditCard card = BuildCard(kCard2, 7, 8, kAddr2);
-
-  EXPECT_CALL(local_, SendChangesToSyncServer(_)).Times(0);
-
-  local_.AutofillProfileChanged(AutofillProfileChange(
-      AutofillProfileChange::UPDATE, address.guid(), &address));
-  local_.CreditCardChanged(
-      CreditCardChange(CreditCardChange::UPDATE, card.guid(), &card));
-}
-
-// Verify that new metadata is sent to the sync server when multiple metadata
-// values change at once.
-TEST_F(AutofillWalletMetadataSyncableServiceTest, AddToServerOnMultiChange) {
-  local_.UpdateAddressStats(BuildAddress(kAddr1, 1, 2, false));
-  local_.UpdateCardStats(BuildCard(kCard1, 3, 4, kAddr1));
-  remote_.UpdateAddressStats(BuildAddress(kAddr1, 1, 2, false));
-  remote_.UpdateCardStats(BuildCard(kCard1, 3, 4, kAddr1));
-  MergeMetadata(&local_, &remote_);
-  // These methods do not trigger notifications or sync:
-  local_.UpdateAddressStats(BuildAddress(kAddr2, 5, 6, true));
-  local_.UpdateCardStats(BuildCard(kCard2, 7, 8, kAddr2));
-
-  EXPECT_CALL(local_, SendChangesToSyncServer(UnorderedElementsAre(
-                          SyncAddressChangeAndDataMatch(
-                              syncer::SyncChange::ACTION_ADD, kAddr2SyncTag,
-                              sync_pb::WalletMetadataSpecifics::ADDRESS,
-                              kAddr2Utf8, 5, 6, true),
-                          SyncCardChangeAndDataMatch(
-                              syncer::SyncChange::ACTION_ADD, kCard2SyncTag,
-                              sync_pb::WalletMetadataSpecifics::CARD,
-                              kCard2Utf8, 7, 8, kAddr2Utf8))));
-
-  local_.AutofillMultipleChangedBySync();
-}
-
-// Verify that higher values of existing metadata are sent to the sync server
-// when multiple metadata values change at once.
-TEST_F(AutofillWalletMetadataSyncableServiceTest,
-       UpdateToHigherValueOnServerOnMultiChange) {
-  local_.UpdateAddressStats(BuildAddress(kAddr1, 1, 2, false));
-  local_.UpdateCardStats(BuildCard(kCard1, 3, 4, kAddr1));
-  remote_.UpdateAddressStats(BuildAddress(kAddr1, 1, 2, false));
-  remote_.UpdateCardStats(BuildCard(kCard1, 3, 4, kAddr1));
-  MergeMetadata(&local_, &remote_);
-  // These methods do not trigger notifications or sync:
-  local_.UpdateAddressStats(BuildAddress(kAddr1, 5, 6, true));
-  local_.UpdateCardStats(BuildCard(kCard1, 7, 8, kAddr2));
-
-  EXPECT_CALL(local_, SendChangesToSyncServer(UnorderedElementsAre(
-                          SyncAddressChangeAndDataMatch(
-                              syncer::SyncChange::ACTION_UPDATE, kAddr1SyncTag,
-                              sync_pb::WalletMetadataSpecifics::ADDRESS,
-                              kAddr1Utf8, 5, 6, true),
-                          SyncCardChangeAndDataMatch(
-                              syncer::SyncChange::ACTION_UPDATE, kCard1SyncTag,
-                              sync_pb::WalletMetadataSpecifics::CARD,
-                              kCard1Utf8, 7, 8, kAddr2Utf8))));
-
-  local_.AutofillMultipleChangedBySync();
-}
-
-// Verify that lower values of existing metadata are not sent to the sync server
-// when multiple metadata values change at once.
-TEST_F(AutofillWalletMetadataSyncableServiceTest,
-       DontUpdateToLowerValueOnServerOnMultiChange) {
-  local_.UpdateAddressStats(BuildAddress(kAddr1, 1, 2, true));
-  local_.UpdateCardStats(BuildCard(kCard1, 3, 4, kAddr1));
-  remote_.UpdateAddressStats(BuildAddress(kAddr1, 1, 2, true));
-  remote_.UpdateCardStats(BuildCard(kCard1, 3, 4, kAddr1));
-  MergeMetadata(&local_, &remote_);
-  // These methods do not trigger notifications or sync:
-  local_.UpdateAddressStats(BuildAddress(kAddr1, 0, 0, false));
-  local_.UpdateCardStats(BuildCard(kCard1, 0, 0, kAddr2));
-
-  EXPECT_CALL(local_, SendChangesToSyncServer(_)).Times(0);
-
-  local_.AutofillMultipleChangedBySync();
-}
-
-// Verify that erased local metadata is also erased from the sync server when
-// multiple metadata values change at once.
-TEST_F(AutofillWalletMetadataSyncableServiceTest,
-       DeleteFromServerOnMultiChange) {
-  local_.UpdateAddressStats(BuildAddress(kAddr1, 1, 2, true));
-  local_.UpdateCardStats(BuildCard(kCard1, 3, 4, kAddr1));
-  remote_.UpdateAddressStats(BuildAddress(kAddr1, 1, 2, true));
-  remote_.UpdateCardStats(BuildCard(kCard1, 3, 4, kAddr1));
-  MergeMetadata(&local_, &remote_);
-  // This method dooes not trigger notifications or sync:
-  local_.ClearServerData();
-
-  EXPECT_CALL(
-      local_,
-      SendChangesToSyncServer(UnorderedElementsAre(
-          SyncChangeMatches(syncer::SyncChange::ACTION_DELETE, kAddr1SyncTag),
-          SyncChangeMatches(syncer::SyncChange::ACTION_DELETE,
-                            kCard1SyncTag))));
-
-  local_.AutofillMultipleChangedBySync();
-}
-
-// Verify that erased local metadata is not erased from the sync server when
-// the service is not tracking Wallet data.
-TEST_F(AutofillWalletMetadataSyncableServiceTest,
-       DeleteFromServerOnMultiChange_NotWhenNotTracking) {
-  local_.OnWalletDataTrackingStateChanged(false);
-
-  local_.UpdateAddressStats(BuildAddress(kAddr1, 1, 2, true));
-  local_.UpdateCardStats(BuildCard(kCard1, 3, 4, kAddr1));
-  remote_.UpdateAddressStats(BuildAddress(kAddr1, 1, 2, true));
-  remote_.UpdateCardStats(BuildCard(kCard1, 3, 4, kAddr1));
-  MergeMetadata(&local_, &remote_);
-  // This method dooes not trigger notifications or sync:
-  local_.ClearServerData();
-
-  EXPECT_CALL(local_, SendChangesToSyncServer(_)).Times(0);
-
-  local_.AutofillMultipleChangedBySync();
-}
-
-// Verify that erased local metadata is also erased from the sync server when
-// we start tracking Wallet data after multiple metadata values change at once.
-TEST_F(AutofillWalletMetadataSyncableServiceTest,
-       DeleteFromServerOnMultiChange_ChangeBeforeTracking) {
-  local_.OnWalletDataTrackingStateChanged(false);
-
-  local_.UpdateAddressStats(BuildAddress(kAddr1, 1, 2, true));
-  local_.UpdateCardStats(BuildCard(kCard1, 3, 4, kAddr1));
-  remote_.UpdateAddressStats(BuildAddress(kAddr1, 1, 2, true));
-  remote_.UpdateCardStats(BuildCard(kCard1, 3, 4, kAddr1));
-  MergeMetadata(&local_, &remote_);
-  // This method dooes not trigger notifications or sync:
-  local_.ClearServerData();
-
-  EXPECT_CALL(
-      local_,
-      SendChangesToSyncServer(UnorderedElementsAre(
-          SyncChangeMatches(syncer::SyncChange::ACTION_DELETE, kAddr1SyncTag),
-          SyncChangeMatches(syncer::SyncChange::ACTION_DELETE,
-                            kCard1SyncTag))));
-
-  local_.AutofillMultipleChangedBySync();
-  local_.OnWalletDataTrackingStateChanged(true);
-}
-
-// Verify that empty sync change from the sync server does not trigger writing
-// to disk or sending any data to the sync server.
-TEST_F(AutofillWalletMetadataSyncableServiceTest, EmptySyncChange) {
-  local_.UpdateAddressStats(BuildAddress(kAddr1, 1, 2, true));
-  local_.UpdateCardStats(BuildCard(kCard1, 3, 4, kAddr1));
-  remote_.UpdateAddressStats(BuildAddress(kAddr1, 1, 2, true));
-  remote_.UpdateCardStats(BuildCard(kCard1, 3, 4, kAddr1));
-  MergeMetadata(&local_, &remote_);
-
-  EXPECT_CALL(local_, UpdateAddressStats(_)).Times(0);
-  EXPECT_CALL(local_, UpdateCardStats(_)).Times(0);
-  EXPECT_CALL(local_, SendChangesToSyncServer(_)).Times(0);
-
-  local_.ProcessSyncChanges(FROM_HERE, syncer::SyncChangeList());
-}
-
-void BuildBasicChange(syncer::SyncChange::SyncChangeType change_type,
-                      const std::string& sync_tag,
-                      sync_pb::WalletMetadataSpecifics::Type metadata_type,
-                      const std::string& server_id,
-                      int64_t use_count,
-                      int64_t use_date,
-                      sync_pb::EntitySpecifics* entity) {
-  entity->mutable_wallet_metadata()->set_type(metadata_type);
-  entity->mutable_wallet_metadata()->set_id(server_id);
-  entity->mutable_wallet_metadata()->set_use_count(use_count);
-  entity->mutable_wallet_metadata()->set_use_date(use_date);
-}
-
-syncer::SyncChange BuildAddressChange(
-    syncer::SyncChange::SyncChangeType change_type,
-    const std::string& sync_tag,
-    sync_pb::WalletMetadataSpecifics::Type metadata_type,
-    const std::string& server_id,
-    int64_t use_count,
-    int64_t use_date,
-    bool has_converted) {
-  sync_pb::EntitySpecifics entity;
-  BuildBasicChange(change_type, sync_tag, metadata_type, server_id, use_count,
-                   use_date, &entity);
-  entity.mutable_wallet_metadata()->set_address_has_converted(has_converted);
-  return syncer::SyncChange(
-      FROM_HERE, change_type,
-      syncer::SyncData::CreateLocalData(sync_tag, sync_tag, entity));
-}
-
-syncer::SyncChange BuildCardChange(
-    syncer::SyncChange::SyncChangeType change_type,
-    const std::string& sync_tag,
-    sync_pb::WalletMetadataSpecifics::Type metadata_type,
-    const std::string& server_id,
-    int64_t use_count,
-    int64_t use_date,
-    const std::string& billing_address_id) {
-  sync_pb::EntitySpecifics entity;
-  BuildBasicChange(change_type, sync_tag, metadata_type, server_id, use_count,
-                   use_date, &entity);
-  entity.mutable_wallet_metadata()->set_card_billing_address_id(
-      billing_address_id);
-  return syncer::SyncChange(
-      FROM_HERE, change_type,
-      syncer::SyncData::CreateLocalData(sync_tag, sync_tag, entity));
-}
-
-// Verify that new metadata from the sync server is ignored when processing
-// on-going sync changes. There should be no disk writes or messages to the sync
-// server.
-TEST_F(AutofillWalletMetadataSyncableServiceTest,
-       IgnoreNewMetadataFromServerOnSyncChange) {
-  local_.UpdateAddressStats(BuildAddress(kAddr1, 2, 2, true));
-  local_.UpdateCardStats(BuildCard(kCard1, 3, 4, kAddr1));
-  remote_.UpdateAddressStats(BuildAddress(kAddr1, 2, 2, true));
-  remote_.UpdateCardStats(BuildCard(kCard1, 3, 4, kAddr1));
-  MergeMetadata(&local_, &remote_);
-  syncer::SyncChangeList changes;
-  changes.push_back(BuildAddressChange(
-      syncer::SyncChange::ACTION_ADD, kAddr2SyncTag,
-      sync_pb::WalletMetadataSpecifics::ADDRESS, kAddr2Utf8, 5, 6, true));
-  changes.push_back(BuildCardChange(
-      syncer::SyncChange::ACTION_ADD, kCard2SyncTag,
-      sync_pb::WalletMetadataSpecifics::CARD, kCard2Utf8, 7, 8, kAddr2Utf8));
-
-  EXPECT_CALL(local_, UpdateAddressStats(_)).Times(0);
-  EXPECT_CALL(local_, UpdateCardStats(_)).Times(0);
-  EXPECT_CALL(local_, SendChangesToSyncServer(_)).Times(0);
-
-  local_.ProcessSyncChanges(FROM_HERE, changes);
-}
-
-// Verify that higher values of metadata from the sync server are saved to
-// disk when processing on-going sync changes.
-TEST_F(AutofillWalletMetadataSyncableServiceTest,
-       SaveHigherValuesFromServerOnSyncChange) {
-  local_.UpdateAddressStats(BuildAddress(kAddr1, 2, 2, false));
-  local_.UpdateCardStats(BuildCard(kCard1, 3, 4, kAddr1));
-  remote_.UpdateAddressStats(BuildAddress(kAddr1, 2, 2, false));
-  remote_.UpdateCardStats(BuildCard(kCard1, 3, 4, kAddr1));
-  MergeMetadata(&local_, &remote_);
-  syncer::SyncChangeList changes;
-  changes.push_back(BuildAddressChange(
-      syncer::SyncChange::ACTION_UPDATE, kAddr1SyncTag,
-      sync_pb::WalletMetadataSpecifics::ADDRESS, kAddr1Utf8, 10, 20, true));
-  changes.push_back(BuildCardChange(
-      syncer::SyncChange::ACTION_UPDATE, kCard1SyncTag,
-      sync_pb::WalletMetadataSpecifics::CARD, kCard1Utf8, 30, 40, kAddr2Utf8));
-
-  EXPECT_CALL(local_, UpdateAddressStats(AutofillAddressMetadataMatches(
-                          kAddr1, 10, 20, true)));
-  EXPECT_CALL(local_, UpdateCardStats(
-                          AutofillCardMetadataMatches(kCard1, 30, 40, kAddr2)));
-  EXPECT_CALL(local_, SendChangesToSyncServer(_)).Times(0);
-
-  local_.ProcessSyncChanges(FROM_HERE, changes);
-}
-
-// Verify that higher local values of metadata are sent to the sync server when
-// processing on-going sync changes.
-TEST_F(AutofillWalletMetadataSyncableServiceTest,
-       SendHigherValuesToServerOnSyncChange) {
-  local_.UpdateAddressStats(BuildAddress(kAddr1, 2, 2, true));
-  local_.UpdateCardStats(BuildCard(kCard1, 3, 4, kAddr1));
-  remote_.UpdateAddressStats(BuildAddress(kAddr1, 2, 2, true));
-  remote_.UpdateCardStats(BuildCard(kCard1, 3, 4, kAddr1));
-  MergeMetadata(&local_, &remote_);
-  syncer::SyncChangeList changes;
-  changes.push_back(BuildAddressChange(
-      syncer::SyncChange::ACTION_UPDATE, kAddr1SyncTag,
-      sync_pb::WalletMetadataSpecifics::ADDRESS, kAddr1Utf8, 0, 0, false));
-  changes.push_back(BuildCardChange(
-      syncer::SyncChange::ACTION_UPDATE, kCard1SyncTag,
-      sync_pb::WalletMetadataSpecifics::CARD, kCard1Utf8, 0, 0, kAddr2Utf8));
-
-  EXPECT_CALL(local_, UpdateAddressStats(_)).Times(0);
-  EXPECT_CALL(local_, UpdateCardStats(_)).Times(0);
-  EXPECT_CALL(local_, SendChangesToSyncServer(UnorderedElementsAre(
-                          SyncAddressChangeAndDataMatch(
-                              syncer::SyncChange::ACTION_UPDATE, kAddr1SyncTag,
-                              sync_pb::WalletMetadataSpecifics::ADDRESS,
-                              kAddr1Utf8, 2, 2, true),
-                          SyncCardChangeAndDataMatch(
-                              syncer::SyncChange::ACTION_UPDATE, kCard1SyncTag,
-                              sync_pb::WalletMetadataSpecifics::CARD,
-                              kCard1Utf8, 3, 4, kAddr1Utf8))));
-
-  local_.ProcessSyncChanges(FROM_HERE, changes);
-}
-
-// Verify that addition of known metadata is treated the same as an update.
-TEST_F(AutofillWalletMetadataSyncableServiceTest,
-       TreatAdditionOfKnownMetadataAsUpdateOnSyncChange) {
-  local_.UpdateAddressStats(BuildAddress(kAddr1, 2, 2, true));
-  local_.UpdateCardStats(BuildCard(kCard1, 3, 4, kAddr1));
-  remote_.UpdateAddressStats(BuildAddress(kAddr1, 2, 2, true));
-  remote_.UpdateCardStats(BuildCard(kCard1, 3, 4, kAddr1));
-  MergeMetadata(&local_, &remote_);
-  syncer::SyncChangeList changes;
-  changes.push_back(BuildAddressChange(
-      syncer::SyncChange::ACTION_ADD, kAddr1SyncTag,
-      sync_pb::WalletMetadataSpecifics::ADDRESS, kAddr1Utf8, 0, 0, false));
-  changes.push_back(BuildCardChange(
-      syncer::SyncChange::ACTION_ADD, kCard1SyncTag,
-      sync_pb::WalletMetadataSpecifics::CARD, kCard1Utf8, 0, 0, kAddr2Utf8));
-
-  EXPECT_CALL(local_, UpdateAddressStats(_)).Times(0);
-  EXPECT_CALL(local_, UpdateCardStats(_)).Times(0);
-  EXPECT_CALL(local_, SendChangesToSyncServer(UnorderedElementsAre(
-                          SyncAddressChangeAndDataMatch(
-                              syncer::SyncChange::ACTION_UPDATE, kAddr1SyncTag,
-                              sync_pb::WalletMetadataSpecifics::ADDRESS,
-                              kAddr1Utf8, 2, 2, true),
-                          SyncCardChangeAndDataMatch(
-                              syncer::SyncChange::ACTION_UPDATE, kCard1SyncTag,
-                              sync_pb::WalletMetadataSpecifics::CARD,
-                              kCard1Utf8, 3, 4, kAddr1Utf8))));
-
-  local_.ProcessSyncChanges(FROM_HERE, changes);
-}
-
-// Verify that an update of locally unknown metadata is ignored. There should be
-// no disk writes and no messages sent to the server.
-TEST_F(AutofillWalletMetadataSyncableServiceTest,
-       IgnoreUpdateOfUnknownMetadataOnSyncChange) {
-  local_.UpdateAddressStats(BuildAddress(kAddr1, 2, 2, true));
-  local_.UpdateCardStats(BuildCard(kCard1, 3, 4, kAddr1));
-  remote_.UpdateAddressStats(BuildAddress(kAddr1, 2, 2, true));
-  remote_.UpdateCardStats(BuildCard(kCard1, 3, 4, kAddr1));
-  MergeMetadata(&local_, &remote_);
-  syncer::SyncChangeList changes;
-  changes.push_back(BuildAddressChange(
-      syncer::SyncChange::ACTION_UPDATE, kAddr2SyncTag,
-      sync_pb::WalletMetadataSpecifics::ADDRESS, kAddr2Utf8, 0, 0, false));
-  changes.push_back(BuildCardChange(
-      syncer::SyncChange::ACTION_UPDATE, kCard2SyncTag,
-      sync_pb::WalletMetadataSpecifics::CARD, kCard2Utf8, 0, 0, kAddr2Utf8));
-
-  EXPECT_CALL(local_, UpdateAddressStats(_)).Times(0);
-  EXPECT_CALL(local_, UpdateCardStats(_)).Times(0);
-  EXPECT_CALL(local_, SendChangesToSyncServer(_)).Times(0);
-
-  local_.ProcessSyncChanges(FROM_HERE, changes);
-}
-
-// Verify that deletion from the sync server of locally unknown metadata is
-// ignored. There should be no disk writes and no messages sent to the server.
-TEST_F(AutofillWalletMetadataSyncableServiceTest,
-       IgnoreDeleteOfUnknownMetadataOnSyncChange) {
-  local_.UpdateAddressStats(BuildAddress(kAddr1, 2, 2, true));
-  local_.UpdateCardStats(BuildCard(kCard1, 3, 4, kAddr1));
-  remote_.UpdateAddressStats(BuildAddress(kAddr1, 2, 2, true));
-  remote_.UpdateCardStats(BuildCard(kCard1, 3, 4, kAddr1));
-  MergeMetadata(&local_, &remote_);
-  syncer::SyncChangeList changes;
-  changes.push_back(BuildAddressChange(
-      syncer::SyncChange::ACTION_DELETE, kAddr2SyncTag,
-      sync_pb::WalletMetadataSpecifics::ADDRESS, kAddr2Utf8, 0, 0, false));
-  changes.push_back(BuildCardChange(
-      syncer::SyncChange::ACTION_DELETE, kCard2SyncTag,
-      sync_pb::WalletMetadataSpecifics::CARD, kCard2Utf8, 0, 0, kAddr2Utf8));
-
-  EXPECT_CALL(local_, UpdateAddressStats(_)).Times(0);
-  EXPECT_CALL(local_, UpdateCardStats(_)).Times(0);
-  EXPECT_CALL(local_, SendChangesToSyncServer(_)).Times(0);
-
-  local_.ProcessSyncChanges(FROM_HERE, changes);
-}
-
-// Verify that deletion from the sync server of locally existing metadata will
-// trigger an undelete message sent to the server.
-TEST_F(AutofillWalletMetadataSyncableServiceTest,
-       UndeleteExistingMetadataOnSyncChange) {
-  local_.UpdateAddressStats(BuildAddress(kAddr1, 2, 2, true));
-  local_.UpdateCardStats(BuildCard(kCard1, 3, 4, kAddr1));
-  remote_.UpdateAddressStats(BuildAddress(kAddr1, 2, 2, true));
-  remote_.UpdateCardStats(BuildCard(kCard1, 3, 4, kAddr1));
-  MergeMetadata(&local_, &remote_);
-  syncer::SyncChangeList changes;
-  changes.push_back(BuildAddressChange(
-      syncer::SyncChange::ACTION_DELETE, kAddr1SyncTag,
-      sync_pb::WalletMetadataSpecifics::ADDRESS, kAddr1Utf8, 0, 0, false));
-  changes.push_back(BuildCardChange(
-      syncer::SyncChange::ACTION_DELETE, kCard1SyncTag,
-      sync_pb::WalletMetadataSpecifics::CARD, kCard1Utf8, 0, 0, kAddr2Utf8));
-
-  EXPECT_CALL(local_, UpdateAddressStats(_)).Times(0);
-  EXPECT_CALL(local_, UpdateCardStats(_)).Times(0);
-  EXPECT_CALL(local_, SendChangesToSyncServer(UnorderedElementsAre(
-                          SyncAddressChangeAndDataMatch(
-                              syncer::SyncChange::ACTION_ADD, kAddr1SyncTag,
-                              sync_pb::WalletMetadataSpecifics::ADDRESS,
-                              kAddr1Utf8, 2, 2, true),
-                          SyncCardChangeAndDataMatch(
-                              syncer::SyncChange::ACTION_ADD, kCard1SyncTag,
-                              sync_pb::WalletMetadataSpecifics::CARD,
-                              kCard1Utf8, 3, 4, kAddr1Utf8))));
-
-  local_.ProcessSyncChanges(FROM_HERE, changes);
-}
-
-// Verify that processing sync changes maintains the local cache of sync server
-// data, which is used to avoid calling the expensive GetAllSyncData() function.
-TEST_F(AutofillWalletMetadataSyncableServiceTest,
-       CacheIsUpToDateAfterSyncChange) {
-  local_.UpdateAddressStats(BuildAddress(kAddr1, 2, 2, true));
-  local_.UpdateAddressStats(BuildAddress(kAddr2, 3, 4, false));
-  local_.UpdateCardStats(BuildCard(kCard1, 5, 6, kAddr1));
-  local_.UpdateCardStats(BuildCard(kCard2, 7, 8, kAddr2));
-  remote_.UpdateAddressStats(BuildAddress(kAddr1, 2, 2, true));
-  remote_.UpdateAddressStats(BuildAddress(kAddr2, 3, 4, false));
-  remote_.UpdateCardStats(BuildCard(kCard1, 5, 6, kAddr1));
-  remote_.UpdateCardStats(BuildCard(kCard2, 7, 8, kAddr2));
-  MergeMetadata(&local_, &remote_);
-  syncer::SyncChangeList changes;
-  changes.push_back(BuildAddressChange(
-      syncer::SyncChange::ACTION_UPDATE, kAddr1SyncTag,
-      sync_pb::WalletMetadataSpecifics::ADDRESS, kAddr1Utf8, 10, 20, false));
-  changes.push_back(BuildCardChange(
-      syncer::SyncChange::ACTION_UPDATE, kCard1SyncTag,
-      sync_pb::WalletMetadataSpecifics::CARD, kCard1Utf8, 50, 60, kAddr1Utf8));
-  local_.ProcessSyncChanges(FROM_HERE, changes);
-  // This method dooes not trigger notifications or sync:
-  local_.ClearServerData();
-
-  EXPECT_CALL(
-      local_,
-      SendChangesToSyncServer(UnorderedElementsAre(
-          SyncChangeMatches(syncer::SyncChange::ACTION_DELETE, kAddr1SyncTag),
-          SyncChangeMatches(syncer::SyncChange::ACTION_DELETE, kAddr2SyncTag),
-          SyncChangeMatches(syncer::SyncChange::ACTION_DELETE, kCard1SyncTag),
-          SyncChangeMatches(syncer::SyncChange::ACTION_DELETE,
-                            kCard2SyncTag))));
-
-  local_.AutofillMultipleChangedBySync();
-}
-
-// Verify that Wallet data arriving after metadata will not send lower metadata
-// values to the sync server.
-TEST_F(AutofillWalletMetadataSyncableServiceTest,
-       SaveHigherValuesLocallyOnLateDataArrival) {
-  remote_.UpdateAddressStats(BuildAddress(kAddr1, 2, 2, false));
-  remote_.UpdateCardStats(BuildCard(kCard1, 5, 6, kAddr1));
-  MergeMetadata(&local_, &remote_);
-  syncer::SyncChangeList changes;
-  changes.push_back(BuildAddressChange(
-      syncer::SyncChange::ACTION_UPDATE, kAddr1SyncTag,
-      sync_pb::WalletMetadataSpecifics::ADDRESS, kAddr1Utf8, 5, 6, true));
-  changes.push_back(BuildCardChange(
-      syncer::SyncChange::ACTION_UPDATE, kCard1SyncTag,
-      sync_pb::WalletMetadataSpecifics::CARD, kCard1Utf8, 7, 8, kAddr2Utf8));
-  local_.ProcessSyncChanges(FROM_HERE, changes);
-  local_.UpdateAddressStats(BuildAddress(kAddr1, 0, 0, true));
-  local_.UpdateCardStats(BuildCard(kCard1, 0, 0, kAddr2));
-
-  EXPECT_CALL(local_, UpdateAddressStats(
-                          AutofillAddressMetadataMatches(kAddr1, 5, 6, true)));
-  EXPECT_CALL(local_, UpdateCardStats(
-                          AutofillCardMetadataMatches(kCard1, 7, 8, kAddr2)));
-  EXPECT_CALL(local_, SendChangesToSyncServer(_)).Times(0);
-
-  local_.AutofillMultipleChangedBySync();
-}
-
-// Verify that processing a small subset of metadata changes before any Wallet
-// data arrived will not cause sending lower metadata values to the sync server
-// once the data finally arrives.
-TEST_F(AutofillWalletMetadataSyncableServiceTest,
-       SaveHigherValuesLocallyOnLateDataArrivalAfterPartialUpdates) {
-  remote_.UpdateAddressStats(BuildAddress(kAddr1, 2, 2, false));
-  remote_.UpdateAddressStats(BuildAddress(kAddr2, 3, 4, false));
-  remote_.UpdateCardStats(BuildCard(kCard1, 5, 6, kAddr1));
-  remote_.UpdateCardStats(BuildCard(kCard2, 7, 8, kAddr1));
-  MergeMetadata(&local_, &remote_);
-  syncer::SyncChangeList changes;
-  changes.push_back(BuildAddressChange(
-      syncer::SyncChange::ACTION_UPDATE, kAddr1SyncTag,
-      sync_pb::WalletMetadataSpecifics::ADDRESS, kAddr1Utf8, 9, 10, false));
-  changes.push_back(BuildCardChange(
-      syncer::SyncChange::ACTION_UPDATE, kCard1SyncTag,
-      sync_pb::WalletMetadataSpecifics::CARD, kCard1Utf8, 11, 12, kAddr2Utf8));
-  changes.push_back(BuildAddressChange(
-      syncer::SyncChange::ACTION_UPDATE, kAddr2SyncTag,
-      sync_pb::WalletMetadataSpecifics::ADDRESS, kAddr2Utf8, 13, 14, true));
-  changes.push_back(BuildCardChange(
-      syncer::SyncChange::ACTION_UPDATE, kCard2SyncTag,
-      sync_pb::WalletMetadataSpecifics::CARD, kCard2Utf8, 15, 16, kAddr1Utf8));
-  local_.ProcessSyncChanges(FROM_HERE, changes);
-  changes.resize(2);
-  local_.ProcessSyncChanges(FROM_HERE, changes);
-  local_.UpdateAddressStats(BuildAddress(kAddr1, 0, 0, false));
-  local_.UpdateAddressStats(BuildAddress(kAddr2, 0, 0, false));
-  local_.UpdateCardStats(BuildCard(kCard1, 0, 0, kAddr1));
-  local_.UpdateCardStats(BuildCard(kCard2, 0, 0, kAddr2));
-
-  EXPECT_CALL(local_, UpdateAddressStats(AutofillAddressMetadataMatches(
-                          kAddr1, 9, 10, false)));
-  EXPECT_CALL(local_, UpdateCardStats(
-                          AutofillCardMetadataMatches(kCard1, 11, 12, kAddr2)));
-  EXPECT_CALL(local_, UpdateAddressStats(AutofillAddressMetadataMatches(
-                          kAddr2, 13, 14, true)));
-  EXPECT_CALL(local_, UpdateCardStats(
-                          AutofillCardMetadataMatches(kCard2, 15, 16, kAddr1)));
-  EXPECT_CALL(local_, SendChangesToSyncServer(_)).Times(0);
-
-  local_.AutofillMultipleChangedBySync();
-}
-
-// Verify that the merge logic keeps the best data on a field by field basis.
-// Make sure that if the better data is split across the local and server
-// version, both are updated with the merge results.
-TEST_F(AutofillWalletMetadataSyncableServiceTest, SaveHigherValues_Mixed1) {
-  local_.UpdateAddressStats(BuildAddress(kAddr1, 2, 20, true));
-  local_.UpdateCardStats(BuildCard(kCard1, 30, 4, ""));
-  remote_.UpdateAddressStats(BuildAddress(kAddr1, 10, 2, false));
-  remote_.UpdateCardStats(BuildCard(kCard1, 3, 40, kAddr1));
-
-  EXPECT_CALL(local_, UpdateAddressStats(AutofillAddressMetadataMatches(
-                          kAddr1, 10, 20, true)));
-  EXPECT_CALL(local_, UpdateCardStats(
-                          AutofillCardMetadataMatches(kCard1, 30, 40, kAddr1)));
-  EXPECT_CALL(local_, SendChangesToSyncServer(UnorderedElementsAre(
-                          SyncAddressChangeAndDataMatch(
-                              syncer::SyncChange::ACTION_UPDATE, kAddr1SyncTag,
-                              sync_pb::WalletMetadataSpecifics::ADDRESS,
-                              kAddr1Utf8, 10, 20, true),
-                          SyncCardChangeAndDataMatch(
-                              syncer::SyncChange::ACTION_UPDATE, kCard1SyncTag,
-                              sync_pb::WalletMetadataSpecifics::CARD,
-                              kCard1Utf8, 30, 40, kAddr1Utf8))));
-
-  MergeMetadata(&local_, &remote_);
-}
-
-// Verify that the merge logic keeps the best data on a field by field basis.
-// Make sure that if the better data is split across the local and server
-// version, both are updated with the merge results.
-// Same as SaveHigherValues_Mixed1 but with the higher values moved from local
-// to server and vice versa.
-TEST_F(AutofillWalletMetadataSyncableServiceTest, SaveHigherValues_Mixed2) {
-  local_.UpdateAddressStats(BuildAddress(kAddr1, 10, 2, false));
-  local_.UpdateCardStats(BuildCard(kCard1, 3, 40, kAddr1));
-  remote_.UpdateAddressStats(BuildAddress(kAddr1, 1, 20, true));
-  remote_.UpdateCardStats(BuildCard(kCard1, 30, 4, ""));
-
-  EXPECT_CALL(local_, UpdateAddressStats(AutofillAddressMetadataMatches(
-                          kAddr1, 10, 20, true)));
-  EXPECT_CALL(local_, UpdateCardStats(
-                          AutofillCardMetadataMatches(kCard1, 30, 40, kAddr1)));
-  EXPECT_CALL(local_, SendChangesToSyncServer(UnorderedElementsAre(
-                          SyncAddressChangeAndDataMatch(
-                              syncer::SyncChange::ACTION_UPDATE, kAddr1SyncTag,
-                              sync_pb::WalletMetadataSpecifics::ADDRESS,
-                              kAddr1Utf8, 10, 20, true),
-                          SyncCardChangeAndDataMatch(
-                              syncer::SyncChange::ACTION_UPDATE, kCard1SyncTag,
-                              sync_pb::WalletMetadataSpecifics::CARD,
-                              kCard1Utf8, 30, 40, kAddr1Utf8))));
-
-  MergeMetadata(&local_, &remote_);
-}
-
-// Verify that if both local and server have a different non empty billing
-// address id refering to a Wallet address, the one with the most recent
-// (bigger) use date is kept.
-TEST_F(AutofillWalletMetadataSyncableServiceTest,
-       DifferentServerBillingAddressId_LocalMostRecent) {
-  local_.UpdateCardStats(BuildCard(kCard1, 3, 40, kAddr1));
-  remote_.UpdateCardStats(BuildCard(kCard1, 3, 4, kAddr2));
-
-  // The value from the local should be kept because it has a more recent use
-  // date.
-  EXPECT_CALL(local_, UpdateCardStats(_)).Times(0);
-  EXPECT_CALL(local_, SendChangesToSyncServer(
-                          UnorderedElementsAre(SyncCardChangeAndDataMatch(
-                              syncer::SyncChange::ACTION_UPDATE, kCard1SyncTag,
-                              sync_pb::WalletMetadataSpecifics::CARD,
-                              kCard1Utf8, 3, 40, kAddr1Utf8))));
-
-  MergeMetadata(&local_, &remote_);
-}
-
-// Verify that if both local and server have a different non empty billing
-// address id refering to a Wallet address, the one with the most recent
-// (bigger) use date is kept.
-TEST_F(AutofillWalletMetadataSyncableServiceTest,
-       DifferentServerBillingAddressId_RemoteMostRecent) {
-  local_.UpdateCardStats(BuildCard(kCard1, 3, 4, kAddr1));
-  remote_.UpdateCardStats(BuildCard(kCard1, 3, 40, kAddr2));
-
-  // The value from the remote should be kept because it has a more recent use
-  // date.
-  EXPECT_CALL(local_, UpdateCardStats(
-                          AutofillCardMetadataMatches(kCard1, 3, 40, kAddr2)));
-  EXPECT_CALL(local_, SendChangesToSyncServer(_)).Times(0);
-
-  MergeMetadata(&local_, &remote_);
-}
-
-// Verify that if both local and server have a different non empty billing
-// address id refering to a local profile, the one with the most recent (bigger)
-// use date is kept.
-TEST_F(AutofillWalletMetadataSyncableServiceTest,
-       DifferentLocalBillingAddressId_LocalMostRecent) {
-  local_.UpdateCardStats(BuildCard(kCard1, 3, 40, kLocalAddr1));
-  remote_.UpdateCardStats(BuildCard(kCard1, 3, 4, kLocalAddr2));
-
-  // The value from the local should be kept because it has a more recent use
-  // date.
-  EXPECT_CALL(local_, UpdateCardStats(_)).Times(0);
-  EXPECT_CALL(local_, SendChangesToSyncServer(
-                          UnorderedElementsAre(SyncCardChangeAndDataMatch(
-                              syncer::SyncChange::ACTION_UPDATE, kCard1SyncTag,
-                              sync_pb::WalletMetadataSpecifics::CARD,
-                              kCard1Utf8, 3, 40, kLocalAddr1Utf8))));
-
-  MergeMetadata(&local_, &remote_);
-}
-
-// Verify that if both local and server have a different non empty billing
-// address id refering to a local profile, the one with the most recent (bigger)
-// use date is kept.
-TEST_F(AutofillWalletMetadataSyncableServiceTest,
-       DifferentLocalBillingAddressId_RemoteMostRecent) {
-  local_.UpdateCardStats(BuildCard(kCard1, 3, 4, kLocalAddr1));
-  remote_.UpdateCardStats(BuildCard(kCard1, 3, 40, kLocalAddr2));
-
-  // The value from the remote should be kept because it has a more recent use
-  // date.
-  EXPECT_CALL(local_, UpdateCardStats(AutofillCardMetadataMatches(
-                          kCard1, 3, 40, kLocalAddr2)));
-  EXPECT_CALL(local_, SendChangesToSyncServer(_)).Times(0);
-
-  MergeMetadata(&local_, &remote_);
-}
-
-// Verify that if both local and server have a different non empty billing
-// address id, the one refering to a local profile is always kept.
-TEST_F(AutofillWalletMetadataSyncableServiceTest,
-       DifferentBillingAddressId_KeepLocalId_Local) {
-  local_.UpdateCardStats(BuildCard(kCard1, 3, 4, kLocalAddr1));
-  remote_.UpdateCardStats(BuildCard(kCard1, 3, 4, kAddr2));
-
-  // The billing address from the local version of the card should be kept since
-  // it refers to a local autofill profile.
-  EXPECT_CALL(local_, UpdateCardStats(_)).Times(0);
-  EXPECT_CALL(local_, SendChangesToSyncServer(
-                          UnorderedElementsAre(SyncCardChangeAndDataMatch(
-                              syncer::SyncChange::ACTION_UPDATE, kCard1SyncTag,
-                              sync_pb::WalletMetadataSpecifics::CARD,
-                              kCard1Utf8, 3, 4, kLocalAddr1Utf8))));
-
-  MergeMetadata(&local_, &remote_);
-}
-
-// Verify that if both local and server have a different non empty billing
-// address id, the one refering to a local profile is always kept, even id the
-// other was used more recently.
-TEST_F(AutofillWalletMetadataSyncableServiceTest,
-       DifferentBillingAddressId_KeepLocalId_Remote) {
-  local_.UpdateCardStats(BuildCard(kCard1, 3, 4, kAddr2));
-  remote_.UpdateCardStats(BuildCard(kCard1, 3, 4, kLocalAddr1));
-
-  // The billing address from the remote version of the card should be kept
-  // since it refers to a local autofill profile.
-  EXPECT_CALL(local_, UpdateCardStats(AutofillCardMetadataMatches(
-                          kCard1, 3, 4, kLocalAddr1)));
-  EXPECT_CALL(local_, SendChangesToSyncServer(_)).Times(0);
-
-  MergeMetadata(&local_, &remote_);
-}
-
-// Verify that if both local and server have a different non empty billing
-// address id, the one refering to a local profile is always kept, even id the
-// other was used more recently. Also makes sure that for the rest of the fields
-// the highest values are kept.
-TEST_F(AutofillWalletMetadataSyncableServiceTest,
-       SaveHigherValues_DifferentBillingAddressId_KeepLocalId_Local) {
-  local_.UpdateCardStats(BuildCard(kCard1, 3, 4, kLocalAddr1));
-  remote_.UpdateCardStats(BuildCard(kCard1, 30, 40, kAddr2));
-
-  // The billing address from the local version of the card should be kept since
-  // it refers to a local autofill profile. The highest use stats should
-  // be kept.
-  EXPECT_CALL(local_, UpdateCardStats(AutofillCardMetadataMatches(
-                          kCard1, 30, 40, kLocalAddr1)));
-  EXPECT_CALL(local_, SendChangesToSyncServer(
-                          UnorderedElementsAre(SyncCardChangeAndDataMatch(
-                              syncer::SyncChange::ACTION_UPDATE, kCard1SyncTag,
-                              sync_pb::WalletMetadataSpecifics::CARD,
-                              kCard1Utf8, 30, 40, kLocalAddr1Utf8))));
-
-  MergeMetadata(&local_, &remote_);
-}
-
-// Verify that if both local and server have a different non empty billing
-// address id, the one refering to a local profile is always kept. Also makes
-// sure that for the rest of the fields the highest values are kept.
-TEST_F(AutofillWalletMetadataSyncableServiceTest,
-       SaveHigherValues_DifferentBillingAddressId_KeepLocalId_Remote) {
-  local_.UpdateCardStats(BuildCard(kCard1, 30, 40, kAddr2));
-  remote_.UpdateCardStats(BuildCard(kCard1, 3, 4, kLocalAddr1));
-
-  // The billing address from the remote version of the card should be kept
-  // since it refers to a local autofill profile. The highest use stats should
-  // be kept.
-  EXPECT_CALL(local_, UpdateCardStats(AutofillCardMetadataMatches(
-                          kCard1, 30, 40, kLocalAddr1)));
-  EXPECT_CALL(local_, SendChangesToSyncServer(
-                          UnorderedElementsAre(SyncCardChangeAndDataMatch(
-                              syncer::SyncChange::ACTION_UPDATE, kCard1SyncTag,
-                              sync_pb::WalletMetadataSpecifics::CARD,
-                              kCard1Utf8, 30, 40, kLocalAddr1Utf8))));
-
-  MergeMetadata(&local_, &remote_);
-}
-
-// Verify that if both local and server have a different non empty billing
-// address id refering to a Wallet address with the same timestamp, the remote
-// one is kept.
-TEST_F(AutofillWalletMetadataSyncableServiceTest,
-       DifferentServerBillingAddressId_BothSameTimestamp) {
-  local_.UpdateCardStats(BuildCard(kCard1, 3, 4, kAddr1));
-  remote_.UpdateCardStats(BuildCard(kCard1, 3, 4, kAddr2));
-
-  // The value from the remote should be kept to promote a stable set of values.
-  EXPECT_CALL(local_, UpdateCardStats(
-                          AutofillCardMetadataMatches(kCard1, 3, 4, kAddr2)));
-  EXPECT_CALL(local_, SendChangesToSyncServer(_)).Times(0);
-
-  MergeMetadata(&local_, &remote_);
-}
-
-// Verify that if both local and server have a different non empty billing
-// address id refering to a local profile with the same timestamp, the remote
-// one is kept.
-TEST_F(AutofillWalletMetadataSyncableServiceTest,
-       DifferentLocalBillingAddressId_BothSameTimestamp) {
-  local_.UpdateCardStats(BuildCard(kCard1, 3, 4, kLocalAddr1));
-  remote_.UpdateCardStats(BuildCard(kCard1, 3, 4, kLocalAddr2));
-
-  // The value from the remote should be kept to promote a stable set of values.
-  EXPECT_CALL(local_, UpdateCardStats(AutofillCardMetadataMatches(
-                          kCard1, 3, 4, kLocalAddr2)));
-  EXPECT_CALL(local_, SendChangesToSyncServer(_)).Times(0);
-
-  MergeMetadata(&local_, &remote_);
-}
-
-// Verify that if the local card has a use_count of one, its use_date is
-// replaced even if it is more recent (new cards are created with a use_date set
-// to the current time).
-TEST_F(AutofillWalletMetadataSyncableServiceTest, NewLocalCard) {
-  local_.UpdateCardStats(BuildCard(kCard1, 1, 5000, kLocalAddr1));
-  remote_.UpdateCardStats(BuildCard(kCard1, 3, 4, kLocalAddr1));
-
-  EXPECT_CALL(local_, UpdateCardStats(AutofillCardMetadataMatches(
-                          kCard1, 3, 4, kLocalAddr1)));
-  EXPECT_CALL(local_, SendChangesToSyncServer(_)).Times(0);
-
-  MergeMetadata(&local_, &remote_);
-}
-
-// Tests that processing remote changes does not trigger a merge. This is a
-// specific test for reflection blocking in notifications.
-TEST_F(AutofillWalletMetadataSyncableServiceTest,
-       RemoteChangesDoNotTriggerMerge) {
-  // Make the backend broadcast back the notifications it receives
-  ON_CALL(backend_, NotifyOfMultipleAutofillChanges())
-      .WillByDefault(
-          DoAll(Invoke(&local_, &MockService::AutofillMultipleChangedBySync),
-                Invoke(&remote_, &MockService::AutofillMultipleChangedBySync)));
-
-  // Get initial data from |remote_| into |local_|.
-  local_.UpdateAddressStats(BuildAddress(kAddr1, 2, 2, true));
-  local_.UpdateCardStats(BuildCard(kCard1, 5, 6, kAddr1));
-  remote_.UpdateAddressStats(BuildAddress(kAddr1, 2, 2, true));
-  remote_.UpdateCardStats(BuildCard(kCard1, 5, 6, kAddr1));
-  MergeMetadata(&local_, &remote_);
-
-  // Silently update local card in the DB.
-  local_.UpdateCardStats(BuildCard(kCard1, 7, 8, kAddr1));
-
-  // Receive a remote update of the address.
-  syncer::SyncChangeList changes;
-  changes.push_back(BuildAddressChange(
-      syncer::SyncChange::ACTION_UPDATE, kAddr1SyncTag,
-      sync_pb::WalletMetadataSpecifics::ADDRESS, kAddr1Utf8, 10, 20, true));
-
-  // Processing remote change should not trigger a commit of the local change.
-  EXPECT_CALL(local_, SendChangesToSyncServer(_)).Times(0);
-
-  local_.ProcessSyncChanges(FROM_HERE, changes);
-}
-
-}  // namespace
-}  // namespace autofill
diff --git a/components/autofill_assistant/browser/BUILD.gn b/components/autofill_assistant/browser/BUILD.gn
index abd4cf3d..3d47bf3 100644
--- a/components/autofill_assistant/browser/BUILD.gn
+++ b/components/autofill_assistant/browser/BUILD.gn
@@ -149,8 +149,15 @@
     "user_action.cc",
     "user_action.h",
     "viewport_mode.h",
-    "web_controller.cc",
-    "web_controller.h",
+    "web/element_finder.cc",
+    "web/element_finder.h",
+    "web/element_position_getter.cc",
+    "web/element_position_getter.h",
+    "web/web_controller.cc",
+    "web/web_controller.h",
+    "web/web_controller_util.cc",
+    "web/web_controller_util.h",
+    "web/web_controller_worker.h",
     "website_login_fetcher.cc",
     "website_login_fetcher.h",
     "website_login_fetcher_impl.cc",
@@ -200,8 +207,6 @@
     "mock_personal_data_manager.h",
     "mock_service.cc",
     "mock_service.h",
-    "mock_web_controller.cc",
-    "mock_web_controller.h",
     "mock_website_login_fetcher.cc",
     "mock_website_login_fetcher.h",
     "protocol_utils_unittest.cc",
@@ -212,6 +217,8 @@
     "selector_unittest.cc",
     "string_conversions_util_unittest.cc",
     "trigger_context_unittest.cc",
+    "web/mock_web_controller.cc",
+    "web/mock_web_controller.h",
   ]
 
   deps = [
diff --git a/components/autofill_assistant/browser/actions/autofill_action_unittest.cc b/components/autofill_assistant/browser/actions/autofill_action_unittest.cc
index 5fdf643..e2ad489 100644
--- a/components/autofill_assistant/browser/actions/autofill_action_unittest.cc
+++ b/components/autofill_assistant/browser/actions/autofill_action_unittest.cc
@@ -14,7 +14,7 @@
 #include "components/autofill/core/browser/data_model/autofill_profile.h"
 #include "components/autofill_assistant/browser/actions/mock_action_delegate.h"
 #include "components/autofill_assistant/browser/mock_personal_data_manager.h"
-#include "components/autofill_assistant/browser/mock_web_controller.h"
+#include "components/autofill_assistant/browser/web/mock_web_controller.h"
 #include "testing/gmock/include/gmock/gmock.h"
 
 namespace autofill_assistant {
diff --git a/components/autofill_assistant/browser/actions/configure_bottom_sheet_action_unittest.cc b/components/autofill_assistant/browser/actions/configure_bottom_sheet_action_unittest.cc
index ad34182..c6bfd874 100644
--- a/components/autofill_assistant/browser/actions/configure_bottom_sheet_action_unittest.cc
+++ b/components/autofill_assistant/browser/actions/configure_bottom_sheet_action_unittest.cc
@@ -11,7 +11,7 @@
 #include "base/test/bind_test_util.h"
 #include "base/test/task_environment.h"
 #include "components/autofill_assistant/browser/actions/mock_action_delegate.h"
-#include "components/autofill_assistant/browser/mock_web_controller.h"
+#include "components/autofill_assistant/browser/web/mock_web_controller.h"
 #include "testing/gmock/include/gmock/gmock.h"
 
 namespace autofill_assistant {
diff --git a/components/autofill_assistant/browser/actions/prompt_action_unittest.cc b/components/autofill_assistant/browser/actions/prompt_action_unittest.cc
index 7092ee8..009a4513 100644
--- a/components/autofill_assistant/browser/actions/prompt_action_unittest.cc
+++ b/components/autofill_assistant/browser/actions/prompt_action_unittest.cc
@@ -12,7 +12,7 @@
 #include "base/test/mock_callback.h"
 #include "base/test/task_environment.h"
 #include "components/autofill_assistant/browser/actions/mock_action_delegate.h"
-#include "components/autofill_assistant/browser/mock_web_controller.h"
+#include "components/autofill_assistant/browser/web/mock_web_controller.h"
 #include "testing/gmock/include/gmock/gmock.h"
 
 namespace autofill_assistant {
diff --git a/components/autofill_assistant/browser/actions/wait_for_dom_action_unittest.cc b/components/autofill_assistant/browser/actions/wait_for_dom_action_unittest.cc
index 152a5b4..15426de0 100644
--- a/components/autofill_assistant/browser/actions/wait_for_dom_action_unittest.cc
+++ b/components/autofill_assistant/browser/actions/wait_for_dom_action_unittest.cc
@@ -11,7 +11,7 @@
 #include "base/test/gmock_callback_support.h"
 #include "base/test/mock_callback.h"
 #include "components/autofill_assistant/browser/actions/mock_action_delegate.h"
-#include "components/autofill_assistant/browser/mock_web_controller.h"
+#include "components/autofill_assistant/browser/web/mock_web_controller.h"
 #include "testing/gmock/include/gmock/gmock.h"
 
 namespace autofill_assistant {
diff --git a/components/autofill_assistant/browser/batch_element_checker.cc b/components/autofill_assistant/browser/batch_element_checker.cc
index 4ead9bf..4cdad7c7 100644
--- a/components/autofill_assistant/browser/batch_element_checker.cc
+++ b/components/autofill_assistant/browser/batch_element_checker.cc
@@ -10,7 +10,7 @@
 #include "base/single_thread_task_runner.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "base/time/time.h"
-#include "components/autofill_assistant/browser/web_controller.h"
+#include "components/autofill_assistant/browser/web/web_controller.h"
 
 namespace autofill_assistant {
 
diff --git a/components/autofill_assistant/browser/batch_element_checker.h b/components/autofill_assistant/browser/batch_element_checker.h
index 28eb4a85..9cf89362 100644
--- a/components/autofill_assistant/browser/batch_element_checker.h
+++ b/components/autofill_assistant/browser/batch_element_checker.h
@@ -40,7 +40,7 @@
   using GetFieldValueCallback =
       base::OnceCallback<void(bool, const std::string&)>;
 
-  // Checks an an element.
+  // Checks an element.
   //
   // New element checks cannot be added once Run has been called.
   void AddElementCheck(const Selector& selector, ElementCheckCallback callback);
diff --git a/components/autofill_assistant/browser/batch_element_checker_unittest.cc b/components/autofill_assistant/browser/batch_element_checker_unittest.cc
index cd86325..37695c2 100644
--- a/components/autofill_assistant/browser/batch_element_checker_unittest.cc
+++ b/components/autofill_assistant/browser/batch_element_checker_unittest.cc
@@ -12,7 +12,7 @@
 #include "base/test/gmock_callback_support.h"
 #include "base/test/mock_callback.h"
 #include "base/test/task_environment.h"
-#include "components/autofill_assistant/browser/mock_web_controller.h"
+#include "components/autofill_assistant/browser/web/mock_web_controller.h"
 #include "testing/gmock/include/gmock/gmock.h"
 
 using ::base::test::RunOnceCallback;
diff --git a/components/autofill_assistant/browser/controller.h b/components/autofill_assistant/browser/controller.h
index f57434b..db85c57b 100644
--- a/components/autofill_assistant/browser/controller.h
+++ b/components/autofill_assistant/browser/controller.h
@@ -26,7 +26,7 @@
 #include "components/autofill_assistant/browser/trigger_context.h"
 #include "components/autofill_assistant/browser/ui_delegate.h"
 #include "components/autofill_assistant/browser/user_action.h"
-#include "components/autofill_assistant/browser/web_controller.h"
+#include "components/autofill_assistant/browser/web/web_controller.h"
 #include "content/public/browser/web_contents_delegate.h"
 #include "content/public/browser/web_contents_observer.h"
 
diff --git a/components/autofill_assistant/browser/controller_unittest.cc b/components/autofill_assistant/browser/controller_unittest.cc
index f971edd..672c941 100644
--- a/components/autofill_assistant/browser/controller_unittest.cc
+++ b/components/autofill_assistant/browser/controller_unittest.cc
@@ -13,10 +13,9 @@
 #include "components/autofill_assistant/browser/features.h"
 #include "components/autofill_assistant/browser/mock_controller_observer.h"
 #include "components/autofill_assistant/browser/mock_service.h"
-#include "components/autofill_assistant/browser/mock_web_controller.h"
 #include "components/autofill_assistant/browser/service.h"
 #include "components/autofill_assistant/browser/trigger_context.h"
-#include "content/public/test/browser_task_environment.h"
+#include "components/autofill_assistant/browser/web/mock_web_controller.h"
 #include "content/public/test/navigation_simulator.h"
 #include "content/public/test/test_browser_context.h"
 #include "content/public/test/test_renderer_host.h"
diff --git a/components/autofill_assistant/browser/element_area.cc b/components/autofill_assistant/browser/element_area.cc
index cd9c11a..23ddb00 100644
--- a/components/autofill_assistant/browser/element_area.cc
+++ b/components/autofill_assistant/browser/element_area.cc
@@ -12,7 +12,7 @@
 #include "base/threading/thread_task_runner_handle.h"
 #include "base/time/time.h"
 #include "components/autofill_assistant/browser/script_executor_delegate.h"
-#include "components/autofill_assistant/browser/web_controller.h"
+#include "components/autofill_assistant/browser/web/web_controller.h"
 
 namespace autofill_assistant {
 
diff --git a/components/autofill_assistant/browser/element_area_unittest.cc b/components/autofill_assistant/browser/element_area_unittest.cc
index 946d737..db37aa6 100644
--- a/components/autofill_assistant/browser/element_area_unittest.cc
+++ b/components/autofill_assistant/browser/element_area_unittest.cc
@@ -14,8 +14,8 @@
 #include "base/test/mock_callback.h"
 #include "base/test/task_environment.h"
 #include "components/autofill_assistant/browser/fake_script_executor_delegate.h"
-#include "components/autofill_assistant/browser/mock_web_controller.h"
 #include "components/autofill_assistant/browser/script_executor_delegate.h"
+#include "components/autofill_assistant/browser/web/mock_web_controller.h"
 #include "testing/gmock/include/gmock/gmock.h"
 
 using ::base::test::RunOnceCallback;
diff --git a/components/autofill_assistant/browser/element_precondition_unittest.cc b/components/autofill_assistant/browser/element_precondition_unittest.cc
index 5850608..eb00f23c 100644
--- a/components/autofill_assistant/browser/element_precondition_unittest.cc
+++ b/components/autofill_assistant/browser/element_precondition_unittest.cc
@@ -12,8 +12,8 @@
 #include "base/test/gmock_callback_support.h"
 #include "base/test/mock_callback.h"
 #include "components/autofill_assistant/browser/batch_element_checker.h"
-#include "components/autofill_assistant/browser/mock_web_controller.h"
 #include "components/autofill_assistant/browser/service.pb.h"
+#include "components/autofill_assistant/browser/web/mock_web_controller.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "third_party/re2/src/re2/re2.h"
 
diff --git a/components/autofill_assistant/browser/script_executor.cc b/components/autofill_assistant/browser/script_executor.cc
index 42ac7a47..b079cfbd 100644
--- a/components/autofill_assistant/browser/script_executor.cc
+++ b/components/autofill_assistant/browser/script_executor.cc
@@ -23,7 +23,7 @@
 #include "components/autofill_assistant/browser/self_delete_full_card_requester.h"
 #include "components/autofill_assistant/browser/service.h"
 #include "components/autofill_assistant/browser/trigger_context.h"
-#include "components/autofill_assistant/browser/web_controller.h"
+#include "components/autofill_assistant/browser/web/web_controller.h"
 #include "components/strings/grit/components_strings.h"
 #include "ui/base/l10n/l10n_util.h"
 
diff --git a/components/autofill_assistant/browser/script_executor_unittest.cc b/components/autofill_assistant/browser/script_executor_unittest.cc
index c28d545f..f6d73e7 100644
--- a/components/autofill_assistant/browser/script_executor_unittest.cc
+++ b/components/autofill_assistant/browser/script_executor_unittest.cc
@@ -14,8 +14,8 @@
 #include "components/autofill_assistant/browser/client_memory.h"
 #include "components/autofill_assistant/browser/fake_script_executor_delegate.h"
 #include "components/autofill_assistant/browser/mock_service.h"
-#include "components/autofill_assistant/browser/mock_web_controller.h"
 #include "components/autofill_assistant/browser/service.h"
+#include "components/autofill_assistant/browser/web/mock_web_controller.h"
 #include "testing/gmock/include/gmock/gmock.h"
 
 namespace autofill_assistant {
diff --git a/components/autofill_assistant/browser/script_precondition.h b/components/autofill_assistant/browser/script_precondition.h
index a3fc996..db4502a 100644
--- a/components/autofill_assistant/browser/script_precondition.h
+++ b/components/autofill_assistant/browser/script_precondition.h
@@ -16,7 +16,7 @@
 #include "base/memory/weak_ptr.h"
 #include "components/autofill_assistant/browser/element_precondition.h"
 #include "components/autofill_assistant/browser/service.pb.h"
-#include "components/autofill_assistant/browser/web_controller.h"
+#include "components/autofill_assistant/browser/web/web_controller.h"
 
 namespace re2 {
 class RE2;
diff --git a/components/autofill_assistant/browser/script_precondition_unittest.cc b/components/autofill_assistant/browser/script_precondition_unittest.cc
index 1212019..d4057a1 100644
--- a/components/autofill_assistant/browser/script_precondition_unittest.cc
+++ b/components/autofill_assistant/browser/script_precondition_unittest.cc
@@ -11,9 +11,9 @@
 #include "base/run_loop.h"
 #include "base/test/gmock_callback_support.h"
 #include "components/autofill_assistant/browser/batch_element_checker.h"
-#include "components/autofill_assistant/browser/mock_web_controller.h"
 #include "components/autofill_assistant/browser/service.pb.h"
 #include "components/autofill_assistant/browser/trigger_context.h"
+#include "components/autofill_assistant/browser/web/mock_web_controller.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "third_party/re2/src/re2/re2.h"
 
diff --git a/components/autofill_assistant/browser/script_tracker_unittest.cc b/components/autofill_assistant/browser/script_tracker_unittest.cc
index 19457be..131774ab 100644
--- a/components/autofill_assistant/browser/script_tracker_unittest.cc
+++ b/components/autofill_assistant/browser/script_tracker_unittest.cc
@@ -10,10 +10,10 @@
 #include "base/test/mock_callback.h"
 #include "components/autofill_assistant/browser/fake_script_executor_delegate.h"
 #include "components/autofill_assistant/browser/mock_service.h"
-#include "components/autofill_assistant/browser/mock_web_controller.h"
 #include "components/autofill_assistant/browser/protocol_utils.h"
 #include "components/autofill_assistant/browser/script_executor_delegate.h"
 #include "components/autofill_assistant/browser/service.h"
+#include "components/autofill_assistant/browser/web/mock_web_controller.h"
 #include "testing/gmock/include/gmock/gmock.h"
 
 namespace autofill_assistant {
diff --git a/components/autofill_assistant/browser/web/element_finder.cc b/components/autofill_assistant/browser/web/element_finder.cc
new file mode 100644
index 0000000..41cc5b1f
--- /dev/null
+++ b/components/autofill_assistant/browser/web/element_finder.cc
@@ -0,0 +1,413 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/autofill_assistant/browser/web/element_finder.h"
+
+#include "components/autofill_assistant/browser/devtools/devtools_client.h"
+#include "components/autofill_assistant/browser/service.pb.h"
+#include "components/autofill_assistant/browser/web/web_controller_util.h"
+#include "content/public/browser/render_frame_host.h"
+#include "content/public/browser/web_contents.h"
+
+namespace autofill_assistant {
+
+namespace {
+// Javascript code to get document root element.
+const char* const kGetDocumentElement =
+    R"(
+    (function() {
+      return document.documentElement;
+    }())
+    )";
+
+// Javascript code to query an elements for a selector, either the first
+// (non-strict) or a single (strict) element.
+//
+// Returns undefined if no elements are found, TOO_MANY_ELEMENTS (18) if too
+// many elements were found and strict mode is enabled.
+const char* const kQuerySelector =
+    R"(function (selector, strictMode) {
+      var found = this.querySelectorAll(selector);
+      if(found.length == 0) return undefined;
+      if(found.length > 1 && strictMode) return 18;
+      return found[0];
+    })";
+
+// Javascript code to query a visible elements for a selector, either the first
+// (non-strict) or a single (strict) visible element.q
+//
+// Returns undefined if no elements are found, TOO_MANY_ELEMENTS (18) if too
+// many elements were found and strict mode is enabled.
+const char* const kQuerySelectorWithConditions =
+    R"(function (selector, strict, visible, inner_text_str, value_str) {
+        var found = this.querySelectorAll(selector);
+        var found_index = -1;
+        var inner_text_re = inner_text_str ? RegExp(inner_text_str) : undefined;
+        var value_re = value_str ? RegExp(value_str) : undefined;
+        var match = function(e) {
+          if (visible && e.getClientRects().length == 0) return false;
+          if (inner_text_re && !inner_text_re.test(e.innerText)) return false;
+          if (value_re && !value_re.test(e.value)) return false;
+          return true;
+        };
+        for (let i = 0; i < found.length; i++) {
+          if (match(found[i])) {
+            if (found_index != -1) return 18;
+            found_index = i;
+            if (!strict) break;
+          }
+        }
+        return found_index == -1 ? undefined : found[found_index];
+    })";
+
+bool ConvertPseudoType(const PseudoType pseudo_type,
+                       dom::PseudoType* pseudo_type_output) {
+  switch (pseudo_type) {
+    case PseudoType::UNDEFINED:
+      break;
+    case PseudoType::FIRST_LINE:
+      *pseudo_type_output = dom::PseudoType::FIRST_LINE;
+      return true;
+    case PseudoType::FIRST_LETTER:
+      *pseudo_type_output = dom::PseudoType::FIRST_LETTER;
+      return true;
+    case PseudoType::BEFORE:
+      *pseudo_type_output = dom::PseudoType::BEFORE;
+      return true;
+    case PseudoType::AFTER:
+      *pseudo_type_output = dom::PseudoType::AFTER;
+      return true;
+    case PseudoType::BACKDROP:
+      *pseudo_type_output = dom::PseudoType::BACKDROP;
+      return true;
+    case PseudoType::SELECTION:
+      *pseudo_type_output = dom::PseudoType::SELECTION;
+      return true;
+    case PseudoType::FIRST_LINE_INHERITED:
+      *pseudo_type_output = dom::PseudoType::FIRST_LINE_INHERITED;
+      return true;
+    case PseudoType::SCROLLBAR:
+      *pseudo_type_output = dom::PseudoType::SCROLLBAR;
+      return true;
+    case PseudoType::SCROLLBAR_THUMB:
+      *pseudo_type_output = dom::PseudoType::SCROLLBAR_THUMB;
+      return true;
+    case PseudoType::SCROLLBAR_BUTTON:
+      *pseudo_type_output = dom::PseudoType::SCROLLBAR_BUTTON;
+      return true;
+    case PseudoType::SCROLLBAR_TRACK:
+      *pseudo_type_output = dom::PseudoType::SCROLLBAR_TRACK;
+      return true;
+    case PseudoType::SCROLLBAR_TRACK_PIECE:
+      *pseudo_type_output = dom::PseudoType::SCROLLBAR_TRACK_PIECE;
+      return true;
+    case PseudoType::SCROLLBAR_CORNER:
+      *pseudo_type_output = dom::PseudoType::SCROLLBAR_CORNER;
+      return true;
+    case PseudoType::RESIZER:
+      *pseudo_type_output = dom::PseudoType::RESIZER;
+      return true;
+    case PseudoType::INPUT_LIST_BUTTON:
+      *pseudo_type_output = dom::PseudoType::INPUT_LIST_BUTTON;
+      return true;
+  }
+  return false;
+}
+}  // namespace
+
+ElementFinder::ElementFinder(content::WebContents* web_contents,
+                             DevtoolsClient* devtools_client,
+                             const Selector& selector,
+                             bool strict)
+    : web_contents_(web_contents),
+      devtools_client_(devtools_client),
+      selector_(selector),
+      strict_(strict),
+      element_result_(std::make_unique<Result>()) {}
+
+ElementFinder::~ElementFinder() = default;
+
+void ElementFinder::Start(Callback callback) {
+  callback_ = std::move(callback);
+
+  if (selector_.empty()) {
+    SendResult(ClientStatus(INVALID_SELECTOR));
+    return;
+  }
+  devtools_client_->GetRuntime()->Evaluate(
+      std::string(kGetDocumentElement),
+      base::BindOnce(&ElementFinder::OnGetDocumentElement,
+                     weak_ptr_factory_.GetWeakPtr()));
+}
+
+void ElementFinder::SendResult(const ClientStatus& status) {
+  DCHECK(callback_);
+  DCHECK(element_result_);
+  std::move(callback_).Run(status, std::move(element_result_));
+}
+
+void ElementFinder::OnGetDocumentElement(
+    std::unique_ptr<runtime::EvaluateResult> result) {
+  ClientStatus status = CheckJavaScriptResult(result.get(), __FILE__, __LINE__);
+  if (!status.ok()) {
+    DVLOG(1) << __func__ << " Failed to get document root element.";
+    SendResult(status);
+    return;
+  }
+  std::string object_id;
+  if (!SafeGetObjectId(result->GetResult(), &object_id)) {
+    DVLOG(1) << __func__ << " Failed to get document root element.";
+    SendResult(ClientStatus(ELEMENT_RESOLUTION_FAILED));
+    return;
+  }
+  element_result_->container_frame_host = web_contents_->GetMainFrame();
+  element_result_->container_frame_selector_index = 0;
+  element_result_->object_id = "";
+  RecursiveFindElement(object_id, 0);
+}
+
+void ElementFinder::RecursiveFindElement(const std::string& object_id,
+                                         size_t index) {
+  std::vector<std::unique_ptr<runtime::CallArgument>> argument;
+  argument.emplace_back(runtime::CallArgument::Builder()
+                            .SetValue(base::Value::ToUniquePtrValue(
+                                base::Value(selector_.selectors[index])))
+                            .Build());
+  // For finding intermediate elements, strict mode would be more appropriate,
+  // as long as the logic does not support more than one intermediate match.
+  //
+  // TODO(b/129387787): first, add logging to figure out whether it matters and
+  // decide between strict mode and full support for multiple matching
+  // intermeditate elements.
+  argument.emplace_back(
+      runtime::CallArgument::Builder()
+          .SetValue(base::Value::ToUniquePtrValue(base::Value(strict_)))
+          .Build());
+  std::string function;
+  if (index == (selector_.selectors.size() - 1)) {
+    if (selector_.must_be_visible || !selector_.inner_text_pattern.empty() ||
+        !selector_.value_pattern.empty()) {
+      function.assign(kQuerySelectorWithConditions);
+      argument.emplace_back(runtime::CallArgument::Builder()
+                                .SetValue(base::Value::ToUniquePtrValue(
+                                    base::Value(selector_.must_be_visible)))
+                                .Build());
+      argument.emplace_back(runtime::CallArgument::Builder()
+                                .SetValue(base::Value::ToUniquePtrValue(
+                                    base::Value(selector_.inner_text_pattern)))
+                                .Build());
+      argument.emplace_back(runtime::CallArgument::Builder()
+                                .SetValue(base::Value::ToUniquePtrValue(
+                                    base::Value(selector_.value_pattern)))
+                                .Build());
+    }
+  }
+  if (function.empty()) {
+    function.assign(kQuerySelector);
+  }
+  devtools_client_->GetRuntime()->CallFunctionOn(
+      runtime::CallFunctionOnParams::Builder()
+          .SetObjectId(object_id)
+          .SetArguments(std::move(argument))
+          .SetFunctionDeclaration(function)
+          .Build(),
+      base::BindOnce(&ElementFinder::OnQuerySelectorAll,
+                     weak_ptr_factory_.GetWeakPtr(), index));
+}
+
+void ElementFinder::OnQuerySelectorAll(
+    size_t index,
+    std::unique_ptr<runtime::CallFunctionOnResult> result) {
+  if (!result) {
+    // It is possible for a document element to already exist, but not be
+    // available yet to query because the document hasn't been loaded. This
+    // results in OnQuerySelectorAll getting a nullptr result. For this specific
+    // call, it is expected.
+    DVLOG(1) << __func__ << ": Context doesn't exist yet to query selector "
+             << index << " of " << selector_;
+    SendResult(ClientStatus(ELEMENT_RESOLUTION_FAILED));
+    return;
+  }
+  ClientStatus status = CheckJavaScriptResult(result.get(), __FILE__, __LINE__);
+  if (!status.ok()) {
+    DVLOG(1) << __func__ << ": Failed to query selector " << index << " of "
+             << selector_;
+    SendResult(status);
+    return;
+  }
+  int int_result;
+  if (SafeGetIntValue(result->GetResult(), &int_result)) {
+    DCHECK(int_result == TOO_MANY_ELEMENTS);
+    SendResult(ClientStatus(TOO_MANY_ELEMENTS));
+    return;
+  }
+  std::string object_id;
+  if (!SafeGetObjectId(result->GetResult(), &object_id)) {
+    SendResult(ClientStatus(ELEMENT_RESOLUTION_FAILED));
+    return;
+  }
+
+  if (selector_.selectors.size() == index + 1) {
+    // The pseudo type is associated to the final element matched by
+    // |selector_|, which means that we currently don't handle matching an
+    // element inside a pseudo element.
+    if (selector_.pseudo_type == PseudoType::UNDEFINED) {
+      // Return object id of the element.
+      element_result_->object_id = object_id;
+      SendResult(OkClientStatus());
+      return;
+    }
+
+    // We are looking for a pseudo element associated with this element.
+    dom::PseudoType pseudo_type;
+    if (!ConvertPseudoType(selector_.pseudo_type, &pseudo_type)) {
+      // Return empty result.
+      SendResult(ClientStatus(INVALID_ACTION));
+      return;
+    }
+
+    devtools_client_->GetDOM()->DescribeNode(
+        dom::DescribeNodeParams::Builder().SetObjectId(object_id).Build(),
+        base::BindOnce(&ElementFinder::OnDescribeNodeForPseudoElement,
+                       weak_ptr_factory_.GetWeakPtr(), pseudo_type));
+    return;
+  }
+
+  devtools_client_->GetDOM()->DescribeNode(
+      dom::DescribeNodeParams::Builder().SetObjectId(object_id).Build(),
+      base::BindOnce(&ElementFinder::OnDescribeNode,
+                     weak_ptr_factory_.GetWeakPtr(), object_id, index));
+}
+
+void ElementFinder::OnDescribeNodeForPseudoElement(
+    dom::PseudoType pseudo_type,
+    std::unique_ptr<dom::DescribeNodeResult> result) {
+  if (!result || !result->GetNode()) {
+    DVLOG(1) << __func__ << " Failed to describe the node for pseudo element.";
+    SendResult(UnexpectedErrorStatus(__FILE__, __LINE__));
+    return;
+  }
+
+  auto* node = result->GetNode();
+  if (node->HasPseudoElements()) {
+    for (const auto& pseudo_element : *(node->GetPseudoElements())) {
+      if (pseudo_element->HasPseudoType() &&
+          pseudo_element->GetPseudoType() == pseudo_type) {
+        devtools_client_->GetDOM()->ResolveNode(
+            dom::ResolveNodeParams::Builder()
+                .SetBackendNodeId(pseudo_element->GetBackendNodeId())
+                .Build(),
+            base::BindOnce(&ElementFinder::OnResolveNodeForPseudoElement,
+                           weak_ptr_factory_.GetWeakPtr()));
+        return;
+      }
+    }
+  }
+
+  // Failed to find the pseudo element: run the callback with empty result.
+  SendResult(ClientStatus(ELEMENT_RESOLUTION_FAILED));
+}
+
+void ElementFinder::OnResolveNodeForPseudoElement(
+    std::unique_ptr<dom::ResolveNodeResult> result) {
+  if (result && result->GetObject() && result->GetObject()->HasObjectId()) {
+    element_result_->object_id = result->GetObject()->GetObjectId();
+  }
+  SendResult(OkClientStatus());
+}
+
+void ElementFinder::OnDescribeNode(
+    const std::string& object_id,
+    size_t index,
+    std::unique_ptr<dom::DescribeNodeResult> result) {
+  if (!result || !result->GetNode()) {
+    DVLOG(1) << __func__ << " Failed to describe the node.";
+    SendResult(UnexpectedErrorStatus(__FILE__, __LINE__));
+    return;
+  }
+
+  auto* node = result->GetNode();
+  std::vector<int> backend_ids;
+  if (node->HasContentDocument()) {
+    backend_ids.emplace_back(node->GetContentDocument()->GetBackendNodeId());
+
+    element_result_->container_frame_selector_index = index;
+
+    // Find out the corresponding render frame host through document url and
+    // name.
+    // TODO(crbug.com/806868): Use more attributes to find out the render frame
+    // host if name and document url are not enough to uniquely identify it.
+    std::string frame_name;
+    if (node->HasAttributes()) {
+      const std::vector<std::string>* attributes = node->GetAttributes();
+      for (size_t i = 0; i < attributes->size();) {
+        if ((*attributes)[i] == "name") {
+          frame_name = (*attributes)[i + 1];
+          break;
+        }
+        // Jump two positions since attribute name and value are always paired.
+        i = i + 2;
+      }
+    }
+    element_result_->container_frame_host = FindCorrespondingRenderFrameHost(
+        frame_name, node->GetContentDocument()->GetDocumentURL());
+    if (!element_result_->container_frame_host) {
+      DVLOG(1) << __func__ << " Failed to find corresponding owner frame.";
+      SendResult(UnexpectedErrorStatus(__FILE__, __LINE__));
+      return;
+    }
+  } else if (node->HasFrameId()) {
+    // TODO(crbug.com/806868): Support out-of-process iframe.
+    DVLOG(3) << "Warning (unsupported): the element is inside an OOPIF.";
+    SendResult(ClientStatus(UNSUPPORTED));
+    return;
+  }
+
+  if (node->HasShadowRoots()) {
+    // TODO(crbug.com/806868): Support multiple shadow roots.
+    backend_ids.emplace_back(
+        node->GetShadowRoots()->front()->GetBackendNodeId());
+  }
+
+  if (!backend_ids.empty()) {
+    devtools_client_->GetDOM()->ResolveNode(
+        dom::ResolveNodeParams::Builder()
+            .SetBackendNodeId(backend_ids[0])
+            .Build(),
+        base::BindOnce(&ElementFinder::OnResolveNode,
+                       weak_ptr_factory_.GetWeakPtr(), index));
+    return;
+  }
+
+  RecursiveFindElement(object_id, ++index);
+}
+
+void ElementFinder::OnResolveNode(
+    size_t index,
+    std::unique_ptr<dom::ResolveNodeResult> result) {
+  if (!result || !result->GetObject() || !result->GetObject()->HasObjectId()) {
+    DVLOG(1) << __func__ << " Failed to resolve object id from backend id.";
+    SendResult(UnexpectedErrorStatus(__FILE__, __LINE__));
+    return;
+  }
+
+  RecursiveFindElement(result->GetObject()->GetObjectId(), ++index);
+}
+
+content::RenderFrameHost* ElementFinder::FindCorrespondingRenderFrameHost(
+    std::string name,
+    std::string document_url) {
+  content::RenderFrameHost* ret_frame = nullptr;
+  for (auto* frame : web_contents_->GetAllFrames()) {
+    if (frame->GetFrameName() == name &&
+        frame->GetLastCommittedURL().spec() == document_url) {
+      DCHECK(!ret_frame);
+      ret_frame = frame;
+    }
+  }
+
+  return ret_frame;
+}
+
+}  // namespace autofill_assistant
\ No newline at end of file
diff --git a/components/autofill_assistant/browser/web/element_finder.h b/components/autofill_assistant/browser/web/element_finder.h
new file mode 100644
index 0000000..1db746fb
--- /dev/null
+++ b/components/autofill_assistant/browser/web/element_finder.h
@@ -0,0 +1,95 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_WEB_ELEMENT_FINDER_H_
+#define COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_WEB_ELEMENT_FINDER_H_
+
+#include <memory>
+#include <string>
+
+#include "base/callback.h"
+#include "base/macros.h"
+#include "base/memory/weak_ptr.h"
+#include "components/autofill_assistant/browser/client_status.h"
+#include "components/autofill_assistant/browser/devtools/devtools/domains/types_dom.h"
+#include "components/autofill_assistant/browser/devtools/devtools/domains/types_runtime.h"
+#include "components/autofill_assistant/browser/selector.h"
+#include "components/autofill_assistant/browser/web/web_controller_worker.h"
+
+namespace content {
+class WebContents;
+class RenderFrameHost;
+}  // namespace content
+
+namespace autofill_assistant {
+class DevtoolsClient;
+
+// Worker class to find element(s) matching a selector.
+class ElementFinder : public WebControllerWorker {
+ public:
+  struct Result {
+    Result() = default;
+    ~Result() = default;
+
+    // The render frame host contains the element.
+    content::RenderFrameHost* container_frame_host;
+
+    // The selector index in the given selectors corresponding to the container
+    // frame. Zero indicates the element is in main frame or the first element
+    // is the container frame selector. Compare main frame with the above
+    // |container_frame_host| to distinguish them.
+    size_t container_frame_selector_index;
+
+    // The object id of the element.
+    std::string object_id;
+  };
+
+  // |web_contents| and |devtools_client| must be valid for the lifetime of the
+  // instance.
+  ElementFinder(content::WebContents* web_contents_,
+                DevtoolsClient* devtools_client,
+                const Selector& selector,
+                bool strict);
+  ~ElementFinder() override;
+
+  using Callback =
+      base::OnceCallback<void(const ClientStatus&, std::unique_ptr<Result>)>;
+
+  // Finds the element and calls the callback.
+  void Start(Callback callback_);
+
+ private:
+  void SendResult(const ClientStatus& status);
+  void OnGetDocumentElement(std::unique_ptr<runtime::EvaluateResult> result);
+  void RecursiveFindElement(const std::string& object_id, size_t index);
+  void OnQuerySelectorAll(
+      size_t index,
+      std::unique_ptr<runtime::CallFunctionOnResult> result);
+  void OnDescribeNodeForPseudoElement(
+      dom::PseudoType pseudo_type,
+      std::unique_ptr<dom::DescribeNodeResult> result);
+  void OnResolveNodeForPseudoElement(
+      std::unique_ptr<dom::ResolveNodeResult> result);
+  void OnDescribeNode(const std::string& object_id,
+                      size_t index,
+                      std::unique_ptr<dom::DescribeNodeResult> result);
+  void OnResolveNode(size_t index,
+                     std::unique_ptr<dom::ResolveNodeResult> result);
+  content::RenderFrameHost* FindCorrespondingRenderFrameHost(
+      std::string name,
+      std::string document_url);
+
+  content::WebContents* const web_contents_;
+  DevtoolsClient* const devtools_client_;
+  const Selector selector_;
+  const bool strict_;
+  Callback callback_;
+  std::unique_ptr<Result> element_result_;
+
+  base::WeakPtrFactory<ElementFinder> weak_ptr_factory_{this};
+};
+
+}  // namespace autofill_assistant
+
+#endif  // COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_WEB_ELEMENT_FINDER_H_
diff --git a/components/autofill_assistant/browser/web/element_position_getter.cc b/components/autofill_assistant/browser/web/element_position_getter.cc
new file mode 100644
index 0000000..8bbbd16
--- /dev/null
+++ b/components/autofill_assistant/browser/web/element_position_getter.cc
@@ -0,0 +1,168 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/autofill_assistant/browser/web/element_position_getter.h"
+
+#include "base/task/post_task.h"
+#include "components/autofill_assistant/browser/devtools/devtools_client.h"
+#include "components/autofill_assistant/browser/service.pb.h"
+#include "components/autofill_assistant/browser/web/web_controller_util.h"
+#include "content/public/browser/browser_task_traits.h"
+#include "content/public/browser/browser_thread.h"
+#include "content/public/browser/render_frame_host.h"
+#include "content/public/browser/web_contents.h"
+
+namespace {
+
+const char* const kScrollIntoViewIfNeededScript =
+    R"(function(node) {
+    node.scrollIntoViewIfNeeded();
+  })";
+
+}  // namespace
+
+namespace autofill_assistant {
+
+ElementPositionGetter::ElementPositionGetter(DevtoolsClient* devtools_client,
+                                             const ClientSettings& settings)
+    : check_interval_(settings.box_model_check_interval),
+      max_rounds_(settings.box_model_check_count),
+      devtools_client_(devtools_client),
+      weak_ptr_factory_(this) {}
+
+ElementPositionGetter::~ElementPositionGetter() = default;
+
+void ElementPositionGetter::Start(content::RenderFrameHost* frame_host,
+                                  std::string element_object_id,
+                                  ElementPositionCallback callback) {
+  object_id_ = element_object_id;
+  callback_ = std::move(callback);
+  remaining_rounds_ = max_rounds_;
+  // TODO(crbug/806868): Consider using autofill_assistant::RetryTimer
+
+  // Wait for a roundtrips through the renderer and compositor pipeline,
+  // otherwise touch event may be dropped because of missing handler.
+  // Note that mouse left button will always be send to the renderer, but it
+  // is slightly better to wait for the changes, like scroll, to be visualized
+  // in compositor as real interaction.
+  frame_host->InsertVisualStateCallback(
+      base::BindOnce(&ElementPositionGetter::OnVisualStateUpdatedCallback,
+                     weak_ptr_factory_.GetWeakPtr()));
+  GetAndWaitBoxModelStable();
+}
+
+void ElementPositionGetter::OnVisualStateUpdatedCallback(bool success) {
+  if (success) {
+    visual_state_updated_ = true;
+    return;
+  }
+
+  OnError();
+}
+
+void ElementPositionGetter::GetAndWaitBoxModelStable() {
+  devtools_client_->GetDOM()->GetBoxModel(
+      dom::GetBoxModelParams::Builder().SetObjectId(object_id_).Build(),
+      base::BindOnce(&ElementPositionGetter::OnGetBoxModelForStableCheck,
+                     weak_ptr_factory_.GetWeakPtr()));
+}
+
+void ElementPositionGetter::OnGetBoxModelForStableCheck(
+    std::unique_ptr<dom::GetBoxModelResult> result) {
+  if (!result || !result->GetModel() || !result->GetModel()->GetContent()) {
+    DVLOG(1) << __func__ << " Failed to get box model.";
+    OnError();
+    return;
+  }
+
+  // Return the center of the element.
+  const std::vector<double>* content_box = result->GetModel()->GetContent();
+  DCHECK_EQ(content_box->size(), 8u);
+  int new_point_x =
+      round((round((*content_box)[0]) + round((*content_box)[2])) * 0.5);
+  int new_point_y =
+      round((round((*content_box)[3]) + round((*content_box)[5])) * 0.5);
+
+  // Wait for at least three rounds (~600ms = 3*check_interval_) for visual
+  // state update callback since it might take longer time to return or never
+  // return if no updates.
+  DCHECK(max_rounds_ > 2 && max_rounds_ >= remaining_rounds_);
+  if (has_point_ && new_point_x == point_x_ && new_point_y == point_y_ &&
+      (visual_state_updated_ || remaining_rounds_ + 2 < max_rounds_)) {
+    // Note that there is still a chance that the element's position has been
+    // changed after the last call of GetBoxModel, however, it might be safe to
+    // assume the element's position will not be changed before issuing click or
+    // tap event after stable for check_interval_. In addition, checking again
+    // after issuing click or tap event doesn't help since the change may be
+    // expected.
+    OnResult(new_point_x, new_point_y);
+    return;
+  }
+
+  if (remaining_rounds_ <= 0) {
+    OnError();
+    return;
+  }
+
+  bool is_first_round = !has_point_;
+  has_point_ = true;
+  point_x_ = new_point_x;
+  point_y_ = new_point_y;
+
+  // Scroll the element into view again if it was moved out of view, starting
+  // from the second round.
+  if (!is_first_round) {
+    std::vector<std::unique_ptr<runtime::CallArgument>> argument;
+    argument.emplace_back(
+        runtime::CallArgument::Builder().SetObjectId(object_id_).Build());
+    devtools_client_->GetRuntime()->CallFunctionOn(
+        runtime::CallFunctionOnParams::Builder()
+            .SetObjectId(object_id_)
+            .SetArguments(std::move(argument))
+            .SetFunctionDeclaration(std::string(kScrollIntoViewIfNeededScript))
+            .SetReturnByValue(true)
+            .Build(),
+        base::BindOnce(&ElementPositionGetter::OnScrollIntoView,
+                       weak_ptr_factory_.GetWeakPtr()));
+    return;
+  }
+
+  --remaining_rounds_;
+  base::PostDelayedTaskWithTraits(
+      FROM_HERE, {content::BrowserThread::UI},
+      base::BindOnce(&ElementPositionGetter::GetAndWaitBoxModelStable,
+                     weak_ptr_factory_.GetWeakPtr()),
+      check_interval_);
+}
+
+void ElementPositionGetter::OnScrollIntoView(
+    std::unique_ptr<runtime::CallFunctionOnResult> result) {
+  ClientStatus status = CheckJavaScriptResult(result.get(), __FILE__, __LINE__);
+  if (!status.ok()) {
+    DVLOG(1) << __func__ << " Failed to scroll the element: " << status;
+    OnError();
+    return;
+  }
+
+  --remaining_rounds_;
+  base::PostDelayedTaskWithTraits(
+      FROM_HERE, {content::BrowserThread::UI},
+      base::BindOnce(&ElementPositionGetter::GetAndWaitBoxModelStable,
+                     weak_ptr_factory_.GetWeakPtr()),
+      check_interval_);
+}
+
+void ElementPositionGetter::OnResult(int x, int y) {
+  if (callback_) {
+    std::move(callback_).Run(/* success= */ true, x, y);
+  }
+}
+
+void ElementPositionGetter::OnError() {
+  if (callback_) {
+    std::move(callback_).Run(/* success= */ false, /* x= */ 0, /* y= */ 0);
+  }
+}
+
+}  // namespace autofill_assistant
\ No newline at end of file
diff --git a/components/autofill_assistant/browser/web/element_position_getter.h b/components/autofill_assistant/browser/web/element_position_getter.h
new file mode 100644
index 0000000..7a30f6f
--- /dev/null
+++ b/components/autofill_assistant/browser/web/element_position_getter.h
@@ -0,0 +1,81 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_WEB_ELEMENT_POSITION_GETTER_H_
+#define COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_WEB_ELEMENT_POSITION_GETTER_H_
+
+#include <memory>
+#include <string>
+
+#include "base/callback.h"
+#include "base/macros.h"
+#include "base/memory/weak_ptr.h"
+#include "components/autofill_assistant/browser/client_settings.h"
+#include "components/autofill_assistant/browser/devtools/devtools/domains/types_dom.h"
+#include "components/autofill_assistant/browser/devtools/devtools/domains/types_runtime.h"
+#include "components/autofill_assistant/browser/selector.h"
+#include "components/autofill_assistant/browser/web/web_controller_worker.h"
+
+namespace content {
+class RenderFrameHost;
+}  // namespace content
+
+namespace autofill_assistant {
+class DevtoolsClient;
+
+// Worker class to get an element's position in viewport coordinates when it is
+// stable and the frame it belongs to has finished its visual update.
+class ElementPositionGetter : public WebControllerWorker {
+ public:
+  // |devtools_client| must be valid for the lifetime of the instance.
+  ElementPositionGetter(DevtoolsClient* devtools_client,
+                        const ClientSettings& settings);
+  ~ElementPositionGetter() override;
+
+  // Callback that receives the position that corresponds to the center
+  // of an element.
+  //
+  // If the first element is false, the call failed. Otherwise, the second
+  // element contains the x position and the third the y position of the center
+  // of the element in viewport coordinates.
+  using ElementPositionCallback = base::OnceCallback<void(bool, int, int)>;
+
+  void Start(content::RenderFrameHost* frame_host,
+             std::string element_object_id,
+             ElementPositionCallback callback);
+
+ private:
+  void OnVisualStateUpdatedCallback(bool success);
+  void GetAndWaitBoxModelStable();
+  void OnGetBoxModelForStableCheck(
+      std::unique_ptr<dom::GetBoxModelResult> result);
+  void OnScrollIntoView(std::unique_ptr<runtime::CallFunctionOnResult> result);
+  void OnResult(int x, int y);
+  void OnError();
+
+  // Time to wait between two box model checks.
+  const base::TimeDelta check_interval_;
+  // Maximum number of checks to run.
+  const int max_rounds_;
+
+  DevtoolsClient* devtools_client_ = nullptr;
+  std::string object_id_;
+  int remaining_rounds_ = 0;
+  ElementPositionCallback callback_;
+  bool visual_state_updated_ = false;
+
+  // If |has_point_| is true, |point_x_| and |point_y_| contain the last
+  // computed center of the element, in viewport coordinates. Note that
+  // negative coordinates are valid, in case the element is above or to the
+  // left of the viewport.
+  bool has_point_ = false;
+  int point_x_ = 0;
+  int point_y_ = 0;
+
+  base::WeakPtrFactory<ElementPositionGetter> weak_ptr_factory_;
+};
+
+}  // namespace autofill_assistant
+
+#endif  // COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_WEB_ELEMENT_POSITION_GETTER_H_
\ No newline at end of file
diff --git a/components/autofill_assistant/browser/mock_web_controller.cc b/components/autofill_assistant/browser/web/mock_web_controller.cc
similarity index 82%
rename from components/autofill_assistant/browser/mock_web_controller.cc
rename to components/autofill_assistant/browser/web/mock_web_controller.cc
index 21dcf826..b3046aa 100644
--- a/components/autofill_assistant/browser/mock_web_controller.cc
+++ b/components/autofill_assistant/browser/web/mock_web_controller.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 "components/autofill_assistant/browser/mock_web_controller.h"
+#include "components/autofill_assistant/browser/web/mock_web_controller.h"
 
 namespace autofill_assistant {
 
diff --git a/components/autofill_assistant/browser/mock_web_controller.h b/components/autofill_assistant/browser/web/mock_web_controller.h
similarity index 92%
rename from components/autofill_assistant/browser/mock_web_controller.h
rename to components/autofill_assistant/browser/web/mock_web_controller.h
index bd2b589e..03e0fb7 100644
--- a/components/autofill_assistant/browser/mock_web_controller.h
+++ b/components/autofill_assistant/browser/web/mock_web_controller.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 COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_MOCK_WEB_CONTROLLER_H_
-#define COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_MOCK_WEB_CONTROLLER_H_
+#ifndef COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_WEB_MOCK_WEB_CONTROLLER_H_
+#define COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_WEB_MOCK_WEB_CONTROLLER_H_
 
 #include <string>
 #include <vector>
@@ -11,7 +11,7 @@
 #include "base/callback.h"
 #include "components/autofill_assistant/browser/actions/click_action.h"
 #include "components/autofill_assistant/browser/top_padding.h"
-#include "components/autofill_assistant/browser/web_controller.h"
+#include "components/autofill_assistant/browser/web/web_controller.h"
 #include "testing/gmock/include/gmock/gmock.h"
 
 namespace autofill_assistant {
@@ -119,4 +119,4 @@
 
 }  // namespace autofill_assistant
 
-#endif  // COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_MOCK_WEB_CONTROLLER_H_
+#endif  // COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_WEB_MOCK_WEB_CONTROLLER_H_
diff --git a/components/autofill_assistant/browser/web_controller.cc b/components/autofill_assistant/browser/web/web_controller.cc
similarity index 63%
rename from components/autofill_assistant/browser/web_controller.cc
rename to components/autofill_assistant/browser/web/web_controller.cc
index afcf07c..650e84e 100644
--- a/components/autofill_assistant/browser/web_controller.cc
+++ b/components/autofill_assistant/browser/web/web_controller.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 "components/autofill_assistant/browser/web_controller.h"
+#include "components/autofill_assistant/browser/web/web_controller.h"
 
 #include <math.h>
 #include <algorithm>
@@ -13,6 +13,7 @@
 #include "base/bind_helpers.h"
 #include "base/callback.h"
 #include "base/logging.h"
+#include "base/stl_util.h"
 #include "base/strings/strcat.h"
 #include "base/strings/string_util.h"
 #include "base/strings/stringprintf.h"
@@ -27,6 +28,7 @@
 #include "components/autofill_assistant/browser/client_status.h"
 #include "components/autofill_assistant/browser/rectf.h"
 #include "components/autofill_assistant/browser/string_conversions_util.h"
+#include "components/autofill_assistant/browser/web/web_controller_util.h"
 #include "content/public/browser/browser_task_traits.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/render_frame_host.h"
@@ -75,11 +77,6 @@
     node.scrollIntoView({block: "center", inline: "center"});
   })";
 
-const char* const kScrollIntoViewIfNeededScript =
-    R"(function(node) {
-    node.scrollIntoViewIfNeeded();
-  })";
-
 // Javascript to select a value from a select box. Also fires a "change" event
 // to trigger any listeners. Changing the index directly does not trigger this.
 const char* const kSelectOptionScript =
@@ -141,54 +138,6 @@
 const char* const kGetOuterHtmlScript =
     "function () { return this.outerHTML; }";
 
-// Javascript code to get document root element.
-const char* const kGetDocumentElement =
-    R"(
-    (function() {
-      return document.documentElement;
-    }())
-    )";
-
-// Javascript code to query an elements for a selector, either the first
-// (non-strict) or a single (strict) element.
-//
-// Returns undefined if no elements are found, TOO_MANY_ELEMENTS (18) if too
-// many elements were found and strict mode is enabled.
-const char* const kQuerySelector =
-    R"(function (selector, strictMode) {
-      var found = this.querySelectorAll(selector);
-      if(found.length == 0) return undefined;
-      if(found.length > 1 && strictMode) return 18;
-      return found[0];
-    })";
-
-// Javascript code to query a visible elements for a selector, either the first
-// (non-strict) or a single (strict) visible element.q
-//
-// Returns undefined if no elements are found, TOO_MANY_ELEMENTS (18) if too
-// many elements were found and strict mode is enabled.
-const char* const kQuerySelectorWithConditions =
-    R"(function (selector, strict, visible, inner_text_str, value_str) {
-        var found = this.querySelectorAll(selector);
-        var found_index = -1;
-        var inner_text_re = inner_text_str ? RegExp(inner_text_str) : undefined;
-        var value_re = value_str ? RegExp(value_str) : undefined;
-        var match = function(e) {
-          if (visible && e.getClientRects().length == 0) return false;
-          if (inner_text_re && !inner_text_re.test(e.innerText)) return false;
-          if (value_re && !value_re.test(e.value)) return false;
-          return true;
-        };
-        for (let i = 0; i < found.length; i++) {
-          if (match(found[i])) {
-            if (found_index != -1) return 18;
-            found_index = i;
-            if (!strict) break;
-          }
-        }
-        return found_index == -1 ? undefined : found[found_index];
-    })";
-
 // Javascript code to query whether the document is ready for interact.
 const char* const kIsDocumentReadyForInteract =
     R"(function () {
@@ -222,143 +171,6 @@
 })
 )";
 
-bool ConvertPseudoType(const PseudoType pseudo_type,
-                       dom::PseudoType* pseudo_type_output) {
-  switch (pseudo_type) {
-    case PseudoType::UNDEFINED:
-      break;
-    case PseudoType::FIRST_LINE:
-      *pseudo_type_output = dom::PseudoType::FIRST_LINE;
-      return true;
-    case PseudoType::FIRST_LETTER:
-      *pseudo_type_output = dom::PseudoType::FIRST_LETTER;
-      return true;
-    case PseudoType::BEFORE:
-      *pseudo_type_output = dom::PseudoType::BEFORE;
-      return true;
-    case PseudoType::AFTER:
-      *pseudo_type_output = dom::PseudoType::AFTER;
-      return true;
-    case PseudoType::BACKDROP:
-      *pseudo_type_output = dom::PseudoType::BACKDROP;
-      return true;
-    case PseudoType::SELECTION:
-      *pseudo_type_output = dom::PseudoType::SELECTION;
-      return true;
-    case PseudoType::FIRST_LINE_INHERITED:
-      *pseudo_type_output = dom::PseudoType::FIRST_LINE_INHERITED;
-      return true;
-    case PseudoType::SCROLLBAR:
-      *pseudo_type_output = dom::PseudoType::SCROLLBAR;
-      return true;
-    case PseudoType::SCROLLBAR_THUMB:
-      *pseudo_type_output = dom::PseudoType::SCROLLBAR_THUMB;
-      return true;
-    case PseudoType::SCROLLBAR_BUTTON:
-      *pseudo_type_output = dom::PseudoType::SCROLLBAR_BUTTON;
-      return true;
-    case PseudoType::SCROLLBAR_TRACK:
-      *pseudo_type_output = dom::PseudoType::SCROLLBAR_TRACK;
-      return true;
-    case PseudoType::SCROLLBAR_TRACK_PIECE:
-      *pseudo_type_output = dom::PseudoType::SCROLLBAR_TRACK_PIECE;
-      return true;
-    case PseudoType::SCROLLBAR_CORNER:
-      *pseudo_type_output = dom::PseudoType::SCROLLBAR_CORNER;
-      return true;
-    case PseudoType::RESIZER:
-      *pseudo_type_output = dom::PseudoType::RESIZER;
-      return true;
-    case PseudoType::INPUT_LIST_BUTTON:
-      *pseudo_type_output = dom::PseudoType::INPUT_LIST_BUTTON;
-      return true;
-  }
-  return false;
-}
-
-// Builds a ClientStatus appropriate for an unexpected error.
-//
-// This should only be used in situations where getting an error cannot be
-// anything but a bug in the client.
-ClientStatus UnexpectedErrorStatus(const std::string& file, int line) {
-  ClientStatus status(OTHER_ACTION_STATUS);
-  auto* info = status.mutable_details()->mutable_unexpected_error_info();
-  info->set_source_file(file);
-  info->set_source_line_number(line);
-  return status;
-}
-
-// Builds a ClientStatus appropriate for a JavaScript error.
-ClientStatus JavaScriptErrorStatus(const std::string& file,
-                                   int line,
-                                   const runtime::ExceptionDetails* exception) {
-  ClientStatus status(UNEXPECTED_JS_ERROR);
-  auto* info = status.mutable_details()->mutable_unexpected_error_info();
-  info->set_source_file(file);
-  info->set_source_line_number(line);
-  if (exception) {
-    if (exception->HasException() &&
-        exception->GetException()->HasClassName()) {
-      info->set_js_exception_classname(
-          exception->GetException()->GetClassName());
-    }
-    info->set_js_exception_line_number(exception->GetLineNumber());
-    info->set_js_exception_column_number(exception->GetColumnNumber());
-  }
-  return status;
-}
-
-// Makes sure that the given EvaluateResult exists, is successful and contain a
-// result.
-template <typename T>
-ClientStatus CheckJavaScriptResult(T* result, const char* file, int line) {
-  if (!result)
-    return JavaScriptErrorStatus(file, line, nullptr);
-  if (result->HasExceptionDetails())
-    return JavaScriptErrorStatus(file, line, result->GetExceptionDetails());
-  if (!result->GetResult())
-    return JavaScriptErrorStatus(file, line, nullptr);
-  return OkClientStatus();
-}
-
-// Safely gets an object id from a RemoteObject
-bool SafeGetObjectId(const runtime::RemoteObject* result, std::string* out) {
-  if (result && result->HasObjectId()) {
-    *out = result->GetObjectId();
-    return true;
-  }
-  return false;
-}
-
-// Safely gets a string value from a RemoteObject
-bool SafeGetStringValue(const runtime::RemoteObject* result, std::string* out) {
-  if (result && result->HasValue() && result->GetValue()->is_string()) {
-    *out = result->GetValue()->GetString();
-    return true;
-  }
-  return false;
-}
-
-// Safely gets a int value from a RemoteObject.
-bool SafeGetIntValue(const runtime::RemoteObject* result, int* out) {
-  if (result && result->HasValue() && result->GetValue()->is_int()) {
-    *out = result->GetValue()->GetInt();
-    return true;
-  }
-  *out = 0;
-  return false;
-}
-
-// Safely gets a boolean value from a RemoteObject
-bool SafeGetBool(const runtime::RemoteObject* result, bool* out) {
-  if (result && result->HasValue() && result->GetValue()->is_bool()) {
-    *out = result->GetValue()->GetBool();
-    return true;
-  }
-  *out = false;
-  return false;
-}
-
 // Converts a int that correspond to the DocumentReadyState enum into an
 // equivalent quoted Javascript string.
 std::string DocumentReadyStateToQuotedJsString(int state) {
@@ -427,548 +239,6 @@
 }
 }  // namespace
 
-class WebController::Worker {
- public:
-  Worker();
-  virtual ~Worker();
-
- private:
-  DISALLOW_COPY_AND_ASSIGN(Worker);
-};
-WebController::Worker::Worker() = default;
-WebController::Worker::~Worker() = default;
-
-class WebController::ElementPositionGetter : public WebController::Worker {
- public:
-  ElementPositionGetter(const ClientSettings& settings);
-  ~ElementPositionGetter() override;
-
-  // |devtools_client| must be valid for the lifetime of the instance, which is
-  // guaranteed since workers are owned by WebController.
-  void Start(content::RenderFrameHost* frame_host,
-             DevtoolsClient* devtools_client,
-             std::string element_object_id,
-             ElementPositionCallback callback);
-
- private:
-  void OnVisualStateUpdatedCallback(bool success);
-  void GetAndWaitBoxModelStable();
-  void OnGetBoxModelForStableCheck(
-      std::unique_ptr<dom::GetBoxModelResult> result);
-  void OnScrollIntoView(std::unique_ptr<runtime::CallFunctionOnResult> result);
-  void OnResult(int x, int y);
-  void OnError();
-
-  // Time to wait between two box model checks.
-  const base::TimeDelta check_interval_;
-  // Maximum number of checks to run.
-  const int max_rounds_;
-
-  DevtoolsClient* devtools_client_ = nullptr;
-  std::string object_id_;
-  int remaining_rounds_ = 0;
-  ElementPositionCallback callback_;
-  bool visual_state_updated_ = false;
-
-  // If |has_point_| is true, |point_x_| and |point_y_| contain the last
-  // computed center of the element, in viewport coordinates. Note that
-  // negative coordinates are valid, in case the element is above or to the
-  // left of the viewport.
-  bool has_point_ = false;
-  int point_x_ = 0;
-  int point_y_ = 0;
-
-  base::WeakPtrFactory<ElementPositionGetter> weak_ptr_factory_{this};
-};
-
-WebController::ElementPositionGetter::ElementPositionGetter(
-    const ClientSettings& settings)
-    : check_interval_(settings.box_model_check_interval),
-      max_rounds_(settings.box_model_check_count) {}
-
-WebController::ElementPositionGetter::~ElementPositionGetter() = default;
-
-void WebController::ElementPositionGetter::Start(
-    content::RenderFrameHost* frame_host,
-    DevtoolsClient* devtools_client,
-    std::string element_object_id,
-    ElementPositionCallback callback) {
-  devtools_client_ = devtools_client;
-  object_id_ = element_object_id;
-  callback_ = std::move(callback);
-  remaining_rounds_ = max_rounds_;
-  // TODO(crbug/806868): Consider using autofill_assistant::RetryTimer
-
-  // Wait for a roundtrips through the renderer and compositor pipeline,
-  // otherwise touch event may be dropped because of missing handler.
-  // Note that mouse left button will always be send to the renderer, but it
-  // is slightly better to wait for the changes, like scroll, to be visualized
-  // in compositor as real interaction.
-  frame_host->InsertVisualStateCallback(base::BindOnce(
-      &WebController::ElementPositionGetter::OnVisualStateUpdatedCallback,
-      weak_ptr_factory_.GetWeakPtr()));
-  GetAndWaitBoxModelStable();
-}
-
-void WebController::ElementPositionGetter::OnVisualStateUpdatedCallback(
-    bool success) {
-  if (success) {
-    visual_state_updated_ = true;
-    return;
-  }
-
-  OnError();
-}
-
-void WebController::ElementPositionGetter::GetAndWaitBoxModelStable() {
-  devtools_client_->GetDOM()->GetBoxModel(
-      dom::GetBoxModelParams::Builder().SetObjectId(object_id_).Build(),
-      base::BindOnce(
-          &WebController::ElementPositionGetter::OnGetBoxModelForStableCheck,
-          weak_ptr_factory_.GetWeakPtr()));
-}
-
-void WebController::ElementPositionGetter::OnGetBoxModelForStableCheck(
-    std::unique_ptr<dom::GetBoxModelResult> result) {
-  if (!result || !result->GetModel() || !result->GetModel()->GetContent()) {
-    DVLOG(1) << __func__ << " Failed to get box model.";
-    OnError();
-    return;
-  }
-
-  // Return the center of the element.
-  const std::vector<double>* content_box = result->GetModel()->GetContent();
-  DCHECK_EQ(content_box->size(), 8u);
-  int new_point_x =
-      round((round((*content_box)[0]) + round((*content_box)[2])) * 0.5);
-  int new_point_y =
-      round((round((*content_box)[3]) + round((*content_box)[5])) * 0.5);
-
-  // Wait for at least three rounds (~600ms = 3*check_interval_) for visual
-  // state update callback since it might take longer time to return or never
-  // return if no updates.
-  DCHECK(max_rounds_ > 2 && max_rounds_ >= remaining_rounds_);
-  if (has_point_ && new_point_x == point_x_ && new_point_y == point_y_ &&
-      (visual_state_updated_ || remaining_rounds_ + 2 < max_rounds_)) {
-    // Note that there is still a chance that the element's position has been
-    // changed after the last call of GetBoxModel, however, it might be safe to
-    // assume the element's position will not be changed before issuing click or
-    // tap event after stable for check_interval_. In addition, checking again
-    // after issuing click or tap event doesn't help since the change may be
-    // expected.
-    OnResult(new_point_x, new_point_y);
-    return;
-  }
-
-  if (remaining_rounds_ <= 0) {
-    OnError();
-    return;
-  }
-
-  bool is_first_round = !has_point_;
-  has_point_ = true;
-  point_x_ = new_point_x;
-  point_y_ = new_point_y;
-
-  // Scroll the element into view again if it was moved out of view, starting
-  // from the second round.
-  if (!is_first_round) {
-    std::vector<std::unique_ptr<runtime::CallArgument>> argument;
-    argument.emplace_back(
-        runtime::CallArgument::Builder().SetObjectId(object_id_).Build());
-    devtools_client_->GetRuntime()->CallFunctionOn(
-        runtime::CallFunctionOnParams::Builder()
-            .SetObjectId(object_id_)
-            .SetArguments(std::move(argument))
-            .SetFunctionDeclaration(std::string(kScrollIntoViewIfNeededScript))
-            .SetReturnByValue(true)
-            .Build(),
-        base::BindOnce(&WebController::ElementPositionGetter::OnScrollIntoView,
-                       weak_ptr_factory_.GetWeakPtr()));
-    return;
-  }
-
-  --remaining_rounds_;
-  base::PostDelayedTask(
-      FROM_HERE, {content::BrowserThread::UI},
-      base::BindOnce(
-          &WebController::ElementPositionGetter::GetAndWaitBoxModelStable,
-          weak_ptr_factory_.GetWeakPtr()),
-      check_interval_);
-}
-
-void WebController::ElementPositionGetter::OnScrollIntoView(
-    std::unique_ptr<runtime::CallFunctionOnResult> result) {
-  ClientStatus status = CheckJavaScriptResult(result.get(), __FILE__, __LINE__);
-  if (!status.ok()) {
-    DVLOG(1) << __func__ << " Failed to scroll the element: " << status;
-    OnError();
-    return;
-  }
-
-  --remaining_rounds_;
-  base::PostDelayedTask(
-      FROM_HERE, {content::BrowserThread::UI},
-      base::BindOnce(
-          &WebController::ElementPositionGetter::GetAndWaitBoxModelStable,
-          weak_ptr_factory_.GetWeakPtr()),
-      check_interval_);
-}
-
-void WebController::ElementPositionGetter::OnResult(int x, int y) {
-  if (callback_) {
-    std::move(callback_).Run(/* success= */ true, x, y);
-  }
-}
-
-void WebController::ElementPositionGetter::OnError() {
-  if (callback_) {
-    std::move(callback_).Run(/* success= */ false, /* x= */ 0, /* y= */ 0);
-  }
-}
-
-class WebController::ElementFinder : public WebController::Worker {
- public:
-  // |devtools_client| and |web_contents| must be valid for the lifetime of the
-  // instance, which is guaranteed since workers are owned by WebController.
-  ElementFinder(content::WebContents* web_contents_,
-                DevtoolsClient* devtools_client,
-                const Selector& selector,
-                bool strict);
-  ~ElementFinder() override;
-
-  // Finds the element and call the callback.
-  void Start(FindElementCallback callback_);
-
- private:
-  void SendResult(const ClientStatus& status);
-  void OnGetDocumentElement(std::unique_ptr<runtime::EvaluateResult> result);
-  void RecursiveFindElement(const std::string& object_id, size_t index);
-  void OnQuerySelectorAll(
-      size_t index,
-      std::unique_ptr<runtime::CallFunctionOnResult> result);
-  void OnDescribeNodeForPseudoElement(
-      dom::PseudoType pseudo_type,
-      std::unique_ptr<dom::DescribeNodeResult> result);
-  void OnResolveNodeForPseudoElement(
-      std::unique_ptr<dom::ResolveNodeResult> result);
-  void OnDescribeNode(const std::string& object_id,
-                      size_t index,
-                      std::unique_ptr<dom::DescribeNodeResult> result);
-  void OnResolveNode(size_t index,
-                     std::unique_ptr<dom::ResolveNodeResult> result);
-  content::RenderFrameHost* FindCorrespondingRenderFrameHost(
-      std::string name,
-      std::string document_url);
-
-  content::WebContents* const web_contents_;
-  DevtoolsClient* const devtools_client_;
-  const Selector selector_;
-  const bool strict_;
-  FindElementCallback callback_;
-  std::unique_ptr<FindElementResult> element_result_;
-
-  base::WeakPtrFactory<ElementFinder> weak_ptr_factory_{this};
-};
-
-WebController::ElementFinder::ElementFinder(content::WebContents* web_contents,
-                                            DevtoolsClient* devtools_client,
-                                            const Selector& selector,
-                                            bool strict)
-    : web_contents_(web_contents),
-      devtools_client_(devtools_client),
-      selector_(selector),
-      strict_(strict),
-      element_result_(std::make_unique<FindElementResult>()) {}
-
-WebController::ElementFinder::~ElementFinder() = default;
-
-void WebController::ElementFinder::Start(FindElementCallback callback) {
-  callback_ = std::move(callback);
-
-  if (selector_.empty()) {
-    SendResult(ClientStatus(INVALID_SELECTOR));
-    return;
-  }
-  devtools_client_->GetRuntime()->Evaluate(
-      std::string(kGetDocumentElement),
-      base::BindOnce(&WebController::ElementFinder::OnGetDocumentElement,
-                     weak_ptr_factory_.GetWeakPtr()));
-}
-
-void WebController::ElementFinder::SendResult(const ClientStatus& status) {
-  DCHECK(callback_);
-  DCHECK(element_result_);
-  std::move(callback_).Run(status, std::move(element_result_));
-}
-
-void WebController::ElementFinder::OnGetDocumentElement(
-    std::unique_ptr<runtime::EvaluateResult> result) {
-  ClientStatus status = CheckJavaScriptResult(result.get(), __FILE__, __LINE__);
-  if (!status.ok()) {
-    DVLOG(1) << __func__ << " Failed to get document root element.";
-    SendResult(status);
-    return;
-  }
-  std::string object_id;
-  if (!SafeGetObjectId(result->GetResult(), &object_id)) {
-    DVLOG(1) << __func__ << " Failed to get document root element.";
-    SendResult(ClientStatus(ELEMENT_RESOLUTION_FAILED));
-    return;
-  }
-  element_result_->container_frame_host = web_contents_->GetMainFrame();
-  element_result_->container_frame_selector_index = 0;
-  element_result_->object_id = "";
-  RecursiveFindElement(object_id, 0);
-}
-
-void WebController::ElementFinder::RecursiveFindElement(
-    const std::string& object_id,
-    size_t index) {
-  std::vector<std::unique_ptr<runtime::CallArgument>> argument;
-  argument.emplace_back(runtime::CallArgument::Builder()
-                            .SetValue(base::Value::ToUniquePtrValue(
-                                base::Value(selector_.selectors[index])))
-                            .Build());
-  // For finding intermediate elements, strict mode would be more appropriate,
-  // as long as the logic does not support more than one intermediate match.
-  //
-  // TODO(b/129387787): first, add logging to figure out whether it matters and
-  // decide between strict mode and full support for multiple matching
-  // intermeditate elements.
-  argument.emplace_back(
-      runtime::CallArgument::Builder()
-          .SetValue(base::Value::ToUniquePtrValue(base::Value(strict_)))
-          .Build());
-  std::string function;
-  if (index == (selector_.selectors.size() - 1)) {
-    if (selector_.must_be_visible || !selector_.inner_text_pattern.empty() ||
-        !selector_.value_pattern.empty()) {
-      function.assign(kQuerySelectorWithConditions);
-      argument.emplace_back(runtime::CallArgument::Builder()
-                                .SetValue(base::Value::ToUniquePtrValue(
-                                    base::Value(selector_.must_be_visible)))
-                                .Build());
-      argument.emplace_back(runtime::CallArgument::Builder()
-                                .SetValue(base::Value::ToUniquePtrValue(
-                                    base::Value(selector_.inner_text_pattern)))
-                                .Build());
-      argument.emplace_back(runtime::CallArgument::Builder()
-                                .SetValue(base::Value::ToUniquePtrValue(
-                                    base::Value(selector_.value_pattern)))
-                                .Build());
-    }
-  }
-  if (function.empty()) {
-    function.assign(kQuerySelector);
-  }
-  devtools_client_->GetRuntime()->CallFunctionOn(
-      runtime::CallFunctionOnParams::Builder()
-          .SetObjectId(object_id)
-          .SetArguments(std::move(argument))
-          .SetFunctionDeclaration(function)
-          .Build(),
-      base::BindOnce(&WebController::ElementFinder::OnQuerySelectorAll,
-                     weak_ptr_factory_.GetWeakPtr(), index));
-}
-
-void WebController::ElementFinder::OnQuerySelectorAll(
-    size_t index,
-    std::unique_ptr<runtime::CallFunctionOnResult> result) {
-  if (!result) {
-    // It is possible for a document element to already exist, but not be
-    // available yet to query because the document hasn't been loaded. This
-    // results in OnQuerySelectorAll getting a nullptr result. For this specific
-    // call, it is expected.
-    DVLOG(1) << __func__ << ": Context doesn't exist yet to query selector "
-             << index << " of " << selector_;
-    SendResult(ClientStatus(ELEMENT_RESOLUTION_FAILED));
-    return;
-  }
-  ClientStatus status = CheckJavaScriptResult(result.get(), __FILE__, __LINE__);
-  if (!status.ok()) {
-    DVLOG(1) << __func__ << ": Failed to query selector " << index << " of "
-             << selector_;
-    SendResult(status);
-    return;
-  }
-  int int_result;
-  if (SafeGetIntValue(result->GetResult(), &int_result)) {
-    DCHECK(int_result == TOO_MANY_ELEMENTS);
-    SendResult(ClientStatus(TOO_MANY_ELEMENTS));
-    return;
-  }
-  std::string object_id;
-  if (!SafeGetObjectId(result->GetResult(), &object_id)) {
-    SendResult(ClientStatus(ELEMENT_RESOLUTION_FAILED));
-    return;
-  }
-
-  if (selector_.selectors.size() == index + 1) {
-    // The pseudo type is associated to the final element matched by
-    // |selector_|, which means that we currently don't handle matching an
-    // element inside a pseudo element.
-    if (selector_.pseudo_type == PseudoType::UNDEFINED) {
-      // Return object id of the element.
-      element_result_->object_id = object_id;
-      SendResult(OkClientStatus());
-      return;
-    }
-
-    // We are looking for a pseudo element associated with this element.
-    dom::PseudoType pseudo_type;
-    if (!ConvertPseudoType(selector_.pseudo_type, &pseudo_type)) {
-      // Return empty result.
-      SendResult(ClientStatus(INVALID_ACTION));
-      return;
-    }
-
-    devtools_client_->GetDOM()->DescribeNode(
-        dom::DescribeNodeParams::Builder().SetObjectId(object_id).Build(),
-        base::BindOnce(
-            &WebController::ElementFinder::OnDescribeNodeForPseudoElement,
-            weak_ptr_factory_.GetWeakPtr(), pseudo_type));
-    return;
-  }
-
-  devtools_client_->GetDOM()->DescribeNode(
-      dom::DescribeNodeParams::Builder().SetObjectId(object_id).Build(),
-      base::BindOnce(&WebController::ElementFinder::OnDescribeNode,
-                     weak_ptr_factory_.GetWeakPtr(), object_id, index));
-}
-
-void WebController::ElementFinder::OnDescribeNodeForPseudoElement(
-    dom::PseudoType pseudo_type,
-    std::unique_ptr<dom::DescribeNodeResult> result) {
-  if (!result || !result->GetNode()) {
-    DVLOG(1) << __func__ << " Failed to describe the node for pseudo element.";
-    SendResult(UnexpectedErrorStatus(__FILE__, __LINE__));
-    return;
-  }
-
-  auto* node = result->GetNode();
-  if (node->HasPseudoElements()) {
-    for (const auto& pseudo_element : *(node->GetPseudoElements())) {
-      if (pseudo_element->HasPseudoType() &&
-          pseudo_element->GetPseudoType() == pseudo_type) {
-        devtools_client_->GetDOM()->ResolveNode(
-            dom::ResolveNodeParams::Builder()
-                .SetBackendNodeId(pseudo_element->GetBackendNodeId())
-                .Build(),
-            base::BindOnce(
-                &WebController::ElementFinder::OnResolveNodeForPseudoElement,
-                weak_ptr_factory_.GetWeakPtr()));
-        return;
-      }
-    }
-  }
-
-  // Failed to find the pseudo element: run the callback with empty result.
-  SendResult(ClientStatus(ELEMENT_RESOLUTION_FAILED));
-}
-
-void WebController::ElementFinder::OnResolveNodeForPseudoElement(
-    std::unique_ptr<dom::ResolveNodeResult> result) {
-  if (result && result->GetObject() && result->GetObject()->HasObjectId()) {
-    element_result_->object_id = result->GetObject()->GetObjectId();
-  }
-  SendResult(OkClientStatus());
-}
-
-void WebController::ElementFinder::OnDescribeNode(
-    const std::string& object_id,
-    size_t index,
-    std::unique_ptr<dom::DescribeNodeResult> result) {
-  if (!result || !result->GetNode()) {
-    DVLOG(1) << __func__ << " Failed to describe the node.";
-    SendResult(UnexpectedErrorStatus(__FILE__, __LINE__));
-    return;
-  }
-
-  auto* node = result->GetNode();
-  std::vector<int> backend_ids;
-  if (node->HasContentDocument()) {
-    backend_ids.emplace_back(node->GetContentDocument()->GetBackendNodeId());
-
-    element_result_->container_frame_selector_index = index;
-
-    // Find out the corresponding render frame host through document url and
-    // name.
-    // TODO(crbug.com/806868): Use more attributes to find out the render frame
-    // host if name and document url are not enough to uniquely identify it.
-    std::string frame_name;
-    if (node->HasAttributes()) {
-      const std::vector<std::string>* attributes = node->GetAttributes();
-      for (size_t i = 0; i < attributes->size();) {
-        if ((*attributes)[i] == "name") {
-          frame_name = (*attributes)[i + 1];
-          break;
-        }
-        // Jump two positions since attribute name and value are always paired.
-        i = i + 2;
-      }
-    }
-    element_result_->container_frame_host = FindCorrespondingRenderFrameHost(
-        frame_name, node->GetContentDocument()->GetDocumentURL());
-    if (!element_result_->container_frame_host) {
-      DVLOG(1) << __func__ << " Failed to find corresponding owner frame.";
-      SendResult(UnexpectedErrorStatus(__FILE__, __LINE__));
-      return;
-    }
-  } else if (node->HasFrameId()) {
-    // TODO(crbug.com/806868): Support out-of-process iframe.
-    DVLOG(3) << "Warning (unsupported): the element is inside an OOPIF.";
-    SendResult(ClientStatus(UNSUPPORTED));
-    return;
-  }
-
-  if (node->HasShadowRoots()) {
-    // TODO(crbug.com/806868): Support multiple shadow roots.
-    backend_ids.emplace_back(
-        node->GetShadowRoots()->front()->GetBackendNodeId());
-  }
-
-  if (!backend_ids.empty()) {
-    devtools_client_->GetDOM()->ResolveNode(
-        dom::ResolveNodeParams::Builder()
-            .SetBackendNodeId(backend_ids[0])
-            .Build(),
-        base::BindOnce(&WebController::ElementFinder::OnResolveNode,
-                       weak_ptr_factory_.GetWeakPtr(), index));
-    return;
-  }
-
-  RecursiveFindElement(object_id, ++index);
-}
-
-void WebController::ElementFinder::OnResolveNode(
-    size_t index,
-    std::unique_ptr<dom::ResolveNodeResult> result) {
-  if (!result || !result->GetObject() || !result->GetObject()->HasObjectId()) {
-    DVLOG(1) << __func__ << " Failed to resolve object id from backend id.";
-    SendResult(UnexpectedErrorStatus(__FILE__, __LINE__));
-    return;
-  }
-
-  RecursiveFindElement(result->GetObject()->GetObjectId(), ++index);
-}
-
-content::RenderFrameHost*
-WebController::ElementFinder::FindCorrespondingRenderFrameHost(
-    std::string name,
-    std::string document_url) {
-  content::RenderFrameHost* ret_frame = nullptr;
-  for (auto* frame : web_contents_->GetAllFrames()) {
-    if (frame->GetFrameName() == name &&
-        frame->GetLastCommittedURL().spec() == document_url) {
-      DCHECK(!ret_frame);
-      ret_frame = frame;
-    }
-  }
-
-  return ret_frame;
-}
-
 // static
 std::unique_ptr<WebController> WebController::CreateForWebContents(
     content::WebContents* web_contents,
@@ -1016,7 +286,7 @@
     base::OnceCallback<void(const ClientStatus&)> callback,
     ClickAction::ClickType click_type,
     const ClientStatus& status,
-    std::unique_ptr<FindElementResult> result) {
+    std::unique_ptr<ElementFinder::Result> result) {
   // Found element must belong to a frame.
   if (!status.ok()) {
     DVLOG(1) << __func__ << " Failed to find the element to click or tap.";
@@ -1036,7 +306,7 @@
 void WebController::OnWaitDocumentToBecomeInteractiveForClickOrTap(
     base::OnceCallback<void(const ClientStatus&)> callback,
     ClickAction::ClickType click_type,
-    std::unique_ptr<FindElementResult> target_element,
+    std::unique_ptr<ElementFinder::Result> target_element,
     bool result) {
   if (!result) {
     std::move(callback).Run(ClientStatus(TIMED_OUT));
@@ -1047,7 +317,7 @@
 }
 
 void WebController::ClickOrTapElement(
-    std::unique_ptr<FindElementResult> target_element,
+    std::unique_ptr<ElementFinder::Result> target_element,
     ClickAction::ClickType click_type,
     base::OnceCallback<void(const ClientStatus&)> callback) {
   std::string element_object_id = target_element->object_id;
@@ -1067,7 +337,7 @@
 }
 
 void WebController::OnScrollIntoView(
-    std::unique_ptr<FindElementResult> target_element,
+    std::unique_ptr<ElementFinder::Result> target_element,
     base::OnceCallback<void(const ClientStatus&)> callback,
     ClickAction::ClickType click_type,
     std::unique_ptr<runtime::CallFunctionOnResult> result) {
@@ -1096,15 +366,14 @@
   }
 
   std::unique_ptr<ElementPositionGetter> getter =
-      std::make_unique<ElementPositionGetter>(*settings_);
-  ElementPositionGetter* getter_ptr = getter.get();
-  pending_workers_[getter_ptr] = std::move(getter);
-  getter_ptr->Start(target_element->container_frame_host,
-                    devtools_client_.get(), target_element->object_id,
-                    base::BindOnce(&WebController::TapOrClickOnCoordinates,
-                                   weak_ptr_factory_.GetWeakPtr(),
-                                   base::Unretained(getter_ptr),
-                                   std::move(callback), click_type));
+      std::make_unique<ElementPositionGetter>(devtools_client_.get(),
+                                              *settings_);
+  auto* ptr = getter.get();
+  pending_workers_.emplace_back(std::move(getter));
+  ptr->Start(target_element->container_frame_host, target_element->object_id,
+             base::BindOnce(&WebController::TapOrClickOnCoordinates,
+                            weak_ptr_factory_.GetWeakPtr(), ptr,
+                            std::move(callback), click_type));
 }
 
 void WebController::OnClickJS(
@@ -1124,7 +393,9 @@
     bool has_coordinates,
     int x,
     int y) {
-  pending_workers_.erase(getter_to_release);
+  base::EraseIf(pending_workers_, [getter_to_release](const auto& worker) {
+    return worker.get() == getter_to_release;
+  });
 
   if (!has_coordinates) {
     DVLOG(1) << __func__ << " Failed to get element position.";
@@ -1231,7 +502,7 @@
 void WebController::OnFindElementForCheck(
     base::OnceCallback<void(bool)> callback,
     const ClientStatus& status,
-    std::unique_ptr<FindElementResult> result) {
+    std::unique_ptr<ElementFinder::Result> result) {
   DVLOG_IF(1,
            !status.ok() && status.proto_status() != ELEMENT_RESOLUTION_FAILED)
       << __func__ << ": " << status;
@@ -1296,7 +567,7 @@
     DocumentReadyState min_ready_state,
     base::OnceCallback<void(const ClientStatus&, DocumentReadyState)> callback,
     const ClientStatus& status,
-    std::unique_ptr<FindElementResult> element) {
+    std::unique_ptr<ElementFinder::Result> element) {
   if (!status.ok()) {
     std::move(callback).Run(status, DOCUMENT_UNKNOWN_READY_STATE);
     return;
@@ -1326,21 +597,23 @@
 
 void WebController::FindElement(const Selector& selector,
                                 bool strict_mode,
-                                FindElementCallback callback) {
+                                ElementFinder::Callback callback) {
   auto finder = std::make_unique<ElementFinder>(
       web_contents_, devtools_client_.get(), selector, strict_mode);
-  ElementFinder* ptr = finder.get();
-  pending_workers_[ptr] = std::move(finder);
+  auto* ptr = finder.get();
+  pending_workers_.emplace_back(std::move(finder));
   ptr->Start(base::BindOnce(&WebController::OnFindElementResult,
                             base::Unretained(this), ptr, std::move(callback)));
 }
 
 void WebController::OnFindElementResult(
     ElementFinder* finder_to_release,
-    FindElementCallback callback,
+    ElementFinder::Callback callback,
     const ClientStatus& status,
-    std::unique_ptr<FindElementResult> result) {
-  pending_workers_.erase(finder_to_release);
+    std::unique_ptr<ElementFinder::Result> result) {
+  base::EraseIf(pending_workers_, [finder_to_release](const auto& worker) {
+    return worker.get() == finder_to_release;
+  });
   std::move(callback).Run(status, std::move(result));
 }
 
@@ -1348,7 +621,7 @@
     const TopPadding& top_padding,
     base::OnceCallback<void(const ClientStatus&)> callback,
     const ClientStatus& status,
-    std::unique_ptr<FindElementResult> element_result) {
+    std::unique_ptr<ElementFinder::Result> element_result) {
   if (!status.ok()) {
     DVLOG(1) << __func__ << " Failed to find the element to focus on.";
     std::move(callback).Run(status);
@@ -1367,7 +640,7 @@
 void WebController::OnWaitDocumentToBecomeInteractiveForFocusElement(
     const TopPadding& top_padding,
     base::OnceCallback<void(const ClientStatus&)> callback,
-    std::unique_ptr<FindElementResult> target_element,
+    std::unique_ptr<ElementFinder::Result> target_element,
     bool result) {
   if (!result) {
     std::move(callback).Run(ClientStatus(ELEMENT_UNSTABLE));
@@ -1426,7 +699,7 @@
     const Selector& selector,
     base::OnceCallback<void(const ClientStatus&)> callback,
     const ClientStatus& status,
-    std::unique_ptr<FindElementResult> element_result) {
+    std::unique_ptr<ElementFinder::Result> element_result) {
   if (!status.ok()) {
     DVLOG(1) << __func__ << " Failed to find the element for filling the form.";
     std::move(callback).Run(status);
@@ -1514,7 +787,7 @@
     const std::string& selected_option,
     base::OnceCallback<void(const ClientStatus&)> callback,
     const ClientStatus& status,
-    std::unique_ptr<FindElementResult> element_result) {
+    std::unique_ptr<ElementFinder::Result> element_result) {
   if (!status.ok()) {
     DVLOG(1) << __func__ << " Failed to find the element to select an option.";
     std::move(callback).Run(status);
@@ -1573,7 +846,7 @@
 void WebController::OnFindElementForHighlightElement(
     base::OnceCallback<void(const ClientStatus&)> callback,
     const ClientStatus& status,
-    std::unique_ptr<FindElementResult> element_result) {
+    std::unique_ptr<ElementFinder::Result> element_result) {
   if (!status.ok()) {
     DVLOG(1) << __func__ << " Failed to find the element to highlight.";
     std::move(callback).Run(status);
@@ -1629,7 +902,7 @@
 void WebController::OnFindElementForGetFieldValue(
     base::OnceCallback<void(bool, const std::string&)> callback,
     const ClientStatus& status,
-    std::unique_ptr<FindElementResult> element_result) {
+    std::unique_ptr<ElementFinder::Result> element_result) {
   const std::string object_id = element_result->object_id;
   if (!status.ok()) {
     std::move(callback).Run(/* exists= */ false, "");
@@ -1794,7 +1067,7 @@
     const std::string& value,
     base::OnceCallback<void(const ClientStatus&)> callback,
     const ClientStatus& status,
-    std::unique_ptr<FindElementResult> element_result) {
+    std::unique_ptr<ElementFinder::Result> element_result) {
   if (!status.ok()) {
     std::move(callback).Run(status);
     return;
@@ -1844,7 +1117,7 @@
     const std::string& value,
     base::OnceCallback<void(const ClientStatus&)> callback,
     const ClientStatus& status,
-    std::unique_ptr<FindElementResult> element_result) {
+    std::unique_ptr<ElementFinder::Result> element_result) {
   if (!status.ok()) {
     std::move(callback).Run(status);
     return;
@@ -1909,7 +1182,7 @@
     const int delay_in_millisecond,
     base::OnceCallback<void(const ClientStatus&)> callback,
     const ClientStatus& status,
-    std::unique_ptr<FindElementResult> element_result) {
+    std::unique_ptr<ElementFinder::Result> element_result) {
   if (!status.ok()) {
     std::move(callback).Run(status);
     return;
@@ -1986,7 +1259,7 @@
 void WebController::OnFindElementForPosition(
     base::OnceCallback<void(bool, const RectF&)> callback,
     const ClientStatus& status,
-    std::unique_ptr<FindElementResult> result) {
+    std::unique_ptr<ElementFinder::Result> result) {
   if (!status.ok()) {
     RectF empty;
     std::move(callback).Run(false, empty);
@@ -2035,7 +1308,7 @@
 void WebController::OnFindElementForGetOuterHtml(
     base::OnceCallback<void(const ClientStatus&, const std::string&)> callback,
     const ClientStatus& status,
-    std::unique_ptr<FindElementResult> element_result) {
+    std::unique_ptr<ElementFinder::Result> element_result) {
   if (!status.ok()) {
     DVLOG(2) << __func__ << " Failed to find element for GetOuterHtml";
     std::move(callback).Run(status, "");
diff --git a/components/autofill_assistant/browser/web_controller.h b/components/autofill_assistant/browser/web/web_controller.h
similarity index 83%
rename from components/autofill_assistant/browser/web_controller.h
rename to components/autofill_assistant/browser/web/web_controller.h
index bccb40c..46d1bea 100644
--- a/components/autofill_assistant/browser/web_controller.h
+++ b/components/autofill_assistant/browser/web/web_controller.h
@@ -2,10 +2,9 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_WEB_CONTROLLER_H_
-#define COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_WEB_CONTROLLER_H_
+#ifndef COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_WEB_WEB_CONTROLLER_H_
+#define COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_WEB_WEB_CONTROLLER_H_
 
-#include <map>
 #include <memory>
 #include <string>
 #include <vector>
@@ -24,6 +23,9 @@
 #include "components/autofill_assistant/browser/rectf.h"
 #include "components/autofill_assistant/browser/selector.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_position_getter.h"
+#include "components/autofill_assistant/browser/web/web_controller_worker.h"
 #include "third_party/icu/source/common/unicode/umachine.h"
 #include "url/gurl.h"
 
@@ -40,7 +42,7 @@
 namespace autofill {
 struct FormData;
 struct FormFieldData;
-}
+}  // namespace autofill
 
 namespace autofill_assistant {
 struct ClientSettings;
@@ -204,47 +206,6 @@
  private:
   friend class WebControllerBrowserTest;
 
-  // Callback that receives the position that corresponds to the center
-  // of an element, from ElementPositionGetter.
-  //
-  // If the first element is false, the call failed. Otherwise, the second
-  // element contains the x position and the third the y position of the center
-  // of the element in viewport coordinates.
-  using ElementPositionCallback = base::OnceCallback<void(bool, int, int)>;
-
-  // Superclass for workers that execute complex operation and keep a pointer to
-  // this controller or the devtools client. Workers are owned by
-  // pending_workers_ and are removed once the operation is finished.
-  class Worker;
-
-  // Worker class to get element's position in viewport coordinates when is
-  // stable and the frame it belongs finished visual update.
-  class ElementPositionGetter;
-
-  // Worker class to find element(s) matching a selector. Returns
-  // FindElementResult.
-  class ElementFinder;
-
-  struct FindElementResult {
-    FindElementResult() = default;
-    ~FindElementResult() = default;
-
-    // The render frame host contains the element.
-    content::RenderFrameHost* container_frame_host;
-
-    // The selector index in the given selectors corresponding to the container
-    // frame. Zero indicates the element is in main frame or the first element
-    // is the container frame selector. Compare main frame with the above
-    // |container_frame_host| to distinguish them.
-    size_t container_frame_selector_index;
-
-    // The object id of the element.
-    std::string object_id;
-  };
-  using FindElementCallback =
-      base::OnceCallback<void(const ClientStatus&,
-                              std::unique_ptr<FindElementResult>)>;
-
   struct FillFormInputData {
     FillFormInputData();
     ~FillFormInputData();
@@ -261,23 +222,23 @@
       base::OnceCallback<void(const ClientStatus&)> callback,
       ClickAction::ClickType click_type,
       const ClientStatus& status,
-      std::unique_ptr<FindElementResult> result);
+      std::unique_ptr<ElementFinder::Result> result);
   void OnWaitDocumentToBecomeInteractiveForClickOrTap(
       base::OnceCallback<void(const ClientStatus&)> callback,
       ClickAction::ClickType click_type,
-      std::unique_ptr<FindElementResult> target_element,
+      std::unique_ptr<ElementFinder::Result> target_element,
       bool result);
   void OnFindElementForTap(
       base::OnceCallback<void(const ClientStatus&)> callback,
       const ClientStatus& status,
-      std::unique_ptr<FindElementResult> result);
+      std::unique_ptr<ElementFinder::Result> result);
   void ClickOrTapElement(
-      std::unique_ptr<FindElementResult> target_element,
+      std::unique_ptr<ElementFinder::Result> target_element,
       ClickAction::ClickType click_type,
       base::OnceCallback<void(const ClientStatus&)> callback);
   void OnClickJS(base::OnceCallback<void(const ClientStatus&)> callback,
                  std::unique_ptr<runtime::CallFunctionOnResult> result);
-  void OnScrollIntoView(std::unique_ptr<FindElementResult> target_element,
+  void OnScrollIntoView(std::unique_ptr<ElementFinder::Result> target_element,
                         base::OnceCallback<void(const ClientStatus&)> callback,
                         ClickAction::ClickType click_type,
                         std::unique_ptr<runtime::CallFunctionOnResult> result);
@@ -304,7 +265,7 @@
       std::unique_ptr<input::DispatchTouchEventResult> result);
   void OnFindElementForCheck(base::OnceCallback<void(bool)> callback,
                              const ClientStatus& status,
-                             std::unique_ptr<FindElementResult> result);
+                             std::unique_ptr<ElementFinder::Result> result);
   void OnWaitForWindowHeightChange(
       base::OnceCallback<void(const ClientStatus&)> callback,
       std::unique_ptr<runtime::EvaluateResult> result);
@@ -314,17 +275,17 @@
   // found. Otherwise if |strict-mode| is true, do not return any.
   void FindElement(const Selector& selector,
                    bool strict_mode,
-                   FindElementCallback callback);
+                   ElementFinder::Callback callback);
   void OnFindElementResult(ElementFinder* finder_to_release,
-                           FindElementCallback callback,
+                           ElementFinder::Callback callback,
                            const ClientStatus& status,
-                           std::unique_ptr<FindElementResult> result);
+                           std::unique_ptr<ElementFinder::Result> result);
   void OnFindElementForFillingForm(
       std::unique_ptr<FillFormInputData> data_to_autofill,
       const Selector& selector,
       base::OnceCallback<void(const ClientStatus&)> callback,
       const ClientStatus& status,
-      std::unique_ptr<FindElementResult> element_result);
+      std::unique_ptr<ElementFinder::Result> element_result);
   void OnGetFormAndFieldDataForFillingForm(
       std::unique_ptr<FillFormInputData> data_to_autofill,
       base::OnceCallback<void(const ClientStatus&)> callback,
@@ -335,11 +296,11 @@
       const TopPadding& top_padding,
       base::OnceCallback<void(const ClientStatus&)> callback,
       const ClientStatus& status,
-      std::unique_ptr<FindElementResult> element_result);
+      std::unique_ptr<ElementFinder::Result> element_result);
   void OnWaitDocumentToBecomeInteractiveForFocusElement(
       const TopPadding& top_padding,
       base::OnceCallback<void(const ClientStatus&)> callback,
-      std::unique_ptr<FindElementResult> target_element,
+      std::unique_ptr<ElementFinder::Result> target_element,
       bool result);
   void OnFocusElement(base::OnceCallback<void(const ClientStatus&)> callback,
                       std::unique_ptr<runtime::CallFunctionOnResult> result);
@@ -347,20 +308,20 @@
       const std::string& selected_option,
       base::OnceCallback<void(const ClientStatus&)> callback,
       const ClientStatus& status,
-      std::unique_ptr<FindElementResult> element_result);
+      std::unique_ptr<ElementFinder::Result> element_result);
   void OnSelectOption(base::OnceCallback<void(const ClientStatus&)> callback,
                       std::unique_ptr<runtime::CallFunctionOnResult> result);
   void OnFindElementForHighlightElement(
       base::OnceCallback<void(const ClientStatus&)> callback,
       const ClientStatus& status,
-      std::unique_ptr<FindElementResult> element_result);
+      std::unique_ptr<ElementFinder::Result> element_result);
   void OnHighlightElement(
       base::OnceCallback<void(const ClientStatus&)> callback,
       std::unique_ptr<runtime::CallFunctionOnResult> result);
   void OnFindElementForGetFieldValue(
       base::OnceCallback<void(bool, const std::string&)> callback,
       const ClientStatus& status,
-      std::unique_ptr<FindElementResult> element_result);
+      std::unique_ptr<ElementFinder::Result> element_result);
   void OnGetValueAttribute(
       base::OnceCallback<void(bool, const std::string&)> callback,
       std::unique_ptr<runtime::CallFunctionOnResult> result);
@@ -395,7 +356,7 @@
       const std::string& value,
       base::OnceCallback<void(const ClientStatus&)> callback,
       const ClientStatus& status,
-      std::unique_ptr<FindElementResult> element_result);
+      std::unique_ptr<ElementFinder::Result> element_result);
   void OnSetAttribute(base::OnceCallback<void(const ClientStatus&)> callback,
                       std::unique_ptr<runtime::CallFunctionOnResult> result);
   void OnFindElementForSendKeyboardInput(
@@ -404,12 +365,12 @@
       int delay_in_milli,
       base::OnceCallback<void(const ClientStatus&)> callback,
       const ClientStatus& status,
-      std::unique_ptr<FindElementResult> element_result);
+      std::unique_ptr<ElementFinder::Result> element_result);
   void OnFindElementForSetFieldValue(
       const std::string& value,
       base::OnceCallback<void(const ClientStatus&)> callback,
       const ClientStatus& status,
-      std::unique_ptr<FindElementResult> element_result);
+      std::unique_ptr<ElementFinder::Result> element_result);
   void OnSetValueAttribute(
       base::OnceCallback<void(const ClientStatus&)> callback,
       std::unique_ptr<runtime::CallFunctionOnResult> result);
@@ -417,14 +378,14 @@
       base::OnceCallback<void(const ClientStatus&, const std::string&)>
           callback,
       const ClientStatus& status,
-      std::unique_ptr<FindElementResult> element_result);
+      std::unique_ptr<ElementFinder::Result> element_result);
   void OnGetOuterHtml(base::OnceCallback<void(const ClientStatus&,
                                               const std::string&)> callback,
                       std::unique_ptr<runtime::CallFunctionOnResult> result);
   void OnFindElementForPosition(
       base::OnceCallback<void(bool, const RectF&)> callback,
       const ClientStatus& status,
-      std::unique_ptr<FindElementResult> result);
+      std::unique_ptr<ElementFinder::Result> result);
   void OnGetVisualViewport(
       base::OnceCallback<void(bool, const RectF&)> callback,
       std::unique_ptr<runtime::EvaluateResult> result);
@@ -450,17 +411,12 @@
       std::string object_id,
       base::OnceCallback<void(bool)> callback,
       std::unique_ptr<runtime::CallFunctionOnResult> result);
-  void OnFindElementForDocumentReadyState(
-      base::OnceCallback<void(const ClientStatus&, const std::string&)>
-          callback,
-      const ClientStatus& status,
-      std::unique_ptr<FindElementResult> element);
   void OnFindElementForWaitForDocumentReadyState(
       DocumentReadyState min_ready_state,
       base::OnceCallback<void(const ClientStatus&, DocumentReadyState)>
           callback,
       const ClientStatus& status,
-      std::unique_ptr<FindElementResult> element);
+      std::unique_ptr<ElementFinder::Result> element);
 
   // Weak pointer is fine here since it must outlive this web controller, which
   // is guaranteed by the owner of this object.
@@ -468,11 +424,11 @@
   std::unique_ptr<DevtoolsClient> devtools_client_;
   const ClientSettings* const settings_;
 
-  // Workers currently running and using |devtools_client_|.
-  std::map<Worker*, std::unique_ptr<Worker>> pending_workers_;
+  // Currently running workers.
+  std::vector<std::unique_ptr<WebControllerWorker>> pending_workers_;
 
   base::WeakPtrFactory<WebController> weak_ptr_factory_{this};
   DISALLOW_COPY_AND_ASSIGN(WebController);
 };
 }  // namespace autofill_assistant
-#endif  // COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_WEB_CONTROLLER_H_
+#endif  // COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_WEB_WEB_CONTROLLER_H_
diff --git a/components/autofill_assistant/browser/web_controller_browsertest.cc b/components/autofill_assistant/browser/web/web_controller_browsertest.cc
similarity index 98%
rename from components/autofill_assistant/browser/web_controller_browsertest.cc
rename to components/autofill_assistant/browser/web/web_controller_browsertest.cc
index 47b497d..9481f48 100644
--- a/components/autofill_assistant/browser/web_controller_browsertest.cc
+++ b/components/autofill_assistant/browser/web/web_controller_browsertest.cc
@@ -10,7 +10,7 @@
 #include "components/autofill_assistant/browser/service.pb.h"
 #include "components/autofill_assistant/browser/string_conversions_util.h"
 #include "components/autofill_assistant/browser/top_padding.h"
-#include "components/autofill_assistant/browser/web_controller.h"
+#include "components/autofill_assistant/browser/web/web_controller.h"
 #include "content/public/browser/web_contents.h"
 #include "content/public/test/browser_test_utils.h"
 #include "content/public/test/content_browser_test.h"
@@ -238,7 +238,7 @@
 
   void FindElement(const Selector& selector,
                    ClientStatus* status_out,
-                   WebController::FindElementResult* result_out) {
+                   ElementFinder::Result* result_out) {
     base::RunLoop run_loop;
     web_controller_->FindElement(
         selector, /* strict_mode= */ true,
@@ -251,9 +251,9 @@
 
   void OnFindElement(const base::Closure& done_callback,
                      ClientStatus* status_out,
-                     WebController::FindElementResult* result_out,
+                     ElementFinder::Result* result_out,
                      const ClientStatus& status,
-                     std::unique_ptr<WebController::FindElementResult> result) {
+                     std::unique_ptr<ElementFinder::Result> result) {
     ASSERT_TRUE(result);
     done_callback.Run();
     if (status_out)
@@ -268,7 +268,7 @@
                            bool is_main_frame) {
     SCOPED_TRACE(::testing::Message() << selector << " strict");
     ClientStatus status;
-    WebController::FindElementResult result;
+    ElementFinder::Result result;
     FindElement(selector, &status, &result);
     EXPECT_EQ(ACTION_APPLIED, status.proto_status());
     CheckFindElementResult(result, expected_index, is_main_frame);
@@ -277,13 +277,13 @@
   void FindElementExpectEmptyResult(const Selector& selector) {
     SCOPED_TRACE(::testing::Message() << selector << " strict");
     ClientStatus status;
-    WebController::FindElementResult result;
+    ElementFinder::Result result;
     FindElement(selector, &status, &result);
     EXPECT_EQ(ELEMENT_RESOLUTION_FAILED, status.proto_status());
     EXPECT_THAT(result.object_id, IsEmpty());
   }
 
-  void CheckFindElementResult(const WebController::FindElementResult& result,
+  void CheckFindElementResult(const ElementFinder::Result& result,
                               size_t expected_index,
                               bool is_main_frame) {
     if (is_main_frame) {
@@ -677,8 +677,7 @@
   WaitForElementRemove(selector);
 }
 
-IN_PROC_BROWSER_TEST_F(WebControllerBrowserTest,
-                       ClickElementInIFrame) {
+IN_PROC_BROWSER_TEST_F(WebControllerBrowserTest, ClickElementInIFrame) {
   Selector selector;
   selector.selectors.emplace_back("#iframe");
   selector.selectors.emplace_back("#shadowsection");
@@ -1241,4 +1240,4 @@
               AnyOf(DOCUMENT_LOADED, DOCUMENT_INTERACTIVE, DOCUMENT_COMPLETE));
 }
 
-}  // namespace
+}  // namespace autofill_assistant
diff --git a/components/autofill_assistant/browser/web/web_controller_util.cc b/components/autofill_assistant/browser/web/web_controller_util.cc
new file mode 100644
index 0000000..8ca38eeb
--- /dev/null
+++ b/components/autofill_assistant/browser/web/web_controller_util.cc
@@ -0,0 +1,70 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/autofill_assistant/browser/web/web_controller_util.h"
+
+namespace autofill_assistant {
+
+ClientStatus UnexpectedErrorStatus(const std::string& file, int line) {
+  ClientStatus status(OTHER_ACTION_STATUS);
+  auto* info = status.mutable_details()->mutable_unexpected_error_info();
+  info->set_source_file(file);
+  info->set_source_line_number(line);
+  return status;
+}
+
+ClientStatus JavaScriptErrorStatus(const std::string& file,
+                                   int line,
+                                   const runtime::ExceptionDetails* exception) {
+  ClientStatus status(UNEXPECTED_JS_ERROR);
+  auto* info = status.mutable_details()->mutable_unexpected_error_info();
+  info->set_source_file(file);
+  info->set_source_line_number(line);
+  if (exception) {
+    if (exception->HasException() &&
+        exception->GetException()->HasClassName()) {
+      info->set_js_exception_classname(
+          exception->GetException()->GetClassName());
+    }
+    info->set_js_exception_line_number(exception->GetLineNumber());
+    info->set_js_exception_column_number(exception->GetColumnNumber());
+  }
+  return status;
+}
+
+bool SafeGetObjectId(const runtime::RemoteObject* result, std::string* out) {
+  if (result && result->HasObjectId()) {
+    *out = result->GetObjectId();
+    return true;
+  }
+  return false;
+}
+
+bool SafeGetStringValue(const runtime::RemoteObject* result, std::string* out) {
+  if (result && result->HasValue() && result->GetValue()->is_string()) {
+    *out = result->GetValue()->GetString();
+    return true;
+  }
+  return false;
+}
+
+bool SafeGetIntValue(const runtime::RemoteObject* result, int* out) {
+  if (result && result->HasValue() && result->GetValue()->is_int()) {
+    *out = result->GetValue()->GetInt();
+    return true;
+  }
+  *out = 0;
+  return false;
+}
+
+bool SafeGetBool(const runtime::RemoteObject* result, bool* out) {
+  if (result && result->HasValue() && result->GetValue()->is_bool()) {
+    *out = result->GetValue()->GetBool();
+    return true;
+  }
+  *out = false;
+  return false;
+}
+
+}  //  namespace autofill_assistant
\ No newline at end of file
diff --git a/components/autofill_assistant/browser/web/web_controller_util.h b/components/autofill_assistant/browser/web/web_controller_util.h
new file mode 100644
index 0000000..79c618c
--- /dev/null
+++ b/components/autofill_assistant/browser/web/web_controller_util.h
@@ -0,0 +1,52 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_WEB_WEB_CONTROLLER_UTIL_H_
+#define COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_WEB_WEB_CONTROLLER_UTIL_H_
+
+#include <string>
+#include "components/autofill_assistant/browser/client_status.h"
+#include "components/autofill_assistant/browser/devtools/devtools/domains/types_runtime.h"
+
+namespace autofill_assistant {
+
+// Builds a ClientStatus appropriate for an unexpected error.
+//
+// This should only be used in situations where getting an error cannot be
+// anything but a bug in the client.
+ClientStatus UnexpectedErrorStatus(const std::string& file, int line);
+
+// Builds a ClientStatus appropriate for a JavaScript error.
+ClientStatus JavaScriptErrorStatus(const std::string& file,
+                                   int line,
+                                   const runtime::ExceptionDetails* exception);
+
+// Makes sure that the given EvaluateResult exists, is successful and contains a
+// result.
+template <typename T>
+ClientStatus CheckJavaScriptResult(T* result, const char* file, int line) {
+  if (!result)
+    return JavaScriptErrorStatus(file, line, nullptr);
+  if (result->HasExceptionDetails())
+    return JavaScriptErrorStatus(file, line, result->GetExceptionDetails());
+  if (!result->GetResult())
+    return JavaScriptErrorStatus(file, line, nullptr);
+  return OkClientStatus();
+}
+
+// Safely gets an object id from a RemoteObject
+bool SafeGetObjectId(const runtime::RemoteObject* result, std::string* out);
+
+// Safely gets a string value from a RemoteObject
+bool SafeGetStringValue(const runtime::RemoteObject* result, std::string* out);
+
+// Safely gets a int value from a RemoteObject.
+bool SafeGetIntValue(const runtime::RemoteObject* result, int* out);
+
+// Safely gets a boolean value from a RemoteObject
+bool SafeGetBool(const runtime::RemoteObject* result, bool* out);
+
+}  //  namespace autofill_assistant
+
+#endif  // COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_WEB_WEB_CONTROLLER_UTIL_H_
\ No newline at end of file
diff --git a/components/autofill_assistant/browser/web/web_controller_worker.h b/components/autofill_assistant/browser/web/web_controller_worker.h
new file mode 100644
index 0000000..5da5a27
--- /dev/null
+++ b/components/autofill_assistant/browser/web/web_controller_worker.h
@@ -0,0 +1,27 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_WEB_WEB_CONTROLLER_WORKER_H_
+#define COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_WEB_WEB_CONTROLLER_WORKER_H_
+
+#include "base/macros.h"
+
+namespace autofill_assistant {
+
+// Superclass for workers of |WebController| that execute complex operations.
+// This superclass merely ensures that workers can be memory-managed by
+// others (in particular an instance of |WebController|), by making the
+// base constructor/destructor public.
+class WebControllerWorker {
+ public:
+  WebControllerWorker() = default;
+  virtual ~WebControllerWorker() = default;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(WebControllerWorker);
+};
+
+}  //  namespace autofill_assistant
+
+#endif  // COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_WEB_WEB_CONTROLLER_WORKER_H_
\ No newline at end of file
diff --git a/components/background_task_scheduler/android/java/src/org/chromium/components/background_task_scheduler/BackgroundTaskSchedulerGcmNetworkManager.java b/components/background_task_scheduler/android/java/src/org/chromium/components/background_task_scheduler/BackgroundTaskSchedulerGcmNetworkManager.java
index 77c55d6..74a432b 100644
--- a/components/background_task_scheduler/android/java/src/org/chromium/components/background_task_scheduler/BackgroundTaskSchedulerGcmNetworkManager.java
+++ b/components/background_task_scheduler/android/java/src/org/chromium/components/background_task_scheduler/BackgroundTaskSchedulerGcmNetworkManager.java
@@ -177,6 +177,12 @@
             builder.setExtras(mTaskExtras);
             mBuilder = builder;
         }
+
+        @Override
+        public void visit(TaskInfo.ExactInfo exactInfo) {
+            throw new RuntimeException("Exact tasks should not be scheduled with "
+                    + "GcmNetworkManager.");
+        }
     }
 
     private static int getGcmNetworkManagerNetworkTypeFromTypeFromTaskNetworkType(
diff --git a/components/background_task_scheduler/android/java/src/org/chromium/components/background_task_scheduler/BackgroundTaskSchedulerImpl.java b/components/background_task_scheduler/android/java/src/org/chromium/components/background_task_scheduler/BackgroundTaskSchedulerImpl.java
index 1bb91a9..99762bbc 100644
--- a/components/background_task_scheduler/android/java/src/org/chromium/components/background_task_scheduler/BackgroundTaskSchedulerImpl.java
+++ b/components/background_task_scheduler/android/java/src/org/chromium/components/background_task_scheduler/BackgroundTaskSchedulerImpl.java
@@ -48,9 +48,8 @@
                     taskInfo.getTaskId(), success);
 
             // Retain expiration metrics
-            ExpirationMetricsVisitor expirationMetricsVisitor =
-                    new ExpirationMetricsVisitor(taskInfo.getTaskId());
-            taskInfo.getTimingInfo().accept(expirationMetricsVisitor);
+            MetricsVisitor metricsVisitor = new MetricsVisitor(taskInfo.getTaskId());
+            taskInfo.getTimingInfo().accept(metricsVisitor);
 
             if (success) {
                 BackgroundTaskSchedulerPrefs.addScheduledTask(taskInfo);
@@ -60,10 +59,10 @@
     }
 
     // TODO(crbug.com/996178): Update the documentation for the expiration feature.
-    private class ExpirationMetricsVisitor implements TaskInfo.TimingInfoVisitor {
+    private class MetricsVisitor implements TaskInfo.TimingInfoVisitor {
         private final int mTaskId;
 
-        ExpirationMetricsVisitor(int taskId) {
+        MetricsVisitor(int taskId) {
             mTaskId = taskId;
         }
 
@@ -78,6 +77,11 @@
             BackgroundTaskSchedulerUma.getInstance().reportTaskCreatedAndExpirationState(
                     mTaskId, periodicInfo.expiresAfterWindowEndTime());
         }
+
+        @Override
+        public void visit(TaskInfo.ExactInfo exactInfo) {
+            BackgroundTaskSchedulerUma.getInstance().reportExactTaskCreated(mTaskId);
+        }
     }
 
     @Override
diff --git a/components/background_task_scheduler/android/java/src/org/chromium/components/background_task_scheduler/BackgroundTaskSchedulerJobService.java b/components/background_task_scheduler/android/java/src/org/chromium/components/background_task_scheduler/BackgroundTaskSchedulerJobService.java
index 7eb169c..c881e7e6 100644
--- a/components/background_task_scheduler/android/java/src/org/chromium/components/background_task_scheduler/BackgroundTaskSchedulerJobService.java
+++ b/components/background_task_scheduler/android/java/src/org/chromium/components/background_task_scheduler/BackgroundTaskSchedulerJobService.java
@@ -19,6 +19,7 @@
 import org.chromium.base.VisibleForTesting;
 
 import java.util.List;
+
 /**
  * An implementation of {@link BackgroundTaskSchedulerDelegate} that uses the system
  * {@link JobScheduler} to schedule jobs.
@@ -183,6 +184,12 @@
             }
             mBuilder.setPeriodic(periodicInfo.getIntervalMs());
         }
+
+        @Override
+        public void visit(TaskInfo.ExactInfo exactInfo) {
+            throw new RuntimeException("Exact tasks should not be scheduled with "
+                    + "JobScheduler.");
+        }
     }
 
     private static int getJobInfoNetworkTypeFromTaskNetworkType(
diff --git a/components/background_task_scheduler/android/java/src/org/chromium/components/background_task_scheduler/BackgroundTaskSchedulerUma.java b/components/background_task_scheduler/android/java/src/org/chromium/components/background_task_scheduler/BackgroundTaskSchedulerUma.java
index 8d5f5c6..40d176e9 100644
--- a/components/background_task_scheduler/android/java/src/org/chromium/components/background_task_scheduler/BackgroundTaskSchedulerUma.java
+++ b/components/background_task_scheduler/android/java/src/org/chromium/components/background_task_scheduler/BackgroundTaskSchedulerUma.java
@@ -139,6 +139,12 @@
         }
     }
 
+    /** Reports metrics for creating an exact tasks. */
+    public void reportExactTaskCreated(int taskId) {
+        cacheEvent("Android.BackgroundTaskScheduler.ExactTaskCreated",
+                toUmaEnumValueFromTaskId(taskId));
+    }
+
     /** Reports metrics for task scheduling with the expiration feature activated. */
     public void reportTaskCreatedAndExpirationState(int taskId, boolean expires) {
         if (expires) {
diff --git a/components/background_task_scheduler/android/java/src/org/chromium/components/background_task_scheduler/TaskInfo.java b/components/background_task_scheduler/android/java/src/org/chromium/components/background_task_scheduler/TaskInfo.java
index 56928212e..79fc74c 100644
--- a/components/background_task_scheduler/android/java/src/org/chromium/components/background_task_scheduler/TaskInfo.java
+++ b/components/background_task_scheduler/android/java/src/org/chromium/components/background_task_scheduler/TaskInfo.java
@@ -52,11 +52,16 @@
          * @param periodicInfo object to act on.
          */
         void visit(PeriodicInfo periodicInfo);
+        /**
+         * Applies actions on a given {@link ExactInfo}. This affects information regarding
+         * timing for an exact task.
+         * @param exactInfo object to act on.
+         */
+        void visit(ExactInfo exactInfo);
     }
 
     /**
      * Specifies information regarding one-off tasks.
-     * This is part of a {@link TaskInfo} if the task is NOT a periodic task.
      */
     public static class OneOffInfo implements TimingInfo {
         private final long mWindowStartTimeMs;
@@ -181,7 +186,6 @@
 
     /**
      * Specifies information regarding periodic tasks.
-     * This is part of a {@link TaskInfo} if the task is a periodic task.
      */
     public static class PeriodicInfo implements TimingInfo {
         private final long mIntervalMs;
@@ -318,6 +322,68 @@
         }
     }
 
+    /**
+     * Specifies information regarding exact tasks.
+     */
+    static class ExactInfo implements TimingInfo {
+        private final long mTriggerAtMs;
+
+        private ExactInfo(Builder builder) {
+            mTriggerAtMs = builder.mTriggerAtMs;
+        }
+
+        long getTriggerAtMs() {
+            return mTriggerAtMs;
+        }
+
+        @Override
+        public void accept(TimingInfoVisitor visitor) {
+            visitor.visit(this);
+        }
+
+        @Override
+        public String toString() {
+            StringBuilder sb = new StringBuilder("{");
+            sb.append("triggerAtMs: ").append(mTriggerAtMs).append("}");
+            return sb.toString();
+        }
+
+        /**
+         * @return a new {@link Builder} object to set the values of the exact task.
+         */
+        static Builder create() {
+            return new Builder();
+        }
+
+        /**
+         * A helper builder to provide a way to build {@link ExactInfo}.
+         *
+         * @see #create()
+         */
+        static final class Builder {
+            private long mTriggerAtMs;
+
+            /**
+             * Sets the exact UTC timestamp at which to schedule the exact task.
+             * @param triggerAtMs the UTC timestamp at which the task should be started.
+             * @return the {@link Builder} for creating the {@link ExactInfo} object.
+             */
+            Builder setTriggerAtMs(long triggerAtMs) {
+                mTriggerAtMs = triggerAtMs;
+                return this;
+            }
+
+            /**
+             * Build the {@link ExactInfo object} specified by this builder.
+             *
+             * @return the {@link ExactInfo} object.
+             */
+            ExactInfo build() {
+                return new ExactInfo(this);
+            }
+        }
+    }
+
     @IntDef({NetworkType.NONE, NetworkType.ANY, NetworkType.UNMETERED})
     @Retention(RetentionPolicy.SOURCE)
     public @interface NetworkType {
diff --git a/components/background_task_scheduler/android/junit/src/org/chromium/components/background_task_scheduler/BackgroundTaskSchedulerUmaTest.java b/components/background_task_scheduler/android/junit/src/org/chromium/components/background_task_scheduler/BackgroundTaskSchedulerUmaTest.java
index c56acc9..3b3684b5 100644
--- a/components/background_task_scheduler/android/junit/src/org/chromium/components/background_task_scheduler/BackgroundTaskSchedulerUmaTest.java
+++ b/components/background_task_scheduler/android/junit/src/org/chromium/components/background_task_scheduler/BackgroundTaskSchedulerUmaTest.java
@@ -194,6 +194,16 @@
 
     @Test
     @Feature({"BackgroundTaskScheduler"})
+    public void testReportExactTaskCreated() {
+        doNothing().when(mUmaSpy).cacheEvent(anyString(), anyInt());
+        BackgroundTaskSchedulerUma.getInstance().reportExactTaskCreated(TaskIds.TEST);
+        verify(mUmaSpy, times(1))
+                .cacheEvent(eq("Android.BackgroundTaskScheduler.ExactTaskCreated"),
+                        eq(BackgroundTaskSchedulerUma.BACKGROUND_TASK_TEST));
+    }
+
+    @Test
+    @Feature({"BackgroundTaskScheduler"})
     public void testReportTaskScheduledWithExpiration() {
         doNothing().when(mUmaSpy).cacheEvent(anyString(), anyInt());
         BackgroundTaskSchedulerUma.getInstance().reportTaskCreatedAndExpirationState(
diff --git a/components/background_task_scheduler/android/junit/src/org/chromium/components/background_task_scheduler/TaskInfoTest.java b/components/background_task_scheduler/android/junit/src/org/chromium/components/background_task_scheduler/TaskInfoTest.java
index 613cdc0..9c5025f 100644
--- a/components/background_task_scheduler/android/junit/src/org/chromium/components/background_task_scheduler/TaskInfoTest.java
+++ b/components/background_task_scheduler/android/junit/src/org/chromium/components/background_task_scheduler/TaskInfoTest.java
@@ -6,8 +6,6 @@
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertTrue;
 
 import org.junit.Before;
@@ -34,9 +32,19 @@
         BackgroundTaskSchedulerFactory.setBackgroundTaskFactory(new TestBackgroundTaskFactory());
     }
 
-    private void checkGeneralTaskInfoFields(TaskInfo taskInfo, int taskId) {
-        assertEquals(taskId, taskInfo.getTaskId());
-        assertEquals(TestBackgroundTask.class, taskInfo.getBackgroundTaskClass());
+    @Test
+    @Feature({"BackgroundTaskScheduler"})
+    public void testGeneralFields() {
+        TaskInfo.TimingInfo timingInfo = TaskInfo.OneOffInfo.create()
+                                                 .setWindowEndTimeMs(TEST_END_MS)
+                                                 .setExpiresAfterWindowEndTime(true)
+                                                 .build();
+        TaskInfo oneOffTask = TaskInfo.createTask(TaskIds.TEST, timingInfo).build();
+
+        assertEquals(TaskIds.TEST, oneOffTask.getTaskId());
+        assertEquals(TestBackgroundTask.class,
+                BackgroundTaskSchedulerFactory.getBackgroundTaskFromTaskId(TaskIds.TEST)
+                        .getClass());
     }
 
     @Test
@@ -47,15 +55,8 @@
                                                  .setExpiresAfterWindowEndTime(true)
                                                  .build();
         TaskInfo oneOffTask = TaskInfo.createTask(TaskIds.TEST, timingInfo).build();
-
-        checkGeneralTaskInfoFields(oneOffTask, TaskIds.TEST);
-
-        assertFalse(oneOffTask.getOneOffInfo().hasWindowStartTimeConstraint());
-        assertEquals(TEST_END_MS, oneOffTask.getOneOffInfo().getWindowEndTimeMs());
-        assertTrue(oneOffTask.getOneOffInfo().expiresAfterWindowEndTime());
-
-        assertNotNull(oneOffTask.getOneOffInfo());
-        assertNull(oneOffTask.getPeriodicInfo());
+        CheckTimingInfoVisitor visitor = new CheckTimingInfoVisitor(null, TEST_END_MS, true);
+        oneOffTask.getTimingInfo().accept(visitor);
     }
 
     @Test
@@ -67,11 +68,9 @@
                                                  .setExpiresAfterWindowEndTime(true)
                                                  .build();
         TaskInfo oneOffTask = TaskInfo.createTask(TaskIds.TEST, timingInfo).build();
-
-        assertTrue(oneOffTask.getOneOffInfo().hasWindowStartTimeConstraint());
-        assertEquals(TEST_START_MS, oneOffTask.getOneOffInfo().getWindowStartTimeMs());
-        assertEquals(TEST_END_MS, oneOffTask.getOneOffInfo().getWindowEndTimeMs());
-        assertTrue(oneOffTask.getOneOffInfo().expiresAfterWindowEndTime());
+        CheckTimingInfoVisitor visitor =
+                new CheckTimingInfoVisitor(TEST_START_MS, TEST_END_MS, true);
+        oneOffTask.getTimingInfo().accept(visitor);
     }
 
     @Test
@@ -83,10 +82,8 @@
                                                  .setExpiresAfterWindowEndTime(true)
                                                  .build();
         TaskInfo oneOffTask = TaskInfo.createTask(TaskIds.TEST, timingInfo).build();
-
-        assertEquals(TEST_END_MS, oneOffTask.getOneOffInfo().getWindowStartTimeMs());
-        assertEquals(TEST_END_MS, oneOffTask.getOneOffInfo().getWindowEndTimeMs());
-        assertTrue(oneOffTask.getOneOffInfo().expiresAfterWindowEndTime());
+        CheckTimingInfoVisitor visitor = new CheckTimingInfoVisitor(TEST_END_MS, TEST_END_MS, true);
+        oneOffTask.getTimingInfo().accept(visitor);
     }
 
     @Test
@@ -94,10 +91,8 @@
     public void testOneOffNoParamsSet() {
         TaskInfo.TimingInfo timingInfo = TaskInfo.OneOffInfo.create().build();
         TaskInfo oneOffTask = TaskInfo.createTask(TaskIds.TEST, timingInfo).build();
-
-        assertFalse(oneOffTask.getOneOffInfo().hasWindowStartTimeConstraint());
-        assertEquals(0, oneOffTask.getOneOffInfo().getWindowEndTimeMs());
-        assertFalse(oneOffTask.getOneOffInfo().expiresAfterWindowEndTime());
+        CheckTimingInfoVisitor visitor = new CheckTimingInfoVisitor(null, new Long(0), false);
+        oneOffTask.getTimingInfo().accept(visitor);
     }
 
     @Test
@@ -108,14 +103,8 @@
                                                  .setExpiresAfterWindowEndTime(true)
                                                  .build();
         TaskInfo periodicTask = TaskInfo.createTask(TaskIds.TEST, timingInfo).build();
-
-        checkGeneralTaskInfoFields(periodicTask, TaskIds.TEST);
-
-        assertFalse(periodicTask.getPeriodicInfo().hasFlex());
-        assertEquals(TEST_END_MS, periodicTask.getPeriodicInfo().getIntervalMs());
-        assertTrue(periodicTask.getPeriodicInfo().expiresAfterWindowEndTime());
-
-        assertEquals(null, periodicTask.getOneOffInfo());
+        CheckTimingInfoVisitor visitor = new CheckTimingInfoVisitor(TEST_END_MS, null, true);
+        periodicTask.getTimingInfo().accept(visitor);
     }
 
     @Test
@@ -127,11 +116,9 @@
                                                  .setExpiresAfterWindowEndTime(true)
                                                  .build();
         TaskInfo periodicTask = TaskInfo.createTask(TaskIds.TEST, timingInfo).build();
-
-        assertTrue(periodicTask.getPeriodicInfo().hasFlex());
-        assertEquals(TEST_FLEX_MS, periodicTask.getPeriodicInfo().getFlexMs());
-        assertEquals(TEST_END_MS, periodicTask.getPeriodicInfo().getIntervalMs());
-        assertTrue(periodicTask.getPeriodicInfo().expiresAfterWindowEndTime());
+        CheckTimingInfoVisitor visitor =
+                new CheckTimingInfoVisitor(TEST_END_MS, TEST_FLEX_MS, true);
+        periodicTask.getTimingInfo().accept(visitor);
     }
 
     @Test
@@ -139,9 +126,60 @@
     public void testPeriodicNoParamsSet() {
         TaskInfo.TimingInfo timingInfo = TaskInfo.PeriodicInfo.create().build();
         TaskInfo periodicTask = TaskInfo.createTask(TaskIds.TEST, timingInfo).build();
+        CheckTimingInfoVisitor visitor = new CheckTimingInfoVisitor(new Long(0), null, false);
+        periodicTask.getTimingInfo().accept(visitor);
+    }
 
-        assertFalse(periodicTask.getPeriodicInfo().hasFlex());
-        assertEquals(0, periodicTask.getPeriodicInfo().getIntervalMs());
-        assertFalse(periodicTask.getPeriodicInfo().expiresAfterWindowEndTime());
+    @Test
+    @Feature({"BackgroundTaskScheduler"})
+    public void testExact() {
+        TaskInfo.TimingInfo timingInfo =
+                TaskInfo.ExactInfo.create().setTriggerAtMs(TEST_END_MS).build();
+        TaskInfo exactOneOffTask = TaskInfo.createTask(TaskIds.TEST, timingInfo).build();
+        CheckTimingInfoVisitor visitor = new CheckTimingInfoVisitor(TEST_END_MS, null, false);
+        exactOneOffTask.getTimingInfo().accept(visitor);
+    }
+
+    private class CheckTimingInfoVisitor implements TaskInfo.TimingInfoVisitor {
+        private final Long mStartOrIntervalOrTriggerMs;
+        private final Long mEndOrFlexMs;
+        private final boolean mExpires;
+
+        CheckTimingInfoVisitor(Long startOrIntervalOrTriggerMs, Long endOrFlexMs, boolean expires) {
+            mStartOrIntervalOrTriggerMs = startOrIntervalOrTriggerMs;
+            mEndOrFlexMs = endOrFlexMs;
+            mExpires = expires;
+        }
+
+        @Override
+        public void visit(TaskInfo.OneOffInfo oneOffInfo) {
+            if (mStartOrIntervalOrTriggerMs == null) {
+                assertFalse(oneOffInfo.hasWindowStartTimeConstraint());
+            } else {
+                assertTrue(oneOffInfo.hasWindowStartTimeConstraint());
+                assertEquals(
+                        mStartOrIntervalOrTriggerMs.longValue(), oneOffInfo.getWindowStartTimeMs());
+            }
+
+            assertEquals(mEndOrFlexMs.longValue(), oneOffInfo.getWindowEndTimeMs());
+            assertEquals(mExpires, oneOffInfo.expiresAfterWindowEndTime());
+        }
+
+        @Override
+        public void visit(TaskInfo.PeriodicInfo periodicInfo) {
+            assertEquals(mStartOrIntervalOrTriggerMs.longValue(), periodicInfo.getIntervalMs());
+
+            if (mEndOrFlexMs == null) {
+                assertFalse(periodicInfo.hasFlex());
+            } else {
+                assertTrue(periodicInfo.hasFlex());
+                assertEquals(mEndOrFlexMs.longValue(), periodicInfo.getFlexMs());
+            }
+        }
+
+        @Override
+        public void visit(TaskInfo.ExactInfo exactInfo) {
+            assertEquals(mStartOrIntervalOrTriggerMs.longValue(), exactInfo.getTriggerAtMs());
+        }
     }
 }
\ No newline at end of file
diff --git a/components/flags_ui/flags_state.cc b/components/flags_ui/flags_state.cc
index b1d4685..564df9e 100644
--- a/components/flags_ui/flags_state.cc
+++ b/components/flags_ui/flags_state.cc
@@ -34,9 +34,6 @@
 const char kTrialGroupAboutFlags[] = "AboutFlags";
 }  // namespace internal
 
-const base::Feature kUnexpireFlagsM78{"TemporaryUnexpireFlagsM78",
-                                      base::FEATURE_DISABLED_BY_DEFAULT};
-
 namespace {
 
 // Separator used for origin list values. The list of origins provided from
diff --git a/components/flags_ui/flags_state.h b/components/flags_ui/flags_state.h
index 324f76da5..068c53d7 100644
--- a/components/flags_ui/flags_state.h
+++ b/components/flags_ui/flags_state.h
@@ -46,8 +46,6 @@
   kEnterprise = 1 << 7,
 };
 
-extern const base::Feature kUnexpireFlagsM78;
-
 // A flag controlling the behavior of the |ConvertFlagsToSwitches| function -
 // whether it should add the sentinel switches around flags.
 enum SentinelsMode { kNoSentinels, kAddSentinels };
diff --git a/components/history/core/browser/thumbnail_database.cc b/components/history/core/browser/thumbnail_database.cc
index cfc3a9c..05d43e7 100644
--- a/components/history/core/browser/thumbnail_database.cc
+++ b/components/history/core/browser/thumbnail_database.cc
@@ -1047,6 +1047,7 @@
 
   if (!db->Open(db_name))
     return sql::INIT_FAILURE;
+  db->Preload();
 
   return sql::INIT_OK;
 }
diff --git a/components/media_message_center/media_notification_background.cc b/components/media_message_center/media_notification_background.cc
index 3d6f49f33..73fe210 100644
--- a/components/media_message_center/media_notification_background.cc
+++ b/components/media_message_center/media_notification_background.cc
@@ -233,16 +233,12 @@
 }  // namespace
 
 MediaNotificationBackground::MediaNotificationBackground(
-    views::View* owner,
     int top_radius,
     int bottom_radius,
     double artwork_max_width_pct)
-    : owner_(owner),
-      top_radius_(top_radius),
+    : top_radius_(top_radius),
       bottom_radius_(bottom_radius),
-      artwork_max_width_pct_(artwork_max_width_pct) {
-  DCHECK(owner);
-}
+      artwork_max_width_pct_(artwork_max_width_pct) {}
 
 MediaNotificationBackground::~MediaNotificationBackground() = default;
 
@@ -274,7 +270,7 @@
     // maintaining the aspect ratio.
     gfx::Rect source_bounds =
         gfx::Rect(0, 0, artwork_.width(), artwork_.height());
-    gfx::Rect artwork_bounds = GetArtworkBounds(bounds);
+    gfx::Rect artwork_bounds = GetArtworkBounds(*view);
 
     canvas->DrawImageInt(
         artwork_, source_bounds.x(), source_bounds.y(), source_bounds.width(),
@@ -286,11 +282,11 @@
   // notification. This may cover up some of the artwork.
   const SkColor background_color =
       background_color_.value_or(kMediaNotificationDefaultBackgroundColor);
-  canvas->FillRect(GetFilledBackgroundBounds(bounds), background_color);
+  canvas->FillRect(GetFilledBackgroundBounds(*view), background_color);
 
   {
     // Draw a gradient to fade the color background and the image together.
-    gfx::Rect draw_bounds = GetGradientBounds(bounds);
+    gfx::Rect draw_bounds = GetGradientBounds(*view);
 
     const SkColor colors[2] = {
         background_color, SkColorSetA(background_color, SK_AlphaTRANSPARENT)};
@@ -315,27 +311,25 @@
   background_color_ = GetNotificationBackgroundColor(artwork_.bitmap());
   foreground_color_ =
       GetNotificationForegroundColor(background_color_, artwork_.bitmap());
-  owner_->SchedulePaint();
 }
 
-void MediaNotificationBackground::UpdateCornerRadius(int top_radius,
+bool MediaNotificationBackground::UpdateCornerRadius(int top_radius,
                                                      int bottom_radius) {
   if (top_radius_ == top_radius && bottom_radius_ == bottom_radius)
-    return;
+    return false;
 
   top_radius_ = top_radius;
   bottom_radius_ = bottom_radius;
-
-  owner_->SchedulePaint();
+  return true;
 }
 
-void MediaNotificationBackground::UpdateArtworkMaxWidthPct(
+bool MediaNotificationBackground::UpdateArtworkMaxWidthPct(
     double max_width_pct) {
   if (artwork_max_width_pct_ == max_width_pct)
-    return;
+    return false;
 
   artwork_max_width_pct_ = max_width_pct;
-  owner_->SchedulePaint();
+  return true;
 }
 
 SkColor MediaNotificationBackground::GetBackgroundColor() const {
@@ -344,11 +338,12 @@
   return kMediaNotificationDefaultBackgroundColor;
 }
 
-SkColor MediaNotificationBackground::GetForegroundColor() const {
+SkColor MediaNotificationBackground::GetForegroundColor(
+    const views::View& owner) const {
   const SkColor foreground =
       foreground_color_.has_value()
           ? *foreground_color_
-          : views::style::GetColor(*owner_, views::style::CONTEXT_LABEL,
+          : views::style::GetColor(owner, views::style::CONTEXT_LABEL,
                                    views::style::STYLE_PRIMARY);
   return color_utils::BlendForMinContrast(foreground, GetBackgroundColor())
       .color;
@@ -373,31 +368,34 @@
 }
 
 gfx::Rect MediaNotificationBackground::GetArtworkBounds(
-    const gfx::Rect& view_bounds) const {
+    const views::View& owner) const {
+  const gfx::Rect& view_bounds = owner.GetContentsBounds();
   int width = GetArtworkWidth(view_bounds.size());
 
   // The artwork should be positioned on the far right hand side of the
   // notification and be the same height.
-  return owner_->GetMirroredRect(
+  return owner.GetMirroredRect(
       gfx::Rect(view_bounds.right() - width, 0, width, view_bounds.height()));
 }
 
 gfx::Rect MediaNotificationBackground::GetFilledBackgroundBounds(
-    const gfx::Rect& view_bounds) const {
+    const views::View& owner) const {
   // The filled background should take up the full notification except the area
   // taken up by the artwork.
+  const gfx::Rect& view_bounds = owner.GetContentsBounds();
   gfx::Rect bounds = gfx::Rect(view_bounds);
   bounds.Inset(0, 0, GetArtworkVisibleWidth(view_bounds.size()), 0);
-  return owner_->GetMirroredRect(bounds);
+  return owner.GetMirroredRect(bounds);
 }
 
 gfx::Rect MediaNotificationBackground::GetGradientBounds(
-    const gfx::Rect& view_bounds) const {
+    const views::View& owner) const {
   if (artwork_.isNull())
     return gfx::Rect(0, 0, 0, 0);
 
   // The gradient should appear above the artwork on the left.
-  return owner_->GetMirroredRect(gfx::Rect(
+  const gfx::Rect& view_bounds = owner.GetContentsBounds();
+  return owner.GetMirroredRect(gfx::Rect(
       view_bounds.width() - GetArtworkVisibleWidth(view_bounds.size()),
       view_bounds.y(), kMediaImageGradientWidth, view_bounds.height()));
 }
diff --git a/components/media_message_center/media_notification_background.h b/components/media_message_center/media_notification_background.h
index 8953a20..357e8bd8 100644
--- a/components/media_message_center/media_notification_background.h
+++ b/components/media_message_center/media_notification_background.h
@@ -29,8 +29,7 @@
 class COMPONENT_EXPORT(MEDIA_MESSAGE_CENTER) MediaNotificationBackground
     : public views::Background {
  public:
-  MediaNotificationBackground(views::View* owner,
-                              int top_radius,
+  MediaNotificationBackground(int top_radius,
                               int bottom_radius,
                               double artwork_max_width_pct);
   ~MediaNotificationBackground() override;
@@ -38,12 +37,12 @@
   // views::Background
   void Paint(gfx::Canvas* canvas, views::View* view) const override;
 
-  void UpdateCornerRadius(int top_radius, int bottom_radius);
   void UpdateArtwork(const gfx::ImageSkia& image);
-  void UpdateArtworkMaxWidthPct(double max_width_pct);
+  bool UpdateCornerRadius(int top_radius, int bottom_radius);
+  bool UpdateArtworkMaxWidthPct(double max_width_pct);
 
   SkColor GetBackgroundColor() const;
-  SkColor GetForegroundColor() const;
+  SkColor GetForegroundColor(const views::View& owner) const;
 
  private:
   friend class MediaNotificationBackgroundTest;
@@ -53,15 +52,12 @@
 
   int GetArtworkWidth(const gfx::Size& view_size) const;
   int GetArtworkVisibleWidth(const gfx::Size& view_size) const;
-  gfx::Rect GetArtworkBounds(const gfx::Rect& view_bounds) const;
-  gfx::Rect GetFilledBackgroundBounds(const gfx::Rect& view_bounds) const;
-  gfx::Rect GetGradientBounds(const gfx::Rect& view_bounds) const;
+  gfx::Rect GetArtworkBounds(const views::View& owner) const;
+  gfx::Rect GetFilledBackgroundBounds(const views::View& owner) const;
+  gfx::Rect GetGradientBounds(const views::View& owner) const;
   SkPoint GetGradientStartPoint(const gfx::Rect& draw_bounds) const;
   SkPoint GetGradientEndPoint(const gfx::Rect& draw_bounds) const;
 
-  // Reference to the owning view that this is a background for.
-  views::View* owner_;
-
   int top_radius_;
   int bottom_radius_;
 
diff --git a/components/media_message_center/media_notification_background_unittest.cc b/components/media_message_center/media_notification_background_unittest.cc
index 4b58881..f73819f 100644
--- a/components/media_message_center/media_notification_background_unittest.cc
+++ b/components/media_message_center/media_notification_background_unittest.cc
@@ -73,16 +73,13 @@
   ~MediaNotificationBackgroundTest() override = default;
 
   void SetUp() override {
-    owner_ = std::make_unique<views::StaticSizedView>();
-    background_ = std::make_unique<MediaNotificationBackground>(owner_.get(),
-                                                                10, 10, 0.1);
+    background_ = std::make_unique<MediaNotificationBackground>(10, 10, 0.1);
 
     EXPECT_FALSE(GetBackgroundColor().has_value());
   }
 
   void TearDown() override {
     background_.reset();
-    owner_.reset();
   }
 
   MediaNotificationBackground* background() const { return background_.get(); }
@@ -96,7 +93,6 @@
   }
 
  private:
-  std::unique_ptr<views::StaticSizedView> owner_;
   std::unique_ptr<MediaNotificationBackground> background_;
 
   DISALLOW_COPY_AND_ASSIGN(MediaNotificationBackgroundTest);
@@ -322,6 +318,8 @@
                                                 : switches::kForceDirectionLTR);
 
     MediaNotificationBackgroundTest::SetUp();
+
+    ASSERT_EQ(IsRTL(), base::i18n::IsRTL());
   }
 
   bool IsRTL() const { return GetParam(); }
@@ -336,15 +334,19 @@
 TEST_P(MediaNotificationBackgroundRTLTest, BoundsSanityCheck) {
   // The test notification will have a width of 200 and a height of 50.
   gfx::Rect bounds(0, 0, 200, 50);
+  auto owner = std::make_unique<views::StaticSizedView>();
+  owner->SetBoundsRect(bounds);
+  ASSERT_EQ(bounds, owner->GetContentsBounds());
 
   // Check the artwork is not visible by default.
   EXPECT_EQ(0, background()->GetArtworkWidth(bounds.size()));
   EXPECT_EQ(0, background()->GetArtworkVisibleWidth(bounds.size()));
-  EXPECT_EQ(gfx::Rect(IsRTL() ? -200 : 200, 0, 0, 50),
-            background()->GetArtworkBounds(bounds));
-  EXPECT_EQ(gfx::Rect(IsRTL() ? -200 : 0, 0, 200, 50),
-            background()->GetFilledBackgroundBounds(bounds));
-  EXPECT_EQ(gfx::Rect(0, 0, 0, 0), background()->GetGradientBounds(bounds));
+  EXPECT_EQ(gfx::Rect(IsRTL() ? 0 : 200, 0, 0, 50),
+            background()->GetArtworkBounds(*owner.get()));
+  EXPECT_EQ(gfx::Rect(IsRTL() ? 0 : 0, 0, 200, 50),
+            background()->GetFilledBackgroundBounds(*owner.get()));
+  EXPECT_EQ(gfx::Rect(0, 0, 0, 0),
+            background()->GetGradientBounds(*owner.get()));
 
   // The background artwork image will have an aspect ratio of 2:1.
   SkBitmap bitmap;
@@ -362,22 +364,22 @@
   EXPECT_EQ(100, background()->GetArtworkVisibleWidth(bounds.size()));
 
   // Check the artwork is positioned to the right.
-  EXPECT_EQ(gfx::Rect(IsRTL() ? -200 : 100, 0, 100, 50),
-            background()->GetArtworkBounds(bounds));
+  EXPECT_EQ(gfx::Rect(IsRTL() ? 0 : 100, 0, 100, 50),
+            background()->GetArtworkBounds(*owner.get()));
 
   // Check the filled background is to the left of the image.
-  EXPECT_EQ(gfx::Rect(IsRTL() ? -100 : 0, 0, 100, 50),
-            background()->GetFilledBackgroundBounds(bounds));
+  EXPECT_EQ(gfx::Rect(IsRTL() ? 100 : 0, 0, 100, 50),
+            background()->GetFilledBackgroundBounds(*owner.get()));
 
   // Check the gradient is positioned above the artwork.
-  const gfx::Rect gradient_bounds = background()->GetGradientBounds(bounds);
-  EXPECT_EQ(gfx::Rect(IsRTL() ? -140 : 100, 0, 40, 50), gradient_bounds);
+  const gfx::Rect gradient_bounds =
+      background()->GetGradientBounds(*owner.get());
+  EXPECT_EQ(gfx::Rect(IsRTL() ? 60 : 100, 0, 40, 50), gradient_bounds);
 
   // Check the gradient point X-values are the start and end of
   // |gradient_bounds|.
-  EXPECT_EQ(IsRTL() ? -100 : 100,
-            background()->GetGradientStartPoint(gradient_bounds).x());
-  EXPECT_EQ(IsRTL() ? -140 : 140,
+  EXPECT_EQ(100, background()->GetGradientStartPoint(gradient_bounds).x());
+  EXPECT_EQ(IsRTL() ? 60 : 140,
             background()->GetGradientEndPoint(gradient_bounds).x());
 
   // Check both of the gradient point Y-values are half the height.
diff --git a/components/media_message_center/media_notification_view.cc b/components/media_message_center/media_notification_view.cc
index c645937..dbf1d5f 100644
--- a/components/media_message_center/media_notification_view.cc
+++ b/components/media_message_center/media_notification_view.cc
@@ -203,7 +203,7 @@
           IDS_MEDIA_MESSAGE_CENTER_MEDIA_NOTIFICATION_ACTION_NEXT_TRACK));
 
   SetBackground(std::make_unique<MediaNotificationBackground>(
-      this, message_center::kNotificationCornerRadius,
+      message_center::kNotificationCornerRadius,
       message_center::kNotificationCornerRadius, kMediaImageMaxWidthPct));
 
   UpdateForegroundColor();
@@ -235,8 +235,10 @@
 
 void MediaNotificationView::UpdateCornerRadius(int top_radius,
                                                int bottom_radius) {
-  GetMediaNotificationBackground()->UpdateCornerRadius(top_radius,
-                                                       bottom_radius);
+  if (GetMediaNotificationBackground()->UpdateCornerRadius(top_radius,
+                                                           bottom_radius)) {
+    SchedulePaint();
+  }
 }
 
 void MediaNotificationView::GetAccessibleNodeData(ui::AXNodeData* node_data) {
@@ -394,8 +396,10 @@
 
   main_row_->Layout();
 
-  GetMediaNotificationBackground()->UpdateArtworkMaxWidthPct(
-      expanded ? kMediaImageMaxWidthExpandedPct : kMediaImageMaxWidthPct);
+  if (GetMediaNotificationBackground()->UpdateArtworkMaxWidthPct(
+          expanded ? kMediaImageMaxWidthExpandedPct : kMediaImageMaxWidthPct)) {
+    SchedulePaint();
+  }
 
   header_row_->SetExpanded(expanded);
 
@@ -439,7 +443,7 @@
   const SkColor background =
       GetMediaNotificationBackground()->GetBackgroundColor();
   const SkColor foreground =
-      GetMediaNotificationBackground()->GetForegroundColor();
+      GetMediaNotificationBackground()->GetForegroundColor(*this);
 
   title_label_->SetEnabledColor(foreground);
   artist_label_->SetEnabledColor(foreground);
diff --git a/components/password_manager/core/browser/leak_detection/authenticated_leak_check_unittest.cc b/components/password_manager/core/browser/leak_detection/authenticated_leak_check_unittest.cc
index 139c87d3..c23a406 100644
--- a/components/password_manager/core/browser/leak_detection/authenticated_leak_check_unittest.cc
+++ b/components/password_manager/core/browser/leak_detection/authenticated_leak_check_unittest.cc
@@ -31,7 +31,7 @@
 using ::testing::StrictMock;
 
 constexpr char kTestEmail[] = "user@gmail.com";
-constexpr char kUsername[] = "username";
+constexpr char kUsername[] = "USERNAME@gmail.com";
 constexpr char kPassword[] = "password123";
 constexpr char kExampleCom[] = "https://example.com";
 
@@ -333,13 +333,20 @@
   PayloadAndCallback payload_and_callback = ImitateNetworkRequest();
   ASSERT_TRUE(!payload_and_callback.payload.empty());
 
+  // |canonicalized_username| is passed to ScryptHashUsernameAndPassword() to
+  // make sure the canonicalization logic works correctly. Assert that
+  // CanonicalizeUsername() was not a no-op.
+  std::string canonicalized_username = CanonicalizeUsername(kUsername);
+  ASSERT_NE(kUsername, canonicalized_username);
+
   auto response = std::make_unique<SingleLookupResponse>();
   std::string key_server;
   response->reencrypted_lookup_hash =
       CipherReEncrypt(payload_and_callback.payload, &key_server);
   response->encrypted_leak_match_prefixes.push_back(
       crypto::SHA256HashString(CipherEncryptWithKey(
-          ScryptHashUsernameAndPassword(kUsername, kPassword), key_server)));
+          ScryptHashUsernameAndPassword(canonicalized_username, kPassword),
+          key_server)));
 
   EXPECT_CALL(delegate(), OnLeakDetectionDone(true, GURL(kExampleCom),
                                               base::ASCIIToUTF16(kUsername),
diff --git a/components/password_manager/core/browser/leak_detection/encryption_utils.cc b/components/password_manager/core/browser/leak_detection/encryption_utils.cc
index 0ba2198..36da42d 100644
--- a/components/password_manager/core/browser/leak_detection/encryption_utils.cc
+++ b/components/password_manager/core/browser/leak_detection/encryption_utils.cc
@@ -35,6 +35,10 @@
       120, 112,  44,  114,  24, 86,  84,  -103, -77, -23, 33,
       24,  108,  33,  26,   1,  34,  60,  69,   74,  -6};
 
+  // Check that |canonicalized_username| is actually canonicalized.
+  // Note: We can't use CanonicalizeUsername() again, since it's not idempotent
+  // if multiple '@' signs are present in the initial username.
+  DCHECK_EQ(base::ToLowerASCII(canonicalized_username), canonicalized_username);
   return crypto::SHA256HashString(base::StrCat(
       {canonicalized_username,
        base::StringPiece(kUsernameSalt, base::size(kUsernameSalt))}));
@@ -44,13 +48,19 @@
   static_assert(
       kUsernameHashPrefixLength % CHAR_BIT == 0,
       "The prefix length must be a multiple of the number of bits in a char.");
+
+  // Check that |canonicalized_username| is actually canonicalized.
+  // Note: We can't use CanonicalizeUsername() again, since it's not idempotent
+  // if multiple '@' signs are present in the initial username.
+  DCHECK_EQ(base::ToLowerASCII(canonicalized_username), canonicalized_username);
   return HashUsername(canonicalized_username)
       .substr(0, kUsernameHashPrefixLength / CHAR_BIT);
 }
 
-std::string ScryptHashUsernameAndPassword(base::StringPiece username,
-                                          base::StringPiece password) {
-  // Constant salt added to the password hash on top of username.
+std::string ScryptHashUsernameAndPassword(
+    base::StringPiece canonicalized_username,
+    base::StringPiece password) {
+  // Constant salt added to the password hash on top of canonicalized_username.
   // Needs to stay in sync with server side constant: go/passwords-leak-salts
   static constexpr char kPasswordHashSalt[] = {
       48,   118, 42,  -46,  63,  123, -95, -101, -8,  -29, 66,
@@ -62,10 +72,15 @@
   static constexpr uint64_t kScryptParallelization = 1;
   static constexpr size_t kScryptMaxMemory = 1024 * 1024 * 32;
 
+  // Check that |canonicalized_username| is actually canonicalized.
+  // Note: We can't use CanonicalizeUsername() again, since it's not idempotent
+  // if multiple '@' signs are present in the initial username.
+  DCHECK_EQ(base::ToLowerASCII(canonicalized_username), canonicalized_username);
   crypto::OpenSSLErrStackTracer err_tracer(FROM_HERE);
-  std::string username_password = base::StrCat({username, password});
+  std::string username_password =
+      base::StrCat({canonicalized_username, password});
   std::string salt = base::StrCat(
-      {username,
+      {canonicalized_username,
        base::StringPiece(kPasswordHashSalt, base::size(kPasswordHashSalt))});
 
   std::string result;
diff --git a/components/password_manager/core/browser/leak_detection/encryption_utils.h b/components/password_manager/core/browser/leak_detection/encryption_utils.h
index fe7d90d..ec6a3bce 100644
--- a/components/password_manager/core/browser/leak_detection/encryption_utils.h
+++ b/components/password_manager/core/browser/leak_detection/encryption_utils.h
@@ -28,9 +28,10 @@
 std::string BucketizeUsername(base::StringPiece canonicalized_username);
 
 // Produces the username/password pair hash using scrypt algorithm.
-// |username| and |password| are UTF-8 strings.
-std::string ScryptHashUsernameAndPassword(base::StringPiece username,
-                                          base::StringPiece password);
+// |canonicalized_username| and |password| are UTF-8 strings.
+std::string ScryptHashUsernameAndPassword(
+    base::StringPiece canonicalized_username,
+    base::StringPiece password);
 
 // Encrypt/decrypt routines.
 
diff --git a/components/password_manager/core/browser/leak_detection/leak_detection_request_utils.cc b/components/password_manager/core/browser/leak_detection/leak_detection_request_utils.cc
index 279be21..9d61252 100644
--- a/components/password_manager/core/browser/leak_detection/leak_detection_request_utils.cc
+++ b/components/password_manager/core/browser/leak_detection/leak_detection_request_utils.cc
@@ -22,10 +22,12 @@
 // asynchronously.
 LookupSingleLeakData PrepareLookupSingleLeakData(const std::string& username,
                                                  const std::string& password) {
+  std::string canonicalized_username = CanonicalizeUsername(username);
   LookupSingleLeakData data;
-  data.username_hash_prefix = BucketizeUsername(CanonicalizeUsername(username));
+  data.username_hash_prefix = BucketizeUsername(canonicalized_username);
   data.encrypted_payload = CipherEncrypt(
-      ScryptHashUsernameAndPassword(username, password), &data.encryption_key);
+      ScryptHashUsernameAndPassword(canonicalized_username, password),
+      &data.encryption_key);
   return data;
 }
 
diff --git a/components/password_manager/core/browser/sync_credentials_filter_unittest.cc b/components/password_manager/core/browser/sync_credentials_filter_unittest.cc
index 04bf66b0..dc57f9b6 100644
--- a/components/password_manager/core/browser/sync_credentials_filter_unittest.cc
+++ b/components/password_manager/core/browser/sync_credentials_filter_unittest.cc
@@ -19,7 +19,7 @@
 #include "components/autofill/core/common/password_form.h"
 #include "components/password_manager/core/browser/fake_form_fetcher.h"
 #include "components/password_manager/core/browser/mock_password_store.h"
-#include "components/password_manager/core/browser/password_manager.h"
+#include "components/password_manager/core/browser/new_password_form_manager.h"
 #include "components/password_manager/core/browser/password_manager_test_utils.h"
 #include "components/password_manager/core/browser/stub_form_saver.h"
 #include "components/password_manager/core/browser/stub_password_manager_client.h"
@@ -111,18 +111,16 @@
 
   CredentialsFilterTest()
       : client_(identity_manager()),
-        password_manager_(&client_),
         pending_(SimpleGaiaForm("user@gmail.com")),
-        form_manager_(&password_manager_,
-                      &client_,
+        form_manager_(&client_,
                       driver_.AsWeakPtr(),
-                      pending_,
+                      pending_.form_data,
+                      &fetcher_,
                       std::make_unique<StubFormSaver>(),
-                      &fetcher_),
+                      nullptr /* metrics_recorder */),
         filter_(&client_,
                 base::BindRepeating(&SyncUsernameTestBase::sync_service,
                                     base::Unretained(this))) {
-    form_manager_.Init(nullptr);
     fetcher_.Fetch();
   }
 
@@ -137,16 +135,15 @@
     fetcher_.SetNonFederated(matches);
     fetcher_.NotifyFetchCompleted();
 
-    form_manager_.ProvisionallySave(pending_);
+    form_manager_.ProvisionallySave(pending_.form_data, &driver_);
   }
 
  protected:
   FakePasswordManagerClient client_;
-  PasswordManager password_manager_;
   StubPasswordManagerDriver driver_;
   PasswordForm pending_;
   FakeFormFetcher fetcher_;
-  PasswordFormManager form_manager_;
+  NewPasswordFormManager form_manager_;
 
   SyncCredentialsFilter filter_;
 };
diff --git a/components/password_manager/core/browser/sync_username_test_base.cc b/components/password_manager/core/browser/sync_username_test_base.cc
index bf541ac..d23c5daf 100644
--- a/components/password_manager/core/browser/sync_username_test_base.cc
+++ b/components/password_manager/core/browser/sync_username_test_base.cc
@@ -5,11 +5,35 @@
 #include "components/password_manager/core/browser/sync_username_test_base.h"
 
 #include "base/strings/utf_string_conversions.h"
+#include "components/autofill/core/common/form_data.h"
 
+using autofill::FormData;
+using autofill::FormFieldData;
 using autofill::PasswordForm;
+using base::ASCIIToUTF16;
 
 namespace password_manager {
 
+namespace {
+
+FormData CreateSigninFormData(const GURL& url, const char* username) {
+  FormData form;
+  form.url = url;
+  FormFieldData field;
+  field.name = ASCIIToUTF16("username_element");
+  field.form_control_type = "text";
+  field.value = ASCIIToUTF16(username);
+  form.fields.push_back(field);
+
+  field.name = ASCIIToUTF16("password_element");
+  field.form_control_type = "password";
+  field.value = ASCIIToUTF16("strong_pw");
+  form.fields.push_back(field);
+  return form;
+}
+
+}  // namespace
+
 SyncUsernameTestBase::SyncUsernameTestBase() = default;
 
 SyncUsernameTestBase::~SyncUsernameTestBase() = default;
@@ -32,7 +56,8 @@
 PasswordForm SyncUsernameTestBase::SimpleGaiaForm(const char* username) {
   PasswordForm form;
   form.signon_realm = "https://accounts.google.com";
-  form.username_value = base::ASCIIToUTF16(username);
+  form.username_value = ASCIIToUTF16(username);
+  form.form_data = CreateSigninFormData(GURL(form.signon_realm), username);
   return form;
 }
 
@@ -40,7 +65,8 @@
 PasswordForm SyncUsernameTestBase::SimpleNonGaiaForm(const char* username) {
   PasswordForm form;
   form.signon_realm = "https://site.com";
-  form.username_value = base::ASCIIToUTF16(username);
+  form.username_value = ASCIIToUTF16(username);
+  form.form_data = CreateSigninFormData(GURL(form.signon_realm), username);
   return form;
 }
 
@@ -49,8 +75,9 @@
                                                      const char* origin) {
   PasswordForm form;
   form.signon_realm = "https://site.com";
-  form.username_value = base::ASCIIToUTF16(username);
+  form.username_value = ASCIIToUTF16(username);
   form.origin = GURL(origin);
+  form.form_data = CreateSigninFormData(GURL(form.signon_realm), username);
   return form;
 }
 
diff --git a/components/sessions/content/content_serialized_navigation_builder.cc b/components/sessions/content/content_serialized_navigation_builder.cc
index 4bd035d..54e9345 100644
--- a/components/sessions/content/content_serialized_navigation_builder.cc
+++ b/components/sessions/content/content_serialized_navigation_builder.cc
@@ -4,6 +4,8 @@
 
 #include "components/sessions/content/content_serialized_navigation_builder.h"
 
+#include <string>
+
 #include "base/logging.h"
 #include "components/sessions/content/content_record_password_state.h"
 #include "components/sessions/content/content_serialized_navigation_driver.h"
@@ -88,19 +90,15 @@
 ContentSerializedNavigationBuilder::ToNavigationEntry(
     const SerializedNavigationEntry* navigation,
     content::BrowserContext* browser_context) {
-  // TODO(lukasza): https://crbug.com/976055: |initiator_origin| should be
-  // persisted across session restore.
-  base::Optional<url::Origin> initiator_origin = base::nullopt;
+  // The initial values of the NavigationEntry are only temporary - they
+  // will get cloberred by one of the SetPageState calls below.
+  GURL temporary_url;
+  content::Referrer temporary_referrer;
+  base::Optional<url::Origin> temporary_initiator_origin = base::nullopt;
 
-  network::mojom::ReferrerPolicy policy =
-      static_cast<network::mojom::ReferrerPolicy>(navigation->referrer_policy_);
   std::unique_ptr<content::NavigationEntry> entry(
       content::NavigationController::CreateNavigationEntry(
-          navigation->virtual_url_,
-          content::Referrer::SanitizeForRequest(
-              navigation->virtual_url_,
-              content::Referrer(navigation->referrer_url_, policy)),
-          initiator_origin,
+          temporary_url, temporary_referrer, temporary_initiator_origin,
           // Use a transition type of reload so that we don't incorrectly
           // increase the typed count.
           ui::PAGE_TRANSITION_RELOAD, false,
@@ -109,8 +107,20 @@
           nullptr /* blob_url_loader_factory */));
 
   entry->SetTitle(navigation->title_);
-  entry->SetPageState(content::PageState::CreateFromEncodedData(
-      navigation->encoded_page_state_));
+  if (navigation->encoded_page_state_.empty()) {
+    // Conjure a new PageState, based on the URL.
+    //
+    // One case where the PageState may be empty is WebUI pages - see
+    // ChromeSerializedNavigationDriver::Sanitize.  Another case is tests for
+    // "foreign" session restore entries, such as
+    // SessionRestoreTest.RestoreForeignTab.
+    entry->SetPageState(
+        content::PageState::CreateFromURL(navigation->virtual_url_));
+  } else {
+    // Restore PageState.
+    entry->SetPageState(content::PageState::CreateFromEncodedData(
+        navigation->encoded_page_state_));
+  }
   entry->SetHasPostData(navigation->has_post_data_);
   entry->SetPostID(navigation->post_id_);
   entry->SetOriginalRequestURL(navigation->original_request_url_);
@@ -118,6 +128,7 @@
   entry->SetTimestamp(navigation->timestamp_);
   entry->SetHttpStatusCode(navigation->http_status_code_);
   entry->SetRedirectChain(navigation->redirect_chain_);
+  entry->SetVirtualURL(navigation->virtual_url_);
   sessions::NavigationTaskId* navigation_task_id =
       sessions::NavigationTaskId::Get(entry.get());
   navigation_task_id->set_id(navigation->task_id());
diff --git a/components/sessions/content/content_serialized_navigation_builder_unittest.cc b/components/sessions/content/content_serialized_navigation_builder_unittest.cc
index d7832d1..d293f061 100644
--- a/components/sessions/content/content_serialized_navigation_builder_unittest.cc
+++ b/components/sessions/content/content_serialized_navigation_builder_unittest.cc
@@ -4,6 +4,10 @@
 
 #include "components/sessions/content/content_serialized_navigation_builder.h"
 
+#include <memory>
+#include <string>
+#include <vector>
+
 #include "base/memory/ptr_util.h"
 #include "base/strings/utf_string_conversions.h"
 #include "components/sessions/content/content_record_password_state.h"
@@ -64,10 +68,9 @@
   navigation_entry->SetReferrer(content::Referrer(
       test_data::kReferrerURL,
       static_cast<network::mojom::ReferrerPolicy>(test_data::kReferrerPolicy)));
+  navigation_entry->SetURL(test_data::kURL);
   navigation_entry->SetVirtualURL(test_data::kVirtualURL);
   navigation_entry->SetTitle(test_data::kTitle);
-  navigation_entry->SetPageState(
-      content::PageState::CreateFromEncodedData(test_data::kEncodedPageState));
   navigation_entry->SetTransitionType(test_data::kTransitionType);
   navigation_entry->SetHasPostData(test_data::kHasPostData);
   navigation_entry->SetPostID(test_data::kPostID);
@@ -147,7 +150,8 @@
   EXPECT_EQ(test_data::kReferrerPolicy, navigation.referrer_policy());
   EXPECT_EQ(test_data::kVirtualURL, navigation.virtual_url());
   EXPECT_EQ(test_data::kTitle, navigation.title());
-  EXPECT_EQ(test_data::kEncodedPageState, navigation.encoded_page_state());
+  EXPECT_EQ(navigation_entry->GetPageState().ToEncodedData(),
+            navigation.encoded_page_state());
   EXPECT_TRUE(ui::PageTransitionTypeIncludingQualifiersIs(
       navigation.transition_type(), test_data::kTransitionType));
   EXPECT_EQ(test_data::kHasPostData, navigation.has_post_data());
@@ -188,7 +192,7 @@
       ContentSerializedNavigationBuilder::FromNavigationEntry(
           test_data::kIndex, navigation_entry.get(),
           ContentSerializedNavigationBuilder::DEFAULT);
-  EXPECT_EQ(test_data::kEncodedPageState,
+  EXPECT_EQ(navigation_entry->GetPageState().ToEncodedData(),
             default_navigation.encoded_page_state());
 
   const SerializedNavigationEntry& excluded_page_state_navigation =
@@ -218,9 +222,10 @@
   EXPECT_EQ(test_data::kReferrerURL, new_navigation_entry->GetReferrer().url);
   EXPECT_EQ(test_data::kReferrerPolicy,
             static_cast<int>(new_navigation_entry->GetReferrer().policy));
+  EXPECT_EQ(test_data::kURL, new_navigation_entry->GetURL());
   EXPECT_EQ(test_data::kVirtualURL, new_navigation_entry->GetVirtualURL());
   EXPECT_EQ(test_data::kTitle, new_navigation_entry->GetTitle());
-  EXPECT_EQ(test_data::kEncodedPageState,
+  EXPECT_EQ(old_navigation_entry->GetPageState().ToEncodedData(),
             new_navigation_entry->GetPageState().ToEncodedData());
   EXPECT_TRUE(ui::PageTransitionTypeIncludingQualifiersIs(
       new_navigation_entry->GetTransitionType(), ui::PAGE_TRANSITION_RELOAD));
diff --git a/components/sessions/core/serialized_navigation_entry_test_helper.cc b/components/sessions/core/serialized_navigation_entry_test_helper.cc
index f5f08bc..8bb74fde 100644
--- a/components/sessions/core/serialized_navigation_entry_test_helper.cc
+++ b/components/sessions/core/serialized_navigation_entry_test_helper.cc
@@ -18,7 +18,8 @@
 const int kUniqueID = 50;
 const GURL kReferrerURL = GURL("http://www.referrer.com");
 const int kReferrerPolicy = 0;
-const GURL kVirtualURL= GURL("http://www.virtual-url.com");
+const GURL kURL = GURL("http://www.url.com");
+const GURL kVirtualURL = GURL("http://www.virtual-url.com");
 const base::string16 kTitle = base::ASCIIToUTF16("title");
 const std::string kEncodedPageState = "page state";
 const ui::PageTransition kTransitionType =
diff --git a/components/sessions/core/serialized_navigation_entry_test_helper.h b/components/sessions/core/serialized_navigation_entry_test_helper.h
index 606b235..9e8af07 100644
--- a/components/sessions/core/serialized_navigation_entry_test_helper.h
+++ b/components/sessions/core/serialized_navigation_entry_test_helper.h
@@ -2,12 +2,13 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef COMPONENTS_SESSIONS_SESSION_TYPES_TEST_HELPER_H_
-#define COMPONENTS_SESSIONS_SESSION_TYPES_TEST_HELPER_H_
+#ifndef COMPONENTS_SESSIONS_CORE_SERIALIZED_NAVIGATION_ENTRY_TEST_HELPER_H_
+#define COMPONENTS_SESSIONS_CORE_SERIALIZED_NAVIGATION_ENTRY_TEST_HELPER_H_
 
 #include <stdint.h>
 
 #include <string>
+#include <vector>
 
 #include "base/macros.h"
 #include "base/strings/string16.h"
@@ -28,6 +29,7 @@
 extern const int kUniqueID;
 extern const GURL kReferrerURL;
 extern const int kReferrerPolicy;
+extern const GURL kURL;
 extern const GURL kVirtualURL;
 extern const base::string16 kTitle;
 extern const std::string kEncodedPageState;
@@ -63,6 +65,11 @@
                                      const SerializedNavigationEntry& actual);
 
   // Creates a SerializedNavigationEntry using the |test_data| constants above.
+  //
+  // Note that the returned SerializedNavigationEntry will have a bogus
+  // PageState and therefore can only be used in limited unit tests (e.g. it
+  // will most likely hit DCHECKs/NOTREACHEDs when passed to the //content
+  // layer).
   static SerializedNavigationEntry CreateNavigationForTest();
 
   static void SetReferrerPolicy(int policy,
@@ -97,6 +104,6 @@
   DISALLOW_IMPLICIT_CONSTRUCTORS(SerializedNavigationEntryTestHelper);
 };
 
-}  // sessions
+}  // namespace sessions
 
-#endif  // COMPONENTS_SESSIONS_SESSION_TYPES_TEST_HELPER_H_
+#endif  // COMPONENTS_SESSIONS_CORE_SERIALIZED_NAVIGATION_ENTRY_TEST_HELPER_H_
diff --git a/components/subresource_filter/FILTER_LIST_GENERATION.md b/components/subresource_filter/FILTER_LIST_GENERATION.md
index 7b7efa4..1d524cd 100644
--- a/components/subresource_filter/FILTER_LIST_GENERATION.md
+++ b/components/subresource_filter/FILTER_LIST_GENERATION.md
@@ -65,12 +65,7 @@
 files. Select gzip compression and use `<your_bucket>/site_urls.*.json.gz` as
 your destination.
 
-Once exported, you can download the files from your bucket and extract them
-into a single file for processing:
-
-```sh
-ls site_urls.*.gz | xargs gunzip -c > site_urls
-```
+Once exported, you can download the files from your bucket.
 
 ## 2. Acquire a filter list in the indexed format
 Chromium's tools are designed to work with a binary indexed version of filter
@@ -89,7 +84,7 @@
 ## 3. Generate the smaller filter list
 ```sh
 1. ninja -C out/Release subresource_filter_tools
-2. out/Release/subresource_filter_tool --ruleset=easylist_indexed match_rules --input_file=site_urls > ordered_list.txt
+2. cat site_urls.*.json.gz | gunzip - | out/Release/subresource_filter_tool --ruleset=easylist_indexed match_rules > ordered_list.txt
 3. head -n 1000 ordered_list.txt | cut -d' ' -f2 > smaller_list.txt
 ```
 
diff --git a/components/subresource_filter/tools/filter_tool_main.cc b/components/subresource_filter/tools/filter_tool_main.cc
index 708e7475..50013aea 100644
--- a/components/subresource_filter/tools/filter_tool_main.cc
+++ b/components/subresource_filter/tools/filter_tool_main.cc
@@ -46,20 +46,20 @@
         For a given request if a whitelist rule matches as well as a blacklist
         rule, the whitelist rule is printed but not the blacklist rule.
 
-    * match_batch --input_file=<json_file_path>
-        Like match, except it does the same for each request in a json file.
-        The file format is one json expression per line. An example line
-        follows (note: in the file it wouldn't have a line break like this
-        comment does):
+    * match_batch [--input_file=<json_file_path>]
+        Like match, except it does the same for each request in stdin. A json
+        file path may be provided to use in place of stdin. The input format
+        is one json expression per line. An example line follows (note: in
+        the file/input stream it wouldn't have a line break like this comment
+        does):
 
         {"origin":"http://www.example.com/","request_url":"http://www.exam
         ple.com/foo.js","request_type":"script"}
 
-    * match_rules --input_file=<json_file_path> --min_matches=<optional>
-        For each record in the given whitespace delimited file (see
-        match_batch for input file format), records the matching rule (see
-        match command above) and prints all of the matched rules and the
-        number of times they matched at the end.
+    * match_rules [--input_file=<json_file_path>] [--min_matches=<optional>]
+        For each record in the input (see match_batch for input formats),
+        records the matching rule (see match command above) and prints all of
+        the matched rules and the number of times they matched at the end.
 
         Which rules get recorded:
         If only a blacklist rule(s) matches, a blacklist rule is
@@ -156,18 +156,18 @@
     return 1;
   }
 
-  if (!command_line.HasSwitch(kSwitchInputFile)) {
-    PrintHelp();
-    return 1;
+  std::ifstream requests_stream;
+  std::istream* input_stream = &std::cin;
+  if (command_line.HasSwitch(kSwitchInputFile)) {
+    requests_stream =
+        std::ifstream(command_line.GetSwitchValueASCII(kSwitchInputFile));
+    input_stream = &requests_stream;
   }
 
-  std::ifstream requests_stream(
-      command_line.GetSwitchValueASCII(kSwitchInputFile));
-
   if (cmd == kMatchBatchCommand) {
-    filter_tool.MatchBatch(&requests_stream);
+    filter_tool.MatchBatch(input_stream);
   } else if (cmd == kMatchRulesCommand) {
-    filter_tool.MatchRules(&requests_stream, min_match_count);
+    filter_tool.MatchRules(input_stream, min_match_count);
   }
 
   return 0;
diff --git a/content/browser/accessibility/browser_accessibility.cc b/content/browser/accessibility/browser_accessibility.cc
index 532706b..4b99f426 100644
--- a/content/browser/accessibility/browser_accessibility.cc
+++ b/content/browser/accessibility/browser_accessibility.cc
@@ -1851,6 +1851,9 @@
   const ui::AXNodeData& data = GetData();
 
   switch (data.role) {
+    case ax::mojom::Role::kArticle:
+      return content_client->GetLocalizedString(IDS_AX_ROLE_ARTICLE);
+
     case ax::mojom::Role::kAudio:
       return content_client->GetLocalizedString(IDS_AX_ROLE_AUDIO);
 
@@ -1877,6 +1880,9 @@
     case ax::mojom::Role::kDetails:
       return content_client->GetLocalizedString(IDS_AX_ROLE_DETAILS);
 
+    case ax::mojom::Role::kFigure:
+      return content_client->GetLocalizedString(IDS_AX_ROLE_FIGURE);
+
     case ax::mojom::Role::kMeter:
       return content_client->GetLocalizedString(IDS_AX_ROLE_METER);
 
diff --git a/content/browser/accessibility/cross_platform_accessibility_browsertest.cc b/content/browser/accessibility/cross_platform_accessibility_browsertest.cc
index 15160b96..c2bc69b 100644
--- a/content/browser/accessibility/cross_platform_accessibility_browsertest.cc
+++ b/content/browser/accessibility/cross_platform_accessibility_browsertest.cc
@@ -706,8 +706,10 @@
                                          ax::mojom::Event::kLoadComplete);
   GURL url(
       "data:text/html,"
+      "<article></article>"
       "<audio controls></audio>"
       "<details></details>"
+      "<figure></figure>"
       "<input>"
       "<input type='color'>"
       "<input type='date'>"
@@ -724,7 +726,7 @@
 
   BrowserAccessibility* root = GetManager()->GetRoot();
   ASSERT_NE(nullptr, root);
-  ASSERT_EQ(12u, root->PlatformChildCount());
+  ASSERT_EQ(14u, root->PlatformChildCount());
 
   auto TestLocalizedRoleDescription =
       [root](int child_index,
@@ -737,19 +739,21 @@
       };
 
   // For testing purposes, assume we get en-US localized strings.
-  TestLocalizedRoleDescription(0, base::ASCIIToUTF16("audio"));
-  TestLocalizedRoleDescription(1, base::ASCIIToUTF16("details"));
-  TestLocalizedRoleDescription(2, base::ASCIIToUTF16(""));
-  TestLocalizedRoleDescription(3, base::ASCIIToUTF16("color picker"));
-  TestLocalizedRoleDescription(4, base::ASCIIToUTF16("date picker"));
+  TestLocalizedRoleDescription(0, base::ASCIIToUTF16("article"));
+  TestLocalizedRoleDescription(1, base::ASCIIToUTF16("audio"));
+  TestLocalizedRoleDescription(2, base::ASCIIToUTF16("details"));
+  TestLocalizedRoleDescription(3, base::ASCIIToUTF16("figure"));
+  TestLocalizedRoleDescription(4, base::ASCIIToUTF16(""));
+  TestLocalizedRoleDescription(5, base::ASCIIToUTF16("color picker"));
+  TestLocalizedRoleDescription(6, base::ASCIIToUTF16("date picker"));
   TestLocalizedRoleDescription(
-      5, base::ASCIIToUTF16("local date and time picker"));
-  TestLocalizedRoleDescription(6, base::ASCIIToUTF16("email"));
-  TestLocalizedRoleDescription(7, base::ASCIIToUTF16("telephone"));
-  TestLocalizedRoleDescription(8, base::ASCIIToUTF16("url"));
-  TestLocalizedRoleDescription(9, base::ASCIIToUTF16("week picker"));
-  TestLocalizedRoleDescription(10, base::ASCIIToUTF16("meter"));
-  TestLocalizedRoleDescription(11, base::ASCIIToUTF16("output"));
+      7, base::ASCIIToUTF16("local date and time picker"));
+  TestLocalizedRoleDescription(8, base::ASCIIToUTF16("email"));
+  TestLocalizedRoleDescription(9, base::ASCIIToUTF16("telephone"));
+  TestLocalizedRoleDescription(10, base::ASCIIToUTF16("url"));
+  TestLocalizedRoleDescription(11, base::ASCIIToUTF16("week picker"));
+  TestLocalizedRoleDescription(12, base::ASCIIToUTF16("meter"));
+  TestLocalizedRoleDescription(13, base::ASCIIToUTF16("output"));
 }
 
 IN_PROC_BROWSER_TEST_F(CrossPlatformAccessibilityBrowserTest,
diff --git a/content/browser/appcache/appcache_storage_impl.cc b/content/browser/appcache/appcache_storage_impl.cc
index fa015980..840597a7 100644
--- a/content/browser/appcache/appcache_storage_impl.cc
+++ b/content/browser/appcache/appcache_storage_impl.cc
@@ -50,8 +50,6 @@
 // Hard coded default when not using quota management.
 constexpr const int kDefaultQuota = 5 * kMB;
 
-constexpr const int kMaxAppCacheMemDiskCacheSize = 10 * kMB;
-
 constexpr base::FilePath::CharType kDiskCacheDirectoryName[] =
     FILE_PATH_LITERAL("Cache");
 constexpr base::FilePath::CharType kAppCacheDatabaseName[] =
@@ -1850,9 +1848,8 @@
     disk_cache_ = std::make_unique<AppCacheDiskCache>();
     if (is_incognito_) {
       rv = disk_cache_->InitWithMemBackend(
-          kMaxAppCacheMemDiskCacheSize,
-          base::BindOnce(&AppCacheStorageImpl::OnDiskCacheInitialized,
-                         base::Unretained(this)));
+          0, base::BindOnce(&AppCacheStorageImpl::OnDiskCacheInitialized,
+                            base::Unretained(this)));
     } else {
       expecting_cleanup_complete_on_disable_ = true;
 
diff --git a/content/browser/browsing_data/browsing_data_browsertest_utils.cc b/content/browser/browsing_data/browsing_data_browsertest_utils.cc
new file mode 100644
index 0000000..521b264a
--- /dev/null
+++ b/content/browser/browsing_data/browsing_data_browsertest_utils.cc
@@ -0,0 +1,177 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/browser/browsing_data/browsing_data_browsertest_utils.h"
+
+#include <memory>
+#include <string>
+#include <utility>
+#include <vector>
+
+#include "base/bind.h"
+#include "base/run_loop.h"
+#include "base/task/post_task.h"
+#include "components/network_session_configurator/common/network_switches.h"
+#include "content/browser/browsing_data/browsing_data_test_utils.h"
+#include "content/public/browser/browser_task_traits.h"
+#include "content/public/browser/storage_partition.h"
+#include "content/public/browser/storage_usage_info.h"
+#include "content/public/browser/system_connector.h"
+#include "content/public/common/content_switches.h"
+#include "content/public/common/network_service_util.h"
+#include "content/public/common/service_names.mojom.h"
+#include "content/public/test/content_browser_test_utils.h"
+#include "net/base/url_util.h"
+#include "net/test/embedded_test_server/http_response.h"
+#include "services/network/public/mojom/network_service_test.mojom.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace content {
+
+namespace browsing_data_browsertest_utils {
+
+namespace {
+
+void AddServiceWorkerCallback(bool success) {
+  ASSERT_TRUE(success);
+}
+
+void GetServiceWorkersCallback(
+    base::OnceClosure callback,
+    std::vector<StorageUsageInfo>* out_service_workers,
+    const std::vector<StorageUsageInfo>& service_workers) {
+  *out_service_workers = service_workers;
+  std::move(callback).Run();
+}
+
+}  // namespace
+
+void ServiceWorkerActivationObserver::SignalActivation(
+    ServiceWorkerContextWrapper* context,
+    const base::Closure& callback) {
+  new ServiceWorkerActivationObserver(context, callback);
+}
+
+ServiceWorkerActivationObserver::ServiceWorkerActivationObserver(
+    ServiceWorkerContextWrapper* context,
+    const base::Closure& callback)
+    : context_(context), scoped_observer_(this), callback_(callback) {
+  scoped_observer_.Add(context);
+}
+
+ServiceWorkerActivationObserver::~ServiceWorkerActivationObserver() {}
+
+void ServiceWorkerActivationObserver::OnVersionStateChanged(
+    int64_t version_id,
+    const GURL& scope,
+    ServiceWorkerVersion::Status) {
+  if (context_->GetLiveVersion(version_id)->status() ==
+      ServiceWorkerVersion::ACTIVATED) {
+    callback_.Run();
+    delete this;
+  }
+}
+
+void SetIgnoreCertificateErrors(base::CommandLine* command_line) {
+  if (IsOutOfProcessNetworkService()) {
+    // |MockCertVerifier| only seems to work when Network Service was enabled.
+    command_line->AppendSwitch(switches::kUseMockCertVerifierForTesting);
+  } else {
+    // We're redirecting all hosts to localhost even on HTTPS, so we'll get
+    // certificate errors.
+    command_line->AppendSwitch(switches::kIgnoreCertificateErrors);
+  }
+}
+
+void AddServiceWorker(const std::string& origin,
+                      StoragePartition* storage_partition,
+                      net::EmbeddedTestServer* https_server) {
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  ServiceWorkerContextWrapper* service_worker_context =
+      static_cast<ServiceWorkerContextWrapper*>(
+          storage_partition->GetServiceWorkerContext());
+
+  GURL scope_url = https_server->GetURL(origin, "/");
+  GURL js_url = https_server->GetURL(origin, "/?file=worker.js");
+
+  // Register the worker.
+  blink::mojom::ServiceWorkerRegistrationOptions options(
+      scope_url, blink::mojom::ScriptType::kClassic,
+      blink::mojom::ServiceWorkerUpdateViaCache::kImports);
+  base::PostTask(
+      FROM_HERE, {BrowserThread::IO},
+      base::BindOnce(&ServiceWorkerContextWrapper::RegisterServiceWorker,
+                     base::Unretained(service_worker_context), js_url, options,
+                     base::Bind(&AddServiceWorkerCallback)));
+
+  // Wait for its activation.
+  base::RunLoop run_loop;
+  base::PostTask(
+      FROM_HERE, {BrowserThread::IO},
+      base::BindOnce(&ServiceWorkerActivationObserver::SignalActivation,
+                     base::Unretained(service_worker_context),
+                     run_loop.QuitClosure()));
+  run_loop.Run();
+}
+
+std::vector<StorageUsageInfo> GetServiceWorkers(
+    StoragePartition* storage_partition) {
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  ServiceWorkerContextWrapper* service_worker_context =
+      static_cast<ServiceWorkerContextWrapper*>(
+          storage_partition->GetServiceWorkerContext());
+
+  std::vector<StorageUsageInfo> service_workers;
+  base::RunLoop run_loop;
+
+  base::PostTask(
+      FROM_HERE, {BrowserThread::IO},
+      base::BindOnce(
+          &ServiceWorkerContextWrapper::GetAllOriginsInfo,
+          base::Unretained(service_worker_context),
+          base::Bind(&GetServiceWorkersCallback, run_loop.QuitClosure(),
+                     base::Unretained(&service_workers))));
+  run_loop.Run();
+
+  return service_workers;
+}
+
+void SetResponseContent(const GURL& url,
+                        std::string* value,
+                        net::test_server::BasicHttpResponse* response) {
+  if (net::GetValueForKeyInQuery(url, "file", value)) {
+    base::FilePath path(GetTestFilePath("browsing_data", value->c_str()));
+    base::File file(path, base::File::FLAG_OPEN | base::File::FLAG_READ);
+    EXPECT_TRUE(file.IsValid());
+    int64_t length = file.GetLength();
+    EXPECT_GE(length, 0);
+    std::unique_ptr<char[]> buffer(new char[length + 1]);
+    file.Read(0, buffer.get(), length);
+    buffer[length] = '\0';
+
+    if (path.Extension() == FILE_PATH_LITERAL(".js"))
+      response->set_content_type("application/javascript");
+    else if (path.Extension() == FILE_PATH_LITERAL(".html"))
+      response->set_content_type("text/html");
+    else
+      NOTREACHED();
+
+    response->set_content(buffer.get());
+  }
+}
+
+void SetUpMockCertVerifier(int32_t default_result) {
+  network::mojom::NetworkServiceTestPtr network_service_test;
+  GetSystemConnector()->BindInterface(mojom::kNetworkServiceName,
+                                      &network_service_test);
+
+  base::RunLoop run_loop(base::RunLoop::Type::kNestableTasksAllowed);
+  network_service_test->MockCertVerifierSetDefaultResult(
+      default_result, run_loop.QuitClosure());
+  run_loop.Run();
+}
+
+}  // namespace browsing_data_browsertest_utils
+
+}  // namespace content
diff --git a/content/browser/browsing_data/browsing_data_browsertest_utils.h b/content/browser/browsing_data/browsing_data_browsertest_utils.h
new file mode 100644
index 0000000..4d0669ce
--- /dev/null
+++ b/content/browser/browsing_data/browsing_data_browsertest_utils.h
@@ -0,0 +1,90 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CONTENT_BROWSER_BROWSING_DATA_BROWSING_DATA_BROWSERTEST_UTILS_H_
+#define CONTENT_BROWSER_BROWSING_DATA_BROWSING_DATA_BROWSERTEST_UTILS_H_
+
+#include <string>
+#include <vector>
+
+#include "base/scoped_observer.h"
+#include "content/browser/service_worker/service_worker_context_core_observer.h"
+#include "content/browser/service_worker/service_worker_context_wrapper.h"
+#include "net/test/embedded_test_server/embedded_test_server.h"
+#include "net/test/embedded_test_server/http_response.h"
+#include "services/network/public/mojom/cookie_manager.mojom.h"
+
+namespace content {
+class StoragePartition;
+
+namespace browsing_data_browsertest_utils {
+
+// TODO(msramek): A class like this already exists in ServiceWorkerBrowserTest.
+// Consider extracting it to a different test utils file.
+class ServiceWorkerActivationObserver
+    : public ServiceWorkerContextCoreObserver {
+ public:
+  // |callback| is called when |context| is activated.
+  static void SignalActivation(ServiceWorkerContextWrapper* context,
+                               const base::Closure& callback);
+
+ private:
+  ServiceWorkerActivationObserver(ServiceWorkerContextWrapper* context,
+                                  const base::Closure& callback);
+
+  ~ServiceWorkerActivationObserver() override;
+
+  // ServiceWorkerContextCoreObserver overrides.
+  void OnVersionStateChanged(int64_t version_id,
+                             const GURL& scope,
+                             ServiceWorkerVersion::Status) override;
+
+  ServiceWorkerContextWrapper* context_;
+  ScopedObserver<ServiceWorkerContextWrapper, ServiceWorkerContextCoreObserver>
+      scoped_observer_;
+  base::Closure callback_;
+};
+
+// Appends a switch to the |command_line| based on whether the network service
+// is enabled. The browser will ignore certificate errors if the network service
+// is not enabled.
+void SetIgnoreCertificateErrors(base::CommandLine* command_line);
+
+// Adds a service worker for the given |origin|. The EmbeddedTestServer
+// |https_server| is required to retrieve a URL to the server based on the
+// |origin|.
+void AddServiceWorker(const std::string& origin,
+                      StoragePartition* storage_partition,
+                      net::EmbeddedTestServer* https_server);
+
+// Retrieves the list of all service workers.
+std::vector<StorageUsageInfo> GetServiceWorkers(
+    StoragePartition* storage_partition);
+
+// Populates the content and content type fields of a given HTTP |response|
+// based on the file extension of the |url| as follows:
+//
+// For .js:
+// Example: "https://localhost/?file=file.js"
+// will set the response header as
+// Content-Type: application/javascript
+//
+// For .html:
+// Example: "https://localhost/?file=file.html"
+// will set the response header as
+// Content-Type: text/html
+//
+// Response content type is only set for .js and .html files.
+void SetResponseContent(const GURL& url,
+                        std::string* value,
+                        net::test_server::BasicHttpResponse* response);
+
+// Sets up a MockCertVerifier with default return value |default_result|.
+void SetUpMockCertVerifier(int32_t default_result);
+
+}  // namespace browsing_data_browsertest_utils
+
+}  // namespace content
+
+#endif  // CONTENT_BROWSER_BROWSING_DATA_BROWSING_DATA_BROWSERTEST_UTILS_H_
diff --git a/content/browser/browsing_data/clear_site_data_handler_browsertest.cc b/content/browser/browsing_data/clear_site_data_handler_browsertest.cc
index f2bef53..100c149 100644
--- a/content/browser/browsing_data/clear_site_data_handler_browsertest.cc
+++ b/content/browser/browsing_data/clear_site_data_handler_browsertest.cc
@@ -14,15 +14,12 @@
 #include "base/strings/stringprintf.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/synchronization/lock.h"
-#include "base/task/post_task.h"
 #include "base/test/bind_test_util.h"
 #include "base/test/scoped_feature_list.h"
 #include "base/thread_annotations.h"
 #include "build/build_config.h"
-#include "components/network_session_configurator/common/network_switches.h"
+#include "content/browser/browsing_data/browsing_data_browsertest_utils.h"
 #include "content/browser/browsing_data/browsing_data_filter_builder_impl.h"
-#include "content/browser/service_worker/service_worker_context_core_observer.h"
-#include "content/browser/service_worker/service_worker_context_wrapper.h"
 #include "content/public/browser/browser_context.h"
 #include "content/public/browser/browser_task_traits.h"
 #include "content/public/browser/browser_thread.h"
@@ -30,12 +27,8 @@
 #include "content/public/browser/content_browser_client.h"
 #include "content/public/browser/storage_partition.h"
 #include "content/public/browser/storage_usage_info.h"
-#include "content/public/browser/system_connector.h"
 #include "content/public/browser/web_contents.h"
-#include "content/public/common/content_switches.h"
 #include "content/public/common/network_service_util.h"
-#include "content/public/common/service_names.mojom.h"
-#include "content/public/test/browser_test_utils.h"
 #include "content/public/test/content_browser_test.h"
 #include "content/public/test/content_browser_test_utils.h"
 #include "content/public/test/mock_browsing_data_remover_delegate.h"
@@ -50,7 +43,6 @@
 #include "net/test/embedded_test_server/http_response.h"
 #include "net/url_request/url_request_context.h"
 #include "net/url_request/url_request_context_getter.h"
-#include "services/network/public/mojom/network_service_test.mojom.h"
 #include "services/service_manager/public/cpp/connector.h"
 #include "storage/browser/quota/quota_settings.h"
 #include "testing/gmock/include/gmock/gmock.h"
@@ -129,57 +121,13 @@
   }
 };
 
-// TODO(msramek): A class like this already exists in ServiceWorkerBrowserTest.
-// Consider extracting it to a test utils file.
-class ServiceWorkerActivationObserver
-    : public ServiceWorkerContextCoreObserver {
- public:
-  static void SignalActivation(ServiceWorkerContextWrapper* context,
-                               const base::Closure& callback) {
-    new ServiceWorkerActivationObserver(context, callback);
-  }
-
- private:
-  ServiceWorkerActivationObserver(ServiceWorkerContextWrapper* context,
-                                  const base::Closure& callback)
-      : context_(context), scoped_observer_(this), callback_(callback) {
-    scoped_observer_.Add(context);
-  }
-
-  ~ServiceWorkerActivationObserver() override {}
-
-  // ServiceWorkerContextCoreObserver overrides.
-  void OnVersionStateChanged(int64_t version_id,
-                             const GURL& scope,
-                             ServiceWorkerVersion::Status) override {
-    if (context_->GetLiveVersion(version_id)->status() ==
-        ServiceWorkerVersion::ACTIVATED) {
-      callback_.Run();
-      delete this;
-    }
-  }
-
-  ServiceWorkerContextWrapper* context_;
-  ScopedObserver<ServiceWorkerContextWrapper, ServiceWorkerContextCoreObserver>
-      scoped_observer_;
-  base::Closure callback_;
-};
-
 }  // namespace
 
 class ClearSiteDataHandlerBrowserTest : public ContentBrowserTest {
  public:
   void SetUpCommandLine(base::CommandLine* command_line) override {
     ContentBrowserTest::SetUpCommandLine(command_line);
-
-    if (IsOutOfProcessNetworkService()) {
-      // |MockCertVerifier| only seems to work when Network Service was enabled.
-      command_line->AppendSwitch(switches::kUseMockCertVerifierForTesting);
-    } else {
-      // We're redirecting all hosts to localhost even on HTTPS, so we'll get
-      // certificate errors.
-      command_line->AppendSwitch(switches::kIgnoreCertificateErrors);
-    }
+    browsing_data_browsertest_utils::SetIgnoreCertificateErrors(command_line);
   }
 
   void SetUpOnMainThread() override {
@@ -192,7 +140,7 @@
     host_resolver()->AddRule("*", "127.0.0.1");
 
     if (IsOutOfProcessNetworkService())
-      SetUpMockCertVerifier(net::OK);
+      browsing_data_browsertest_utils::SetUpMockCertVerifier(net::OK);
 
     embedded_test_server()->RegisterRequestHandler(
         base::BindRepeating(&ClearSiteDataHandlerBrowserTest::HandleRequest,
@@ -248,64 +196,6 @@
     return cookie_list;
   }
 
-  // Adds a service worker. Used in the storage integration tests.
-  void AddServiceWorker(const std::string& origin) {
-    DCHECK_CURRENTLY_ON(BrowserThread::UI);
-    ServiceWorkerContextWrapper* service_worker_context =
-        static_cast<ServiceWorkerContextWrapper*>(
-            storage_partition()->GetServiceWorkerContext());
-
-    GURL scope_url = https_server()->GetURL(origin, "/");
-    GURL js_url = https_server()->GetURL(origin, "/?file=worker.js");
-
-    // Register the worker.
-    blink::mojom::ServiceWorkerRegistrationOptions options(
-        scope_url, blink::mojom::ScriptType::kClassic,
-        blink::mojom::ServiceWorkerUpdateViaCache::kImports);
-    RunOrPostTaskOnThread(
-        FROM_HERE, ServiceWorkerContext::GetCoreThreadId(),
-        base::BindOnce(
-            &ServiceWorkerContextWrapper::RegisterServiceWorker,
-            base::Unretained(service_worker_context), js_url, options,
-            base::Bind(
-                &ClearSiteDataHandlerBrowserTest::AddServiceWorkerCallback,
-                base::Unretained(this))));
-
-    // Wait for its activation.
-    base::RunLoop run_loop;
-    RunOrPostTaskOnThread(
-        FROM_HERE, ServiceWorkerContext::GetCoreThreadId(),
-        base::BindOnce(&ServiceWorkerActivationObserver::SignalActivation,
-                       base::Unretained(service_worker_context),
-                       run_loop.QuitClosure()));
-    run_loop.Run();
-  }
-
-  // Retrieves the list of all service workers. Used in the storage integration
-  // tests.
-  std::vector<StorageUsageInfo> GetServiceWorkers() {
-    DCHECK_CURRENTLY_ON(BrowserThread::UI);
-    ServiceWorkerContextWrapper* service_worker_context =
-        static_cast<ServiceWorkerContextWrapper*>(
-            storage_partition()->GetServiceWorkerContext());
-
-    std::vector<StorageUsageInfo> service_workers;
-    base::RunLoop run_loop;
-
-    RunOrPostTaskOnThread(
-        FROM_HERE, ServiceWorkerContext::GetCoreThreadId(),
-        base::BindOnce(
-            &ServiceWorkerContextWrapper::GetAllOriginsInfo,
-            base::Unretained(service_worker_context),
-            base::Bind(
-                &ClearSiteDataHandlerBrowserTest::GetServiceWorkersCallback,
-                base::Unretained(this), run_loop.QuitClosure(),
-                base::Unretained(&service_workers))));
-    run_loop.Run();
-
-    return service_workers;
-  }
-
   void CreateCacheEntry(const GURL& url) {
     ASSERT_EQ(net::OK,
               LoadBasicRequest(storage_partition()->GetNetworkContext(), url));
@@ -392,27 +282,15 @@
     if (net::GetValueForKeyInQuery(request.GetURL(), "html", &value)) {
       response->set_content_type("text/html");
       response->set_content(value);
+
+      // The "html" parameter is telling the server what to serve, and the XSS
+      // auditor will complain if its |value| contains JS code. Disable that
+      // protection.
+      response->AddCustomHeader("X-XSS-Protection", "0");
     }
 
-    if (net::GetValueForKeyInQuery(request.GetURL(), "file", &value)) {
-      base::FilePath path(GetTestFilePath("browsing_data", value.c_str()));
-      base::File file(path, base::File::FLAG_OPEN | base::File::FLAG_READ);
-      EXPECT_TRUE(file.IsValid());
-      int64_t length = file.GetLength();
-      EXPECT_GE(length, 0);
-      std::unique_ptr<char[]> buffer(new char[length + 1]);
-      file.Read(0, buffer.get(), length);
-      buffer[length] = '\0';
-
-      if (path.Extension() == FILE_PATH_LITERAL(".js"))
-        response->set_content_type("application/javascript");
-      else if (path.Extension() == FILE_PATH_LITERAL(".html"))
-        response->set_content_type("text/html");
-      else
-        NOTREACHED();
-
-      response->set_content(buffer.get());
-    }
+    browsing_data_browsertest_utils::SetResponseContent(request.GetURL(),
+                                                        &value, response.get());
 
     if (base::StartsWith(request.relative_url, "/cachetime",
                          base::CompareCase::SENSITIVE)) {
@@ -425,17 +303,6 @@
     return std::move(response);
   }
 
-  void SetUpMockCertVerifier(int32_t default_result) {
-    network::mojom::NetworkServiceTestPtr network_service_test;
-    GetSystemConnector()->BindInterface(mojom::kNetworkServiceName,
-                                        &network_service_test);
-
-    base::RunLoop run_loop(base::RunLoop::Type::kNestableTasksAllowed);
-    network_service_test->MockCertVerifierSetDefaultResult(
-        default_result, run_loop.QuitClosure());
-    run_loop.Run();
-  }
-
   // Callback handler for AddCookie().
   static void AddCookieCallback(
       base::OnceClosure callback,
@@ -454,18 +321,6 @@
     std::move(callback).Run();
   }
 
-  // Callback handler for AddServiceWorker().
-  void AddServiceWorkerCallback(bool success) { ASSERT_TRUE(success); }
-
-  // Callback handler for GetServiceWorkers().
-  void GetServiceWorkersCallback(
-      base::OnceClosure callback,
-      std::vector<StorageUsageInfo>* out_service_workers,
-      const std::vector<StorageUsageInfo>& service_workers) {
-    *out_service_workers = service_workers;
-    std::move(callback).Run();
-  }
-
   // If this is set, |HandleRequest| will always respond with Clear-Site-Data.
   base::Lock clear_site_data_header_lock_;
   std::string clear_site_data_header_ GUARDED_BY(clear_site_data_header_lock_);
@@ -885,36 +740,44 @@
 // Integration test for the unregistering of service workers.
 IN_PROC_BROWSER_TEST_F(ClearSiteDataHandlerBrowserTest,
                        StorageServiceWorkersIntegrationTest) {
-  AddServiceWorker("origin1.com");
-  AddServiceWorker("origin2.com");
+  StoragePartition* partition = storage_partition();
+  net::EmbeddedTestServer* server = https_server();
+
+  browsing_data_browsertest_utils::AddServiceWorker("origin1.com", partition,
+                                                    server);
+  browsing_data_browsertest_utils::AddServiceWorker("origin2.com", partition,
+                                                    server);
 
   // There are two service workers installed on two origins.
-  std::vector<StorageUsageInfo> service_workers = GetServiceWorkers();
+  std::vector<StorageUsageInfo> service_workers =
+      browsing_data_browsertest_utils::GetServiceWorkers(partition);
   EXPECT_EQ(2u, service_workers.size());
 
   // Navigate to a URL within the scope of "origin1.com" which responds with
   // a Clear-Site-Data header. Verify that this did NOT remove the service
   // worker for "origin1.com", as the header would not be respected outside
   // of the scope.
-  GURL url = https_server()->GetURL("origin1.com", "/anything-in-the-scope");
+  GURL url = server->GetURL("origin1.com", "/anything-in-the-scope");
   AddQuery(&url, "header", "\"storage\"");
   NavigateToURL(shell(), url);
-  service_workers = GetServiceWorkers();
+  service_workers =
+      browsing_data_browsertest_utils::GetServiceWorkers(partition);
   EXPECT_EQ(2u, service_workers.size());
 
   // This time, we will navigate to a URL on "origin1.com" that is not handled
   // by the serice worker, but results in a network request. One such resource
   // not handled by "worker.js" is the path "resource".
   // The header will be respected and the worker deleted.
-  url = https_server()->GetURL("origin1.com", "/resource");
+  url = server->GetURL("origin1.com", "/resource");
   AddQuery(&url, "header", "\"storage\"");
   NavigateToURL(shell(), url);
 
   // Only "origin2.com" now has a service worker.
-  service_workers = GetServiceWorkers();
+  service_workers =
+      browsing_data_browsertest_utils::GetServiceWorkers(partition);
   ASSERT_EQ(1u, service_workers.size());
   EXPECT_EQ(service_workers[0].origin.GetURL(),
-            https_server()->GetURL("origin2.com", "/"));
+            server->GetURL("origin2.com", "/"));
 
   // TODO(msramek): Test that the service worker update ping also deletes
   // the service worker.
diff --git a/content/browser/browsing_data/same_site_data_remover_impl_browsertest.cc b/content/browser/browsing_data/same_site_data_remover_impl_browsertest.cc
index 3f539900..39d23fa6 100644
--- a/content/browser/browsing_data/same_site_data_remover_impl_browsertest.cc
+++ b/content/browser/browsing_data/same_site_data_remover_impl_browsertest.cc
@@ -9,30 +9,18 @@
 #include <vector>
 
 #include "base/bind.h"
-#include "base/command_line.h"
 #include "base/run_loop.h"
-#include "base/scoped_observer.h"
-#include "base/task/post_task.h"
-#include "components/network_session_configurator/common/network_switches.h"
+#include "content/browser/browsing_data/browsing_data_browsertest_utils.h"
 #include "content/browser/browsing_data/browsing_data_test_utils.h"
-#include "content/browser/service_worker/service_worker_context_wrapper.h"
-#include "content/public/browser/browser_task_traits.h"
 #include "content/public/browser/same_site_data_remover.h"
 #include "content/public/browser/storage_partition.h"
 #include "content/public/browser/storage_usage_info.h"
-#include "content/public/browser/system_connector.h"
-#include "content/public/common/content_switches.h"
 #include "content/public/common/network_service_util.h"
-#include "content/public/common/service_names.mojom.h"
 #include "content/public/test/content_browser_test.h"
-#include "content/public/test/content_browser_test_utils.h"
 #include "content/shell/browser/shell.h"
-#include "net/base/url_util.h"
 #include "net/dns/mock_host_resolver.h"
 #include "net/test/embedded_test_server/http_request.h"
 #include "net/test/embedded_test_server/http_response.h"
-#include "services/network/public/mojom/cookie_manager.mojom.h"
-#include "services/network/public/mojom/network_service_test.mojom.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -40,44 +28,6 @@
 
 namespace content {
 
-namespace {
-
-class ServiceWorkerActivationObserver
-    : public ServiceWorkerContextCoreObserver {
- public:
-  static void SignalActivation(ServiceWorkerContextWrapper* context,
-                               const base::Closure& callback) {
-    new ServiceWorkerActivationObserver(context, callback);
-  }
-
- private:
-  ServiceWorkerActivationObserver(ServiceWorkerContextWrapper* context,
-                                  const base::Closure& callback)
-      : context_(context), scoped_observer_(this), callback_(callback) {
-    scoped_observer_.Add(context);
-  }
-
-  ~ServiceWorkerActivationObserver() override {}
-
-  // ServiceWorkerContextCoreObserver overrides.
-  void OnVersionStateChanged(int64_t version_id,
-                             const GURL& scope,
-                             ServiceWorkerVersion::Status) override {
-    if (context_->GetLiveVersion(version_id)->status() ==
-        ServiceWorkerVersion::ACTIVATED) {
-      callback_.Run();
-      delete this;
-    }
-  }
-
-  ServiceWorkerContextWrapper* context_;
-  ScopedObserver<ServiceWorkerContextWrapper, ServiceWorkerContextCoreObserver>
-      scoped_observer_;
-  base::Closure callback_;
-};
-
-}  // namespace
-
 class SameSiteDataRemoverBrowserTest : public ContentBrowserTest {
  public:
   SameSiteDataRemoverBrowserTest() {}
@@ -89,7 +39,7 @@
     host_resolver()->AddRule("*", "127.0.0.1");
 
     if (IsOutOfProcessNetworkService())
-      SetUpMockCertVerifier(net::OK);
+      browsing_data_browsertest_utils::SetUpMockCertVerifier(net::OK);
 
     https_server_.reset(new net::EmbeddedTestServer(
         net::test_server::EmbeddedTestServer::TYPE_HTTPS));
@@ -102,92 +52,19 @@
 
   void SetUpCommandLine(base::CommandLine* command_line) override {
     ContentBrowserTest::SetUpCommandLine(command_line);
-
-    if (IsOutOfProcessNetworkService()) {
-      // |MockCertVerifier| only seems to work when Network Service was enabled.
-      command_line->AppendSwitch(switches::kUseMockCertVerifierForTesting);
-    } else {
-      // We're redirecting all hosts to localhost even on HTTPS, so we'll get
-      // certificate errors.
-      command_line->AppendSwitch(switches::kIgnoreCertificateErrors);
-    }
+    browsing_data_browsertest_utils::SetIgnoreCertificateErrors(command_line);
   }
 
   BrowserContext* GetBrowserContext() {
     return shell()->web_contents()->GetBrowserContext();
   }
 
+  StoragePartition* GetStoragePartition() {
+    return BrowserContext::GetDefaultStoragePartition(GetBrowserContext());
+  }
+
   net::EmbeddedTestServer* GetHttpsServer() { return https_server_.get(); }
 
-  void SetUpMockCertVerifier(int32_t default_result) {
-    network::mojom::NetworkServiceTestPtr network_service_test;
-    GetSystemConnector()->BindInterface(mojom::kNetworkServiceName,
-                                        &network_service_test);
-
-    base::RunLoop run_loop(base::RunLoop::Type::kNestableTasksAllowed);
-    network_service_test->MockCertVerifierSetDefaultResult(
-        default_result, run_loop.QuitClosure());
-    run_loop.Run();
-  }
-
-  void AddServiceWorker(const std::string& origin) {
-    DCHECK_CURRENTLY_ON(BrowserThread::UI);
-    StoragePartition* partition =
-        BrowserContext::GetDefaultStoragePartition(GetBrowserContext());
-    ServiceWorkerContextWrapper* service_worker_context =
-        static_cast<ServiceWorkerContextWrapper*>(
-            partition->GetServiceWorkerContext());
-
-    GURL scope_url = GetHttpsServer()->GetURL(origin, "/");
-    GURL js_url = GetHttpsServer()->GetURL(origin, "/?file=worker.js");
-
-    // Register the worker.
-    blink::mojom::ServiceWorkerRegistrationOptions options(
-        scope_url, blink::mojom::ScriptType::kClassic,
-        blink::mojom::ServiceWorkerUpdateViaCache::kImports);
-    RunOrPostTaskOnThread(
-        FROM_HERE, ServiceWorkerContext::GetCoreThreadId(),
-        base::BindOnce(
-            &ServiceWorkerContextWrapper::RegisterServiceWorker,
-            base::Unretained(service_worker_context), js_url, options,
-            base::Bind(
-                &SameSiteDataRemoverBrowserTest::AddServiceWorkerCallback,
-                base::Unretained(this))));
-
-    // Wait for its activation.
-    base::RunLoop run_loop;
-    RunOrPostTaskOnThread(
-        FROM_HERE, ServiceWorkerContext::GetCoreThreadId(),
-        base::BindOnce(&ServiceWorkerActivationObserver::SignalActivation,
-                       base::Unretained(service_worker_context),
-                       run_loop.QuitClosure()));
-    run_loop.Run();
-  }
-
-  std::vector<StorageUsageInfo> GetServiceWorkers() {
-    DCHECK_CURRENTLY_ON(BrowserThread::UI);
-    StoragePartition* partition =
-        BrowserContext::GetDefaultStoragePartition(GetBrowserContext());
-    ServiceWorkerContextWrapper* service_worker_context =
-        static_cast<ServiceWorkerContextWrapper*>(
-            partition->GetServiceWorkerContext());
-
-    std::vector<StorageUsageInfo> service_workers;
-    base::RunLoop run_loop;
-    RunOrPostTaskOnThread(
-        FROM_HERE, ServiceWorkerContext::GetCoreThreadId(),
-        base::BindOnce(
-            &ServiceWorkerContextWrapper::GetAllOriginsInfo,
-            base::Unretained(service_worker_context),
-            base::Bind(
-                &SameSiteDataRemoverBrowserTest::GetServiceWorkersCallback,
-                base::Unretained(this), run_loop.QuitClosure(),
-                base::Unretained(&service_workers))));
-    run_loop.Run();
-
-    return service_workers;
-  }
-
   void ClearData(bool clear_storage) {
     base::RunLoop run_loop;
     ClearSameSiteNoneData(run_loop.QuitClosure(), GetBrowserContext(),
@@ -196,16 +73,6 @@
   }
 
  private:
-  void AddServiceWorkerCallback(bool success) { ASSERT_TRUE(success); }
-
-  void GetServiceWorkersCallback(
-      base::OnceClosure callback,
-      std::vector<StorageUsageInfo>* out_service_workers,
-      const std::vector<StorageUsageInfo>& service_workers) {
-    *out_service_workers = service_workers;
-    std::move(callback).Run();
-  }
-
   // Handles all requests.
   //
   // Supports the following <key>=<value> query parameters in the url:
@@ -215,23 +82,8 @@
     auto response(std::make_unique<net::test_server::BasicHttpResponse>());
 
     std::string value;
-    if (net::GetValueForKeyInQuery(request.GetURL(), "file", &value)) {
-      base::FilePath path(GetTestFilePath("browsing_data", value.c_str()));
-      base::File file(path, base::File::FLAG_OPEN | base::File::FLAG_READ);
-      EXPECT_TRUE(file.IsValid());
-      int64_t length = file.GetLength();
-      EXPECT_GE(length, 0);
-      std::unique_ptr<char[]> buffer(new char[length + 1]);
-      file.Read(0, buffer.get(), length);
-      buffer[length] = '\0';
-
-      if (path.Extension() == FILE_PATH_LITERAL(".js"))
-        response->set_content_type("application/javascript");
-      else
-        NOTREACHED();
-
-      response->set_content(buffer.get());
-    }
+    browsing_data_browsertest_utils::SetResponseContent(request.GetURL(),
+                                                        &value, response.get());
 
     return std::move(response);
   }
@@ -243,11 +95,13 @@
 
 IN_PROC_BROWSER_TEST_F(SameSiteDataRemoverBrowserTest,
                        TestClearDataWithStorageRemoval) {
+  StoragePartition* storage_partition = GetStoragePartition();
   CreateCookieForTest("TestCookie", "www.google.com",
                       net::CookieSameSite::NO_RESTRICTION,
                       net::CookieOptions::SameSiteCookieContext::CROSS_SITE,
                       GetBrowserContext());
-  AddServiceWorker("www.google.com");
+  browsing_data_browsertest_utils::AddServiceWorker(
+      "www.google.com", storage_partition, GetHttpsServer());
 
   ClearData(/* clear_storage= */ true);
 
@@ -257,17 +111,20 @@
   EXPECT_THAT(cookies, IsEmpty());
 
   // Check that the service worker for the cookie domain was removed.
-  std::vector<StorageUsageInfo> service_workers = GetServiceWorkers();
+  std::vector<StorageUsageInfo> service_workers =
+      browsing_data_browsertest_utils::GetServiceWorkers(storage_partition);
   EXPECT_THAT(service_workers, IsEmpty());
 }
 
 IN_PROC_BROWSER_TEST_F(SameSiteDataRemoverBrowserTest,
                        TestClearDataWithoutStorageRemoval) {
+  StoragePartition* storage_partition = GetStoragePartition();
   CreateCookieForTest("TestCookie", "www.google.com",
                       net::CookieSameSite::NO_RESTRICTION,
                       net::CookieOptions::SameSiteCookieContext::CROSS_SITE,
                       GetBrowserContext());
-  AddServiceWorker("www.google.com");
+  browsing_data_browsertest_utils::AddServiceWorker(
+      "www.google.com", storage_partition, GetHttpsServer());
 
   ClearData(/* clear_storage= */ false);
 
@@ -277,7 +134,8 @@
   EXPECT_THAT(cookies, IsEmpty());
 
   // Storage partition data should NOT have been cleared.
-  std::vector<StorageUsageInfo> service_workers = GetServiceWorkers();
+  std::vector<StorageUsageInfo> service_workers =
+      browsing_data_browsertest_utils::GetServiceWorkers(storage_partition);
   ASSERT_EQ(1u, service_workers.size());
   EXPECT_EQ(service_workers[0].origin.GetURL(),
             GetHttpsServer()->GetURL("www.google.com", "/"));
diff --git a/content/browser/child_process_launcher_helper_fuchsia.cc b/content/browser/child_process_launcher_helper_fuchsia.cc
index ea9bef7..204ff17 100644
--- a/content/browser/child_process_launcher_helper_fuchsia.cc
+++ b/content/browser/child_process_launcher_helper_fuchsia.cc
@@ -6,14 +6,41 @@
 
 #include "base/command_line.h"
 #include "base/process/launch.h"
+#include "base/strings/stringprintf.h"
 #include "content/browser/child_process_launcher.h"
 #include "content/public/browser/child_process_launcher_utils.h"
 #include "content/public/common/sandboxed_process_launcher_delegate.h"
 #include "services/service_manager/embedder/result_codes.h"
+#include "services/service_manager/embedder/switches.h"
 
 namespace content {
 namespace internal {
 
+namespace {
+
+const char* ProcessNameFromSandboxType(
+    service_manager::SandboxType sandbox_type) {
+  switch (sandbox_type) {
+    case service_manager::SANDBOX_TYPE_NO_SANDBOX:
+      return nullptr;
+    case service_manager::SANDBOX_TYPE_WEB_CONTEXT:
+      return "context";
+    case service_manager::SANDBOX_TYPE_RENDERER:
+      return "renderer";
+    case service_manager::SANDBOX_TYPE_UTILITY:
+      return "utility";
+    case service_manager::SANDBOX_TYPE_GPU:
+      return "gpu";
+    case service_manager::SANDBOX_TYPE_NETWORK:
+      return "network";
+    default:
+      NOTREACHED() << sandbox_type;
+      return nullptr;
+  }
+}
+
+}  // namespace
+
 void ChildProcessLauncherHelper::SetProcessPriorityOnLauncherThread(
     base::Process process,
     const ChildProcessLauncherPriority& priority) {
@@ -68,6 +95,12 @@
                                              command_line());
   sandbox_policy_.UpdateLaunchOptionsForSandbox(options);
 
+  // Set process name suffix to make it easier to identify the process.
+  const char* process_type =
+      ProcessNameFromSandboxType(delegate_->GetSandboxType());
+  if (process_type)
+    options->process_name_suffix = base::StringPrintf(":%s", process_type);
+
   return true;
 }
 
diff --git a/content/browser/frame_host/navigation_controller_impl_unittest.cc b/content/browser/frame_host/navigation_controller_impl_unittest.cc
index 648b1cda..19b3c788 100644
--- a/content/browser/frame_host/navigation_controller_impl_unittest.cc
+++ b/content/browser/frame_host/navigation_controller_impl_unittest.cc
@@ -2450,7 +2450,6 @@
           std::string(), browser_context(),
           nullptr /* blob_url_loader_factory */);
   entry->SetTitle(base::ASCIIToUTF16("Title"));
-  entry->SetPageState(PageState::CreateFromEncodedData("state"));
   const base::Time timestamp = base::Time::Now();
   entry->SetTimestamp(timestamp);
   entries.push_back(std::move(entry));
@@ -2519,7 +2518,6 @@
           std::string(), browser_context(),
           nullptr /* blob_url_loader_factory */);
   new_entry->SetTitle(base::ASCIIToUTF16("Title"));
-  new_entry->SetPageState(PageState::CreateFromEncodedData("state"));
   entries.push_back(std::move(new_entry));
   std::unique_ptr<WebContents> our_contents =
       WebContents::Create(WebContents::CreateParams(browser_context()));
diff --git a/content/browser/frame_host/navigation_entry_impl.cc b/content/browser/frame_host/navigation_entry_impl.cc
index 96903525c..275a9da 100644
--- a/content/browser/frame_host/navigation_entry_impl.cc
+++ b/content/browser/frame_host/navigation_entry_impl.cc
@@ -95,6 +95,12 @@
   }
 }
 
+base::Optional<base::string16> UrlToOptionalString16(const GURL& url) {
+  if (!url.is_valid())
+    return base::nullopt;
+  return base::UTF8ToUTF16(url.spec());
+}
+
 void RecursivelyGenerateFrameState(
     NavigationEntryImpl::TreeNode* node,
     ExplodedFrameState* state,
@@ -112,6 +118,35 @@
   // Copy the FrameNavigationEntry's frame state into the destination state.
   *state = frame_state;
 
+  // Some data is stored *both* in 1) PageState/ExplodedFrameState and 2)
+  // FrameNavigationEntry.  We want to treat FrameNavigationEntry as the
+  // authoritative source of the data, so we clobber the ExplodedFrameState with
+  // the data taken from FrameNavigationEntry.
+  //
+  // The following ExplodedFrameState fields do not have an equivalent
+  // FrameNavigationEntry field:
+  // - target
+  // - state_object
+  // - document_state
+  // - scroll_restoration_type
+  // - did_save_scroll_or_scale_state
+  // - visual_viewport_scroll_offset
+  // - scroll_offset
+  // - page_scale_factor
+  // - http_body (FrameNavigationEntry::GetPostData extracts the body from
+  //   the ExplodedFrameState)
+  // - scroll_anchor_selector
+  // - scroll_anchor_offset
+  // - scroll_anchor_simhash
+  state->url_string = UrlToOptionalString16(node->frame_entry->url());
+  state->referrer = UrlToOptionalString16(node->frame_entry->referrer().url);
+  state->referrer_policy = node->frame_entry->referrer().policy;
+  state->item_sequence_number = node->frame_entry->item_sequence_number();
+  state->document_sequence_number =
+      node->frame_entry->document_sequence_number();
+  // TODO(lukasza): https://crbug.com/976055: Persist |initiator_origin| in
+  // the ExplodedFrameState.
+
   // Copy the frame's files into the PageState's |referenced_files|.
   referenced_files->reserve(referenced_files->size() +
                             exploded_page_state.referenced_files.size());
@@ -386,12 +421,10 @@
   if (!frame_tree_->children.empty())
     frame_tree_->children.clear();
 
-  // If the PageState can't be parsed or has no children, just store it on the
-  // main frame's FrameNavigationEntry without recursively creating subframe
-  // entries.
+  // If the PageState can't be parsed, just store it on the main frame's
+  // FrameNavigationEntry without recursively creating subframe entries.
   ExplodedPageState exploded_state;
-  if (!DecodePageState(state.ToEncodedData(), &exploded_state) ||
-      exploded_state.top.children.size() == 0U) {
+  if (!DecodePageState(state.ToEncodedData(), &exploded_state)) {
     frame_tree_->frame_entry->SetPageState(state);
     return;
   }
@@ -401,14 +434,8 @@
 }
 
 PageState NavigationEntryImpl::GetPageState() {
-  // Just return the main frame's state if there are no subframe
-  // FrameNavigationEntries.
-  if (frame_tree_->children.size() == 0U)
-    return frame_tree_->frame_entry->page_state();
-
-  // When we're using subframe entries, each FrameNavigationEntry has a
-  // frame-specific PageState.  We combine these into an ExplodedPageState tree
-  // and generate a full PageState from it.
+  // Each FrameNavigationEntry has a frame-specific PageState.  We combine these
+  // into an ExplodedPageState tree and generate a full PageState from it.
   ExplodedPageState exploded_state;
   RecursivelyGenerateFrameState(frame_tree_.get(), &exploded_state.top,
                                 &exploded_state.referenced_files);
diff --git a/content/browser/frame_host/navigation_entry_impl_unittest.cc b/content/browser/frame_host/navigation_entry_impl_unittest.cc
index 9bbcf168..45cb8cd6 100644
--- a/content/browser/frame_host/navigation_entry_impl_unittest.cc
+++ b/content/browser/frame_host/navigation_entry_impl_unittest.cc
@@ -14,6 +14,7 @@
 #include "base/time/time.h"
 #include "build/build_config.h"
 #include "content/browser/site_instance_impl.h"
+#include "content/common/page_state_serialization.h"
 #include "content/public/browser/ssl_status.h"
 #include "content/public/test/browser_task_environment.h"
 #include "content/public/test/test_browser_context.h"
@@ -49,6 +50,13 @@
   DISALLOW_COPY_AND_ASSIGN(TestSSLStatusData);
 };
 
+PageState CreateTestPageState() {
+  ExplodedPageState exploded_state;
+  std::string encoded_data;
+  EncodePageState(exploded_state, &encoded_data);
+  return PageState::CreateFromEncodedData(encoded_data);
+}
+
 }  // namespace
 
 class NavigationEntryTest : public testing::Test {
@@ -231,12 +239,6 @@
   entry2_->SetTitle(ASCIIToUTF16("title2"));
   EXPECT_EQ(ASCIIToUTF16("title2"), entry2_->GetTitle());
 
-  // State
-  EXPECT_FALSE(entry1_->GetPageState().IsValid());
-  EXPECT_FALSE(entry2_->GetPageState().IsValid());
-  entry2_->SetPageState(PageState::CreateFromEncodedData("state"));
-  EXPECT_EQ("state", entry2_->GetPageState().ToEncodedData());
-
   // Transition type
   EXPECT_TRUE(ui::PageTransitionTypeIncludingQualifiersIs(
       entry1_->GetTransitionType(), ui::PAGE_TRANSITION_LINK));
@@ -292,10 +294,21 @@
   // Initiator origin.
   EXPECT_FALSE(
       entry1_->root_node()->frame_entry->initiator_origin().has_value());
-  EXPECT_TRUE(
+  ASSERT_TRUE(
       entry2_->root_node()->frame_entry->initiator_origin().has_value());
   EXPECT_EQ(url::Origin::Create(GURL("https://initiator.example.com")),
             entry2_->root_node()->frame_entry->initiator_origin().value());
+
+  // State.
+  //
+  // Note that calling SetPageState may also set some other FNE members
+  // (referrer, initiator, etc.).  This is why it is important to test
+  // SetPageState/GetPageState last.
+  PageState test_page_state = CreateTestPageState();
+  entry2_->SetPageState(test_page_state);
+  // TODO(lukasza): https://crbug.com/976055: Once |initiator_origin| is
+  // persisted across session restore, the test here should verify that
+  // SetPageState round-trips via GetPageState.
 }
 
 // Test basic Clone behavior.
diff --git a/content/browser/frame_host/render_frame_message_filter_browsertest.cc b/content/browser/frame_host/render_frame_message_filter_browsertest.cc
index 1b38667..b06c83b 100644
--- a/content/browser/frame_host/render_frame_message_filter_browsertest.cc
+++ b/content/browser/frame_host/render_frame_message_filter_browsertest.cc
@@ -295,7 +295,7 @@
  public:
   RestrictedCookieManagerInterceptor(
       mojo::PendingReceiver<network::mojom::RestrictedCookieManager> receiver,
-      network::mojom::RestrictedCookieManagerPtr real_rcm)
+      mojo::PendingRemote<network::mojom::RestrictedCookieManager> real_rcm)
       : receiver_(this, std::move(receiver)), real_rcm_(std::move(real_rcm)) {}
 
   void set_override_url(base::Optional<std::string> maybe_url) {
@@ -332,7 +332,7 @@
   base::Optional<std::string> override_url_;
 
   mojo::Receiver<network::mojom::RestrictedCookieManager> receiver_;
-  network::mojom::RestrictedCookieManagerPtr real_rcm_;
+  mojo::Remote<network::mojom::RestrictedCookieManager> real_rcm_;
 };
 
 class CookieStoreContentBrowserClient : public ContentBrowserClient {
@@ -351,8 +351,8 @@
     mojo::PendingReceiver<network::mojom::RestrictedCookieManager>
         orig_receiver = std::move(*receiver);
 
-    network::mojom::RestrictedCookieManagerPtr real_rcm;
-    *receiver = mojo::MakeRequest(&real_rcm);
+    mojo::PendingRemote<network::mojom::RestrictedCookieManager> real_rcm;
+    *receiver = real_rcm.InitWithNewPipeAndPassReceiver();
 
     rcm_interceptor_ = std::make_unique<RestrictedCookieManagerInterceptor>(
         std::move(orig_receiver), std::move(real_rcm));
diff --git a/content/browser/media/android/media_resource_getter_impl.cc b/content/browser/media/android/media_resource_getter_impl.cc
index 066a634..64f2255 100644
--- a/content/browser/media/android/media_resource_getter_impl.cc
+++ b/content/browser/media/android/media_resource_getter_impl.cc
@@ -19,6 +19,7 @@
 #include "content/public/common/content_client.h"
 #include "content/public/common/url_constants.h"
 #include "media/base/android/media_url_interceptor.h"
+#include "mojo/public/cpp/bindings/remote.h"
 #include "net/base/auth.h"
 #include "net/http/http_auth.h"
 #include "services/network/public/mojom/restricted_cookie_manager.mojom.h"
@@ -32,24 +33,22 @@
 // Returns the cookie manager for the |browser_context| at the client end of the
 // mojo pipe. This will be restricted to the origin of |url|, and will apply
 // policies from user and ContentBrowserClient to cookie operations.
-network::mojom::RestrictedCookieManagerPtr GetRestrictedCookieManagerForContext(
-    BrowserContext* browser_context,
-    const GURL& url,
-    int render_process_id,
-    int render_frame_id) {
+mojo::PendingRemote<network::mojom::RestrictedCookieManager>
+GetRestrictedCookieManagerForContext(BrowserContext* browser_context,
+                                     const GURL& url,
+                                     int render_process_id,
+                                     int render_frame_id) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
 
   url::Origin origin = url::Origin::Create(url);
   StoragePartition* storage_partition =
       BrowserContext::GetDefaultStoragePartition(browser_context);
 
-  network::mojom::RestrictedCookieManagerPtr pipe;
-  mojo::PendingReceiver<network::mojom::RestrictedCookieManager> receiver =
-      mojo::MakeRequest(&pipe);
+  mojo::PendingRemote<network::mojom::RestrictedCookieManager> pipe;
   storage_partition->CreateRestrictedCookieManager(
       network::mojom::RestrictedCookieManagerRole::NETWORK, origin,
       /* is_service_worker = */ false, render_process_id, render_frame_id,
-      std::move(receiver));
+      pipe.InitWithNewPipeAndPassReceiver());
   return pipe;
 }
 
@@ -61,7 +60,7 @@
 }
 
 void ReturnResultOnUIThreadAndClosePipe(
-    network::mojom::RestrictedCookieManagerPtr pipe,
+    mojo::Remote<network::mojom::RestrictedCookieManager> pipe,
     base::OnceCallback<void(const std::string&)> callback,
     const std::string& result) {
   base::PostTask(FROM_HERE, {BrowserThread::UI},
@@ -143,9 +142,9 @@
     return;
   }
 
-  network::mojom::RestrictedCookieManagerPtr cookie_manager =
+  mojo::Remote<network::mojom::RestrictedCookieManager> cookie_manager(
       GetRestrictedCookieManagerForContext(
-          browser_context_, url, render_process_id_, render_frame_id_);
+          browser_context_, url, render_process_id_, render_frame_id_));
   network::mojom::RestrictedCookieManager* cookie_manager_ptr =
       cookie_manager.get();
   cookie_manager_ptr->GetCookiesString(
diff --git a/content/browser/picture_in_picture/picture_in_picture_service_impl.cc b/content/browser/picture_in_picture/picture_in_picture_service_impl.cc
index f465e90..b37eb213 100644
--- a/content/browser/picture_in_picture/picture_in_picture_service_impl.cc
+++ b/content/browser/picture_in_picture/picture_in_picture_service_impl.cc
@@ -42,7 +42,6 @@
     const base::Optional<viz::SurfaceId>& surface_id,
     const gfx::Size& natural_size,
     bool show_play_pause_button,
-    bool show_mute_button,
     mojo::PendingRemote<blink::mojom::PictureInPictureSessionObserver> observer,
     StartSessionCallback callback) {
   gfx::Size window_size;
@@ -60,7 +59,7 @@
   if (result == PictureInPictureResult::kSuccess) {
     active_session_ = std::make_unique<PictureInPictureSession>(
         this, MediaPlayerId(render_frame_host_, player_id), surface_id,
-        natural_size, show_play_pause_button, show_mute_button,
+        natural_size, show_play_pause_button,
         session_remote.InitWithNewPipeAndPassReceiver(), std::move(observer),
         &window_size);
   }
diff --git a/content/browser/picture_in_picture/picture_in_picture_service_impl.h b/content/browser/picture_in_picture/picture_in_picture_service_impl.h
index cfa35d1..96f796c 100644
--- a/content/browser/picture_in_picture/picture_in_picture_service_impl.h
+++ b/content/browser/picture_in_picture/picture_in_picture_service_impl.h
@@ -45,7 +45,6 @@
       const base::Optional<viz::SurfaceId>& surface_id,
       const gfx::Size& natural_size,
       bool show_play_pause_button,
-      bool show_mute_button,
       mojo::PendingRemote<blink::mojom::PictureInPictureSessionObserver>,
       StartSessionCallback) final;
 
diff --git a/content/browser/picture_in_picture/picture_in_picture_service_impl_unittest.cc b/content/browser/picture_in_picture/picture_in_picture_service_impl_unittest.cc
index b0b4520..ce37baa 100644
--- a/content/browser/picture_in_picture/picture_in_picture_service_impl_unittest.cc
+++ b/content/browser/picture_in_picture/picture_in_picture_service_impl_unittest.cc
@@ -72,7 +72,6 @@
   }
   void SetPlaybackState(PlaybackState playback_state) override {}
   void SetAlwaysHidePlayPauseButton(bool is_visible) override {}
-  void SetMutedState(MutedState muted_state) override {}
   void SetSkipAdButtonVisibility(bool is_visible) override {}
   void SetNextTrackButtonVisibility(bool is_visible) override {}
   void SetPreviousTrackButtonVisibility(bool is_visible) override {}
@@ -162,8 +161,7 @@
 
   service().StartSession(
       kPlayerVideoOnlyId, surface_id, gfx::Size(42, 42),
-      true /* show_play_pause_button */, true /* show_mute_button */,
-      std::move(observer_remote),
+      true /* show_play_pause_button */, std::move(observer_remote),
       base::BindLambdaForTesting(
           [&](mojo::PendingRemote<blink::mojom::PictureInPictureSession> remote,
               const gfx::Size& b) {
@@ -205,8 +203,7 @@
 
   service().StartSession(
       kPlayerVideoOnlyId, surface_id, gfx::Size(42, 42),
-      true /* show_play_pause_button */, true /* show_mute_button */,
-      std::move(observer_remote),
+      true /* show_play_pause_button */, std::move(observer_remote),
       base::BindLambdaForTesting(
           [&](mojo::PendingRemote<blink::mojom::PictureInPictureSession> remote,
               const gfx::Size& b) {
diff --git a/content/browser/picture_in_picture/picture_in_picture_session.cc b/content/browser/picture_in_picture/picture_in_picture_session.cc
index 99cba809..0fab46b 100644
--- a/content/browser/picture_in_picture/picture_in_picture_session.cc
+++ b/content/browser/picture_in_picture/picture_in_picture_session.cc
@@ -18,7 +18,6 @@
     const base::Optional<viz::SurfaceId>& surface_id,
     const gfx::Size& natural_size,
     bool show_play_pause_button,
-    bool show_mute_button,
     mojo::PendingReceiver<blink::mojom::PictureInPictureSession> receiver,
     mojo::PendingRemote<blink::mojom::PictureInPictureSessionObserver> observer,
     gfx::Size* window_size)
@@ -32,7 +31,6 @@
   GetController().SetActiveSession(this);
   GetController().EmbedSurface(surface_id.value(), natural_size);
   GetController().SetAlwaysHidePlayPauseButton(show_play_pause_button);
-  GetController().SetAlwaysHideMuteButton(show_mute_button);
   GetController().Show();
 
   *window_size = GetController().GetSize();
@@ -50,13 +48,11 @@
     uint32_t player_id,
     const base::Optional<viz::SurfaceId>& surface_id,
     const gfx::Size& natural_size,
-    bool show_play_pause_button,
-    bool show_mute_button) {
+    bool show_play_pause_button) {
   player_id_ = MediaPlayerId(service_->render_frame_host_, player_id);
 
   GetController().EmbedSurface(surface_id.value(), natural_size);
   GetController().SetAlwaysHidePlayPauseButton(show_play_pause_button);
-  GetController().SetAlwaysHideMuteButton(show_mute_button);
   GetController().SetActiveSession(this);
 }
 
diff --git a/content/browser/picture_in_picture/picture_in_picture_session.h b/content/browser/picture_in_picture/picture_in_picture_session.h
index fe080c9..d1030e5 100644
--- a/content/browser/picture_in_picture/picture_in_picture_session.h
+++ b/content/browser/picture_in_picture/picture_in_picture_session.h
@@ -33,7 +33,6 @@
       const base::Optional<viz::SurfaceId>& surface_id,
       const gfx::Size& natural_size,
       bool show_play_pause_button,
-      bool show_mute_button,
       mojo::PendingReceiver<blink::mojom::PictureInPictureSession> receiver,
       mojo::PendingRemote<blink::mojom::PictureInPictureSessionObserver>
           observer,
@@ -45,8 +44,7 @@
   void Update(uint32_t player_id,
               const base::Optional<viz::SurfaceId>& surface_id,
               const gfx::Size& natural_size,
-              bool show_play_pause_button,
-              bool show_mute_button) final;
+              bool show_play_pause_button) final;
 
   void NotifyWindowResized(const gfx::Size& size);
 
diff --git a/content/browser/picture_in_picture/picture_in_picture_window_controller_impl.cc b/content/browser/picture_in_picture/picture_in_picture_window_controller_impl.cc
index 0b609df..84fc728 100644
--- a/content/browser/picture_in_picture/picture_in_picture_window_controller_impl.cc
+++ b/content/browser/picture_in_picture/picture_in_picture_window_controller_impl.cc
@@ -201,34 +201,10 @@
   return true /* playing */;
 }
 
-void PictureInPictureWindowControllerImpl::UpdateMutedState() {
-  if (!window_)
-    return;
-
-  if (always_hide_mute_button_) {
-    window_->SetMutedState(OverlayWindow::MutedState::kNoAudio);
-    return;
-  }
-
-  window_->SetMutedState(IsPlayerMuted() ? OverlayWindow::MutedState::kMuted
-                                         : OverlayWindow::MutedState::kUnmuted);
-}
-
-bool PictureInPictureWindowControllerImpl::ToggleMute() {
-  DCHECK(window_);
-
-  bool new_muted_status = !IsPlayerMuted();
-  media_player_id_->render_frame_host->Send(new MediaPlayerDelegateMsg_Muted(
-      media_player_id_->render_frame_host->GetRoutingID(),
-      media_player_id_->delegate_id, new_muted_status));
-  return new_muted_status;
-}
-
 void PictureInPictureWindowControllerImpl::UpdateMediaPlayerId() {
   media_player_id_ =
       active_session_ ? active_session_->player_id() : base::nullopt;
   UpdatePlaybackState(IsPlayerActive(), !media_player_id_.has_value());
-  UpdateMutedState();
 }
 
 void PictureInPictureWindowControllerImpl::SetActiveSession(
@@ -248,12 +224,6 @@
   UpdatePlayPauseButtonVisibility();
 }
 
-void PictureInPictureWindowControllerImpl::SetAlwaysHideMuteButton(
-    bool is_visible) {
-  always_hide_mute_button_ = !is_visible;
-  UpdateMutedState();
-}
-
 void PictureInPictureWindowControllerImpl::SkipAd() {
   if (media_session_action_skip_ad_handled_)
     MediaSession::Get(initiator_)->SkipAd();
@@ -317,7 +287,6 @@
     return;
 
   UpdatePlaybackState(true /* is_playing */, false /* reached_end_of_stream */);
-  UpdateMutedState();
 }
 
 void PictureInPictureWindowControllerImpl::MediaStoppedPlaying(
@@ -335,58 +304,6 @@
       reason == WebContentsObserver::MediaStoppedReason::kReachedEndOfStream);
 }
 
-void PictureInPictureWindowControllerImpl::MediaMutedStatusChanged(
-    const MediaPlayerId& media_player_id,
-    bool muted) {
-  if (initiator_->IsBeingDestroyed())
-    return;
-
-  if (muted)
-    AddMutedPlayerEntry(media_player_id);
-  else
-    RemoveMutedPlayerEntry(media_player_id);
-
-  if (media_player_id_ == media_player_id)
-    UpdateMutedState();
-}
-
-void PictureInPictureWindowControllerImpl::AddMutedPlayerEntry(
-    const MediaPlayerId& id) {
-  muted_players_[id.render_frame_host].insert(id.delegate_id);
-}
-
-bool PictureInPictureWindowControllerImpl::RemoveMutedPlayerEntry(
-    const MediaPlayerId& id) {
-  auto it = muted_players_.find(id.render_frame_host);
-  if (it == muted_players_.end())
-    return false;
-
-  // Remove the player.
-  bool did_remove = it->second.erase(id.delegate_id) == 1;
-  if (!did_remove)
-    return false;
-
-  // If there are no players left, remove the entry.
-  if (it->second.empty())
-    muted_players_.erase(it);
-
-  return true;
-}
-
-bool PictureInPictureWindowControllerImpl::IsPlayerMuted() {
-  // At creation time, the player id may not be set.
-  if (!media_player_id_.has_value())
-    return false;
-
-  const auto& players =
-      muted_players_.find(media_player_id_->render_frame_host);
-  if (players == muted_players_.end())
-    return false;
-
-  return players->second.find(media_player_id_->delegate_id) !=
-         players->second.end();
-}
-
 void PictureInPictureWindowControllerImpl::OnLeavingPictureInPicture(
     bool should_pause_video) {
   if (IsPlayerActive() && should_pause_video) {
diff --git a/content/browser/picture_in_picture/picture_in_picture_window_controller_impl.h b/content/browser/picture_in_picture/picture_in_picture_window_controller_impl.h
index 4b918964..9e04efb 100644
--- a/content/browser/picture_in_picture/picture_in_picture_window_controller_impl.h
+++ b/content/browser/picture_in_picture/picture_in_picture_window_controller_impl.h
@@ -43,7 +43,6 @@
   ~PictureInPictureWindowControllerImpl() override;
 
   using PlayerSet = std::set<int>;
-  using MutedMediaPlayerMap = std::map<RenderFrameHost*, PlayerSet>;
 
   // PictureInPictureWindowController:
   CONTENT_EXPORT void Show() override;
@@ -53,15 +52,11 @@
   CONTENT_EXPORT OverlayWindow* GetWindowForTesting() override;
   CONTENT_EXPORT void UpdateLayerBounds() override;
   CONTENT_EXPORT bool IsPlayerActive() override;
-  CONTENT_EXPORT bool IsPlayerMuted() override;
   CONTENT_EXPORT WebContents* GetInitiatorWebContents() override;
   CONTENT_EXPORT bool TogglePlayPause() override;
-  CONTENT_EXPORT bool ToggleMute() override;
   CONTENT_EXPORT void UpdatePlaybackState(bool is_playing,
                                           bool reached_end_of_stream) override;
-  CONTENT_EXPORT void UpdateMutedState() override;
   CONTENT_EXPORT void SetAlwaysHidePlayPauseButton(bool is_visible) override;
-  CONTENT_EXPORT void SetAlwaysHideMuteButton(bool is_visible) override;
   CONTENT_EXPORT void SkipAd() override;
   CONTENT_EXPORT void NextTrack() override;
   CONTENT_EXPORT void PreviousTrack() override;
@@ -77,7 +72,6 @@
   void MediaStoppedPlaying(const MediaPlayerInfo&,
                            const MediaPlayerId&,
                            WebContentsObserver::MediaStoppedReason) override;
-  void MediaMutedStatusChanged(const MediaPlayerId&, bool muted) override;
 
   // TODO(mlamouri): temporary method used because of the media player id is
   // stored in a different location from the one that is used to update the
@@ -118,10 +112,6 @@
   // always_hide_play_pause_button_ is false.
   void UpdatePlayPauseButtonVisibility();
 
-  // Used to add/remove a muted player entry to |muted_players_|.
-  void AddMutedPlayerEntry(const MediaPlayerId& id);
-  bool RemoveMutedPlayerEntry(const MediaPlayerId& id);
-
   std::unique_ptr<OverlayWindow> window_;
 
   // TODO(929156): remove this as it should be accessible via `web_contents()`.
@@ -134,9 +124,6 @@
 
   viz::SurfaceId surface_id_;
 
-  // Used to track the muted state of all players.
-  MutedMediaPlayerMap muted_players_;
-
   // Used to show/hide some actions in Picture-in-Picture window. These are set
   // to true when website handles some Media Session actions.
   bool media_session_action_play_handled_ = false;
@@ -150,10 +137,6 @@
   // Session API in UpdatePlayPauseButtonVisibility().
   bool always_hide_play_pause_button_ = false;
 
-  // Used to hide mute button if video has no audio track or if MuteButton
-  // origin trial is disabled.
-  bool always_hide_mute_button_ = false;
-
   // Session currently associated with the Picture-in-Picture window. The
   // session object makes the bridge with the renderer process by handling
   // requests and holding states such as the active player id.
diff --git a/content/browser/renderer_host/render_widget_host_view_event_handler.cc b/content/browser/renderer_host/render_widget_host_view_event_handler.cc
index 6074939..f452b49 100644
--- a/content/browser/renderer_host/render_widget_host_view_event_handler.cc
+++ b/content/browser/renderer_host/render_widget_host_view_event_handler.cc
@@ -75,12 +75,7 @@
 // DefWindowProc so it can generate WM_APPCOMMAND as necessary.
 bool ShouldGenerateAppCommand(const ui::MouseEvent* event) {
 #if defined(OS_WIN)
-  switch (event->native_event().message) {
-    case WM_XBUTTONUP:
-      return !base::FeatureList::IsEnabled(features::kExtendedMouseButtons);
-    case WM_NCXBUTTONUP:
-      return true;
-  }
+  return (event->native_event().message == WM_NCXBUTTONUP);
 #endif
   return false;
 }
@@ -628,7 +623,7 @@
     case WM_XBUTTONDOWN:
     case WM_XBUTTONUP:
     case WM_XBUTTONDBLCLK:
-      return base::FeatureList::IsEnabled(features::kExtendedMouseButtons);
+      return true;
     case WM_NCMOUSELEAVE:
     case WM_NCMOUSEMOVE:
     case WM_NCLBUTTONDOWN:
@@ -647,22 +642,6 @@
     default:
       break;
   }
-#elif defined(USE_X11)
-  if (!base::FeatureList::IsEnabled(features::kExtendedMouseButtons)) {
-    // Renderer only supports standard mouse buttons, so ignore programmable
-    // buttons.
-    switch (event->type()) {
-      case ui::ET_MOUSE_PRESSED:
-      case ui::ET_MOUSE_RELEASED: {
-        const int kAllowedButtons = ui::EF_LEFT_MOUSE_BUTTON |
-                                    ui::EF_MIDDLE_MOUSE_BUTTON |
-                                    ui::EF_RIGHT_MOUSE_BUTTON;
-        return (event->flags() & kAllowedButtons) != 0;
-      }
-      default:
-        break;
-    }
-  }
 #endif
   return true;
 }
diff --git a/content/browser/sms/sms_browsertest.cc b/content/browser/sms/sms_browsertest.cc
index f5b1a4d..3a187766 100644
--- a/content/browser/sms/sms_browsertest.cc
+++ b/content/browser/sms/sms_browsertest.cc
@@ -95,8 +95,7 @@
 
 }  // namespace
 
-// Flaky. crbug.com/997549
-IN_PROC_BROWSER_TEST_F(SmsBrowserTest, DISABLED_Receive) {
+IN_PROC_BROWSER_TEST_F(SmsBrowserTest, Receive) {
   GURL url = GetTestUrl(nullptr, "simple_page.html");
   NavigateToURL(shell(), url);
 
@@ -124,15 +123,21 @@
     provider->NotifyReceive(url::Origin::Create(url), "hello");
   }));
 
+  // Wait for UKM to be recorded to avoid race condition.
+  base::RunLoop ukm_loop;
+  ukm_recorder()->SetOnAddEntryCallback(Entry::kEntryName,
+                                        ukm_loop.QuitClosure());
+
   EXPECT_EQ("hello", EvalJs(shell(), script));
 
+  ukm_loop.Run();
+
   ASSERT_FALSE(provider->HasObservers());
 
   ExpectOutcomeUKM(url, blink::SMSReceiverOutcome::kSuccess);
 }
 
-// Flaky. crbug.com/997549
-IN_PROC_BROWSER_TEST_F(SmsBrowserTest, DISABLED_AtMostOnePendingSmsRequest) {
+IN_PROC_BROWSER_TEST_F(SmsBrowserTest, AtMostOnePendingSmsRequest) {
   GURL url = GetTestUrl(nullptr, "simple_page.html");
   NavigateToURL(shell(), url);
 
@@ -159,23 +164,35 @@
     loop.Quit();
   }));
 
+  // Wait for UKM to be recorded to avoid race condition.
+  base::RunLoop ukm_loop1;
+  ukm_recorder()->SetOnAddEntryCallback(Entry::kEntryName,
+                                        ukm_loop1.QuitClosure());
+
   EXPECT_EQ("AbortError", EvalJs(shell(), script));
 
+  loop.Run();
+  ukm_loop1.Run();
+
   ExpectOutcomeUKM(url, blink::SMSReceiverOutcome::kCancelled);
 
-  loop.Run();
+  // Wait for UKM to be recorded to avoid race condition.
+  base::RunLoop ukm_loop2;
+  ukm_recorder()->SetOnAddEntryCallback(Entry::kEntryName,
+                                        ukm_loop2.QuitClosure());
 
   provider->NotifyReceive(url::Origin::Create(url), "hello");
 
   EXPECT_EQ("hello", EvalJs(shell(), "first"));
 
+  ukm_loop2.Run();
+
   ASSERT_FALSE(provider->HasObservers());
 
   ExpectOutcomeUKM(url, blink::SMSReceiverOutcome::kSuccess);
 }
 
-// Flaky. crbug.com/997549
-IN_PROC_BROWSER_TEST_F(SmsBrowserTest, DISABLED_Reload) {
+IN_PROC_BROWSER_TEST_F(SmsBrowserTest, Reload) {
   GURL url = GetTestUrl(nullptr, "simple_page.html");
   NavigateToURL(shell(), url);
 
@@ -206,7 +223,6 @@
 
   // Wait for UKM to be recorded to avoid race condition.
   base::RunLoop ukm_loop;
-
   ukm_recorder()->SetOnAddEntryCallback(Entry::kEntryName,
                                         ukm_loop.QuitClosure());
 
@@ -252,8 +268,7 @@
   ExpectNoOutcomeUKM();
 }
 
-// Flaky. crbug.com/997549
-IN_PROC_BROWSER_TEST_F(SmsBrowserTest, DISABLED_TwoTabsSameOrigin) {
+IN_PROC_BROWSER_TEST_F(SmsBrowserTest, TwoTabsSameOrigin) {
   auto* provider = new NiceMock<MockSmsProvider>();
   BrowserMainLoop::GetInstance()->SetSmsProviderForTesting(
       base::WrapUnique(provider));
@@ -307,6 +322,7 @@
 
   {
     base::RunLoop loop;
+    base::RunLoop ukm_loop;
 
     EXPECT_CALL(delegate_, CreateSmsPrompt(_, _, _, _))
         .WillOnce(
@@ -316,20 +332,27 @@
               loop.Quit();
             }));
 
+    // Wait for UKM to be recorded to avoid race condition.
+    ukm_recorder()->SetOnAddEntryCallback(Entry::kEntryName,
+                                          ukm_loop.QuitClosure());
+
     provider->NotifyReceive(url::Origin::Create(url), "hello1");
 
     loop.Run();
+    ukm_loop.Run();
   }
 
   EXPECT_EQ("hello1", EvalJs(tab1, "sms"));
 
   ASSERT_TRUE(provider->HasObservers());
 
+  ExpectOutcomeUKM(url, blink::SMSReceiverOutcome::kSuccess);
+
+  ukm_recorder()->Purge();
+
   {
     base::RunLoop loop;
-    ExpectOutcomeUKM(url, blink::SMSReceiverOutcome::kSuccess);
-
-    ukm_recorder()->Purge();
+    base::RunLoop ukm_loop;
 
     EXPECT_CALL(delegate_, CreateSmsPrompt(_, _, _, _))
         .WillOnce(
@@ -339,9 +362,14 @@
               loop.Quit();
             }));
 
+    // Wait for UKM to be recorded to avoid race condition.
+    ukm_recorder()->SetOnAddEntryCallback(Entry::kEntryName,
+                                          ukm_loop.QuitClosure());
+
     provider->NotifyReceive(url::Origin::Create(url), "hello2");
 
     loop.Run();
+    ukm_loop.Run();
   }
 
   EXPECT_EQ("hello2", EvalJs(tab2, "sms"));
@@ -351,8 +379,7 @@
   ExpectOutcomeUKM(url, blink::SMSReceiverOutcome::kSuccess);
 }
 
-// Flaky. crbug.com/997549
-IN_PROC_BROWSER_TEST_F(SmsBrowserTest, DISABLED_TwoTabsDifferentOrigin) {
+IN_PROC_BROWSER_TEST_F(SmsBrowserTest, TwoTabsDifferentOrigin) {
   auto* provider = new NiceMock<MockSmsProvider>();
   BrowserMainLoop::GetInstance()->SetSmsProviderForTesting(
       base::WrapUnique(provider));
@@ -396,6 +423,7 @@
 
   {
     base::RunLoop loop;
+    base::RunLoop ukm_loop;
     EXPECT_CALL(delegate_, CreateSmsPrompt(_, _, _, _))
         .WillOnce(
             Invoke([&loop](RenderFrameHost*, const url::Origin&,
@@ -403,8 +431,12 @@
               std::move(on_confirm).Run();
               loop.Quit();
             }));
+    // Wait for UKM to be recorded to avoid race condition.
+    ukm_recorder()->SetOnAddEntryCallback(Entry::kEntryName,
+                                          ukm_loop.QuitClosure());
     provider->NotifyReceive(url::Origin::Create(url1), "hello1");
     loop.Run();
+    ukm_loop.Run();
   }
 
   EXPECT_EQ("hello1", EvalJs(tab1, "sms"));
@@ -413,6 +445,7 @@
 
   {
     base::RunLoop loop;
+    base::RunLoop ukm_loop;
     EXPECT_CALL(delegate_, CreateSmsPrompt(_, _, _, _))
         .WillOnce(
             Invoke([&loop](RenderFrameHost*, const url::Origin&,
@@ -420,8 +453,12 @@
               std::move(on_confirm).Run();
               loop.Quit();
             }));
+    // Wait for UKM to be recorded to avoid race condition.
+    ukm_recorder()->SetOnAddEntryCallback(Entry::kEntryName,
+                                          ukm_loop.QuitClosure());
     provider->NotifyReceive(url::Origin::Create(url2), "hello2");
     loop.Run();
+    ukm_loop.Run();
   }
 
   EXPECT_EQ("hello2", EvalJs(tab2, "sms"));
@@ -463,8 +500,7 @@
   ExpectNoOutcomeUKM();
 }
 
-// Flaky. crbug.com/997549
-IN_PROC_BROWSER_TEST_F(SmsBrowserTest, DISABLED_Cancels) {
+IN_PROC_BROWSER_TEST_F(SmsBrowserTest, Cancels) {
   GURL url = GetTestUrl(nullptr, "simple_page.html");
   NavigateToURL(shell(), url);
 
@@ -475,6 +511,7 @@
   shell()->web_contents()->SetDelegate(&delegate_);
 
   base::RunLoop loop;
+  base::RunLoop ukm_loop;
 
   EXPECT_CALL(delegate_, CreateSmsPrompt(_, _, _, _))
       .WillOnce(Invoke([&loop](RenderFrameHost*, const url::Origin&,
@@ -488,6 +525,10 @@
     provider->NotifyReceive(url::Origin::Create(url), "hello");
   }));
 
+  // Wait for UKM to be recorded to avoid race condition.
+  ukm_recorder()->SetOnAddEntryCallback(Entry::kEntryName,
+                                        ukm_loop.QuitClosure());
+
   std::string script = R"(
     navigator.sms.receive({timeout: 60}).catch(({name}) => {
       error = name;
@@ -498,6 +539,7 @@
   EXPECT_EQ(true, EvalJs(shell(), script));
 
   loop.Run();
+  ukm_loop.Run();
 
   EXPECT_EQ("AbortError", EvalJs(shell(), "error"));
 
diff --git a/content/browser/theme_helper_mac.mm b/content/browser/theme_helper_mac.mm
index 8bb37de..8ccfbb9 100644
--- a/content/browser/theme_helper_mac.mm
+++ b/content/browser/theme_helper_mac.mm
@@ -52,14 +52,27 @@
   NSUserDefaults* defaults = [NSUserDefaults standardUserDefaults];
   [defaults synchronize];
 
+  // NSScrollerButtonDelay and NSScrollerButtonPeriod are no longer initialized
+  // in +[NSApplication _initializeRegisteredDefaults] as of 10.15. Their values
+  // still seem to affect behavior, but their use is logged as an "unusual app
+  // config", so it's not clear how much longer they'll be implemented.
+  params->has_initial_button_delay =
+      [defaults objectForKey:@"NSScrollerButtonDelay"] != nil;
   params->initial_button_delay =
       [defaults floatForKey:@"NSScrollerButtonDelay"];
+  params->has_autoscroll_button_delay =
+      [defaults objectForKey:@"NSScrollerButtonPeriod"] != nil;
   params->autoscroll_button_delay =
       [defaults floatForKey:@"NSScrollerButtonPeriod"];
   params->jump_on_track_click =
       [defaults boolForKey:@"AppleScrollerPagingBehavior"];
   params->preferred_scroller_style =
       ThemeHelperMac::GetPreferredScrollerStyle();
+
+  // One one hand, this constant isn't registered anywhere. On the other hand,
+  // this constant is still (as of 10.15) being used by AppKit to draw controls.
+  // On the other other hand, this value sent over the wire is actually ignored.
+  // TODO(https://crbug.com/997934): Figure out why it's being ignored.
   params->button_placement = GetButtonPlacement();
 
   id rubber_band_value = [defaults objectForKey:@"NSScrollViewRubberbanding"];
diff --git a/content/browser/wake_lock/wake_lock_context_host.cc b/content/browser/wake_lock/wake_lock_context_host.cc
index e5088822e..805c006 100644
--- a/content/browser/wake_lock/wake_lock_context_host.cc
+++ b/content/browser/wake_lock/wake_lock_context_host.cc
@@ -40,7 +40,7 @@
     connector->BindInterface(device::mojom::kServiceName,
                              mojo::MakeRequest(&wake_lock_provider));
     wake_lock_provider->GetWakeLockContextForID(
-        id_, mojo::MakeRequest(&wake_lock_context_));
+        id_, wake_lock_context_.BindNewPipeAndPassReceiver());
   }
 }
 
diff --git a/content/browser/wake_lock/wake_lock_context_host.h b/content/browser/wake_lock/wake_lock_context_host.h
index 4100e3c..005d0c5 100644
--- a/content/browser/wake_lock/wake_lock_context_host.h
+++ b/content/browser/wake_lock/wake_lock_context_host.h
@@ -6,6 +6,7 @@
 #define CONTENT_BROWSER_WAKE_LOCK_WAKE_LOCK_CONTEXT_HOST_H_
 
 #include "content/public/browser/web_contents.h"
+#include "mojo/public/cpp/bindings/remote.h"
 #include "services/device/public/mojom/wake_lock_context.mojom.h"
 #include "services/device/public/mojom/wake_lock_provider.mojom.h"
 #include "ui/gfx/native_widget_types.h"
@@ -27,7 +28,7 @@
 
   // Returns the WakeLockContext* to which this instance is connected.
   device::mojom::WakeLockContext* GetWakeLockContext() {
-    return wake_lock_context_.get();
+    return wake_lock_context_ ? wake_lock_context_.get() : nullptr;
   }
 
  private:
@@ -38,7 +39,7 @@
   WebContents* web_contents_;
 
   // The WakeLockContext instance that is connected to this instance.
-  device::mojom::WakeLockContextPtr wake_lock_context_;
+  mojo::Remote<device::mojom::WakeLockContext> wake_lock_context_;
 
   DISALLOW_COPY_AND_ASSIGN(WakeLockContextHost);
 };
diff --git a/content/common/renderer.mojom b/content/common/renderer.mojom
index fb2de84..3750287 100644
--- a/content/common/renderer.mojom
+++ b/content/common/renderer.mojom
@@ -148,12 +148,21 @@
 };
 
 struct UpdateScrollbarThemeParams {
+  // TODO(avi): Update these to optional values when optional numeric types are
+  // allowed. (https://crbug.com/657632)
+  bool has_initial_button_delay;
   float initial_button_delay;
+  bool has_autoscroll_button_delay;
   float autoscroll_button_delay;
+
   bool jump_on_track_click;
   ScrollerStyle preferred_scroller_style;
   bool redraw;
+
+  // TODO(https://crbug.com/997934): This value is ignored on the receiving end.
+  // Either remove it, or make it not be ignored.
   ScrollbarButtonsPlacement button_placement;
+
   bool scroll_view_rubber_banding;
 };
 
diff --git a/content/public/browser/overlay_window.h b/content/public/browser/overlay_window.h
index 8b3248e..26df3fc 100644
--- a/content/public/browser/overlay_window.h
+++ b/content/public/browser/overlay_window.h
@@ -37,12 +37,6 @@
     kEndOfVideo,
   };
 
-  enum MutedState {
-    kMuted = 0,
-    kUnmuted,
-    kNoAudio,
-  };
-
   OverlayWindow() = default;
   virtual ~OverlayWindow() = default;
 
@@ -62,7 +56,6 @@
   virtual void UpdateVideoSize(const gfx::Size& natural_size) = 0;
   virtual void SetPlaybackState(PlaybackState playback_state) = 0;
   virtual void SetAlwaysHidePlayPauseButton(bool is_visible) = 0;
-  virtual void SetMutedState(MutedState muted_state) = 0;
   virtual void SetSkipAdButtonVisibility(bool is_visible) = 0;
   virtual void SetNextTrackButtonVisibility(bool is_visible) = 0;
   virtual void SetPreviousTrackButtonVisibility(bool is_visible) = 0;
diff --git a/content/public/browser/picture_in_picture_window_controller.h b/content/public/browser/picture_in_picture_window_controller.h
index 884eabc..f7c80a3f 100644
--- a/content/public/browser/picture_in_picture_window_controller.h
+++ b/content/public/browser/picture_in_picture_window_controller.h
@@ -43,13 +43,10 @@
   virtual OverlayWindow* GetWindowForTesting() = 0;
   virtual void UpdateLayerBounds() = 0;
   virtual bool IsPlayerActive() = 0;
-  virtual bool IsPlayerMuted() = 0;
   virtual WebContents* GetInitiatorWebContents() = 0;
   virtual void UpdatePlaybackState(bool is_playing,
                                    bool reached_end_of_stream) = 0;
-  virtual void UpdateMutedState() = 0;
   virtual void SetAlwaysHidePlayPauseButton(bool is_visible) = 0;
-  virtual void SetAlwaysHideMuteButton(bool is_visible) = 0;
 
   // Called when the user interacts with the "Skip Ad" control.
   virtual void SkipAd() = 0;
@@ -65,9 +62,6 @@
   // call.
   virtual bool TogglePlayPause() = 0;
 
-  // Returns true if the player is muted after this call.
-  virtual bool ToggleMute() = 0;
-
  protected:
   // Use PictureInPictureWindowController::GetOrCreateForWebContents() to
   // create an instance.
diff --git a/content/public/common/content_features.cc b/content/public/common/content_features.cc
index 4c942a6..d71a8f7 100644
--- a/content/public/common/content_features.cc
+++ b/content/public/common/content_features.cc
@@ -136,10 +136,6 @@
 const base::Feature kExpensiveBackgroundTimerThrottling{
     "ExpensiveBackgroundTimerThrottling", base::FEATURE_ENABLED_BY_DEFAULT};
 
-// Enables exposing back/forward mouse buttons to the renderer and the web.
-const base::Feature kExtendedMouseButtons{"ExtendedMouseButtons",
-                                          base::FEATURE_ENABLED_BY_DEFAULT};
-
 // When enabled Feature Policy propagation is similar to sandbox flags and,
 // sandbox flags are implemented on top of Feature Policy.
 const base::Feature kFeaturePolicyForSandbox{"FeaturePolicyForSandbox",
diff --git a/content/public/common/content_features.h b/content/public/common/content_features.h
index 95331fd7..9fb9214 100644
--- a/content/public/common/content_features.h
+++ b/content/public/common/content_features.h
@@ -40,7 +40,6 @@
 CONTENT_EXPORT extern const base::Feature kExperimentalAccessibilityLabels;
 CONTENT_EXPORT extern const base::Feature kExperimentalProductivityFeatures;
 CONTENT_EXPORT extern const base::Feature kExpensiveBackgroundTimerThrottling;
-CONTENT_EXPORT extern const base::Feature kExtendedMouseButtons;
 CONTENT_EXPORT extern const base::Feature kFeaturePolicyForSandbox;
 CONTENT_EXPORT extern const base::Feature kFontSrcLocalMatching;
 CONTENT_EXPORT extern const base::Feature kFractionalScrollOffsets;
diff --git a/content/renderer/BUILD.gn b/content/renderer/BUILD.gn
index db56b91..5c40e46 100644
--- a/content/renderer/BUILD.gn
+++ b/content/renderer/BUILD.gn
@@ -208,7 +208,6 @@
     "media/webrtc/peer_connection_tracker.h",
     "media/webrtc/rtc_certificate_generator.cc",
     "media/webrtc/rtc_certificate_generator.h",
-    "media/webrtc/rtc_event_log_output_sink.h",
     "media/webrtc/rtc_event_log_output_sink_proxy.cc",
     "media/webrtc/rtc_event_log_output_sink_proxy.h",
     "media/webrtc/rtc_peer_connection_handler.cc",
@@ -217,8 +216,6 @@
     "media/webrtc/rtc_rtp_receiver.h",
     "media/webrtc/rtc_rtp_sender.cc",
     "media/webrtc/rtc_rtp_sender.h",
-    "media/webrtc/rtc_rtp_source.cc",
-    "media/webrtc/rtc_rtp_source.h",
     "media/webrtc/rtc_rtp_transceiver.cc",
     "media/webrtc/rtc_rtp_transceiver.h",
     "media/webrtc/rtc_stats.cc",
diff --git a/content/renderer/input/render_widget_input_handler.cc b/content/renderer/input/render_widget_input_handler.cc
index 54392d8..04f26da 100644
--- a/content/renderer/input/render_widget_input_handler.cc
+++ b/content/renderer/input/render_widget_input_handler.cc
@@ -227,6 +227,12 @@
 viz::FrameSinkId RenderWidgetInputHandler::GetFrameSinkIdAtPoint(
     const gfx::PointF& point,
     gfx::PointF* local_point) {
+  // This method must only be called on a local root, which is guaranteed to
+  // have a WebWidget.
+  // TODO(https://crbug.com/995981): Eventually we should be able to remote this
+  // DCHECK, since RenderWidget's lifetime [and thus this instance's] will be
+  // synchronized with the WebWidget.
+  DCHECK(widget_->GetWebWidget());
   gfx::PointF point_in_pixel(point);
   if (widget_->compositor_deps()->IsUseZoomForDSFEnabled()) {
     point_in_pixel = gfx::ConvertPointToPixel(
@@ -264,6 +270,13 @@
 
 WebInputEventResult RenderWidgetInputHandler::HandleTouchEvent(
     const blink::WebCoalescedInputEvent& coalesced_event) {
+  // This method must only be called on non-frozen RenderWidget, which is
+  // guaranteed to have a WebWidget.
+  // TODO(https://crbug.com/995981): Eventually we should be able to remote this
+  // DCHECK, since RenderWidget's lifetime [and thus this instance's] will be
+  // synchronized with the WebWidget.
+  DCHECK(widget_->GetWebWidget());
+
   const WebInputEvent& input_event = coalesced_event.Event();
 
   if (input_event.GetType() == WebInputEvent::kTouchScrollStarted) {
@@ -296,6 +309,13 @@
     const blink::WebCoalescedInputEvent& coalesced_event,
     const ui::LatencyInfo& latency_info,
     HandledEventCallback callback) {
+  // This method must only be called on non-frozen RenderWidget, which is
+  // guaranteed to have a WebWidget.
+  // TODO(https://crbug.com/995981): Eventually we should be able to remote this
+  // DCHECK, since RenderWidget's lifetime [and thus this instance's] will be
+  // synchronized with the WebWidget.
+  DCHECK(widget_->GetWebWidget());
+
   const WebInputEvent& input_event = coalesced_event.Event();
   base::AutoReset<bool> handling_input_event_resetter(&handling_input_event_,
                                                       true);
@@ -583,6 +603,13 @@
     std::vector<InjectScrollGestureParams> injected_scroll_params,
     const WebInputEvent& input_event,
     const ui::LatencyInfo& original_latency_info) {
+  // This method must only be called on non-frozen RenderWidget, which is
+  // guaranteed to have a WebWidget.
+  // TODO(https://crbug.com/995981): Eventually we should be able to remote this
+  // DCHECK, since RenderWidget's lifetime [and thus this instance's] will be
+  // synchronized with the WebWidget.
+  DCHECK(widget_->GetWebWidget());
+
   DCHECK(injected_scroll_params.size());
 
   base::TimeTicks original_timestamp;
diff --git a/content/renderer/media/webrtc/rtc_event_log_output_sink.h b/content/renderer/media/webrtc/rtc_event_log_output_sink.h
deleted file mode 100644
index b902c687..0000000
--- a/content/renderer/media/webrtc/rtc_event_log_output_sink.h
+++ /dev/null
@@ -1,21 +0,0 @@
-// Copyright (c) 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CONTENT_RENDERER_MEDIA_WEBRTC_RTC_EVENT_LOG_OUTPUT_SINK_H_
-#define CONTENT_RENDERER_MEDIA_WEBRTC_RTC_EVENT_LOG_OUTPUT_SINK_H_
-
-#include <string>
-
-namespace content {
-
-class RtcEventLogOutputSink {
- public:
-  virtual ~RtcEventLogOutputSink() = default;
-
-  virtual void OnWebRtcEventLogWrite(const std::string& output) = 0;
-};
-
-}  // namespace content
-
-#endif  // CONTENT_RENDERER_MEDIA_WEBRTC_RTC_EVENT_LOG_OUTPUT_SINK_H_
diff --git a/content/renderer/media/webrtc/rtc_event_log_output_sink_proxy.cc b/content/renderer/media/webrtc/rtc_event_log_output_sink_proxy.cc
index c9fd9e9..f6e9c0fb 100644
--- a/content/renderer/media/webrtc/rtc_event_log_output_sink_proxy.cc
+++ b/content/renderer/media/webrtc/rtc_event_log_output_sink_proxy.cc
@@ -8,7 +8,7 @@
 namespace content {
 
 RtcEventLogOutputSinkProxy::RtcEventLogOutputSinkProxy(
-    RtcEventLogOutputSink* sink)
+    blink::RtcEventLogOutputSink* sink)
     : sink_(sink) {
   CHECK(sink_);
 }
diff --git a/content/renderer/media/webrtc/rtc_event_log_output_sink_proxy.h b/content/renderer/media/webrtc/rtc_event_log_output_sink_proxy.h
index a3412d60..5ef9754d 100644
--- a/content/renderer/media/webrtc/rtc_event_log_output_sink_proxy.h
+++ b/content/renderer/media/webrtc/rtc_event_log_output_sink_proxy.h
@@ -5,14 +5,14 @@
 #ifndef CONTENT_RENDERER_MEDIA_WEBRTC_RTC_EVENT_LOG_OUTPUT_SINK_PROXY_H_
 #define CONTENT_RENDERER_MEDIA_WEBRTC_RTC_EVENT_LOG_OUTPUT_SINK_PROXY_H_
 
-#include "content/renderer/media/webrtc/rtc_event_log_output_sink.h"
+#include "third_party/blink/public/platform/modules/peerconnection/rtc_event_log_output_sink.h"
 #include "third_party/webrtc/api/rtc_event_log_output.h"
 
 namespace content {
 
 class RtcEventLogOutputSinkProxy final : public webrtc::RtcEventLogOutput {
  public:
-  RtcEventLogOutputSinkProxy(RtcEventLogOutputSink* sink);
+  RtcEventLogOutputSinkProxy(blink::RtcEventLogOutputSink* sink);
   ~RtcEventLogOutputSinkProxy() override;
 
   bool IsActive() const override;
@@ -20,7 +20,7 @@
   bool Write(const std::string& output) override;
 
  private:
-  RtcEventLogOutputSink* const sink_;
+  blink::RtcEventLogOutputSink* const sink_;
 };
 
 }  // namespace content
diff --git a/content/renderer/media/webrtc/rtc_peer_connection_handler.cc b/content/renderer/media/webrtc/rtc_peer_connection_handler.cc
index 6727fab..04239d9 100644
--- a/content/renderer/media/webrtc/rtc_peer_connection_handler.cc
+++ b/content/renderer/media/webrtc/rtc_peer_connection_handler.cc
@@ -31,7 +31,6 @@
 #include "content/public/common/content_switches.h"
 #include "content/renderer/media/webrtc/peer_connection_dependency_factory.h"
 #include "content/renderer/media/webrtc/peer_connection_tracker.h"
-#include "content/renderer/media/webrtc/rtc_event_log_output_sink.h"
 #include "content/renderer/media/webrtc/rtc_event_log_output_sink_proxy.h"
 #include "content/renderer/media/webrtc/rtc_stats.h"
 #include "content/renderer/media/webrtc/webrtc_set_description_observer.h"
@@ -39,6 +38,7 @@
 #include "media/base/media_switches.h"
 #include "third_party/blink/public/platform/modules/mediastream/web_platform_media_stream_track.h"
 #include "third_party/blink/public/platform/modules/mediastream/webrtc_uma_histograms.h"
+#include "third_party/blink/public/platform/modules/peerconnection/rtc_event_log_output_sink.h"
 #include "third_party/blink/public/platform/web_media_constraints.h"
 #include "third_party/blink/public/platform/web_rtc_answer_options.h"
 #include "third_party/blink/public/platform/web_rtc_data_channel_init.h"
@@ -810,7 +810,7 @@
 class RTCPeerConnectionHandler::Observer
     : public base::RefCountedThreadSafe<RTCPeerConnectionHandler::Observer>,
       public PeerConnectionObserver,
-      public RtcEventLogOutputSink {
+      public blink::RtcEventLogOutputSink {
  public:
   Observer(const base::WeakPtr<RTCPeerConnectionHandler>& handler,
            scoped_refptr<base::SingleThreadTaskRunner> task_runner)
diff --git a/content/renderer/media/webrtc/rtc_rtp_receiver.cc b/content/renderer/media/webrtc/rtc_rtp_receiver.cc
index 651480e4..2ad7cc7 100644
--- a/content/renderer/media/webrtc/rtc_rtp_receiver.cc
+++ b/content/renderer/media/webrtc/rtc_rtp_receiver.cc
@@ -6,9 +6,9 @@
 
 #include "base/bind.h"
 #include "base/logging.h"
-#include "content/renderer/media/webrtc/rtc_rtp_source.h"
 #include "content/renderer/media/webrtc/rtc_stats.h"
 #include "content/renderer/media/webrtc/webrtc_util.h"
+#include "third_party/blink/public/platform/web_rtc_rtp_source.h"
 #include "third_party/webrtc/api/scoped_refptr.h"
 
 namespace content {
@@ -163,7 +163,7 @@
     blink::WebVector<std::unique_ptr<blink::WebRTCRtpSource>> sources(
         webrtc_sources.size());
     for (size_t i = 0; i < webrtc_sources.size(); ++i) {
-      sources[i] = std::make_unique<RTCRtpSource>(webrtc_sources[i]);
+      sources[i] = blink::CreateRTCRtpSource(webrtc_sources[i]);
     }
     return sources;
   }
diff --git a/content/renderer/render_thread_impl.cc b/content/renderer/render_thread_impl.cc
index 47689892..fd8be9b 100644
--- a/content/renderer/render_thread_impl.cc
+++ b/content/renderer/render_thread_impl.cc
@@ -2138,7 +2138,12 @@
     mojom::UpdateScrollbarThemeParamsPtr params) {
 #if defined(OS_MACOSX)
   blink::WebScrollbarTheme::UpdateScrollbarsWithNSDefaults(
-      params->initial_button_delay, params->autoscroll_button_delay,
+      params->has_initial_button_delay
+          ? base::make_optional(params->initial_button_delay)
+          : base::nullopt,
+      params->has_autoscroll_button_delay
+          ? base::make_optional(params->autoscroll_button_delay)
+          : base::nullopt,
       params->preferred_scroller_style, params->redraw,
       params->jump_on_track_click);
 
diff --git a/content/renderer/render_widget.cc b/content/renderer/render_widget.cc
index 8db1a1a..e46ef5e 100644
--- a/content/renderer/render_widget.cc
+++ b/content/renderer/render_widget.cc
@@ -722,12 +722,6 @@
 
 void RenderWidget::OnSynchronizeVisualProperties(
     const VisualProperties& original_params) {
-  // TODO:(https://crbug.com/995981): If there is no WebWidget, then the
-  // RenderWidget should also be destroyed, and this conditional should not be
-  // necessary.
-  if (!GetWebWidget())
-    return;
-
   TRACE_EVENT0("renderer", "RenderWidget::OnSynchronizeVisualProperties");
 
   VisualProperties params = original_params;
@@ -1135,6 +1129,11 @@
 
 void RenderWidget::DoRequestNewLayerTreeFrameSink(
     LayerTreeFrameSinkCallback callback) {
+  // TODO:(https://crbug.com/995981): If there is no WebWidget, then the
+  // RenderWidget should also be destroyed, and this DCHECK should not be
+  // necessary.
+  DCHECK(GetWebWidget());
+
   // TODO(jonross): have this generated by the LayerTreeFrameSink itself, which
   // would then handle binding.
   mojom::RenderFrameMetadataObserverPtr ptr;
@@ -1572,6 +1571,10 @@
                                          browser_controls_shrink_blink_size_);
     return;
   }
+  // TODO:(https://crbug.com/995981): If there is no WebWidget, then the
+  // RenderWidget should also be destroyed, and this DCHECK should not be
+  // necessary.
+  DCHECK(GetWebWidget());
   GetWebWidget()->Resize(size);
 }
 
@@ -2564,6 +2567,15 @@
 }
 
 void RenderWidget::SetIsFullscreen(bool fullscreen) {
+  // TODO:(https://crbug.com/995981): If there is no WebWidget, then the
+  // RenderWidget should also be destroyed, and this conditional should not be
+  // necessary.
+  // We intentionally avoid setting internal state so that the next time visual
+  // properties are synchronized, state will be correctly propagated to the
+  // WebWidget.
+  if (!GetWebWidget())
+    return;
+
   if (fullscreen == is_fullscreen_granted_)
     return;
   is_fullscreen_granted_ = fullscreen;
diff --git a/content/shell/browser/web_test/web_test_content_browser_client.cc b/content/shell/browser/web_test/web_test_content_browser_client.cc
index 1a159e8..e0e6f18 100644
--- a/content/shell/browser/web_test/web_test_content_browser_client.cc
+++ b/content/shell/browser/web_test/web_test_content_browser_client.cc
@@ -74,7 +74,6 @@
   }
   void SetPlaybackState(PlaybackState playback_state) override {}
   void SetAlwaysHidePlayPauseButton(bool is_visible) override {}
-  void SetMutedState(MutedState muted_state) override {}
   void SetSkipAdButtonVisibility(bool is_visible) override {}
   void SetNextTrackButtonVisibility(bool is_visible) override {}
   void SetPreviousTrackButtonVisibility(bool is_visible) override {}
diff --git a/content/shell/test_runner/event_sender.cc b/content/shell/test_runner/event_sender.cc
index 6ae9aa6..8f95b775 100644
--- a/content/shell/test_runner/event_sender.cc
+++ b/content/shell/test_runner/event_sender.cc
@@ -733,9 +733,6 @@
       .SetMethod("setTouchCancelable", &EventSenderBindings::SetTouchCancelable)
       .SetMethod("dumpFilenameBeingDragged",
                  &EventSenderBindings::DumpFilenameBeingDragged)
-      .SetMethod("gestureFlingCancel", &EventSenderBindings::GestureFlingCancel)
-      .SetMethod("gestureFlingStart", &EventSenderBindings::GestureFlingStart)
-      .SetMethod("isFlinging", &EventSenderBindings::IsFlinging)
       .SetMethod("gestureScrollFirstPoint",
                  &EventSenderBindings::GestureScrollFirstPoint)
       .SetMethod("touchStart", &EventSenderBindings::TouchStart)
@@ -890,26 +887,6 @@
     sender_->DumpFilenameBeingDragged();
 }
 
-void EventSenderBindings::GestureFlingCancel() {
-  if (sender_)
-    sender_->GestureFlingCancel();
-}
-
-void EventSenderBindings::GestureFlingStart(float x,
-                                            float y,
-                                            float velocity_x,
-                                            float velocity_y,
-                                            gin::Arguments* args) {
-  if (sender_)
-    sender_->GestureFlingStart(x, y, velocity_x, velocity_y, args);
-}
-
-bool EventSenderBindings::IsFlinging() {
-  if (sender_)
-    return sender_->IsFlinging();
-  return false;
-}
-
 void EventSenderBindings::GestureScrollFirstPoint(float x, float y) {
   if (sender_)
     sender_->GestureScrollFirstPoint(x, y);
@@ -1952,65 +1929,6 @@
   }
 }
 
-void EventSender::GestureFlingCancel() {
-  WebGestureEvent event(WebInputEvent::kGestureFlingCancel,
-                        WebInputEvent::kNoModifiers, GetCurrentEventTime(),
-                        blink::WebGestureDevice::kTouchpad);
-  // Generally it won't matter what device we use here, and since it might
-  // be cumbersome to expect all callers to specify a device, we'll just
-  // choose Touchpad here.
-
-  if (force_layout_on_events_)
-    UpdateLifecycleToPrePaint();
-
-  HandleInputEventOnViewOrPopup(event);
-}
-
-void EventSender::GestureFlingStart(float x,
-                                    float y,
-                                    float velocity_x,
-                                    float velocity_y,
-                                    gin::Arguments* args) {
-  WebGestureEvent event(WebInputEvent::kGestureFlingStart,
-                        WebInputEvent::kNoModifiers, GetCurrentEventTime());
-
-  std::string device_string;
-  if (!args->PeekNext().IsEmpty() && args->PeekNext()->IsString())
-    args->GetNext(&device_string);
-
-  if (device_string == kSourceDeviceStringTouchpad) {
-    event.SetSourceDevice(blink::WebGestureDevice::kTouchpad);
-  } else if (device_string == kSourceDeviceStringTouchscreen) {
-    event.SetSourceDevice(blink::WebGestureDevice::kTouchscreen);
-  } else {
-    args->ThrowError();
-    return;
-  }
-
-  float max_start_velocity = std::max(fabs(velocity_x), fabs(velocity_y));
-  if (!max_start_velocity) {
-    v8::Isolate* isolate = blink::MainThreadIsolate();
-    isolate->ThrowException(v8::Exception::TypeError(
-        gin::StringToV8(isolate, "Invalid max start velocity.")));
-    return;
-  }
-
-  event.SetPositionInWidget(WebFloatPoint(x, y));
-  event.SetPositionInScreen(WebFloatPoint(x, y));
-
-  event.data.fling_start.velocity_x = velocity_x;
-  event.data.fling_start.velocity_y = velocity_y;
-
-  if (force_layout_on_events_)
-    UpdateLifecycleToPrePaint();
-
-  HandleInputEventOnViewOrPopup(event);
-}
-
-bool EventSender::IsFlinging() {
-  return mainFrameWidget()->IsFlinging();
-}
-
 void EventSender::GestureScrollFirstPoint(float x, float y) {
   current_gesture_location_ = WebFloatPoint(x, y);
 }
diff --git a/content/shell/test_runner/event_sender.h b/content/shell/test_runner/event_sender.h
index 8e9d780..4ac763f4 100644
--- a/content/shell/test_runner/event_sender.h
+++ b/content/shell/test_runner/event_sender.h
@@ -132,13 +132,6 @@
 
   void DumpFilenameBeingDragged();
 
-  void GestureFlingCancel();
-  void GestureFlingStart(float x,
-                         float y,
-                         float velocity_x,
-                         float velocity_y,
-                         gin::Arguments* args);
-  bool IsFlinging();
   void GestureScrollFirstPoint(float x, float y);
 
   void TouchStart(gin::Arguments* args);
diff --git a/content/test/BUILD.gn b/content/test/BUILD.gn
index 45b046c..79bc997a 100644
--- a/content/test/BUILD.gn
+++ b/content/test/BUILD.gn
@@ -593,6 +593,8 @@
   }
 
   sources = [
+    "../browser/browsing_data/browsing_data_browsertest_utils.cc",
+    "../browser/browsing_data/browsing_data_browsertest_utils.h",
     "../public/test/content_browser_test.cc",
     "../public/test/content_browser_test.h",
     "../public/test/content_browser_test_utils.cc",
@@ -611,6 +613,7 @@
     "//base:i18n",
     "//base/test:test_config",
     "//base/test:test_support",
+    "//components/network_session_configurator/common:common",
     "//components/viz/service",
     "//content/app:both_for_content_tests",
     "//content/browser:for_content_tests",
diff --git a/content/test/data/accessibility/html/article-expected-uia-win.txt b/content/test/data/accessibility/html/article-expected-uia-win.txt
index efe01316..057c893 100644
--- a/content/test/data/accessibility/html/article-expected-uia-win.txt
+++ b/content/test/data/accessibility/html/article-expected-uia-win.txt
@@ -1,3 +1,3 @@
 document
-++article
+++article ControlType='UIA_GroupControlTypeId' LocalizedControlType='article'
 ++++description Name='This is an article element.'
diff --git a/content/test/data/accessibility/html/article.html b/content/test/data/accessibility/html/article.html
index 10af48b..bf9ff949 100644
--- a/content/test/data/accessibility/html/article.html
+++ b/content/test/data/accessibility/html/article.html
@@ -2,6 +2,8 @@
 @MAC-ALLOW:AXRole*
 @MAC-ALLOW:AXSubrole=AXDocumentArticle
 @MAC-DENY:AXTitle*
+@UIA-WIN-ALLOW:ControlType='UIA_GroupControlTypeId'
+@UIA-WIN-ALLOW:LocalizedControlType='article'
 @WIN-ALLOW:xml-roles:article
 @AURALINUX-ALLOW:xml-roles:article
 -->
diff --git a/content/test/data/accessibility/html/figure-expected-uia-win.txt b/content/test/data/accessibility/html/figure-expected-uia-win.txt
index 0c4353e3..1eb4524 100644
--- a/content/test/data/accessibility/html/figure-expected-uia-win.txt
+++ b/content/test/data/accessibility/html/figure-expected-uia-win.txt
@@ -1,3 +1,3 @@
 document
-++group
+++group LocalizedControlType='figure'
 ++++img Name='Sunspots'
diff --git a/content/test/data/accessibility/html/figure-expected-win.txt b/content/test/data/accessibility/html/figure-expected-win.txt
index 9359a64..325d0f9273 100644
--- a/content/test/data/accessibility/html/figure-expected-win.txt
+++ b/content/test/data/accessibility/html/figure-expected-win.txt
@@ -1,3 +1,3 @@
 ROLE_SYSTEM_DOCUMENT READONLY FOCUSABLE
-++ROLE_SYSTEM_GROUPING xml-roles:figure
+++ROLE_SYSTEM_GROUPING xml-roles:figure localized_extended_role='figure'
 ++++ROLE_SYSTEM_GRAPHIC name='Sunspots' READONLY xml-roles:img
diff --git a/content/test/data/accessibility/html/figure.html b/content/test/data/accessibility/html/figure.html
index 49dfa3550..12f6f72 100644
--- a/content/test/data/accessibility/html/figure.html
+++ b/content/test/data/accessibility/html/figure.html
@@ -1,5 +1,7 @@
 <!--
 @MAC-ALLOW:AXRole*
+@UIA-WIN-ALLOW:LocalizedControlType='figure'
+@WIN-ALLOW:localized_extended_role='figure'
 @WIN-ALLOW:xml-roles*
 @AURALINUX-ALLOW:xml-roles*
 -->
diff --git a/content/test/gpu/gpu_tests/test_expectations/pixel_expectations.txt b/content/test/gpu/gpu_tests/test_expectations/pixel_expectations.txt
index 8a964a7..aab4e3a7 100644
--- a/content/test/gpu/gpu_tests/test_expectations/pixel_expectations.txt
+++ b/content/test/gpu/gpu_tests/test_expectations/pixel_expectations.txt
@@ -187,6 +187,7 @@
 crbug.com/984973 [ linux skia-renderer use-vulkan ] Pixel_CanvasDisplaySRGBUnaccelerated2D [ Skip ]
 crbug.com/984973 [ linux skia-renderer use-vulkan ] Pixel_CanvasDisplaySRGBUnaccelerated2DGPUCompositing [ Skip ]
 crbug.com/984973 [ linux skia-renderer use-vulkan ] Pixel_CanvasUnacceleratedLowLatency2D [ Skip ]
+crbug.com/984973 [ linux skia-renderer use-vulkan ] Pixel_Canvas2DTabSwitch_SoftwareCompositing [ Skip ]
 crbug.com/984973 [ linux skia-renderer use-vulkan ] Pixel_OffscreenCanvasUnaccelerated2D [ Skip ]
 crbug.com/984973 [ linux skia-renderer use-vulkan ] Pixel_OffscreenCanvasUnaccelerated2DWorker [ Skip ]
 crbug.com/984973 [ linux skia-renderer use-vulkan ] Pixel_OffscreenCanvasWebGLSoftwareCompositing [ Skip ]
diff --git a/content/test/gpu/gpu_tests/test_expectations/webgl2_conformance_expectations.txt b/content/test/gpu/gpu_tests/test_expectations/webgl2_conformance_expectations.txt
index 61f4399..fa168f73 100644
--- a/content/test/gpu/gpu_tests/test_expectations/webgl2_conformance_expectations.txt
+++ b/content/test/gpu/gpu_tests/test_expectations/webgl2_conformance_expectations.txt
@@ -624,6 +624,7 @@
 crbug.com/483282 [ linux amd ] deqp/functional/gles3/texturespecification/teximage2d_depth_pbo.html [ Failure ]
 crbug.com/483282 [ linux amd ] deqp/functional/gles3/draw/random.html [ Failure ]
 crbug.com/483282 [ linux amd ] deqp/functional/gles3/fbomultisample* [ Failure ]
+crbug.com/483282 [ linux amd ] deqp/functional/gles3/framebufferblit/conversion_07.html [ Failure ]
 crbug.com/658832 [ linux amd ] deqp/functional/gles3/framebufferblit/default_framebuffer_00.html [ Failure ]
 crbug.com/483282 [ linux amd ] conformance2/glsl3/vector-dynamic-indexing.html [ Failure ]
 crbug.com/483282 [ no-angle linux amd ] conformance2/reading/read-pixels-pack-parameters.html [ Failure ]
diff --git a/docs/flag_expiry.md b/docs/flag_expiry.md
index 889eefb..addc261 100644
--- a/docs/flag_expiry.md
+++ b/docs/flag_expiry.md
@@ -56,4 +56,10 @@
 
 TODO(https://crbug.com/953690): Fill in this list :)
 
+## See Also
+
+* [//chrome/browser/flag-metadata.json](../chrome/browser/flag-metadata.json)
+* [//chrome/browser/expired_flags_list.h](../chrome/browser/expired_flags_list.h)
+* [//tools/flags/generate_expired_list.py](../tools/flags/generate_expired_list.py)
+
 [file a bug]: https://new.crbug.com
diff --git a/fuchsia/engine/context_provider_impl.cc b/fuchsia/engine/context_provider_impl.cc
index d5f4ed1..bf215b6 100644
--- a/fuchsia/engine/context_provider_impl.cc
+++ b/fuchsia/engine/context_provider_impl.cc
@@ -84,6 +84,8 @@
   }
 
   base::LaunchOptions launch_options;
+  launch_options.process_name_suffix = ":context";
+
   service_manager::SandboxPolicyFuchsia sandbox_policy;
   sandbox_policy.Initialize(service_manager::SANDBOX_TYPE_WEB_CONTEXT);
   sandbox_policy.SetServiceDirectory(std::move(service_directory));
diff --git a/gpu/command_buffer/service/external_vk_image_dawn_representation.cc b/gpu/command_buffer/service/external_vk_image_dawn_representation.cc
index 9475f8c..9e08c403 100644
--- a/gpu/command_buffer/service/external_vk_image_dawn_representation.cc
+++ b/gpu/command_buffer/service/external_vk_image_dawn_representation.cc
@@ -48,7 +48,7 @@
 }
 
 DawnTexture ExternalVkImageDawnRepresentation::BeginAccess(
-    DawnTextureUsageBit usage) {
+    DawnTextureUsage usage) {
   std::vector<SemaphoreHandle> handles;
 
   if (!backing_impl()->BeginAccess(false, &handles, false /* is_gl */)) {
diff --git a/gpu/command_buffer/service/external_vk_image_dawn_representation.h b/gpu/command_buffer/service/external_vk_image_dawn_representation.h
index c040553..e605db8 100644
--- a/gpu/command_buffer/service/external_vk_image_dawn_representation.h
+++ b/gpu/command_buffer/service/external_vk_image_dawn_representation.h
@@ -22,7 +22,7 @@
                                     uint32_t memory_type_index);
   ~ExternalVkImageDawnRepresentation() override;
 
-  DawnTexture BeginAccess(DawnTextureUsageBit usage) override;
+  DawnTexture BeginAccess(DawnTextureUsage usage) override;
   void EndAccess() override;
 
  private:
diff --git a/gpu/command_buffer/service/shared_image_backing_factory_iosurface.mm b/gpu/command_buffer/service/shared_image_backing_factory_iosurface.mm
index 5f99d5e4..83dbdec 100644
--- a/gpu/command_buffer/service/shared_image_backing_factory_iosurface.mm
+++ b/gpu/command_buffer/service/shared_image_backing_factory_iosurface.mm
@@ -296,7 +296,7 @@
     dawn_procs_.deviceRelease(device_);
   }
 
-  DawnTexture BeginAccess(DawnTextureUsageBit usage) final {
+  DawnTexture BeginAccess(DawnTextureUsage usage) final {
     DawnTextureDescriptor desc;
     desc.nextInChain = nullptr;
     desc.format = dawn_format_;
diff --git a/gpu/command_buffer/service/shared_image_backing_factory_iosurface_unittest.cc b/gpu/command_buffer/service/shared_image_backing_factory_iosurface_unittest.cc
index 3029d83..8438373c 100644
--- a/gpu/command_buffer/service/shared_image_backing_factory_iosurface_unittest.cc
+++ b/gpu/command_buffer/service/shared_image_backing_factory_iosurface_unittest.cc
@@ -290,9 +290,8 @@
 
   // Clear the shared image to green using Dawn.
   {
-    dawn::Texture texture =
-        dawn::Texture::Acquire(dawn_representation->BeginAccess(
-            DAWN_TEXTURE_USAGE_BIT_OUTPUT_ATTACHMENT));
+    dawn::Texture texture = dawn::Texture::Acquire(
+        dawn_representation->BeginAccess(DAWN_TEXTURE_USAGE_OUTPUT_ATTACHMENT));
 
     dawn::RenderPassColorAttachmentDescriptor color_desc;
     color_desc.attachment = texture.CreateDefaultView();
diff --git a/gpu/command_buffer/service/shared_image_representation.h b/gpu/command_buffer/service/shared_image_representation.h
index 6a576d3..30d643c 100644
--- a/gpu/command_buffer/service/shared_image_representation.h
+++ b/gpu/command_buffer/service/shared_image_representation.h
@@ -303,7 +303,7 @@
   // TODO(penghuang): Add ScopedAccess helper class.
   // This can return null in case of a Dawn validation error, for example if
   // usage is invalid.
-  virtual DawnTexture BeginAccess(DawnTextureUsageBit usage) = 0;
+  virtual DawnTexture BeginAccess(DawnTextureUsage usage) = 0;
   virtual void EndAccess() = 0;
 };
 
diff --git a/gpu/command_buffer/service/webgpu_decoder_impl.cc b/gpu/command_buffer/service/webgpu_decoder_impl.cc
index 5d417d2..9aefcad2d 100644
--- a/gpu/command_buffer/service/webgpu_decoder_impl.cc
+++ b/gpu/command_buffer/service/webgpu_decoder_impl.cc
@@ -574,7 +574,7 @@
   uint32_t device_generation = static_cast<uint32_t>(c.device_generation);
   uint32_t id = static_cast<uint32_t>(c.id);
   uint32_t generation = static_cast<uint32_t>(c.generation);
-  uint32_t usage = static_cast<DawnTextureUsageBit>(c.usage);
+  uint32_t usage = static_cast<DawnTextureUsage>(c.usage);
 
   // Unpack the mailbox
   if (sizeof(Mailbox) > immediate_data_size) {
@@ -599,14 +599,13 @@
   }
 
   static constexpr uint32_t kAllowedTextureUsages = static_cast<uint32_t>(
-      DAWN_TEXTURE_USAGE_BIT_COPY_SRC | DAWN_TEXTURE_USAGE_BIT_COPY_DST |
-      DAWN_TEXTURE_USAGE_BIT_SAMPLED |
-      DAWN_TEXTURE_USAGE_BIT_OUTPUT_ATTACHMENT);
+      DAWN_TEXTURE_USAGE_COPY_SRC | DAWN_TEXTURE_USAGE_COPY_DST |
+      DAWN_TEXTURE_USAGE_SAMPLED | DAWN_TEXTURE_USAGE_OUTPUT_ATTACHMENT);
   if (usage & ~kAllowedTextureUsages) {
     DLOG(ERROR) << "AssociateMailbox: Invalid usage";
     return error::kInvalidArguments;
   }
-  DawnTextureUsageBit dawn_usage = static_cast<DawnTextureUsageBit>(usage);
+  DawnTextureUsage dawn_usage = static_cast<DawnTextureUsage>(usage);
 
   // Create a DawnTexture from the mailbox.
   std::unique_ptr<SharedImageRepresentationDawn> shared_image =
diff --git a/gpu/command_buffer/service/webgpu_decoder_unittest.cc b/gpu/command_buffer/service/webgpu_decoder_unittest.cc
index f71be008..7eceeaf 100644
--- a/gpu/command_buffer/service/webgpu_decoder_unittest.cc
+++ b/gpu/command_buffer/service/webgpu_decoder_unittest.cc
@@ -109,7 +109,7 @@
   {
     gpu::Mailbox bad_mailbox;
     AssociateMailboxCmdStorage cmd;
-    cmd.cmd.Init(0, 0, 1, 0, DAWN_TEXTURE_USAGE_BIT_SAMPLED, bad_mailbox.name);
+    cmd.cmd.Init(0, 0, 1, 0, DAWN_TEXTURE_USAGE_SAMPLED, bad_mailbox.name);
     EXPECT_EQ(error::kInvalidArguments,
               ExecuteImmediateCmd(cmd.cmd, sizeof(bad_mailbox.name)));
   }
@@ -117,7 +117,7 @@
   // Error case: device doesn't exist.
   {
     AssociateMailboxCmdStorage cmd;
-    cmd.cmd.Init(42, 42, 1, 0, DAWN_TEXTURE_USAGE_BIT_SAMPLED, mailbox.name);
+    cmd.cmd.Init(42, 42, 1, 0, DAWN_TEXTURE_USAGE_SAMPLED, mailbox.name);
     EXPECT_EQ(error::kInvalidArguments,
               ExecuteImmediateCmd(cmd.cmd, sizeof(mailbox.name)));
   }
@@ -125,7 +125,7 @@
   // Error case: texture ID invalid for the wire server.
   {
     AssociateMailboxCmdStorage cmd;
-    cmd.cmd.Init(0, 0, 42, 42, DAWN_TEXTURE_USAGE_BIT_SAMPLED, mailbox.name);
+    cmd.cmd.Init(0, 0, 42, 42, DAWN_TEXTURE_USAGE_SAMPLED, mailbox.name);
     EXPECT_EQ(error::kInvalidArguments,
               ExecuteImmediateCmd(cmd.cmd, sizeof(mailbox.name)));
   }
@@ -133,7 +133,7 @@
   // Error case: invalid usage.
   {
     AssociateMailboxCmdStorage cmd;
-    cmd.cmd.Init(0, 0, 42, 42, DAWN_TEXTURE_USAGE_BIT_SAMPLED, mailbox.name);
+    cmd.cmd.Init(0, 0, 42, 42, DAWN_TEXTURE_USAGE_SAMPLED, mailbox.name);
     EXPECT_EQ(error::kInvalidArguments,
               ExecuteImmediateCmd(cmd.cmd, sizeof(mailbox.name)));
   }
@@ -141,7 +141,7 @@
   // Error case: invalid texture usage.
   {
     AssociateMailboxCmdStorage cmd;
-    cmd.cmd.Init(0, 0, 1, 0, DAWN_TEXTURE_USAGE_BIT_FORCE32, mailbox.name);
+    cmd.cmd.Init(0, 0, 1, 0, DAWN_TEXTURE_USAGE_FORCE32, mailbox.name);
     EXPECT_EQ(error::kInvalidArguments,
               ExecuteImmediateCmd(cmd.cmd, sizeof(mailbox.name)));
   }
@@ -153,7 +153,7 @@
   // and generation invalid.
   {
     AssociateMailboxCmdStorage cmd;
-    cmd.cmd.Init(0, 0, 1, 0, DAWN_TEXTURE_USAGE_BIT_SAMPLED, mailbox.name);
+    cmd.cmd.Init(0, 0, 1, 0, DAWN_TEXTURE_USAGE_SAMPLED, mailbox.name);
     EXPECT_EQ(error::kNoError,
               ExecuteImmediateCmd(cmd.cmd, sizeof(mailbox.name)));
   }
@@ -161,7 +161,7 @@
   // Error case: associated to an already associated texture.
   {
     AssociateMailboxCmdStorage cmd;
-    cmd.cmd.Init(0, 0, 1, 0, DAWN_TEXTURE_USAGE_BIT_SAMPLED, mailbox.name);
+    cmd.cmd.Init(0, 0, 1, 0, DAWN_TEXTURE_USAGE_SAMPLED, mailbox.name);
     EXPECT_EQ(error::kInvalidArguments,
               ExecuteImmediateCmd(cmd.cmd, sizeof(mailbox.name)));
   }
@@ -188,7 +188,7 @@
   // Associate a mailbox so we can later dissociate it.
   {
     AssociateMailboxCmdStorage cmd;
-    cmd.cmd.Init(0, 0, 1, 0, DAWN_TEXTURE_USAGE_BIT_SAMPLED, mailbox.name);
+    cmd.cmd.Init(0, 0, 1, 0, DAWN_TEXTURE_USAGE_SAMPLED, mailbox.name);
     EXPECT_EQ(error::kNoError,
               ExecuteImmediateCmd(cmd.cmd, sizeof(mailbox.name)));
   }
diff --git a/gpu/command_buffer/tests/webgpu_mailbox_unittest.cc b/gpu/command_buffer/tests/webgpu_mailbox_unittest.cc
index de124e6..bfc1c4c 100644
--- a/gpu/command_buffer/tests/webgpu_mailbox_unittest.cc
+++ b/gpu/command_buffer/tests/webgpu_mailbox_unittest.cc
@@ -97,7 +97,7 @@
         webgpu()->ReserveTexture(device.Get());
 
     webgpu()->AssociateMailbox(0, 0, reservation.id, reservation.generation,
-                               DAWN_TEXTURE_USAGE_BIT_OUTPUT_ATTACHMENT,
+                               DAWN_TEXTURE_USAGE_OUTPUT_ATTACHMENT,
                                reinterpret_cast<GLbyte*>(&mailbox));
     dawn::Texture texture = dawn::Texture::Acquire(reservation.texture);
 
@@ -141,15 +141,14 @@
     webgpu()->FlushCommands();
 
     webgpu()->AssociateMailbox(0, 0, reservation.id, reservation.generation,
-                               DAWN_TEXTURE_USAGE_BIT_COPY_SRC,
+                               DAWN_TEXTURE_USAGE_COPY_SRC,
                                reinterpret_cast<GLbyte*>(&mailbox));
     dawn::Texture texture = dawn::Texture::Acquire(reservation.texture);
 
     // Copy the texture in a mappable buffer.
     dawn::BufferDescriptor buffer_desc;
     buffer_desc.size = 4;
-    buffer_desc.usage =
-        dawn::BufferUsageBit::MapRead | dawn::BufferUsageBit::CopyDst;
+    buffer_desc.usage = dawn::BufferUsage::MapRead | dawn::BufferUsage::CopyDst;
     dawn::Buffer readback_buffer = device.CreateBuffer(&buffer_desc);
 
     dawn::TextureCopyView copy_src;
@@ -218,7 +217,7 @@
   dawn::Texture texture = dawn::Texture::Acquire(reservation.texture);
 
   webgpu()->AssociateMailbox(0, 0, reservation.id, reservation.generation,
-                             DAWN_TEXTURE_USAGE_BIT_OUTPUT_ATTACHMENT,
+                             DAWN_TEXTURE_USAGE_OUTPUT_ATTACHMENT,
                              reinterpret_cast<GLbyte*>(&mailbox));
   webgpu()->DissociateMailbox(reservation.id, reservation.generation);
 
diff --git a/ios/chrome/app/resources/LaunchScreen.xib b/ios/chrome/app/resources/LaunchScreen.xib
index 3008ab66..1bfa3950 100644
--- a/ios/chrome/app/resources/LaunchScreen.xib
+++ b/ios/chrome/app/resources/LaunchScreen.xib
@@ -1,8 +1,8 @@
 <?xml version="1.0" encoding="UTF-8"?>
-<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="14845" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" useTraitCollections="YES" colorMatched="YES">
+<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="14854.2" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" useTraitCollections="YES" colorMatched="YES">
     <device id="retina6_1" orientation="portrait" appearance="light"/>
     <dependencies>
-        <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="14799.2"/>
+        <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="14806.4"/>
         <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
     </dependencies>
     <objects>
@@ -33,7 +33,7 @@
                         </constraints>
                     </imageView>
                 </subviews>
-                <color key="backgroundColor" xcode11CocoaTouchSystemColor="systemBackgroundColor" cocoaTouchSystemColor="whiteColor"/>
+                <color key="backgroundColor" systemColor="systemBackgroundColor" cocoaTouchSystemColor="whiteColor"/>
                 <constraints>
                     <constraint firstItem="K7H-Iv-QNk" firstAttribute="width" secondItem="tRS-Cx-RH3" secondAttribute="width" multiplier="0.381966" id="3hJ-Yo-1Tg"/>
                     <constraint firstItem="K7H-Iv-QNk" firstAttribute="height" secondItem="tRS-Cx-RH3" secondAttribute="height" multiplier="0.381966" id="962-tL-cOd"/>
diff --git a/ios/chrome/browser/sync/ios_chrome_sync_client.mm b/ios/chrome/browser/sync/ios_chrome_sync_client.mm
index 202024a..19c7410 100644
--- a/ios/chrome/browser/sync/ios_chrome_sync_client.mm
+++ b/ios/chrome/browser/sync/ios_chrome_sync_client.mm
@@ -15,7 +15,6 @@
 #include "components/autofill/core/browser/webdata/autocomplete_sync_bridge.h"
 #include "components/autofill/core/browser/webdata/autofill_profile_sync_bridge.h"
 #include "components/autofill/core/browser/webdata/autofill_wallet_metadata_sync_bridge.h"
-#include "components/autofill/core/browser/webdata/autofill_wallet_metadata_syncable_service.h"
 #include "components/autofill/core/browser/webdata/autofill_wallet_sync_bridge.h"
 #include "components/autofill/core/browser/webdata/autofill_webdata_service.h"
 #include "components/autofill/core/common/autofill_features.h"
@@ -212,13 +211,6 @@
       return browser_state_->GetSyncablePrefs()
           ->GetSyncableService(syncer::PRIORITY_PREFERENCES)
           ->AsWeakPtr();
-    case syncer::AUTOFILL_WALLET_METADATA: {
-      if (!profile_web_data_service_)
-        return base::WeakPtr<syncer::SyncableService>();
-      return autofill::AutofillWalletMetadataSyncableService::
-          FromWebDataService(profile_web_data_service_.get())
-              ->AsWeakPtr();
-    }
     case syncer::HISTORY_DELETE_DIRECTIVES: {
       history::HistoryService* history =
           ios::HistoryServiceFactory::GetForBrowserState(
diff --git a/ios/chrome/browser/ui/alert_view_controller/alert_view_controller.mm b/ios/chrome/browser/ui/alert_view_controller/alert_view_controller.mm
index 86ea9e4..fd18497b 100644
--- a/ios/chrome/browser/ui/alert_view_controller/alert_view_controller.mm
+++ b/ios/chrome/browser/ui/alert_view_controller/alert_view_controller.mm
@@ -118,10 +118,8 @@
     if ([self.traitCollection
             hasDifferentColorAppearanceComparedToTraitCollection:
                 previousTraitCollection]) {
-      [self.traitCollection performAsCurrentTraitCollection:^{
-        self.textFieldStackHolder.layer.borderColor =
-            UIColor.cr_separatorColor.CGColor;
-      }];
+      self.textFieldStackHolder.layer.borderColor =
+          UIColor.cr_separatorColor.CGColor;
     }
   }
 }
diff --git a/ios/chrome/browser/ui/bubble/bubble_view.mm b/ios/chrome/browser/ui/bubble/bubble_view.mm
index 59b1df1..70e40294 100644
--- a/ios/chrome/browser/ui/bubble/bubble_view.mm
+++ b/ios/chrome/browser/ui/bubble/bubble_view.mm
@@ -356,9 +356,7 @@
     if ([self.traitCollection
             hasDifferentColorAppearanceComparedToTraitCollection:
                 previousTraitCollection]) {
-      UIColor* resolvedColor =
-          [BubbleColor() resolvedColorWithTraitCollection:self.traitCollection];
-      self.arrowLayer.fillColor = resolvedColor.CGColor;
+      self.arrowLayer.fillColor = BubbleColor().CGColor;
     }
   }
 }
diff --git a/ios/chrome/browser/ui/infobars/banners/infobar_banner_view_controller.mm b/ios/chrome/browser/ui/infobars/banners/infobar_banner_view_controller.mm
index 669967ee..e361a59a 100644
--- a/ios/chrome/browser/ui/infobars/banners/infobar_banner_view_controller.mm
+++ b/ios/chrome/browser/ui/infobars/banners/infobar_banner_view_controller.mm
@@ -275,10 +275,8 @@
     if ([self.traitCollection
             hasDifferentColorAppearanceComparedToTraitCollection:
                 previousTraitCollection]) {
-      [self.traitCollection performAsCurrentTraitCollection:^{
-        [self.view.layer
-            setShadowColor:[UIColor colorNamed:kToolbarShadowColor].CGColor];
-      }];
+      [self.view.layer
+          setShadowColor:[UIColor colorNamed:kToolbarShadowColor].CGColor];
     }
   }
 }
diff --git a/ios/chrome/browser/ui/open_in/BUILD.gn b/ios/chrome/browser/ui/open_in/BUILD.gn
index 4118e0d..3345c393 100644
--- a/ios/chrome/browser/ui/open_in/BUILD.gn
+++ b/ios/chrome/browser/ui/open_in/BUILD.gn
@@ -23,7 +23,7 @@
     "//ios/chrome/browser/ui/coordinators:chrome_coordinators",
     "//ios/chrome/browser/ui/util",
     "//ios/chrome/browser/web_state_list",
-    "//ios/chrome/common/ui_util",
+    "//ios/chrome/common/colors",
     "//ios/chrome/common/ui_util",
     "//ios/third_party/material_components_ios",
     "//ios/web/public",
diff --git a/ios/chrome/browser/ui/open_in/open_in_toolbar.mm b/ios/chrome/browser/ui/open_in/open_in_toolbar.mm
index e16e9a23..6d799e3 100644
--- a/ios/chrome/browser/ui/open_in/open_in_toolbar.mm
+++ b/ios/chrome/browser/ui/open_in/open_in_toolbar.mm
@@ -7,10 +7,10 @@
 #include <cmath>
 
 #include "base/logging.h"
-#import "ios/chrome/browser/ui/colors/MDCPalette+CrAdditions.h"
 #import "ios/chrome/browser/ui/util/named_guide.h"
 #include "ios/chrome/browser/ui/util/rtl_geometry.h"
 #import "ios/chrome/browser/ui/util/uikit_ui_util.h"
+#import "ios/chrome/common/colors/semantic_color_names.h"
 #import "ios/chrome/common/ui_util/constraints_ui_util.h"
 #include "ios/chrome/grit/ios_strings.h"
 #import "ios/third_party/material_components_ios/src/components/Buttons/src/MaterialButtons.h"
@@ -28,28 +28,17 @@
 
 // The toolbar's border related constants.
 const CGFloat kTopBorderHeight = 0.5f;
-const CGFloat kTopBorderTransparency = 0.13f;
-const int kTopBorderColor = 0x000000;
-
-// The toolbar's background related constants.
-const int kToolbarBackgroundColor = 0xFFFFFF;
-const CGFloat kToolbarBackgroundTransparency = 0.97f;
 
 }  // anonymous namespace
 
-@interface OpenInToolbar () {
-  // Backing object for |self.openButton|.
-  MDCButton* _openButton;
-  // Backing object for |self.topBorder|.
-  UIView* _topBorder;
-}
+@interface OpenInToolbar ()
 
 // The "Open in..." button that's hooked up with the target and action passed
 // on initialization.
-@property(nonatomic, retain, readonly) MDCButton* openButton;
+@property(nonatomic, strong, readonly) MDCButton* openButton;
 
 // The line used as the border at the top of the toolbar.
-@property(nonatomic, retain, readonly) UIView* topBorder;
+@property(nonatomic, strong, readonly) UIView* topBorder;
 
 // View used to have a bottom margin to prevent overlapping with the bottom
 // toolbar. This view is used because the the CRWWebControllerContainerView is
@@ -95,6 +84,8 @@
 
 @synthesize bottomMargin = _bottomMargin;
 @synthesize bottomMarginConstraint = _bottomMarginConstraint;
+@synthesize openButton = _openButton;
+@synthesize topBorder = _topBorder;
 
 - (instancetype)initWithFrame:(CGRect)aRect {
   NOTREACHED();
@@ -105,8 +96,7 @@
   self = [super initWithFrame:CGRectZero];
   if (self) {
     DCHECK([target respondsToSelector:action]);
-    [self setBackgroundColor:UIColorFromRGB(kToolbarBackgroundColor,
-                                            kToolbarBackgroundTransparency)];
+    self.backgroundColor = [UIColor colorNamed:kBackgroundColor];
     [self addSubview:self.openButton];
     [self.openButton addTarget:target
                         action:action
@@ -147,7 +137,7 @@
 - (MDCButton*)openButton {
   if (!_openButton) {
     _openButton = [[MDCFlatButton alloc] init];
-    [_openButton setTitleColor:[[MDCPalette cr_bluePalette] tint500]
+    [_openButton setTitleColor:[UIColor colorNamed:kBlueColor]
                       forState:UIControlStateNormal];
     [_openButton setTitle:l10n_util::GetNSStringWithFixup(IDS_IOS_OPEN_IN)
                  forState:UIControlStateNormal];
@@ -159,8 +149,7 @@
 - (UIView*)topBorder {
   if (!_topBorder) {
     _topBorder = [[UIView alloc] initWithFrame:CGRectZero];
-    [_topBorder setBackgroundColor:UIColorFromRGB(kTopBorderColor,
-                                                  kTopBorderTransparency)];
+    _topBorder.backgroundColor = [UIColor colorNamed:kToolbarShadowColor];
   }
   return _topBorder;
 }
diff --git a/ios/web_view/internal/sync/web_view_sync_client.mm b/ios/web_view/internal/sync/web_view_sync_client.mm
index 1336ae9f..d3ccec9 100644
--- a/ios/web_view/internal/sync/web_view_sync_client.mm
+++ b/ios/web_view/internal/sync/web_view_sync_client.mm
@@ -11,7 +11,6 @@
 #include "base/logging.h"
 #include "base/task/post_task.h"
 #include "components/autofill/core/browser/webdata/autofill_profile_sync_bridge.h"
-#include "components/autofill/core/browser/webdata/autofill_wallet_metadata_syncable_service.h"
 #include "components/autofill/core/browser/webdata/autofill_webdata_service.h"
 #include "components/autofill/core/common/autofill_features.h"
 #include "components/browser_sync/profile_sync_components_factory_impl.h"
@@ -173,16 +172,7 @@
 
 base::WeakPtr<syncer::SyncableService>
 WebViewSyncClient::GetSyncableServiceForType(syncer::ModelType type) {
-  auto service = account_web_data_service_ ?: profile_web_data_service_;
-  if (!service) {
-    NOTREACHED();
-    return base::WeakPtr<syncer::SyncableService>();
-  }
   switch (type) {
-    case syncer::AUTOFILL_WALLET_METADATA:
-      return autofill::AutofillWalletMetadataSyncableService::
-          FromWebDataService(service.get())
-              ->AsWeakPtr();
     case syncer::PASSWORDS:
       return password_store_ ? password_store_->GetPasswordSyncableService()
                              : base::WeakPtr<syncer::SyncableService>();
diff --git a/media/cast/test/end2end_unittest.cc b/media/cast/test/end2end_unittest.cc
index bd13c9ac..ade6fbc 100644
--- a/media/cast/test/end2end_unittest.cc
+++ b/media/cast/test/end2end_unittest.cc
@@ -28,6 +28,7 @@
 #include "base/test/simple_test_tick_clock.h"
 #include "base/test/task_environment.h"
 #include "base/time/tick_clock.h"
+#include "build/build_config.h"
 #include "media/base/audio_bus.h"
 #include "media/base/fake_single_thread_task_runner.h"
 #include "media/base/video_frame.h"
@@ -1218,7 +1219,9 @@
 // Tests that a system configured for 30 FPS drops frames when input is provided
 // at a much higher frame rate.
 // Fails consistently on official builds: crbug.com/612496
-#ifdef OFFICIAL_BUILD
+// crbug.com/997944. Flaky on multiple platforms.
+#if defined(OFFICIAL_BUILD) || defined(OS_LINUX) || defined(OS_MACOSX) || \
+    defined(OS_WIN)
 #define MAYBE_ShoveHighFrameRateDownYerThroat \
   DISABLED_ShoveHighFrameRateDownYerThroat
 #else
diff --git a/media/filters/vp9_parser.cc b/media/filters/vp9_parser.cc
index f975e7e..2a904b6 100644
--- a/media/filters/vp9_parser.cc
+++ b/media/filters/vp9_parser.cc
@@ -531,6 +531,12 @@
   stream_decrypt_config_ = std::move(stream_config);
 }
 
+void Vp9Parser::SetStream(const uint8_t* stream,
+                          off_t stream_size,
+                          std::unique_ptr<DecryptConfig> stream_config) {
+  SetStream(stream, stream_size, {}, std::move(stream_config));
+}
+
 void Vp9Parser::Reset() {
   stream_ = nullptr;
   bytes_left_ = 0;
diff --git a/media/filters/vp9_parser.h b/media/filters/vp9_parser.h
index 0aa1bb8..359bafd8 100644
--- a/media/filters/vp9_parser.h
+++ b/media/filters/vp9_parser.h
@@ -382,6 +382,10 @@
                  const std::vector<uint32_t>& spatial_layer_frame_size,
                  std::unique_ptr<DecryptConfig> stream_config);
 
+  void SetStream(const uint8_t* stream,
+                 off_t stream_size,
+                 std::unique_ptr<DecryptConfig> stream_config);
+
   // Parse the next frame in the current stream buffer, filling |fhdr| with
   // the parsed frame header and updating current segmentation and loop filter
   // state. The necessary frame size to decode |fhdr| fills in |allocate_size|.
diff --git a/media/filters/vp9_parser_encrypted_fuzzertest.cc b/media/filters/vp9_parser_encrypted_fuzzertest.cc
index 69e3820b..8b2b4ae 100644
--- a/media/filters/vp9_parser_encrypted_fuzzertest.cc
+++ b/media/filters/vp9_parser_encrypted_fuzzertest.cc
@@ -57,7 +57,7 @@
   while (ivf_parser.ParseNextFrame(&ivf_frame_header, &ivf_payload)) {
     media::Vp9FrameHeader vp9_frame_header;
     vp9_parser.SetStream(
-        ivf_payload, ivf_frame_header.frame_size, {},
+        ivf_payload, ivf_frame_header.frame_size,
         media::DecryptConfig::CreateCencConfig(key_id, iv, subsamples));
     // TODO(kcwu): further fuzzing the case of Vp9Parser::kAwaitingRefresh.
     std::unique_ptr<media::DecryptConfig> null_config;
diff --git a/media/filters/vp9_parser_fuzzertest.cc b/media/filters/vp9_parser_fuzzertest.cc
index 9da885b..a4343d5 100644
--- a/media/filters/vp9_parser_fuzzertest.cc
+++ b/media/filters/vp9_parser_fuzzertest.cc
@@ -36,7 +36,7 @@
   // Parse until the end of stream/unsupported stream/error in stream is found.
   while (ivf_parser.ParseNextFrame(&ivf_frame_header, &ivf_payload)) {
     media::Vp9FrameHeader vp9_frame_header;
-    vp9_parser.SetStream(ivf_payload, ivf_frame_header.frame_size, {}, nullptr);
+    vp9_parser.SetStream(ivf_payload, ivf_frame_header.frame_size, nullptr);
     // TODO(kcwu): further fuzzing the case of Vp9Parser::kAwaitingRefresh.
     std::unique_ptr<media::DecryptConfig> null_config;
     gfx::Size allocate_size;
diff --git a/media/filters/vp9_parser_unittest.cc b/media/filters/vp9_parser_unittest.cc
index b435229..23816767 100644
--- a/media/filters/vp9_parser_unittest.cc
+++ b/media/filters/vp9_parser_unittest.cc
@@ -144,7 +144,7 @@
       if (!ivf_parser_.ParseNextFrame(&ivf_frame_header, &ivf_payload))
         return Vp9Parser::kEOStream;
 
-      vp9_parser_->SetStream(ivf_payload, ivf_frame_header.frame_size, {},
+      vp9_parser_->SetStream(ivf_payload, ivf_frame_header.frame_size,
                              nullptr);
       continue;
     }
@@ -158,7 +158,7 @@
     size_t framesize,
     std::unique_ptr<DecryptConfig> config,
     std::vector<std::unique_ptr<DecryptConfig>>& expected_split) {
-  vp9_parser_->SetStream(superframe, framesize, {}, std::move(config));
+  vp9_parser_->SetStream(superframe, framesize, std::move(config));
   for (auto& expected : expected_split) {
     std::unique_ptr<DecryptConfig> actual =
         vp9_parser_->NextFrameDecryptContextForTesting();
@@ -428,7 +428,7 @@
       // marker again.
       superframe_marker_byte};
 
-  vp9_parser_->SetStream(kSuperframe, sizeof(kSuperframe), {},
+  vp9_parser_->SetStream(kSuperframe, sizeof(kSuperframe),
                          DecryptConfig::CreateCencConfig(
                              kKeyID, kInitialIV, {SubsampleEntry(16, 32)}));
 
@@ -459,7 +459,7 @@
       // marker again.
       superframe_marker_byte};
 
-  vp9_parser_->SetStream(kSuperframe, sizeof(kSuperframe), {},
+  vp9_parser_->SetStream(kSuperframe, sizeof(kSuperframe),
                          DecryptConfig::CreateCencConfig(
                              kKeyID, kInitialIV, {SubsampleEntry(0, 48)}));
 
@@ -494,7 +494,7 @@
       // marker again.
       superframe_marker_byte};
 
-  vp9_parser_->SetStream(kSuperframe, sizeof(kSuperframe), {},
+  vp9_parser_->SetStream(kSuperframe, sizeof(kSuperframe),
                          DecryptConfig::CreateCencConfig(
                              kKeyID, kInitialIV, {SubsampleEntry(48, 0)}));
 
@@ -530,7 +530,7 @@
       superframe_marker_byte};
 
   vp9_parser_->SetStream(
-      kSuperframe, sizeof(kSuperframe), {},
+      kSuperframe, sizeof(kSuperframe),
       DecryptConfig::CreateCencConfig(kKeyID, kInitialIV,
                                       {
                                           SubsampleEntry(16, 16),
diff --git a/media/gpu/test/video_player/test_vda_video_decoder.cc b/media/gpu/test/video_player/test_vda_video_decoder.cc
index abc8e9d..cc14231e 100644
--- a/media/gpu/test/video_player/test_vda_video_decoder.cc
+++ b/media/gpu/test/video_player/test_vda_video_decoder.cc
@@ -362,19 +362,19 @@
 
   switch (error) {
     case VideoDecodeAccelerator::ILLEGAL_STATE:
-      LOG(FATAL) << "ILLEGAL_STATE";
+      LOG(ERROR) << "ILLEGAL_STATE";
       break;
     case VideoDecodeAccelerator::INVALID_ARGUMENT:
-      LOG(FATAL) << "INVALID_ARGUMENT";
+      LOG(ERROR) << "INVALID_ARGUMENT";
       break;
     case VideoDecodeAccelerator::UNREADABLE_INPUT:
-      LOG(FATAL) << "UNREADABLE_INPUT";
+      LOG(ERROR) << "UNREADABLE_INPUT";
       break;
     case VideoDecodeAccelerator::PLATFORM_FAILURE:
-      LOG(FATAL) << "PLATFORM_FAILURE";
+      LOG(ERROR) << "PLATFORM_FAILURE";
       break;
     default:
-      LOG(FATAL) << "Unknown error " << error;
+      LOG(ERROR) << "Unknown error " << error;
       break;
   }
 }
diff --git a/media/gpu/video_encode_accelerator_unittest.cc b/media/gpu/video_encode_accelerator_unittest.cc
index 2aede768..c4dada1 100644
--- a/media/gpu/video_encode_accelerator_unittest.cc
+++ b/media/gpu/video_encode_accelerator_unittest.cc
@@ -1057,7 +1057,7 @@
   // partition numbers/sizes. For now assume one frame per buffer.
   Vp9FrameHeader header;
   gfx::Size allocate_size;
-  parser_.SetStream(stream, size, {}, nullptr);
+  parser_.SetStream(stream, size, nullptr);
   EXPECT_TRUE(Vp9Parser::kInvalidStream !=
               parser_.ParseNextFrame(&header, &allocate_size, nullptr));
   if (header.IsKeyframe()) {
diff --git a/media/gpu/windows/dxva_video_decode_accelerator_win.cc b/media/gpu/windows/dxva_video_decode_accelerator_win.cc
index fef3a79c..365b1d52 100644
--- a/media/gpu/windows/dxva_video_decode_accelerator_win.cc
+++ b/media/gpu/windows/dxva_video_decode_accelerator_win.cc
@@ -412,7 +412,7 @@
   // Detects stream configuration changes.
   // Returns false on failure.
   bool DetectConfig(const uint8_t* stream, unsigned int size) override {
-    parser_.SetStream(stream, size, {} /* spatial_layer_frame_size */, nullptr);
+    parser_.SetStream(stream, size, nullptr);
     Vp9FrameHeader fhdr;
     gfx::Size allocate_size;
     std::unique_ptr<DecryptConfig> null_config;
diff --git a/media/renderers/video_resource_updater.cc b/media/renderers/video_resource_updater.cc
index 079a4df6..de1357af5 100644
--- a/media/renderers/video_resource_updater.cc
+++ b/media/renderers/video_resource_updater.cc
@@ -70,7 +70,13 @@
     case PIXEL_FORMAT_UYVY:
     case PIXEL_FORMAT_ABGR:
       DCHECK_EQ(num_textures, 1);
-      buffer_formats[0] = gfx::BufferFormat::RGBA_8888;
+      // This maps VideoPixelFormat back to GMB BufferFormat
+      // NOTE: ABGR == RGBA and ARGB == BGRA, they differ only byte order
+      // See: VideoFormat function in gpu_memory_buffer_video_frame_pool
+      // https://cs.chromium.org/chromium/src/media/video/gpu_memory_buffer_video_frame_pool.cc?type=cs&g=0&l=281
+      buffer_formats[0] = (format == PIXEL_FORMAT_ABGR)
+                              ? gfx::BufferFormat::RGBA_8888
+                              : gfx::BufferFormat::BGRA_8888;
       switch (target) {
         case GL_TEXTURE_EXTERNAL_OES:
           if (use_stream_video_draw_quad)
diff --git a/net/extras/sqlite/sqlite_persistent_store_backend_base.cc b/net/extras/sqlite/sqlite_persistent_store_backend_base.cc
index 805d5ee9..82d8c6e 100644
--- a/net/extras/sqlite/sqlite_persistent_store_backend_base.cc
+++ b/net/extras/sqlite/sqlite_persistent_store_backend_base.cc
@@ -102,6 +102,7 @@
     Reset();
     return false;
   }
+  db_->Preload();
 
   if (!MigrateDatabaseSchema() || !CreateDatabaseSchema()) {
     DLOG(ERROR) << "Unable to update or initialize " << histogram_tag_
diff --git a/net/http/http_cache_transaction.cc b/net/http/http_cache_transaction.cc
index 11a0cc4..cccfe47 100644
--- a/net/http/http_cache_transaction.cc
+++ b/net/http/http_cache_transaction.cc
@@ -1427,7 +1427,7 @@
   // created a new ActiveEntry (new_entry_) to write to (and doomed the old
   // one). Now that the new entry has been created, start writing the response.
 
-  DCHECK_EQ(result, OK);
+  CHECK_EQ(result, OK);
   DCHECK_EQ(mode_, WRITE);
   DCHECK(new_entry_);
   DCHECK(response_.headers);
diff --git a/remoting/host/client_session.cc b/remoting/host/client_session.cc
index d72f011d..6228b488 100644
--- a/remoting/host/client_session.cc
+++ b/remoting/host/client_session.cc
@@ -44,13 +44,6 @@
 
 using protocol::ActionRequest;
 
-namespace {
-
-// Name of command-line flag to disable use of I444 by default.
-const char kDisableI444SwitchName[] = "disable-i444";
-
-}  // namespace
-
 ClientSession::ClientSession(
     EventHandler* event_handler,
     std::unique_ptr<protocol::ConnectionToClient> connection,
@@ -71,11 +64,7 @@
       disable_clipboard_filter_(clipboard_echo_filter_.host_filter()),
       client_clipboard_factory_(clipboard_echo_filter_.client_filter()),
       max_duration_(max_duration),
-      pairing_registry_(pairing_registry),
-      // Note that |lossless_video_color_| defaults to true, but actually only
-      // controls VP9 video stream color quality.
-      lossless_video_color_(!base::CommandLine::ForCurrentProcess()->HasSwitch(
-          kDisableI444SwitchName)) {
+      pairing_registry_(pairing_registry) {
   connection_->session()->AddPlugin(&host_experiment_session_plugin_);
   connection_->SetEventHandler(this);
 
diff --git a/services/device/public/cpp/test/test_wake_lock_provider.cc b/services/device/public/cpp/test/test_wake_lock_provider.cc
index 5127229..543c4da 100644
--- a/services/device/public/cpp/test/test_wake_lock_provider.cc
+++ b/services/device/public/cpp/test/test_wake_lock_provider.cc
@@ -10,7 +10,6 @@
 #include "base/callback.h"
 #include "base/logging.h"
 #include "mojo/public/cpp/bindings/binding.h"
-#include "mojo/public/cpp/bindings/strong_binding.h"
 #include "services/device/public/mojom/constants.mojom.h"
 
 namespace device {
@@ -160,7 +159,7 @@
 
 void TestWakeLockProvider::GetWakeLockContextForID(
     int context_id,
-    mojo::InterfaceRequest<mojom::WakeLockContext> request) {
+    mojo::PendingReceiver<mojom::WakeLockContext> receiver) {
   // This method is only used on Android.
   NOTIMPLEMENTED();
 }
diff --git a/services/device/public/cpp/test/test_wake_lock_provider.h b/services/device/public/cpp/test/test_wake_lock_provider.h
index e7e551d..f34fb9a 100644
--- a/services/device/public/cpp/test/test_wake_lock_provider.h
+++ b/services/device/public/cpp/test/test_wake_lock_provider.h
@@ -39,7 +39,7 @@
   // mojom::WakeLockProvider:
   void GetWakeLockContextForID(
       int context_id,
-      mojo::InterfaceRequest<mojom::WakeLockContext> request) override;
+      mojo::PendingReceiver<mojom::WakeLockContext> receiver) override;
   void GetWakeLockWithoutContext(mojom::WakeLockType type,
                                  mojom::WakeLockReason reason,
                                  const std::string& description,
diff --git a/services/device/public/mojom/wake_lock_provider.mojom b/services/device/public/mojom/wake_lock_provider.mojom
index 4353391..2e89db96 100644
--- a/services/device/public/mojom/wake_lock_provider.mojom
+++ b/services/device/public/mojom/wake_lock_provider.mojom
@@ -12,7 +12,8 @@
   // Gets a WakeLockContext that is associated with |context_id|. |context_id|
   // is used to obtain the NativeView associated with the relevant context on
   // Android (see WakeLockContextCallback). |context_id| must be >= 0.
-  GetWakeLockContextForID(int32 context_id, WakeLockContext& context);
+  GetWakeLockContextForID(int32 context_id,
+                          pending_receiver<WakeLockContext> context);
 
   // Gets a WakeLock outside of any context. This method can be used
   // if the client does not have any context available (e.g., is not
diff --git a/services/device/wake_lock/wake_lock_provider.cc b/services/device/wake_lock/wake_lock_provider.cc
index a629a4c95..a50ef84 100644
--- a/services/device/wake_lock/wake_lock_provider.cc
+++ b/services/device/wake_lock/wake_lock_provider.cc
@@ -8,7 +8,7 @@
 #include <string>
 #include <utility>
 
-#include "mojo/public/cpp/bindings/strong_binding.h"
+#include "mojo/public/cpp/bindings/self_owned_receiver.h"
 #include "services/device/wake_lock/wake_lock.h"
 
 namespace device {
@@ -56,12 +56,12 @@
 
 void WakeLockProvider::GetWakeLockContextForID(
     int context_id,
-    mojom::WakeLockContextRequest request) {
+    mojo::PendingReceiver<mojom::WakeLockContext> receiver) {
   DCHECK_GE(context_id, 0);
-  mojo::MakeStrongBinding(
+  mojo::MakeSelfOwnedReceiver(
       std::make_unique<WakeLockContext>(context_id, file_task_runner_,
                                         native_view_getter_),
-      std::move(request));
+      std::move(receiver));
 }
 
 void WakeLockProvider::GetWakeLockWithoutContext(
diff --git a/services/device/wake_lock/wake_lock_provider.h b/services/device/wake_lock/wake_lock_provider.h
index ac59e17..8d38ef7 100644
--- a/services/device/wake_lock/wake_lock_provider.h
+++ b/services/device/wake_lock/wake_lock_provider.h
@@ -13,6 +13,7 @@
 #include "base/single_thread_task_runner.h"
 #include "mojo/public/cpp/bindings/interface_ptr_set.h"
 #include "mojo/public/cpp/bindings/interface_request.h"
+#include "mojo/public/cpp/bindings/pending_receiver.h"
 #include "services/device/public/mojom/wake_lock_context.mojom.h"
 #include "services/device/public/mojom/wake_lock_provider.mojom.h"
 #include "services/device/wake_lock/wake_lock.h"
@@ -33,8 +34,9 @@
   void AddBinding(mojom::WakeLockProviderRequest request);
 
   // mojom::WakeLockProvider overrides.
-  void GetWakeLockContextForID(int context_id,
-                               mojom::WakeLockContextRequest request) override;
+  void GetWakeLockContextForID(
+      int context_id,
+      mojo::PendingReceiver<mojom::WakeLockContext> receiver) override;
   void GetWakeLockWithoutContext(mojom::WakeLockType type,
                                  mojom::WakeLockReason reason,
                                  const std::string& description,
diff --git a/services/network/restricted_cookie_manager_unittest.cc b/services/network/restricted_cookie_manager_unittest.cc
index 7c8f861b..3b865bb 100644
--- a/services/network/restricted_cookie_manager_unittest.cc
+++ b/services/network/restricted_cookie_manager_unittest.cc
@@ -15,6 +15,7 @@
 #include "mojo/core/embedder/embedder.h"
 #include "mojo/public/cpp/bindings/pending_remote.h"
 #include "mojo/public/cpp/bindings/receiver.h"
+#include "mojo/public/cpp/bindings/remote.h"
 #include "net/base/features.h"
 #include "net/cookies/canonical_cookie_test_helpers.h"
 #include "net/cookies/cookie_constants.h"
@@ -171,9 +172,10 @@
             false /* is_service_worker*/,
             kProcessId,
             kRoutingId)),
-        binding_(service_.get(), mojo::MakeRequest(&service_ptr_)) {
+        receiver_(service_.get(),
+                  service_remote_.BindNewPipeAndPassReceiver()) {
     sync_service_ =
-        std::make_unique<RestrictedCookieManagerSync>(service_ptr_.get());
+        std::make_unique<RestrictedCookieManagerSync>(service_remote_.get());
   }
   ~RestrictedCookieManagerTest() override {}
 
@@ -242,7 +244,7 @@
 
   bool received_bad_message() { return received_bad_message_; }
 
-  mojom::RestrictedCookieManager* backend() { return service_ptr_.get(); }
+  mojom::RestrictedCookieManager* backend() { return service_remote_.get(); }
 
  protected:
   void OnBadMessage(const std::string& reason) {
@@ -261,8 +263,8 @@
   CookieSettings cookie_settings_;
   RecordingNetworkContextClient recording_client_;
   std::unique_ptr<RestrictedCookieManager> service_;
-  mojom::RestrictedCookieManagerPtr service_ptr_;
-  mojo::Binding<mojom::RestrictedCookieManager> binding_;
+  mojo::Remote<mojom::RestrictedCookieManager> service_remote_;
+  mojo::Receiver<mojom::RestrictedCookieManager> receiver_;
   std::unique_ptr<RestrictedCookieManagerSync> sync_service_;
   bool expecting_bad_message_ = false;
   bool received_bad_message_ = false;
diff --git a/sql/database.cc b/sql/database.cc
index 3ef9c18d..d5b4b5bd 100644
--- a/sql/database.cc
+++ b/sql/database.cc
@@ -36,6 +36,10 @@
 #include "sql/vfs_wrapper.h"
 #include "third_party/sqlite/sqlite3.h"
 
+#if defined(OS_WIN)
+#include "base/win/file_pre_reader.h"
+#endif
+
 namespace {
 
 // Spin for up to a second waiting for the lock to clear when setting
@@ -355,6 +359,9 @@
     return;
   }
 
+#if defined(OS_WIN)
+  base::win::PreReadFile(DbPath(), false);
+#else
   // The constructor and set_page_size() ensure that page_size_ is never zero.
   const int page_size = page_size_;
   DCHECK(page_size);
@@ -383,6 +390,7 @@
     if (rc != SQLITE_OK)
       return;
   }
+#endif
 }
 
 // SQLite keeps unused pages associated with a database in a cache.  It asks
diff --git a/third_party/.gitignore b/third_party/.gitignore
index 4a0d413a..a0870189 100644
--- a/third_party/.gitignore
+++ b/third_party/.gitignore
@@ -130,6 +130,7 @@
 /libexif/sources
 /libFuzzer/src
 /libprotobuf-mutator/src
+/libipp/libipp
 /libjingle/source
 /libjpeg_turbo
 /liblouis/src
diff --git a/third_party/blink/public/BUILD.gn b/third_party/blink/public/BUILD.gn
index 42d03e0..93f8748 100644
--- a/third_party/blink/public/BUILD.gn
+++ b/third_party/blink/public/BUILD.gn
@@ -157,6 +157,7 @@
     "platform/modules/mediastream/web_platform_media_stream_track.h",
     "platform/modules/mediastream/webrtc_uma_histograms.h",
     "platform/modules/peerconnection/audio_codec_factory.h",
+    "platform/modules/peerconnection/rtc_event_log_output_sink.h",
     "platform/modules/remoteplayback/web_remote_playback_client.h",
     "platform/modules/service_worker/web_service_worker_error.h",
     "platform/modules/service_worker/web_service_worker_network_provider.h",
diff --git a/third_party/blink/public/mojom/picture_in_picture/picture_in_picture.mojom b/third_party/blink/public/mojom/picture_in_picture/picture_in_picture.mojom
index 8a1d0a5..f8880f4 100644
--- a/third_party/blink/public/mojom/picture_in_picture/picture_in_picture.mojom
+++ b/third_party/blink/public/mojom/picture_in_picture/picture_in_picture.mojom
@@ -28,8 +28,7 @@
   Update(uint32 player_id,
       viz.mojom.SurfaceId? surface_id,
       gfx.mojom.Size natural_size,
-      bool show_play_pause_button,
-      bool show_mute_button);
+      bool show_play_pause_button);
 
   // Request to stop the current session. It will close the Picture-in-Picture
   // window and make other calls related to the session no-ops.
@@ -51,15 +50,12 @@
   // natural_size: Size of the video frames.
   // show_play_pause_button: Whether a play/pause control should be offered in
   //                         the Picture-in-Picture window.
-  // show_mute_button: Whether a mute control should be offered in the
-  //                   Picture-in-Picture window.
   // observer: Observer to be associated with the session.
   StartSession(
       uint32 player_id,
       viz.mojom.SurfaceId? surface_id,
       gfx.mojom.Size natural_size,
       bool show_play_pause_button,
-      bool show_mute_button,
       pending_remote<PictureInPictureSessionObserver> observer)
           => (pending_remote<PictureInPictureSession>? session, gfx.mojom.Size size);
 };
diff --git a/third_party/blink/public/platform/mac/web_scrollbar_theme.h b/third_party/blink/public/platform/mac/web_scrollbar_theme.h
index 9af5197c..0cfe437 100644
--- a/third_party/blink/public/platform/mac/web_scrollbar_theme.h
+++ b/third_party/blink/public/platform/mac/web_scrollbar_theme.h
@@ -31,6 +31,7 @@
 #ifndef THIRD_PARTY_BLINK_PUBLIC_PLATFORM_MAC_WEB_SCROLLBAR_THEME_H_
 #define THIRD_PARTY_BLINK_PUBLIC_PLATFORM_MAC_WEB_SCROLLBAR_THEME_H_
 
+#include "base/optional.h"
 #include "third_party/blink/public/platform/web_common.h"
 
 namespace blink {
@@ -50,8 +51,8 @@
   // |redraw| is true if the update requires a redraw to include the change.
   // |jump_on_track_click| is the current value of AppleScrollerPagingBehavior.
   BLINK_EXPORT static void UpdateScrollbarsWithNSDefaults(
-      float initial_button_delay,
-      float autoscroll_button_delay,
+      base::Optional<float> initial_button_delay,
+      base::Optional<float> autoscroll_button_delay,
       ScrollerStyle preferred_scroller_style,
       bool redraw,
       bool jump_on_track_click);
diff --git a/third_party/blink/public/platform/modules/peerconnection/rtc_event_log_output_sink.h b/third_party/blink/public/platform/modules/peerconnection/rtc_event_log_output_sink.h
new file mode 100644
index 0000000..12b5371
--- /dev/null
+++ b/third_party/blink/public/platform/modules/peerconnection/rtc_event_log_output_sink.h
@@ -0,0 +1,25 @@
+// Copyright (c) 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef THIRD_PARTY_BLINK_PUBLIC_PLATFORM_MODULES_PEERCONNECTION_RTC_EVENT_LOG_OUTPUT_SINK_H_
+#define THIRD_PARTY_BLINK_PUBLIC_PLATFORM_MODULES_PEERCONNECTION_RTC_EVENT_LOG_OUTPUT_SINK_H_
+
+#include <string>
+
+#include "third_party/blink/public/platform/web_common.h"
+
+namespace blink {
+
+// TODO(crbug.com/787254): Move this class out of the Blink exposed API
+// when all users of it have been Onion souped.
+class BLINK_PLATFORM_EXPORT RtcEventLogOutputSink {
+ public:
+  virtual ~RtcEventLogOutputSink() = default;
+
+  virtual void OnWebRtcEventLogWrite(const std::string& output) = 0;
+};
+
+}  // namespace blink
+
+#endif  // THIRD_PARTY_BLINK_PUBLIC_PLATFORM_MODULES_PEERCONNECTION_RTC_EVENT_LOG_OUTPUT_SINK_H_
diff --git a/third_party/blink/public/platform/web_rtc_rtp_source.h b/third_party/blink/public/platform/web_rtc_rtp_source.h
index f90acbd..959440f 100644
--- a/third_party/blink/public/platform/web_rtc_rtp_source.h
+++ b/third_party/blink/public/platform/web_rtc_rtp_source.h
@@ -12,6 +12,10 @@
 class TimeTicks;
 }
 
+namespace webrtc {
+class RtpSource;
+}
+
 namespace blink {
 
 // Represents both SSRCs and CSRCs.
@@ -33,6 +37,9 @@
   virtual uint32_t RtpTimestamp() const = 0;
 };
 
+BLINK_PLATFORM_EXPORT std::unique_ptr<WebRTCRtpSource> CreateRTCRtpSource(
+    const webrtc::RtpSource& source);
+
 }  // namespace blink
 
 #endif  // THIRD_PARTY_BLINK_PUBLIC_PLATFORM_WEB_RTC_RTP_SOURCE_H_
diff --git a/third_party/blink/renderer/core/BUILD.gn b/third_party/blink/renderer/core/BUILD.gn
index 9e948d72..158fc92 100644
--- a/third_party/blink/renderer/core/BUILD.gn
+++ b/third_party/blink/renderer/core/BUILD.gn
@@ -1259,6 +1259,7 @@
     "html/html_link_element_test.cc",
     "html/html_meta_element_test.cc",
     "html/html_object_element_test.cc",
+    "html/html_plugin_element_test.cc",
     "html/html_slot_element_test.cc",
     "html/html_table_row_element_test.cc",
     "html/image_document_test.cc",
diff --git a/third_party/blink/renderer/core/events/promise_rejection_event.cc b/third_party/blink/renderer/core/events/promise_rejection_event.cc
index d8cfbb6..1c974474 100644
--- a/third_party/blink/renderer/core/events/promise_rejection_event.cc
+++ b/third_party/blink/renderer/core/events/promise_rejection_event.cc
@@ -25,14 +25,6 @@
 
 PromiseRejectionEvent::~PromiseRejectionEvent() = default;
 
-void PromiseRejectionEvent::Dispose() {
-  // Clear ScopedPersistents so that V8 doesn't call phantom callbacks
-  // (and touch the ScopedPersistents) after Oilpan starts lazy sweeping.
-  promise_.Clear();
-  reason_.Clear();
-  world_ = nullptr;
-}
-
 ScriptPromise PromiseRejectionEvent::promise(ScriptState* script_state) const {
   // Return null when the promise is accessed by a different world than the
   // world that created the promise.
@@ -57,7 +49,8 @@
 
 bool PromiseRejectionEvent::CanBeDispatchedInWorld(
     const DOMWrapperWorld& world) const {
-  return world_ && world_->GetWorldId() == world.GetWorldId();
+  DCHECK(world_);
+  return world_->GetWorldId() == world.GetWorldId();
 }
 
 void PromiseRejectionEvent::Trace(blink::Visitor* visitor) {
diff --git a/third_party/blink/renderer/core/events/promise_rejection_event.h b/third_party/blink/renderer/core/events/promise_rejection_event.h
index afcc54a..78786ef7 100644
--- a/third_party/blink/renderer/core/events/promise_rejection_event.h
+++ b/third_party/blink/renderer/core/events/promise_rejection_event.h
@@ -18,7 +18,6 @@
 
 class CORE_EXPORT PromiseRejectionEvent final : public Event {
   DEFINE_WRAPPERTYPEINFO();
-  USING_PRE_FINALIZER(PromiseRejectionEvent, Dispose);
 
  public:
   static PromiseRejectionEvent* Create(
@@ -46,7 +45,6 @@
 
  private:
   ~PromiseRejectionEvent() override;
-  void Dispose();
 
   scoped_refptr<DOMWrapperWorld> world_;
   TraceWrapperV8Reference<v8::Value> promise_;
diff --git a/third_party/blink/renderer/core/frame/local_frame_view.cc b/third_party/blink/renderer/core/frame/local_frame_view.cc
index 73b7574..08dfb2ee 100644
--- a/third_party/blink/renderer/core/frame/local_frame_view.cc
+++ b/third_party/blink/renderer/core/frame/local_frame_view.cc
@@ -3455,6 +3455,11 @@
   plugins_.insert(plugin);
 }
 
+void LocalFrameView::RemovePlugin(WebPluginContainerImpl* plugin) {
+  DCHECK(plugins_.Contains(plugin));
+  plugins_.erase(plugin);
+}
+
 void LocalFrameView::RemoveScrollbar(Scrollbar* scrollbar) {
   DCHECK(scrollbars_.Contains(scrollbar));
   scrollbars_.erase(scrollbar);
diff --git a/third_party/blink/renderer/core/frame/local_frame_view.h b/third_party/blink/renderer/core/frame/local_frame_view.h
index 0c895d0b..5a4238d 100644
--- a/third_party/blink/renderer/core/frame/local_frame_view.h
+++ b/third_party/blink/renderer/core/frame/local_frame_view.h
@@ -492,6 +492,7 @@
   using PluginSet = HeapHashSet<Member<WebPluginContainerImpl>>;
   const PluginSet& Plugins() const { return plugins_; }
   void AddPlugin(WebPluginContainerImpl*);
+  void RemovePlugin(WebPluginContainerImpl*);
   // Custom scrollbars in PaintLayerScrollableArea need to be called with
   // StyleChanged whenever window focus is changed.
   void RemoveScrollbar(Scrollbar*);
diff --git a/third_party/blink/renderer/core/frame/use_counter_helper.cc b/third_party/blink/renderer/core/frame/use_counter_helper.cc
index 6d903fe..6038cd2 100644
--- a/third_party/blink/renderer/core/frame/use_counter_helper.cc
+++ b/third_party/blink/renderer/core/frame/use_counter_helper.cc
@@ -25,7 +25,6 @@
 
 #include "third_party/blink/renderer/core/frame/use_counter_helper.h"
 
-#include "third_party/blink/public/mojom/use_counter/css_property_id.mojom-blink.h"
 #include "third_party/blink/renderer/core/css/css_style_sheet.h"
 #include "third_party/blink/renderer/core/css/style_sheet_contents.h"
 #include "third_party/blink/renderer/core/dom/document.h"
diff --git a/third_party/blink/renderer/core/frame/use_counter_helper.h b/third_party/blink/renderer/core/frame/use_counter_helper.h
index 00e7d69..6c12e3e 100644
--- a/third_party/blink/renderer/core/frame/use_counter_helper.h
+++ b/third_party/blink/renderer/core/frame/use_counter_helper.h
@@ -28,6 +28,7 @@
 
 #include <bitset>
 #include "base/macros.h"
+#include "third_party/blink/public/mojom/use_counter/css_property_id.mojom-blink.h"
 #include "third_party/blink/renderer/core/core_export.h"
 #include "third_party/blink/renderer/core/css/css_property_names.h"
 #include "third_party/blink/renderer/core/css/parser/css_parser_mode.h"
@@ -163,13 +164,10 @@
   std::bitset<static_cast<size_t>(WebFeature::kNumberOfFeatures)>
       features_recorded_;
 
-  // TODO(majidvp): Use CSSSampleId::kMaxValue here. We insert CSSSampleId into
-  // this bitset so max value should reflect that. At the moment
-  // numCSSPropertyIDs (currently 995) is larger than CSSSampleId:kMaxValue
-  // (currently 645) so while inefficient it is safe to use but this can change
-  // in future.
-  std::bitset<numCSSPropertyIDs> css_recorded_;
-  std::bitset<numCSSPropertyIDs> animated_css_recorded_;
+  static constexpr size_t kMaxSample =
+      static_cast<size_t>(mojom::CSSSampleId::kMaxValue) + 1;
+  std::bitset<kMaxSample> css_recorded_;
+  std::bitset<kMaxSample> animated_css_recorded_;
 
   HeapHashSet<Member<Observer>> observers_;
 
diff --git a/third_party/blink/renderer/core/html/html_plugin_element.cc b/third_party/blink/renderer/core/html/html_plugin_element.cc
index ee41419..52dba9c 100644
--- a/third_party/blink/renderer/core/html/html_plugin_element.cc
+++ b/third_party/blink/renderer/core/html/html_plugin_element.cc
@@ -312,6 +312,7 @@
   if (!performing_reattach)
     SetDisposeView();
 
+  RemovePluginFromFrameView(plugin);
   ResetInstance();
 
   HTMLFrameOwnerElement::DetachLayoutTree(performing_reattach);
@@ -626,7 +627,9 @@
   loaded_url_ = url;
 
   if (persisted_plugin_) {
+    auto* plugin = persisted_plugin_.Get();
     SetEmbeddedContentView(persisted_plugin_.Release());
+    layout_object->GetFrameView()->AddPlugin(plugin);
   } else {
     bool load_manually =
         GetDocument().IsPluginDocument() && !GetDocument().ContainsPlugins();
@@ -634,7 +637,7 @@
         *this, url, plugin_params.Names(), plugin_params.Values(), mime_type,
         load_manually);
     if (!plugin) {
-      if (layout_object && !layout_object->ShowsUnavailablePluginIndicator()) {
+      if (!layout_object->ShowsUnavailablePluginIndicator()) {
         plugin_is_available_ = false;
         layout_object->SetPluginAvailability(
             LayoutEmbeddedObject::kPluginMissing);
@@ -642,12 +645,8 @@
       return false;
     }
 
-    if (layout_object) {
-      SetEmbeddedContentView(plugin);
-      layout_object->GetFrameView()->AddPlugin(plugin);
-    } else {
-      SetPersistedPlugin(plugin);
-    }
+    SetEmbeddedContentView(plugin);
+    layout_object->GetFrameView()->AddPlugin(plugin);
   }
 
   GetDocument().SetContainsPlugins();
@@ -722,6 +721,25 @@
   return true;
 }
 
+void HTMLPlugInElement::RemovePluginFromFrameView(
+    WebPluginContainerImpl* plugin) {
+  if (!plugin)
+    return;
+
+  auto* layout_object = GetLayoutEmbeddedObject();
+  if (!layout_object)
+    return;
+
+  auto* frame_view = layout_object->GetFrameView();
+  if (!frame_view)
+    return;
+
+  if (!frame_view->Plugins().Contains(plugin))
+    return;
+
+  frame_view->RemovePlugin(plugin);
+}
+
 void HTMLPlugInElement::DidAddUserAgentShadowRoot(ShadowRoot&) {
   UserAgentShadowRoot()->AppendChild(
       HTMLSlotElement::CreateUserAgentDefaultSlot(GetDocument()));
diff --git a/third_party/blink/renderer/core/html/html_plugin_element.h b/third_party/blink/renderer/core/html/html_plugin_element.h
index 053689c9..7d19199 100644
--- a/third_party/blink/renderer/core/html/html_plugin_element.h
+++ b/third_party/blink/renderer/core/html/html_plugin_element.h
@@ -200,6 +200,7 @@
   bool AllowedToLoadPlugin(const KURL&, const String& mime_type);
   // Perform checks based on the URL and MIME-type of the object to load.
   bool AllowedToLoadObject(const KURL&, const String& mime_type);
+  void RemovePluginFromFrameView(WebPluginContainerImpl* plugin);
 
   enum class ObjectContentType {
     kNone,
diff --git a/third_party/blink/renderer/core/html/html_plugin_element_test.cc b/third_party/blink/renderer/core/html/html_plugin_element_test.cc
new file mode 100644
index 0000000..295f95d
--- /dev/null
+++ b/third_party/blink/renderer/core/html/html_plugin_element_test.cc
@@ -0,0 +1,138 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "third_party/blink/renderer/core/html/html_plugin_element.h"
+
+#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/blink/public/web/web_plugin_params.h"
+#include "third_party/blink/renderer/core/dom/document.h"
+#include "third_party/blink/renderer/core/exported/web_plugin_container_impl.h"
+#include "third_party/blink/renderer/core/frame/settings.h"
+#include "third_party/blink/renderer/core/loader/empty_clients.h"
+#include "third_party/blink/renderer/core/testing/fake_web_plugin.h"
+#include "third_party/blink/renderer/core/testing/page_test_base.h"
+#include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
+
+namespace blink {
+
+namespace {
+
+class TestPluginLocalFrameClient : public EmptyLocalFrameClient {
+ public:
+  TestPluginLocalFrameClient() = default;
+
+  int plugin_created_count() const { return plugin_created_count_; }
+
+ private:
+  std::unique_ptr<WebURLLoaderFactory> CreateURLLoaderFactory() override {
+    return Platform::Current()->CreateDefaultURLLoaderFactory();
+  }
+
+  WebPluginContainerImpl* CreatePlugin(HTMLPlugInElement& element,
+                                       const KURL& url,
+                                       const Vector<String>& param_names,
+                                       const Vector<String>& param_values,
+                                       const String& mime_type,
+                                       bool load_manually) override {
+    ++plugin_created_count_;
+
+    // Based on LocalFrameClientImpl::CreatePlugin
+    WebPluginParams params;
+    params.url = url;
+    params.mime_type = mime_type;
+    params.attribute_names = param_names;
+    params.attribute_values = param_values;
+    params.load_manually = load_manually;
+
+    WebPlugin* web_plugin = new FakeWebPlugin(params);
+    if (!web_plugin)
+      return nullptr;
+
+    // The container takes ownership of the WebPlugin.
+    auto* container =
+        MakeGarbageCollected<WebPluginContainerImpl>(element, web_plugin);
+
+    if (!web_plugin->Initialize(container))
+      return nullptr;
+
+    if (!element.GetLayoutObject())
+      return nullptr;
+
+    return container;
+  }
+
+  int plugin_created_count_ = 0;
+};
+
+}  // namespace
+
+class HTMLPlugInElementTest : public PageTestBase,
+                              public testing::WithParamInterface<const char*> {
+ protected:
+  void SetUp() final {
+    frame_client_ = MakeGarbageCollected<TestPluginLocalFrameClient>();
+    PageTestBase::SetupPageWithClients(nullptr, frame_client_, nullptr);
+    GetFrame().GetSettings()->SetPluginsEnabled(true);
+  }
+
+  void TearDown() final {
+    PageTestBase::TearDown();
+    frame_client_ = nullptr;
+  }
+
+  LocalFrameView& GetFrameView() const {
+    return GetDummyPageHolder().GetFrameView();
+  }
+
+  int plugin_created_count() const {
+    return frame_client_->plugin_created_count();
+  }
+
+ private:
+  Persistent<TestPluginLocalFrameClient> frame_client_;
+};
+
+INSTANTIATE_TEST_SUITE_P(,
+                         HTMLPlugInElementTest,
+                         testing::Values("embed", "object"));
+
+TEST_P(HTMLPlugInElementTest, RemovePlugin) {
+  constexpr char kDivWithPlugin[] = R"HTML(
+    <div>
+      <%s id='test_plugin'
+          type='application/x-test-plugin'
+          src='test_plugin'>
+      </%s>
+    </div>
+  )HTML";
+
+  const char* container_type = GetParam();
+  GetDocument().body()->SetInnerHTMLFromString(
+      String::Format(kDivWithPlugin, container_type, container_type));
+
+  auto* plugin =
+      ToHTMLPlugInElement(GetDocument().getElementById("test_plugin"));
+  ASSERT_TRUE(plugin);
+  EXPECT_EQ(container_type, plugin->tagName().LowerASCII());
+
+  UpdateAllLifecyclePhasesForTest();
+  plugin->UpdatePlugin();
+
+  EXPECT_EQ(1, plugin_created_count());
+
+  auto* owned_plugin = plugin->OwnedPlugin();
+  ASSERT_TRUE(owned_plugin);
+
+  EXPECT_EQ(1u, GetFrameView().Plugins().size());
+  ASSERT_TRUE(GetFrameView().Plugins().Contains(owned_plugin));
+
+  plugin->parentNode()->removeChild(plugin);
+  EXPECT_FALSE(GetDocument().HasElementWithId("test_plugin"));
+
+  UpdateAllLifecyclePhasesForTest();
+  EXPECT_EQ(0u, GetFrameView().Plugins().size());
+  EXPECT_FALSE(GetFrameView().Plugins().Contains(owned_plugin));
+}
+
+}  // namespace blink
diff --git a/third_party/blink/renderer/core/html/media/video_wake_lock_test.cc b/third_party/blink/renderer/core/html/media/video_wake_lock_test.cc
index 189922e..6a2d579 100644
--- a/third_party/blink/renderer/core/html/media/video_wake_lock_test.cc
+++ b/third_party/blink/renderer/core/html/media/video_wake_lock_test.cc
@@ -38,8 +38,7 @@
   void Update(uint32_t player_id,
               const base::Optional<viz::SurfaceId>&,
               const blink::WebSize&,
-              bool show_play_pause_button,
-              bool show_mute_button) final {}
+              bool show_play_pause_button) final {}
 
  private:
   mojo::Receiver<mojom::blink::PictureInPictureSession> receiver_;
@@ -64,7 +63,6 @@
       const base::Optional<viz::SurfaceId>&,
       const blink::WebSize&,
       bool,
-      bool,
       mojo::PendingRemote<mojom::blink::PictureInPictureSessionObserver>,
       StartSessionCallback callback) final {
     mojo::PendingRemote<mojom::blink::PictureInPictureSession> session_remote;
diff --git a/third_party/blink/renderer/core/loader/cookie_jar.cc b/third_party/blink/renderer/core/loader/cookie_jar.cc
index 5bb98eac..2f68fd3c 100644
--- a/third_party/blink/renderer/core/loader/cookie_jar.cc
+++ b/third_party/blink/renderer/core/loader/cookie_jar.cc
@@ -52,9 +52,10 @@
 }
 
 void CookieJar::RequestRestrictedCookieManagerIfNeeded() {
-  if (!backend_.is_bound() || backend_.encountered_error()) {
+  if (!backend_.is_bound() || !backend_.is_connected()) {
+    backend_.reset();
     document_->GetInterfaceProvider()->GetInterface(
-        mojo::MakeRequest(&backend_));
+        backend_.BindNewPipeAndPassReceiver());
   }
 }
 
diff --git a/third_party/blink/renderer/core/loader/cookie_jar.h b/third_party/blink/renderer/core/loader/cookie_jar.h
index bd2fd5a..f1602d1 100644
--- a/third_party/blink/renderer/core/loader/cookie_jar.h
+++ b/third_party/blink/renderer/core/loader/cookie_jar.h
@@ -7,6 +7,7 @@
 
 #include "services/network/public/mojom/restricted_cookie_manager.mojom-blink.h"
 
+#include "mojo/public/cpp/bindings/remote.h"
 #include "third_party/blink/renderer/platform/heap/persistent.h"
 #include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
 
@@ -25,7 +26,7 @@
  private:
   void RequestRestrictedCookieManagerIfNeeded();
 
-  network::mojom::blink::RestrictedCookieManagerPtr backend_;
+  mojo::Remote<network::mojom::blink::RestrictedCookieManager> backend_;
   WeakPersistent<blink::Document> document_;  // Document owns |this|.
 };
 
diff --git a/third_party/blink/renderer/core/paint/paint_layer_scrollable_area.cc b/third_party/blink/renderer/core/paint/paint_layer_scrollable_area.cc
index f630930..410c9ee 100644
--- a/third_party/blink/renderer/core/paint/paint_layer_scrollable_area.cc
+++ b/third_party/blink/renderer/core/paint/paint_layer_scrollable_area.cc
@@ -1647,8 +1647,15 @@
                                           orientation == kVerticalScrollbar);
 }
 
+bool PaintLayerScrollableArea::HasOverflowControls() const {
+  // We do not need to check for ScrollCorner because it only exists iff there
+  // are scrollbars, see: |ScrollCornerRect| and |UpdateScrollCornerStyle|.
+  DCHECK(!ScrollCorner() || HasScrollbar());
+  return HasScrollbar() || GetLayoutBox()->CanResize();
+}
+
 void PaintLayerScrollableArea::PositionOverflowControls() {
-  if (!HasOverflowControls() && !GetLayoutBox()->CanResize())
+  if (!HasOverflowControls())
     return;
 
   const IntRect border_box =
@@ -1660,9 +1667,8 @@
   if (Scrollbar* horizontal_scrollbar = HorizontalScrollbar())
     horizontal_scrollbar->SetFrameRect(RectForHorizontalScrollbar(border_box));
 
-  const IntRect& scroll_corner = ScrollCornerRect();
   if (scroll_corner_)
-    scroll_corner_->SetFrameRect(LayoutRect(scroll_corner));
+    scroll_corner_->SetFrameRect(LayoutRect(ScrollCornerRect()));
 
   if (resizer_)
     resizer_->SetFrameRect(
@@ -1704,7 +1710,7 @@
 bool PaintLayerScrollableArea::HitTestOverflowControls(
     HitTestResult& result,
     const IntPoint& local_point) {
-  if (!HasScrollbar() && !GetLayoutBox()->CanResize())
+  if (!HasOverflowControls())
     return false;
 
   IntRect resize_control_rect;
diff --git a/third_party/blink/renderer/core/paint/paint_layer_scrollable_area.h b/third_party/blink/renderer/core/paint/paint_layer_scrollable_area.h
index d3aa31c..786664f 100644
--- a/third_party/blink/renderer/core/paint/paint_layer_scrollable_area.h
+++ b/third_party/blink/renderer/core/paint/paint_layer_scrollable_area.h
@@ -377,9 +377,11 @@
   bool HasScrollbar() const {
     return HasHorizontalScrollbar() || HasVerticalScrollbar();
   }
-  bool HasOverflowControls() const {
-    return HasScrollbar() || ScrollCorner() || Resizer();
-  }
+  // Overflow controls are scrollbars, scroll corners, and resizers. The
+  // |scroll_corner_| and |resizer_| scrollbar parts are only created for
+  // specific pseudo styles but there can still be a scroll corner control or
+  // resize control without these custom styled scrollbar parts.
+  bool HasOverflowControls() const;
   bool HasOverflow() const {
     return HasHorizontalOverflow() || HasVerticalOverflow();
   }
diff --git a/third_party/blink/renderer/core/scroll/scrollbar_theme_mac.h b/third_party/blink/renderer/core/scroll/scrollbar_theme_mac.h
index 11cf27e..0365d27 100644
--- a/third_party/blink/renderer/core/scroll/scrollbar_theme_mac.h
+++ b/third_party/blink/renderer/core/scroll/scrollbar_theme_mac.h
@@ -95,8 +95,8 @@
 
   // See WebScrollbarTheme for parameters description.
   static void UpdateScrollbarsWithNSDefaults(
-      float initial_button_delay,
-      float autoscroll_button_delay,
+      base::Optional<float> initial_button_delay,
+      base::Optional<float> autoscroll_button_delay,
       NSScrollerStyle preferred_scroller_style,
       bool redraw,
       bool jump_on_track_click);
diff --git a/third_party/blink/renderer/core/scroll/scrollbar_theme_mac.mm b/third_party/blink/renderer/core/scroll/scrollbar_theme_mac.mm
index 6219cb1..b1bdc89 100644
--- a/third_party/blink/renderer/core/scroll/scrollbar_theme_mac.mm
+++ b/third_party/blink/renderer/core/scroll/scrollbar_theme_mac.mm
@@ -415,13 +415,15 @@
 
 // static
 void ScrollbarThemeMac::UpdateScrollbarsWithNSDefaults(
-    float initial_button_delay,
-    float autoscroll_button_delay,
+    base::Optional<float> initial_button_delay,
+    base::Optional<float> autoscroll_button_delay,
     NSScrollerStyle preferred_scroller_style,
     bool redraw,
     bool jump_on_track_click) {
-  s_initial_button_delay = initial_button_delay;
-  s_autoscroll_button_delay = autoscroll_button_delay;
+  s_initial_button_delay =
+      initial_button_delay.value_or(s_initial_button_delay);
+  s_autoscroll_button_delay =
+      autoscroll_button_delay.value_or(s_autoscroll_button_delay);
   s_preferred_scroller_style = preferred_scroller_style;
   s_jump_on_track_click = jump_on_track_click;
   if (redraw) {
diff --git a/third_party/blink/renderer/core/scroll/web_scrollbar_theme.mm b/third_party/blink/renderer/core/scroll/web_scrollbar_theme.mm
index 55530f5..bde3fec 100644
--- a/third_party/blink/renderer/core/scroll/web_scrollbar_theme.mm
+++ b/third_party/blink/renderer/core/scroll/web_scrollbar_theme.mm
@@ -45,8 +45,8 @@
               "ScrollerStyleOverlay must match NSScrollerStyleOverlay");
 
 void WebScrollbarTheme::UpdateScrollbarsWithNSDefaults(
-    float initial_button_delay,
-    float autoscroll_button_delay,
+    base::Optional<float> initial_button_delay,
+    base::Optional<float> autoscroll_button_delay,
     ScrollerStyle preferred_scroller_style,
     bool redraw,
     bool jump_on_track_click) {
diff --git a/third_party/blink/renderer/devtools/front_end/resources/IndexedDBModel.js b/third_party/blink/renderer/devtools/front_end/resources/IndexedDBModel.js
index 6ae3f07..8a95859 100644
--- a/third_party/blink/renderer/devtools/front_end/resources/IndexedDBModel.js
+++ b/third_party/blink/renderer/devtools/front_end/resources/IndexedDBModel.js
@@ -160,7 +160,7 @@
    * @param {string} origin
    */
   clearForOrigin(origin) {
-    if (!this._enabled)
+    if (!this._enabled || !this._databaseNamesBySecurityOrigin[origin])
       return;
 
     this._removeOrigin(origin);
diff --git a/third_party/blink/renderer/modules/cookie_store/cookie_store.cc b/third_party/blink/renderer/modules/cookie_store/cookie_store.cc
index 47a43c3c..3585a84 100644
--- a/third_party/blink/renderer/modules/cookie_store/cookie_store.cc
+++ b/third_party/blink/renderer/modules/cookie_store/cookie_store.cc
@@ -456,7 +456,7 @@
 
 CookieStore::CookieStore(
     ExecutionContext* execution_context,
-    network::mojom::blink::RestrictedCookieManagerPtr backend,
+    mojo::Remote<network::mojom::blink::RestrictedCookieManager> backend,
     mojo::Remote<blink::mojom::blink::CookieStore> subscription_backend)
     : ContextLifecycleObserver(execution_context),
       backend_(std::move(backend)),
diff --git a/third_party/blink/renderer/modules/cookie_store/cookie_store.h b/third_party/blink/renderer/modules/cookie_store/cookie_store.h
index 606218e..d85631f 100644
--- a/third_party/blink/renderer/modules/cookie_store/cookie_store.h
+++ b/third_party/blink/renderer/modules/cookie_store/cookie_store.h
@@ -37,9 +37,10 @@
  public:
   CookieStore(
       ExecutionContext*,
-      network::mojom::blink::RestrictedCookieManagerPtr backend,
+      mojo::Remote<network::mojom::blink::RestrictedCookieManager> backend,
       mojo::Remote<blink::mojom::blink::CookieStore> subscription_backend);
-  // Needed because of the network::mojom::blink::RestrictedCookieManagerPtr
+  // Needed because of the
+  // mojo::Remote<network::mojom::blink::RestrictedCookieManager>
   ~CookieStore() override;
 
   ScriptPromise getAll(ScriptState*, const String& name, ExceptionState&);
@@ -146,7 +147,7 @@
   void StopObserving();
 
   // Wraps an always-on Mojo pipe for sending requests to the Network Service.
-  network::mojom::blink::RestrictedCookieManagerPtr backend_;
+  mojo::Remote<network::mojom::blink::RestrictedCookieManager> backend_;
 
   // Wraps a Mojo pipe for managing service worker cookie change subscriptions.
   //
diff --git a/third_party/blink/renderer/modules/cookie_store/service_worker_global_scope_cookie_store.cc b/third_party/blink/renderer/modules/cookie_store/service_worker_global_scope_cookie_store.cc
index daeaadc..586f5394 100644
--- a/third_party/blink/renderer/modules/cookie_store/service_worker_global_scope_cookie_store.cc
+++ b/third_party/blink/renderer/modules/cookie_store/service_worker_global_scope_cookie_store.cc
@@ -19,18 +19,18 @@
 CookieStore* GlobalCookieStoreImpl<WorkerGlobalScope>::BuildCookieStore(
     ExecutionContext* execution_context,
     service_manager::InterfaceProvider* interface_provider) {
-  network::mojom::blink::RestrictedCookieManagerPtr cookie_manager_ptr;
-  interface_provider->GetInterface(mojo::MakeRequest(
-      &cookie_manager_ptr,
-      execution_context->GetTaskRunner(TaskType::kMiscPlatformAPI)));
-
+  mojo::Remote<network::mojom::blink::RestrictedCookieManager>
+      cookie_manager_remote;
+  interface_provider->GetInterface(
+      cookie_manager_remote.BindNewPipeAndPassReceiver(
+          execution_context->GetTaskRunner(TaskType::kMiscPlatformAPI)));
   mojo::Remote<blink::mojom::blink::CookieStore> cookie_store_remote;
   interface_provider->GetInterface(
       cookie_store_remote.BindNewPipeAndPassReceiver(
           execution_context->GetTaskRunner(TaskType::kMiscPlatformAPI)));
 
   return MakeGarbageCollected<CookieStore>(execution_context,
-                                           std::move(cookie_manager_ptr),
+                                           std::move(cookie_manager_remote),
                                            std::move(cookie_store_remote));
 }
 
diff --git a/third_party/blink/renderer/modules/cookie_store/window_cookie_store.cc b/third_party/blink/renderer/modules/cookie_store/window_cookie_store.cc
index bae54f40..666e592 100644
--- a/third_party/blink/renderer/modules/cookie_store/window_cookie_store.cc
+++ b/third_party/blink/renderer/modules/cookie_store/window_cookie_store.cc
@@ -19,13 +19,14 @@
 CookieStore* GlobalCookieStoreImpl<LocalDOMWindow>::BuildCookieStore(
     ExecutionContext* execution_context,
     service_manager::InterfaceProvider* interface_provider) {
-  network::mojom::blink::RestrictedCookieManagerPtr cookie_manager_ptr;
+  mojo::Remote<network::mojom::blink::RestrictedCookieManager>
+      cookie_manager_remote;
   // See https://bit.ly/2S0zRAS for task types.
-  interface_provider->GetInterface(mojo::MakeRequest(
-      &cookie_manager_ptr,
-      execution_context->GetTaskRunner(TaskType::kMiscPlatformAPI)));
+  interface_provider->GetInterface(
+      cookie_manager_remote.BindNewPipeAndPassReceiver(
+          execution_context->GetTaskRunner(TaskType::kMiscPlatformAPI)));
   return MakeGarbageCollected<CookieStore>(
-      execution_context, std::move(cookie_manager_ptr),
+      execution_context, std::move(cookie_manager_remote),
       mojo::Remote<blink::mojom::blink::CookieStore>());
 }
 
diff --git a/third_party/blink/renderer/modules/picture_in_picture/picture_in_picture_controller_impl.cc b/third_party/blink/renderer/modules/picture_in_picture/picture_in_picture_controller_impl.cc
index d594908..b5490ca 100644
--- a/third_party/blink/renderer/modules/picture_in_picture/picture_in_picture_controller_impl.cc
+++ b/third_party/blink/renderer/modules/picture_in_picture/picture_in_picture_controller_impl.cc
@@ -177,8 +177,7 @@
       video_element->GetWebMediaPlayer()->GetDelegateId(),
       video_element->GetWebMediaPlayer()->GetSurfaceId(),
       video_element->GetWebMediaPlayer()->NaturalSize(),
-      ShouldShowPlayPauseButton(*video_element),
-      ShouldShowMuteButton(*video_element), std::move(session_observer),
+      ShouldShowPlayPauseButton(*video_element), std::move(session_observer),
       WTF::Bind(&PictureInPictureControllerImpl::OnEnteredPictureInPicture,
                 WrapPersistent(this), WrapPersistent(video_element),
                 WrapPersistent(resolver)));
@@ -386,8 +385,7 @@
       picture_in_picture_element_->GetWebMediaPlayer()->GetDelegateId(),
       picture_in_picture_element_->GetWebMediaPlayer()->GetSurfaceId(),
       picture_in_picture_element_->GetWebMediaPlayer()->NaturalSize(),
-      ShouldShowPlayPauseButton(*picture_in_picture_element_),
-      ShouldShowMuteButton(*picture_in_picture_element_));
+      ShouldShowPlayPauseButton(*picture_in_picture_element_));
 }
 
 void PictureInPictureControllerImpl::OnWindowSizeChanged(
@@ -400,13 +398,6 @@
   OnExitedPictureInPicture(nullptr);
 }
 
-bool PictureInPictureControllerImpl::ShouldShowMuteButton(
-    const HTMLVideoElement& element) {
-  DCHECK(GetSupplementable());
-  return element.HasAudio() && RuntimeEnabledFeatures::MuteButtonEnabled(
-                                   GetSupplementable()->GetExecutionContext());
-}
-
 void PictureInPictureControllerImpl::Trace(blink::Visitor* visitor) {
   visitor->Trace(picture_in_picture_element_);
   visitor->Trace(auto_picture_in_picture_elements_);
diff --git a/third_party/blink/renderer/modules/picture_in_picture/picture_in_picture_controller_impl.h b/third_party/blink/renderer/modules/picture_in_picture/picture_in_picture_controller_impl.h
index 46ad6ac..916fcc2 100644
--- a/third_party/blink/renderer/modules/picture_in_picture/picture_in_picture_controller_impl.h
+++ b/third_party/blink/renderer/modules/picture_in_picture/picture_in_picture_controller_impl.h
@@ -116,10 +116,6 @@
   // initialized successfully.
   bool EnsureService();
 
-  // Returns true if video has an audio track and if MuteButton origin trial is
-  // enabled. Otherwise it returns false.
-  bool ShouldShowMuteButton(const HTMLVideoElement& element);
-
   // The Picture-in-Picture element for the associated document.
   Member<HTMLVideoElement> picture_in_picture_element_;
 
diff --git a/third_party/blink/renderer/modules/picture_in_picture/picture_in_picture_controller_test.cc b/third_party/blink/renderer/modules/picture_in_picture/picture_in_picture_controller_test.cc
index 65e4c812..169a910 100644
--- a/third_party/blink/renderer/modules/picture_in_picture/picture_in_picture_controller_test.cc
+++ b/third_party/blink/renderer/modules/picture_in_picture/picture_in_picture_controller_test.cc
@@ -44,11 +44,10 @@
   ~MockPictureInPictureSession() override = default;
 
   MOCK_METHOD1(Stop, void(StopCallback));
-  MOCK_METHOD5(Update,
+  MOCK_METHOD4(Update,
                void(uint32_t,
                     const base::Optional<viz::SurfaceId>&,
                     const blink::WebSize&,
-                    bool,
                     bool));
 
  private:
@@ -63,7 +62,7 @@
  public:
   MockPictureInPictureService() {
     // Setup default implementations.
-    ON_CALL(*this, StartSession(_, _, _, _, _, _, _))
+    ON_CALL(*this, StartSession(_, _, _, _, _, _))
         .WillByDefault(testing::Invoke(
             this, &MockPictureInPictureService::StartSessionInternal));
   }
@@ -77,13 +76,12 @@
         session_remote_.InitWithNewPipeAndPassReceiver()));
   }
 
-  MOCK_METHOD7(
+  MOCK_METHOD6(
       StartSession,
       void(uint32_t,
            const base::Optional<viz::SurfaceId>&,
            const blink::WebSize&,
            bool,
-           bool,
            mojo::PendingRemote<mojom::blink::PictureInPictureSessionObserver>,
            StartSessionCallback));
 
@@ -94,7 +92,6 @@
       const base::Optional<viz::SurfaceId>&,
       const blink::WebSize&,
       bool,
-      bool,
       mojo::PendingRemote<mojom::blink::PictureInPictureSessionObserver>,
       StartSessionCallback callback) {
     std::move(callback).Run(std::move(session_remote_), WebSize());
@@ -203,7 +200,7 @@
   WebMediaPlayer* player = Video()->GetWebMediaPlayer();
   EXPECT_CALL(Service(),
               StartSession(player->GetDelegateId(), player->GetSurfaceId(),
-                           player->NaturalSize(), true, false, _, _));
+                           player->NaturalSize(), true, _, _));
 
   PictureInPictureControllerImpl::From(GetDocument())
       .EnterPictureInPicture(Video(), nullptr /* options */,
@@ -223,7 +220,7 @@
   WebMediaPlayer* player = Video()->GetWebMediaPlayer();
   EXPECT_CALL(Service(),
               StartSession(player->GetDelegateId(), player->GetSurfaceId(),
-                           player->NaturalSize(), true, false, _, _));
+                           player->NaturalSize(), true, _, _));
 
   PictureInPictureControllerImpl::From(GetDocument())
       .EnterPictureInPicture(Video(), nullptr /* options */,
@@ -251,7 +248,7 @@
   WebMediaPlayer* player = Video()->GetWebMediaPlayer();
   EXPECT_CALL(Service(),
               StartSession(player->GetDelegateId(), player->GetSurfaceId(),
-                           player->NaturalSize(), true, false, _, _));
+                           player->NaturalSize(), true, _, _));
 
   PictureInPictureControllerImpl::From(GetDocument())
       .EnterPictureInPicture(Video(), nullptr /* options */,
@@ -271,7 +268,7 @@
   WebMediaPlayer* player = Video()->GetWebMediaPlayer();
   EXPECT_CALL(Service(),
               StartSession(player->GetDelegateId(), player->GetSurfaceId(),
-                           player->NaturalSize(), true, false, _, _));
+                           player->NaturalSize(), true, _, _));
 
   PictureInPictureControllerImpl::From(GetDocument())
       .EnterPictureInPicture(Video(), nullptr /* options */,
@@ -300,7 +297,7 @@
   WebMediaPlayer* player = Video()->GetWebMediaPlayer();
   EXPECT_CALL(Service(),
               StartSession(player->GetDelegateId(), player->GetSurfaceId(),
-                           player->NaturalSize(), false, false, _, _));
+                           player->NaturalSize(), false, _, _));
 
   PictureInPictureControllerImpl::From(GetDocument())
       .EnterPictureInPicture(Video(), nullptr /* options */,
@@ -320,7 +317,7 @@
   WebMediaPlayer* player = Video()->GetWebMediaPlayer();
   EXPECT_CALL(Service(),
               StartSession(player->GetDelegateId(), player->GetSurfaceId(),
-                           player->NaturalSize(), false, false, _, _));
+                           player->NaturalSize(), false, _, _));
 
   PictureInPictureControllerImpl::From(GetDocument())
       .EnterPictureInPicture(Video(), nullptr /* options */,
diff --git a/third_party/blink/renderer/modules/webgpu/dawn_conversions.cc b/third_party/blink/renderer/modules/webgpu/dawn_conversions.cc
index 10f9d5b..e63e66d 100644
--- a/third_party/blink/renderer/modules/webgpu/dawn_conversions.cc
+++ b/third_party/blink/renderer/modules/webgpu/dawn_conversions.cc
@@ -86,6 +86,10 @@
 template <>
 DawnTextureFormat AsDawnEnum<DawnTextureFormat>(
     const WTF::String& webgpu_enum) {
+  if (webgpu_enum.IsNull()) {
+    return DAWN_TEXTURE_FORMAT_NONE;
+  }
+
   // Normal 8 bit formats
   if (webgpu_enum == "r8unorm") {
     return DAWN_TEXTURE_FORMAT_R8_UNORM;
@@ -231,6 +235,9 @@
 template <>
 DawnTextureViewDimension AsDawnEnum<DawnTextureViewDimension>(
     const WTF::String& webgpu_enum) {
+  if (webgpu_enum.IsNull()) {
+    return DAWN_TEXTURE_VIEW_DIMENSION_NONE;
+  }
   if (webgpu_enum == "2d") {
     return DAWN_TEXTURE_VIEW_DIMENSION_2D;
   }
diff --git a/third_party/blink/renderer/modules/webgpu/gpu_bind_group_layout.cc b/third_party/blink/renderer/modules/webgpu/gpu_bind_group_layout.cc
index 0fda998..859082c 100644
--- a/third_party/blink/renderer/modules/webgpu/gpu_bind_group_layout.cc
+++ b/third_party/blink/renderer/modules/webgpu/gpu_bind_group_layout.cc
@@ -17,7 +17,7 @@
   dawn_binding.binding = webgpu_binding->binding();
   dawn_binding.type = AsDawnEnum<DawnBindingType>(webgpu_binding->type());
   dawn_binding.visibility =
-      AsDawnEnum<DawnShaderStageBit>(webgpu_binding->visibility());
+      AsDawnEnum<DawnShaderStage>(webgpu_binding->visibility());
   dawn_binding.textureComponentType = AsDawnEnum<DawnTextureComponentType>(
       webgpu_binding->textureComponentType());
   dawn_binding.multisampled = webgpu_binding->multisampled();
diff --git a/third_party/blink/renderer/modules/webgpu/gpu_buffer.cc b/third_party/blink/renderer/modules/webgpu/gpu_buffer.cc
index 79a4656..4c9c1951 100644
--- a/third_party/blink/renderer/modules/webgpu/gpu_buffer.cc
+++ b/third_party/blink/renderer/modules/webgpu/gpu_buffer.cc
@@ -49,7 +49,7 @@
 
   DawnBufferDescriptor dawn_desc = {};
   dawn_desc.nextInChain = nullptr;
-  dawn_desc.usage = AsDawnEnum<DawnBufferUsageBit>(webgpu_desc->usage());
+  dawn_desc.usage = AsDawnEnum<DawnBufferUsage>(webgpu_desc->usage());
   dawn_desc.size = webgpu_desc->size();
 
   return dawn_desc;
diff --git a/third_party/blink/renderer/modules/webgpu/gpu_swap_chain.cc b/third_party/blink/renderer/modules/webgpu/gpu_swap_chain.cc
index a46cfae0..a400bf0e 100644
--- a/third_party/blink/renderer/modules/webgpu/gpu_swap_chain.cc
+++ b/third_party/blink/renderer/modules/webgpu/gpu_swap_chain.cc
@@ -23,7 +23,7 @@
     : DawnObjectBase(descriptor->device()->GetDawnControlClient()),
       device_(descriptor->device()),
       context_(context),
-      usage_(AsDawnEnum<DawnTextureUsageBit>(descriptor->usage())) {
+      usage_(AsDawnEnum<DawnTextureUsage>(descriptor->usage())) {
   swap_buffers_ = base::AdoptRef(new WebGPUSwapBufferProvider(
       this, GetDawnControlClient(), usage_,
       AsDawnEnum<DawnTextureFormat>(descriptor->format())));
diff --git a/third_party/blink/renderer/modules/webgpu/gpu_swap_chain.h b/third_party/blink/renderer/modules/webgpu/gpu_swap_chain.h
index dcd998c4..b644bba9 100644
--- a/third_party/blink/renderer/modules/webgpu/gpu_swap_chain.h
+++ b/third_party/blink/renderer/modules/webgpu/gpu_swap_chain.h
@@ -48,7 +48,7 @@
 
   Member<GPUDevice> device_;
   Member<GPUCanvasContext> context_;
-  DawnTextureUsageBit usage_;
+  DawnTextureUsage usage_;
 
   Member<GPUTexture> texture_;
 };
diff --git a/third_party/blink/renderer/modules/webgpu/gpu_texture.cc b/third_party/blink/renderer/modules/webgpu/gpu_texture.cc
index 87e82db3..6006899d 100644
--- a/third_party/blink/renderer/modules/webgpu/gpu_texture.cc
+++ b/third_party/blink/renderer/modules/webgpu/gpu_texture.cc
@@ -19,7 +19,7 @@
 
   DawnTextureDescriptor dawn_desc = {};
   dawn_desc.nextInChain = nullptr;
-  dawn_desc.usage = static_cast<DawnTextureUsageBit>(webgpu_desc->usage());
+  dawn_desc.usage = static_cast<DawnTextureUsage>(webgpu_desc->usage());
   dawn_desc.dimension =
       AsDawnEnum<DawnTextureDimension>(webgpu_desc->dimension());
   dawn_desc.size = AsDawnType(webgpu_desc->size());
@@ -81,11 +81,6 @@
       device_, GetProcs().textureCreateView(GetHandle(), &dawn_desc));
 }
 
-GPUTextureView* GPUTexture::createDefaultView() {
-  return GPUTextureView::Create(
-      device_, GetProcs().textureCreateDefaultView(GetHandle()));
-}
-
 void GPUTexture::destroy() {
   GetProcs().textureDestroy(GetHandle());
 }
diff --git a/third_party/blink/renderer/modules/webgpu/gpu_texture.h b/third_party/blink/renderer/modules/webgpu/gpu_texture.h
index 95acb2a2..2063c41 100644
--- a/third_party/blink/renderer/modules/webgpu/gpu_texture.h
+++ b/third_party/blink/renderer/modules/webgpu/gpu_texture.h
@@ -24,7 +24,6 @@
 
   // gpu_texture.idl
   GPUTextureView* createView(const GPUTextureViewDescriptor* webgpu_desc);
-  GPUTextureView* createDefaultView();
   void destroy();
 
  private:
diff --git a/third_party/blink/renderer/modules/webgpu/gpu_texture.idl b/third_party/blink/renderer/modules/webgpu/gpu_texture.idl
index 0049a47..cdbcb36 100644
--- a/third_party/blink/renderer/modules/webgpu/gpu_texture.idl
+++ b/third_party/blink/renderer/modules/webgpu/gpu_texture.idl
@@ -7,7 +7,6 @@
 [
     RuntimeEnabled=WebGPU
 ] interface GPUTexture {
-    GPUTextureView createView(GPUTextureViewDescriptor desc);
-    GPUTextureView createDefaultView();
+    GPUTextureView createView(optional GPUTextureViewDescriptor desc);
     void destroy();
 };
diff --git a/third_party/blink/renderer/modules/webgpu/gpu_texture_view_descriptor.idl b/third_party/blink/renderer/modules/webgpu/gpu_texture_view_descriptor.idl
index dda055b..551d292 100644
--- a/third_party/blink/renderer/modules/webgpu/gpu_texture_view_descriptor.idl
+++ b/third_party/blink/renderer/modules/webgpu/gpu_texture_view_descriptor.idl
@@ -5,13 +5,13 @@
 // https://gpuweb.github.io/gpuweb/
 
 dictionary GPUTextureViewDescriptor {
-    required GPUTextureFormat format;
-    required GPUTextureViewDimension dimension;
-    required GPUTextureAspect aspect;
+    GPUTextureFormat format;
+    GPUTextureViewDimension dimension;
+    GPUTextureAspect aspect = "all";
     unsigned long baseMipLevel = 0;
-    unsigned long mipLevelCount = 1;
+    unsigned long mipLevelCount = 0;
     unsigned long baseArrayLayer = 0;
-    unsigned long arrayLayerCount = 1;
+    unsigned long arrayLayerCount = 0;
 };
 
 enum GPUTextureViewDimension {
diff --git a/third_party/blink/renderer/platform/BUILD.gn b/third_party/blink/renderer/platform/BUILD.gn
index ac3c0c7d..a0078a1e 100644
--- a/third_party/blink/renderer/platform/BUILD.gn
+++ b/third_party/blink/renderer/platform/BUILD.gn
@@ -1231,6 +1231,8 @@
     "peerconnection/rtc_dtmf_sender_handler.cc",
     "peerconnection/rtc_dtmf_sender_handler.h",
     "peerconnection/rtc_offer_options_platform.h",
+    "peerconnection/rtc_rtp_source.cc",
+    "peerconnection/rtc_rtp_source.h",
     "peerconnection/rtc_session_description_request.h",
     "peerconnection/rtc_stats_request.h",
     "peerconnection/rtc_stats_response_base.h",
diff --git a/third_party/blink/renderer/platform/graphics/gpu/webgpu_swap_buffer_provider.cc b/third_party/blink/renderer/platform/graphics/gpu/webgpu_swap_buffer_provider.cc
index fc376069..7681d87d 100644
--- a/third_party/blink/renderer/platform/graphics/gpu/webgpu_swap_buffer_provider.cc
+++ b/third_party/blink/renderer/platform/graphics/gpu/webgpu_swap_buffer_provider.cc
@@ -29,7 +29,7 @@
 WebGPUSwapBufferProvider::WebGPUSwapBufferProvider(
     Client* client,
     scoped_refptr<DawnControlClientHolder> dawn_control_client,
-    DawnTextureUsageBit usage,
+    DawnTextureUsage usage,
     DawnTextureFormat format)
     : dawn_control_client_(dawn_control_client),
       client_(client),
diff --git a/third_party/blink/renderer/platform/graphics/gpu/webgpu_swap_buffer_provider.h b/third_party/blink/renderer/platform/graphics/gpu/webgpu_swap_buffer_provider.h
index 83711044..5d2a866 100644
--- a/third_party/blink/renderer/platform/graphics/gpu/webgpu_swap_buffer_provider.h
+++ b/third_party/blink/renderer/platform/graphics/gpu/webgpu_swap_buffer_provider.h
@@ -35,7 +35,7 @@
   WebGPUSwapBufferProvider(
       Client* client,
       scoped_refptr<DawnControlClientHolder> dawn_control_client,
-      DawnTextureUsageBit usage,
+      DawnTextureUsage usage,
       DawnTextureFormat format);
   ~WebGPUSwapBufferProvider() override;
 
@@ -84,7 +84,7 @@
   scoped_refptr<cc::TextureLayer> layer_;
   bool neutered_ = false;
 
-  DawnTextureUsageBit usage_;
+  DawnTextureUsage usage_;
 
   uint32_t wire_texture_id_ = 0;
   uint32_t wire_texture_generation_ = 0;
diff --git a/third_party/blink/renderer/platform/graphics/gpu/webgpu_swap_buffer_provider_test.cc b/third_party/blink/renderer/platform/graphics/gpu/webgpu_swap_buffer_provider_test.cc
index ee3e046..9e99fc6 100644
--- a/third_party/blink/renderer/platform/graphics/gpu/webgpu_swap_buffer_provider_test.cc
+++ b/third_party/blink/renderer/platform/graphics/gpu/webgpu_swap_buffer_provider_test.cc
@@ -58,7 +58,7 @@
       bool* alive,
       Client* client,
       scoped_refptr<DawnControlClientHolder> dawn_control_client,
-      DawnTextureUsageBit usage,
+      DawnTextureUsage usage,
       DawnTextureFormat format)
       : WebGPUSwapBufferProvider(client, dawn_control_client, usage, format),
         alive_(alive) {}
@@ -84,8 +84,7 @@
         base::MakeRefCounted<DawnControlClientHolder>(std::move(provider));
     provider_ = base::MakeRefCounted<WebGPUSwapBufferProviderForTests>(
         &provider_alive_, &client_, dawn_control_client_,
-        DAWN_TEXTURE_USAGE_BIT_OUTPUT_ATTACHMENT,
-        DAWN_TEXTURE_FORMAT_RGBA8_UNORM);
+        DAWN_TEXTURE_USAGE_OUTPUT_ATTACHMENT, DAWN_TEXTURE_FORMAT_RGBA8_UNORM);
   }
 
   scoped_refptr<DawnControlClientHolder> dawn_control_client_;
diff --git a/content/renderer/media/webrtc/rtc_rtp_source.cc b/third_party/blink/renderer/platform/peerconnection/rtc_rtp_source.cc
similarity index 74%
rename from content/renderer/media/webrtc/rtc_rtp_source.cc
rename to third_party/blink/renderer/platform/peerconnection/rtc_rtp_source.cc
index 308f39f..7169cc9 100644
--- a/content/renderer/media/webrtc/rtc_rtp_source.cc
+++ b/third_party/blink/renderer/platform/peerconnection/rtc_rtp_source.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 "content/renderer/media/webrtc/rtc_rtp_source.h"
+#include "third_party/blink/renderer/platform/peerconnection/rtc_rtp_source.h"
 
 #include <cmath>
 
@@ -10,21 +10,26 @@
 #include "base/time/time.h"
 #include "third_party/webrtc/api/scoped_refptr.h"
 
-namespace content {
+namespace blink {
+
+std::unique_ptr<WebRTCRtpSource> CreateRTCRtpSource(
+    const webrtc::RtpSource& source) {
+  return std::make_unique<RTCRtpSource>(source);
+}
 
 RTCRtpSource::RTCRtpSource(const webrtc::RtpSource& source) : source_(source) {}
 
 RTCRtpSource::~RTCRtpSource() {}
 
-blink::WebRTCRtpSource::Type RTCRtpSource::SourceType() const {
+WebRTCRtpSource::Type RTCRtpSource::SourceType() const {
   switch (source_.source_type()) {
     case webrtc::RtpSourceType::SSRC:
-      return blink::WebRTCRtpSource::Type::kSSRC;
+      return WebRTCRtpSource::Type::kSSRC;
     case webrtc::RtpSourceType::CSRC:
-      return blink::WebRTCRtpSource::Type::kCSRC;
+      return WebRTCRtpSource::Type::kCSRC;
     default:
       NOTREACHED();
-      return blink::WebRTCRtpSource::Type::kSSRC;
+      return WebRTCRtpSource::Type::kSSRC;
   }
 }
 
@@ -54,4 +59,4 @@
   return source_.rtp_timestamp();
 }
 
-}  // namespace content
+}  // namespace blink
diff --git a/content/renderer/media/webrtc/rtc_rtp_source.h b/third_party/blink/renderer/platform/peerconnection/rtc_rtp_source.h
similarity index 65%
rename from content/renderer/media/webrtc/rtc_rtp_source.h
rename to third_party/blink/renderer/platform/peerconnection/rtc_rtp_source.h
index ecf3fd73..cd771ac 100644
--- a/content/renderer/media/webrtc/rtc_rtp_source.h
+++ b/third_party/blink/renderer/platform/peerconnection/rtc_rtp_source.h
@@ -2,23 +2,22 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef CONTENT_RENDERER_MEDIA_WEBRTC_RTC_RTP_SOURCE_H_
-#define CONTENT_RENDERER_MEDIA_WEBRTC_RTC_RTP_SOURCE_H_
+#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_PEERCONNECTION_RTC_RTP_SOURCE_H_
+#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_PEERCONNECTION_RTC_RTP_SOURCE_H_
 
 #include "base/macros.h"
 #include "base/memory/ref_counted.h"
-#include "content/common/content_export.h"
 #include "third_party/blink/public/platform/web_rtc_rtp_source.h"
 #include "third_party/webrtc/api/rtp_receiver_interface.h"
 
-namespace content {
+namespace blink {
 
-class CONTENT_EXPORT RTCRtpSource : public blink::WebRTCRtpSource {
+class RTCRtpSource : public WebRTCRtpSource {
  public:
   explicit RTCRtpSource(const webrtc::RtpSource& source);
   ~RTCRtpSource() override;
 
-  blink::WebRTCRtpSource::Type SourceType() const override;
+  WebRTCRtpSource::Type SourceType() const override;
   base::TimeTicks Timestamp() const override;
   uint32_t Source() const override;
   base::Optional<double> AudioLevel() const override;
@@ -30,6 +29,6 @@
   DISALLOW_COPY_AND_ASSIGN(RTCRtpSource);
 };
 
-}  // namespace content
+}  // namespace blink
 
-#endif  // CONTENT_RENDERER_MEDIA_WEBRTC_RTC_RTP_SOURCE_H_
+#endif  // THIRD_PARTY_BLINK_RENDERER_PLATFORM_PEERCONNECTION_RTC_RTP_SOURCE_H_
diff --git a/third_party/blink/renderer/platform/runtime_enabled_features.json5 b/third_party/blink/renderer/platform/runtime_enabled_features.json5
index cc2b679..f5d78e6 100644
--- a/third_party/blink/renderer/platform/runtime_enabled_features.json5
+++ b/third_party/blink/renderer/platform/runtime_enabled_features.json5
@@ -1025,12 +1025,6 @@
       name: "MouseSubframeNoImplicitCapture",
     },
     {
-      name: "MuteButton",
-      depends_on: ["PictureInPictureAPI"],
-      origin_trial_feature_name: "MuteButton",
-      status: "experimental",
-    },
-    {
       // Enabled when blink::features::kNativeFileSystemAPI is enabled.
       name: "NativeFileSystem",
     },
diff --git a/third_party/blink/web_tests/TestExpectations b/third_party/blink/web_tests/TestExpectations
index 8259a185..ffb0d5c 100644
--- a/third_party/blink/web_tests/TestExpectations
+++ b/third_party/blink/web_tests/TestExpectations
@@ -2993,7 +2993,6 @@
 
 crbug.com/831729 external/wpt/event-timing/crossiframe.html [ Timeout ]
 crbug.com/831729 external/wpt/event-timing/observer-manual.html [ Skip ]
-crbug.com/987236  [ Linux ] external/wpt/event-timing/bufferbeforeonload.html [ Timeout ]
 
 # Working on getting the CSP tests going:
 crbug.com/694525 external/wpt/content-security-policy/connect-src/worker-from-guid.sub.html [ Skip ]
@@ -6269,7 +6268,6 @@
 crbug.com/972476 std-switch/switch-appearance-customization.html [ Failure ]
 
 # Sheriff 2019-05-20
-crbug.com/963739 [ Fuchsia ] synthetic_gestures/smooth-scroll-tiny-delta.html [ Pass Timeout ]
 crbug.com/964239 external/wpt/css/css-scroll-snap/scroll-margin.html [ Pass Failure ]
 crbug.com/965389 [ Mac ] media/track/track-cue-rendering-position-auto.html [ Pass Failure ]
 crbug.com/965389 [ Mac ] virtual/audio-service/media/track/track-cue-rendering-position-auto.html [ Pass Failure ]
@@ -6407,7 +6405,6 @@
 # Sheriff 2019-07-26
 crbug.com/835943 [ Debug ] http/tests/appcache/non-html.xhtml [ Crash Pass ]
 crbug.com/874866 [ Linux Debug ] media/controls/doubletap-to-jump-backwards.html [ Failure ]
-crbug.com/988231 external/wpt/event-timing/observethenonload.html [ Pass Timeout ]
 crbug.com/988232 virtual/controls-refresh/fast/forms/controls-new-ui/password/password-alt-f8-twice.html [ Pass Failure ]
 crbug.com/988232 virtual/controls-refresh/fast/forms/controls-new-ui/password/password-alt-f8.html [ Pass Failure ]
 crbug.com/988232 virtual/controls-refresh/fast/forms/controls-new-ui/password/password-eye-icon-font-size-48px.html [ Pass Failure ]
diff --git a/third_party/blink/web_tests/WPTOverrideExpectations b/third_party/blink/web_tests/WPTOverrideExpectations
index 0c79361..138e0849 100644
--- a/third_party/blink/web_tests/WPTOverrideExpectations
+++ b/third_party/blink/web_tests/WPTOverrideExpectations
@@ -805,8 +805,6 @@
 crbug.com/lpz external/wpt/event-timing/buffered-flag.html [ Timeout ]
 crbug.com/lpz external/wpt/event-timing/crossiframe.html [ Failure ]
 crbug.com/lpz external/wpt/event-timing/idlharness.any.html [ Failure ]
-crbug.com/lpz external/wpt/event-timing/onloadthenobserve-firstInput.html [ Timeout ]
-crbug.com/lpz external/wpt/event-timing/onloadthenobserve.html [ Timeout ]
 crbug.com/lpz external/wpt/event-timing/retrievability.html [ Timeout ]
 crbug.com/lpz external/wpt/event-timing/retrieve-firstInput.html [ Failure ]
 crbug.com/lpz external/wpt/event-timing/timingconditions.html [ Timeout ]
diff --git a/third_party/blink/web_tests/animations/interpolation/shape-image-threshold-interpolation.html b/third_party/blink/web_tests/animations/interpolation/shape-image-threshold-interpolation.html
deleted file mode 100644
index 2f12343..0000000
--- a/third_party/blink/web_tests/animations/interpolation/shape-image-threshold-interpolation.html
+++ /dev/null
@@ -1,79 +0,0 @@
-<!DOCTYPE html>
-<meta charset="UTF-8">
-<style>
-.parent {
-  shape-image-threshold: 0.4;
-}
-.target {
-  shape-image-threshold: 0.6;
-}
-</style>
-<body>
-<script src="resources/interpolation-test.js"></script>
-<script>
-assertInterpolation({
-  property: 'shape-image-threshold',
-  from: neutralKeyframe,
-  to: '0.8',
-}, [
-  {at: -1.5, is: '0.3'},
-  {at: -0.5, is: '0.5'},
-  {at: 0, is: '0.6'},
-  {at: 0.5, is: '0.7'},
-  {at: 1, is: '0.8'},
-  {at: 1.5, is: '0.9'},
-]);
-
-assertInterpolation({
-  property: 'shape-image-threshold',
-  from: 'initial',
-  to: '0.8',
-}, [
-  {at: -1.5, is: '0'},
-  {at: -0.5, is: '0'},
-  {at: 0, is: '0'},
-  {at: 0.5, is: '0.4'},
-  {at: 1, is: '0.8'},
-  {at: 1.5, is: '1'},
-]);
-
-assertInterpolation({
-  property: 'shape-image-threshold',
-  from: 'inherit',
-  to: '0.8',
-}, [
-  {at: -1.5, is: '0'},
-  {at: -0.5, is: '0.2'},
-  {at: 0, is: '0.4'},
-  {at: 0.5, is: '0.6'},
-  {at: 1, is: '0.8'},
-  {at: 1.5, is: '1'},
-]);
-
-assertInterpolation({
-  property: 'shape-image-threshold',
-  from: 'unset',
-  to: '0.8',
-}, [
-  {at: -1.5, is: '0'},
-  {at: -0.5, is: '0'},
-  {at: 0, is: '0'},
-  {at: 0.5, is: '0.4'},
-  {at: 1, is: '0.8'},
-  {at: 1.5, is: '1'},
-]);
-
-assertInterpolation({
-  property: 'shape-image-threshold',
-  from: '0.5',
-  to: '1'
-}, [
-  {at: -1.5, is: '0'},
-  {at: -0.5, is: '0.25'},
-  {at: 0, is: '0.5'},
-  {at: 0.5, is: '0.75'},
-  {at: 1, is: '1'},
-  {at: 1.5, is: '1'}
-]);
-</script>
-</body>
diff --git a/third_party/blink/web_tests/animations/interpolation/shape-margin-interpolation.html b/third_party/blink/web_tests/animations/interpolation/shape-margin-interpolation.html
deleted file mode 100644
index 6bf3562..0000000
--- a/third_party/blink/web_tests/animations/interpolation/shape-margin-interpolation.html
+++ /dev/null
@@ -1,79 +0,0 @@
-<!DOCTYPE html>
-<meta charset="UTF-8">
-<style>
-.parent {
-  shape-margin: 30px;
-}
-.target {
-  shape-margin: 10px;
-}
-</style>
-<body>
-<script src="resources/interpolation-test.js"></script>
-<script>
-assertInterpolation({
-  property: 'shape-margin',
-  from: neutralKeyframe,
-  to: '20px',
-}, [
-  {at: -0.3, is: '7px'},
-  {at: 0, is: '10px'},
-  {at: 0.3, is: '13px'},
-  {at: 0.6, is: '16px'},
-  {at: 1, is: '20px'},
-  {at: 1.5, is: '25px'},
-]);
-
-assertInterpolation({
-  property: 'shape-margin',
-  from: 'initial',
-  to: '20px',
-}, [
-  {at: -0.3, is: '0px'},
-  {at: 0, is: '0px'},
-  {at: 0.3, is: '6px'},
-  {at: 0.6, is: '12px'},
-  {at: 1, is: '20px'},
-  {at: 1.5, is: '30px'},
-]);
-
-assertInterpolation({
-  property: 'shape-margin',
-  from: 'inherit',
-  to: '20px',
-}, [
-  {at: -0.3, is: '33px'},
-  {at: 0, is: '30px'},
-  {at: 0.3, is: '27px'},
-  {at: 0.6, is: '24px'},
-  {at: 1, is: '20px'},
-  {at: 1.5, is: '15px'},
-]);
-
-assertInterpolation({
-  property: 'shape-margin',
-  from: 'unset',
-  to: '20px',
-}, [
-  {at: -0.3, is: '0px'},
-  {at: 0, is: '0px'},
-  {at: 0.3, is: '6px'},
-  {at: 0.6, is: '12px'},
-  {at: 1, is: '20px'},
-  {at: 1.5, is: '30px'},
-]);
-
-assertInterpolation({
-  property: 'shape-margin',
-  from: '0px',
-  to: '100px'
-}, [
-  {at: -0.3, is: '0px'}, // CSS shape-margin can't be negative.
-  {at: 0, is: '0px'},
-  {at: 0.3, is: '30px'},
-  {at: 0.6, is: '60px'},
-  {at: 1, is: '100px'},
-  {at: 1.5, is: '150px'},
-]);
-</script>
-</body>
diff --git a/third_party/blink/web_tests/animations/interpolation/shape-outside-interpolation.html b/third_party/blink/web_tests/animations/interpolation/shape-outside-interpolation.html
deleted file mode 100644
index 1e28397..0000000
--- a/third_party/blink/web_tests/animations/interpolation/shape-outside-interpolation.html
+++ /dev/null
@@ -1,129 +0,0 @@
-<!DOCTYPE html>
-<meta charset="UTF-8">
-<style>
-.parent {
-  shape-outside: circle(80% at 30% 10%);
-}
-.target {
-  shape-outside: circle(60% at 10% 30%);
-}
-</style>
-<body>
-<script src="resources/interpolation-test.js"></script>
-<script>
-/* TODO: add inset test once blend() works for it */
-
-assertInterpolation({
-  property: 'shape-outside',
-  from: neutralKeyframe,
-  to: 'circle(40% at 20% 20%)',
-}, [
-  {at: -0.3, is: 'circle(66% at 7% 33%)'},
-  {at: 0, is: 'circle(60% at 10% 30%)'},
-  {at: 0.3, is: 'circle(54% at 13% 27%)'},
-  {at: 0.6, is: 'circle(48% at 16% 24%)'},
-  {at: 1, is: 'circle(40% at 20% 20%)'},
-  {at: 1.5, is: 'circle(30% at 25% 15%)'},
-]);
-
-assertNoInterpolation({
-  property: 'shape-outside',
-  from: 'initial',
-  to: 'circle(40% at 20% 20%)',
-});
-
-assertInterpolation({
-  property: 'shape-outside',
-  from: 'inherit',
-  to: 'circle(40% at 20% 20%)',
-}, [
-  {at: -0.3, is: 'circle(92% at 33% 7%)'},
-  {at: 0, is: 'circle(80% at 30% 10%)'},
-  {at: 0.3, is: 'circle(68% at 27% 13%)'},
-  {at: 0.6, is: 'circle(56% at 24% 16%)'},
-  {at: 1, is: 'circle(40% at 20% 20%)'},
-  {at: 1.5, is: 'circle(20% at 15% 25%)'},
-]);
-
-assertNoInterpolation({
-  property: 'shape-outside',
-  from: 'unset',
-  to: 'circle(40% at 20% 20%)',
-});
-
-assertInterpolation({
-  property: 'shape-outside',
-  from: 'circle(100% at 0% 0%)',
-  to: 'circle(50% at 25% 25%)',
-}, [
-  {at: -0.3, is: 'circle(115% at -7.5% -7.5%)'},
-  {at: 0, is: 'circle(100% at 0% 0%)'},
-  {at: 0.3, is: 'circle(85% at 7.5% 7.5%)'},
-  {at: 0.6, is: 'circle(70% at 15% 15%)'},
-  {at: 1, is: 'circle(50% at 25% 25%)'},
-  {at: 1.5, is: 'circle(25% at 37.5% 37.5%)'}
-]);
-
-assertInterpolation({
-  property: 'shape-outside',
-  from: 'ellipse(100% 100% at 0% 0%)',
-  to: 'ellipse(50% 50% at 25% 25%)',
-}, [
-  {at: -0.3, is: 'ellipse(115% 115% at -7.5% -7.5%)'},
-  {at: 0, is: 'ellipse(100% 100% at 0% 0%)'},
-  {at: 0.3, is: 'ellipse(85% 85% at 7.5% 7.5%)'},
-  {at: 0.6, is: 'ellipse(70% 70% at 15% 15%)'},
-  {at: 1, is: 'ellipse(50% 50% at 25% 25%)'},
-  {at: 1.5, is: 'ellipse(25% 25% at 37.5% 37.5%)'}
-]);
-
-assertInterpolation({
-  property: 'shape-outside',
-  from: 'polygon(nonzero, 0px 0px, 25px 25px, 50px 50px)',
-  to: 'polygon(nonzero, 25px 25px, 50px 50px, 75px 75px)',
-}, [
-  {at: -0.3, is: 'polygon(nonzero, -7.5px -7.5px, 17.5px 17.5px, 42.5px 42.5px)'},
-  {at: 0, is: 'polygon(nonzero, 0px 0px, 25px 25px, 50px 50px)'},
-  {at: 0.3, is: 'polygon(nonzero, 7.5px 7.5px, 32.5px 32.5px, 57.5px 57.5px)'},
-  {at: 0.6, is: 'polygon(nonzero, 15px 15px, 40px 40px, 65px 65px)'},
-  {at: 1, is: 'polygon(nonzero, 25px 25px, 50px 50px, 75px 75px)'},
-  {at: 1.5, is: 'polygon(nonzero, 37.5px 37.5px, 62.5px 62.5px, 87.5px 87.5px)'}
-]);
-
-assertNoInterpolation({
-  property: 'shape-outside',
-  from: 'polygon(evenodd, 0px 0px, 25px 25px, 50px 50px)',
-  to: 'polygon(nonzero, 25px 25px, 50px 50px, 75px 75px)',
-});
-
-assertInterpolation({
-  property: 'shape-outside',
-  from: 'inset(100%)',
-  to: 'inset(120%)',
-}, [
-  {at: -0.3, is: 'inset(94%)'},
-  {at: 0, is: 'inset(100%)'},
-  {at: 0.3, is: 'inset(106%)'},
-  {at: 0.6, is: 'inset(112%)'},
-  {at: 1, is: 'inset(120%)'},
-  {at: 1.5, is: 'inset(130%)'},
-]);
-
-assertNoInterpolation({
-  property: 'shape-outside',
-  from: 'none',
-  to: 'ellipse(100% 100% at 0% 0%)',
-});
-
-// TODO: add intermediate keyframe tests when CSS shapes position computed values are cleaned up
-assertInterpolation({
-  property: 'shape-outside',
-  from: 'circle(25% at right 5% bottom 15px)',
-  to: 'circle(45% at right 25% bottom 35px)',
-}, [
-  {at: 0.25, is: 'circle(30% at 90% calc(-20px + 100%))'},
-  {at: 0.5, is: 'circle(35% at 85% calc(-25px + 100%))'},
-  {at: 0.75, is: 'circle(40% at 80% calc(-30px + 100%))'},
-]);
-</script>
-</body>
diff --git a/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_6.json b/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_6.json
index ca78f1b9..d3fb62d 100644
--- a/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_6.json
+++ b/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_6.json
@@ -50291,6 +50291,30 @@
      {}
     ]
    ],
+   "css/css-grid/grid-items/grid-item-rel-pos-001.html": [
+    [
+     "css/css-grid/grid-items/grid-item-rel-pos-001.html",
+     [
+      [
+       "/css/css-grid/grid-items/grid-item-rel-pos-001-ref.html",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
+   "css/css-grid/grid-items/grid-item-rel-pos-002.html": [
+    [
+     "css/css-grid/grid-items/grid-item-rel-pos-002.html",
+     [
+      [
+       "/css/css-grid/grid-items/grid-item-rel-pos-002-ref.html",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
    "css/css-grid/grid-items/grid-items-001.html": [
     [
      "css/css-grid/grid-items/grid-items-001.html",
@@ -140142,6 +140166,12 @@
    "css/css-grid/grid-items/grid-item-percentage-sizes-003-ref.html": [
     []
    ],
+   "css/css-grid/grid-items/grid-item-rel-pos-001-ref.html": [
+    []
+   ],
+   "css/css-grid/grid-items/grid-item-rel-pos-002-ref.html": [
+    []
+   ],
    "css/css-grid/grid-items/grid-items-sizing-alignment-001-ref.html": [
     []
    ],
@@ -152391,6 +152421,9 @@
    "dom/historical-expected.txt": [
     []
    ],
+   "dom/idlharness.window_exclude=Node-expected.txt": [
+    []
+   ],
    "dom/interfaces-expected.txt": [
     []
    ],
@@ -154608,12 +154641,6 @@
    "fetch/api/basic/request-upload.any.worker-expected.txt": [
     []
    ],
-   "fetch/api/basic/scheme-data.any-expected.txt": [
-    []
-   ],
-   "fetch/api/basic/scheme-data.any.worker-expected.txt": [
-    []
-   ],
    "fetch/api/cors/cors-filtering-worker-expected.txt": [
     []
    ],
@@ -222581,24 +222608,150 @@
      {}
     ]
    ],
-   "dom/interface-objects.html": [
+   "dom/idlharness.any.js": [
     [
-     "dom/interface-objects.html",
-     {}
-    ]
-   ],
-   "dom/interfaces.html": [
-    [
-     "dom/interfaces.html?exclude=Node",
+     "dom/idlharness.any.serviceworker.html",
      {
+      "script_metadata": [
+       [
+        "global",
+        "!window,worker"
+       ],
+       [
+        "script",
+        "/resources/WebIDLParser.js"
+       ],
+       [
+        "script",
+        "/resources/idlharness.js"
+       ],
+       [
+        "timeout",
+        "long"
+       ]
+      ],
       "timeout": "long"
      }
     ],
     [
-     "dom/interfaces.html?include=Node",
+     "dom/idlharness.any.sharedworker.html",
      {
+      "script_metadata": [
+       [
+        "global",
+        "!window,worker"
+       ],
+       [
+        "script",
+        "/resources/WebIDLParser.js"
+       ],
+       [
+        "script",
+        "/resources/idlharness.js"
+       ],
+       [
+        "timeout",
+        "long"
+       ]
+      ],
       "timeout": "long"
      }
+    ],
+    [
+     "dom/idlharness.any.worker.html",
+     {
+      "script_metadata": [
+       [
+        "global",
+        "!window,worker"
+       ],
+       [
+        "script",
+        "/resources/WebIDLParser.js"
+       ],
+       [
+        "script",
+        "/resources/idlharness.js"
+       ],
+       [
+        "timeout",
+        "long"
+       ]
+      ],
+      "timeout": "long"
+     }
+    ]
+   ],
+   "dom/idlharness.window.js": [
+    [
+     "dom/idlharness.window.html?exclude=Node",
+     {
+      "script_metadata": [
+       [
+        "script",
+        "/resources/WebIDLParser.js"
+       ],
+       [
+        "script",
+        "/resources/idlharness.js"
+       ],
+       [
+        "script",
+        "/common/subset-tests-by-key.js"
+       ],
+       [
+        "variant",
+        "?include=Node"
+       ],
+       [
+        "variant",
+        "?exclude=Node"
+       ],
+       [
+        "timeout",
+        "long"
+       ]
+      ],
+      "timeout": "long"
+     }
+    ],
+    [
+     "dom/idlharness.window.html?include=Node",
+     {
+      "script_metadata": [
+       [
+        "script",
+        "/resources/WebIDLParser.js"
+       ],
+       [
+        "script",
+        "/resources/idlharness.js"
+       ],
+       [
+        "script",
+        "/common/subset-tests-by-key.js"
+       ],
+       [
+        "variant",
+        "?include=Node"
+       ],
+       [
+        "variant",
+        "?exclude=Node"
+       ],
+       [
+        "timeout",
+        "long"
+       ]
+      ],
+      "timeout": "long"
+     }
+    ]
+   ],
+   "dom/interface-objects.html": [
+    [
+     "dom/interface-objects.html",
+     {}
     ]
    ],
    "dom/lists/DOMTokenList-Iterable.html": [
@@ -294341,12 +294494,26 @@
      {}
     ]
    ],
+   "trusted-types/TrustedTypePolicyFactory-getPropertyType.tentative.html": [
+    [
+     "trusted-types/TrustedTypePolicyFactory-getPropertyType.tentative.html",
+     {}
+    ]
+   ],
    "trusted-types/TrustedTypePolicyFactory-isXXX.tentative.html": [
     [
      "trusted-types/TrustedTypePolicyFactory-isXXX.tentative.html",
      {}
     ]
    ],
+   "trusted-types/TrustedTypePolicyFactory-metadata.tentative.html": [
+    [
+     "trusted-types/TrustedTypePolicyFactory-metadata.tentative.html",
+     {
+      "timeout": "long"
+     }
+    ]
+   ],
    "trusted-types/Window-TrustedTypes.tentative.html": [
     [
      "trusted-types/Window-TrustedTypes.tentative.html",
@@ -327306,7 +327473,7 @@
    "support"
   ],
   "audio-output/idlharness.https.window.js": [
-   "f10e523bcdc530ee1dbd04a52541ac0b343e9376",
+   "c13b167296d8059b96bfa4704714051e341ee987",
    "testharness"
   ],
   "audio-output/setSinkId-manual.https.html": [
@@ -327610,7 +327777,7 @@
    "support"
   ],
   "beacon/idlharness.any.js": [
-   "958daf4865d1d7c9dfb621a163e15a8862330d2b",
+   "bf267ab8bdce52ce32df4ea3a53b30b6d35c8000",
    "testharness"
   ],
   "beacon/resources/beacon.py": [
@@ -370777,6 +370944,22 @@
    "fccf4fe0a6ed1f128ff7ec2b322a4a2916c873b1",
    "reftest"
   ],
+  "css/css-grid/grid-items/grid-item-rel-pos-001-ref.html": [
+   "a6305e560ef9ae01b5f89df59f3d42cd9ce4ab85",
+   "support"
+  ],
+  "css/css-grid/grid-items/grid-item-rel-pos-001.html": [
+   "d72df4126ddc096036a84199616a35fd49c4cc36",
+   "reftest"
+  ],
+  "css/css-grid/grid-items/grid-item-rel-pos-002-ref.html": [
+   "643b80e1ca88d4bf332c02637b1fe0478e951f1e",
+   "support"
+  ],
+  "css/css-grid/grid-items/grid-item-rel-pos-002.html": [
+   "4a4d6c843ac4f82cb1403a15739174ec781634ef",
+   "reftest"
+  ],
   "css/css-grid/grid-items/grid-items-001.html": [
    "fc9b27be4d1eb62d13afc9da04790da748b1a6ba",
    "reftest"
@@ -420325,6 +420508,18 @@
    "921fa07b3f6de0f9a579b75b14d6509039765205",
    "testharness"
   ],
+  "dom/idlharness.any.js": [
+   "db841dc75b73d0cd22d9f273cd9277ce99c2843d",
+   "testharness"
+  ],
+  "dom/idlharness.window.js": [
+   "3f44ed5adbe4320e6399cc300343743924f626e3",
+   "testharness"
+  ],
+  "dom/idlharness.window_exclude=Node-expected.txt": [
+   "217c77d9778dbd9ac1cf39d3bfd1fe7b4b02f807",
+   "support"
+  ],
   "dom/interface-objects.html": [
    "936d63517eada5521f814fabdbd785a57b9640b2",
    "testharness"
@@ -420333,10 +420528,6 @@
    "648f8f6475fb0fc829bdaaf49e379333b7d5489f",
    "support"
   ],
-  "dom/interfaces.html": [
-   "111608bcaec1c39fa832474ebe014e8730a40c4e",
-   "testharness"
-  ],
   "dom/interfaces_exclude=Node-expected.txt": [
    "e5d121860dcb77cc0fc0f8cb9c18ffbc5edc8986",
    "support"
@@ -424674,7 +424865,7 @@
    "testharness"
   ],
   "encrypted-media/idlharness.https.html": [
-   "6a2ae80a5384aa885d7a1545b19f41cc828c420e",
+   "805094280771a2b0828a517c24bc4abf1b77d076",
    "testharness"
   ],
   "encrypted-media/polyfill/cast-polyfill.js": [
@@ -426553,18 +426744,10 @@
    "fb1357eaf294b8973f44af30c2fafc40100d8eaf",
    "testharness"
   ],
-  "fetch/api/basic/scheme-data.any-expected.txt": [
-   "012001f6e498a62417525e92ddc0d0698114d020",
-   "support"
-  ],
   "fetch/api/basic/scheme-data.any.js": [
    "2ff2545cc6463f855d6f8ad1657407c85343a7e7",
    "testharness"
   ],
-  "fetch/api/basic/scheme-data.any.worker-expected.txt": [
-   "012001f6e498a62417525e92ddc0d0698114d020",
-   "support"
-  ],
   "fetch/api/basic/scheme-others.sub.any.js": [
    "5f9848ff4c297d662a82aa9e847f548371c33d19",
    "testharness"
@@ -429294,7 +429477,7 @@
    "testharness"
   ],
   "geolocation-API/idlharness.window.js": [
-   "f8c92c121352b6daffe3c3b289f49d3572292c10",
+   "fe4ac8895dfb6e889eded7d694e3c87905868b4f",
    "testharness"
   ],
   "geolocation-API/support.js": [
@@ -454142,7 +454325,7 @@
    "manual"
   ],
   "mediacapture-depth/idlharness.html": [
-   "1afc6e5a05b2b8e0a288e7b680cf2920bdd1c525",
+   "963229aaca31dd8b92a07e1bb1da4c3eace7ad5b",
    "testharness"
   ],
   "mediacapture-fromelement/META.yml": [
@@ -454518,7 +454701,7 @@
    "testharness"
   ],
   "mediacapture-streams/idlharness.https.window.js": [
-   "5b255fca6b0b770ab6f849afe5d657c66052215a",
+   "594e1121b005ea3cd7ef1f30aa15fbed07dff1a4",
    "testharness"
   ],
   "mediacapture-streams/idlharness.window-expected.txt": [
@@ -464246,7 +464429,7 @@
    "manual"
   ],
   "orientation-event/idlharness.https.window.js": [
-   "ed8309d6480eaaec45e986a3391854d67b01ba2d",
+   "55cfed9276b480d7f70c616fa8d815f6ec925d66",
    "testharness"
   ],
   "orientation-event/ondeviceorientationabsolute.https.html": [
@@ -465326,7 +465509,7 @@
    "support"
   ],
   "permissions/interfaces.any.js": [
-   "b93453886930679c557a5c4a01651150b82670d9",
+   "ff0a969badace39c3c4466c4528e30c21355e132",
    "testharness"
   ],
   "permissions/test-background-fetch-permission.html": [
@@ -475726,7 +475909,7 @@
    "testharness"
   ],
   "requestidlecallback/idlharness.window.js": [
-   "2c9f6593208a4070d590fd81854ee78c5d20ce4d",
+   "69cd5a49b0432a65db9da267248a6f97d93cd0b9",
    "testharness"
   ],
   "requestidlecallback/resources/post_name_on_load.html": [
@@ -477102,7 +477285,7 @@
    "testharness"
   ],
   "server-timing/idlharness.https.any.js": [
-   "9c101e0f4cf2c5ef0196ac18342c8329755f794e",
+   "ded320f0f61f4de1132d5cfb76a7e74a16154f3c",
    "testharness"
   ],
   "server-timing/navigation_timing_idl.https.html": [
@@ -490562,7 +490745,7 @@
    "testharness"
   ],
   "trusted-types/GlobalEventHandlers-onclick.tentative.html": [
-   "6e8c560ebd1dafb4cc2b4509b2340790dade49c2",
+   "8c9c2f1a70bdb368bf535f40b8eae136c2eee23a",
    "testharness"
   ],
   "trusted-types/HTMLElement-generic.tentative.html": [
@@ -490645,10 +490828,18 @@
    "ea00566854d12cbd6d2610aafdac44fd549ffbe7",
    "testharness"
   ],
+  "trusted-types/TrustedTypePolicyFactory-getPropertyType.tentative.html": [
+   "90fc7d5566d8d74dd70b7ff74a349dc424b4cdf8",
+   "testharness"
+  ],
   "trusted-types/TrustedTypePolicyFactory-isXXX.tentative.html": [
    "854f69ed1e550bd660b8cf7a18b4a81a666072fd",
    "testharness"
   ],
+  "trusted-types/TrustedTypePolicyFactory-metadata.tentative.html": [
+   "694e4d2660fce5c3b89e457023ea147c84d67834",
+   "testharness"
+  ],
   "trusted-types/Window-TrustedTypes.tentative.html": [
    "5bbb4356c21d249a21c8204aad6c9ba7a353cb4e",
    "testharness"
@@ -504242,7 +504433,7 @@
    "testharness"
   ],
   "xhr/data-uri-expected.txt": [
-   "bf77d17f26baf3ae886b4021f34a3a882cc9f663",
+   "c0d444f8132ff4f4691880be13c562e5e42b355b",
    "support"
   ],
   "xhr/data-uri.htm": [
diff --git a/third_party/blink/web_tests/external/wpt/audio-output/idlharness.https.window.js b/third_party/blink/web_tests/external/wpt/audio-output/idlharness.https.window.js
index f10e523b..c13b167 100644
--- a/third_party/blink/web_tests/external/wpt/audio-output/idlharness.https.window.js
+++ b/third_party/blink/web_tests/external/wpt/audio-output/idlharness.https.window.js
@@ -5,20 +5,15 @@
 
 'use strict';
 
-promise_test(async () => {
-  const srcs = ['audio-output', 'dom', 'html'];
-  const [idl, dom, html] = await Promise.all(
-    srcs.map(i => fetch(`/interfaces/${i}.idl`).then(r => r.text())));
-
-  const idl_array = new IdlArray();
-  idl_array.add_idls(idl);
-  idl_array.add_dependency_idls(html);
-  idl_array.add_dependency_idls(dom);
-  self.audio = document.createElement('audio');
-  self.video = document.createElement('video');
-  idl_array.add_objects({
-    HTMLAudioElement: ['audio'],
-    HTMLVideoElement: ['video']
-  });
-  idl_array.test();
-}, 'Test IDL implementation of audio-output API');
+idl_test(
+  ['audio-output'],
+  ['html', 'dom'],
+  idl_array => {
+    self.audio = document.createElement('audio');
+    self.video = document.createElement('video');
+    idl_array.add_objects({
+      HTMLAudioElement: ['audio'],
+      HTMLVideoElement: ['video']
+    });
+  }
+);
diff --git a/third_party/blink/web_tests/external/wpt/beacon/idlharness.any.js b/third_party/blink/web_tests/external/wpt/beacon/idlharness.any.js
index 958daf4..bf267ab 100644
--- a/third_party/blink/web_tests/external/wpt/beacon/idlharness.any.js
+++ b/third_party/blink/web_tests/external/wpt/beacon/idlharness.any.js
@@ -3,15 +3,12 @@
 
 // https://w3c.github.io/beacon/
 
-promise_test(async () => {
-  const idl = await fetch('/interfaces/beacon.idl').then(r => r.text());
-  const html = await fetch('/interfaces/html.idl').then(r => r.text());
-
-  const idl_array = new IdlArray();
-  idl_array.add_idls(idl);
-  idl_array.add_dependency_idls(html);
-  idl_array.add_objects({
-    Navigator: ['navigator'],
-  });
-  idl_array.test();
-}, 'beacon interfaces');
+idl_test(
+  ['beacon'],
+  ['html'],
+  idl_array => {
+    idl_array.add_objects({
+      Navigator: ['navigator'],
+    });
+  }
+);
diff --git a/third_party/blink/web_tests/external/wpt/css/css-grid/grid-items/grid-item-rel-pos-001-ref.html b/third_party/blink/web_tests/external/wpt/css/css-grid/grid-items/grid-item-rel-pos-001-ref.html
new file mode 100644
index 0000000..a6305e56
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-grid/grid-items/grid-item-rel-pos-001-ref.html
@@ -0,0 +1,30 @@
+<!DOCTYPE HTML>
+<meta charset="utf-8">
+<title>Reference: Rel.pos. grid item with style change.</title>
+<link rel="author" title="James0x57" href="mailto:James0x57@gmail.com">
+<link rel="author" title="Mats Palmgren" href="mailto:mats@mozilla.com">
+<style>
+.grid {
+  margin: 40px;
+  display: grid;
+  grid: auto / repeat(3,100px);
+  grid-gap: 20px;
+}
+span, even {
+  position: relative;
+  min-height: 20px;
+  background: grey;
+  left: 0px;
+}
+.offset even {
+  left: 50%;
+}
+
+</style>
+
+
+<div class="grid offset">
+  <span></span><span></span><span></span>
+  <even></even><even></even><even></even>
+  <span></span><span></span><span></span>
+</div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-grid/grid-items/grid-item-rel-pos-001.html b/third_party/blink/web_tests/external/wpt/css/css-grid/grid-items/grid-item-rel-pos-001.html
new file mode 100644
index 0000000..d72df41
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-grid/grid-items/grid-item-rel-pos-001.html
@@ -0,0 +1,42 @@
+<!DOCTYPE HTML>
+<meta charset="utf-8">
+<title>CSS Grid Layout Test: Rel.pos. grid item with style change.</title>
+<link rel="author" title="James0x57" href="mailto:James0x57@gmail.com">
+<link rel="author" title="Mats Palmgren" href="mailto:mats@mozilla.com">
+<link rel="help" href="http://www.w3.org/TR/css-grid-1/#grid-items" title="Grid Items">
+<link rel="help" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1576355">
+<link rel="match" href="grid-item-rel-pos-001-ref.html">
+<meta name="assert" content="Checks that the rel.pos. grid items are positioned correctly after a 'left' style change.">
+<style>
+.grid {
+  margin: 40px;
+  display: grid;
+  grid: auto / repeat(3,100px);
+  grid-gap: 20px;
+}
+span, even {
+  position: relative;
+  min-height: 20px;
+  background: grey;
+  left: 0px;
+}
+.offset even {
+  left: 50%;
+}
+
+</style>
+
+
+<div class="grid offset">
+  <span></span><span></span><span></span>
+  <even></even><even></even><even></even>
+  <span></span><span></span><span></span>
+</div>
+
+<script>
+  document.body.offsetHeight;
+  let grid = document.querySelector('.grid');
+  grid.classList.remove('offset')
+  document.body.offsetHeight;
+  grid.classList.add('offset')
+</script>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-grid/grid-items/grid-item-rel-pos-002-ref.html b/third_party/blink/web_tests/external/wpt/css/css-grid/grid-items/grid-item-rel-pos-002-ref.html
new file mode 100644
index 0000000..643b80e1
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-grid/grid-items/grid-item-rel-pos-002-ref.html
@@ -0,0 +1,31 @@
+<!DOCTYPE HTML>
+<meta charset="utf-8">
+<title>Reference: Rel.pos. centered grid item with style change.</title>
+<link rel="author" title="James0x57" href="mailto:James0x57@gmail.com">
+<link rel="author" title="Mats Palmgren" href="mailto:mats@mozilla.com">
+<style>
+.grid {
+  margin: 40px;
+  display: grid;
+  grid: auto / repeat(3,100px);
+  grid-gap: 20px;
+}
+span, even {
+  position: relative;
+  min-height: 20px;
+  background: grey;
+  left: 0px;
+  width: 30px;
+  justify-self: center;
+}
+.offset even {
+  left: 20%;
+}
+
+</style>
+
+<div class="grid offset">
+  <span></span><span></span><span></span>
+  <even></even><even></even><even></even>
+  <span></span><span></span><span></span>
+</div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-grid/grid-items/grid-item-rel-pos-002.html b/third_party/blink/web_tests/external/wpt/css/css-grid/grid-items/grid-item-rel-pos-002.html
new file mode 100644
index 0000000..4a4d6c8
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-grid/grid-items/grid-item-rel-pos-002.html
@@ -0,0 +1,43 @@
+<!DOCTYPE HTML>
+<meta charset="utf-8">
+<title>CSS Grid Layout Test: Rel.pos. centered grid item with style change.</title>
+<link rel="author" title="James0x57" href="mailto:James0x57@gmail.com">
+<link rel="author" title="Mats Palmgren" href="mailto:mats@mozilla.com">
+<link rel="help" href="http://www.w3.org/TR/css-grid-1/#grid-items" title="Grid Items">
+<link rel="help" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1576355">
+<link rel="match" href="grid-item-rel-pos-002-ref.html">
+<meta name="assert" content="Checks that the rel.pos. grid items are positioned correctly after a 'left' style change.">
+<style>
+.grid {
+  margin: 40px;
+  display: grid;
+  grid: auto / repeat(3,100px);
+  grid-gap: 20px;
+}
+span, even {
+  position: relative;
+  min-height: 20px;
+  background: grey;
+  left: 0px;
+  width: 30px;
+  justify-self: center;
+}
+.offset even {
+  left: 20%;
+}
+
+</style>
+
+<div class="grid offset">
+  <span></span><span></span><span></span>
+  <even></even><even></even><even></even>
+  <span></span><span></span><span></span>
+</div>
+
+<script>
+  document.body.offsetHeight;
+  let grid = document.querySelector('.grid');
+  grid.classList.remove('offset')
+  document.body.offsetHeight;
+  grid.classList.add('offset')
+</script>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-shapes/animation/shape-image-threshold-interpolation.html b/third_party/blink/web_tests/external/wpt/css/css-shapes/animation/shape-image-threshold-interpolation.html
new file mode 100644
index 0000000..edac744
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-shapes/animation/shape-image-threshold-interpolation.html
@@ -0,0 +1,87 @@
+<!DOCTYPE html>
+<meta charset="UTF-8">
+<title>shape-image-threshold interpolation</title>
+<link rel="help" href="https://drafts.csswg.org/css-shapes/#shape-image-threshold-property">
+<meta name="assert" content="shape-image-threshold supports animation by computed value">
+
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/css/support/interpolation-testcommon.js"></script>
+
+<style>
+.parent {
+  shape-image-threshold: 0.4;
+}
+.target {
+  shape-image-threshold: 0.6;
+}
+</style>
+
+<body></body>
+
+<script>
+test_interpolation({
+  property: 'shape-image-threshold',
+  from: neutralKeyframe,
+  to: '0.8',
+}, [
+  {at: -1.5, expect: '0.3'},
+  {at: -0.5, expect: '0.5'},
+  {at: 0, expect: '0.6'},
+  {at: 0.5, expect: '0.7'},
+  {at: 1, expect: '0.8'},
+  {at: 1.5, expect: '0.9'},
+]);
+
+test_interpolation({
+  property: 'shape-image-threshold',
+  from: 'initial',
+  to: '0.8',
+}, [
+  {at: -1.5, expect: '0'},
+  {at: -0.5, expect: '0'},
+  {at: 0, expect: '0'},
+  {at: 0.5, expect: '0.4'},
+  {at: 1, expect: '0.8'},
+  {at: 1.5, expect: '1'},
+]);
+
+test_interpolation({
+  property: 'shape-image-threshold',
+  from: 'inherit',
+  to: '0.8',
+}, [
+  {at: -1.5, expect: '0'},
+  {at: -0.5, expect: '0.2'},
+  {at: 0, expect: '0.4'},
+  {at: 0.5, expect: '0.6'},
+  {at: 1, expect: '0.8'},
+  {at: 1.5, expect: '1'},
+]);
+
+test_interpolation({
+  property: 'shape-image-threshold',
+  from: 'unset',
+  to: '0.8',
+}, [
+  {at: -1.5, expect: '0'},
+  {at: -0.5, expect: '0'},
+  {at: 0, expect: '0'},
+  {at: 0.5, expect: '0.4'},
+  {at: 1, expect: '0.8'},
+  {at: 1.5, expect: '1'},
+]);
+
+test_interpolation({
+  property: 'shape-image-threshold',
+  from: '0.5',
+  to: '1'
+}, [
+  {at: -1.5, expect: '0'},
+  {at: -0.5, expect: '0.25'},
+  {at: 0, expect: '0.5'},
+  {at: 0.5, expect: '0.75'},
+  {at: 1, expect: '1'},
+  {at: 1.5, expect: '1'}
+]);
+</script>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-shapes/animation/shape-margin-interpolation.html b/third_party/blink/web_tests/external/wpt/css/css-shapes/animation/shape-margin-interpolation.html
new file mode 100644
index 0000000..48b3d0c
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-shapes/animation/shape-margin-interpolation.html
@@ -0,0 +1,87 @@
+<!DOCTYPE html>
+<meta charset="UTF-8">
+<title>shape-margin interpolation</title>
+<link rel="help" href="https://drafts.csswg.org/css-shapes/#shape-margin-property">
+<meta name="assert" content="shape-margin supports animation by computed value">
+
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/css/support/interpolation-testcommon.js"></script>
+
+<style>
+.parent {
+  shape-margin: 30px;
+}
+.target {
+  shape-margin: 10px;
+}
+</style>
+
+<body></body>
+
+<script>
+test_interpolation({
+  property: 'shape-margin',
+  from: neutralKeyframe,
+  to: '20px',
+}, [
+  {at: -0.3, expect: '7px'},
+  {at: 0, expect: '10px'},
+  {at: 0.3, expect: '13px'},
+  {at: 0.6, expect: '16px'},
+  {at: 1, expect: '20px'},
+  {at: 1.5, expect: '25px'},
+]);
+
+test_interpolation({
+  property: 'shape-margin',
+  from: 'initial',
+  to: '20px',
+}, [
+  {at: -0.3, expect: '0px'},
+  {at: 0, expect: '0px'},
+  {at: 0.3, expect: '6px'},
+  {at: 0.6, expect: '12px'},
+  {at: 1, expect: '20px'},
+  {at: 1.5, expect: '30px'},
+]);
+
+test_interpolation({
+  property: 'shape-margin',
+  from: 'inherit',
+  to: '20px',
+}, [
+  {at: -0.3, expect: '33px'},
+  {at: 0, expect: '30px'},
+  {at: 0.3, expect: '27px'},
+  {at: 0.6, expect: '24px'},
+  {at: 1, expect: '20px'},
+  {at: 1.5, expect: '15px'},
+]);
+
+test_interpolation({
+  property: 'shape-margin',
+  from: 'unset',
+  to: '20px',
+}, [
+  {at: -0.3, expect: '0px'},
+  {at: 0, expect: '0px'},
+  {at: 0.3, expect: '6px'},
+  {at: 0.6, expect: '12px'},
+  {at: 1, expect: '20px'},
+  {at: 1.5, expect: '30px'},
+]);
+
+test_interpolation({
+  property: 'shape-margin',
+  from: '0px',
+  to: '100px'
+}, [
+  {at: -0.3, expect: '0px'}, // CSS shape-margin can't be negative.
+  {at: 0, expect: '0px'},
+  {at: 0.3, expect: '30px'},
+  {at: 0.6, expect: '60px'},
+  {at: 1, expect: '100px'},
+  {at: 1.5, expect: '150px'},
+]);
+</script>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-shapes/animation/shape-outside-interpolation.html b/third_party/blink/web_tests/external/wpt/css/css-shapes/animation/shape-outside-interpolation.html
new file mode 100644
index 0000000..3380acd
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-shapes/animation/shape-outside-interpolation.html
@@ -0,0 +1,137 @@
+<!DOCTYPE html>
+<meta charset="UTF-8">
+<title>shape-outside interpolation</title>
+<link rel="help" href="https://drafts.csswg.org/css-shapes/#shape-outside-property">
+<meta name="assert" content="shape-outside supports animation as <basic-shape> or discrete">
+
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/css/support/interpolation-testcommon.js"></script>
+
+<style>
+.parent {
+  shape-outside: circle(80% at 30% 10%);
+}
+.target {
+  shape-outside: circle(60% at 10% 30%);
+}
+</style>
+
+<body></body>
+
+<script>
+/* TODO: add inset test once blend() works for it */
+
+test_interpolation({
+  property: 'shape-outside',
+  from: neutralKeyframe,
+  to: 'circle(40% at 20% 20%)',
+}, [
+  {at: -0.3, expect: 'circle(66% at 7% 33%)'},
+  {at: 0, expect: 'circle(60% at 10% 30%)'},
+  {at: 0.3, expect: 'circle(54% at 13% 27%)'},
+  {at: 0.6, expect: 'circle(48% at 16% 24%)'},
+  {at: 1, expect: 'circle(40% at 20% 20%)'},
+  {at: 1.5, expect: 'circle(30% at 25% 15%)'},
+]);
+
+test_no_interpolation({
+  property: 'shape-outside',
+  from: 'initial',
+  to: 'circle(40% at 20% 20%)',
+});
+
+test_interpolation({
+  property: 'shape-outside',
+  from: 'inherit',
+  to: 'circle(40% at 20% 20%)',
+}, [
+  {at: -0.3, expect: 'circle(92% at 33% 7%)'},
+  {at: 0, expect: 'circle(80% at 30% 10%)'},
+  {at: 0.3, expect: 'circle(68% at 27% 13%)'},
+  {at: 0.6, expect: 'circle(56% at 24% 16%)'},
+  {at: 1, expect: 'circle(40% at 20% 20%)'},
+  {at: 1.5, expect: 'circle(20% at 15% 25%)'},
+]);
+
+test_no_interpolation({
+  property: 'shape-outside',
+  from: 'unset',
+  to: 'circle(40% at 20% 20%)',
+});
+
+test_interpolation({
+  property: 'shape-outside',
+  from: 'circle(100% at 0% 0%)',
+  to: 'circle(50% at 25% 25%)',
+}, [
+  {at: -0.3, expect: 'circle(115% at -7.5% -7.5%)'},
+  {at: 0, expect: 'circle(100% at 0% 0%)'},
+  {at: 0.3, expect: 'circle(85% at 7.5% 7.5%)'},
+  {at: 0.6, expect: 'circle(70% at 15% 15%)'},
+  {at: 1, expect: 'circle(50% at 25% 25%)'},
+  {at: 1.5, expect: 'circle(25% at 37.5% 37.5%)'}
+]);
+
+test_interpolation({
+  property: 'shape-outside',
+  from: 'ellipse(100% 100% at 0% 0%)',
+  to: 'ellipse(50% 50% at 25% 25%)',
+}, [
+  {at: -0.3, expect: 'ellipse(115% 115% at -7.5% -7.5%)'},
+  {at: 0, expect: 'ellipse(100% 100% at 0% 0%)'},
+  {at: 0.3, expect: 'ellipse(85% 85% at 7.5% 7.5%)'},
+  {at: 0.6, expect: 'ellipse(70% 70% at 15% 15%)'},
+  {at: 1, expect: 'ellipse(50% 50% at 25% 25%)'},
+  {at: 1.5, expect: 'ellipse(25% 25% at 37.5% 37.5%)'}
+]);
+
+test_interpolation({
+  property: 'shape-outside',
+  from: 'polygon(nonzero, 0px 0px, 25px 25px, 50px 50px)',
+  to: 'polygon(nonzero, 25px 25px, 50px 50px, 75px 75px)',
+}, [
+  {at: -0.3, expect: 'polygon(nonzero, -7.5px -7.5px, 17.5px 17.5px, 42.5px 42.5px)'},
+  {at: 0, expect: 'polygon(nonzero, 0px 0px, 25px 25px, 50px 50px)'},
+  {at: 0.3, expect: 'polygon(nonzero, 7.5px 7.5px, 32.5px 32.5px, 57.5px 57.5px)'},
+  {at: 0.6, expect: 'polygon(nonzero, 15px 15px, 40px 40px, 65px 65px)'},
+  {at: 1, expect: 'polygon(nonzero, 25px 25px, 50px 50px, 75px 75px)'},
+  {at: 1.5, expect: 'polygon(nonzero, 37.5px 37.5px, 62.5px 62.5px, 87.5px 87.5px)'}
+]);
+
+test_no_interpolation({
+  property: 'shape-outside',
+  from: 'polygon(evenodd, 0px 0px, 25px 25px, 50px 50px)',
+  to: 'polygon(nonzero, 25px 25px, 50px 50px, 75px 75px)',
+});
+
+test_interpolation({
+  property: 'shape-outside',
+  from: 'inset(100%)',
+  to: 'inset(120%)',
+}, [
+  {at: -0.3, expect: 'inset(94%)'},
+  {at: 0, expect: 'inset(100%)'},
+  {at: 0.3, expect: 'inset(106%)'},
+  {at: 0.6, expect: 'inset(112%)'},
+  {at: 1, expect: 'inset(120%)'},
+  {at: 1.5, expect: 'inset(130%)'},
+]);
+
+test_no_interpolation({
+  property: 'shape-outside',
+  from: 'none',
+  to: 'ellipse(100% 100% at 0% 0%)',
+});
+
+// TODO: add intermediate keyframe tests when CSS shapes position computed values are cleaned up
+test_interpolation({
+  property: 'shape-outside',
+  from: 'circle(25% at right 5% bottom 15px)',
+  to: 'circle(45% at right 25% bottom 35px)',
+}, [
+  {at: 0.25, expect: 'circle(30% at 90% calc(-20px + 100%))'},
+  {at: 0.5, expect: 'circle(35% at 85% calc(-25px + 100%))'},
+  {at: 0.75, expect: 'circle(40% at 80% calc(-30px + 100%))'},
+]);
+</script>
diff --git a/third_party/blink/web_tests/external/wpt/dom/idlharness.any.js b/third_party/blink/web_tests/external/wpt/dom/idlharness.any.js
new file mode 100644
index 0000000..db841dc7
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/dom/idlharness.any.js
@@ -0,0 +1,22 @@
+// META: global=!window,worker
+// META: script=/resources/WebIDLParser.js
+// META: script=/resources/idlharness.js
+// META: timeout=long
+
+'use strict';
+
+idl_test(
+  ['dom'],
+  ['html'],
+  idl_array => {
+    idl_array.add_objects({
+      EventTarget: ['new EventTarget()'],
+      Event: ['new Event("foo")'],
+      CustomEvent: ['new CustomEvent("foo")'],
+      AbortController: ['new AbortController()'],
+      AbortSignal: ['new AbortController().signal'],
+    });
+  }
+);
+
+done();
diff --git a/third_party/blink/web_tests/external/wpt/dom/idlharness.window.js b/third_party/blink/web_tests/external/wpt/dom/idlharness.window.js
new file mode 100644
index 0000000..3f44ed5
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/dom/idlharness.window.js
@@ -0,0 +1,44 @@
+// META: script=/resources/WebIDLParser.js
+// META: script=/resources/idlharness.js
+// META: script=/common/subset-tests-by-key.js
+// META: variant=?include=Node
+// META: variant=?exclude=Node
+// META: timeout=long
+
+'use strict';
+
+idl_test(
+  ['dom'],
+  ['html'],
+  idl_array => {
+    self.xmlDoc = document.implementation.createDocument(null, '', null);
+    self.detachedRange = document.createRange();
+    detachedRange.detach();
+    self.element = xmlDoc.createElementNS(null, 'test');
+    element.setAttribute('bar', 'baz');
+
+    idl_array.add_objects({
+      EventTarget: ['new EventTarget()'],
+      Event: ['document.createEvent("Event")', 'new Event("foo")'],
+      CustomEvent: ['new CustomEvent("foo")'],
+      AbortController: ['new AbortController()'],
+      AbortSignal: ['new AbortController().signal'],
+      Document: ['new Document()'],
+      XMLDocument: ['xmlDoc'],
+      DOMImplementation: ['document.implementation'],
+      DocumentFragment: ['document.createDocumentFragment()'],
+      DocumentType: ['document.doctype'],
+      Element: ['element'],
+      Attr: ['document.querySelector("[id]").attributes[0]'],
+      Text: ['document.createTextNode("abc")'],
+      ProcessingInstruction: ['xmlDoc.createProcessingInstruction("abc", "def")'],
+      Comment: ['document.createComment("abc")'],
+      Range: ['document.createRange()', 'detachedRange'],
+      NodeIterator: ['document.createNodeIterator(document.body, NodeFilter.SHOW_ALL, null, false)'],
+      TreeWalker: ['document.createTreeWalker(document.body, NodeFilter.SHOW_ALL, null, false)'],
+      NodeList: ['document.querySelectorAll("script")'],
+      HTMLCollection: ['document.body.children'],
+      DOMTokenList: ['document.body.classList'],
+    });
+  }
+);
diff --git a/third_party/blink/web_tests/external/wpt/dom/idlharness.window_exclude=Node-expected.txt b/third_party/blink/web_tests/external/wpt/dom/idlharness.window_exclude=Node-expected.txt
new file mode 100644
index 0000000..217c77d
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/dom/idlharness.window_exclude=Node-expected.txt
@@ -0,0 +1,1108 @@
+This is a testharness.js-based test.
+Found 1104 tests; 1080 PASS, 24 FAIL, 0 TIMEOUT, 0 NOTRUN.
+PASS idl_test setup
+PASS Partial interface Window: original interface defined
+PASS Event interface: existence and properties of interface object
+PASS Event interface object length
+PASS Event interface object name
+PASS Event interface: existence and properties of interface prototype object
+PASS Event interface: existence and properties of interface prototype object's "constructor" property
+PASS Event interface: existence and properties of interface prototype object's @@unscopables property
+PASS Event interface: attribute type
+PASS Event interface: attribute target
+PASS Event interface: attribute srcElement
+PASS Event interface: attribute currentTarget
+PASS Event interface: operation composedPath()
+PASS Event interface: constant NONE on interface object
+PASS Event interface: constant NONE on interface prototype object
+PASS Event interface: constant CAPTURING_PHASE on interface object
+PASS Event interface: constant CAPTURING_PHASE on interface prototype object
+PASS Event interface: constant AT_TARGET on interface object
+PASS Event interface: constant AT_TARGET on interface prototype object
+PASS Event interface: constant BUBBLING_PHASE on interface object
+PASS Event interface: constant BUBBLING_PHASE on interface prototype object
+PASS Event interface: attribute eventPhase
+PASS Event interface: operation stopPropagation()
+PASS Event interface: attribute cancelBubble
+PASS Event interface: operation stopImmediatePropagation()
+PASS Event interface: attribute bubbles
+PASS Event interface: attribute cancelable
+PASS Event interface: attribute returnValue
+PASS Event interface: operation preventDefault()
+PASS Event interface: attribute defaultPrevented
+PASS Event interface: attribute composed
+PASS Event interface: attribute timeStamp
+PASS Event interface: operation initEvent(DOMString, boolean, boolean)
+PASS Event must be primary interface of document.createEvent("Event")
+PASS Stringification of document.createEvent("Event")
+PASS Event interface: document.createEvent("Event") must inherit property "type" with the proper type
+PASS Event interface: document.createEvent("Event") must inherit property "target" with the proper type
+PASS Event interface: document.createEvent("Event") must inherit property "srcElement" with the proper type
+PASS Event interface: document.createEvent("Event") must inherit property "currentTarget" with the proper type
+PASS Event interface: document.createEvent("Event") must inherit property "composedPath()" with the proper type
+PASS Event interface: document.createEvent("Event") must inherit property "NONE" with the proper type
+PASS Event interface: document.createEvent("Event") must inherit property "CAPTURING_PHASE" with the proper type
+PASS Event interface: document.createEvent("Event") must inherit property "AT_TARGET" with the proper type
+PASS Event interface: document.createEvent("Event") must inherit property "BUBBLING_PHASE" with the proper type
+PASS Event interface: document.createEvent("Event") must inherit property "eventPhase" with the proper type
+PASS Event interface: document.createEvent("Event") must inherit property "stopPropagation()" with the proper type
+PASS Event interface: document.createEvent("Event") must inherit property "cancelBubble" with the proper type
+PASS Event interface: document.createEvent("Event") must inherit property "stopImmediatePropagation()" with the proper type
+PASS Event interface: document.createEvent("Event") must inherit property "bubbles" with the proper type
+PASS Event interface: document.createEvent("Event") must inherit property "cancelable" with the proper type
+PASS Event interface: document.createEvent("Event") must inherit property "returnValue" with the proper type
+PASS Event interface: document.createEvent("Event") must inherit property "preventDefault()" with the proper type
+PASS Event interface: document.createEvent("Event") must inherit property "defaultPrevented" with the proper type
+PASS Event interface: document.createEvent("Event") must inherit property "composed" with the proper type
+PASS Event interface: document.createEvent("Event") must have own property "isTrusted"
+PASS Event interface: document.createEvent("Event") must inherit property "timeStamp" with the proper type
+PASS Event interface: document.createEvent("Event") must inherit property "initEvent(DOMString, boolean, boolean)" with the proper type
+PASS Event interface: calling initEvent(DOMString, boolean, boolean) on document.createEvent("Event") with too few arguments must throw TypeError
+PASS Event must be primary interface of new Event("foo")
+PASS Stringification of new Event("foo")
+PASS Event interface: new Event("foo") must inherit property "type" with the proper type
+PASS Event interface: new Event("foo") must inherit property "target" with the proper type
+PASS Event interface: new Event("foo") must inherit property "srcElement" with the proper type
+PASS Event interface: new Event("foo") must inherit property "currentTarget" with the proper type
+PASS Event interface: new Event("foo") must inherit property "composedPath()" with the proper type
+PASS Event interface: new Event("foo") must inherit property "NONE" with the proper type
+PASS Event interface: new Event("foo") must inherit property "CAPTURING_PHASE" with the proper type
+PASS Event interface: new Event("foo") must inherit property "AT_TARGET" with the proper type
+PASS Event interface: new Event("foo") must inherit property "BUBBLING_PHASE" with the proper type
+PASS Event interface: new Event("foo") must inherit property "eventPhase" with the proper type
+PASS Event interface: new Event("foo") must inherit property "stopPropagation()" with the proper type
+PASS Event interface: new Event("foo") must inherit property "cancelBubble" with the proper type
+PASS Event interface: new Event("foo") must inherit property "stopImmediatePropagation()" with the proper type
+PASS Event interface: new Event("foo") must inherit property "bubbles" with the proper type
+PASS Event interface: new Event("foo") must inherit property "cancelable" with the proper type
+PASS Event interface: new Event("foo") must inherit property "returnValue" with the proper type
+PASS Event interface: new Event("foo") must inherit property "preventDefault()" with the proper type
+PASS Event interface: new Event("foo") must inherit property "defaultPrevented" with the proper type
+PASS Event interface: new Event("foo") must inherit property "composed" with the proper type
+PASS Event interface: new Event("foo") must have own property "isTrusted"
+PASS Event interface: new Event("foo") must inherit property "timeStamp" with the proper type
+PASS Event interface: new Event("foo") must inherit property "initEvent(DOMString, boolean, boolean)" with the proper type
+PASS Event interface: calling initEvent(DOMString, boolean, boolean) on new Event("foo") with too few arguments must throw TypeError
+PASS CustomEvent interface: existence and properties of interface object
+PASS CustomEvent interface object length
+PASS CustomEvent interface object name
+PASS CustomEvent interface: existence and properties of interface prototype object
+PASS CustomEvent interface: existence and properties of interface prototype object's "constructor" property
+PASS CustomEvent interface: existence and properties of interface prototype object's @@unscopables property
+PASS CustomEvent interface: attribute detail
+PASS CustomEvent interface: operation initCustomEvent(DOMString, boolean, boolean, any)
+PASS CustomEvent must be primary interface of new CustomEvent("foo")
+PASS Stringification of new CustomEvent("foo")
+PASS CustomEvent interface: new CustomEvent("foo") must inherit property "detail" with the proper type
+PASS CustomEvent interface: new CustomEvent("foo") must inherit property "initCustomEvent(DOMString, boolean, boolean, any)" with the proper type
+PASS CustomEvent interface: calling initCustomEvent(DOMString, boolean, boolean, any) on new CustomEvent("foo") with too few arguments must throw TypeError
+PASS Event interface: new CustomEvent("foo") must inherit property "type" with the proper type
+PASS Event interface: new CustomEvent("foo") must inherit property "target" with the proper type
+PASS Event interface: new CustomEvent("foo") must inherit property "srcElement" with the proper type
+PASS Event interface: new CustomEvent("foo") must inherit property "currentTarget" with the proper type
+PASS Event interface: new CustomEvent("foo") must inherit property "composedPath()" with the proper type
+PASS Event interface: new CustomEvent("foo") must inherit property "NONE" with the proper type
+PASS Event interface: new CustomEvent("foo") must inherit property "CAPTURING_PHASE" with the proper type
+PASS Event interface: new CustomEvent("foo") must inherit property "AT_TARGET" with the proper type
+PASS Event interface: new CustomEvent("foo") must inherit property "BUBBLING_PHASE" with the proper type
+PASS Event interface: new CustomEvent("foo") must inherit property "eventPhase" with the proper type
+PASS Event interface: new CustomEvent("foo") must inherit property "stopPropagation()" with the proper type
+PASS Event interface: new CustomEvent("foo") must inherit property "cancelBubble" with the proper type
+PASS Event interface: new CustomEvent("foo") must inherit property "stopImmediatePropagation()" with the proper type
+PASS Event interface: new CustomEvent("foo") must inherit property "bubbles" with the proper type
+PASS Event interface: new CustomEvent("foo") must inherit property "cancelable" with the proper type
+PASS Event interface: new CustomEvent("foo") must inherit property "returnValue" with the proper type
+PASS Event interface: new CustomEvent("foo") must inherit property "preventDefault()" with the proper type
+PASS Event interface: new CustomEvent("foo") must inherit property "defaultPrevented" with the proper type
+PASS Event interface: new CustomEvent("foo") must inherit property "composed" with the proper type
+PASS Event interface: new CustomEvent("foo") must have own property "isTrusted"
+PASS Event interface: new CustomEvent("foo") must inherit property "timeStamp" with the proper type
+PASS Event interface: new CustomEvent("foo") must inherit property "initEvent(DOMString, boolean, boolean)" with the proper type
+PASS Event interface: calling initEvent(DOMString, boolean, boolean) on new CustomEvent("foo") with too few arguments must throw TypeError
+PASS EventTarget interface: existence and properties of interface object
+PASS EventTarget interface object length
+PASS EventTarget interface object name
+PASS EventTarget interface: existence and properties of interface prototype object
+PASS EventTarget interface: existence and properties of interface prototype object's "constructor" property
+PASS EventTarget interface: existence and properties of interface prototype object's @@unscopables property
+PASS EventTarget interface: operation addEventListener(DOMString, EventListener, [object Object],[object Object])
+PASS EventTarget interface: operation removeEventListener(DOMString, EventListener, [object Object],[object Object])
+PASS EventTarget interface: operation dispatchEvent(Event)
+PASS EventTarget must be primary interface of new EventTarget()
+PASS Stringification of new EventTarget()
+PASS EventTarget interface: new EventTarget() must inherit property "addEventListener(DOMString, EventListener, [object Object],[object Object])" with the proper type
+PASS EventTarget interface: calling addEventListener(DOMString, EventListener, [object Object],[object Object]) on new EventTarget() with too few arguments must throw TypeError
+PASS EventTarget interface: new EventTarget() must inherit property "removeEventListener(DOMString, EventListener, [object Object],[object Object])" with the proper type
+PASS EventTarget interface: calling removeEventListener(DOMString, EventListener, [object Object],[object Object]) on new EventTarget() with too few arguments must throw TypeError
+PASS EventTarget interface: new EventTarget() must inherit property "dispatchEvent(Event)" with the proper type
+PASS EventTarget interface: calling dispatchEvent(Event) on new EventTarget() with too few arguments must throw TypeError
+PASS EventListener interface: existence and properties of interface object
+PASS EventListener interface: existence and properties of interface prototype object
+PASS EventListener interface: existence and properties of interface prototype object's "constructor" property
+PASS EventListener interface: existence and properties of interface prototype object's @@unscopables property
+PASS EventListener interface: operation handleEvent(Event)
+PASS AbortController interface: existence and properties of interface object
+PASS AbortController interface object length
+PASS AbortController interface object name
+PASS AbortController interface: existence and properties of interface prototype object
+PASS AbortController interface: existence and properties of interface prototype object's "constructor" property
+PASS AbortController interface: existence and properties of interface prototype object's @@unscopables property
+PASS AbortController interface: attribute signal
+PASS AbortController interface: operation abort()
+PASS AbortController must be primary interface of new AbortController()
+PASS Stringification of new AbortController()
+PASS AbortController interface: new AbortController() must inherit property "signal" with the proper type
+PASS AbortController interface: new AbortController() must inherit property "abort()" with the proper type
+PASS AbortSignal interface: existence and properties of interface object
+PASS AbortSignal interface object length
+PASS AbortSignal interface object name
+PASS AbortSignal interface: existence and properties of interface prototype object
+PASS AbortSignal interface: existence and properties of interface prototype object's "constructor" property
+PASS AbortSignal interface: existence and properties of interface prototype object's @@unscopables property
+PASS AbortSignal interface: attribute aborted
+PASS AbortSignal interface: attribute onabort
+PASS AbortSignal must be primary interface of new AbortController().signal
+PASS Stringification of new AbortController().signal
+PASS AbortSignal interface: new AbortController().signal must inherit property "aborted" with the proper type
+PASS AbortSignal interface: new AbortController().signal must inherit property "onabort" with the proper type
+PASS EventTarget interface: new AbortController().signal must inherit property "addEventListener(DOMString, EventListener, [object Object],[object Object])" with the proper type
+PASS EventTarget interface: calling addEventListener(DOMString, EventListener, [object Object],[object Object]) on new AbortController().signal with too few arguments must throw TypeError
+PASS EventTarget interface: new AbortController().signal must inherit property "removeEventListener(DOMString, EventListener, [object Object],[object Object])" with the proper type
+PASS EventTarget interface: calling removeEventListener(DOMString, EventListener, [object Object],[object Object]) on new AbortController().signal with too few arguments must throw TypeError
+PASS EventTarget interface: new AbortController().signal must inherit property "dispatchEvent(Event)" with the proper type
+PASS EventTarget interface: calling dispatchEvent(Event) on new AbortController().signal with too few arguments must throw TypeError
+PASS NodeList interface: existence and properties of interface object
+PASS NodeList interface object length
+PASS NodeList interface object name
+PASS NodeList interface: existence and properties of interface prototype object
+PASS NodeList interface: existence and properties of interface prototype object's "constructor" property
+PASS NodeList interface: existence and properties of interface prototype object's @@unscopables property
+PASS NodeList interface: operation item(unsigned long)
+PASS NodeList interface: attribute length
+PASS NodeList interface: iterable<Node>
+PASS NodeList must be primary interface of document.querySelectorAll("script")
+PASS Stringification of document.querySelectorAll("script")
+PASS NodeList interface: document.querySelectorAll("script") must inherit property "item(unsigned long)" with the proper type
+PASS NodeList interface: calling item(unsigned long) on document.querySelectorAll("script") with too few arguments must throw TypeError
+PASS NodeList interface: document.querySelectorAll("script") must inherit property "length" with the proper type
+PASS HTMLCollection interface: existence and properties of interface object
+PASS HTMLCollection interface object length
+PASS HTMLCollection interface object name
+PASS HTMLCollection interface: existence and properties of interface prototype object
+PASS HTMLCollection interface: existence and properties of interface prototype object's "constructor" property
+PASS HTMLCollection interface: existence and properties of interface prototype object's @@unscopables property
+PASS HTMLCollection interface: attribute length
+PASS HTMLCollection interface: operation item(unsigned long)
+PASS HTMLCollection interface: operation namedItem(DOMString)
+PASS HTMLCollection must be primary interface of document.body.children
+PASS Stringification of document.body.children
+PASS HTMLCollection interface: document.body.children must inherit property "length" with the proper type
+PASS HTMLCollection interface: document.body.children must inherit property "item(unsigned long)" with the proper type
+PASS HTMLCollection interface: calling item(unsigned long) on document.body.children with too few arguments must throw TypeError
+PASS HTMLCollection interface: document.body.children must inherit property "namedItem(DOMString)" with the proper type
+PASS HTMLCollection interface: calling namedItem(DOMString) on document.body.children with too few arguments must throw TypeError
+PASS MutationObserver interface: existence and properties of interface object
+PASS MutationObserver interface object length
+PASS MutationObserver interface object name
+PASS MutationObserver interface: existence and properties of interface prototype object
+PASS MutationObserver interface: existence and properties of interface prototype object's "constructor" property
+PASS MutationObserver interface: existence and properties of interface prototype object's @@unscopables property
+PASS MutationObserver interface: operation observe(Node, MutationObserverInit)
+PASS MutationObserver interface: operation disconnect()
+PASS MutationObserver interface: operation takeRecords()
+PASS MutationRecord interface: existence and properties of interface object
+PASS MutationRecord interface object length
+PASS MutationRecord interface object name
+PASS MutationRecord interface: existence and properties of interface prototype object
+PASS MutationRecord interface: existence and properties of interface prototype object's "constructor" property
+PASS MutationRecord interface: existence and properties of interface prototype object's @@unscopables property
+PASS MutationRecord interface: attribute type
+PASS MutationRecord interface: attribute target
+PASS MutationRecord interface: attribute addedNodes
+PASS MutationRecord interface: attribute removedNodes
+PASS MutationRecord interface: attribute previousSibling
+PASS MutationRecord interface: attribute nextSibling
+PASS MutationRecord interface: attribute attributeName
+PASS MutationRecord interface: attribute attributeNamespace
+PASS MutationRecord interface: attribute oldValue
+PASS Document interface: existence and properties of interface object
+PASS Document interface object length
+PASS Document interface object name
+PASS Document interface: existence and properties of interface prototype object
+PASS Document interface: existence and properties of interface prototype object's "constructor" property
+FAIL Document interface: existence and properties of interface prototype object's @@unscopables property assert_false: Document.prototype[Symbol.unscopables] should not be writable expected false got true
+PASS Document interface: attribute implementation
+PASS Document interface: attribute URL
+PASS Document interface: attribute documentURI
+FAIL Document interface: attribute origin assert_true: The prototype object must have a property "origin" expected true got false
+PASS Document interface: attribute compatMode
+PASS Document interface: attribute characterSet
+PASS Document interface: attribute charset
+PASS Document interface: attribute inputEncoding
+PASS Document interface: attribute contentType
+PASS Document interface: attribute doctype
+PASS Document interface: attribute documentElement
+PASS Document interface: operation getElementsByTagName(DOMString)
+PASS Document interface: operation getElementsByTagNameNS(DOMString, DOMString)
+PASS Document interface: operation getElementsByClassName(DOMString)
+PASS Document interface: operation createElement(DOMString, [object Object],[object Object])
+PASS Document interface: operation createElementNS(DOMString, DOMString, [object Object],[object Object])
+PASS Document interface: operation createDocumentFragment()
+PASS Document interface: operation createTextNode(DOMString)
+PASS Document interface: operation createCDATASection(DOMString)
+PASS Document interface: operation createComment(DOMString)
+PASS Document interface: operation createProcessingInstruction(DOMString, DOMString)
+PASS Document interface: operation importNode(Node, boolean)
+PASS Document interface: operation adoptNode(Node)
+PASS Document interface: operation createAttribute(DOMString)
+PASS Document interface: operation createAttributeNS(DOMString, DOMString)
+PASS Document interface: operation createEvent(DOMString)
+PASS Document interface: operation createRange()
+PASS Document interface: operation createNodeIterator(Node, unsigned long, NodeFilter)
+PASS Document interface: operation createTreeWalker(Node, unsigned long, NodeFilter)
+PASS Document interface: operation getElementById(DOMString)
+PASS Document interface: attribute children
+PASS Document interface: attribute firstElementChild
+PASS Document interface: attribute lastElementChild
+PASS Document interface: attribute childElementCount
+PASS Document interface: operation prepend([object Object],[object Object])
+PASS Document interface: operation append([object Object],[object Object])
+PASS Document interface: operation querySelector(DOMString)
+PASS Document interface: operation querySelectorAll(DOMString)
+PASS Document must be primary interface of new Document()
+PASS Stringification of new Document()
+PASS Document interface: new Document() must inherit property "implementation" with the proper type
+PASS Document interface: new Document() must inherit property "URL" with the proper type
+PASS Document interface: new Document() must inherit property "documentURI" with the proper type
+FAIL Document interface: new Document() must inherit property "origin" with the proper type assert_inherits: property "origin" not found in prototype chain
+PASS Document interface: new Document() must inherit property "compatMode" with the proper type
+PASS Document interface: new Document() must inherit property "characterSet" with the proper type
+PASS Document interface: new Document() must inherit property "charset" with the proper type
+PASS Document interface: new Document() must inherit property "inputEncoding" with the proper type
+PASS Document interface: new Document() must inherit property "contentType" with the proper type
+PASS Document interface: new Document() must inherit property "doctype" with the proper type
+PASS Document interface: new Document() must inherit property "documentElement" with the proper type
+PASS Document interface: new Document() must inherit property "getElementsByTagName(DOMString)" with the proper type
+PASS Document interface: calling getElementsByTagName(DOMString) on new Document() with too few arguments must throw TypeError
+PASS Document interface: new Document() must inherit property "getElementsByTagNameNS(DOMString, DOMString)" with the proper type
+PASS Document interface: calling getElementsByTagNameNS(DOMString, DOMString) on new Document() with too few arguments must throw TypeError
+PASS Document interface: new Document() must inherit property "getElementsByClassName(DOMString)" with the proper type
+PASS Document interface: calling getElementsByClassName(DOMString) on new Document() with too few arguments must throw TypeError
+PASS Document interface: new Document() must inherit property "createElement(DOMString, [object Object],[object Object])" with the proper type
+PASS Document interface: calling createElement(DOMString, [object Object],[object Object]) on new Document() with too few arguments must throw TypeError
+PASS Document interface: new Document() must inherit property "createElementNS(DOMString, DOMString, [object Object],[object Object])" with the proper type
+PASS Document interface: calling createElementNS(DOMString, DOMString, [object Object],[object Object]) on new Document() with too few arguments must throw TypeError
+PASS Document interface: new Document() must inherit property "createDocumentFragment()" with the proper type
+PASS Document interface: new Document() must inherit property "createTextNode(DOMString)" with the proper type
+PASS Document interface: calling createTextNode(DOMString) on new Document() with too few arguments must throw TypeError
+PASS Document interface: new Document() must inherit property "createCDATASection(DOMString)" with the proper type
+PASS Document interface: calling createCDATASection(DOMString) on new Document() with too few arguments must throw TypeError
+PASS Document interface: new Document() must inherit property "createComment(DOMString)" with the proper type
+PASS Document interface: calling createComment(DOMString) on new Document() with too few arguments must throw TypeError
+PASS Document interface: new Document() must inherit property "createProcessingInstruction(DOMString, DOMString)" with the proper type
+PASS Document interface: calling createProcessingInstruction(DOMString, DOMString) on new Document() with too few arguments must throw TypeError
+PASS Document interface: new Document() must inherit property "importNode(Node, boolean)" with the proper type
+PASS Document interface: calling importNode(Node, boolean) on new Document() with too few arguments must throw TypeError
+PASS Document interface: new Document() must inherit property "adoptNode(Node)" with the proper type
+PASS Document interface: calling adoptNode(Node) on new Document() with too few arguments must throw TypeError
+PASS Document interface: new Document() must inherit property "createAttribute(DOMString)" with the proper type
+PASS Document interface: calling createAttribute(DOMString) on new Document() with too few arguments must throw TypeError
+PASS Document interface: new Document() must inherit property "createAttributeNS(DOMString, DOMString)" with the proper type
+PASS Document interface: calling createAttributeNS(DOMString, DOMString) on new Document() with too few arguments must throw TypeError
+PASS Document interface: new Document() must inherit property "createEvent(DOMString)" with the proper type
+PASS Document interface: calling createEvent(DOMString) on new Document() with too few arguments must throw TypeError
+PASS Document interface: new Document() must inherit property "createRange()" with the proper type
+PASS Document interface: new Document() must inherit property "createNodeIterator(Node, unsigned long, NodeFilter)" with the proper type
+PASS Document interface: calling createNodeIterator(Node, unsigned long, NodeFilter) on new Document() with too few arguments must throw TypeError
+PASS Document interface: new Document() must inherit property "createTreeWalker(Node, unsigned long, NodeFilter)" with the proper type
+PASS Document interface: calling createTreeWalker(Node, unsigned long, NodeFilter) on new Document() with too few arguments must throw TypeError
+PASS Document interface: new Document() must inherit property "getElementById(DOMString)" with the proper type
+PASS Document interface: calling getElementById(DOMString) on new Document() with too few arguments must throw TypeError
+PASS Document interface: new Document() must inherit property "children" with the proper type
+PASS Document interface: new Document() must inherit property "firstElementChild" with the proper type
+PASS Document interface: new Document() must inherit property "lastElementChild" with the proper type
+PASS Document interface: new Document() must inherit property "childElementCount" with the proper type
+PASS Document interface: new Document() must inherit property "prepend([object Object],[object Object])" with the proper type
+PASS Document interface: calling prepend([object Object],[object Object]) on new Document() with too few arguments must throw TypeError
+PASS Document interface: new Document() must inherit property "append([object Object],[object Object])" with the proper type
+PASS Document interface: calling append([object Object],[object Object]) on new Document() with too few arguments must throw TypeError
+PASS Document interface: new Document() must inherit property "querySelector(DOMString)" with the proper type
+PASS Document interface: calling querySelector(DOMString) on new Document() with too few arguments must throw TypeError
+PASS Document interface: new Document() must inherit property "querySelectorAll(DOMString)" with the proper type
+PASS Document interface: calling querySelectorAll(DOMString) on new Document() with too few arguments must throw TypeError
+PASS EventTarget interface: new Document() must inherit property "addEventListener(DOMString, EventListener, [object Object],[object Object])" with the proper type
+PASS EventTarget interface: calling addEventListener(DOMString, EventListener, [object Object],[object Object]) on new Document() with too few arguments must throw TypeError
+PASS EventTarget interface: new Document() must inherit property "removeEventListener(DOMString, EventListener, [object Object],[object Object])" with the proper type
+PASS EventTarget interface: calling removeEventListener(DOMString, EventListener, [object Object],[object Object]) on new Document() with too few arguments must throw TypeError
+PASS EventTarget interface: new Document() must inherit property "dispatchEvent(Event)" with the proper type
+PASS EventTarget interface: calling dispatchEvent(Event) on new Document() with too few arguments must throw TypeError
+PASS XMLDocument interface: existence and properties of interface object
+PASS XMLDocument interface object length
+PASS XMLDocument interface object name
+PASS XMLDocument interface: existence and properties of interface prototype object
+PASS XMLDocument interface: existence and properties of interface prototype object's "constructor" property
+PASS XMLDocument interface: existence and properties of interface prototype object's @@unscopables property
+PASS XMLDocument must be primary interface of xmlDoc
+PASS Stringification of xmlDoc
+PASS Document interface: xmlDoc must inherit property "implementation" with the proper type
+PASS Document interface: xmlDoc must inherit property "URL" with the proper type
+PASS Document interface: xmlDoc must inherit property "documentURI" with the proper type
+FAIL Document interface: xmlDoc must inherit property "origin" with the proper type assert_inherits: property "origin" not found in prototype chain
+PASS Document interface: xmlDoc must inherit property "compatMode" with the proper type
+PASS Document interface: xmlDoc must inherit property "characterSet" with the proper type
+PASS Document interface: xmlDoc must inherit property "charset" with the proper type
+PASS Document interface: xmlDoc must inherit property "inputEncoding" with the proper type
+PASS Document interface: xmlDoc must inherit property "contentType" with the proper type
+PASS Document interface: xmlDoc must inherit property "doctype" with the proper type
+PASS Document interface: xmlDoc must inherit property "documentElement" with the proper type
+PASS Document interface: xmlDoc must inherit property "getElementsByTagName(DOMString)" with the proper type
+PASS Document interface: calling getElementsByTagName(DOMString) on xmlDoc with too few arguments must throw TypeError
+PASS Document interface: xmlDoc must inherit property "getElementsByTagNameNS(DOMString, DOMString)" with the proper type
+PASS Document interface: calling getElementsByTagNameNS(DOMString, DOMString) on xmlDoc with too few arguments must throw TypeError
+PASS Document interface: xmlDoc must inherit property "getElementsByClassName(DOMString)" with the proper type
+PASS Document interface: calling getElementsByClassName(DOMString) on xmlDoc with too few arguments must throw TypeError
+PASS Document interface: xmlDoc must inherit property "createElement(DOMString, [object Object],[object Object])" with the proper type
+PASS Document interface: calling createElement(DOMString, [object Object],[object Object]) on xmlDoc with too few arguments must throw TypeError
+PASS Document interface: xmlDoc must inherit property "createElementNS(DOMString, DOMString, [object Object],[object Object])" with the proper type
+PASS Document interface: calling createElementNS(DOMString, DOMString, [object Object],[object Object]) on xmlDoc with too few arguments must throw TypeError
+PASS Document interface: xmlDoc must inherit property "createDocumentFragment()" with the proper type
+PASS Document interface: xmlDoc must inherit property "createTextNode(DOMString)" with the proper type
+PASS Document interface: calling createTextNode(DOMString) on xmlDoc with too few arguments must throw TypeError
+PASS Document interface: xmlDoc must inherit property "createCDATASection(DOMString)" with the proper type
+PASS Document interface: calling createCDATASection(DOMString) on xmlDoc with too few arguments must throw TypeError
+PASS Document interface: xmlDoc must inherit property "createComment(DOMString)" with the proper type
+PASS Document interface: calling createComment(DOMString) on xmlDoc with too few arguments must throw TypeError
+PASS Document interface: xmlDoc must inherit property "createProcessingInstruction(DOMString, DOMString)" with the proper type
+PASS Document interface: calling createProcessingInstruction(DOMString, DOMString) on xmlDoc with too few arguments must throw TypeError
+PASS Document interface: xmlDoc must inherit property "importNode(Node, boolean)" with the proper type
+PASS Document interface: calling importNode(Node, boolean) on xmlDoc with too few arguments must throw TypeError
+PASS Document interface: xmlDoc must inherit property "adoptNode(Node)" with the proper type
+PASS Document interface: calling adoptNode(Node) on xmlDoc with too few arguments must throw TypeError
+PASS Document interface: xmlDoc must inherit property "createAttribute(DOMString)" with the proper type
+PASS Document interface: calling createAttribute(DOMString) on xmlDoc with too few arguments must throw TypeError
+PASS Document interface: xmlDoc must inherit property "createAttributeNS(DOMString, DOMString)" with the proper type
+PASS Document interface: calling createAttributeNS(DOMString, DOMString) on xmlDoc with too few arguments must throw TypeError
+PASS Document interface: xmlDoc must inherit property "createEvent(DOMString)" with the proper type
+PASS Document interface: calling createEvent(DOMString) on xmlDoc with too few arguments must throw TypeError
+PASS Document interface: xmlDoc must inherit property "createRange()" with the proper type
+PASS Document interface: xmlDoc must inherit property "createNodeIterator(Node, unsigned long, NodeFilter)" with the proper type
+PASS Document interface: calling createNodeIterator(Node, unsigned long, NodeFilter) on xmlDoc with too few arguments must throw TypeError
+PASS Document interface: xmlDoc must inherit property "createTreeWalker(Node, unsigned long, NodeFilter)" with the proper type
+PASS Document interface: calling createTreeWalker(Node, unsigned long, NodeFilter) on xmlDoc with too few arguments must throw TypeError
+PASS Document interface: xmlDoc must inherit property "getElementById(DOMString)" with the proper type
+PASS Document interface: calling getElementById(DOMString) on xmlDoc with too few arguments must throw TypeError
+PASS Document interface: xmlDoc must inherit property "children" with the proper type
+PASS Document interface: xmlDoc must inherit property "firstElementChild" with the proper type
+PASS Document interface: xmlDoc must inherit property "lastElementChild" with the proper type
+PASS Document interface: xmlDoc must inherit property "childElementCount" with the proper type
+PASS Document interface: xmlDoc must inherit property "prepend([object Object],[object Object])" with the proper type
+PASS Document interface: calling prepend([object Object],[object Object]) on xmlDoc with too few arguments must throw TypeError
+PASS Document interface: xmlDoc must inherit property "append([object Object],[object Object])" with the proper type
+PASS Document interface: calling append([object Object],[object Object]) on xmlDoc with too few arguments must throw TypeError
+PASS Document interface: xmlDoc must inherit property "querySelector(DOMString)" with the proper type
+PASS Document interface: calling querySelector(DOMString) on xmlDoc with too few arguments must throw TypeError
+PASS Document interface: xmlDoc must inherit property "querySelectorAll(DOMString)" with the proper type
+PASS Document interface: calling querySelectorAll(DOMString) on xmlDoc with too few arguments must throw TypeError
+PASS EventTarget interface: xmlDoc must inherit property "addEventListener(DOMString, EventListener, [object Object],[object Object])" with the proper type
+PASS EventTarget interface: calling addEventListener(DOMString, EventListener, [object Object],[object Object]) on xmlDoc with too few arguments must throw TypeError
+PASS EventTarget interface: xmlDoc must inherit property "removeEventListener(DOMString, EventListener, [object Object],[object Object])" with the proper type
+PASS EventTarget interface: calling removeEventListener(DOMString, EventListener, [object Object],[object Object]) on xmlDoc with too few arguments must throw TypeError
+PASS EventTarget interface: xmlDoc must inherit property "dispatchEvent(Event)" with the proper type
+PASS EventTarget interface: calling dispatchEvent(Event) on xmlDoc with too few arguments must throw TypeError
+PASS DOMImplementation interface: existence and properties of interface object
+PASS DOMImplementation interface object length
+PASS DOMImplementation interface object name
+PASS DOMImplementation interface: existence and properties of interface prototype object
+PASS DOMImplementation interface: existence and properties of interface prototype object's "constructor" property
+PASS DOMImplementation interface: existence and properties of interface prototype object's @@unscopables property
+PASS DOMImplementation interface: operation createDocumentType(DOMString, DOMString, DOMString)
+PASS DOMImplementation interface: operation createDocument(DOMString, DOMString, DocumentType)
+PASS DOMImplementation interface: operation createHTMLDocument(DOMString)
+PASS DOMImplementation interface: operation hasFeature()
+PASS DOMImplementation must be primary interface of document.implementation
+PASS Stringification of document.implementation
+PASS DOMImplementation interface: document.implementation must inherit property "createDocumentType(DOMString, DOMString, DOMString)" with the proper type
+PASS DOMImplementation interface: calling createDocumentType(DOMString, DOMString, DOMString) on document.implementation with too few arguments must throw TypeError
+PASS DOMImplementation interface: document.implementation must inherit property "createDocument(DOMString, DOMString, DocumentType)" with the proper type
+PASS DOMImplementation interface: calling createDocument(DOMString, DOMString, DocumentType) on document.implementation with too few arguments must throw TypeError
+PASS DOMImplementation interface: document.implementation must inherit property "createHTMLDocument(DOMString)" with the proper type
+PASS DOMImplementation interface: calling createHTMLDocument(DOMString) on document.implementation with too few arguments must throw TypeError
+PASS DOMImplementation interface: document.implementation must inherit property "hasFeature()" with the proper type
+PASS DocumentType interface: existence and properties of interface object
+PASS DocumentType interface object length
+PASS DocumentType interface object name
+PASS DocumentType interface: existence and properties of interface prototype object
+PASS DocumentType interface: existence and properties of interface prototype object's "constructor" property
+FAIL DocumentType interface: existence and properties of interface prototype object's @@unscopables property assert_false: DocumentType.prototype[Symbol.unscopables] should not be writable expected false got true
+PASS DocumentType interface: attribute name
+PASS DocumentType interface: attribute publicId
+PASS DocumentType interface: attribute systemId
+PASS DocumentType interface: operation before([object Object],[object Object])
+PASS DocumentType interface: operation after([object Object],[object Object])
+PASS DocumentType interface: operation replaceWith([object Object],[object Object])
+PASS DocumentType interface: operation remove()
+PASS DocumentType must be primary interface of document.doctype
+PASS Stringification of document.doctype
+PASS DocumentType interface: document.doctype must inherit property "name" with the proper type
+PASS DocumentType interface: document.doctype must inherit property "publicId" with the proper type
+PASS DocumentType interface: document.doctype must inherit property "systemId" with the proper type
+PASS DocumentType interface: document.doctype must inherit property "before([object Object],[object Object])" with the proper type
+PASS DocumentType interface: calling before([object Object],[object Object]) on document.doctype with too few arguments must throw TypeError
+PASS DocumentType interface: document.doctype must inherit property "after([object Object],[object Object])" with the proper type
+PASS DocumentType interface: calling after([object Object],[object Object]) on document.doctype with too few arguments must throw TypeError
+PASS DocumentType interface: document.doctype must inherit property "replaceWith([object Object],[object Object])" with the proper type
+PASS DocumentType interface: calling replaceWith([object Object],[object Object]) on document.doctype with too few arguments must throw TypeError
+PASS DocumentType interface: document.doctype must inherit property "remove()" with the proper type
+PASS EventTarget interface: document.doctype must inherit property "addEventListener(DOMString, EventListener, [object Object],[object Object])" with the proper type
+PASS EventTarget interface: calling addEventListener(DOMString, EventListener, [object Object],[object Object]) on document.doctype with too few arguments must throw TypeError
+PASS EventTarget interface: document.doctype must inherit property "removeEventListener(DOMString, EventListener, [object Object],[object Object])" with the proper type
+PASS EventTarget interface: calling removeEventListener(DOMString, EventListener, [object Object],[object Object]) on document.doctype with too few arguments must throw TypeError
+PASS EventTarget interface: document.doctype must inherit property "dispatchEvent(Event)" with the proper type
+PASS EventTarget interface: calling dispatchEvent(Event) on document.doctype with too few arguments must throw TypeError
+PASS DocumentFragment interface: existence and properties of interface object
+PASS DocumentFragment interface object length
+PASS DocumentFragment interface object name
+PASS DocumentFragment interface: existence and properties of interface prototype object
+PASS DocumentFragment interface: existence and properties of interface prototype object's "constructor" property
+FAIL DocumentFragment interface: existence and properties of interface prototype object's @@unscopables property assert_false: DocumentFragment.prototype[Symbol.unscopables] should not be writable expected false got true
+PASS DocumentFragment interface: operation getElementById(DOMString)
+PASS DocumentFragment interface: attribute children
+PASS DocumentFragment interface: attribute firstElementChild
+PASS DocumentFragment interface: attribute lastElementChild
+PASS DocumentFragment interface: attribute childElementCount
+PASS DocumentFragment interface: operation prepend([object Object],[object Object])
+PASS DocumentFragment interface: operation append([object Object],[object Object])
+PASS DocumentFragment interface: operation querySelector(DOMString)
+PASS DocumentFragment interface: operation querySelectorAll(DOMString)
+PASS DocumentFragment must be primary interface of document.createDocumentFragment()
+PASS Stringification of document.createDocumentFragment()
+PASS DocumentFragment interface: document.createDocumentFragment() must inherit property "getElementById(DOMString)" with the proper type
+PASS DocumentFragment interface: calling getElementById(DOMString) on document.createDocumentFragment() with too few arguments must throw TypeError
+PASS DocumentFragment interface: document.createDocumentFragment() must inherit property "children" with the proper type
+PASS DocumentFragment interface: document.createDocumentFragment() must inherit property "firstElementChild" with the proper type
+PASS DocumentFragment interface: document.createDocumentFragment() must inherit property "lastElementChild" with the proper type
+PASS DocumentFragment interface: document.createDocumentFragment() must inherit property "childElementCount" with the proper type
+PASS DocumentFragment interface: document.createDocumentFragment() must inherit property "prepend([object Object],[object Object])" with the proper type
+PASS DocumentFragment interface: calling prepend([object Object],[object Object]) on document.createDocumentFragment() with too few arguments must throw TypeError
+PASS DocumentFragment interface: document.createDocumentFragment() must inherit property "append([object Object],[object Object])" with the proper type
+PASS DocumentFragment interface: calling append([object Object],[object Object]) on document.createDocumentFragment() with too few arguments must throw TypeError
+PASS DocumentFragment interface: document.createDocumentFragment() must inherit property "querySelector(DOMString)" with the proper type
+PASS DocumentFragment interface: calling querySelector(DOMString) on document.createDocumentFragment() with too few arguments must throw TypeError
+PASS DocumentFragment interface: document.createDocumentFragment() must inherit property "querySelectorAll(DOMString)" with the proper type
+PASS DocumentFragment interface: calling querySelectorAll(DOMString) on document.createDocumentFragment() with too few arguments must throw TypeError
+PASS EventTarget interface: document.createDocumentFragment() must inherit property "addEventListener(DOMString, EventListener, [object Object],[object Object])" with the proper type
+PASS EventTarget interface: calling addEventListener(DOMString, EventListener, [object Object],[object Object]) on document.createDocumentFragment() with too few arguments must throw TypeError
+PASS EventTarget interface: document.createDocumentFragment() must inherit property "removeEventListener(DOMString, EventListener, [object Object],[object Object])" with the proper type
+PASS EventTarget interface: calling removeEventListener(DOMString, EventListener, [object Object],[object Object]) on document.createDocumentFragment() with too few arguments must throw TypeError
+PASS EventTarget interface: document.createDocumentFragment() must inherit property "dispatchEvent(Event)" with the proper type
+PASS EventTarget interface: calling dispatchEvent(Event) on document.createDocumentFragment() with too few arguments must throw TypeError
+PASS ShadowRoot interface: existence and properties of interface object
+PASS ShadowRoot interface object length
+PASS ShadowRoot interface object name
+PASS ShadowRoot interface: existence and properties of interface prototype object
+PASS ShadowRoot interface: existence and properties of interface prototype object's "constructor" property
+PASS ShadowRoot interface: existence and properties of interface prototype object's @@unscopables property
+PASS ShadowRoot interface: attribute mode
+PASS ShadowRoot interface: attribute host
+PASS Element interface: existence and properties of interface object
+PASS Element interface object length
+PASS Element interface object name
+PASS Element interface: existence and properties of interface prototype object
+PASS Element interface: existence and properties of interface prototype object's "constructor" property
+FAIL Element interface: existence and properties of interface prototype object's @@unscopables property assert_false: Element.prototype[Symbol.unscopables] should not be writable expected false got true
+PASS Element interface: attribute namespaceURI
+PASS Element interface: attribute prefix
+PASS Element interface: attribute localName
+PASS Element interface: attribute tagName
+PASS Element interface: attribute id
+PASS Element interface: attribute className
+PASS Element interface: attribute classList
+PASS Element interface: attribute slot
+PASS Element interface: operation hasAttributes()
+PASS Element interface: attribute attributes
+PASS Element interface: operation getAttributeNames()
+PASS Element interface: operation getAttribute(DOMString)
+PASS Element interface: operation getAttributeNS(DOMString, DOMString)
+PASS Element interface: operation setAttribute(DOMString, DOMString)
+PASS Element interface: operation setAttributeNS(DOMString, DOMString, DOMString)
+PASS Element interface: operation removeAttribute(DOMString)
+PASS Element interface: operation removeAttributeNS(DOMString, DOMString)
+PASS Element interface: operation toggleAttribute(DOMString, boolean)
+PASS Element interface: operation hasAttribute(DOMString)
+PASS Element interface: operation hasAttributeNS(DOMString, DOMString)
+PASS Element interface: operation getAttributeNode(DOMString)
+PASS Element interface: operation getAttributeNodeNS(DOMString, DOMString)
+PASS Element interface: operation setAttributeNode(Attr)
+PASS Element interface: operation setAttributeNodeNS(Attr)
+PASS Element interface: operation removeAttributeNode(Attr)
+PASS Element interface: operation attachShadow(ShadowRootInit)
+PASS Element interface: attribute shadowRoot
+PASS Element interface: operation closest(DOMString)
+PASS Element interface: operation matches(DOMString)
+PASS Element interface: operation webkitMatchesSelector(DOMString)
+PASS Element interface: operation getElementsByTagName(DOMString)
+PASS Element interface: operation getElementsByTagNameNS(DOMString, DOMString)
+PASS Element interface: operation getElementsByClassName(DOMString)
+PASS Element interface: operation insertAdjacentElement(DOMString, Element)
+PASS Element interface: operation insertAdjacentText(DOMString, DOMString)
+PASS Element interface: attribute children
+PASS Element interface: attribute firstElementChild
+PASS Element interface: attribute lastElementChild
+PASS Element interface: attribute childElementCount
+PASS Element interface: operation prepend([object Object],[object Object])
+PASS Element interface: operation append([object Object],[object Object])
+PASS Element interface: operation querySelector(DOMString)
+PASS Element interface: operation querySelectorAll(DOMString)
+PASS Element interface: attribute previousElementSibling
+PASS Element interface: attribute nextElementSibling
+PASS Element interface: operation before([object Object],[object Object])
+PASS Element interface: operation after([object Object],[object Object])
+PASS Element interface: operation replaceWith([object Object],[object Object])
+PASS Element interface: operation remove()
+PASS Element interface: attribute assignedSlot
+PASS Element must be primary interface of element
+PASS Stringification of element
+PASS Element interface: element must inherit property "namespaceURI" with the proper type
+PASS Element interface: element must inherit property "prefix" with the proper type
+PASS Element interface: element must inherit property "localName" with the proper type
+PASS Element interface: element must inherit property "tagName" with the proper type
+PASS Element interface: element must inherit property "id" with the proper type
+PASS Element interface: element must inherit property "className" with the proper type
+PASS Element interface: element must inherit property "classList" with the proper type
+PASS Element interface: element must inherit property "slot" with the proper type
+PASS Element interface: element must inherit property "hasAttributes()" with the proper type
+PASS Element interface: element must inherit property "attributes" with the proper type
+PASS Element interface: element must inherit property "getAttributeNames()" with the proper type
+PASS Element interface: element must inherit property "getAttribute(DOMString)" with the proper type
+PASS Element interface: calling getAttribute(DOMString) on element with too few arguments must throw TypeError
+PASS Element interface: element must inherit property "getAttributeNS(DOMString, DOMString)" with the proper type
+PASS Element interface: calling getAttributeNS(DOMString, DOMString) on element with too few arguments must throw TypeError
+PASS Element interface: element must inherit property "setAttribute(DOMString, DOMString)" with the proper type
+PASS Element interface: calling setAttribute(DOMString, DOMString) on element with too few arguments must throw TypeError
+PASS Element interface: element must inherit property "setAttributeNS(DOMString, DOMString, DOMString)" with the proper type
+PASS Element interface: calling setAttributeNS(DOMString, DOMString, DOMString) on element with too few arguments must throw TypeError
+PASS Element interface: element must inherit property "removeAttribute(DOMString)" with the proper type
+PASS Element interface: calling removeAttribute(DOMString) on element with too few arguments must throw TypeError
+PASS Element interface: element must inherit property "removeAttributeNS(DOMString, DOMString)" with the proper type
+PASS Element interface: calling removeAttributeNS(DOMString, DOMString) on element with too few arguments must throw TypeError
+PASS Element interface: element must inherit property "toggleAttribute(DOMString, boolean)" with the proper type
+PASS Element interface: calling toggleAttribute(DOMString, boolean) on element with too few arguments must throw TypeError
+PASS Element interface: element must inherit property "hasAttribute(DOMString)" with the proper type
+PASS Element interface: calling hasAttribute(DOMString) on element with too few arguments must throw TypeError
+PASS Element interface: element must inherit property "hasAttributeNS(DOMString, DOMString)" with the proper type
+PASS Element interface: calling hasAttributeNS(DOMString, DOMString) on element with too few arguments must throw TypeError
+PASS Element interface: element must inherit property "getAttributeNode(DOMString)" with the proper type
+PASS Element interface: calling getAttributeNode(DOMString) on element with too few arguments must throw TypeError
+PASS Element interface: element must inherit property "getAttributeNodeNS(DOMString, DOMString)" with the proper type
+PASS Element interface: calling getAttributeNodeNS(DOMString, DOMString) on element with too few arguments must throw TypeError
+PASS Element interface: element must inherit property "setAttributeNode(Attr)" with the proper type
+PASS Element interface: calling setAttributeNode(Attr) on element with too few arguments must throw TypeError
+PASS Element interface: element must inherit property "setAttributeNodeNS(Attr)" with the proper type
+PASS Element interface: calling setAttributeNodeNS(Attr) on element with too few arguments must throw TypeError
+PASS Element interface: element must inherit property "removeAttributeNode(Attr)" with the proper type
+PASS Element interface: calling removeAttributeNode(Attr) on element with too few arguments must throw TypeError
+PASS Element interface: element must inherit property "attachShadow(ShadowRootInit)" with the proper type
+PASS Element interface: calling attachShadow(ShadowRootInit) on element with too few arguments must throw TypeError
+PASS Element interface: element must inherit property "shadowRoot" with the proper type
+PASS Element interface: element must inherit property "closest(DOMString)" with the proper type
+PASS Element interface: calling closest(DOMString) on element with too few arguments must throw TypeError
+PASS Element interface: element must inherit property "matches(DOMString)" with the proper type
+PASS Element interface: calling matches(DOMString) on element with too few arguments must throw TypeError
+PASS Element interface: element must inherit property "webkitMatchesSelector(DOMString)" with the proper type
+PASS Element interface: calling webkitMatchesSelector(DOMString) on element with too few arguments must throw TypeError
+PASS Element interface: element must inherit property "getElementsByTagName(DOMString)" with the proper type
+PASS Element interface: calling getElementsByTagName(DOMString) on element with too few arguments must throw TypeError
+PASS Element interface: element must inherit property "getElementsByTagNameNS(DOMString, DOMString)" with the proper type
+PASS Element interface: calling getElementsByTagNameNS(DOMString, DOMString) on element with too few arguments must throw TypeError
+PASS Element interface: element must inherit property "getElementsByClassName(DOMString)" with the proper type
+PASS Element interface: calling getElementsByClassName(DOMString) on element with too few arguments must throw TypeError
+PASS Element interface: element must inherit property "insertAdjacentElement(DOMString, Element)" with the proper type
+PASS Element interface: calling insertAdjacentElement(DOMString, Element) on element with too few arguments must throw TypeError
+PASS Element interface: element must inherit property "insertAdjacentText(DOMString, DOMString)" with the proper type
+PASS Element interface: calling insertAdjacentText(DOMString, DOMString) on element with too few arguments must throw TypeError
+PASS Element interface: element must inherit property "children" with the proper type
+PASS Element interface: element must inherit property "firstElementChild" with the proper type
+PASS Element interface: element must inherit property "lastElementChild" with the proper type
+PASS Element interface: element must inherit property "childElementCount" with the proper type
+PASS Element interface: element must inherit property "prepend([object Object],[object Object])" with the proper type
+PASS Element interface: calling prepend([object Object],[object Object]) on element with too few arguments must throw TypeError
+PASS Element interface: element must inherit property "append([object Object],[object Object])" with the proper type
+PASS Element interface: calling append([object Object],[object Object]) on element with too few arguments must throw TypeError
+PASS Element interface: element must inherit property "querySelector(DOMString)" with the proper type
+PASS Element interface: calling querySelector(DOMString) on element with too few arguments must throw TypeError
+PASS Element interface: element must inherit property "querySelectorAll(DOMString)" with the proper type
+PASS Element interface: calling querySelectorAll(DOMString) on element with too few arguments must throw TypeError
+PASS Element interface: element must inherit property "previousElementSibling" with the proper type
+PASS Element interface: element must inherit property "nextElementSibling" with the proper type
+PASS Element interface: element must inherit property "before([object Object],[object Object])" with the proper type
+PASS Element interface: calling before([object Object],[object Object]) on element with too few arguments must throw TypeError
+PASS Element interface: element must inherit property "after([object Object],[object Object])" with the proper type
+PASS Element interface: calling after([object Object],[object Object]) on element with too few arguments must throw TypeError
+PASS Element interface: element must inherit property "replaceWith([object Object],[object Object])" with the proper type
+PASS Element interface: calling replaceWith([object Object],[object Object]) on element with too few arguments must throw TypeError
+PASS Element interface: element must inherit property "remove()" with the proper type
+PASS Element interface: element must inherit property "assignedSlot" with the proper type
+PASS EventTarget interface: element must inherit property "addEventListener(DOMString, EventListener, [object Object],[object Object])" with the proper type
+PASS EventTarget interface: calling addEventListener(DOMString, EventListener, [object Object],[object Object]) on element with too few arguments must throw TypeError
+PASS EventTarget interface: element must inherit property "removeEventListener(DOMString, EventListener, [object Object],[object Object])" with the proper type
+PASS EventTarget interface: calling removeEventListener(DOMString, EventListener, [object Object],[object Object]) on element with too few arguments must throw TypeError
+PASS EventTarget interface: element must inherit property "dispatchEvent(Event)" with the proper type
+PASS EventTarget interface: calling dispatchEvent(Event) on element with too few arguments must throw TypeError
+PASS NamedNodeMap interface: existence and properties of interface object
+PASS NamedNodeMap interface object length
+PASS NamedNodeMap interface object name
+PASS NamedNodeMap interface: existence and properties of interface prototype object
+PASS NamedNodeMap interface: existence and properties of interface prototype object's "constructor" property
+PASS NamedNodeMap interface: existence and properties of interface prototype object's @@unscopables property
+PASS NamedNodeMap interface: attribute length
+PASS NamedNodeMap interface: operation item(unsigned long)
+PASS NamedNodeMap interface: operation getNamedItem(DOMString)
+PASS NamedNodeMap interface: operation getNamedItemNS(DOMString, DOMString)
+PASS NamedNodeMap interface: operation setNamedItem(Attr)
+PASS NamedNodeMap interface: operation setNamedItemNS(Attr)
+PASS NamedNodeMap interface: operation removeNamedItem(DOMString)
+PASS NamedNodeMap interface: operation removeNamedItemNS(DOMString, DOMString)
+PASS Attr interface: existence and properties of interface object
+PASS Attr interface object length
+PASS Attr interface object name
+PASS Attr interface: existence and properties of interface prototype object
+PASS Attr interface: existence and properties of interface prototype object's "constructor" property
+PASS Attr interface: existence and properties of interface prototype object's @@unscopables property
+PASS Attr interface: attribute namespaceURI
+PASS Attr interface: attribute prefix
+PASS Attr interface: attribute localName
+PASS Attr interface: attribute name
+PASS Attr interface: attribute value
+PASS Attr interface: attribute ownerElement
+PASS Attr interface: attribute specified
+PASS Attr must be primary interface of document.querySelector("[id]").attributes[0]
+PASS Stringification of document.querySelector("[id]").attributes[0]
+PASS Attr interface: document.querySelector("[id]").attributes[0] must inherit property "namespaceURI" with the proper type
+PASS Attr interface: document.querySelector("[id]").attributes[0] must inherit property "prefix" with the proper type
+PASS Attr interface: document.querySelector("[id]").attributes[0] must inherit property "localName" with the proper type
+PASS Attr interface: document.querySelector("[id]").attributes[0] must inherit property "name" with the proper type
+PASS Attr interface: document.querySelector("[id]").attributes[0] must inherit property "value" with the proper type
+PASS Attr interface: document.querySelector("[id]").attributes[0] must inherit property "ownerElement" with the proper type
+PASS Attr interface: document.querySelector("[id]").attributes[0] must inherit property "specified" with the proper type
+PASS EventTarget interface: document.querySelector("[id]").attributes[0] must inherit property "addEventListener(DOMString, EventListener, [object Object],[object Object])" with the proper type
+PASS EventTarget interface: calling addEventListener(DOMString, EventListener, [object Object],[object Object]) on document.querySelector("[id]").attributes[0] with too few arguments must throw TypeError
+PASS EventTarget interface: document.querySelector("[id]").attributes[0] must inherit property "removeEventListener(DOMString, EventListener, [object Object],[object Object])" with the proper type
+PASS EventTarget interface: calling removeEventListener(DOMString, EventListener, [object Object],[object Object]) on document.querySelector("[id]").attributes[0] with too few arguments must throw TypeError
+PASS EventTarget interface: document.querySelector("[id]").attributes[0] must inherit property "dispatchEvent(Event)" with the proper type
+PASS EventTarget interface: calling dispatchEvent(Event) on document.querySelector("[id]").attributes[0] with too few arguments must throw TypeError
+PASS CharacterData interface: existence and properties of interface object
+PASS CharacterData interface object length
+PASS CharacterData interface object name
+PASS CharacterData interface: existence and properties of interface prototype object
+PASS CharacterData interface: existence and properties of interface prototype object's "constructor" property
+FAIL CharacterData interface: existence and properties of interface prototype object's @@unscopables property assert_false: CharacterData.prototype[Symbol.unscopables] should not be writable expected false got true
+PASS CharacterData interface: attribute data
+PASS CharacterData interface: attribute length
+PASS CharacterData interface: operation substringData(unsigned long, unsigned long)
+PASS CharacterData interface: operation appendData(DOMString)
+PASS CharacterData interface: operation insertData(unsigned long, DOMString)
+PASS CharacterData interface: operation deleteData(unsigned long, unsigned long)
+PASS CharacterData interface: operation replaceData(unsigned long, unsigned long, DOMString)
+PASS CharacterData interface: attribute previousElementSibling
+PASS CharacterData interface: attribute nextElementSibling
+PASS CharacterData interface: operation before([object Object],[object Object])
+PASS CharacterData interface: operation after([object Object],[object Object])
+PASS CharacterData interface: operation replaceWith([object Object],[object Object])
+PASS CharacterData interface: operation remove()
+PASS Text interface: existence and properties of interface object
+PASS Text interface object length
+PASS Text interface object name
+PASS Text interface: existence and properties of interface prototype object
+PASS Text interface: existence and properties of interface prototype object's "constructor" property
+PASS Text interface: existence and properties of interface prototype object's @@unscopables property
+PASS Text interface: operation splitText(unsigned long)
+PASS Text interface: attribute wholeText
+PASS Text interface: attribute assignedSlot
+PASS Text must be primary interface of document.createTextNode("abc")
+PASS Stringification of document.createTextNode("abc")
+PASS Text interface: document.createTextNode("abc") must inherit property "splitText(unsigned long)" with the proper type
+PASS Text interface: calling splitText(unsigned long) on document.createTextNode("abc") with too few arguments must throw TypeError
+PASS Text interface: document.createTextNode("abc") must inherit property "wholeText" with the proper type
+PASS Text interface: document.createTextNode("abc") must inherit property "assignedSlot" with the proper type
+PASS CharacterData interface: document.createTextNode("abc") must inherit property "data" with the proper type
+PASS CharacterData interface: document.createTextNode("abc") must inherit property "length" with the proper type
+PASS CharacterData interface: document.createTextNode("abc") must inherit property "substringData(unsigned long, unsigned long)" with the proper type
+PASS CharacterData interface: calling substringData(unsigned long, unsigned long) on document.createTextNode("abc") with too few arguments must throw TypeError
+PASS CharacterData interface: document.createTextNode("abc") must inherit property "appendData(DOMString)" with the proper type
+PASS CharacterData interface: calling appendData(DOMString) on document.createTextNode("abc") with too few arguments must throw TypeError
+PASS CharacterData interface: document.createTextNode("abc") must inherit property "insertData(unsigned long, DOMString)" with the proper type
+PASS CharacterData interface: calling insertData(unsigned long, DOMString) on document.createTextNode("abc") with too few arguments must throw TypeError
+PASS CharacterData interface: document.createTextNode("abc") must inherit property "deleteData(unsigned long, unsigned long)" with the proper type
+PASS CharacterData interface: calling deleteData(unsigned long, unsigned long) on document.createTextNode("abc") with too few arguments must throw TypeError
+PASS CharacterData interface: document.createTextNode("abc") must inherit property "replaceData(unsigned long, unsigned long, DOMString)" with the proper type
+PASS CharacterData interface: calling replaceData(unsigned long, unsigned long, DOMString) on document.createTextNode("abc") with too few arguments must throw TypeError
+PASS CharacterData interface: document.createTextNode("abc") must inherit property "previousElementSibling" with the proper type
+PASS CharacterData interface: document.createTextNode("abc") must inherit property "nextElementSibling" with the proper type
+PASS CharacterData interface: document.createTextNode("abc") must inherit property "before([object Object],[object Object])" with the proper type
+PASS CharacterData interface: calling before([object Object],[object Object]) on document.createTextNode("abc") with too few arguments must throw TypeError
+PASS CharacterData interface: document.createTextNode("abc") must inherit property "after([object Object],[object Object])" with the proper type
+PASS CharacterData interface: calling after([object Object],[object Object]) on document.createTextNode("abc") with too few arguments must throw TypeError
+PASS CharacterData interface: document.createTextNode("abc") must inherit property "replaceWith([object Object],[object Object])" with the proper type
+PASS CharacterData interface: calling replaceWith([object Object],[object Object]) on document.createTextNode("abc") with too few arguments must throw TypeError
+PASS CharacterData interface: document.createTextNode("abc") must inherit property "remove()" with the proper type
+PASS EventTarget interface: document.createTextNode("abc") must inherit property "addEventListener(DOMString, EventListener, [object Object],[object Object])" with the proper type
+PASS EventTarget interface: calling addEventListener(DOMString, EventListener, [object Object],[object Object]) on document.createTextNode("abc") with too few arguments must throw TypeError
+PASS EventTarget interface: document.createTextNode("abc") must inherit property "removeEventListener(DOMString, EventListener, [object Object],[object Object])" with the proper type
+PASS EventTarget interface: calling removeEventListener(DOMString, EventListener, [object Object],[object Object]) on document.createTextNode("abc") with too few arguments must throw TypeError
+PASS EventTarget interface: document.createTextNode("abc") must inherit property "dispatchEvent(Event)" with the proper type
+PASS EventTarget interface: calling dispatchEvent(Event) on document.createTextNode("abc") with too few arguments must throw TypeError
+PASS CDATASection interface: existence and properties of interface object
+PASS CDATASection interface object length
+PASS CDATASection interface object name
+PASS CDATASection interface: existence and properties of interface prototype object
+PASS CDATASection interface: existence and properties of interface prototype object's "constructor" property
+PASS CDATASection interface: existence and properties of interface prototype object's @@unscopables property
+PASS ProcessingInstruction interface: existence and properties of interface object
+PASS ProcessingInstruction interface object length
+PASS ProcessingInstruction interface object name
+PASS ProcessingInstruction interface: existence and properties of interface prototype object
+PASS ProcessingInstruction interface: existence and properties of interface prototype object's "constructor" property
+PASS ProcessingInstruction interface: existence and properties of interface prototype object's @@unscopables property
+PASS ProcessingInstruction interface: attribute target
+PASS ProcessingInstruction must be primary interface of xmlDoc.createProcessingInstruction("abc", "def")
+PASS Stringification of xmlDoc.createProcessingInstruction("abc", "def")
+PASS ProcessingInstruction interface: xmlDoc.createProcessingInstruction("abc", "def") must inherit property "target" with the proper type
+PASS CharacterData interface: xmlDoc.createProcessingInstruction("abc", "def") must inherit property "data" with the proper type
+PASS CharacterData interface: xmlDoc.createProcessingInstruction("abc", "def") must inherit property "length" with the proper type
+PASS CharacterData interface: xmlDoc.createProcessingInstruction("abc", "def") must inherit property "substringData(unsigned long, unsigned long)" with the proper type
+PASS CharacterData interface: calling substringData(unsigned long, unsigned long) on xmlDoc.createProcessingInstruction("abc", "def") with too few arguments must throw TypeError
+PASS CharacterData interface: xmlDoc.createProcessingInstruction("abc", "def") must inherit property "appendData(DOMString)" with the proper type
+PASS CharacterData interface: calling appendData(DOMString) on xmlDoc.createProcessingInstruction("abc", "def") with too few arguments must throw TypeError
+PASS CharacterData interface: xmlDoc.createProcessingInstruction("abc", "def") must inherit property "insertData(unsigned long, DOMString)" with the proper type
+PASS CharacterData interface: calling insertData(unsigned long, DOMString) on xmlDoc.createProcessingInstruction("abc", "def") with too few arguments must throw TypeError
+PASS CharacterData interface: xmlDoc.createProcessingInstruction("abc", "def") must inherit property "deleteData(unsigned long, unsigned long)" with the proper type
+PASS CharacterData interface: calling deleteData(unsigned long, unsigned long) on xmlDoc.createProcessingInstruction("abc", "def") with too few arguments must throw TypeError
+PASS CharacterData interface: xmlDoc.createProcessingInstruction("abc", "def") must inherit property "replaceData(unsigned long, unsigned long, DOMString)" with the proper type
+PASS CharacterData interface: calling replaceData(unsigned long, unsigned long, DOMString) on xmlDoc.createProcessingInstruction("abc", "def") with too few arguments must throw TypeError
+PASS CharacterData interface: xmlDoc.createProcessingInstruction("abc", "def") must inherit property "previousElementSibling" with the proper type
+PASS CharacterData interface: xmlDoc.createProcessingInstruction("abc", "def") must inherit property "nextElementSibling" with the proper type
+PASS CharacterData interface: xmlDoc.createProcessingInstruction("abc", "def") must inherit property "before([object Object],[object Object])" with the proper type
+PASS CharacterData interface: calling before([object Object],[object Object]) on xmlDoc.createProcessingInstruction("abc", "def") with too few arguments must throw TypeError
+PASS CharacterData interface: xmlDoc.createProcessingInstruction("abc", "def") must inherit property "after([object Object],[object Object])" with the proper type
+PASS CharacterData interface: calling after([object Object],[object Object]) on xmlDoc.createProcessingInstruction("abc", "def") with too few arguments must throw TypeError
+PASS CharacterData interface: xmlDoc.createProcessingInstruction("abc", "def") must inherit property "replaceWith([object Object],[object Object])" with the proper type
+PASS CharacterData interface: calling replaceWith([object Object],[object Object]) on xmlDoc.createProcessingInstruction("abc", "def") with too few arguments must throw TypeError
+PASS CharacterData interface: xmlDoc.createProcessingInstruction("abc", "def") must inherit property "remove()" with the proper type
+PASS EventTarget interface: xmlDoc.createProcessingInstruction("abc", "def") must inherit property "addEventListener(DOMString, EventListener, [object Object],[object Object])" with the proper type
+PASS EventTarget interface: calling addEventListener(DOMString, EventListener, [object Object],[object Object]) on xmlDoc.createProcessingInstruction("abc", "def") with too few arguments must throw TypeError
+PASS EventTarget interface: xmlDoc.createProcessingInstruction("abc", "def") must inherit property "removeEventListener(DOMString, EventListener, [object Object],[object Object])" with the proper type
+PASS EventTarget interface: calling removeEventListener(DOMString, EventListener, [object Object],[object Object]) on xmlDoc.createProcessingInstruction("abc", "def") with too few arguments must throw TypeError
+PASS EventTarget interface: xmlDoc.createProcessingInstruction("abc", "def") must inherit property "dispatchEvent(Event)" with the proper type
+PASS EventTarget interface: calling dispatchEvent(Event) on xmlDoc.createProcessingInstruction("abc", "def") with too few arguments must throw TypeError
+PASS Comment interface: existence and properties of interface object
+PASS Comment interface object length
+PASS Comment interface object name
+PASS Comment interface: existence and properties of interface prototype object
+PASS Comment interface: existence and properties of interface prototype object's "constructor" property
+PASS Comment interface: existence and properties of interface prototype object's @@unscopables property
+PASS Comment must be primary interface of document.createComment("abc")
+PASS Stringification of document.createComment("abc")
+PASS CharacterData interface: document.createComment("abc") must inherit property "data" with the proper type
+PASS CharacterData interface: document.createComment("abc") must inherit property "length" with the proper type
+PASS CharacterData interface: document.createComment("abc") must inherit property "substringData(unsigned long, unsigned long)" with the proper type
+PASS CharacterData interface: calling substringData(unsigned long, unsigned long) on document.createComment("abc") with too few arguments must throw TypeError
+PASS CharacterData interface: document.createComment("abc") must inherit property "appendData(DOMString)" with the proper type
+PASS CharacterData interface: calling appendData(DOMString) on document.createComment("abc") with too few arguments must throw TypeError
+PASS CharacterData interface: document.createComment("abc") must inherit property "insertData(unsigned long, DOMString)" with the proper type
+PASS CharacterData interface: calling insertData(unsigned long, DOMString) on document.createComment("abc") with too few arguments must throw TypeError
+PASS CharacterData interface: document.createComment("abc") must inherit property "deleteData(unsigned long, unsigned long)" with the proper type
+PASS CharacterData interface: calling deleteData(unsigned long, unsigned long) on document.createComment("abc") with too few arguments must throw TypeError
+PASS CharacterData interface: document.createComment("abc") must inherit property "replaceData(unsigned long, unsigned long, DOMString)" with the proper type
+PASS CharacterData interface: calling replaceData(unsigned long, unsigned long, DOMString) on document.createComment("abc") with too few arguments must throw TypeError
+PASS CharacterData interface: document.createComment("abc") must inherit property "previousElementSibling" with the proper type
+PASS CharacterData interface: document.createComment("abc") must inherit property "nextElementSibling" with the proper type
+PASS CharacterData interface: document.createComment("abc") must inherit property "before([object Object],[object Object])" with the proper type
+PASS CharacterData interface: calling before([object Object],[object Object]) on document.createComment("abc") with too few arguments must throw TypeError
+PASS CharacterData interface: document.createComment("abc") must inherit property "after([object Object],[object Object])" with the proper type
+PASS CharacterData interface: calling after([object Object],[object Object]) on document.createComment("abc") with too few arguments must throw TypeError
+PASS CharacterData interface: document.createComment("abc") must inherit property "replaceWith([object Object],[object Object])" with the proper type
+PASS CharacterData interface: calling replaceWith([object Object],[object Object]) on document.createComment("abc") with too few arguments must throw TypeError
+PASS CharacterData interface: document.createComment("abc") must inherit property "remove()" with the proper type
+PASS EventTarget interface: document.createComment("abc") must inherit property "addEventListener(DOMString, EventListener, [object Object],[object Object])" with the proper type
+PASS EventTarget interface: calling addEventListener(DOMString, EventListener, [object Object],[object Object]) on document.createComment("abc") with too few arguments must throw TypeError
+PASS EventTarget interface: document.createComment("abc") must inherit property "removeEventListener(DOMString, EventListener, [object Object],[object Object])" with the proper type
+PASS EventTarget interface: calling removeEventListener(DOMString, EventListener, [object Object],[object Object]) on document.createComment("abc") with too few arguments must throw TypeError
+PASS EventTarget interface: document.createComment("abc") must inherit property "dispatchEvent(Event)" with the proper type
+PASS EventTarget interface: calling dispatchEvent(Event) on document.createComment("abc") with too few arguments must throw TypeError
+FAIL AbstractRange interface: existence and properties of interface object assert_own_property: self does not have own property "AbstractRange" expected property "AbstractRange" missing
+FAIL AbstractRange interface object length assert_own_property: self does not have own property "AbstractRange" expected property "AbstractRange" missing
+FAIL AbstractRange interface object name assert_own_property: self does not have own property "AbstractRange" expected property "AbstractRange" missing
+FAIL AbstractRange interface: existence and properties of interface prototype object assert_own_property: self does not have own property "AbstractRange" expected property "AbstractRange" missing
+FAIL AbstractRange interface: existence and properties of interface prototype object's "constructor" property assert_own_property: self does not have own property "AbstractRange" expected property "AbstractRange" missing
+FAIL AbstractRange interface: existence and properties of interface prototype object's @@unscopables property assert_own_property: self does not have own property "AbstractRange" expected property "AbstractRange" missing
+FAIL AbstractRange interface: attribute startContainer assert_own_property: self does not have own property "AbstractRange" expected property "AbstractRange" missing
+FAIL AbstractRange interface: attribute startOffset assert_own_property: self does not have own property "AbstractRange" expected property "AbstractRange" missing
+FAIL AbstractRange interface: attribute endContainer assert_own_property: self does not have own property "AbstractRange" expected property "AbstractRange" missing
+FAIL AbstractRange interface: attribute endOffset assert_own_property: self does not have own property "AbstractRange" expected property "AbstractRange" missing
+FAIL AbstractRange interface: attribute collapsed assert_own_property: self does not have own property "AbstractRange" expected property "AbstractRange" missing
+FAIL StaticRange interface: existence and properties of interface object assert_own_property: self does not have own property "AbstractRange" expected property "AbstractRange" missing
+PASS StaticRange interface object length
+PASS StaticRange interface object name
+FAIL StaticRange interface: existence and properties of interface prototype object assert_own_property: self does not have own property "AbstractRange" expected property "AbstractRange" missing
+PASS StaticRange interface: existence and properties of interface prototype object's "constructor" property
+PASS StaticRange interface: existence and properties of interface prototype object's @@unscopables property
+FAIL Range interface: existence and properties of interface object assert_own_property: self does not have own property "AbstractRange" expected property "AbstractRange" missing
+PASS Range interface object length
+PASS Range interface object name
+FAIL Range interface: existence and properties of interface prototype object assert_own_property: self does not have own property "AbstractRange" expected property "AbstractRange" missing
+PASS Range interface: existence and properties of interface prototype object's "constructor" property
+PASS Range interface: existence and properties of interface prototype object's @@unscopables property
+PASS Range interface: attribute commonAncestorContainer
+PASS Range interface: operation setStart(Node, unsigned long)
+PASS Range interface: operation setEnd(Node, unsigned long)
+PASS Range interface: operation setStartBefore(Node)
+PASS Range interface: operation setStartAfter(Node)
+PASS Range interface: operation setEndBefore(Node)
+PASS Range interface: operation setEndAfter(Node)
+PASS Range interface: operation collapse(boolean)
+PASS Range interface: operation selectNode(Node)
+PASS Range interface: operation selectNodeContents(Node)
+PASS Range interface: constant START_TO_START on interface object
+PASS Range interface: constant START_TO_START on interface prototype object
+PASS Range interface: constant START_TO_END on interface object
+PASS Range interface: constant START_TO_END on interface prototype object
+PASS Range interface: constant END_TO_END on interface object
+PASS Range interface: constant END_TO_END on interface prototype object
+PASS Range interface: constant END_TO_START on interface object
+PASS Range interface: constant END_TO_START on interface prototype object
+PASS Range interface: operation compareBoundaryPoints(unsigned short, Range)
+PASS Range interface: operation deleteContents()
+PASS Range interface: operation extractContents()
+PASS Range interface: operation cloneContents()
+PASS Range interface: operation insertNode(Node)
+PASS Range interface: operation surroundContents(Node)
+PASS Range interface: operation cloneRange()
+PASS Range interface: operation detach()
+PASS Range interface: operation isPointInRange(Node, unsigned long)
+PASS Range interface: operation comparePoint(Node, unsigned long)
+PASS Range interface: operation intersectsNode(Node)
+PASS Range interface: stringifier
+PASS Range must be primary interface of document.createRange()
+PASS Stringification of document.createRange()
+PASS Range interface: document.createRange() must inherit property "commonAncestorContainer" with the proper type
+PASS Range interface: document.createRange() must inherit property "setStart(Node, unsigned long)" with the proper type
+PASS Range interface: calling setStart(Node, unsigned long) on document.createRange() with too few arguments must throw TypeError
+PASS Range interface: document.createRange() must inherit property "setEnd(Node, unsigned long)" with the proper type
+PASS Range interface: calling setEnd(Node, unsigned long) on document.createRange() with too few arguments must throw TypeError
+PASS Range interface: document.createRange() must inherit property "setStartBefore(Node)" with the proper type
+PASS Range interface: calling setStartBefore(Node) on document.createRange() with too few arguments must throw TypeError
+PASS Range interface: document.createRange() must inherit property "setStartAfter(Node)" with the proper type
+PASS Range interface: calling setStartAfter(Node) on document.createRange() with too few arguments must throw TypeError
+PASS Range interface: document.createRange() must inherit property "setEndBefore(Node)" with the proper type
+PASS Range interface: calling setEndBefore(Node) on document.createRange() with too few arguments must throw TypeError
+PASS Range interface: document.createRange() must inherit property "setEndAfter(Node)" with the proper type
+PASS Range interface: calling setEndAfter(Node) on document.createRange() with too few arguments must throw TypeError
+PASS Range interface: document.createRange() must inherit property "collapse(boolean)" with the proper type
+PASS Range interface: calling collapse(boolean) on document.createRange() with too few arguments must throw TypeError
+PASS Range interface: document.createRange() must inherit property "selectNode(Node)" with the proper type
+PASS Range interface: calling selectNode(Node) on document.createRange() with too few arguments must throw TypeError
+PASS Range interface: document.createRange() must inherit property "selectNodeContents(Node)" with the proper type
+PASS Range interface: calling selectNodeContents(Node) on document.createRange() with too few arguments must throw TypeError
+PASS Range interface: document.createRange() must inherit property "START_TO_START" with the proper type
+PASS Range interface: document.createRange() must inherit property "START_TO_END" with the proper type
+PASS Range interface: document.createRange() must inherit property "END_TO_END" with the proper type
+PASS Range interface: document.createRange() must inherit property "END_TO_START" with the proper type
+PASS Range interface: document.createRange() must inherit property "compareBoundaryPoints(unsigned short, Range)" with the proper type
+PASS Range interface: calling compareBoundaryPoints(unsigned short, Range) on document.createRange() with too few arguments must throw TypeError
+PASS Range interface: document.createRange() must inherit property "deleteContents()" with the proper type
+PASS Range interface: document.createRange() must inherit property "extractContents()" with the proper type
+PASS Range interface: document.createRange() must inherit property "cloneContents()" with the proper type
+PASS Range interface: document.createRange() must inherit property "insertNode(Node)" with the proper type
+PASS Range interface: calling insertNode(Node) on document.createRange() with too few arguments must throw TypeError
+PASS Range interface: document.createRange() must inherit property "surroundContents(Node)" with the proper type
+PASS Range interface: calling surroundContents(Node) on document.createRange() with too few arguments must throw TypeError
+PASS Range interface: document.createRange() must inherit property "cloneRange()" with the proper type
+PASS Range interface: document.createRange() must inherit property "detach()" with the proper type
+PASS Range interface: document.createRange() must inherit property "isPointInRange(Node, unsigned long)" with the proper type
+PASS Range interface: calling isPointInRange(Node, unsigned long) on document.createRange() with too few arguments must throw TypeError
+PASS Range interface: document.createRange() must inherit property "comparePoint(Node, unsigned long)" with the proper type
+PASS Range interface: calling comparePoint(Node, unsigned long) on document.createRange() with too few arguments must throw TypeError
+PASS Range interface: document.createRange() must inherit property "intersectsNode(Node)" with the proper type
+PASS Range interface: calling intersectsNode(Node) on document.createRange() with too few arguments must throw TypeError
+PASS AbstractRange interface: document.createRange() must inherit property "startContainer" with the proper type
+PASS AbstractRange interface: document.createRange() must inherit property "startOffset" with the proper type
+PASS AbstractRange interface: document.createRange() must inherit property "endContainer" with the proper type
+PASS AbstractRange interface: document.createRange() must inherit property "endOffset" with the proper type
+PASS AbstractRange interface: document.createRange() must inherit property "collapsed" with the proper type
+PASS Range must be primary interface of detachedRange
+PASS Stringification of detachedRange
+PASS Range interface: detachedRange must inherit property "commonAncestorContainer" with the proper type
+PASS Range interface: detachedRange must inherit property "setStart(Node, unsigned long)" with the proper type
+PASS Range interface: calling setStart(Node, unsigned long) on detachedRange with too few arguments must throw TypeError
+PASS Range interface: detachedRange must inherit property "setEnd(Node, unsigned long)" with the proper type
+PASS Range interface: calling setEnd(Node, unsigned long) on detachedRange with too few arguments must throw TypeError
+PASS Range interface: detachedRange must inherit property "setStartBefore(Node)" with the proper type
+PASS Range interface: calling setStartBefore(Node) on detachedRange with too few arguments must throw TypeError
+PASS Range interface: detachedRange must inherit property "setStartAfter(Node)" with the proper type
+PASS Range interface: calling setStartAfter(Node) on detachedRange with too few arguments must throw TypeError
+PASS Range interface: detachedRange must inherit property "setEndBefore(Node)" with the proper type
+PASS Range interface: calling setEndBefore(Node) on detachedRange with too few arguments must throw TypeError
+PASS Range interface: detachedRange must inherit property "setEndAfter(Node)" with the proper type
+PASS Range interface: calling setEndAfter(Node) on detachedRange with too few arguments must throw TypeError
+PASS Range interface: detachedRange must inherit property "collapse(boolean)" with the proper type
+PASS Range interface: calling collapse(boolean) on detachedRange with too few arguments must throw TypeError
+PASS Range interface: detachedRange must inherit property "selectNode(Node)" with the proper type
+PASS Range interface: calling selectNode(Node) on detachedRange with too few arguments must throw TypeError
+PASS Range interface: detachedRange must inherit property "selectNodeContents(Node)" with the proper type
+PASS Range interface: calling selectNodeContents(Node) on detachedRange with too few arguments must throw TypeError
+PASS Range interface: detachedRange must inherit property "START_TO_START" with the proper type
+PASS Range interface: detachedRange must inherit property "START_TO_END" with the proper type
+PASS Range interface: detachedRange must inherit property "END_TO_END" with the proper type
+PASS Range interface: detachedRange must inherit property "END_TO_START" with the proper type
+PASS Range interface: detachedRange must inherit property "compareBoundaryPoints(unsigned short, Range)" with the proper type
+PASS Range interface: calling compareBoundaryPoints(unsigned short, Range) on detachedRange with too few arguments must throw TypeError
+PASS Range interface: detachedRange must inherit property "deleteContents()" with the proper type
+PASS Range interface: detachedRange must inherit property "extractContents()" with the proper type
+PASS Range interface: detachedRange must inherit property "cloneContents()" with the proper type
+PASS Range interface: detachedRange must inherit property "insertNode(Node)" with the proper type
+PASS Range interface: calling insertNode(Node) on detachedRange with too few arguments must throw TypeError
+PASS Range interface: detachedRange must inherit property "surroundContents(Node)" with the proper type
+PASS Range interface: calling surroundContents(Node) on detachedRange with too few arguments must throw TypeError
+PASS Range interface: detachedRange must inherit property "cloneRange()" with the proper type
+PASS Range interface: detachedRange must inherit property "detach()" with the proper type
+PASS Range interface: detachedRange must inherit property "isPointInRange(Node, unsigned long)" with the proper type
+PASS Range interface: calling isPointInRange(Node, unsigned long) on detachedRange with too few arguments must throw TypeError
+PASS Range interface: detachedRange must inherit property "comparePoint(Node, unsigned long)" with the proper type
+PASS Range interface: calling comparePoint(Node, unsigned long) on detachedRange with too few arguments must throw TypeError
+PASS Range interface: detachedRange must inherit property "intersectsNode(Node)" with the proper type
+PASS Range interface: calling intersectsNode(Node) on detachedRange with too few arguments must throw TypeError
+PASS AbstractRange interface: detachedRange must inherit property "startContainer" with the proper type
+PASS AbstractRange interface: detachedRange must inherit property "startOffset" with the proper type
+PASS AbstractRange interface: detachedRange must inherit property "endContainer" with the proper type
+PASS AbstractRange interface: detachedRange must inherit property "endOffset" with the proper type
+PASS AbstractRange interface: detachedRange must inherit property "collapsed" with the proper type
+PASS NodeIterator interface: existence and properties of interface object
+PASS NodeIterator interface object length
+PASS NodeIterator interface object name
+PASS NodeIterator interface: existence and properties of interface prototype object
+PASS NodeIterator interface: existence and properties of interface prototype object's "constructor" property
+PASS NodeIterator interface: existence and properties of interface prototype object's @@unscopables property
+PASS NodeIterator interface: attribute root
+PASS NodeIterator interface: attribute referenceNode
+PASS NodeIterator interface: attribute pointerBeforeReferenceNode
+PASS NodeIterator interface: attribute whatToShow
+PASS NodeIterator interface: attribute filter
+PASS NodeIterator interface: operation nextNode()
+PASS NodeIterator interface: operation previousNode()
+PASS NodeIterator interface: operation detach()
+PASS NodeIterator must be primary interface of document.createNodeIterator(document.body, NodeFilter.SHOW_ALL, null, false)
+PASS Stringification of document.createNodeIterator(document.body, NodeFilter.SHOW_ALL, null, false)
+PASS NodeIterator interface: document.createNodeIterator(document.body, NodeFilter.SHOW_ALL, null, false) must inherit property "root" with the proper type
+PASS NodeIterator interface: document.createNodeIterator(document.body, NodeFilter.SHOW_ALL, null, false) must inherit property "referenceNode" with the proper type
+PASS NodeIterator interface: document.createNodeIterator(document.body, NodeFilter.SHOW_ALL, null, false) must inherit property "pointerBeforeReferenceNode" with the proper type
+PASS NodeIterator interface: document.createNodeIterator(document.body, NodeFilter.SHOW_ALL, null, false) must inherit property "whatToShow" with the proper type
+PASS NodeIterator interface: document.createNodeIterator(document.body, NodeFilter.SHOW_ALL, null, false) must inherit property "filter" with the proper type
+PASS NodeIterator interface: document.createNodeIterator(document.body, NodeFilter.SHOW_ALL, null, false) must inherit property "nextNode()" with the proper type
+PASS NodeIterator interface: document.createNodeIterator(document.body, NodeFilter.SHOW_ALL, null, false) must inherit property "previousNode()" with the proper type
+PASS NodeIterator interface: document.createNodeIterator(document.body, NodeFilter.SHOW_ALL, null, false) must inherit property "detach()" with the proper type
+PASS TreeWalker interface: existence and properties of interface object
+PASS TreeWalker interface object length
+PASS TreeWalker interface object name
+PASS TreeWalker interface: existence and properties of interface prototype object
+PASS TreeWalker interface: existence and properties of interface prototype object's "constructor" property
+PASS TreeWalker interface: existence and properties of interface prototype object's @@unscopables property
+PASS TreeWalker interface: attribute root
+PASS TreeWalker interface: attribute whatToShow
+PASS TreeWalker interface: attribute filter
+PASS TreeWalker interface: attribute currentNode
+PASS TreeWalker interface: operation parentNode()
+PASS TreeWalker interface: operation firstChild()
+PASS TreeWalker interface: operation lastChild()
+PASS TreeWalker interface: operation previousSibling()
+PASS TreeWalker interface: operation nextSibling()
+PASS TreeWalker interface: operation previousNode()
+PASS TreeWalker interface: operation nextNode()
+PASS TreeWalker must be primary interface of document.createTreeWalker(document.body, NodeFilter.SHOW_ALL, null, false)
+PASS Stringification of document.createTreeWalker(document.body, NodeFilter.SHOW_ALL, null, false)
+PASS TreeWalker interface: document.createTreeWalker(document.body, NodeFilter.SHOW_ALL, null, false) must inherit property "root" with the proper type
+PASS TreeWalker interface: document.createTreeWalker(document.body, NodeFilter.SHOW_ALL, null, false) must inherit property "whatToShow" with the proper type
+PASS TreeWalker interface: document.createTreeWalker(document.body, NodeFilter.SHOW_ALL, null, false) must inherit property "filter" with the proper type
+PASS TreeWalker interface: document.createTreeWalker(document.body, NodeFilter.SHOW_ALL, null, false) must inherit property "currentNode" with the proper type
+PASS TreeWalker interface: document.createTreeWalker(document.body, NodeFilter.SHOW_ALL, null, false) must inherit property "parentNode()" with the proper type
+PASS TreeWalker interface: document.createTreeWalker(document.body, NodeFilter.SHOW_ALL, null, false) must inherit property "firstChild()" with the proper type
+PASS TreeWalker interface: document.createTreeWalker(document.body, NodeFilter.SHOW_ALL, null, false) must inherit property "lastChild()" with the proper type
+PASS TreeWalker interface: document.createTreeWalker(document.body, NodeFilter.SHOW_ALL, null, false) must inherit property "previousSibling()" with the proper type
+PASS TreeWalker interface: document.createTreeWalker(document.body, NodeFilter.SHOW_ALL, null, false) must inherit property "nextSibling()" with the proper type
+PASS TreeWalker interface: document.createTreeWalker(document.body, NodeFilter.SHOW_ALL, null, false) must inherit property "previousNode()" with the proper type
+PASS TreeWalker interface: document.createTreeWalker(document.body, NodeFilter.SHOW_ALL, null, false) must inherit property "nextNode()" with the proper type
+PASS NodeFilter interface: existence and properties of interface object
+PASS NodeFilter interface object name
+PASS NodeFilter interface: existence and properties of interface prototype object
+PASS NodeFilter interface: existence and properties of interface prototype object's "constructor" property
+PASS NodeFilter interface: existence and properties of interface prototype object's @@unscopables property
+PASS NodeFilter interface: constant FILTER_ACCEPT on interface object
+PASS NodeFilter interface: constant FILTER_ACCEPT on interface prototype object
+PASS NodeFilter interface: constant FILTER_REJECT on interface object
+PASS NodeFilter interface: constant FILTER_REJECT on interface prototype object
+PASS NodeFilter interface: constant FILTER_SKIP on interface object
+PASS NodeFilter interface: constant FILTER_SKIP on interface prototype object
+PASS NodeFilter interface: constant SHOW_ALL on interface object
+PASS NodeFilter interface: constant SHOW_ALL on interface prototype object
+PASS NodeFilter interface: constant SHOW_ELEMENT on interface object
+PASS NodeFilter interface: constant SHOW_ELEMENT on interface prototype object
+PASS NodeFilter interface: constant SHOW_ATTRIBUTE on interface object
+PASS NodeFilter interface: constant SHOW_ATTRIBUTE on interface prototype object
+PASS NodeFilter interface: constant SHOW_TEXT on interface object
+PASS NodeFilter interface: constant SHOW_TEXT on interface prototype object
+PASS NodeFilter interface: constant SHOW_CDATA_SECTION on interface object
+PASS NodeFilter interface: constant SHOW_CDATA_SECTION on interface prototype object
+PASS NodeFilter interface: constant SHOW_ENTITY_REFERENCE on interface object
+PASS NodeFilter interface: constant SHOW_ENTITY_REFERENCE on interface prototype object
+PASS NodeFilter interface: constant SHOW_ENTITY on interface object
+PASS NodeFilter interface: constant SHOW_ENTITY on interface prototype object
+PASS NodeFilter interface: constant SHOW_PROCESSING_INSTRUCTION on interface object
+PASS NodeFilter interface: constant SHOW_PROCESSING_INSTRUCTION on interface prototype object
+PASS NodeFilter interface: constant SHOW_COMMENT on interface object
+PASS NodeFilter interface: constant SHOW_COMMENT on interface prototype object
+PASS NodeFilter interface: constant SHOW_DOCUMENT on interface object
+PASS NodeFilter interface: constant SHOW_DOCUMENT on interface prototype object
+PASS NodeFilter interface: constant SHOW_DOCUMENT_TYPE on interface object
+PASS NodeFilter interface: constant SHOW_DOCUMENT_TYPE on interface prototype object
+PASS NodeFilter interface: constant SHOW_DOCUMENT_FRAGMENT on interface object
+PASS NodeFilter interface: constant SHOW_DOCUMENT_FRAGMENT on interface prototype object
+PASS NodeFilter interface: constant SHOW_NOTATION on interface object
+PASS NodeFilter interface: constant SHOW_NOTATION on interface prototype object
+PASS NodeFilter interface: operation acceptNode(Node)
+PASS DOMTokenList interface: existence and properties of interface object
+PASS DOMTokenList interface object length
+PASS DOMTokenList interface object name
+PASS DOMTokenList interface: existence and properties of interface prototype object
+PASS DOMTokenList interface: existence and properties of interface prototype object's "constructor" property
+PASS DOMTokenList interface: existence and properties of interface prototype object's @@unscopables property
+PASS DOMTokenList interface: attribute length
+PASS DOMTokenList interface: operation item(unsigned long)
+PASS DOMTokenList interface: operation contains(DOMString)
+PASS DOMTokenList interface: operation add(DOMString)
+PASS DOMTokenList interface: operation remove(DOMString)
+PASS DOMTokenList interface: operation toggle(DOMString, boolean)
+PASS DOMTokenList interface: operation replace(DOMString, DOMString)
+PASS DOMTokenList interface: operation supports(DOMString)
+PASS DOMTokenList interface: attribute value
+PASS DOMTokenList interface: stringifier
+PASS DOMTokenList interface: iterable<DOMString>
+PASS DOMTokenList must be primary interface of document.body.classList
+PASS Stringification of document.body.classList
+PASS DOMTokenList interface: document.body.classList must inherit property "length" with the proper type
+PASS DOMTokenList interface: document.body.classList must inherit property "item(unsigned long)" with the proper type
+PASS DOMTokenList interface: calling item(unsigned long) on document.body.classList with too few arguments must throw TypeError
+PASS DOMTokenList interface: document.body.classList must inherit property "contains(DOMString)" with the proper type
+PASS DOMTokenList interface: calling contains(DOMString) on document.body.classList with too few arguments must throw TypeError
+PASS DOMTokenList interface: document.body.classList must inherit property "add(DOMString)" with the proper type
+PASS DOMTokenList interface: calling add(DOMString) on document.body.classList with too few arguments must throw TypeError
+PASS DOMTokenList interface: document.body.classList must inherit property "remove(DOMString)" with the proper type
+PASS DOMTokenList interface: calling remove(DOMString) on document.body.classList with too few arguments must throw TypeError
+PASS DOMTokenList interface: document.body.classList must inherit property "toggle(DOMString, boolean)" with the proper type
+PASS DOMTokenList interface: calling toggle(DOMString, boolean) on document.body.classList with too few arguments must throw TypeError
+PASS DOMTokenList interface: document.body.classList must inherit property "replace(DOMString, DOMString)" with the proper type
+PASS DOMTokenList interface: calling replace(DOMString, DOMString) on document.body.classList with too few arguments must throw TypeError
+PASS DOMTokenList interface: document.body.classList must inherit property "supports(DOMString)" with the proper type
+PASS DOMTokenList interface: calling supports(DOMString) on document.body.classList with too few arguments must throw TypeError
+PASS DOMTokenList interface: document.body.classList must inherit property "value" with the proper type
+FAIL Window interface: attribute event assert_true: property should be enumerable expected true got false
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/external/wpt/dom/interfaces.html b/third_party/blink/web_tests/external/wpt/dom/interfaces.html
deleted file mode 100644
index 111608b..0000000
--- a/third_party/blink/web_tests/external/wpt/dom/interfaces.html
+++ /dev/null
@@ -1,63 +0,0 @@
-<!doctype html>
-<meta charset=utf-8>
-<title>DOM IDL tests</title>
-<meta name="timeout" content="long">
-<meta name="variant" content="?include=Node">
-<meta name="variant" content="?exclude=Node">
-<script src=/resources/testharness.js></script>
-<script src=/resources/testharnessreport.js></script>
-<script src=/common/subset-tests-by-key.js></script>
-<script src=/resources/WebIDLParser.js></script>
-<script src=/resources/idlharness.js></script>
-
-<h1>DOM IDL tests</h1>
-<div id=log></div>
-<script>
-"use strict";
-var xmlDoc = document.implementation.createDocument(null, "", null);
-var detachedRange = document.createRange();
-detachedRange.detach();
-var element = xmlDoc.createElementNS(null, "test");
-element.setAttribute("bar", "baz");
-
-var idlArray = new IdlArray();
-
-function doTest([html, dom]) {
-  idlArray.add_idls(dom);
-  idlArray.add_dependency_idls(html);
-  idlArray.add_objects({
-    EventTarget: ['new EventTarget()'],
-    Event: ['document.createEvent("Event")', 'new Event("foo")'],
-    CustomEvent: ['new CustomEvent("foo")'],
-    AbortController: ['new AbortController()'],
-    AbortSignal: ['new AbortController().signal'],
-    Document: ['new Document()'],
-    XMLDocument: ['xmlDoc'],
-    DOMImplementation: ['document.implementation'],
-    DocumentFragment: ['document.createDocumentFragment()'],
-    DocumentType: ['document.doctype'],
-    Element: ['element'],
-    Attr: ['document.querySelector("[id]").attributes[0]'],
-    Text: ['document.createTextNode("abc")'],
-    ProcessingInstruction: ['xmlDoc.createProcessingInstruction("abc", "def")'],
-    Comment: ['document.createComment("abc")'],
-    Range: ['document.createRange()', 'detachedRange'],
-    NodeIterator: ['document.createNodeIterator(document.body, NodeFilter.SHOW_ALL, null, false)'],
-    TreeWalker: ['document.createTreeWalker(document.body, NodeFilter.SHOW_ALL, null, false)'],
-    NodeList: ['document.querySelectorAll("script")'],
-    HTMLCollection: ['document.body.children'],
-    DOMTokenList: ['document.body.classList'],
-  });
-  idlArray.test();
-}
-
-function fetchText(url) {
-  return fetch(url).then((response) => response.text());
-}
-
-promise_test(function() {
-  return Promise.all(['/interfaces/html.idl',
-                      '/interfaces/dom.idl'].map(fetchText))
-                .then(doTest);
-}, "Test driver");
-</script>
diff --git a/third_party/blink/web_tests/external/wpt/encrypted-media/idlharness.https.html b/third_party/blink/web_tests/external/wpt/encrypted-media/idlharness.https.html
index 6a2ae80a..8050942 100644
--- a/third_party/blink/web_tests/external/wpt/encrypted-media/idlharness.https.html
+++ b/third_party/blink/web_tests/external/wpt/encrypted-media/idlharness.https.html
@@ -22,16 +22,19 @@
     <script>
       'use strict';
 
-      promise_test(async () => {
-        const idls = await fetch('/interfaces/encrypted-media.idl').then(r => r.text());
-        const html = await fetch('/interfaces/html.idl').then(r => r.text());
-        const dom = await fetch('/interfaces/dom.idl').then(r => r.text());
-        var idl_array = new IdlArray();
-        idl_array.add_idls(idls);
-        idl_array.add_dependency_idls(html);
-        idl_array.add_dependency_idls(dom);
-        idl_array.test();
-      }, 'Test encrypted-media IDL');
+      idl_test(
+        ['encrypted-media'],
+        ['html', 'dom'],
+        idl_array => {
+          self.audio = document.createElement('audio');
+          self.video = document.createElement('video');
+          idl_array.add_objects({
+            HTMLAudioElement: ['audio'],
+            HTMLVideoElement: ['video'],
+            Navigator: ['navigator'],
+          });
+        }
+      );
     </script>
   </body>
 </html>
diff --git a/third_party/blink/web_tests/external/wpt/event-timing/bufferbeforeonload.html b/third_party/blink/web_tests/external/wpt/event-timing/bufferbeforeonload.html
deleted file mode 100644
index 4b003a9..0000000
--- a/third_party/blink/web_tests/external/wpt/event-timing/bufferbeforeonload.html
+++ /dev/null
@@ -1,99 +0,0 @@
-<!DOCTYPE html>
-<html>
-<meta charset=utf-8 />
-<title>Event Timing: buffer long-latency events before onload</title>
-<meta name="timeout" content="long">
-<button id='button' onmousedown='clickDelay()'>Generate a 'click' event</button>
-<script src=/resources/testharness.js></script>
-<script src=/resources/testharnessreport.js></script>
-<script src=/resources/testdriver.js></script>
-<script src=/resources/testdriver-vendor.js></script>
-
-<script src=resources/event-timing-test-utils.js></script>
-<img src=resources/slow-image.py>
-
-<script>
-  let clickTimeMin;
-  let processingStartMin;
-  let onloadStart;
-  let firstClickStart = 0;
-  let firstClickEnd = 0;
-  function clickDelay() {
-    const onclickStart = performance.now();
-    if (firstClickStart === 0)
-      firstClickStart = onclickStart;
-    while(performance.now() < onclickStart + 60) {}
-    if (firstClickEnd === 0)
-      firstClickEnd = performance.now();
-  }
-
-  function validateEntries(entries) {
-    const entriesBeforeOnload = entries.filter(
-        e => e.startTime < onloadStart);
-    assert_equals(entriesBeforeOnload.length, 1,
-        "Long latency events before onload should be buffered.");
-    const entry = entriesBeforeOnload[0];
-    verifyClickEvent(entry, true);
-
-    assert_greater_than_equal(entry.startTime, clickTimeMin,
-        "The entry's start time should be later than clickTimeMin.");
-    assert_greater_than_equal(entry.processingStart, processingStartMin,
-        "The entry should be processed later than processingStartMin.");
-    assert_less_than_equal(entry.processingStart, firstClickStart,
-        "The processingStart must be before firstClickStart.")
-    assert_greater_than_equal(entry.processingEnd, firstClickEnd,
-        "The processingEnd must be after firstClickEnd.");
-
-    const entriesAfterOnload = entries.filter(
-        e => e.startTime >= onloadStart);
-    assert_equals(entriesAfterOnload.length, 1,
-        "Events after onload should still be buffered.");
-  }
-
-  /* Timeline:
-     Begin Busy Loop
-     Click 1 arrives
-     End Busy Loop
-     (Dispatch and Process Click 1 - buffered)
-     Onload Event Fires
-     Begin Busy Loop
-     Click 2 arrives
-     End Busy Loop
-     (Dispatch and Process Click 2 - not buffered)
-  */
-  async_test(function(t) {
-    if (!window.PerformanceEventTiming)
-      assert_unreached("PerformanceEventTiming is not supported");
-
-    clickTimeMin = performance.now();
-    clickAndBlockMain('button');
-    // Event handlers will be dispatched asynchronously, so this will be called
-    // before processing begins.
-    processingStartMin = performance.now();
-    const bufferedEntries = [];
-    on_event(window, 'load', e => {
-      onloadStart = performance.now();
-      // Register the observer after the page has been loaded
-      const observer = new PerformanceObserver(function (entryList, observer) {
-        entryList.getEntries().forEach(function(entry) {
-          assert_equals(entry.entryType, "event");
-          if (entry.name === 'mousedown') {
-            bufferedEntries.push(entry);
-          }
-          if (bufferedEntries.length == 2) {
-            validateEntries(bufferedEntries)
-            observer.disconnect();
-            t.done();
-          }
-        });
-      })
-      observer.observe({
-        type: "event",
-        buffered: true
-      });
-      clickAndBlockMain('button');
-    });
-  }, "Event Timing: click, onload.");
-
-</script>
-</html>
diff --git a/third_party/blink/web_tests/external/wpt/event-timing/click-timing.html b/third_party/blink/web_tests/external/wpt/event-timing/click-timing.html
new file mode 100644
index 0000000..afe53bfc
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/event-timing/click-timing.html
@@ -0,0 +1,64 @@
+<!DOCTYPE html>
+<html>
+<meta charset=utf-8 />
+<title>Event Timing: compare timing of two long clicks
+</title>
+<button id='button'>Generate a 'click' event</button>
+<script src=/resources/testharness.js></script>
+<script src=/resources/testharnessreport.js></script>
+<script src=/resources/testdriver.js></script>
+<script src=/resources/testdriver-vendor.js></script>
+<script src=resources/event-timing-test-utils.js></script>
+<script>
+  /* Timeline:
+     Observer starts
+     Long click 1
+     Long click 2
+     Once two clicks have been received by observer, compare the timestamps.
+  */
+  let timeBeforeFirstClick;
+  let timeAfterFirstClick;
+  let timeAfterSecondClick;
+  let observedEntries = [];
+  async_test(function(t) {
+    if (!window.PerformanceEventTiming)
+      assert_unreached("PerformanceEventTiming is not supported");
+
+    new PerformanceObserver(t.step_func(entryList => {
+      observedEntries = observedEntries.concat(entryList.getEntries().filter(
+        entry => entry.name === 'mousedown'));
+      if (observedEntries.length < 2)
+        return;
+
+      assert_not_equals(timeBeforeFirstClick, undefined);
+      assert_not_equals(timeAfterFirstClick, undefined);
+      assert_not_equals(timeAfterSecondClick, undefined);
+      // First click.
+      verifyClickEvent(observedEntries[0]);
+      assert_between_exclusive(observedEntries[0].processingStart,
+          timeBeforeFirstClick,
+          timeAfterFirstClick,
+          "First click's processingStart");
+      assert_greater_than(timeAfterFirstClick, observedEntries[0].startTime,
+          "timeAfterFirstClick should be later than first click's start time.");
+
+      // Second click.
+      verifyClickEvent(observedEntries[1]);
+      assert_between_exclusive(observedEntries[1].processingStart,
+          timeAfterFirstClick,
+          timeAfterSecondClick,
+          "Second click's processingStart");
+      assert_greater_than(timeAfterSecondClick, observedEntries[1].startTime,
+          "timeAfterSecondClick should be later than second click's start time.");
+      t.done();
+    })).observe({type: 'event'});
+    timeBeforeFirstClick = performance.now();
+    clickAndBlockMain('button').then( () => {
+      timeAfterFirstClick = performance.now();
+      clickAndBlockMain('button').then(() => {
+        timeAfterSecondClick = performance.now();
+      })
+    });
+  }, "Event Timing: compare click timings.");
+</script>
+</html>
diff --git a/third_party/blink/web_tests/external/wpt/event-timing/observethenonload.html b/third_party/blink/web_tests/external/wpt/event-timing/observethenonload.html
deleted file mode 100644
index 8295aaf..0000000
--- a/third_party/blink/web_tests/external/wpt/event-timing/observethenonload.html
+++ /dev/null
@@ -1,97 +0,0 @@
-<!DOCTYPE html>
-<html>
-<meta charset=utf-8 />
-<title>Event Timing: Performance observers can observe long-latency events
-</title>
-<meta name="timeout" content="long">
-<button id='button'>Generate a 'click' event</button>
-<script src=/resources/testharness.js></script>
-<script src=/resources/testharnessreport.js></script>
-<script src=/resources/testdriver.js></script>
-<script src=/resources/testdriver-vendor.js></script>
-
-<script src=resources/event-timing-test-utils.js></script>
-<img src=resources/slow-image.py>
-
-<script>
-  let timeBeforeFirstClick;
-  let timeAfterFirstClick;
-  let timeAfterSecondClick;
-  let onloadStart;
-  let observedEntries = [];
-
-  function verifyObserverEntries(observedEntries) {
-    const entriesAfterFirstClick = observedEntries.filter(
-        e => e.startTime > timeAfterFirstClick);
-    assert_equals(entriesAfterFirstClick.length, 1,
-        'There should be one event after timeAfterFirstClick.');
-    const entry1 = entriesAfterFirstClick[0];
-    verifyClickEvent(entry1);
-    assert_greater_than(entry1.processingStart, timeAfterFirstClick,
-        "entry1's processing start should be after timeAfterFirstClick");
-    assert_less_than(entry1.processingStart, timeAfterSecondClick,
-        "entry1's processing start should be before timeAfterSecondClick.");
-    assert_greater_than(entry1.startTime, onloadStart,
-        "entry1's start time should be later than onloadStart.");
-
-    const entriesBeforeFirstClick =
-        observedEntries.filter(e => e.startTime < timeAfterFirstClick);
-    assert_equals(entriesBeforeFirstClick.length, 1,
-        'There should be one event before timeAfterFirstClick.'
-    );
-    const entry2 = entriesBeforeFirstClick[0];
-    verifyClickEvent(entry2);
-    assert_greater_than(entry2.processingStart, timeBeforeFirstClick,
-        "entry2's processing start should be after timeBeforeFirstClick");
-    assert_less_than(entry2.processingStart, timeAfterFirstClick,
-        "entry2's processing start should be berfore timeAfterFirstClick.");
-    assert_greater_than(timeAfterFirstClick, entry2.startTime,
-        "timeAfterFirstClick should be later than entry2's start time.");
-    // This should happen before onLoad
-    assert_greater_than(onloadStart, entry2.startTime,
-        "Onload should be later than entry's start time.");
-  }
-
-  /* Timeline:
-     Observer starts
-     Begin Busy Loop
-     Click 1 arrives
-     End Busy Loop
-     (Dispatch and Process Click 1 (buffered, observed))
-     Onload Event Fires
-     Begin Busy Loop
-     Click 2 arrives
-     End Busy Loop
-     (Dispatch and Process Click 2 (buffered, observed))
-     observer callback start
-  */
-  async_test(function(t) {
-    if (!window.PerformanceEventTiming)
-      assert_unreached("PerformanceEventTiming is not supported");
-
-    const observerPromise = new Promise((resolve, reject) => {
-      new PerformanceObserver(function(entryList) {
-        observedEntries = observedEntries.concat(entryList.getEntries().filter(
-          entry => entry.name === 'mousedown'));
-        if (observedEntries.length < 2) return;
-        resolve(observedEntries);
-      }).observe({ type: 'event' , buffered: true});
-    });
-    timeBeforeFirstClick = performance.now();
-    clickAndBlockMain('button').then( () => {
-      timeAfterFirstClick = performance.now();
-    });
-    on_event(window, 'load', function(e) {
-      onloadStart = performance.now();
-      // After onload start and before registering observer.
-      const bufferPromise = clickAndBlockMain('button').then(wait);
-      Promise.all([observerPromise, bufferPromise]).then((results) => {
-        timeAfterSecondClick = performance.now();
-        t.step(verifyObserverEntries.bind(null, results[0]));
-        t.done();
-      });
-    });
-  }, "Event Timing: click, observer, onload, click.");
-
-</script>
-</html>
diff --git a/third_party/blink/web_tests/external/wpt/event-timing/onloadthenobserve-firstInput.html b/third_party/blink/web_tests/external/wpt/event-timing/onloadthenobserve-firstInput.html
deleted file mode 100644
index 3cd80e2..0000000
--- a/third_party/blink/web_tests/external/wpt/event-timing/onloadthenobserve-firstInput.html
+++ /dev/null
@@ -1,66 +0,0 @@
-<!DOCTYPE html>
-<html>
-<meta charset=utf-8 />
-<title>Event Timing: buffer long-latency events before onload</title>
-<meta name="timeout" content="long">
-<button id='button'>Generate a 'click' event</button>
-<script src=/resources/testharness.js></script>
-<script src=/resources/testharnessreport.js></script>
-<script src=/resources/testdriver.js></script>
-<script src=/resources/testdriver-vendor.js></script>
-
-<script src=resources/event-timing-test-utils.js></script>
-
-<script>
-  /* Timeline:
-     Onload
-     PerformanceObserver is registered
-     Click 1
-     Click 2
-     PerformanceObserver should observe only one first-input entry.
-     (Dispatch and Process Click 2 - not buffered)
-  */
-  async_test(function(t) {
-    if (!window.PerformanceEventTiming)
-      assert_unreached("PerformanceEventTiming is not supported");
-
-    let numFirstInputObserved = 0;
-    let numEventsObserved = 0;
-    let observedEventEntries = [];
-
-    const event_observer_promise = new Promise((resolve, reject) => {
-      new PerformanceObserver(function(entryList) {
-        observedEventEntries = entryList.getEntries().filter(
-          entry => entry.name === 'mousedown');
-        numEventsObserved += observedEventEntries.length;
-        if (numEventsObserved >= 2) {
-          // There should be 2 event entries.
-          assert_equals(numEventsObserved, 2,
-            "There should be 2 observed event entries.");
-          resolve();
-        }
-      }).observe({ type: 'event' , buffered: true});
-    });
-
-    const first_input_observer_promise = new Promise((resolve, reject) => {
-      new PerformanceObserver(function(entryList) {
-        assert_equals(entryList.getEntries().length, 1);
-        resolve();
-      }).observe({ type: 'first-input' , buffered: true});
-    });
-
-    on_event(window, 'load', function(e) {
-      const click_promise = clickAndBlockMain('button').then(() => {
-        clickAndBlockMain('button');
-      });
-      Promise.all(
-          [event_observer_promise, first_input_observer_promise, click_promise]
-              ).then(() => {
-        t.done();
-      });
-    });
-  },
-  "Event Timing: check first-input after onload, observer, click, click."
-  );
-</script>
-</html>
diff --git a/third_party/blink/web_tests/external/wpt/event-timing/onloadthenobserve.html b/third_party/blink/web_tests/external/wpt/event-timing/onloadthenobserve.html
deleted file mode 100644
index 4365f48..0000000
--- a/third_party/blink/web_tests/external/wpt/event-timing/onloadthenobserve.html
+++ /dev/null
@@ -1,80 +0,0 @@
-<!DOCTYPE html>
-<html>
-<meta charset=utf-8 />
-<title>Event Timing: long-latency events after onload and before observer
-registration are lost
-</title>
-<meta name="timeout" content="long">
-<button id='button'>Generate a 'click' event</button>
-<script src=/resources/testharness.js></script>
-<script src=/resources/testharnessreport.js></script>
-<script src=/resources/testdriver.js></script>
-<script src=/resources/testdriver-vendor.js></script>
-
-<script src=resources/event-timing-test-utils.js></script>
-<script>
-  let callbackTime;
-  let observerStart;
-  let processingStartMin;
-
-  function verifyObserverEntries(observedEntries) {
-    // Verify observer entries.  Should not include first click since we didn't
-    // buffered to true.
-    assert_equals(observedEntries.length, 1, "Long latency task after observer start should be observed.");
-    const entry = observedEntries[0];
-    verifyClickEvent(entry);
-    assert_greater_than(entry.processingStart, processingStartMin,
-        "The entry's processing start should be later than processingStartMin.");
-    assert_greater_than(callbackTime, entry.processingStart,
-        "The callback time should be later than the entry's processing start.");
-    assert_greater_than(entry.startTime, observerStart,
-        "The entry's start time should be later than observer start.");
-    assert_greater_than(callbackTime, entry.startTime,
-        "The callback time should be later than entry's start time.");
-  }
-
-  function startObserver(t) {
-    new PerformanceObserver(t.step_func_done((entryList, obs) => {
-        callbackTime = performance.now();
-        const observedEntries = entryList.getEntries().filter(
-            entry => entry.name === 'mousedown');
-        verifyObserverEntries(observedEntries);
-      })).observe({ type: 'event'});
-    observerStart = performance.now();
-  }
-
-  /* Timeline:
-     Onload Event fires
-     Begin Busy Loop
-     Click 1 arrives
-     End Busy Loop
-     (Dispatch and Process Click 1 (not buffered, not observed))
-     Observer start
-     Begin Busy Loop
-     Click 2 arrives
-     End Busy Loop
-     (Dispatch and Process Click 2 (not buffered, observed))
-  */
-  async_test(function(t) {
-    if (!window.PerformanceEventTiming)
-      assert_unreached("PerformanceEventTiming is not supported");
-
-    // Use a dummy observer to know when the first click has been dispatched.
-    const observerPromise = new Promise((resolve, reject) => {
-      new PerformanceObserver((entryList, observer) => {
-        resolve();
-        observer.disconnect();
-      }).observe({ entryTypes: ['event'] });
-    });
-    on_event(window, 'load', () => {
-      const clickPromise = clickAndBlockMain('button');
-      Promise.all([observerPromise, clickPromise]).then(() => {
-        startObserver(t);
-        clickAndBlockMain('button');
-        processingStartMin = performance.now();
-      });
-    });
-  },"Event Timing: onload, click, observer, click.");
-
-</script>
-</html>
diff --git a/third_party/blink/web_tests/external/wpt/geolocation-API/idlharness.window.js b/third_party/blink/web_tests/external/wpt/geolocation-API/idlharness.window.js
index f8c92c1..fe4ac88 100644
--- a/third_party/blink/web_tests/external/wpt/geolocation-API/idlharness.window.js
+++ b/third_party/blink/web_tests/external/wpt/geolocation-API/idlharness.window.js
@@ -3,16 +3,15 @@
 
 // https://www.w3.org/TR/geolocation-API/
 
-promise_test(async () => {
-  const idl = await fetch('/interfaces/geolocation-API.idl').then(r => r.text());
-  const html = await fetch('/interfaces/html.idl').then(r => r.text());
-
-  const idl_array = new IdlArray();
-  idl_array.add_idls(idl);
-  idl_array.add_dependency_idls(html);
-  idl_array.add_objects({
-    Navigator: ["navigator"],
-    Geolocation: ["navigator.geolocation"]
-  });
-  idl_array.test();
-}, 'geolocation-API interfaces');
+idl_test(
+  ['geolocation-API'],
+  ['html'],
+  idl_array => {
+    self.audio = document.createElement('audio');
+    self.video = document.createElement('video');
+    idl_array.add_objects({
+      Navigator: ['navigator'],
+      Geolocation: ['navigator.geolocation'],
+    });
+  }
+);
diff --git a/third_party/blink/web_tests/external/wpt/mediacapture-depth/idlharness.html b/third_party/blink/web_tests/external/wpt/mediacapture-depth/idlharness.html
index 1afc6e5..963229aa 100644
--- a/third_party/blink/web_tests/external/wpt/mediacapture-depth/idlharness.html
+++ b/third_party/blink/web_tests/external/wpt/mediacapture-depth/idlharness.html
@@ -4,7 +4,7 @@
 <head>
   <meta charset=utf-8>
   <title>Media Capture Depth Stream Extensions IDL test</title>
-  <link rel="help" href="See https://w3c.github.io/mediacapture-depth/">
+  <link rel="help" href="https://w3c.github.io/mediacapture-depth/">
   <script src="/resources/testharness.js"></script>
   <script src="/resources/testharnessreport.js"></script>
   <script src="/resources/WebIDLParser.js"></script>
@@ -15,15 +15,13 @@
   <script>
     'use strict';
 
-    promise_test(async () => {
-      const idl = await fetch('/interfaces/mediacapture-depth.idl').then(r => r.text());
-      const main = await fetch('/interfaces/mediacapture-streams.idl').then(r => r.text());
-
-      var idl_array = new IdlArray();
-      idl_array.add_idls(idl);
-      idl_array.add_dependency_idls(main);
-      idl_array.test();
-    }, 'mediacapture-depth interfaces');
+    idl_test(
+      ['mediacapture-depth'],
+      ['mediacapture-streams'],
+      idl_array => {
+        // No objects, spec defines dictionaries only.
+      }
+    );
   </script>
   <div id="log"></div>
 </body>
diff --git a/third_party/blink/web_tests/external/wpt/mediacapture-streams/idlharness.https.window.js b/third_party/blink/web_tests/external/wpt/mediacapture-streams/idlharness.https.window.js
index 5b255fca..594e112 100644
--- a/third_party/blink/web_tests/external/wpt/mediacapture-streams/idlharness.https.window.js
+++ b/third_party/blink/web_tests/external/wpt/mediacapture-streams/idlharness.https.window.js
@@ -5,50 +5,44 @@
 
 // https://w3c.github.io/mediacapture-main/
 
-
-promise_test(async () => {
-  const srcs = ['mediacapture-streams','dom','html'];
-  const [idl, dom, html] = await Promise.all(
-    srcs.map(i => fetch(`/interfaces/${i}.idl`).then(r => r.text())));
-
-  const idl_array = new IdlArray();
-  idl_array.add_idls(idl);
-  idl_array.add_dependency_idls(html);
-  idl_array.add_dependency_idls(dom);
-
-  const devices = [];
-  // Errors will be surfaced in idlharness.js's test_object below.
-  try {
-    const list = await navigator.mediaDevices.enumerateDevices();
-    for (const item of list) {
-      switch (item.kind) {
-      case 'audioinput':
-      case 'videoinput':
-      case 'audiooutput':
-        self[item.kind] = item;
-        devices.push(item.kind);
-      default:
-        assert_unreached(
-          'media.kind should be one of "audioinput", "videoinput", or "audiooutput".');
+idl_test(
+  ['mediacapture-streams'],
+  ['dom', 'html'],
+  async idl_array => {
+    const inputDevices = [];
+    const outputDevices = [];
+    try {
+      const list = await navigator.mediaDevices.enumerateDevices();
+      for (const device of list) {
+        if (device.kind in self) {
+          continue;
+        }
+        assert_in_array(device.kind, ['audioinput', 'videoinput', 'audiooutput']);
+        self[device.kind] = device;
+        if (device.kind.endsWith('input')) {
+          inputDevices.push(device.kind);
+        } else {
+          outputDevices.push(device.kind);
+        }
       }
-    }
-  } catch (e) {}
+    } catch (e) {}
 
-  try {
-    self.stream = await navigator.mediaDevices.getUserMedia({audio: true});
-    self.track = stream.getTracks()[0];
-    self.trackEvent = new MediaStreamTrackEvent("type", {
-      track: track,
+    try {
+      self.stream = await navigator.mediaDevices.getUserMedia({audio: true});
+      self.track = stream.getTracks()[0];
+      self.trackEvent = new MediaStreamTrackEvent("type", {
+        track: track,
+      });
+    } catch (e) {}
+
+    idl_array.add_objects({
+      InputDeviceInfo: inputDevices,
+      MediaStream: ['stream', 'new MediaStream()'],
+      Navigator: ['navigator'],
+      MediaDevices: ['navigator.mediaDevices'],
+      MediaDeviceInfo: outputDevices,
+      MediaStreamTrack: ['track'],
+      MediaStreamTrackEvent: ['trackEvent'],
     });
-  } catch (e) { throw e}
-
-  idl_array.add_objects({
-    InputDeviceInfo: devices,
-    MediaStream: ['stream', 'new MediaStream()'],
-    Navigator: ['navigator'],
-    MediaDevices: ['navigator.mediaDevices'],
-    MediaStreamTrack: ['track'],
-    MediaStreamTrackEvent: ['trackEvent'],
-  });
-  idl_array.test();
-}, 'mediacapture-streams interfaces.');
+  }
+);
diff --git a/third_party/blink/web_tests/external/wpt/orientation-event/idlharness.https.window.js b/third_party/blink/web_tests/external/wpt/orientation-event/idlharness.https.window.js
index ed8309d6..55cfed92 100644
--- a/third_party/blink/web_tests/external/wpt/orientation-event/idlharness.https.window.js
+++ b/third_party/blink/web_tests/external/wpt/orientation-event/idlharness.https.window.js
@@ -5,19 +5,14 @@
 
 'use strict';
 
-promise_test(async () => {
-  const idl = await fetch('/interfaces/orientation-event.idl').then(r => r.text());
-  const dom = await fetch('/interfaces/dom.idl').then(r => r.text());
-  const html = await fetch('/interfaces/html.idl').then(r => r.text());
-
-  var idl_array = new IdlArray();
-  idl_array.add_idls(idl);
-  idl_array.add_dependency_idls(html);
-  idl_array.add_dependency_idls(dom);
-  idl_array.add_objects({
-    Window: ['window'],
-    DeviceOrientationEvent: ['new DeviceOrientationEvent("foo")'],
-    DeviceMotionEvent: ['new DeviceMotionEvent("foo")'],
-  });
-  idl_array.test();
-}, 'orientation-event interfaces');
+idl_test(
+  ['orientation-event'],
+  ['html', 'dom'],
+  idl_array => {
+    idl_array.add_objects({
+      Window: ['window'],
+      DeviceOrientationEvent: ['new DeviceOrientationEvent("foo")'],
+      DeviceMotionEvent: ['new DeviceMotionEvent("foo")'],
+    });
+  }
+);
diff --git a/third_party/blink/web_tests/external/wpt/permissions/interfaces.any.js b/third_party/blink/web_tests/external/wpt/permissions/interfaces.any.js
index b9345388..ff0a969b 100644
--- a/third_party/blink/web_tests/external/wpt/permissions/interfaces.any.js
+++ b/third_party/blink/web_tests/external/wpt/permissions/interfaces.any.js
@@ -1,41 +1,27 @@
 // META: script=/resources/WebIDLParser.js
 // META: script=/resources/idlharness.js
 
-"use strict";
-
-if (self.importScripts) {
-  importScripts("/resources/testharness.js");
-  importScripts("/resources/WebIDLParser.js", "/resources/idlharness.js");
-}
-
 // https://w3c.github.io/permissions/#idl-index
 
-promise_test(async () => {
-  const idl = await fetch("/interfaces/permissions.idl").then(r => r.text());
-  const dom = await fetch("/interfaces/dom.idl").then(r => r.text());
-  const html = await fetch("/interfaces/html.idl").then(r => r.text());
+"use strict";
 
-  const idl_array = new IdlArray();
-  idl_array.add_idls(idl);
-  idl_array.add_dependency_idls(dom);
-  idl_array.add_dependency_idls(html);
+idl_test(
+  ['permissions'],
+  ['html', 'dom'],
+  async idl_array => {
+    try {
+      self.permissionStatus = await navigator.permissions.query({ name: "geolocation" });
+    } catch (e) {}
 
-  try {
-    self.permissionStatus = await navigator.permissions.query({ name: "geolocation" });
-    self.permissionStatus = await navigator.permissions.query({ name: "background-fetch" });
-  } catch (e) {
-    // Will be surfaced in idlharness.js's test_object below.
+    if (self.GLOBAL.isWorker()) {
+      idl_array.add_objects({ WorkerNavigator: ['navigator'] });
+    } else {
+      idl_array.add_objects({ Navigator: ['navigator'] });
+    }
+
+    idl_array.add_objects({
+      Permissions: ['navigator.permissions'],
+      PermissionStatus: ['permissionStatus']
+    });
   }
-
-  if (self.GLOBAL.isWorker()) {
-    idl_array.add_objects({ WorkerNavigator: ['navigator'] });
-  } else {
-    idl_array.add_objects({ Navigator: ['navigator'] });
-  }
-
-  idl_array.add_objects({
-    Permissions: ['navigator.permissions'],
-    PermissionStatus: ['permissionStatus']
-  });
-  idl_array.test();
-}, "Test IDL implementation of Permissions API");
+);
diff --git a/third_party/blink/web_tests/external/wpt/requestidlecallback/idlharness.window.js b/third_party/blink/web_tests/external/wpt/requestidlecallback/idlharness.window.js
index 2c9f6593..69cd5a4 100644
--- a/third_party/blink/web_tests/external/wpt/requestidlecallback/idlharness.window.js
+++ b/third_party/blink/web_tests/external/wpt/requestidlecallback/idlharness.window.js
@@ -1,30 +1,24 @@
 // META: script=/resources/WebIDLParser.js
 // META: script=/resources/idlharness.js
 
-async_test(function() {
-  const srcs = ['requestidlecallback', 'html', 'dom'];
-  Promise.all(srcs.map(i => fetch(`/interfaces/${i}.idl`).then(r => r.text())))
-    .then(([idl, html, dom]) => {
-      var idl_array = new IdlArray();
-      idl_array.add_idls(idl);
-      idl_array.add_dependency_idls(html);
-      idl_array.add_dependency_idls(dom);
-      idl_array.add_objects({Window: ['window']});
+// https://w3c.github.io/requestidlecallback/
 
-      let deadline;
-      const execIDLTest = this.step_func_done(function() {
-        idl_array.add_objects({IdleDeadline: [deadline]});
-        idl_array.test();
-      });
+'use strict';
 
-      if (!window.requestIdleCallback) {
-        execIDLTest();
-      } else {
-        const callback = this.step_func(d => {
-          deadline = d;
-          execIDLTest();
-        });
-        requestIdleCallback(callback, { timeout: 100 });
-      }
+idl_test(
+  ['requestidlecallback'],
+  ['html', 'dom'],
+  async idl_array => {
+    idl_array.add_objects({
+      IdleDeadline: ['deadline'],
+      Window: ['window'],
     });
-}, 'IdleDeadline object setup');
+
+    await new Promise(resolve => {
+      requestIdleCallback(d => {
+        self.deadline = d;
+        resolve();
+      }, { timeout: 100 });
+    });
+  }
+);
diff --git a/third_party/blink/web_tests/external/wpt/server-timing/idlharness.https.any.js b/third_party/blink/web_tests/external/wpt/server-timing/idlharness.https.any.js
index 9c101e0f..ded320f0 100644
--- a/third_party/blink/web_tests/external/wpt/server-timing/idlharness.https.any.js
+++ b/third_party/blink/web_tests/external/wpt/server-timing/idlharness.https.any.js
@@ -5,17 +5,12 @@
 
 // https://w3c.github.io/server-timing/
 
-promise_test(async () => {
-  const idl = await fetch('/interfaces/server-timing.idl').then(r => r.text());
-  const res = await fetch('/interfaces/resource-timing.idl').then(r => r.text());
-  const perf = await fetch('/interfaces/performance-timeline.idl').then(r => r.text());
-
-  const idl_array = new IdlArray();
-  idl_array.add_idls(idl);
-  idl_array.add_dependency_idls(res);
-  idl_array.add_dependency_idls(perf);
-  idl_array.add_objects({
-    Performance: ['performance'],
-  });
-  idl_array.test();
-}, 'Test server-timing IDL implementation');
+idl_test(
+  ['server-timing'],
+  ['resource-timing', 'performance-timeline'],
+  idl_array => {
+    idl_array.add_objects({
+      Performance: ['performance'],
+    });
+  }
+);
diff --git a/third_party/blink/web_tests/external/wpt/webgpu/framework/version.js b/third_party/blink/web_tests/external/wpt/webgpu/framework/version.js
index b9ec1b4..9be02560 100644
--- a/third_party/blink/web_tests/external/wpt/webgpu/framework/version.js
+++ b/third_party/blink/web_tests/external/wpt/webgpu/framework/version.js
@@ -1,3 +1,3 @@
 // AUTO-GENERATED - DO NOT EDIT. See tools/gen_version.
 
-export const version = '84ef21bec576c9272e64e08727dbdf75a2b0e9d8';
+export const version = 'f690ac56a3291801e817433f43877132bb531d5f';
diff --git a/third_party/blink/web_tests/external/wpt/webgpu/suites/cts/command_buffer/render/basic.spec.js b/third_party/blink/web_tests/external/wpt/webgpu/suites/cts/command_buffer/render/basic.spec.js
index bb201db..83bb026 100644
--- a/third_party/blink/web_tests/external/wpt/webgpu/suites/cts/command_buffer/render/basic.spec.js
+++ b/third_party/blink/web_tests/external/wpt/webgpu/suites/cts/command_buffer/render/basic.spec.js
@@ -22,7 +22,7 @@
     },
     usage: GPUTextureUsage.COPY_SRC | GPUTextureUsage.OUTPUT_ATTACHMENT
   });
-  const colorAttachmentView = colorAttachment.createDefaultView();
+  const colorAttachmentView = colorAttachment.createView();
   const encoder = t.device.createCommandEncoder({});
   const pass = encoder.beginRenderPass({
     colorAttachments: [{
diff --git a/third_party/blink/web_tests/external/wpt/webgpu/suites/cts/command_buffer/render/rendering.spec.js b/third_party/blink/web_tests/external/wpt/webgpu/suites/cts/command_buffer/render/rendering.spec.js
index 762285d..c8a7d7f 100644
--- a/third_party/blink/web_tests/external/wpt/webgpu/suites/cts/command_buffer/render/rendering.spec.js
+++ b/third_party/blink/web_tests/external/wpt/webgpu/suites/cts/command_buffer/render/rendering.spec.js
@@ -20,7 +20,7 @@
     },
     usage: GPUTextureUsage.COPY_SRC | GPUTextureUsage.OUTPUT_ATTACHMENT
   });
-  const colorAttachmentView = colorAttachment.createDefaultView();
+  const colorAttachmentView = colorAttachment.createView();
   const vertexModule = t.device.createShaderModule({
     code:
     /* GLSL(
diff --git a/third_party/blink/web_tests/http/tests/devtools/application-panel/resources-panel-idb-clear-for-origin-expected.txt b/third_party/blink/web_tests/http/tests/devtools/application-panel/resources-panel-idb-clear-for-origin-expected.txt
new file mode 100644
index 0000000..c780b570
--- /dev/null
+++ b/third_party/blink/web_tests/http/tests/devtools/application-panel/resources-panel-idb-clear-for-origin-expected.txt
@@ -0,0 +1,20 @@
+Validate IndexeddbModel clearForOrigin
+
+Create IndexedDB in main frame
+Database Length: 1
+Database Entries:
+  Security Origin:http://127.0.0.1:8000, Database Name:Database-main-frame
+**done**
+
+Removing bogus security origin...
+Database Length: 1
+Database Entries:
+  Security Origin:http://127.0.0.1:8000, Database Name:Database-main-frame
+**done**
+
+Removing http://127.0.0.1:8000 security origin...
+Database Length: 0
+Database Entries:
+**done**
+
+
diff --git a/third_party/blink/web_tests/http/tests/devtools/application-panel/resources-panel-idb-clear-for-origin.js b/third_party/blink/web_tests/http/tests/devtools/application-panel/resources-panel-idb-clear-for-origin.js
new file mode 100644
index 0000000..6f80e6c
--- /dev/null
+++ b/third_party/blink/web_tests/http/tests/devtools/application-panel/resources-panel-idb-clear-for-origin.js
@@ -0,0 +1,51 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+(async function() {
+  TestRunner.addResult(`Validate IndexeddbModel clearForOrigin\n`);
+  await TestRunner.loadModule('application_test_runner');
+  // Note: every test that uses a storage API must manually clean-up state from previous tests.
+  await ApplicationTestRunner.resetState();
+
+  await TestRunner.loadModule('console_test_runner');
+  await TestRunner.showPanel('resources');
+
+  const model = TestRunner.mainTarget.model(Resources.IndexedDBModel);
+  const view = UI.panels.resources;
+
+  function createIndexedDBInMainFrame(callback) {
+    var mainFrameId = TestRunner.resourceTreeModel.mainFrame.id;
+    ApplicationTestRunner.createDatabase(mainFrameId, 'Database-main-frame', () => {
+      var event = model.addEventListener(Resources.IndexedDBModel.Events.DatabaseAdded, () => {
+        Common.EventTarget.removeEventListeners([event]);
+        callback();
+      });
+      model.refreshDatabaseNames();
+    });
+  }
+
+  function dumpDatabases() {
+    const databases = model.databases();
+    TestRunner.addResult('Database Length: ' + databases.length);
+    TestRunner.addResult('Database Entries:');
+    for (let j = 0; j < databases.length; ++j)
+      TestRunner.addResult(`  Security Origin:${databases[j].securityOrigin}, Database Name:${databases[j].name}`);
+    TestRunner.addResult('**done**\n');
+  }
+
+  TestRunner.addResult('Create IndexedDB in main frame');
+  await new Promise(createIndexedDBInMainFrame);
+  await TestRunner.addSnifferPromise(UI.panels.resources._sidebar.indexedDBListTreeElement, '_indexedDBLoadedForTest');
+  dumpDatabases();
+
+  TestRunner.addResult('Removing bogus security origin...');
+  model.clearForOrigin('http://bogus-security-origin.com');
+  dumpDatabases();
+
+  TestRunner.addResult('Removing http://127.0.0.1:8000 security origin...');
+  model.clearForOrigin('http://127.0.0.1:8000');
+  dumpDatabases();
+
+  TestRunner.completeTest();
+})();
diff --git a/third_party/blink/web_tests/media/picture-in-picture/picture-in-picture-service-error.html b/third_party/blink/web_tests/media/picture-in-picture/picture-in-picture-service-error.html
index 2a02e74..9f4247e 100644
--- a/third_party/blink/web_tests/media/picture-in-picture/picture-in-picture-service-error.html
+++ b/third_party/blink/web_tests/media/picture-in-picture/picture-in-picture-service-error.html
@@ -22,7 +22,7 @@
   }
 
   async startSession(playerId, surfaceId, naturalSize, showPlayPauseButton,
-        showMuteButton, observer, callback) {
+        observer, callback) {
     return { session: null, size: new gfx.mojom.Size() };
   }
 };
diff --git a/third_party/closure_compiler/externs/settings_private.js b/third_party/closure_compiler/externs/settings_private.js
index fc5c38da..e2870f25 100644
--- a/third_party/closure_compiler/externs/settings_private.js
+++ b/third_party/closure_compiler/externs/settings_private.js
@@ -47,6 +47,7 @@
 chrome.settingsPrivate.Enforcement = {
   ENFORCED: 'ENFORCED',
   RECOMMENDED: 'RECOMMENDED',
+  PARENT_SUPERVISED: 'PARENT_SUPERVISED',
 };
 
 /**
diff --git a/third_party/libaddressinput/OWNERS b/third_party/libaddressinput/OWNERS
index b483a338..75aa61f 100644
--- a/third_party/libaddressinput/OWNERS
+++ b/third_party/libaddressinput/OWNERS
@@ -1,4 +1,7 @@
-rouslan@chromium.org
+battre@chromium.org
+dvadym@chromium.org
+kolos@chromium.org
 mathp@chromium.org
+rouslan@chromium.org
 
 # COMPONENT: UI>Browser>Autofill
diff --git a/third_party/libipp/BUILD.gn b/third_party/libipp/BUILD.gn
new file mode 100644
index 0000000..3653f9c
--- /dev/null
+++ b/third_party/libipp/BUILD.gn
@@ -0,0 +1,29 @@
+# Copyright 2019 The Chromium OS Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+static_library("libipp") {
+  include_dirs = [ "." ]
+  sources = [
+    "libipp/ipp.h",
+    "libipp/ipp_attribute.cc",
+    "libipp/ipp_attribute.h",
+    "libipp/ipp_base.cc",
+    "libipp/ipp_base.h",
+    "libipp/ipp_collections.cc",
+    "libipp/ipp_collections.h",
+    "libipp/ipp_encoding.h",
+    "libipp/ipp_enums.cc",
+    "libipp/ipp_enums.h",
+    "libipp/ipp_export.h",
+    "libipp/ipp_frame.h",
+    "libipp/ipp_frame_builder.cc",
+    "libipp/ipp_frame_builder.h",
+    "libipp/ipp_operations.cc",
+    "libipp/ipp_operations.h",
+    "libipp/ipp_package.cc",
+    "libipp/ipp_package.h",
+    "libipp/ipp_parser.cc",
+    "libipp/ipp_parser.h",
+  ]
+}
diff --git a/third_party/libipp/LICENSE b/third_party/libipp/LICENSE
new file mode 100644
index 0000000..5448446
--- /dev/null
+++ b/third_party/libipp/LICENSE
@@ -0,0 +1,27 @@
+// Copyright 2019 The Chromium OS Authors. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//    * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//    * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//    * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/third_party/libipp/OWNERS b/third_party/libipp/OWNERS
new file mode 100644
index 0000000..4529fb66
--- /dev/null
+++ b/third_party/libipp/OWNERS
@@ -0,0 +1,2 @@
+pawliczek@chromium.org
+skau@chromium.org
diff --git a/third_party/libipp/README.chromium b/third_party/libipp/README.chromium
new file mode 100644
index 0000000..f68030f8
--- /dev/null
+++ b/third_party/libipp/README.chromium
@@ -0,0 +1,17 @@
+Name: libipp
+URL: https://chromium.googlesource.com/chromiumos/platform2/libipp
+Version: 6c45a4f3a05cb5dd700414fe4d94cf685159d3ce
+License: BSD
+License File: LICENSE
+Security Critical: yes
+
+Description:
+ChromeOS library for bulding/parsing IPP frames.
+
+Modifications:
+- None
+
+To import a new snapshot of libipp:
+- Checkout the latest version: git checkout 6c45a4f3a05cb5dd700414fe4d94cf685159d3ce
+- Change the chromium/src/DEPS entry to the newly checked out commit.
+- Update this README to reflect the new version number.
diff --git a/third_party/libphonenumber/OWNERS b/third_party/libphonenumber/OWNERS
index ce847508..75aa61f 100644
--- a/third_party/libphonenumber/OWNERS
+++ b/third_party/libphonenumber/OWNERS
@@ -1,3 +1,6 @@
+battre@chromium.org
+dvadym@chromium.org
+kolos@chromium.org
 mathp@chromium.org
 rouslan@chromium.org
 
diff --git a/tools/flags/generate_expired_list.py b/tools/flags/generate_expired_list.py
new file mode 100755
index 0000000..da5b65c
--- /dev/null
+++ b/tools/flags/generate_expired_list.py
@@ -0,0 +1,125 @@
+#!/usr/bin/env python
+# Copyright 2019 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+
+"""Generates the list of expired flags as a C++ source file.
+
+This program generates a data structure representing the set of flags that
+expired before or as of the current Chromium milestone. Specifically, it reads
+the flag metadata JSON file and emits a structure mapping flag internal names to
+expiration milestones. This data structure is then linked into the built
+Chromium, to be used to decide whether to show or hide a given flag in the flags
+UI.
+
+This program can be run with no arguments to run its own unit tests.
+"""
+
+
+import list_flags
+import os
+import sys
+
+
+ROOT_PATH = os.path.join(os.path.dirname(__file__), '..', '..')
+
+
+def get_chromium_version():
+  """Parses the Chromium version out of //chrome/VERSION."""
+  with open(os.path.join(ROOT_PATH, 'chrome', 'VERSION')) as f:
+    for line in f.readlines():
+      key, value = line.strip().split('=')
+      if key == 'MAJOR':
+        return value
+  return None
+
+
+def gen_file_header(prog_name, meta_name):
+  """Returns the header for the generated expiry list file.
+
+  The generated header contains at least:
+  * A copyright message on the first line
+  * A reference to this program (prog_name)
+  * A reference to the input metadata file
+  >>> 'The Chromium Authors' in gen_file_header('foo', 'bar')
+  True
+  >>> '/progname' in gen_file_header('/progname', '/dataname')
+  True
+  >>> '/dataname' in gen_file_header('/progname', '/dataname')
+  True
+  """
+  return """// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This is a generated file. Do not edit it! It was generated by:
+//   {prog_name}
+// and it was generated from:
+//   {meta_name}
+
+#include "chrome/browser/expired_flags_list.h"
+
+namespace flags {{
+const ExpiredFlag kExpiredFlags[] = {{
+""".format(prog_name=prog_name, meta_name=meta_name)
+
+
+def gen_file_footer():
+  return """
+  {nullptr, 0},
+};
+
+}  // namespace flags"""
+
+
+def gen_file_body(flags, mstone):
+  """Generates the body of the flag expiration list.
+
+  Flags appear in the list only if:
+  * Their expiration mstone is not -1
+  * Either the chrome version is unknown OR
+  * Their expiration mstone is <= the chrome version
+
+  >>> flags = [ { 'name': 'foo', 'expiry_milestone': 1 } ]
+  >>> flags.append({ 'name': 'bar', 'expiry_milestone': 2 })
+  >>> flags.append({ 'name': 'baz', 'expiry_milestone': -1 })
+  >>> gen_file_body(flags, 1)
+  '  {"foo", 1},'
+  >>> gen_file_body(flags, 2)
+  '  {"foo", 1},\\n  {"bar", 2},'
+  >>> gen_file_body(flags, None)
+  '  {"foo", 1},\\n  {"bar", 2},'
+  """
+  if mstone != None:
+    flags = list_flags.keep_expired_by(flags, mstone)
+  output = []
+  for f in flags:
+    if f['expiry_milestone'] != -1:
+      name, expiry = f['name'], f['expiry_milestone']
+      output.append('  {"' + name + '", ' + str(expiry) + '},')
+  return '\n'.join(output)
+
+
+def gen_expiry_file(program_name, metadata_name):
+  output = gen_file_header(program_name, metadata_name)
+  output += gen_file_body(list_flags.load_metadata(), get_chromium_version())
+  output += gen_file_footer()
+  return output
+
+
+def main():
+  import doctest
+  doctest.testmod()
+
+  if len(sys.argv) < 3:
+    print '{}: only ran tests'.format(sys.argv[0])
+    return
+
+  output = gen_expiry_file(sys.argv[0], sys.argv[1])
+  with open(sys.argv[2], 'w') as f:
+    f.write(output)
+
+
+if __name__ == '__main__':
+  main()
diff --git a/tools/mb/mb.py b/tools/mb/mb.py
index 04df1f8a..8f26bd5 100755
--- a/tools/mb/mb.py
+++ b/tools/mb/mb.py
@@ -1100,6 +1100,7 @@
       # TODO(https://crbug.com/912946): Remove this if statement.
       if (f == 'angledata/gl_cts/' or  # http://anglebug.com/3827
           (is_msan and f == 'instrumented_libraries_prebuilt/') or
+          f == 'mr_extension/' or # https://crbug.com/997947
           f == 'locales/' or
           f.startswith('nacl_test_data/') or
           f.startswith('ppapi_nacl_tests_libs/') or
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml
index 1282da44..62a8cdb 100644
--- a/tools/metrics/histograms/enums.xml
+++ b/tools/metrics/histograms/enums.xml
@@ -35200,6 +35200,7 @@
   <int value="-996673716" label="enable-web-app-frame"/>
   <int value="-994558985" label="EnableNotificationIndicator:disabled"/>
   <int value="-994088375" label="VrBrowsingExperimentalRendering:enabled"/>
+  <int value="-994044484" label="TemporaryUnexpireFlagsM76:disabled"/>
   <int value="-993476089" label="AutoScreenBrightness:disabled"/>
   <int value="-992785453" label="ExplicitLanguageAsk:disabled"/>
   <int value="-991253797"
@@ -35852,6 +35853,7 @@
   <int value="-79327236" label="ModeSpecificPowerButton:enabled"/>
   <int value="-78035185" label="custom_summary"/>
   <int value="-77872983" label="BookmarkAppsMac:disabled"/>
+  <int value="-76953963" label="CloseTabSuggestionsStale:enabled"/>
   <int value="-76631048" label="disable-offline-auto-reload-visible-only"/>
   <int value="-76445689" label="WasmCodeCache:enabled"/>
   <int value="-75418012" label="ContextualSuggestionsOptOut:disabled"/>
@@ -36649,6 +36651,7 @@
   <int value="1060319397" label="enable-data-reduction-proxy-carrier-test"/>
   <int value="1062357243" label="remember-cert-error-decisions"/>
   <int value="1064288458" label="OfflineRecentPages:enabled"/>
+  <int value="1065216170" label="CloseTabSuggestionsStale:disabled"/>
   <int value="1067618884" label="enable-experimental-input-view-features"/>
   <int value="1067990299" label="enable-ui-devtools"/>
   <int value="1069325321" label="CrostiniGpuSupport:enabled"/>
@@ -37182,6 +37185,7 @@
       label="ContextualSuggestionsIPHReverseScroll:disabled"/>
   <int value="1803465156" label="enable-zero-suggest-most-visited"/>
   <int value="1803470125" label="SyncUSSSessions:enabled"/>
+  <int value="1803914892" label="TemporaryUnexpireFlagsM76:enabled"/>
   <int value="1807374811" label="CCTModuleCache:enabled"/>
   <int value="1809940714" label="SpeculativeLaunchServiceWorker:disabled"/>
   <int value="1810258949" label="DisplayLocking:enabled"/>
diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml
index 16b978d4..c64180bd 100644
--- a/tools/metrics/histograms/histograms.xml
+++ b/tools/metrics/histograms/histograms.xml
@@ -1576,6 +1576,17 @@
   </summary>
 </histogram>
 
+<histogram name="Android.BackgroundTaskScheduler.ExactTaskCreated"
+    enum="BackgroundTaskId" expires_after="2020-01-31">
+  <owner>ioanastefan@chromium.org</owner>
+  <owner>nator@chromium.org</owner>
+  <owner>knollr@chromium.org</owner>
+  <summary>
+    Records that an exact task has been created. Recorded when the task is
+    scheduled.
+  </summary>
+</histogram>
+
 <histogram name="Android.BackgroundTaskScheduler.MigrationToProto"
     enum="BackgroundTaskId" expires_after="2019-11-30">
   <owner>ioanastefan@chromium.org</owner>
@@ -128808,21 +128819,25 @@
 </histogram>
 
 <histogram name="Signin.AndroidGetAccountIdsTime" units="ms"
-    expires_after="2020-02-16">
+    expires_after="M82">
+  <owner>alexilin@chromium.org</owner>
   <owner>bsazonov@chromium.org</owner>
   <summary>
     The time it takes to retrieve Gaia ids for all accounts from GoogleAuthUtil.
   </summary>
 </histogram>
 
-<histogram name="Signin.AndroidGetAccountsTime" units="ms">
-  <owner>nyquist@chromium.org</owner>
+<histogram name="Signin.AndroidGetAccountsTime" units="ms" expires_after="M82">
+  <owner>alexilin@chromium.org</owner>
+  <owner>bsazonov@chromium.org</owner>
   <summary>
     The time it takes to retrieve the list of accounts from the system.
   </summary>
 </histogram>
 
-<histogram name="Signin.AndroidGetAccountsTimeUiThread" units="ms">
+<histogram name="Signin.AndroidGetAccountsTimeUiThread" units="ms"
+    expires_after="M82">
+  <owner>alexilin@chromium.org</owner>
   <owner>bsazonov@chromium.org</owner>
   <summary>
     The time it takes to retrieve the list of accounts from the system on the UI
diff --git a/tools/traffic_annotation/auditor/traffic_annotation_auditor.cc b/tools/traffic_annotation/auditor/traffic_annotation_auditor.cc
index 200ee16..93b6823 100644
--- a/tools/traffic_annotation/auditor/traffic_annotation_auditor.cc
+++ b/tools/traffic_annotation/auditor/traffic_annotation_auditor.cc
@@ -197,7 +197,8 @@
 
   // Get list of files/folders to process.
   std::vector<std::string> file_paths;
-  GenerateFilesListForClangTool(path_filters, filter_files_based_on_heuristics,
+  GenerateFilesListForClangTool(backend, path_filters,
+                                filter_files_based_on_heuristics,
                                 use_compile_commands, &file_paths);
   if (file_paths.empty())
     return true;
@@ -334,27 +335,33 @@
 }
 
 void TrafficAnnotationAuditor::GenerateFilesListForClangTool(
+    ExtractorBackend backend,
     const std::vector<std::string>& path_filters,
     bool filter_files_based_on_heuristics,
     bool use_compile_commands,
     std::vector<std::string>* file_paths) {
+  TrafficAnnotationFileFilter filter;
+
   // If |use_compile_commands| is requested or
   // |filter_files_based_on_heuristics| is false, we pass all given file paths
   // to the running script and the files in the safe list will be later removed
   // from the results.
   if (!filter_files_based_on_heuristics || use_compile_commands) {
-    // If no path filter is specified, return current location. The clang tool
-    // will be run from the repository 'src' folder and hence this will point to
-    // repository root.
-    if (path_filters.empty())
+    if (backend == ExtractorBackend::PYTHON_SCRIPT) {
+      // With python_script, simply run on the whole directory.
+      filter.GetFilesFromGit(absolute_source_path_);
+      *file_paths = filter.git_files();
+    } else if (path_filters.empty()) {
+      // If no path filter is specified, return current location. The clang tool
+      // will be run from the repository 'src' folder and hence this will point
+      // to repository root.
       file_paths->push_back("./");
-    else
+    } else {
       *file_paths = path_filters;
+    }
     return;
   }
 
-  TrafficAnnotationFileFilter filter;
-
   // If no path filter is provided, get all relevant files, except the safe
   // listed ones.
   if (path_filters.empty()) {
diff --git a/tools/traffic_annotation/auditor/traffic_annotation_auditor.h b/tools/traffic_annotation/auditor/traffic_annotation_auditor.h
index 3c32a52..323f9d6 100644
--- a/tools/traffic_annotation/auditor/traffic_annotation_auditor.h
+++ b/tools/traffic_annotation/auditor/traffic_annotation_auditor.h
@@ -199,6 +199,7 @@
   // Generates files list to Run clang tool on. Please refer to RunExtractor
   // function's comment.
   void GenerateFilesListForClangTool(
+      ExtractorBackend backend,
       const std::vector<std::string>& path_filters,
       bool filter_files_based_on_heuristics,
       bool use_compile_commands,
diff --git a/tools/traffic_annotation/bin/linux64/traffic_annotation_auditor.sha1 b/tools/traffic_annotation/bin/linux64/traffic_annotation_auditor.sha1
index 74681b9..bffaadb 100644
--- a/tools/traffic_annotation/bin/linux64/traffic_annotation_auditor.sha1
+++ b/tools/traffic_annotation/bin/linux64/traffic_annotation_auditor.sha1
@@ -1 +1 @@
-62dbe9751c9d8d03810f9928e29859e5af43db8d
\ No newline at end of file
+e3a801da7edfd02cf050f233738e44a8f9e526d2
\ No newline at end of file
diff --git a/tools/traffic_annotation/bin/win32/traffic_annotation_auditor.exe.sha1 b/tools/traffic_annotation/bin/win32/traffic_annotation_auditor.exe.sha1
index bde6d84f..92f1f46 100644
--- a/tools/traffic_annotation/bin/win32/traffic_annotation_auditor.exe.sha1
+++ b/tools/traffic_annotation/bin/win32/traffic_annotation_auditor.exe.sha1
@@ -1 +1 @@
-135da9329dc7bfe8e8056ed3976a704c777d49f3
\ No newline at end of file
+2390166409ac2d4a87539ceefc99f56a6a68b105
\ No newline at end of file
diff --git a/ui/accessibility/platform/ax_platform_node_win.cc b/ui/accessibility/platform/ax_platform_node_win.cc
index a0e8812d..e1284e9 100644
--- a/ui/accessibility/platform/ax_platform_node_win.cc
+++ b/ui/accessibility/platform/ax_platform_node_win.cc
@@ -5897,7 +5897,7 @@
       return UIA_PaneControlTypeId;
 
     case ax::mojom::Role::kArticle:
-      return UIA_DocumentControlTypeId;
+      return UIA_GroupControlTypeId;
 
     case ax::mojom::Role::kAudio:
       return UIA_GroupControlTypeId;
diff --git a/ui/accessibility/platform/test_ax_node_wrapper.cc b/ui/accessibility/platform/test_ax_node_wrapper.cc
index bd957f94..a1f63cef 100644
--- a/ui/accessibility/platform/test_ax_node_wrapper.cc
+++ b/ui/accessibility/platform/test_ax_node_wrapper.cc
@@ -578,6 +578,9 @@
 base::string16 TestAXNodeWrapper::GetLocalizedStringForRoleDescription() const {
   const AXNodeData& data = GetData();
   switch (data.role) {
+    case ax::mojom::Role::kArticle:
+      return base::ASCIIToUTF16("article");
+
     case ax::mojom::Role::kAudio:
       return base::ASCIIToUTF16("audio");
 
@@ -603,6 +606,9 @@
     case ax::mojom::Role::kDetails:
       return base::ASCIIToUTF16("details");
 
+    case ax::mojom::Role::kFigure:
+      return base::ASCIIToUTF16("figure");
+
     case ax::mojom::Role::kMeter:
       return base::ASCIIToUTF16("meter");
 
diff --git a/ui/aura/window_event_dispatcher.cc b/ui/aura/window_event_dispatcher.cc
index 1fe00525..b3887da 100644
--- a/ui/aura/window_event_dispatcher.cc
+++ b/ui/aura/window_event_dispatcher.cc
@@ -20,7 +20,6 @@
 #include "ui/aura/client/screen_position_client.h"
 #include "ui/aura/env.h"
 #include "ui/aura/env_input_state_controller.h"
-#include "ui/aura/window.h"
 #include "ui/aura/window_delegate.h"
 #include "ui/aura/window_event_dispatcher_observer.h"
 #include "ui/aura/window_targeter.h"
diff --git a/ui/aura/window_event_dispatcher.h b/ui/aura/window_event_dispatcher.h
index 680ff3e..f1a1bcad5 100644
--- a/ui/aura/window_event_dispatcher.h
+++ b/ui/aura/window_event_dispatcher.h
@@ -18,6 +18,7 @@
 #include "ui/aura/aura_export.h"
 #include "ui/aura/client/capture_delegate.h"
 #include "ui/aura/env_observer.h"
+#include "ui/aura/window.h"
 #include "ui/aura/window_observer.h"
 #include "ui/base/cursor/cursor.h"
 #include "ui/events/event_constants.h"
diff --git a/ui/compositor/layer.cc b/ui/compositor/layer.cc
index 02579ea..9da2d35 100644
--- a/ui/compositor/layer.cc
+++ b/ui/compositor/layer.cc
@@ -230,6 +230,8 @@
   cc_layer_->RemoveFromParent();
   if (transfer_release_callback_)
     transfer_release_callback_->Run(gpu::SyncToken(), false);
+
+  ResetSubtreeReflectedLayer();
 }
 
 std::unique_ptr<Layer> Layer::Clone() const {
@@ -738,12 +740,7 @@
     animator_->SwitchToLayer(new_layer);
   }
 
-  if (subtree_reflected_layer_) {
-    size_t result =
-        subtree_reflected_layer_->subtree_reflecting_layers_.erase(this);
-    DCHECK_EQ(1u, result);
-    subtree_reflected_layer_ = nullptr;
-  }
+  ResetSubtreeReflectedLayer();
 
   if (texture_layer_.get())
     texture_layer_->ClearClient();
@@ -1632,4 +1629,14 @@
   SetBounds(new_bounds);
 }
 
+void Layer::ResetSubtreeReflectedLayer() {
+  if (!subtree_reflected_layer_)
+    return;
+
+  size_t result =
+      subtree_reflected_layer_->subtree_reflecting_layers_.erase(this);
+  DCHECK_EQ(1u, result);
+  subtree_reflected_layer_ = nullptr;
+}
+
 }  // namespace ui
diff --git a/ui/compositor/layer.h b/ui/compositor/layer.h
index f40db7c1..2e77a40e0 100644
--- a/ui/compositor/layer.h
+++ b/ui/compositor/layer.h
@@ -603,6 +603,10 @@
   // Changes the size of |this| to match that of |layer|.
   void MatchLayerSize(const Layer* layer);
 
+  // Resets |subtree_reflected_layer_| and updates the reflected layer's
+  // |subtree_reflecting_layers_| list accordingly.
+  void ResetSubtreeReflectedLayer();
+
   const LayerType type_;
 
   Compositor* compositor_;
diff --git a/ui/compositor/layer_unittest.cc b/ui/compositor/layer_unittest.cc
index 87b1a6b3..fda43bb 100644
--- a/ui/compositor/layer_unittest.cc
+++ b/ui/compositor/layer_unittest.cc
@@ -1594,6 +1594,12 @@
   reflected_layer->SetBounds(new_reflected_bounds);
   EXPECT_EQ(reflecting_bounds.origin(), reflecting_layer->bounds().origin());
   EXPECT_EQ(new_reflected_bounds.size(), reflecting_layer->bounds().size());
+
+  // No crashes on reflected layer bounds change after the reflecting layer is
+  // released.
+  reflecting_layer = nullptr;
+  reflected_layer->SetBounds(reflected_bounds);
+  EXPECT_EQ(reflected_bounds, reflected_layer->bounds());
 }
 
 void ExpectRgba(int x, int y, SkColor expected_color, SkColor actual_color) {
diff --git a/ui/strings/ui_strings.grd b/ui/strings/ui_strings.grd
index 5dfb97992..fbcc0fab 100644
--- a/ui/strings/ui_strings.grd
+++ b/ui/strings/ui_strings.grd
@@ -988,8 +988,8 @@
       <message name="IDS_BROWSER_SHARING_CLICK_TO_CALL_DIALOG_FAILED_MESSAGE" desc="The label to be shown on the dialog when user click on a phone number, if sending it to a device failed.">
         Check your phone's connection and try again
       </message>
-      <message name="IDS_BROWSER_SHARING_CLICK_TO_CALL_DIALOG_SEND_SUCCESS" desc="The label to be shown next to the omnibox icon after a phone number got sent to a users device.">
-        Sent to device
+      <message name="IDS_BROWSER_SHARING_OMNIBOX_SENDING_LABEL" desc="The label to be shown next to the omnibox icon when the message is being sent to the other device.">
+        Sending...
       </message>
     </messages>
   </release>
diff --git a/ui/strings/ui_strings_grd/IDS_BROWSER_SHARING_OMNIBOX_SENDING_LABEL.png.sha1 b/ui/strings/ui_strings_grd/IDS_BROWSER_SHARING_OMNIBOX_SENDING_LABEL.png.sha1
new file mode 100644
index 0000000..c9ca773
--- /dev/null
+++ b/ui/strings/ui_strings_grd/IDS_BROWSER_SHARING_OMNIBOX_SENDING_LABEL.png.sha1
@@ -0,0 +1 @@
+be4376302ced60a07f2e318dbd8fa5f0a70cb969
\ No newline at end of file
diff --git a/ui/views/animation/animation_delegate_views.cc b/ui/views/animation/animation_delegate_views.cc
index 660e42f..9bd14c74 100644
--- a/ui/views/animation/animation_delegate_views.cc
+++ b/ui/views/animation/animation_delegate_views.cc
@@ -6,7 +6,6 @@
 
 #include "ui/gfx/animation/animation_container.h"
 #include "ui/views/animation/compositor_animation_runner.h"
-#include "ui/views/view.h"
 #include "ui/views/widget/widget.h"
 
 namespace views {
diff --git a/ui/views/animation/animation_delegate_views.h b/ui/views/animation/animation_delegate_views.h
index ee025be..637b718f 100644
--- a/ui/views/animation/animation_delegate_views.h
+++ b/ui/views/animation/animation_delegate_views.h
@@ -10,13 +10,12 @@
 #include "base/scoped_observer.h"
 #include "ui/gfx/animation/animation_container_observer.h"
 #include "ui/gfx/animation/animation_delegate.h"
+#include "ui/views/view.h"
 #include "ui/views/view_observer.h"
 #include "ui/views/views_export.h"
 
 namespace views {
 
-class View;
-
 // Provides default implementaton to adapt CompositorAnimationRunner for
 // Animation. Falls back to the default animation runner when |view| is nullptr.
 class VIEWS_EXPORT AnimationDelegateViews
@@ -52,7 +51,7 @@
   View* view_;
   gfx::AnimationContainer* container_ = nullptr;
 
-  ScopedObserver<View, AnimationDelegateViews> scoped_observer_{this};
+  ScopedObserver<View, ViewObserver> scoped_observer_{this};
 };
 
 }  // namespace views
diff --git a/ui/views/animation/compositor_animation_runner.cc b/ui/views/animation/compositor_animation_runner.cc
index e5abea4..07aa4e4 100644
--- a/ui/views/animation/compositor_animation_runner.cc
+++ b/ui/views/animation/compositor_animation_runner.cc
@@ -4,8 +4,6 @@
 
 #include "ui/views/animation/compositor_animation_runner.h"
 
-#include "ui/compositor/compositor.h"
-
 namespace views {
 
 ////////////////////////////////////////////////////////////////////////////////
diff --git a/ui/views/animation/compositor_animation_runner.h b/ui/views/animation/compositor_animation_runner.h
index 58a9ab7..b1da6213 100644
--- a/ui/views/animation/compositor_animation_runner.h
+++ b/ui/views/animation/compositor_animation_runner.h
@@ -7,14 +7,11 @@
 
 #include "base/scoped_observer.h"
 #include "base/time/time.h"
+#include "ui/compositor/compositor.h"
 #include "ui/compositor/compositor_animation_observer.h"
 #include "ui/compositor/compositor_observer.h"
 #include "ui/gfx/animation/animation_container.h"
 
-namespace ui {
-class Compositor;
-}  // namespace ui
-
 namespace views {
 
 // An animation runner based on ui::Compositor.
@@ -51,7 +48,8 @@
 
    private:
     CompositorAnimationRunner* runner_;
-    ScopedObserver<ui::Compositor, CompositorChecker> scoped_observer_{this};
+    ScopedObserver<ui::Compositor, ui::CompositorObserver> scoped_observer_{
+        this};
   };
 
   // When |compositor_| is nullptr, it means compositor has been shut down.
diff --git a/ui/views/bubble/tooltip_icon.cc b/ui/views/bubble/tooltip_icon.cc
index 289e921..e007660 100644
--- a/ui/views/bubble/tooltip_icon.cc
+++ b/ui/views/bubble/tooltip_icon.cc
@@ -19,8 +19,7 @@
       tooltip_icon_size_(tooltip_icon_size),
       mouse_inside_(false),
       bubble_(nullptr),
-      preferred_width_(0),
-      observer_(this) {
+      preferred_width_(0) {
   SetDrawAsHovered(false);
 }
 
diff --git a/ui/views/bubble/tooltip_icon.h b/ui/views/bubble/tooltip_icon.h
index cb10e59..073241b 100644
--- a/ui/views/bubble/tooltip_icon.h
+++ b/ui/views/bubble/tooltip_icon.h
@@ -14,6 +14,7 @@
 #include "ui/views/bubble/bubble_border.h"
 #include "ui/views/controls/image_view.h"
 #include "ui/views/mouse_watcher.h"
+#include "ui/views/widget/widget.h"
 #include "ui/views/widget/widget_observer.h"
 
 namespace views {
@@ -89,7 +90,7 @@
   // A watcher that keeps |bubble_| open if the user's mouse enters it.
   std::unique_ptr<MouseWatcher> mouse_watcher_;
 
-  ScopedObserver<Widget, TooltipIcon> observer_;
+  ScopedObserver<Widget, WidgetObserver> observer_{this};
 
   DISALLOW_COPY_AND_ASSIGN(TooltipIcon);
 };
diff --git a/ui/webui/resources/cr_elements/chromeos/network/BUILD.gn b/ui/webui/resources/cr_elements/chromeos/network/BUILD.gn
index 30fde56..0d6271b 100644
--- a/ui/webui/resources/cr_elements/chromeos/network/BUILD.gn
+++ b/ui/webui/resources/cr_elements/chromeos/network/BUILD.gn
@@ -43,7 +43,7 @@
     deps = [
       ":cr_network_list_types",
       ":cr_onc_types",
-      "//ui/webui/resources/cr_elements/policy:cr_policy_network_behavior",
+      "//ui/webui/resources/cr_elements/policy:cr_policy_network_behavior_mojo",
       "//ui/webui/resources/js:assert",
     ]
   }
diff --git a/ui/webui/resources/cr_elements/chromeos/network/cr_network_list_item.html b/ui/webui/resources/cr_elements/chromeos/network/cr_network_list_item.html
index 9d52d4d..d7c76b7 100644
--- a/ui/webui/resources/cr_elements/chromeos/network/cr_network_list_item.html
+++ b/ui/webui/resources/cr_elements/chromeos/network/cr_network_list_item.html
@@ -6,7 +6,7 @@
 <link rel="import" href="../../cr_icon_button/cr_icon_button.html">
 <link rel="import" href="../../icons.html">
 <link rel="import" href="../../policy/cr_policy_indicator.html">
-<link rel="import" href="../../policy/cr_policy_network_behavior.html">
+<link rel="import" href="../../policy/cr_policy_network_behavior_mojo.html">
 <link rel="import" href="../../shared_style_css.html">
 <link rel="import" href="../../shared_vars_css.html">
 <link rel="import" href="chrome://resources/polymer/v1_0/iron-flex-layout/iron-flex-layout-classes.html">
@@ -75,8 +75,8 @@
           [[getNetworkStateText_(networkState)]]
         </div>
       </div>
-      <template is="dom-if" if="[[isPolicySourceMojo(networkState.source)]]">
-        <cr-policy-indicator indicator-type="[[getIndicatorTypeForSourceMojo(
+      <template is="dom-if" if="[[isPolicySource(networkState.source)]]">
+        <cr-policy-indicator indicator-type="[[getIndicatorTypeForSource(
             networkState.source)]]">
         </cr-policy-indicator>
       </template>
diff --git a/ui/webui/resources/cr_elements/chromeos/network/cr_network_list_item.js b/ui/webui/resources/cr_elements/chromeos/network/cr_network_list_item.js
index d3425683..a329cfe 100644
--- a/ui/webui/resources/cr_elements/chromeos/network/cr_network_list_item.js
+++ b/ui/webui/resources/cr_elements/chromeos/network/cr_network_list_item.js
@@ -10,6 +10,10 @@
 Polymer({
   is: 'cr-network-list-item',
 
+  behaviors: [
+    CrPolicyNetworkBehaviorMojo,
+  ],
+
   properties: {
     /** @type {!CrNetworkList.CrNetworkListItemType|undefined} */
     item: {
@@ -65,8 +69,6 @@
     showTechnologyBadge: {type: Boolean, value: true},
   },
 
-  behaviors: [CrPolicyNetworkBehavior],
-
   /** @override */
   attached: function() {
     this.listen(this, 'keydown', 'onKeydown_');
diff --git a/ui/webui/resources/cr_elements/policy/cr_policy_network_behavior.js b/ui/webui/resources/cr_elements/policy/cr_policy_network_behavior.js
index 68b1040..aff8824 100644
--- a/ui/webui/resources/cr_elements/policy/cr_policy_network_behavior.js
+++ b/ui/webui/resources/cr_elements/policy/cr_policy_network_behavior.js
@@ -108,17 +108,6 @@
   },
 
   /**
-   * @param {chromeos.networkConfig.mojom.OncSource} source
-   * @return {boolean}
-   * @protected
-   */
-  isPolicySourceMojo: function(source) {
-    return !!source &&
-        (source == chromeos.networkConfig.mojom.OncSource.kDevicePolicy ||
-         source == chromeos.networkConfig.mojom.OncSource.kUserPolicy);
-  },
-
-  /**
    * @param {string} source
    * @return {!CrPolicyIndicatorType}
    * @private
@@ -134,21 +123,6 @@
   },
 
   /**
-   * @param {chromeos.networkConfig.mojom.OncSource} source
-   * @return {!CrPolicyIndicatorType}
-   * @private
-   */
-  getIndicatorTypeForSourceMojo: function(source) {
-    if (source == chromeos.networkConfig.mojom.OncSource.kDevicePolicy) {
-      return CrPolicyIndicatorType.DEVICE_POLICY;
-    }
-    if (source == chromeos.networkConfig.mojom.OncSource.kUserPolicy) {
-      return CrPolicyIndicatorType.USER_POLICY;
-    }
-    return CrPolicyIndicatorType.NONE;
-  },
-
-  /**
    * @param {Object} dict A managed ONC dictionary.
    * @param {string} path A path to a setting inside |dict|.
    * @return {!CrOnc.ManagedProperty|undefined} The value of the setting at
diff --git a/ui/webui/resources/cr_elements/policy/cr_policy_network_indicator.html b/ui/webui/resources/cr_elements/policy/cr_policy_network_indicator.html
index 37120ce..52a50e3 100644
--- a/ui/webui/resources/cr_elements/policy/cr_policy_network_indicator.html
+++ b/ui/webui/resources/cr_elements/policy/cr_policy_network_indicator.html
@@ -3,11 +3,6 @@
 <link rel="import" href="../hidden_style_css.html">
 <link rel="import" href="cr_policy_indicator_behavior.html">
 <link rel="import" href="cr_policy_network_behavior.html">
-<!-- Currently cr_policy_network_behavior_mojo.html is included only for testing
-     in cr_policy_network_behavior_mojo_tests.js which requires the behavior to
-     be loaded from an html file that the browser knows about.
-     TODO(853953): Convert this class to use the mojo API. -->
-<link rel="import" href="cr_policy_network_behavior_mojo.html">
 <link rel="import" href="cr_tooltip_icon.html">
 
 <dom-module id="cr-policy-network-indicator">
diff --git a/ui/webui/resources/cr_elements/policy/cr_policy_pref_indicator.js b/ui/webui/resources/cr_elements/policy/cr_policy_pref_indicator.js
index 6362e1b4..563e77a4 100644
--- a/ui/webui/resources/cr_elements/policy/cr_policy_pref_indicator.js
+++ b/ui/webui/resources/cr_elements/policy/cr_policy_pref_indicator.js
@@ -67,6 +67,9 @@
           return CrPolicyIndicatorType.CHILD_RESTRICTION;
       }
     }
+    if (enforcement == chrome.settingsPrivate.Enforcement.PARENT_SUPERVISED) {
+      return CrPolicyIndicatorType.PARENT;
+    }
     return CrPolicyIndicatorType.NONE;
   },