diff --git a/DEPS b/DEPS
index f5fb7c1..7af9405 100644
--- a/DEPS
+++ b/DEPS
@@ -126,11 +126,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': '5257816bd3ae9d877293d2b6fe87754a7e08ab5b',
+  'skia_revision': '30595ea7c7825fb170d546cf77602e37b2ec8bd6',
   # 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': '17cb18153b15e04ef11d9a474a20f33d78383393',
+  'v8_revision': '0e223be0fe07b0ae6eceb58b48cb1719c39db14e',
   # 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.
@@ -138,7 +138,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': 'abf6dbbb107b3487480422b6ce37e9662cb8f302',
+  'angle_revision': '0029dfe28cf4ed9e6fa0928a632063f4b72b63f1',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling SwiftShader
   # and whatever else without interference from each other.
@@ -146,7 +146,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling PDFium
   # and whatever else without interference from each other.
-  'pdfium_revision': '27a3c7755b4d5a7ee7266691e8c4fe2abf8f325d',
+  'pdfium_revision': '011147f5b36f401dc40036851613e5eaba7bab03',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling openmax_dl
   # and whatever else without interference from each other.
@@ -154,7 +154,10 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling BoringSSL
   # and whatever else without interference from each other.
-  'boringssl_revision': '70fe6105565e71e44e0a2a4ee617a26fd8fdcd96',
+  #
+  # Note this revision should be updated with
+  # third_party/boringssl/roll_boringssl.py, not roll-dep.
+  'boringssl_revision': '7ef4223fb32431529a797c5b8d3bf26ece6c138b',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling google-toolbox-for-mac
   # and whatever else without interference from each other.
@@ -729,7 +732,7 @@
 
   # Build tools for Chrome OS. Note: This depends on third_party/pyelftools.
   'src/third_party/chromite': {
-      'url': Var('chromium_git') + '/chromiumos/chromite.git' + '@' + '3ef549770d8fdf3e3ca472182f421fc50575ec4f',
+      'url': Var('chromium_git') + '/chromiumos/chromite.git' + '@' + 'dbec33e55f7acef520a56e1d2b4aa832311a9b13',
       'condition': 'checkout_linux',
   },
 
@@ -744,7 +747,7 @@
 
   # For Linux and Chromium OS.
   'src/third_party/cros_system_api': {
-      'url': Var('chromium_git') + '/chromiumos/platform2/system_api.git' + '@' + 'dbbd7b449a7f9aeff25ab388f4ec5002912b2e97',
+      'url': Var('chromium_git') + '/chromiumos/platform2/system_api.git' + '@' + '3cf556ebeb2d5e152cefb8ccee3754c87c2fb5ee',
       'condition': 'checkout_linux',
   },
 
@@ -754,7 +757,7 @@
   },
 
   'src/third_party/depot_tools':
-    Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + 'aec259ea62328ce39916607876956239fbce29b8',
+    Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + '98f4a99359d51a696dd8c1eafb78a7b4157001bb',
 
   'src/third_party/devtools-node-modules':
     Var('chromium_git') + '/external/github.com/ChromeDevTools/devtools-node-modules' + '@' + Var('devtools_node_modules_revision'),
@@ -1293,7 +1296,7 @@
     Var('chromium_git') + '/v8/v8.git' + '@' +  Var('v8_revision'),
 
   'src-internal': {
-    'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@a483882d60579f45dd09ee494d2c68ff222e87e8',
+    'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@4ddd89fe2fbd342f80a693a1daf17250083583fa',
     'condition': 'checkout_src_internal',
   },
 
diff --git a/android_webview/javatests/src/org/chromium/android_webview/test/PopupWindowTest.java b/android_webview/javatests/src/org/chromium/android_webview/test/PopupWindowTest.java
index 3fd8ec8e..b866822 100644
--- a/android_webview/javatests/src/org/chromium/android_webview/test/PopupWindowTest.java
+++ b/android_webview/javatests/src/org/chromium/android_webview/test/PopupWindowTest.java
@@ -28,6 +28,9 @@
 import org.chromium.content_public.browser.test.util.TestCallbackHelperContainer;
 import org.chromium.net.test.util.TestWebServer;
 
+import java.util.Locale;
+import java.util.concurrent.TimeUnit;
+
 /**
  * Tests for pop up window flow.
  */
@@ -274,6 +277,72 @@
                         popupContents, popupContentsClient, jsGetSelection));
     }
 
+    @Test
+    @SmallTest
+    @Feature({"AndroidWebView"})
+    public void testPopupWindowHasUserGestureForUserInitiated() throws Throwable {
+        runPopupUserGestureTest(true);
+    }
+
+    @Test
+    @SmallTest
+    @Feature({"AndroidWebView"})
+    public void testPopupWindowHasUserGestureForUserInitiatedNoOpener() throws Throwable {
+        runPopupUserGestureTest(false);
+    }
+
+    private void runPopupUserGestureTest(boolean hasOpener) throws Throwable {
+        ThreadUtils.runOnUiThreadBlocking(() -> {
+            mParentContents.getSettings().setJavaScriptEnabled(true);
+            mParentContents.getSettings().setSupportMultipleWindows(true);
+            mParentContents.getSettings().setJavaScriptCanOpenWindowsAutomatically(true);
+        });
+
+        final String body = String.format(Locale.US,
+                "<a href=\"popup.html\" id=\"link\" %s target=\"_blank\">example.com</a>",
+                hasOpener ? "" : "rel=\"noopener noreferrer\"");
+        final String mainHtml = CommonResources.makeHtmlPageFrom("", body);
+        final String openerUrl = mWebServer.setResponse("/popupOpener.html", mainHtml, null);
+        final String popupUrl = mWebServer.setResponse("/popup.html",
+                CommonResources.makeHtmlPageFrom(
+                        "<title>" + POPUP_TITLE + "</title>", "This is a popup window"),
+                null);
+
+        mParentContentsClient.getOnCreateWindowHelper().setReturnValue(true);
+        mActivityTestRule.loadUrlSync(
+                mParentContents, mParentContentsClient.getOnPageFinishedHelper(), openerUrl);
+
+        TestAwContentsClient.OnCreateWindowHelper onCreateWindowHelper =
+                mParentContentsClient.getOnCreateWindowHelper();
+        int currentCallCount = onCreateWindowHelper.getCallCount();
+        DOMUtils.clickNode(mParentContents.getWebContents(), "link");
+        onCreateWindowHelper.waitForCallback(
+                currentCallCount, 1, AwActivityTestRule.WAIT_TIMEOUT_MS, TimeUnit.MILLISECONDS);
+
+        Assert.assertTrue(onCreateWindowHelper.getIsUserGesture());
+    }
+
+    @Test
+    @SmallTest
+    @Feature({"AndroidWebView"})
+    public void testPopupWindowNoUserGestureForJsInitiated() throws Throwable {
+        final String popupPath = "/popup.html";
+        final String openerPageHtml = CommonResources.makeHtmlPageFrom("",
+                "<script>"
+                        + "function tryOpenWindow() {"
+                        + "  var newWindow = window.open('" + popupPath + "');"
+                        + "}</script>");
+
+        final String popupPageHtml = CommonResources.makeHtmlPageFrom(
+                "<title>" + POPUP_TITLE + "</title>", "This is a popup window");
+
+        mActivityTestRule.triggerPopup(mParentContents, mParentContentsClient, mWebServer,
+                openerPageHtml, popupPageHtml, popupPath, "tryOpenWindow()");
+        TestAwContentsClient.OnCreateWindowHelper onCreateWindowHelper =
+                mParentContentsClient.getOnCreateWindowHelper();
+        Assert.assertFalse(onCreateWindowHelper.getIsUserGesture());
+    }
+
     // Copied from imeTest.java.
     private void assertWaitForSelectActionBarStatus(
             boolean show, final SelectionPopupController controller) {
diff --git a/android_webview/javatests/src/org/chromium/android_webview/test/TestAwContentsClient.java b/android_webview/javatests/src/org/chromium/android_webview/test/TestAwContentsClient.java
index 7a2bc1c..fe890153 100644
--- a/android_webview/javatests/src/org/chromium/android_webview/test/TestAwContentsClient.java
+++ b/android_webview/javatests/src/org/chromium/android_webview/test/TestAwContentsClient.java
@@ -22,9 +22,10 @@
 import org.chromium.content_public.browser.test.util.TestCallbackHelperContainer.OnReceivedErrorHelper;
 
 import java.util.ArrayList;
+import java.util.Collections;
 import java.util.HashMap;
 import java.util.List;
-import java.util.concurrent.ConcurrentHashMap;
+import java.util.Map;
 
 /**
  * AwContentsClient subclass used for testing.
@@ -328,7 +329,7 @@
             return mIsDialog;
         }
 
-        public boolean getUserAgent() {
+        public boolean getIsUserGesture() {
             assert getCallCount() > 0;
             return mIsUserGesture;
         }
@@ -527,10 +528,10 @@
      */
     public static class ShouldInterceptRequestHelper extends CallbackHelper {
         private List<String> mShouldInterceptRequestUrls = new ArrayList<String>();
-        private ConcurrentHashMap<String, AwWebResourceResponse> mReturnValuesByUrls =
-                new ConcurrentHashMap<String, AwWebResourceResponse>();
-        private ConcurrentHashMap<String, AwWebResourceRequest> mRequestsByUrls =
-                new ConcurrentHashMap<String, AwWebResourceRequest>();
+        private Map<String, AwWebResourceResponse> mReturnValuesByUrls =
+                Collections.synchronizedMap(new HashMap<String, AwWebResourceResponse>());
+        private Map<String, AwWebResourceRequest> mRequestsByUrls =
+                Collections.synchronizedMap(new HashMap<String, AwWebResourceRequest>());
         // This is read on another thread, so needs to be marked volatile.
         private volatile AwWebResourceResponse mShouldInterceptRequestReturnValue;
         void setReturnValue(AwWebResourceResponse value) {
diff --git a/ash/app_list/app_list_controller_impl.cc b/ash/app_list/app_list_controller_impl.cc
index 2819bf9..2954c363 100644
--- a/ash/app_list/app_list_controller_impl.cc
+++ b/ash/app_list/app_list_controller_impl.cc
@@ -62,7 +62,9 @@
 }  // namespace
 
 AppListControllerImpl::AppListControllerImpl()
-    : presenter_(std::make_unique<AppListPresenterDelegateImpl>(this)) {
+    : presenter_(std::make_unique<AppListPresenterDelegateImpl>(this)),
+      home_launcher_gesture_handler_(
+          std::make_unique<HomeLauncherGestureHandler>(this)) {
   model_.AddObserver(this);
 
   SessionController* session_controller = Shell::Get()->session_controller();
@@ -77,12 +79,6 @@
   Shell::Get()->wallpaper_controller()->AddObserver(this);
   Shell::Get()->AddShellObserver(this);
   keyboard::KeyboardController::Get()->AddObserver(this);
-
-  if (app_list_features::IsHomeLauncherGesturesEnabled()) {
-    home_launcher_gesture_handler_ =
-        std::make_unique<HomeLauncherGestureHandler>(this);
-  }
-
   Shell::Get()->voice_interaction_controller()->AddLocalObserver(this);
   Shell::Get()->window_tree_host_manager()->AddObserver(this);
   Shell::Get()->mru_window_tracker()->AddObserver(this);
@@ -638,13 +634,8 @@
   if (!IsTabletMode())
     return ToggleAppList(display_id, show_source, event_time_stamp);
 
-  // Whether the this action is handled.
-  bool handled = false;
-
-  if (home_launcher_gesture_handler_) {
-    handled = home_launcher_gesture_handler_->ShowHomeLauncher(
-        Shell::Get()->display_manager()->GetDisplayForId(display_id));
-  }
+  bool handled = home_launcher_gesture_handler_->ShowHomeLauncher(
+      Shell::Get()->display_manager()->GetDisplayForId(display_id));
 
   if (!handled) {
     if (Shell::Get()->overview_controller()->IsSelecting()) {
@@ -852,9 +843,6 @@
 bool AppListControllerImpl::ProcessHomeLauncherGesture(
     ui::GestureEvent* event,
     const gfx::Point& screen_location) {
-  if (!home_launcher_gesture_handler_)
-    return false;
-
   switch (event->type()) {
     case ui::ET_SCROLL_FLING_START:
     case ui::ET_GESTURE_SCROLL_BEGIN:
@@ -882,9 +870,6 @@
     return false;
   }
 
-  if (!home_launcher_gesture_handler_)
-    return true;
-
   return home_launcher_gesture_handler_->mode() !=
          HomeLauncherGestureHandler::Mode::kSlideUpToShow;
 }
diff --git a/ash/app_list/views/contents_view.cc b/ash/app_list/views/contents_view.cc
index 1e3d4cee..9880fb3 100644
--- a/ash/app_list/views/contents_view.cc
+++ b/ash/app_list/views/contents_view.cc
@@ -365,14 +365,6 @@
 void ContentsView::UpdateExpandArrowOpacity(double progress,
                                             ash::AppListState current_state,
                                             ash::AppListState target_state) {
-  // Don't show |expand_arrow_view_| when the home launcher gestures are
-  // disabled in tablet mode.
-  if (app_list_view_->is_tablet_mode() &&
-      !app_list_features::IsHomeLauncherGesturesEnabled()) {
-    expand_arrow_view_->layer()->SetOpacity(0);
-    return;
-  }
-
   if (current_state == ash::AppListState::kStateSearchResults &&
       (target_state == ash::AppListState::kStateStart ||
        target_state == ash::AppListState::kStateApps)) {
diff --git a/ash/public/cpp/app_list/app_list_features.cc b/ash/public/cpp/app_list/app_list_features.cc
index b08bff2..5f50698 100644
--- a/ash/public/cpp/app_list/app_list_features.cc
+++ b/ash/public/cpp/app_list/app_list_features.cc
@@ -20,8 +20,6 @@
     "EnablePlayStoreAppSearch", base::FEATURE_DISABLED_BY_DEFAULT};
 const base::Feature kEnableAppDataSearch{"EnableAppDataSearch",
                                          base::FEATURE_DISABLED_BY_DEFAULT};
-const base::Feature kEnableHomeLauncherGestures{
-    "HomeLauncherGestures", base::FEATURE_ENABLED_BY_DEFAULT};
 const base::Feature kEnableSettingsShortcutSearch{
     "EnableSettingsShortcutSearch", base::FEATURE_DISABLED_BY_DEFAULT};
 const base::Feature kEnableZeroStateSuggestions{
@@ -57,10 +55,6 @@
   return base::FeatureList::IsEnabled(kEnableAppDataSearch);
 }
 
-bool IsHomeLauncherGesturesEnabled() {
-  return base::FeatureList::IsEnabled(kEnableHomeLauncherGestures);
-}
-
 bool IsSettingsShortcutSearchEnabled() {
   return base::FeatureList::IsEnabled(kEnableSettingsShortcutSearch);
 }
diff --git a/ash/public/cpp/app_list/app_list_features.h b/ash/public/cpp/app_list/app_list_features.h
index c69d435..2c192d4 100644
--- a/ash/public/cpp/app_list/app_list_features.h
+++ b/ash/public/cpp/app_list/app_list_features.h
@@ -35,10 +35,6 @@
 // Enables in-app data search.
 ASH_PUBLIC_EXPORT extern const base::Feature kEnableAppDataSearch;
 
-// Enables using gestures to show or hide the home launcher.
-// TODO(crbug.com/872319): Remove this after the feature is launched.
-ASH_PUBLIC_EXPORT extern const base::Feature kEnableHomeLauncherGestures;
-
 // Enables the Settings shortcut search.
 ASH_PUBLIC_EXPORT extern const base::Feature kEnableSettingsShortcutSearch;
 
@@ -63,7 +59,6 @@
 bool ASH_PUBLIC_EXPORT IsBackgroundBlurEnabled();
 bool ASH_PUBLIC_EXPORT IsPlayStoreAppSearchEnabled();
 bool ASH_PUBLIC_EXPORT IsAppDataSearchEnabled();
-bool ASH_PUBLIC_EXPORT IsHomeLauncherGesturesEnabled();
 bool ASH_PUBLIC_EXPORT IsSettingsShortcutSearchEnabled();
 bool ASH_PUBLIC_EXPORT IsZeroStateSuggestionsEnabled();
 bool ASH_PUBLIC_EXPORT IsAppListSearchAutocompleteEnabled();
diff --git a/ash/shelf/shelf_layout_manager.cc b/ash/shelf/shelf_layout_manager.cc
index af81f82..5a59daf 100644
--- a/ash/shelf/shelf_layout_manager.cc
+++ b/ash/shelf/shelf_layout_manager.cc
@@ -1260,13 +1260,6 @@
 }
 
 bool ShelfLayoutManager::ShouldHomeGestureHandleEvent(float scroll_y) const {
-  HomeLauncherGestureHandler* home_launcher_handler =
-      Shell::Get()->app_list_controller()->home_launcher_gesture_handler();
-
-  // If there is no |home_launcher_handler|, return early.
-  if (!home_launcher_handler)
-    return false;
-
   // If the shelf is not visible, home gesture shouldn't trigger.
   if (!IsVisible())
     return false;
@@ -1399,8 +1392,8 @@
 
   HomeLauncherGestureHandler* home_launcher_handler =
       Shell::Get()->app_list_controller()->home_launcher_gesture_handler();
-  if (home_launcher_handler &&
-      home_launcher_handler->OnReleaseEvent(gesture_in_screen.location())) {
+  DCHECK(home_launcher_handler);
+  if (home_launcher_handler->OnReleaseEvent(gesture_in_screen.location())) {
     gesture_drag_status_ = GESTURE_DRAG_NONE;
     return;
   }
@@ -1449,7 +1442,8 @@
   if (gesture_drag_status_ == GESTURE_DRAG_APPLIST_IN_PROGRESS) {
     HomeLauncherGestureHandler* home_launcher_handler =
         Shell::Get()->app_list_controller()->home_launcher_gesture_handler();
-    if (home_launcher_handler && home_launcher_handler->IsDragInProgress())
+    DCHECK(home_launcher_handler);
+    if (home_launcher_handler->IsDragInProgress())
       home_launcher_handler->Cancel();
     else
       Shell::Get()->app_list_controller()->DismissAppList();
diff --git a/ash/system/unified/unified_system_tray_bubble.cc b/ash/system/unified/unified_system_tray_bubble.cc
index aab15ac..0928ba69 100644
--- a/ash/system/unified/unified_system_tray_bubble.cc
+++ b/ash/system/unified/unified_system_tray_bubble.cc
@@ -128,6 +128,7 @@
   }
 
   tray->tray_event_filter()->AddBubble(this);
+  tray->shelf()->AddObserver(this);
   Shell::Get()->tablet_mode_controller()->AddObserver(this);
   Shell::Get()->activation_client()->AddObserver(this);
 }
@@ -137,6 +138,7 @@
   if (Shell::Get()->tablet_mode_controller())
     Shell::Get()->tablet_mode_controller()->RemoveObserver(this);
   tray_->tray_event_filter()->RemoveBubble(this);
+  tray_->shelf()->RemoveObserver(this);
   if (bubble_widget_) {
     bubble_widget_->RemoveObserver(this);
     bubble_widget_->Close();
@@ -299,6 +301,11 @@
   UpdateBubbleBounds();
 }
 
+void UnifiedSystemTrayBubble::OnAutoHideStateChanged(
+    ShelfAutoHideState new_state) {
+  UpdateBubbleBounds();
+}
+
 void UnifiedSystemTrayBubble::UpdateBubbleBounds() {
   int max_height = CalculateMaxHeight();
   unified_view_->SetMaxHeight(max_height);
diff --git a/ash/system/unified/unified_system_tray_bubble.h b/ash/system/unified/unified_system_tray_bubble.h
index 9517c45..a8c62755 100644
--- a/ash/system/unified/unified_system_tray_bubble.h
+++ b/ash/system/unified/unified_system_tray_bubble.h
@@ -7,6 +7,7 @@
 
 #include <memory>
 
+#include "ash/shelf/shelf_observer.h"
 #include "ash/system/screen_layout_observer.h"
 #include "ash/system/tray/time_to_click_recorder.h"
 #include "ash/system/tray/tray_bubble_base.h"
@@ -38,6 +39,7 @@
 class UnifiedSystemTrayBubble : public TrayBubbleBase,
                                 public ash::ScreenLayoutObserver,
                                 public views::WidgetObserver,
+                                public ShelfObserver,
                                 public ::wm::ActivationChangeObserver,
                                 public TimeToClickRecorder::Delegate,
                                 public TabletModeObserver {
@@ -100,6 +102,9 @@
   void OnTabletModeStarted() override;
   void OnTabletModeEnded() override;
 
+  // ShelfObserver:
+  void OnAutoHideStateChanged(ShelfAutoHideState new_state) override;
+
  private:
   friend class UnifiedSystemTrayTestApi;
 
diff --git a/ash/wm/overview/overview_constants.h b/ash/wm/overview/overview_constants.h
index 639bb78..f92445c 100644
--- a/ash/wm/overview/overview_constants.h
+++ b/ash/wm/overview/overview_constants.h
@@ -34,6 +34,10 @@
 constexpr float kWallpaperBlurSigma = 10.f;
 constexpr float kWallpaperClearBlurSigma = 0.f;
 
+// Amount of time we wait to unpause the occlusion tracker after a overview item
+// is finished dragging. Waits a bit longer than the overview item animation.
+constexpr int kOcclusionPauseDurationForDragMs = 300;
+
 }  // namespace ash
 
 #endif  // ASH_WM_OVERVIEW_OVERVIEW_CONSTANTS_H_
diff --git a/ash/wm/overview/overview_controller.cc b/ash/wm/overview/overview_controller.cc
index c47e0f9..0e74d70 100644
--- a/ash/wm/overview/overview_controller.cc
+++ b/ash/wm/overview/overview_controller.cc
@@ -50,12 +50,12 @@
 constexpr int kBlurSlideDurationMs = 250;
 
 // It can take up to two frames until the frame created in the UI thread that
-// triggered animation observer is drawn. Wait 50ms in attemp to
-// let its draw and swap finish.
+// triggered animation observer is drawn. Wait 50ms in attempt to let its draw
+// and swap finish.
 constexpr int kOcclusionPauseDurationForStartMs = 50;
 
-// Wait longer when exiting overview mode in case when a user
-// may re-enter overview mode immediately, contents are ready.
+// Wait longer when exiting overview mode in case when a user may re-enter
+// overview mode immediately, contents are ready.
 constexpr int kOcclusionPauseDurationForEndMs = 500;
 
 bool IsBlurAllowed() {
@@ -321,10 +321,7 @@
     }
 
     // Suspend occlusion tracker until the exit animation is complete.
-    reset_pauser_task_.Cancel();
-    occlusion_tracker_pauser_ =
-        std::make_unique<aura::WindowOcclusionTracker::ScopedPause>(
-            Shell::Get()->aura_env());
+    PauseOcclusionTracker();
 
     overview_session_->set_enter_exit_overview_type(new_type);
     if (type == OverviewSession::EnterExitOverviewType::kWindowsMinimized ||
@@ -359,10 +356,7 @@
     delayed_animations_.clear();
 
     // Suspend occlusion tracker until the enter animation is complete.
-    reset_pauser_task_.Cancel();
-    occlusion_tracker_pauser_ =
-        std::make_unique<aura::WindowOcclusionTracker::ScopedPause>(
-            Shell::Get()->aura_env());
+    PauseOcclusionTracker();
 
     overview_session_ = std::make_unique<OverviewSession>(this);
     overview_session_->set_enter_exit_overview_type(new_type);
@@ -384,11 +378,7 @@
   Shell::Get()->NotifyOverviewModeStartingAnimationComplete(canceled);
   if (overview_session_)
     overview_session_->OnStartingAnimationComplete(canceled);
-  reset_pauser_task_.Reset(base::BindOnce(&OverviewController::ResetPauser,
-                                          weak_ptr_factory_.GetWeakPtr()));
-  base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
-      FROM_HERE, reset_pauser_task_.callback(),
-      base::TimeDelta::FromMilliseconds(kOcclusionPauseDurationForStartMs));
+  UnpauseOcclusionTracker(kOcclusionPauseDurationForStartMs);
 }
 
 void OverviewController::OnEndingAnimationComplete(bool canceled) {
@@ -399,11 +389,7 @@
     overview_blur_controller_->Unblur();
 
   Shell::Get()->NotifyOverviewModeEndingAnimationComplete(canceled);
-  reset_pauser_task_.Reset(base::BindOnce(&OverviewController::ResetPauser,
-                                          weak_ptr_factory_.GetWeakPtr()));
-  base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
-      FROM_HERE, reset_pauser_task_.callback(),
-      base::TimeDelta::FromMilliseconds(occlusion_pause_duration_for_end_ms_));
+  UnpauseOcclusionTracker(occlusion_pause_duration_for_end_ms_);
 }
 
 void OverviewController::ResetPauser() {
@@ -530,6 +516,24 @@
   return !start_animations_.empty();
 }
 
+void OverviewController::PauseOcclusionTracker() {
+  if (occlusion_tracker_pauser_)
+    return;
+
+  reset_pauser_task_.Cancel();
+  occlusion_tracker_pauser_ =
+      std::make_unique<aura::WindowOcclusionTracker::ScopedPause>(
+          Shell::Get()->aura_env());
+}
+
+void OverviewController::UnpauseOcclusionTracker(int delay) {
+  reset_pauser_task_.Reset(base::BindOnce(&OverviewController::ResetPauser,
+                                          weak_ptr_factory_.GetWeakPtr()));
+  base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
+      FROM_HERE, reset_pauser_task_.callback(),
+      base::TimeDelta::FromMilliseconds(delay));
+}
+
 std::vector<aura::Window*>
 OverviewController::GetWindowsListInOverviewGridsForTesting() {
   std::vector<aura::Window*> windows;
@@ -555,12 +559,8 @@
   if (!IsSelecting())
     return;
 
-  if (!occlusion_tracker_pauser_) {
-    reset_pauser_task_.Cancel();
-    occlusion_tracker_pauser_ =
-        std::make_unique<aura::WindowOcclusionTracker::ScopedPause>(
-            Shell::Get()->aura_env());
-  }
+  if (!occlusion_tracker_pauser_)
+    PauseOcclusionTracker();
 
   if (!start_animations_.empty())
     OnStartingAnimationComplete(/*canceled=*/true);
diff --git a/ash/wm/overview/overview_controller.h b/ash/wm/overview/overview_controller.h
index 5e88d1d..21fd918 100644
--- a/ash/wm/overview/overview_controller.h
+++ b/ash/wm/overview/overview_controller.h
@@ -64,6 +64,11 @@
   // Returns true if we're in start-overview animation.
   bool IsInStartAnimation();
 
+  // Pause or unpause the occlusion tracker. Resets the unpause delay if we were
+  // already in the process of unpausing.
+  void PauseOcclusionTracker();
+  void UnpauseOcclusionTracker(int delay);
+
   // Gets the windows list that are shown in the overview windows grids if the
   // overview mode is active for testing.
   std::vector<aura::Window*> GetWindowsListInOverviewGridsForTesting();
diff --git a/ash/wm/overview/overview_item.cc b/ash/wm/overview/overview_item.cc
index 461fef2..f8f2634 100644
--- a/ash/wm/overview/overview_item.cc
+++ b/ash/wm/overview/overview_item.cc
@@ -420,7 +420,7 @@
 }
 
 void OverviewItem::UpdateWindowDimensionsType() {
-  // TODO(oshima|sammiequan|xdai): Use EnableBackdropIfNeeded.
+  // TODO(oshima|sammiequon|xdai): Use EnableBackdropIfNeeded.
   transform_window_.UpdateWindowDimensionsType();
   if (GetWindowDimensionsType() ==
       ScopedOverviewTransformWindow::GridWindowFillMode::kNormal) {
@@ -500,6 +500,7 @@
 void OverviewItem::HandleReleaseEvent(const gfx::Point& location_in_screen) {
   if (!IsDragItem())
     return;
+
   overview_grid_->SetSelectionWidgetVisibility(true);
   overview_session_->CompleteDrag(this, location_in_screen);
 }
@@ -713,6 +714,11 @@
 void OverviewItem::OnWindowDestroying(aura::Window* window) {
   window->RemoveObserver(this);
   transform_window_.OnWindowDestroyed();
+
+  if (is_being_dragged_) {
+    Shell::Get()->overview_controller()->UnpauseOcclusionTracker(
+        kOcclusionPauseDurationForDragMs);
+  }
 }
 
 void OverviewItem::OnWindowTitleChanged(aura::Window* window) {
diff --git a/ash/wm/overview/overview_utils.cc b/ash/wm/overview/overview_utils.cc
index 84cd18b3..2f42102 100644
--- a/ash/wm/overview/overview_utils.cc
+++ b/ash/wm/overview/overview_utils.cc
@@ -293,11 +293,10 @@
   if (!Shell::Get()->overview_controller()->IsSelecting())
     return false;
 
-  HomeLauncherGestureHandler* home_launcher_gesture_handler =
-      Shell::Get()->app_list_controller()->home_launcher_gesture_handler();
-  if (home_launcher_gesture_handler &&
-      home_launcher_gesture_handler->mode() ==
-          HomeLauncherGestureHandler::Mode::kSlideUpToShow) {
+  if (Shell::Get()
+          ->app_list_controller()
+          ->home_launcher_gesture_handler()
+          ->mode() == HomeLauncherGestureHandler::Mode::kSlideUpToShow) {
     return true;
   }
 
diff --git a/ash/wm/overview/overview_window_drag_controller.cc b/ash/wm/overview/overview_window_drag_controller.cc
index 6de2e08..64a7af74 100644
--- a/ash/wm/overview/overview_window_drag_controller.cc
+++ b/ash/wm/overview/overview_window_drag_controller.cc
@@ -8,6 +8,8 @@
 
 #include "ash/screen_util.h"
 #include "ash/shell.h"
+#include "ash/wm/overview/overview_constants.h"
+#include "ash/wm/overview/overview_controller.h"
 #include "ash/wm/overview/overview_grid.h"
 #include "ash/wm/overview/overview_item.h"
 #include "ash/wm/overview/overview_session.h"
@@ -44,6 +46,11 @@
 constexpr float kFlingToCloseVelocityThreshold = 2000.f;
 constexpr float kItemMinOpacity = 0.4f;
 
+void UnpauseOcclusionTracker() {
+  Shell::Get()->overview_controller()->UnpauseOcclusionTracker(
+      kOcclusionPauseDurationForDragMs);
+}
+
 }  // namespace
 
 OverviewWindowDragController::OverviewWindowDragController(
@@ -64,6 +71,7 @@
         GetSnapPosition(location_in_screen) != SplitViewController::NONE;
   }
   current_drag_behavior_ = DragBehavior::kUndefined;
+  Shell::Get()->overview_controller()->PauseOcclusionTracker();
 }
 
 void OverviewWindowDragController::Drag(const gfx::Point& location_in_screen) {
@@ -169,6 +177,7 @@
   did_move_ = false;
   item_ = nullptr;
   current_drag_behavior_ = DragBehavior::kNoDrag;
+  UnpauseOcclusionTracker();
 }
 
 void OverviewWindowDragController::StartSplitViewDragMode(
@@ -202,6 +211,7 @@
       did_move_ = false;
       item_ = nullptr;
       current_drag_behavior_ = DragBehavior::kNoDrag;
+      UnpauseOcclusionTracker();
       return;
     }
   }
@@ -231,6 +241,7 @@
     split_view_controller_->ShowAppCannotSnapToast();
   }
   current_drag_behavior_ = DragBehavior::kNoDrag;
+  UnpauseOcclusionTracker();
 }
 
 void OverviewWindowDragController::ResetGesture() {
@@ -243,6 +254,7 @@
   // CompleteDrag but stops dragging as well, so reset |item_|.
   item_ = nullptr;
   current_drag_behavior_ = DragBehavior::kNoDrag;
+  UnpauseOcclusionTracker();
 }
 
 void OverviewWindowDragController::ResetOverviewSession() {
diff --git a/ash/wm/splitview/split_view_controller.cc b/ash/wm/splitview/split_view_controller.cc
index dd3f294..c51fa1d 100644
--- a/ash/wm/splitview/split_view_controller.cc
+++ b/ash/wm/splitview/split_view_controller.cc
@@ -514,6 +514,7 @@
   // clamshell mode or when a task is minimized during a resize.
   if (is_resizing_) {
     is_resizing_ = false;
+    RestoreWindowsTransformAfterResizing();
     FinishWindowResizing(left_window_);
     FinishWindowResizing(right_window_);
   }
diff --git a/ash/wm/splitview/split_view_controller_unittest.cc b/ash/wm/splitview/split_view_controller_unittest.cc
index 52db25d..6561db5 100644
--- a/ash/wm/splitview/split_view_controller_unittest.cc
+++ b/ash/wm/splitview/split_view_controller_unittest.cc
@@ -1788,6 +1788,43 @@
   EXPECT_FALSE(ShouldAllowSplitView());
 }
 
+// Test that if split view ends while the divider is dragged to where a snapped
+// window is sliding off the screen because it has reached minimum size, then
+// the offset is cleared.
+TEST_F(SplitViewControllerTest, EndSplitViewWhileResizingBeyondMinimum) {
+  int64_t display_id = display::Screen::GetScreen()->GetPrimaryDisplay().id();
+  display::DisplayManager* display_manager = Shell::Get()->display_manager();
+  display::test::ScopedSetInternalDisplayId set_internal(display_manager,
+                                                         display_id);
+  ScreenOrientationControllerTestApi test_api(
+      Shell::Get()->screen_orientation_controller());
+
+  const gfx::Rect bounds(0, 0, 300, 200);
+  std::unique_ptr<aura::Window> window(CreateWindow(bounds));
+  aura::test::TestWindowDelegate* delegate =
+      static_cast<aura::test::TestWindowDelegate*>(window->delegate());
+
+  // Set the screen orientation to LANDSCAPE_PRIMARY
+  test_api.SetDisplayRotation(display::Display::ROTATE_0,
+                              display::Display::RotationSource::ACTIVE);
+
+  gfx::Rect display_bounds =
+      screen_util::GetDisplayWorkAreaBoundsInScreenForDefaultContainer(
+          window.get());
+  split_view_controller()->SnapWindow(window.get(), SplitViewController::LEFT);
+  delegate->set_minimum_size(
+      gfx::Size(display_bounds.width() * 0.4f, display_bounds.height()));
+
+  gfx::Rect divider_bounds =
+      split_view_divider()->GetDividerBoundsInScreen(false);
+  split_view_controller()->StartResize(divider_bounds.CenterPoint());
+  gfx::Point resize_point(display_bounds.width() * 0.33f, 0);
+  split_view_controller()->Resize(resize_point);
+  ASSERT_FALSE(window->layer()->GetTargetTransform().IsIdentity());
+  EndSplitView();
+  EXPECT_TRUE(window->layer()->GetTargetTransform().IsIdentity());
+}
+
 // TestShellObserver which tracks how many overview items there are when
 // overview mode is about to end.
 class TestOverviewItemsOnOverviewModeEndObserver : public ShellObserver {
diff --git a/ash/wm/tablet_mode/tablet_mode_controller.cc b/ash/wm/tablet_mode/tablet_mode_controller.cc
index 0c0842d..dad1f7b 100644
--- a/ash/wm/tablet_mode/tablet_mode_controller.cc
+++ b/ash/wm/tablet_mode/tablet_mode_controller.cc
@@ -674,7 +674,7 @@
   if (IsTabletModeWindowManagerEnabled()) {
     // If we are currently in tablet mode, the internal input events should
     // always be blocked.
-    should_block_internal_events = true;
+    should_block_internal_events = (force_ui_mode_ == UiMode::kNone);
   } else if (HasActiveInternalDisplay() &&
              (LidAngleIsInTabletModeRange() || tablet_mode_switch_is_on_)) {
     // If we are currently in clamshell mode, the intenral input events should
diff --git a/ash/wm/tablet_mode/tablet_mode_controller_unittest.cc b/ash/wm/tablet_mode/tablet_mode_controller_unittest.cc
index 1231a2c..c7d13eb 100644
--- a/ash/wm/tablet_mode/tablet_mode_controller_unittest.cc
+++ b/ash/wm/tablet_mode/tablet_mode_controller_unittest.cc
@@ -724,11 +724,7 @@
 TEST_F(TabletModeControllerTest, CannotEnterTabletModeWithExternalMouse) {
   // Set the current list of devices to empty so that they don't interfere
   // with the test.
-  // TODO(sammiequon): Investigate whether RunUntilIdle() calls like this one
-  // are really necessary. Remove them or add a comment explaining the purpose.
-  base::RunLoop().RunUntilIdle();
   ws::InputDeviceClientTestApi().SetMouseDevices({});
-  base::RunLoop().RunUntilIdle();
 
   OpenLidToAngle(300.0f);
   EXPECT_TRUE(IsTabletModeStarted());
@@ -739,7 +735,6 @@
   // Attach a external mouse.
   ws::InputDeviceClientTestApi().SetMouseDevices(
       {ui::InputDevice(3, ui::InputDeviceType::INPUT_DEVICE_USB, "mouse")});
-  base::RunLoop().RunUntilIdle();
   EXPECT_FALSE(IsTabletModeStarted());
 
   // Open lid to tent mode. Verify that tablet mode is not started.
@@ -752,9 +747,7 @@
 TEST_F(TabletModeControllerTest, LeaveTabletModeWhenExternalMouseConnected) {
   // Set the current list of devices to empty so that they don't interfere
   // with the test.
-  base::RunLoop().RunUntilIdle();
   ws::InputDeviceClientTestApi().SetMouseDevices({});
-  base::RunLoop().RunUntilIdle();
 
   // Start in tablet mode.
   OpenLidToAngle(300.0f);
@@ -765,13 +758,11 @@
   // events are still blocked because the keyboard is still facing the bottom.
   ws::InputDeviceClientTestApi().SetMouseDevices(
       {ui::InputDevice(3, ui::InputDeviceType::INPUT_DEVICE_USB, "mouse")});
-  base::RunLoop().RunUntilIdle();
   EXPECT_FALSE(IsTabletModeStarted());
   EXPECT_TRUE(AreEventsBlocked());
 
   // Verify that after unplugging the mouse, tablet mode will resume.
   ws::InputDeviceClientTestApi().SetMouseDevices({});
-  base::RunLoop().RunUntilIdle();
   EXPECT_TRUE(IsTabletModeStarted());
   EXPECT_TRUE(AreEventsBlocked());
 }
@@ -781,9 +772,7 @@
 TEST_F(TabletModeControllerTest, ExternalMouseInLaptopMode) {
   // Set the current list of devices to empty so that they don't interfere
   // with the test.
-  base::RunLoop().RunUntilIdle();
   ws::InputDeviceClientTestApi().SetMouseDevices({});
-  base::RunLoop().RunUntilIdle();
 
   // Start in laptop mode.
   OpenLidToAngle(30.0f);
@@ -793,14 +782,12 @@
   // Attach external mouse doesn't change the mode.
   ws::InputDeviceClientTestApi().SetMouseDevices(
       {ui::InputDevice(3, ui::InputDeviceType::INPUT_DEVICE_USB, "mouse")});
-  base::RunLoop().RunUntilIdle();
   EXPECT_FALSE(IsTabletModeStarted());
   EXPECT_FALSE(AreEventsBlocked());
 
   // Now remove the external mouse. It still should maintain in laptop mode
   // because its lid angle is still in laptop mode.
   ws::InputDeviceClientTestApi().SetMouseDevices({});
-  base::RunLoop().RunUntilIdle();
   EXPECT_FALSE(IsTabletModeStarted());
   EXPECT_FALSE(AreEventsBlocked());
 }
@@ -822,7 +809,6 @@
   // Set the current list of devices with an external mouse.
   ws::InputDeviceClientTestApi().SetMouseDevices(
       {ui::InputDevice(3, ui::InputDeviceType::INPUT_DEVICE_USB, "mouse")});
-  base::RunLoop().RunUntilIdle();
 
   // Deactivate internal display to simulate Docked Mode.
   std::vector<display::ManagedDisplayInfo> all_displays;
@@ -843,8 +829,6 @@
 
   // Detach the external mouse.
   ws::InputDeviceClientTestApi().SetMouseDevices({});
-  base::RunLoop().RunUntilIdle();
-
   // Still expect clamshell mode.
   EXPECT_FALSE(IsTabletModeStarted());
 }
@@ -854,9 +838,7 @@
 TEST_F(TabletModeControllerTest, ExternalMouseWithLidAngleTest) {
   // Set the current list of devices to empty so that they don't interfere
   // with the test.
-  base::RunLoop().RunUntilIdle();
   ws::InputDeviceClientTestApi().SetMouseDevices({});
-  base::RunLoop().RunUntilIdle();
 
   // Start in laptop mode.
   OpenLidToAngle(30.0f);
@@ -866,7 +848,6 @@
   // Attach external mouse doesn't change the mode.
   ws::InputDeviceClientTestApi().SetMouseDevices(
       {ui::InputDevice(3, ui::InputDeviceType::INPUT_DEVICE_USB, "mouse")});
-  base::RunLoop().RunUntilIdle();
   EXPECT_FALSE(IsTabletModeStarted());
   EXPECT_FALSE(AreEventsBlocked());
 
@@ -880,14 +861,12 @@
   // Remove the external mouse should enter tablet mode now. The internal input
   // events should still be blocked.
   ws::InputDeviceClientTestApi().SetMouseDevices({});
-  base::RunLoop().RunUntilIdle();
   EXPECT_TRUE(IsTabletModeStarted());
   EXPECT_TRUE(AreEventsBlocked());
 
   // Attach the mouse again should enter clamshell mode again.
   ws::InputDeviceClientTestApi().SetMouseDevices(
       {ui::InputDevice(3, ui::InputDeviceType::INPUT_DEVICE_USB, "mouse")});
-  base::RunLoop().RunUntilIdle();
   EXPECT_FALSE(IsTabletModeStarted());
   EXPECT_TRUE(AreEventsBlocked());
 
@@ -900,7 +879,6 @@
   // Now remove the mouse. The device should stay in clamshell mode and the
   // internal events should not be blocked.
   ws::InputDeviceClientTestApi().SetMouseDevices({});
-  base::RunLoop().RunUntilIdle();
   EXPECT_FALSE(IsTabletModeStarted());
   EXPECT_FALSE(AreEventsBlocked());
 }
@@ -911,9 +889,7 @@
 TEST_F(TabletModeControllerTest, ExternalMouseWithTabletModeSwithTest) {
   // Set the current list of devices to empty so that they don't interfere
   // with the test.
-  base::RunLoop().RunUntilIdle();
   ws::InputDeviceClientTestApi().SetMouseDevices({});
-  base::RunLoop().RunUntilIdle();
 
   // Start in laptop mode.
   SetTabletMode(false);
@@ -923,7 +899,6 @@
   // Attach external mouse doesn't change the mode.
   ws::InputDeviceClientTestApi().SetMouseDevices(
       {ui::InputDevice(3, ui::InputDeviceType::INPUT_DEVICE_USB, "mouse")});
-  base::RunLoop().RunUntilIdle();
   EXPECT_FALSE(IsTabletModeStarted());
   EXPECT_FALSE(AreEventsBlocked());
 
@@ -937,14 +912,12 @@
   // Remove the external mouse should enter tablet mode now. The internal input
   // events should still be blocked.
   ws::InputDeviceClientTestApi().SetMouseDevices({});
-  base::RunLoop().RunUntilIdle();
   EXPECT_TRUE(IsTabletModeStarted());
   EXPECT_TRUE(AreEventsBlocked());
 
   // Attach the mouse again should enter clamshell mode again.
   ws::InputDeviceClientTestApi().SetMouseDevices(
       {ui::InputDevice(3, ui::InputDeviceType::INPUT_DEVICE_USB, "mouse")});
-  base::RunLoop().RunUntilIdle();
   EXPECT_FALSE(IsTabletModeStarted());
   EXPECT_TRUE(AreEventsBlocked());
 
@@ -957,7 +930,6 @@
   // Now remove the mouse. The device should stay in clamshell mode and the
   // internal events should not be blocked.
   ws::InputDeviceClientTestApi().SetMouseDevices({});
-  base::RunLoop().RunUntilIdle();
   EXPECT_FALSE(IsTabletModeStarted());
   EXPECT_FALSE(AreEventsBlocked());
 }
@@ -967,10 +939,8 @@
 TEST_F(TabletModeControllerTest, ExternalTouchPadTest) {
   // Set the current list of devices to empty so that they don't interfere
   // with the test.
-  base::RunLoop().RunUntilIdle();
   ws::InputDeviceClientTestApi().SetMouseDevices({});
   ws::InputDeviceClientTestApi().SetTouchpadDevices({});
-  base::RunLoop().RunUntilIdle();
 
   OpenLidToAngle(300.0f);
   EXPECT_TRUE(IsTabletModeStarted());
@@ -981,7 +951,6 @@
   // Attach a external touchpad.
   ws::InputDeviceClientTestApi().SetTouchpadDevices(
       {ui::InputDevice(3, ui::InputDeviceType::INPUT_DEVICE_USB, "touchpad")});
-  base::RunLoop().RunUntilIdle();
   EXPECT_FALSE(IsTabletModeStarted());
   EXPECT_FALSE(AreEventsBlocked());
 
@@ -992,7 +961,6 @@
 
   // Verify that after unplugging the touchpad, tablet mode will resume.
   ws::InputDeviceClientTestApi().SetTouchpadDevices({});
-  base::RunLoop().RunUntilIdle();
   EXPECT_TRUE(IsTabletModeStarted());
   EXPECT_TRUE(AreEventsBlocked());
 }
@@ -1058,26 +1026,26 @@
 
 // Verify when the force touch view mode flag is turned on, tablet mode is on
 // initially, and opening the lid to less than 180 degress or setting tablet
-// mode to off will not turn off tablet mode.
+// mode to off will not turn off tablet mode. The internal keyboard and trackpad
+// should still work as it makes testing easier.
 TEST_F(TabletModeControllerForceTabletModeTest, ForceTabletModeTest) {
   EXPECT_EQ(TabletModeController::UiMode::kTabletMode, forced_ui_mode());
   EXPECT_TRUE(IsTabletModeStarted());
-  EXPECT_TRUE(AreEventsBlocked());
+  EXPECT_FALSE(AreEventsBlocked());
 
   OpenLidToAngle(30.0f);
   EXPECT_TRUE(IsTabletModeStarted());
-  EXPECT_TRUE(AreEventsBlocked());
+  EXPECT_FALSE(AreEventsBlocked());
 
   SetTabletMode(false);
   EXPECT_TRUE(IsTabletModeStarted());
-  EXPECT_TRUE(AreEventsBlocked());
+  EXPECT_FALSE(AreEventsBlocked());
 
   // Tests that attaching a external mouse will not change the mode.
   ws::InputDeviceClientTestApi().SetMouseDevices(
       {ui::InputDevice(3, ui::InputDeviceType::INPUT_DEVICE_USB, "mouse")});
-  base::RunLoop().RunUntilIdle();
   EXPECT_TRUE(IsTabletModeStarted());
-  EXPECT_TRUE(AreEventsBlocked());
+  EXPECT_FALSE(AreEventsBlocked());
 }
 
 TEST_F(TabletModeControllerForceTabletModeTest, DockInForcedTabletMode) {
diff --git a/base/android/java/src/org/chromium/base/process_launcher/ChildProcessService.java b/base/android/java/src/org/chromium/base/process_launcher/ChildProcessService.java
index 1629c5d..2364197c 100644
--- a/base/android/java/src/org/chromium/base/process_launcher/ChildProcessService.java
+++ b/base/android/java/src/org/chromium/base/process_launcher/ChildProcessService.java
@@ -31,7 +31,6 @@
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.util.List;
-import java.util.concurrent.Semaphore;
 
 import javax.annotation.concurrent.GuardedBy;
 
@@ -89,8 +88,6 @@
     // Only set once in bind(), does not require synchronization.
     private boolean mServiceBound;
 
-    private final Semaphore mActivitySemaphore = new Semaphore(1);
-
     // Interface to send notifications to the parent process.
     private IParentProcess mParentProcess;
 
@@ -276,15 +273,13 @@
                                 "Android.WebView.SplitApkWorkaroundResult",
                                 sSplitApkWorkaroundResult, SplitApkWorkaroundResult.NUM_ENTRIES);
                     }
-                    if (mActivitySemaphore.tryAcquire()) {
-                        mDelegate.runMain();
-                        try {
-                            mParentProcess.reportCleanExit();
-                        } catch (RemoteException e) {
-                            Log.e(TAG, "Failed to call clean exit callback.", e);
-                        }
-                        nativeExitChildProcess();
+                    mDelegate.runMain();
+                    try {
+                        mParentProcess.reportCleanExit();
+                    } catch (RemoteException e) {
+                        Log.e(TAG, "Failed to call clean exit callback.", e);
                     }
+                    nativeExitChildProcess();
                 } catch (InterruptedException e) {
                     Log.w(TAG, "%s startup failed: %s", MAIN_THREAD_NAME, e);
                 }
@@ -297,26 +292,7 @@
     public void onDestroy() {
         super.onDestroy();
         Log.i(TAG, "Destroying ChildProcessService pid=%d", Process.myPid());
-        if (mActivitySemaphore.tryAcquire()) {
-            // TODO(crbug.com/457406): This is a bit hacky, but there is no known better solution
-            // as this service will get reused (at least if not sandboxed).
-            // In fact, we might really want to always exit() from onDestroy(), not just from
-            // the early return here.
-            System.exit(0);
-            return;
-        }
-        synchronized (mLibraryInitializedLock) {
-            try {
-                while (!mLibraryInitialized) {
-                    // Avoid a potential race in calling through to native code before the library
-                    // has loaded.
-                    mLibraryInitializedLock.wait();
-                }
-            } catch (InterruptedException e) {
-                // Ignore
-            }
-        }
-        mDelegate.onDestroy();
+        System.exit(0);
     }
 
     /*
diff --git a/base/android/java/src/org/chromium/base/process_launcher/ChildProcessServiceDelegate.java b/base/android/java/src/org/chromium/base/process_launcher/ChildProcessServiceDelegate.java
index 7beffef..d865823 100644
--- a/base/android/java/src/org/chromium/base/process_launcher/ChildProcessServiceDelegate.java
+++ b/base/android/java/src/org/chromium/base/process_launcher/ChildProcessServiceDelegate.java
@@ -33,13 +33,6 @@
     void onConnectionSetup(Bundle connectionBundle, List<IBinder> clientInterfaces);
 
     /**
-     * Called when the service gets destroyed.
-     * Note that the system might kill the process hosting the service without this method being
-     * called.
-     */
-    void onDestroy();
-
-    /**
      * Called when the delegate should load the native library.
      * @param hostContext The host context the library should be loaded with (i.e. Chrome).
      * @return true if the library was loaded successfully, false otherwise in which case the
diff --git a/base/test/android/java/src/org/chromium/base/MultiprocessTestClientServiceDelegate.java b/base/test/android/java/src/org/chromium/base/MultiprocessTestClientServiceDelegate.java
index 8a63fe8..654863d 100644
--- a/base/test/android/java/src/org/chromium/base/MultiprocessTestClientServiceDelegate.java
+++ b/base/test/android/java/src/org/chromium/base/MultiprocessTestClientServiceDelegate.java
@@ -50,9 +50,6 @@
     }
 
     @Override
-    public void onDestroy() {}
-
-    @Override
     public void preloadNativeLibrary(Context hostContext) {
         LibraryLoader.getInstance().preloadNow();
     }
diff --git a/base/test/android/javatests/src/org/chromium/base/test/util/CallbackHelper.java b/base/test/android/javatests/src/org/chromium/base/test/util/CallbackHelper.java
index 3b9c216..ea8e0b0 100644
--- a/base/test/android/javatests/src/org/chromium/base/test/util/CallbackHelper.java
+++ b/base/test/android/javatests/src/org/chromium/base/test/util/CallbackHelper.java
@@ -166,9 +166,7 @@
      * @param currentCallCount the value obtained by calling getCallCount().
      * @param numberOfCallsToWaitFor number of calls (counting since
      *                               currentCallCount was obtained) that we will wait for.
-     * @param timeout timeout value. We will wait the specified amount of time for a single
-     *                callback to occur so the method call may block up to
-     *                <code>numberOfCallsToWaitFor * timeout</code> units.
+     * @param timeout timeout value for all callbacks to occur.
      * @param unit timeout unit.
      * @throws InterruptedException
      * @throws TimeoutException Thrown if the method times out before onPageFinished is called.
@@ -179,17 +177,17 @@
         assert numberOfCallsToWaitFor > 0;
         synchronized (mLock) {
             int callCountWhenDoneWaiting = currentCallCount + numberOfCallsToWaitFor;
-            while (callCountWhenDoneWaiting > mCallCount) {
-                int callCountBeforeWait = mCallCount;
-                mLock.wait(unit.toMillis(timeout));
+            long deadline = System.currentTimeMillis() + unit.toMillis(timeout);
+            while (callCountWhenDoneWaiting > mCallCount && System.currentTimeMillis() < deadline) {
+                mLock.wait(deadline - System.currentTimeMillis());
                 if (mFailureString != null) {
                     String s = mFailureString;
                     mFailureString = null;
                     Assert.fail(s);
                 }
-                if (callCountBeforeWait == mCallCount) {
-                    throw new TimeoutException(msg == null ? "waitForCallback timed out!" : msg);
-                }
+            }
+            if (callCountWhenDoneWaiting > mCallCount) {
+                throw new TimeoutException(msg == null ? "waitForCallback timed out!" : msg);
             }
         }
     }
diff --git a/base/trace_event/memory_infra_background_whitelist.cc b/base/trace_event/memory_infra_background_whitelist.cc
index f6125dd4..835fc28 100644
--- a/base/trace_event/memory_infra_background_whitelist.cc
+++ b/base/trace_event/memory_infra_background_whitelist.cc
@@ -66,6 +66,7 @@
     "blink_gc/allocated_objects",
     "blink_objects/AdSubframe",
     "blink_objects/AudioHandler",
+    "blink_objects/ContextLifecycleStateObserver",
     "blink_objects/DetachedScriptState",
     "blink_objects/Document",
     "blink_objects/Frame",
@@ -77,7 +78,6 @@
     "blink_objects/Resource",
     "blink_objects/RTCPeerConnection",
     "blink_objects/ScriptPromise",
-    "blink_objects/PausableObject",
     "blink_objects/V8PerContextData",
     "blink_objects/WorkerGlobalScope",
     "blink_objects/UACSSResource",
diff --git a/base/win/scoped_handle.h b/base/win/scoped_handle.h
index 1b630bb..4f9cada 100644
--- a/base/win/scoped_handle.h
+++ b/base/win/scoped_handle.h
@@ -8,6 +8,7 @@
 #include "base/win/windows_types.h"
 
 #include "base/base_export.h"
+#include "base/compiler_specific.h"
 #include "base/gtest_prod_util.h"
 #include "base/location.h"
 #include "base/logging.h"
@@ -84,7 +85,7 @@
   }
 
   // Transfers ownership away from this object.
-  Handle Take() {
+  Handle Take() WARN_UNUSED_RESULT {
     Handle temp = handle_;
     handle_ = Traits::NullHandle();
     if (Traits::IsHandleValid(temp)) {
diff --git a/build/android/gyp/util/md5_check.py b/build/android/gyp/util/md5_check.py
index 7659124..bac22a01 100644
--- a/build/android/gyp/util/md5_check.py
+++ b/build/android/gyp/util/md5_check.py
@@ -52,7 +52,7 @@
       'record paths must end in \'.stamp\' so that they are easy to find '
       'and delete')
 
-  new_metadata = _Metadata()
+  new_metadata = _Metadata(track_entries=pass_changes or PRINT_EXPLANATIONS)
   new_metadata.AddStrings(input_strings)
 
   for path in input_paths:
@@ -222,7 +222,12 @@
 
 
 class _Metadata(object):
-  """Data model for tracking change metadata."""
+  """Data model for tracking change metadata.
+
+  Args:
+    track_entries: Enables per-file change tracking. Slower, but required for
+        Changes functionality.
+  """
   # Schema:
   # {
   #   "files-md5": "VALUE",
@@ -241,7 +246,8 @@
   #   ],
   #   "input-strings": ["a", "b", ...],
   # }
-  def __init__(self):
+  def __init__(self, track_entries=False):
+    self._track_entries = track_entries
     self._files_md5 = None
     self._strings_md5 = None
     self._files = []
@@ -256,18 +262,20 @@
     obj = json.load(fileobj)
     ret._files_md5 = obj['files-md5']
     ret._strings_md5 = obj['strings-md5']
-    ret._files = obj['input-files']
-    ret._strings = obj['input-strings']
+    ret._files = obj.get('input-files', [])
+    ret._strings = obj.get('input-strings', [])
     return ret
 
   def ToFile(self, fileobj):
     """Serializes metadata to the given file object."""
     obj = {
-        "files-md5": self.FilesMd5(),
-        "strings-md5": self.StringsMd5(),
-        "input-files": self._files,
-        "input-strings": self._strings,
+        'files-md5': self.FilesMd5(),
+        'strings-md5': self.StringsMd5(),
     }
+    if self._track_entries:
+      obj['input-files'] = sorted(self._files, key=lambda e: e['path'])
+      obj['input-strings'] = self._strings
+
     json.dump(obj, fileobj, indent=2)
 
   def _AssertNotQueried(self):
diff --git a/build/android/gyp/util/md5_check_test.py b/build/android/gyp/util/md5_check_test.py
index 312d4a9..75ddf3e 100755
--- a/build/android/gyp/util/md5_check_test.py
+++ b/build/android/gyp/util/md5_check_test.py
@@ -119,7 +119,10 @@
     CheckCallAndRecord(True, 'removing a string should trigger call')
 
     input_strings.append('a brand new string')
-    CheckCallAndRecord(True, 'added input string should trigger call')
+    CheckCallAndRecord(
+        True,
+        'added input string should trigger call',
+        added_or_modified_only=False)
 
     _WriteZipFile(input_file2.name, [('path/1.txt', '1')])
     CheckCallAndRecord(True, 'added subpath should trigger call',
diff --git a/cc/layers/recording_source.cc b/cc/layers/recording_source.cc
index 66c44cc..6e65259 100644
--- a/cc/layers/recording_source.cc
+++ b/cc/layers/recording_source.cc
@@ -128,10 +128,6 @@
   requires_clear_ = requires_clear;
 }
 
-const DisplayItemList* RecordingSource::GetDisplayItemList() {
-  return display_list_.get();
-}
-
 scoped_refptr<RasterSource> RecordingSource::CreateRasterSource() const {
   return scoped_refptr<RasterSource>(new RasterSource(this));
 }
diff --git a/cc/layers/recording_source.h b/cc/layers/recording_source.h
index 674b96d7..7469a11 100644
--- a/cc/layers/recording_source.h
+++ b/cc/layers/recording_source.h
@@ -55,9 +55,6 @@
   // These functions are virtual for testing.
   virtual scoped_refptr<RasterSource> CreateRasterSource() const;
 
-  const DisplayItemList* GetDisplayItemList();
-  gfx::Rect recorded_viewport() const { return recorded_viewport_; }
-
   bool is_solid_color() const { return is_solid_color_; }
 
  protected:
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 2537a63..74410f9 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ChromeFeatureList.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ChromeFeatureList.java
@@ -267,6 +267,7 @@
     public static final String OMNIBOX_HIDE_TRIVIAL_SUBDOMAINS_IN_STEADY_STATE =
             "OmniboxUIExperimentHideSteadyStateUrlTrivialSubdomains";
     public static final String OMNIBOX_NEW_ANSWER_LAYOUT = "OmniboxNewAnswerLayout";
+    public static final String OMNIBOX_RICH_ENTITY_SUGGESTIONS = "OmniboxRichEntitySuggestions";
     public static final String OMNIBOX_SPARE_RENDERER = "OmniboxSpareRenderer";
     public static final String OMNIBOX_VOICE_SEARCH_ALWAYS_VISIBLE =
             "OmniboxVoiceSearchAlwaysVisible";
diff --git a/chrome/app/chrome_watcher_command_line_win_unittest.cc b/chrome/app/chrome_watcher_command_line_win_unittest.cc
index bea3c79..6cf783d 100644
--- a/chrome/app/chrome_watcher_command_line_win_unittest.cc
+++ b/chrome/app/chrome_watcher_command_line_win_unittest.cc
@@ -8,6 +8,7 @@
 
 #include "base/command_line.h"
 #include "base/files/file_path.h"
+#include "base/macros.h"
 #include "base/process/process.h"
 #include "base/process/process_handle.h"
 #include "base/win/scoped_handle.h"
@@ -36,8 +37,8 @@
   // the same handle. This function allows the generator handles to be released
   // before they are subsequently claimed by an interpreter.
   void ReleaseHandlesWithoutClosing() {
-    on_initialized_event_handle_.Take();
-    parent_process_handle_.Take();
+    ignore_result(on_initialized_event_handle_.Take());
+    ignore_result(parent_process_handle_.Take());
   }
 };
 
diff --git a/chrome/browser/BUILD.gn b/chrome/browser/BUILD.gn
index b796f38..da171f6 100644
--- a/chrome/browser/BUILD.gn
+++ b/chrome/browser/BUILD.gn
@@ -950,6 +950,8 @@
     "page_load_metrics/observers/ad_metrics/frame_data.h",
     "page_load_metrics/observers/amp_page_load_metrics_observer.cc",
     "page_load_metrics/observers/amp_page_load_metrics_observer.h",
+    "page_load_metrics/observers/amp_ukm_observer.cc",
+    "page_load_metrics/observers/amp_ukm_observer.h",
     "page_load_metrics/observers/core_page_load_metrics_observer.cc",
     "page_load_metrics/observers/core_page_load_metrics_observer.h",
     "page_load_metrics/observers/data_reduction_proxy_metrics_observer.cc",
@@ -1032,8 +1034,6 @@
     "page_load_metrics/page_load_metrics_util.h",
     "page_load_metrics/page_load_tracker.cc",
     "page_load_metrics/page_load_tracker.h",
-    "page_load_metrics/user_input_tracker.cc",
-    "page_load_metrics/user_input_tracker.h",
     "password_manager/chrome_password_manager_client.cc",
     "password_manager/chrome_password_manager_client.h",
     "password_manager/password_manager_util_linux.cc",
@@ -3565,8 +3565,6 @@
   if (is_desktop_linux) {
     # Desktop linux, doesn't count ChromeOS.
     sources += [
-      "dbus/dbus_thread_linux.cc",
-      "dbus/dbus_thread_linux.h",
       "first_run/upgrade_util.cc",
       "first_run/upgrade_util_linux.cc",
       "first_run/upgrade_util_linux.h",
@@ -3578,6 +3576,10 @@
       "shell_integration_linux.h",
     ]
 
+    if (use_dbus) {
+      deps += [ "//components/dbus:dbus_thread_linux" ]
+    }
+
     if (enable_native_notifications) {
       sources += [
         "notifications/notification_platform_bridge_linux.cc",
diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc
index c1795082..c39994d 100644
--- a/chrome/browser/about_flags.cc
+++ b/chrome/browser/about_flags.cc
@@ -2983,6 +2983,11 @@
      FEATURE_VALUE_TYPE(omnibox::kOmniboxNewAnswerLayout)},
 #endif  // defined(OS_ANDROID)
 
+    {"omnibox-rich-entity-suggestions",
+     flag_descriptions::kOmniboxRichEntitySuggestionsName,
+     flag_descriptions::kOmniboxRichEntitySuggestionsDescription, kOsAll,
+     FEATURE_VALUE_TYPE(omnibox::kOmniboxRichEntitySuggestions)},
+
 #if defined(OS_LINUX) || defined(OS_MACOSX) || defined(OS_WIN)
     {"omnibox-experimental-keyword-mode",
      flag_descriptions::kOmniboxExperimentalKeywordModeName,
@@ -2991,10 +2996,6 @@
     {"omnibox-reverse-answers", flag_descriptions::kOmniboxReverseAnswersName,
      flag_descriptions::kOmniboxReverseAnswersDescription, kOsDesktop,
      FEATURE_VALUE_TYPE(omnibox::kOmniboxReverseAnswers)},
-    {"omnibox-rich-entity-suggestions",
-     flag_descriptions::kOmniboxRichEntitySuggestionsName,
-     flag_descriptions::kOmniboxRichEntitySuggestionsDescription, kOsDesktop,
-     FEATURE_VALUE_TYPE(omnibox::kOmniboxRichEntitySuggestions)},
     {"omnibox-tail-suggestions", flag_descriptions::kOmniboxTailSuggestionsName,
      flag_descriptions::kOmniboxTailSuggestionsDescription, kOsDesktop,
      FEATURE_VALUE_TYPE(omnibox::kOmniboxTailSuggestions)},
@@ -4011,12 +4012,8 @@
      flag_descriptions::kVaapiJpegImageDecodeAccelerationName,
      flag_descriptions::kVaapiJpegImageDecodeAccelerationDescription, kOsCrOS,
      FEATURE_VALUE_TYPE(features::kVaapiJpegImageDecodeAcceleration)},
-
-    {"enable-home-launcher-gestures",
-     flag_descriptions::kEnableHomeLauncherGesturesName,
-     flag_descriptions::kEnableHomeLauncherGesturesDescription, kOsCrOS,
-     FEATURE_VALUE_TYPE(app_list_features::kEnableHomeLauncherGestures)},
 #endif
+
 #if defined(OS_WIN)
     {"calculate-native-win-occlusion",
      flag_descriptions::kCalculateNativeWinOcclusionName,
diff --git a/chrome/browser/android/chrome_feature_list.cc b/chrome/browser/android/chrome_feature_list.cc
index 121ee89..09eaf12 100644
--- a/chrome/browser/android/chrome_feature_list.cc
+++ b/chrome/browser/android/chrome_feature_list.cc
@@ -85,7 +85,6 @@
     &features::kWebPayments,
     &feed::kInterestFeedContentSuggestions,
     &invalidation::switches::kFCMInvalidations,
-    &omnibox::kOmniboxNewAnswerLayout,
     &kAdjustWebApkInstallationSpace,
     &kAllowRemoteContextForNotifications,
     &kAndroidNightMode,
@@ -184,6 +183,8 @@
     &offline_pages::kPrefetchingOfflinePagesFeature,
     &omnibox::kHideSteadyStateUrlScheme,
     &omnibox::kHideSteadyStateUrlTrivialSubdomains,
+    &omnibox::kOmniboxNewAnswerLayout,
+    &omnibox::kOmniboxRichEntitySuggestions,
     &omnibox::kQueryInOmnibox,
     &password_manager::features::kGooglePasswordManager,
     &password_manager::features::kPasswordsKeyboardAccessory,
diff --git a/chrome/browser/android/signin/signin_manager_android_unittest.cc b/chrome/browser/android/signin/signin_manager_android_unittest.cc
index 859a3bf..a0d9ff4 100644
--- a/chrome/browser/android/signin/signin_manager_android_unittest.cc
+++ b/chrome/browser/android/signin/signin_manager_android_unittest.cc
@@ -30,6 +30,7 @@
 #include "content/public/browser/storage_partition.h"
 #include "content/public/test/test_browser_thread_bundle.h"
 #include "testing/gtest/include/gtest/gtest.h"
+#include "url/origin.h"
 
 namespace {
 
@@ -134,15 +135,14 @@
   // TODO(crbug.com/929456): This helper is not attached anywhere to
   // be able to observe deletions.
   // Add service workers.
-  scoped_refptr<CannedBrowsingDataCacheStorageHelper> helper(
-      new CannedBrowsingDataCacheStorageHelper(
-          content::BrowserContext::GetDefaultStoragePartition(profile())
-              ->GetCacheStorageContext()));
+  auto helper = base::MakeRefCounted<CannedBrowsingDataCacheStorageHelper>(
+      content::BrowserContext::GetDefaultStoragePartition(profile())
+          ->GetCacheStorageContext());
 
   for (const TestCase& test_case : kTestCases)
-    helper->AddCacheStorage(GURL(test_case.worker_url));
+    helper->Add(url::Origin::Create(GURL(test_case.worker_url)));
 
-  ASSERT_EQ(base::size(kTestCases), helper->GetCacheStorageCount());
+  ASSERT_EQ(base::size(kTestCases), helper->GetCount());
 
   // Delete service workers and wait for completion.
   base::RunLoop run_loop;
@@ -152,14 +152,14 @@
   run_loop.Run();
 
   // Test whether the correct service worker caches were deleted.
-  std::set<std::string> remaining_cache_storages;
-  for (const auto& info : helper->GetCacheStorageUsageInfo())
-    remaining_cache_storages.insert(info.origin.spec());
+  std::set<url::Origin> remaining_cache_storages = helper->GetOrigins();
 
   // TODO(crbug.com/929456): If deleted, the key should not be present.
   for (const TestCase& test_case : kTestCases) {
-    EXPECT_EQ(test_case.should_be_deleted,
-              base::ContainsKey(remaining_cache_storages, test_case.worker_url))
+    EXPECT_EQ(
+        test_case.should_be_deleted,
+        base::ContainsKey(remaining_cache_storages,
+                          url::Origin::Create(GURL(test_case.worker_url))))
         << test_case.worker_url << " should "
         << (test_case.should_be_deleted ? "" : "NOT ")
         << "be deleted, but it was"
diff --git a/chrome/browser/browsing_data/browsing_data_cache_storage_helper.cc b/chrome/browser/browsing_data/browsing_data_cache_storage_helper.cc
index 8713eab..750a3ec 100644
--- a/chrome/browser/browsing_data/browsing_data_cache_storage_helper.cc
+++ b/chrome/browser/browsing_data/browsing_data_cache_storage_helper.cc
@@ -4,6 +4,7 @@
 
 #include "chrome/browser/browsing_data/browsing_data_cache_storage_helper.h"
 
+#include <utility>
 #include <vector>
 
 #include "base/bind.h"
@@ -81,52 +82,34 @@
   cache_storage_context_->DeleteForOrigin(origin);
 }
 
-CannedBrowsingDataCacheStorageHelper::PendingCacheStorageUsageInfo::
-    PendingCacheStorageUsageInfo(const GURL& origin,
-                                 int64_t total_size_bytes,
-                                 const base::Time& last_modified)
-    : origin(origin),
-      total_size_bytes(total_size_bytes),
-      last_modified(last_modified) {}
-
-CannedBrowsingDataCacheStorageHelper::PendingCacheStorageUsageInfo::
-    ~PendingCacheStorageUsageInfo() {}
-
-bool CannedBrowsingDataCacheStorageHelper::PendingCacheStorageUsageInfo::
-operator<(const PendingCacheStorageUsageInfo& other) const {
-  return origin < other.origin;
-}
-
 CannedBrowsingDataCacheStorageHelper::CannedBrowsingDataCacheStorageHelper(
     content::CacheStorageContext* context)
     : BrowsingDataCacheStorageHelper(context) {}
 
 CannedBrowsingDataCacheStorageHelper::~CannedBrowsingDataCacheStorageHelper() {}
 
-void CannedBrowsingDataCacheStorageHelper::AddCacheStorage(const GURL& origin) {
-  if (!BrowsingDataHelper::HasWebScheme(origin))
+void CannedBrowsingDataCacheStorageHelper::Add(const url::Origin& origin) {
+  if (!BrowsingDataHelper::HasWebScheme(origin.GetURL()))
     return;  // Non-websafe state is not considered browsing data.
 
-  pending_cache_storage_info_.insert(
-      PendingCacheStorageUsageInfo(origin, 0, base::Time()));
+  pending_origins_.insert(origin);
 }
 
 void CannedBrowsingDataCacheStorageHelper::Reset() {
-  pending_cache_storage_info_.clear();
+  pending_origins_.clear();
 }
 
 bool CannedBrowsingDataCacheStorageHelper::empty() const {
-  return pending_cache_storage_info_.empty();
+  return pending_origins_.empty();
 }
 
-size_t CannedBrowsingDataCacheStorageHelper::GetCacheStorageCount() const {
-  return pending_cache_storage_info_.size();
+size_t CannedBrowsingDataCacheStorageHelper::GetCount() const {
+  return pending_origins_.size();
 }
 
-const std::set<
-    CannedBrowsingDataCacheStorageHelper::PendingCacheStorageUsageInfo>&
-CannedBrowsingDataCacheStorageHelper::GetCacheStorageUsageInfo() const {
-  return pending_cache_storage_info_;
+const std::set<url::Origin>& CannedBrowsingDataCacheStorageHelper::GetOrigins()
+    const {
+  return pending_origins_;
 }
 
 void CannedBrowsingDataCacheStorageHelper::StartFetching(
@@ -135,13 +118,8 @@
   DCHECK(!callback.is_null());
 
   std::list<StorageUsageInfo> result;
-  for (const PendingCacheStorageUsageInfo& pending_info :
-       pending_cache_storage_info_) {
-    StorageUsageInfo info(url::Origin::Create(pending_info.origin),
-                          pending_info.total_size_bytes,
-                          pending_info.last_modified);
-    result.push_back(info);
-  }
+  for (const auto& origin : pending_origins_)
+    result.emplace_back(origin, 0, base::Time());
 
   base::PostTaskWithTraits(FROM_HERE, {BrowserThread::UI},
                            base::BindOnce(std::move(callback), result));
@@ -149,12 +127,6 @@
 
 void CannedBrowsingDataCacheStorageHelper::DeleteCacheStorage(
     const GURL& origin) {
-  for (auto it = pending_cache_storage_info_.begin();
-       it != pending_cache_storage_info_.end();) {
-    if (it->origin == origin)
-      pending_cache_storage_info_.erase(it++);
-    else
-      ++it;
-  }
+  pending_origins_.erase(url::Origin::Create(origin));
   BrowsingDataCacheStorageHelper::DeleteCacheStorage(origin);
 }
diff --git a/chrome/browser/browsing_data/browsing_data_cache_storage_helper.h b/chrome/browser/browsing_data/browsing_data_cache_storage_helper.h
index 458930e..8be5f29 100644
--- a/chrome/browser/browsing_data/browsing_data_cache_storage_helper.h
+++ b/chrome/browser/browsing_data/browsing_data_cache_storage_helper.h
@@ -17,6 +17,7 @@
 #include "base/time/time.h"
 #include "content/public/browser/cache_storage_context.h"
 #include "url/gurl.h"
+#include "url/origin.h"
 
 namespace content {
 struct StorageUsageInfo;
@@ -64,30 +65,16 @@
 
 // This class is an implementation of BrowsingDataCacheStorageHelper that does
 // not fetch its information from the Cache Storage context, but is passed the
-// info as a parameter.
+// info by a call when accessed.
 class CannedBrowsingDataCacheStorageHelper
     : public BrowsingDataCacheStorageHelper {
  public:
-  // Contains information about a Cache Storage.
-  struct PendingCacheStorageUsageInfo {
-    PendingCacheStorageUsageInfo(const GURL& origin,
-                                 int64_t total_size_bytes,
-                                 const base::Time& last_modified);
-    ~PendingCacheStorageUsageInfo();
-
-    bool operator<(const PendingCacheStorageUsageInfo& other) const;
-
-    GURL origin;
-    int64_t total_size_bytes;
-    base::Time last_modified;
-  };
-
   explicit CannedBrowsingDataCacheStorageHelper(
       content::CacheStorageContext* context);
 
   // Add a Cache Storage to the set of canned Cache Storages that is
   // returned by this helper.
-  void AddCacheStorage(const GURL& origin);
+  void Add(const url::Origin& origin);
 
   // Clear the list of canned Cache Storages.
   void Reset();
@@ -96,12 +83,10 @@
   bool empty() const;
 
   // Returns the number of currently stored Cache Storages.
-  size_t GetCacheStorageCount() const;
+  size_t GetCount() const;
 
   // Returns the current list of Cache Storages.
-  const std::set<
-      CannedBrowsingDataCacheStorageHelper::PendingCacheStorageUsageInfo>&
-  GetCacheStorageUsageInfo() const;
+  const std::set<url::Origin>& GetOrigins() const;
 
   // BrowsingDataCacheStorageHelper methods.
   void StartFetching(FetchCallback callback) override;
@@ -110,7 +95,7 @@
  private:
   ~CannedBrowsingDataCacheStorageHelper() override;
 
-  std::set<PendingCacheStorageUsageInfo> pending_cache_storage_info_;
+  std::set<url::Origin> pending_origins_;
 
   DISALLOW_COPY_AND_ASSIGN(CannedBrowsingDataCacheStorageHelper);
 };
diff --git a/chrome/browser/browsing_data/browsing_data_cache_storage_helper_browsertest.cc b/chrome/browser/browsing_data/browsing_data_cache_storage_helper_browsertest.cc
index a7d4888..2a6a697 100644
--- a/chrome/browser/browsing_data/browsing_data_cache_storage_helper_browsertest.cc
+++ b/chrome/browser/browsing_data/browsing_data_cache_storage_helper_browsertest.cc
@@ -38,8 +38,8 @@
 
   scoped_refptr<CannedBrowsingDataCacheStorageHelper> helper(
       new CannedBrowsingDataCacheStorageHelper(CacheStorageContext()));
-  helper->AddCacheStorage(origin1);
-  helper->AddCacheStorage(origin2);
+  helper->Add(url::Origin::Create(origin1));
+  helper->Add(url::Origin::Create(origin2));
 
   TestCompletionCallback callback;
   helper->StartFetching(base::Bind(&TestCompletionCallback::callback,
@@ -59,8 +59,8 @@
 
   scoped_refptr<CannedBrowsingDataCacheStorageHelper> helper(
       new CannedBrowsingDataCacheStorageHelper(CacheStorageContext()));
-  helper->AddCacheStorage(origin);
-  helper->AddCacheStorage(origin);
+  helper->Add(url::Origin::Create(origin));
+  helper->Add(url::Origin::Create(origin));
 
   TestCompletionCallback callback;
   helper->StartFetching(base::Bind(&TestCompletionCallback::callback,
diff --git a/chrome/browser/browsing_data/browsing_data_cache_storage_helper_unittest.cc b/chrome/browser/browsing_data/browsing_data_cache_storage_helper_unittest.cc
index dfa38b4..5453e15 100644
--- a/chrome/browser/browsing_data/browsing_data_cache_storage_helper_unittest.cc
+++ b/chrome/browser/browsing_data/browsing_data_cache_storage_helper_unittest.cc
@@ -33,7 +33,7 @@
       new CannedBrowsingDataCacheStorageHelper(CacheStorageContext()));
 
   ASSERT_TRUE(helper->empty());
-  helper->AddCacheStorage(origin);
+  helper->Add(url::Origin::Create(origin));
   ASSERT_FALSE(helper->empty());
   helper->Reset();
   ASSERT_TRUE(helper->empty());
@@ -47,12 +47,12 @@
       new CannedBrowsingDataCacheStorageHelper(CacheStorageContext()));
 
   EXPECT_TRUE(helper->empty());
-  helper->AddCacheStorage(origin1);
-  helper->AddCacheStorage(origin2);
-  helper->AddCacheStorage(origin2);
-  EXPECT_EQ(2u, helper->GetCacheStorageCount());
+  helper->Add(url::Origin::Create(origin1));
+  helper->Add(url::Origin::Create(origin2));
+  helper->Add(url::Origin::Create(origin2));
+  EXPECT_EQ(2u, helper->GetCount());
   helper->DeleteCacheStorage(origin2);
-  EXPECT_EQ(1u, helper->GetCacheStorageCount());
+  EXPECT_EQ(1u, helper->GetCount());
 }
 
 TEST_F(CannedBrowsingDataCacheStorageHelperTest, IgnoreExtensionsAndDevTools) {
@@ -63,9 +63,9 @@
       new CannedBrowsingDataCacheStorageHelper(CacheStorageContext()));
 
   ASSERT_TRUE(helper->empty());
-  helper->AddCacheStorage(origin1);
+  helper->Add(url::Origin::Create(origin1));
   ASSERT_TRUE(helper->empty());
-  helper->AddCacheStorage(origin2);
+  helper->Add(url::Origin::Create(origin2));
   ASSERT_TRUE(helper->empty());
 }
 
diff --git a/chrome/browser/browsing_data/browsing_data_database_helper.cc b/chrome/browser/browsing_data/browsing_data_database_helper.cc
index 48715b8d..8fe08c7b 100644
--- a/chrome/browser/browsing_data/browsing_data_database_helper.cc
+++ b/chrome/browser/browsing_data/browsing_data_database_helper.cc
@@ -73,47 +73,35 @@
           tracker_, origin, net::CompletionCallback()));
 }
 
-CannedBrowsingDataDatabaseHelper::PendingDatabaseInfo::PendingDatabaseInfo(
-    const GURL& origin)
-    : origin(origin) {}
-
-CannedBrowsingDataDatabaseHelper::PendingDatabaseInfo::~PendingDatabaseInfo() {}
-
-bool CannedBrowsingDataDatabaseHelper::PendingDatabaseInfo::operator<(
-    const PendingDatabaseInfo& other) const {
-  return origin < other.origin;
-}
-
 CannedBrowsingDataDatabaseHelper::CannedBrowsingDataDatabaseHelper(
     Profile* profile)
     : BrowsingDataDatabaseHelper(profile) {
 }
 
-void CannedBrowsingDataDatabaseHelper::AddDatabase(const GURL& origin) {
+void CannedBrowsingDataDatabaseHelper::Add(const url::Origin& origin) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
-  if (!BrowsingDataHelper::HasWebScheme(origin))
+  if (!BrowsingDataHelper::HasWebScheme(origin.GetURL()))
     return;  // Non-websafe state is not considered browsing data.
-  pending_database_info_.insert(PendingDatabaseInfo(origin));
+  pending_origins_.insert(origin);
 }
 
 void CannedBrowsingDataDatabaseHelper::Reset() {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
-  pending_database_info_.clear();
+  pending_origins_.clear();
 }
 
 bool CannedBrowsingDataDatabaseHelper::empty() const {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
-  return pending_database_info_.empty();
+  return pending_origins_.empty();
 }
 
-size_t CannedBrowsingDataDatabaseHelper::GetDatabaseCount() const {
+size_t CannedBrowsingDataDatabaseHelper::GetCount() const {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
-  return pending_database_info_.size();
+  return pending_origins_.size();
 }
 
-const std::set<CannedBrowsingDataDatabaseHelper::PendingDatabaseInfo>&
-CannedBrowsingDataDatabaseHelper::GetPendingDatabaseInfo() {
-  return pending_database_info_;
+const std::set<url::Origin>& CannedBrowsingDataDatabaseHelper::GetOrigins() {
+  return pending_origins_;
 }
 
 void CannedBrowsingDataDatabaseHelper::StartFetching(FetchCallback callback) {
@@ -121,9 +109,8 @@
   DCHECK(!callback.is_null());
 
   std::list<StorageUsageInfo> result;
-  for (const PendingDatabaseInfo& info : pending_database_info_) {
-    result.push_back(content::StorageUsageInfo(url::Origin::Create(info.origin),
-                                               0, base::Time()));
+  for (const auto& origin : pending_origins_) {
+    result.emplace_back(origin, 0, base::Time());
   }
 
   base::PostTaskWithTraits(FROM_HERE, {BrowserThread::UI},
@@ -132,11 +119,7 @@
 
 void CannedBrowsingDataDatabaseHelper::DeleteDatabase(
     const url::Origin& origin) {
-  GURL origin_url = origin.GetURL();
-  base::EraseIf(pending_database_info_,
-                [&origin_url](const PendingDatabaseInfo& info) {
-                  return info.origin == origin_url;
-                });
+  pending_origins_.erase(origin);
   BrowsingDataDatabaseHelper::DeleteDatabase(origin);
 }
 
diff --git a/chrome/browser/browsing_data/browsing_data_database_helper.h b/chrome/browser/browsing_data/browsing_data_database_helper.h
index b700c15..712bc12c 100644
--- a/chrome/browser/browsing_data/browsing_data_database_helper.h
+++ b/chrome/browser/browsing_data/browsing_data_database_helper.h
@@ -19,6 +19,7 @@
 #include "storage/browser/database/database_tracker.h"
 #include "storage/common/database/database_identifier.h"
 #include "url/gurl.h"
+#include "url/origin.h"
 
 namespace content {
 struct StorageUsageInfo;
@@ -59,26 +60,15 @@
 };
 
 // This class is a thin wrapper around BrowsingDataDatabaseHelper that does not
-// fetch its information from the database tracker, but gets them passed as
-// a parameter during construction.
+// fetch its information from the database tracker, but gets them passed by
+// a call when accessed.
 class CannedBrowsingDataDatabaseHelper : public BrowsingDataDatabaseHelper {
  public:
-  // TODO(jsbell): Replace this struct with just url::Origin.
-  struct PendingDatabaseInfo {
-    explicit PendingDatabaseInfo(const GURL& origin);
-    ~PendingDatabaseInfo();
-
-    // The operator is needed to store |PendingDatabaseInfo| objects in a set.
-    bool operator<(const PendingDatabaseInfo& other) const;
-
-    GURL origin;
-  };
-
   explicit CannedBrowsingDataDatabaseHelper(Profile* profile);
 
   // Add a database to the set of canned databases that is returned by this
   // helper.
-  void AddDatabase(const GURL& origin);
+  void Add(const url::Origin& origin);
 
   // Clear the list of canned databases.
   void Reset();
@@ -87,10 +77,10 @@
   bool empty() const;
 
   // Returns the number of currently stored databases.
-  size_t GetDatabaseCount() const;
+  size_t GetCount() const;
 
   // Returns the current list of web databases.
-  const std::set<PendingDatabaseInfo>& GetPendingDatabaseInfo();
+  const std::set<url::Origin>& GetOrigins();
 
   // BrowsingDataDatabaseHelper implementation.
   void StartFetching(FetchCallback callback) override;
@@ -99,7 +89,7 @@
  private:
   ~CannedBrowsingDataDatabaseHelper() override;
 
-  std::set<PendingDatabaseInfo> pending_database_info_;
+  std::set<url::Origin> pending_origins_;
 
   DISALLOW_COPY_AND_ASSIGN(CannedBrowsingDataDatabaseHelper);
 };
diff --git a/chrome/browser/browsing_data/browsing_data_database_helper_browsertest.cc b/chrome/browser/browsing_data/browsing_data_database_helper_browsertest.cc
index 43c18586..c20e4b4 100644
--- a/chrome/browser/browsing_data/browsing_data_database_helper_browsertest.cc
+++ b/chrome/browser/browsing_data/browsing_data_database_helper_browsertest.cc
@@ -91,9 +91,9 @@
 
   scoped_refptr<CannedBrowsingDataDatabaseHelper> helper(
       new CannedBrowsingDataDatabaseHelper(browser()->profile()));
-  helper->AddDatabase(origin1.GetURL());
-  helper->AddDatabase(origin1.GetURL());
-  helper->AddDatabase(origin2.GetURL());
+  helper->Add(origin1);
+  helper->Add(origin1);
+  helper->Add(origin2);
 
   TestCompletionCallback callback;
   helper->StartFetching(
@@ -114,8 +114,8 @@
 
   scoped_refptr<CannedBrowsingDataDatabaseHelper> helper(
       new CannedBrowsingDataDatabaseHelper(browser()->profile()));
-  helper->AddDatabase(origin.GetURL());
-  helper->AddDatabase(origin.GetURL());
+  helper->Add(origin);
+  helper->Add(origin);
 
   TestCompletionCallback callback;
   helper->StartFetching(
diff --git a/chrome/browser/browsing_data/browsing_data_database_helper_unittest.cc b/chrome/browser/browsing_data/browsing_data_database_helper_unittest.cc
index 55090ff4..ad548ec 100644
--- a/chrome/browser/browsing_data/browsing_data_database_helper_unittest.cc
+++ b/chrome/browser/browsing_data/browsing_data_database_helper_unittest.cc
@@ -26,7 +26,7 @@
       new CannedBrowsingDataDatabaseHelper(&profile));
 
   ASSERT_TRUE(helper->empty());
-  helper->AddDatabase(origin);
+  helper->Add(url::Origin::Create(origin));
   ASSERT_FALSE(helper->empty());
   helper->Reset();
   ASSERT_TRUE(helper->empty());
@@ -43,14 +43,14 @@
       new CannedBrowsingDataDatabaseHelper(&profile));
 
   EXPECT_TRUE(helper->empty());
-  helper->AddDatabase(origin1);
-  helper->AddDatabase(origin2);
-  helper->AddDatabase(origin3);
-  EXPECT_EQ(3u, helper->GetDatabaseCount());
+  helper->Add(url::Origin::Create(origin1));
+  helper->Add(url::Origin::Create(origin2));
+  helper->Add(url::Origin::Create(origin3));
+  EXPECT_EQ(3u, helper->GetCount());
   helper->DeleteDatabase(url::Origin::Create(origin2));
-  EXPECT_EQ(2u, helper->GetDatabaseCount());
+  EXPECT_EQ(2u, helper->GetCount());
   helper->DeleteDatabase(url::Origin::Create(origin2));
-  EXPECT_EQ(2u, helper->GetDatabaseCount());
+  EXPECT_EQ(2u, helper->GetCount());
 }
 
 TEST_F(CannedBrowsingDataDatabaseHelperTest, IgnoreExtensionsAndDevTools) {
@@ -63,9 +63,9 @@
       new CannedBrowsingDataDatabaseHelper(&profile));
 
   ASSERT_TRUE(helper->empty());
-  helper->AddDatabase(origin1);
+  helper->Add(url::Origin::Create(origin1));
   ASSERT_TRUE(helper->empty());
-  helper->AddDatabase(origin2);
+  helper->Add(url::Origin::Create(origin2));
   ASSERT_TRUE(helper->empty());
   helper->Reset();
   ASSERT_TRUE(helper->empty());
diff --git a/chrome/browser/browsing_data/browsing_data_file_system_helper.cc b/chrome/browser/browsing_data/browsing_data_file_system_helper.cc
index a724ce4..3f2f035 100644
--- a/chrome/browser/browsing_data/browsing_data_file_system_helper.cc
+++ b/chrome/browser/browsing_data/browsing_data_file_system_helper.cc
@@ -5,7 +5,7 @@
 #include "chrome/browser/browsing_data/browsing_data_file_system_helper.h"
 
 #include <memory>
-#include <set>
+#include <utility>
 
 #include "base/bind.h"
 #include "base/location.h"
@@ -165,52 +165,34 @@
 
 CannedBrowsingDataFileSystemHelper::~CannedBrowsingDataFileSystemHelper() {}
 
-void CannedBrowsingDataFileSystemHelper::AddFileSystem(
-    const url::Origin& origin,
-    const storage::FileSystemType type,
-    const int64_t size) {
+void CannedBrowsingDataFileSystemHelper::Add(const url::Origin& origin) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
-  // This canned implementation of AddFileSystem uses an O(n^2) algorithm; which
-  // is fine, as it isn't meant for use in a high-volume context. If it turns
-  // out that we want to start using this in a context with many, many origins,
-  // we should think about reworking the implementation.
-  bool duplicate_origin = false;
-  for (FileSystemInfo& file_system : file_system_info_) {
-    if (file_system.origin == origin) {
-      file_system.usage_map[type] = size;
-      duplicate_origin = true;
-      break;
-    }
-  }
-  if (duplicate_origin)
-    return;
-
   if (!BrowsingDataHelper::HasWebScheme(origin.GetURL()))
     return;  // Non-websafe state is not considered browsing data.
-
-  FileSystemInfo info(origin);
-  info.usage_map[type] = size;
-  file_system_info_.push_back(info);
+  pending_origins_.insert(origin);
 }
 
 void CannedBrowsingDataFileSystemHelper::Reset() {
-  file_system_info_.clear();
+  pending_origins_.clear();
 }
 
 bool CannedBrowsingDataFileSystemHelper::empty() const {
-  return file_system_info_.empty();
+  return pending_origins_.empty();
 }
 
-size_t CannedBrowsingDataFileSystemHelper::GetFileSystemCount() const {
+size_t CannedBrowsingDataFileSystemHelper::GetCount() const {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
-  return file_system_info_.size();
+  return pending_origins_.size();
 }
 
 void CannedBrowsingDataFileSystemHelper::StartFetching(FetchCallback callback) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
   DCHECK(!callback.is_null());
 
-  base::PostTaskWithTraits(
-      FROM_HERE, {BrowserThread::UI},
-      base::BindOnce(std::move(callback), file_system_info_));
+  std::list<FileSystemInfo> result;
+  for (const auto& origin : pending_origins_)
+    result.emplace_back(origin);
+
+  base::PostTaskWithTraits(FROM_HERE, {BrowserThread::UI},
+                           base::BindOnce(std::move(callback), result));
 }
diff --git a/chrome/browser/browsing_data/browsing_data_file_system_helper.h b/chrome/browser/browsing_data/browsing_data_file_system_helper.h
index 85a0fe2..acb0688 100644
--- a/chrome/browser/browsing_data/browsing_data_file_system_helper.h
+++ b/chrome/browser/browsing_data/browsing_data_file_system_helper.h
@@ -10,6 +10,7 @@
 
 #include <list>
 #include <map>
+#include <set>
 
 #include "base/callback.h"
 #include "base/macros.h"
@@ -89,7 +90,8 @@
 
 // An implementation of the BrowsingDataFileSystemHelper interface that can
 // be manually populated with data, rather than fetching data from the file
-// systems created in a particular Profile.
+// systems created in a particular Profile. Only kTemporary file systems
+// are supported.
 class CannedBrowsingDataFileSystemHelper
     : public BrowsingDataFileSystemHelper {
  public:
@@ -98,12 +100,8 @@
   explicit CannedBrowsingDataFileSystemHelper(Profile* profile);
 
   // Manually adds a filesystem to the set of canned file systems that this
-  // helper returns via StartFetching. If an origin contains both a temporary
-  // and a persistent filesystem, AddFileSystem must be called twice (once for
-  // each file system type).
-  void AddFileSystem(const url::Origin& origin,
-                     storage::FileSystemType type,
-                     int64_t size);
+  // helper returns via StartFetching.
+  void Add(const url::Origin& origin);
 
   // Clear this helper's list of canned filesystems.
   void Reset();
@@ -112,12 +110,10 @@
   bool empty() const;
 
   // Returns the number of currently stored filesystems.
-  size_t GetFileSystemCount() const;
+  size_t GetCount() const;
 
   // Returns the current list of filesystems.
-  const std::list<FileSystemInfo>& GetFileSystemInfo() {
-    return file_system_info_;
-  }
+  const std::set<url::Origin>& GetOrigins() const { return pending_origins_; }
 
   // BrowsingDataFileSystemHelper implementation.
   void StartFetching(FetchCallback callback) override;
@@ -132,7 +128,7 @@
   ~CannedBrowsingDataFileSystemHelper() override;
 
   // Holds the current list of filesystems returned to the client.
-  std::list<FileSystemInfo> file_system_info_;
+  std::set<url::Origin> pending_origins_;
 
   DISALLOW_COPY_AND_ASSIGN(CannedBrowsingDataFileSystemHelper);
 };
diff --git a/chrome/browser/browsing_data/browsing_data_file_system_helper_unittest.cc b/chrome/browser/browsing_data/browsing_data_file_system_helper_unittest.cc
index 0c75dea..40c1ed0 100644
--- a/chrome/browser/browsing_data/browsing_data_file_system_helper_unittest.cc
+++ b/chrome/browser/browsing_data/browsing_data_file_system_helper_unittest.cc
@@ -2,10 +2,11 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "testing/gtest/include/gtest/gtest.h"
-
 #include <stddef.h>
 
+#include <memory>
+#include <string>
+
 #include "base/bind.h"
 #include "base/bind_helpers.h"
 #include "base/files/file_util.h"
@@ -21,6 +22,7 @@
 #include "storage/browser/fileapi/file_system_context.h"
 #include "storage/browser/fileapi/file_system_url.h"
 #include "storage/common/fileapi/file_system_types.h"
+#include "testing/gtest/include/gtest/gtest.h"
 
 using content::BrowserContext;
 using content::BrowserThread;
@@ -82,9 +84,9 @@
   }
 
   // Blocks on the run_loop quits.
-  void BlockUntilQuit(base::RunLoop& run_loop) {
-    run_loop.Run();                               // Won't return until Quit().
-    content::RunAllTasksUntilIdle();              // Flush other runners.
+  void BlockUntilQuit(base::RunLoop* run_loop) {
+    run_loop->Run();                  // Won't return until Quit().
+    content::RunAllTasksUntilIdle();  // Flush other runners.
   }
 
   // Callback that should be executed in response to
@@ -108,7 +110,7 @@
             base::Bind(
                 &BrowsingDataFileSystemHelperTest::OpenFileSystemCallback,
                 base::Unretained(this), &run_loop));
-    BlockUntilQuit(run_loop);
+    BlockUntilQuit(&run_loop);
     return open_file_system_result_ == base::File::FILE_OK;
   }
 
@@ -142,7 +144,7 @@
     helper_->StartFetching(
         base::Bind(&BrowsingDataFileSystemHelperTest::CallbackStartFetching,
                    base::Unretained(this), &run_loop));
-    BlockUntilQuit(run_loop);
+    BlockUntilQuit(&run_loop);
   }
 
   // Calls StartFetching() on the test's CannedBrowsingDataFileSystemHelper
@@ -152,7 +154,7 @@
     canned_helper_->StartFetching(
         base::Bind(&BrowsingDataFileSystemHelperTest::CallbackStartFetching,
                    base::Unretained(this), &run_loop));
-    BlockUntilQuit(run_loop);
+    BlockUntilQuit(&run_loop);
   }
 
   // Sets up kOrigin1 with a temporary file system, kOrigin2 with a persistent
@@ -266,41 +268,39 @@
 // whether or not it currently contains file systems.
 TEST_F(BrowsingDataFileSystemHelperTest, Empty) {
   ASSERT_TRUE(canned_helper_->empty());
-  canned_helper_->AddFileSystem(kOrigin1, kTemporary, 0);
+  canned_helper_->Add(kOrigin1);
   ASSERT_FALSE(canned_helper_->empty());
   canned_helper_->Reset();
   ASSERT_TRUE(canned_helper_->empty());
 }
 
-// Verifies that AddFileSystem correctly adds file systems, and that both
-// the type and usage metadata are reported as provided.
+// Verifies that AddFileSystem correctly adds file systems. The canned helper
+// does not record usage size.
 TEST_F(BrowsingDataFileSystemHelperTest, CannedAddFileSystem) {
-  canned_helper_->AddFileSystem(kOrigin1, kPersistent, 200);
-  canned_helper_->AddFileSystem(kOrigin2, kTemporary, 100);
+  canned_helper_->Add(kOrigin1);
+  canned_helper_->Add(kOrigin2);
 
   FetchCannedFileSystems();
 
   EXPECT_EQ(2U, file_system_info_list_->size());
   auto info = file_system_info_list_->begin();
   EXPECT_EQ(kOrigin1, info->origin);
-  EXPECT_TRUE(base::ContainsKey(info->usage_map, kPersistent));
+  EXPECT_FALSE(base::ContainsKey(info->usage_map, kPersistent));
   EXPECT_FALSE(base::ContainsKey(info->usage_map, kTemporary));
-  EXPECT_EQ(200, info->usage_map[kPersistent]);
 
   info++;
   EXPECT_EQ(kOrigin2, info->origin);
   EXPECT_FALSE(base::ContainsKey(info->usage_map, kPersistent));
-  EXPECT_TRUE(base::ContainsKey(info->usage_map, kTemporary));
-  EXPECT_EQ(100, info->usage_map[kTemporary]);
+  EXPECT_FALSE(base::ContainsKey(info->usage_map, kTemporary));
 }
 
 // Verifies that the CannedBrowsingDataFileSystemHelper correctly ignores
 // extension and devtools schemes.
 TEST_F(BrowsingDataFileSystemHelperTest, IgnoreExtensionsAndDevTools) {
   ASSERT_TRUE(canned_helper_->empty());
-  canned_helper_->AddFileSystem(kOriginExt, kTemporary, 0);
+  canned_helper_->Add(kOriginExt);
   ASSERT_TRUE(canned_helper_->empty());
-  canned_helper_->AddFileSystem(kOriginDevTools, kTemporary, 0);
+  canned_helper_->Add(kOriginDevTools);
   ASSERT_TRUE(canned_helper_->empty());
 }
 
diff --git a/chrome/browser/browsing_data/browsing_data_indexed_db_helper.cc b/chrome/browser/browsing_data/browsing_data_indexed_db_helper.cc
index ea346bfc..7f33f56 100644
--- a/chrome/browser/browsing_data/browsing_data_indexed_db_helper.cc
+++ b/chrome/browser/browsing_data/browsing_data_indexed_db_helper.cc
@@ -5,6 +5,7 @@
 #include "chrome/browser/browsing_data/browsing_data_indexed_db_helper.h"
 
 #include <tuple>
+#include <utility>
 #include <vector>
 
 #include "base/bind.h"
@@ -72,19 +73,6 @@
   indexed_db_context_->DeleteForOrigin(url::Origin::Create(origin));
 }
 
-CannedBrowsingDataIndexedDBHelper::PendingIndexedDBInfo::PendingIndexedDBInfo(
-    const GURL& origin)
-    : origin(origin) {}
-
-CannedBrowsingDataIndexedDBHelper::
-PendingIndexedDBInfo::~PendingIndexedDBInfo() {
-}
-
-bool CannedBrowsingDataIndexedDBHelper::PendingIndexedDBInfo::operator<(
-    const PendingIndexedDBInfo& other) const {
-  return origin < other.origin;
-}
-
 CannedBrowsingDataIndexedDBHelper::CannedBrowsingDataIndexedDBHelper(
     content::IndexedDBContext* context)
     : BrowsingDataIndexedDBHelper(context) {
@@ -92,28 +80,28 @@
 
 CannedBrowsingDataIndexedDBHelper::~CannedBrowsingDataIndexedDBHelper() {}
 
-void CannedBrowsingDataIndexedDBHelper::AddIndexedDB(const GURL& origin) {
-  if (!BrowsingDataHelper::HasWebScheme(origin))
+void CannedBrowsingDataIndexedDBHelper::Add(const url::Origin& origin) {
+  if (!BrowsingDataHelper::HasWebScheme(origin.GetURL()))
     return;  // Non-websafe state is not considered browsing data.
 
-  pending_indexed_db_info_.insert(PendingIndexedDBInfo(origin));
+  pending_origins_.insert(origin);
 }
 
 void CannedBrowsingDataIndexedDBHelper::Reset() {
-  pending_indexed_db_info_.clear();
+  pending_origins_.clear();
 }
 
 bool CannedBrowsingDataIndexedDBHelper::empty() const {
-  return pending_indexed_db_info_.empty();
+  return pending_origins_.empty();
 }
 
-size_t CannedBrowsingDataIndexedDBHelper::GetIndexedDBCount() const {
-  return pending_indexed_db_info_.size();
+size_t CannedBrowsingDataIndexedDBHelper::GetCount() const {
+  return pending_origins_.size();
 }
 
-const std::set<CannedBrowsingDataIndexedDBHelper::PendingIndexedDBInfo>&
-CannedBrowsingDataIndexedDBHelper::GetIndexedDBInfo() const  {
-  return pending_indexed_db_info_;
+const std::set<url::Origin>& CannedBrowsingDataIndexedDBHelper::GetOrigins()
+    const {
+  return pending_origins_;
 }
 
 void CannedBrowsingDataIndexedDBHelper::StartFetching(FetchCallback callback) {
@@ -121,9 +109,8 @@
   DCHECK(!callback.is_null());
 
   std::list<StorageUsageInfo> result;
-  for (const PendingIndexedDBInfo& pending_info : pending_indexed_db_info_)
-    result.emplace_back(url::Origin::Create(pending_info.origin), 0,
-                        base::Time());
+  for (const auto& origin : pending_origins_)
+    result.emplace_back(origin, 0, base::Time());
 
   base::PostTaskWithTraits(FROM_HERE, {BrowserThread::UI},
                            base::BindOnce(std::move(callback), result));
@@ -131,12 +118,6 @@
 
 void CannedBrowsingDataIndexedDBHelper::DeleteIndexedDB(
     const GURL& origin) {
-  for (auto it = pending_indexed_db_info_.begin();
-       it != pending_indexed_db_info_.end();) {
-    if (it->origin == origin)
-      pending_indexed_db_info_.erase(it++);
-    else
-      ++it;
-  }
+  pending_origins_.erase(url::Origin::Create(origin));
   BrowsingDataIndexedDBHelper::DeleteIndexedDB(origin);
 }
diff --git a/chrome/browser/browsing_data/browsing_data_indexed_db_helper.h b/chrome/browser/browsing_data/browsing_data_indexed_db_helper.h
index 346cf18..d7daeb2 100644
--- a/chrome/browser/browsing_data/browsing_data_indexed_db_helper.h
+++ b/chrome/browser/browsing_data/browsing_data_indexed_db_helper.h
@@ -16,6 +16,7 @@
 #include "base/strings/string16.h"
 #include "content/public/browser/indexed_db_context.h"
 #include "url/gurl.h"
+#include "url/origin.h"
 
 namespace content {
 struct StorageUsageInfo;
@@ -59,27 +60,17 @@
 };
 
 // This class is an implementation of BrowsingDataIndexedDBHelper that does
-// not fetch its information from the indexed database tracker, but gets them
-// passed as a parameter.
+// not fetch its information from the Indexed DB context, but gets them
+// passed by a call when accessed.
 class CannedBrowsingDataIndexedDBHelper
     : public BrowsingDataIndexedDBHelper {
  public:
-  // Contains information about an indexed database.
-  struct PendingIndexedDBInfo {
-    explicit PendingIndexedDBInfo(const GURL& origin);
-    ~PendingIndexedDBInfo();
-
-    bool operator<(const PendingIndexedDBInfo& other) const;
-
-    GURL origin;
-  };
-
   explicit CannedBrowsingDataIndexedDBHelper(
       content::IndexedDBContext* context);
 
   // Add a indexed database to the set of canned indexed databases that is
   // returned by this helper.
-  void AddIndexedDB(const GURL& origin);
+  void Add(const url::Origin& origin);
 
   // Clear the list of canned indexed databases.
   void Reset();
@@ -88,11 +79,10 @@
   bool empty() const;
 
   // Returns the number of currently stored indexed databases.
-  size_t GetIndexedDBCount() const;
+  size_t GetCount() const;
 
   // Returns the current list of indexed data bases.
-  const std::set<CannedBrowsingDataIndexedDBHelper::PendingIndexedDBInfo>&
-      GetIndexedDBInfo() const;
+  const std::set<url::Origin>& GetOrigins() const;
 
   // BrowsingDataIndexedDBHelper methods.
   void StartFetching(FetchCallback callback) override;
@@ -101,7 +91,7 @@
  private:
   ~CannedBrowsingDataIndexedDBHelper() override;
 
-  std::set<PendingIndexedDBInfo> pending_indexed_db_info_;
+  std::set<url::Origin> pending_origins_;
 
   DISALLOW_COPY_AND_ASSIGN(CannedBrowsingDataIndexedDBHelper);
 };
diff --git a/chrome/browser/browsing_data/browsing_data_indexed_db_helper_browsertest.cc b/chrome/browser/browsing_data/browsing_data_indexed_db_helper_browsertest.cc
index c753960..dbbfd03 100644
--- a/chrome/browser/browsing_data/browsing_data_indexed_db_helper_browsertest.cc
+++ b/chrome/browser/browsing_data/browsing_data_indexed_db_helper_browsertest.cc
@@ -36,8 +36,8 @@
 
   scoped_refptr<CannedBrowsingDataIndexedDBHelper> helper(
       new CannedBrowsingDataIndexedDBHelper(IndexedDBContext()));
-  helper->AddIndexedDB(origin1);
-  helper->AddIndexedDB(origin2);
+  helper->Add(url::Origin::Create(origin1));
+  helper->Add(url::Origin::Create(origin2));
 
   TestCompletionCallback callback;
   helper->StartFetching(
@@ -58,8 +58,8 @@
 
   scoped_refptr<CannedBrowsingDataIndexedDBHelper> helper(
       new CannedBrowsingDataIndexedDBHelper(IndexedDBContext()));
-  helper->AddIndexedDB(origin);
-  helper->AddIndexedDB(origin);
+  helper->Add(url::Origin::Create(origin));
+  helper->Add(url::Origin::Create(origin));
 
   TestCompletionCallback callback;
   helper->StartFetching(
diff --git a/chrome/browser/browsing_data/browsing_data_indexed_db_helper_unittest.cc b/chrome/browser/browsing_data/browsing_data_indexed_db_helper_unittest.cc
index e6b49282..7d5f803 100644
--- a/chrome/browser/browsing_data/browsing_data_indexed_db_helper_unittest.cc
+++ b/chrome/browser/browsing_data/browsing_data_indexed_db_helper_unittest.cc
@@ -32,7 +32,7 @@
       new CannedBrowsingDataIndexedDBHelper(IndexedDBContext()));
 
   ASSERT_TRUE(helper->empty());
-  helper->AddIndexedDB(origin);
+  helper->Add(url::Origin::Create(origin));
   ASSERT_FALSE(helper->empty());
   helper->Reset();
   ASSERT_TRUE(helper->empty());
@@ -46,11 +46,11 @@
       new CannedBrowsingDataIndexedDBHelper(IndexedDBContext()));
 
   EXPECT_TRUE(helper->empty());
-  helper->AddIndexedDB(origin1);
-  helper->AddIndexedDB(origin2);
-  EXPECT_EQ(2u, helper->GetIndexedDBCount());
+  helper->Add(url::Origin::Create(origin1));
+  helper->Add(url::Origin::Create(origin2));
+  EXPECT_EQ(2u, helper->GetCount());
   helper->DeleteIndexedDB(origin2);
-  EXPECT_EQ(1u, helper->GetIndexedDBCount());
+  EXPECT_EQ(1u, helper->GetCount());
 }
 
 TEST_F(CannedBrowsingDataIndexedDBHelperTest, IgnoreExtensionsAndDevTools) {
@@ -61,9 +61,9 @@
       new CannedBrowsingDataIndexedDBHelper(IndexedDBContext()));
 
   ASSERT_TRUE(helper->empty());
-  helper->AddIndexedDB(origin1);
+  helper->Add(url::Origin::Create(origin1));
   ASSERT_TRUE(helper->empty());
-  helper->AddIndexedDB(origin2);
+  helper->Add(url::Origin::Create(origin2));
   ASSERT_TRUE(helper->empty());
 }
 
diff --git a/chrome/browser/browsing_data/browsing_data_local_storage_helper.cc b/chrome/browser/browsing_data/browsing_data_local_storage_helper.cc
index 585e9b2..3fae278 100644
--- a/chrome/browser/browsing_data/browsing_data_local_storage_helper.cc
+++ b/chrome/browser/browsing_data/browsing_data_local_storage_helper.cc
@@ -79,29 +79,27 @@
     : BrowsingDataLocalStorageHelper(profile) {
 }
 
-void CannedBrowsingDataLocalStorageHelper::AddLocalStorage(
-    const GURL& origin_url) {
-  if (!HasStorageScheme(origin_url))
+void CannedBrowsingDataLocalStorageHelper::Add(const url::Origin& origin) {
+  if (!HasStorageScheme(origin.GetURL()))
     return;
-  pending_local_storage_info_.insert(origin_url);
-  url::Origin origin = url::Origin::Create(origin_url);
+  pending_origins_.insert(origin);
 }
 
 void CannedBrowsingDataLocalStorageHelper::Reset() {
-  pending_local_storage_info_.clear();
+  pending_origins_.clear();
 }
 
 bool CannedBrowsingDataLocalStorageHelper::empty() const {
-  return pending_local_storage_info_.empty();
+  return pending_origins_.empty();
 }
 
-size_t CannedBrowsingDataLocalStorageHelper::GetLocalStorageCount() const {
-  return pending_local_storage_info_.size();
+size_t CannedBrowsingDataLocalStorageHelper::GetCount() const {
+  return pending_origins_.size();
 }
 
-const std::set<GURL>&
-CannedBrowsingDataLocalStorageHelper::GetLocalStorageInfo() const {
-  return pending_local_storage_info_;
+const std::set<url::Origin>& CannedBrowsingDataLocalStorageHelper::GetOrigins()
+    const {
+  return pending_origins_;
 }
 
 void CannedBrowsingDataLocalStorageHelper::StartFetching(
@@ -110,9 +108,8 @@
   DCHECK(!callback.is_null());
 
   std::list<content::StorageUsageInfo> result;
-  for (const GURL& url : pending_local_storage_info_)
-    result.push_back(
-        content::StorageUsageInfo(url::Origin::Create(url), 0, base::Time()));
+  for (const auto& origin : pending_origins_)
+    result.emplace_back(origin, 0, base::Time());
 
   base::PostTaskWithTraits(FROM_HERE, {BrowserThread::UI},
                            base::BindOnce(std::move(callback), result));
@@ -121,7 +118,7 @@
 void CannedBrowsingDataLocalStorageHelper::DeleteOrigin(
     const url::Origin& origin,
     base::OnceClosure callback) {
-  pending_local_storage_info_.erase(origin.GetURL());
+  pending_origins_.erase(origin);
   BrowsingDataLocalStorageHelper::DeleteOrigin(origin, std::move(callback));
 }
 
diff --git a/chrome/browser/browsing_data/browsing_data_local_storage_helper.h b/chrome/browser/browsing_data/browsing_data_local_storage_helper.h
index 60ac51f..09368b8 100644
--- a/chrome/browser/browsing_data/browsing_data_local_storage_helper.h
+++ b/chrome/browser/browsing_data/browsing_data_local_storage_helper.h
@@ -19,7 +19,7 @@
 #include "base/time/time.h"
 #include "content/public/browser/dom_storage_context.h"
 #include "content/public/browser/storage_usage_info.h"
-#include "url/gurl.h"
+#include "url/origin.h"
 
 class Profile;
 
@@ -54,8 +54,8 @@
 };
 
 // This class is a thin wrapper around BrowsingDataLocalStorageHelper that does
-// not fetch its information from the local storage tracker, but gets them
-// passed as a parameter during construction.
+// not fetch its information from the local storage context, but gets them
+// passed by a call when accessed.
 class CannedBrowsingDataLocalStorageHelper
     : public BrowsingDataLocalStorageHelper {
  public:
@@ -63,7 +63,7 @@
 
   // Add a local storage to the set of canned local storages that is returned
   // by this helper.
-  void AddLocalStorage(const GURL& origin_url);
+  void Add(const url::Origin& origin_url);
 
   // Clear the list of canned local storages.
   void Reset();
@@ -72,10 +72,10 @@
   bool empty() const;
 
   // Returns the number of local storages currently stored.
-  size_t GetLocalStorageCount() const;
+  size_t GetCount() const;
 
   // Returns the set of origins that use local storage.
-  const std::set<GURL>& GetLocalStorageInfo() const;
+  const std::set<url::Origin>& GetOrigins() const;
 
   // BrowsingDataLocalStorageHelper implementation.
   void StartFetching(FetchCallback callback) override;
@@ -85,7 +85,7 @@
  private:
   ~CannedBrowsingDataLocalStorageHelper() override;
 
-  std::set<GURL> pending_local_storage_info_;
+  std::set<url::Origin> pending_origins_;
 
   DISALLOW_COPY_AND_ASSIGN(CannedBrowsingDataLocalStorageHelper);
 };
diff --git a/chrome/browser/browsing_data/browsing_data_local_storage_helper_browsertest.cc b/chrome/browser/browsing_data/browsing_data_local_storage_helper_browsertest.cc
index f2d2f5f..fa1be426 100644
--- a/chrome/browser/browsing_data/browsing_data_local_storage_helper_browsertest.cc
+++ b/chrome/browser/browsing_data/browsing_data_local_storage_helper_browsertest.cc
@@ -153,8 +153,8 @@
 
   scoped_refptr<CannedBrowsingDataLocalStorageHelper> helper(
       new CannedBrowsingDataLocalStorageHelper(browser()->profile()));
-  helper->AddLocalStorage(origin1);
-  helper->AddLocalStorage(origin2);
+  helper->Add(url::Origin::Create(origin1));
+  helper->Add(url::Origin::Create(origin2));
 
   TestCompletionCallback callback;
   helper->StartFetching(
@@ -175,8 +175,8 @@
 
   scoped_refptr<CannedBrowsingDataLocalStorageHelper> helper(
       new CannedBrowsingDataLocalStorageHelper(browser()->profile()));
-  helper->AddLocalStorage(origin);
-  helper->AddLocalStorage(origin);
+  helper->Add(url::Origin::Create(origin));
+  helper->Add(url::Origin::Create(origin));
 
   TestCompletionCallback callback;
   helper->StartFetching(
diff --git a/chrome/browser/browsing_data/browsing_data_local_storage_helper_unittest.cc b/chrome/browser/browsing_data/browsing_data_local_storage_helper_unittest.cc
index 5c48df9..8bbb4f8 100644
--- a/chrome/browser/browsing_data/browsing_data_local_storage_helper_unittest.cc
+++ b/chrome/browser/browsing_data/browsing_data_local_storage_helper_unittest.cc
@@ -24,7 +24,7 @@
       new CannedBrowsingDataLocalStorageHelper(&profile));
 
   ASSERT_TRUE(helper->empty());
-  helper->AddLocalStorage(origin);
+  helper->Add(url::Origin::Create(origin));
   ASSERT_FALSE(helper->empty());
   helper->Reset();
   ASSERT_TRUE(helper->empty());
@@ -41,14 +41,14 @@
       new CannedBrowsingDataLocalStorageHelper(&profile));
 
   EXPECT_TRUE(helper->empty());
-  helper->AddLocalStorage(origin1);
-  helper->AddLocalStorage(origin2);
-  helper->AddLocalStorage(origin3);
-  EXPECT_EQ(3u, helper->GetLocalStorageCount());
+  helper->Add(url::Origin::Create(origin1));
+  helper->Add(url::Origin::Create(origin2));
+  helper->Add(url::Origin::Create(origin3));
+  EXPECT_EQ(3u, helper->GetCount());
   helper->DeleteOrigin(url::Origin::Create(origin2), base::DoNothing());
-  EXPECT_EQ(2u, helper->GetLocalStorageCount());
+  EXPECT_EQ(2u, helper->GetCount());
   helper->DeleteOrigin(url::Origin::Create(origin1), base::DoNothing());
-  EXPECT_EQ(1u, helper->GetLocalStorageCount());
+  EXPECT_EQ(1u, helper->GetCount());
 }
 
 TEST_F(CannedBrowsingDataLocalStorageTest, IgnoreExtensionsAndDevTools) {
@@ -61,9 +61,9 @@
       new CannedBrowsingDataLocalStorageHelper(&profile));
 
   ASSERT_TRUE(helper->empty());
-  helper->AddLocalStorage(origin1);
+  helper->Add(url::Origin::Create(origin1));
   ASSERT_TRUE(helper->empty());
-  helper->AddLocalStorage(origin2);
+  helper->Add(url::Origin::Create(origin2));
   ASSERT_TRUE(helper->empty());
 }
 
diff --git a/chrome/browser/browsing_data/browsing_data_service_worker_helper.cc b/chrome/browser/browsing_data/browsing_data_service_worker_helper.cc
index 92add64a..bb1a3ed1 100644
--- a/chrome/browser/browsing_data/browsing_data_service_worker_helper.cc
+++ b/chrome/browser/browsing_data/browsing_data_service_worker_helper.cc
@@ -5,6 +5,7 @@
 #include "chrome/browser/browsing_data/browsing_data_service_worker_helper.h"
 
 #include <tuple>
+#include <utility>
 #include <vector>
 
 #include "base/bind.h"
@@ -84,25 +85,6 @@
   service_worker_context_->DeleteForOrigin(origin, base::DoNothing());
 }
 
-CannedBrowsingDataServiceWorkerHelper::PendingServiceWorkerUsageInfo::
-    PendingServiceWorkerUsageInfo(const GURL& origin,
-                                  const std::vector<GURL>& scopes)
-    : origin(origin), scopes(scopes) {
-}
-
-CannedBrowsingDataServiceWorkerHelper::PendingServiceWorkerUsageInfo::
-    PendingServiceWorkerUsageInfo(const PendingServiceWorkerUsageInfo& other) =
-        default;
-
-CannedBrowsingDataServiceWorkerHelper::PendingServiceWorkerUsageInfo::
-    ~PendingServiceWorkerUsageInfo() {
-}
-
-bool CannedBrowsingDataServiceWorkerHelper::PendingServiceWorkerUsageInfo::
-operator<(const PendingServiceWorkerUsageInfo& other) const {
-  return std::tie(origin, scopes) < std::tie(other.origin, other.scopes);
-}
-
 CannedBrowsingDataServiceWorkerHelper::CannedBrowsingDataServiceWorkerHelper(
     content::ServiceWorkerContext* context)
     : BrowsingDataServiceWorkerHelper(context) {
@@ -112,31 +94,28 @@
     ~CannedBrowsingDataServiceWorkerHelper() {
 }
 
-void CannedBrowsingDataServiceWorkerHelper::AddServiceWorker(
-    const GURL& origin, const std::vector<GURL>& scopes) {
-  if (!BrowsingDataHelper::HasWebScheme(origin))
+void CannedBrowsingDataServiceWorkerHelper::Add(const url::Origin& origin) {
+  if (!BrowsingDataHelper::HasWebScheme(origin.GetURL()))
     return;  // Non-websafe state is not considered browsing data.
 
-  pending_service_worker_info_.insert(
-      PendingServiceWorkerUsageInfo(origin, scopes));
+  pending_origins_.insert(origin);
 }
 
 void CannedBrowsingDataServiceWorkerHelper::Reset() {
-  pending_service_worker_info_.clear();
+  pending_origins_.clear();
 }
 
 bool CannedBrowsingDataServiceWorkerHelper::empty() const {
-  return pending_service_worker_info_.empty();
+  return pending_origins_.empty();
 }
 
-size_t CannedBrowsingDataServiceWorkerHelper::GetServiceWorkerCount() const {
-  return pending_service_worker_info_.size();
+size_t CannedBrowsingDataServiceWorkerHelper::GetCount() const {
+  return pending_origins_.size();
 }
 
-const std::set<
-    CannedBrowsingDataServiceWorkerHelper::PendingServiceWorkerUsageInfo>&
-CannedBrowsingDataServiceWorkerHelper::GetServiceWorkerUsageInfo() const {
-  return pending_service_worker_info_;
+const std::set<url::Origin>& CannedBrowsingDataServiceWorkerHelper::GetOrigins()
+    const {
+  return pending_origins_;
 }
 
 void CannedBrowsingDataServiceWorkerHelper::StartFetching(
@@ -145,11 +124,8 @@
   DCHECK(!callback.is_null());
 
   std::list<StorageUsageInfo> result;
-  for (const PendingServiceWorkerUsageInfo& pending_info :
-       pending_service_worker_info_) {
-    result.emplace_back(url::Origin::Create(pending_info.origin), 0,
-                        base::Time());
-  }
+  for (const auto& origin : pending_origins_)
+    result.emplace_back(origin, 0, base::Time());
 
   base::PostTaskWithTraits(FROM_HERE, {BrowserThread::UI},
                            base::BindOnce(std::move(callback), result));
@@ -157,12 +133,6 @@
 
 void CannedBrowsingDataServiceWorkerHelper::DeleteServiceWorkers(
     const GURL& origin) {
-  for (auto it = pending_service_worker_info_.begin();
-       it != pending_service_worker_info_.end();) {
-    if (it->origin == origin)
-      pending_service_worker_info_.erase(it++);
-    else
-      ++it;
-  }
+  pending_origins_.erase(url::Origin::Create(origin));
   BrowsingDataServiceWorkerHelper::DeleteServiceWorkers(origin);
 }
diff --git a/chrome/browser/browsing_data/browsing_data_service_worker_helper.h b/chrome/browser/browsing_data/browsing_data_service_worker_helper.h
index 2e66fd5..af09453 100644
--- a/chrome/browser/browsing_data/browsing_data_service_worker_helper.h
+++ b/chrome/browser/browsing_data/browsing_data_service_worker_helper.h
@@ -16,6 +16,7 @@
 #include "base/memory/ref_counted.h"
 #include "content/public/browser/service_worker_context.h"
 #include "url/gurl.h"
+#include "url/origin.h"
 
 namespace content {
 struct StorageUsageInfo;
@@ -64,29 +65,16 @@
 
 // This class is an implementation of BrowsingDataServiceWorkerHelper that does
 // not fetch its information from the Service Worker context, but is passed the
-// info as a parameter.
+// info by call when accessed.
 class CannedBrowsingDataServiceWorkerHelper
     : public BrowsingDataServiceWorkerHelper {
  public:
-  // Contains information about a Service Worker.
-  struct PendingServiceWorkerUsageInfo {
-    PendingServiceWorkerUsageInfo(const GURL& origin,
-                                  const std::vector<GURL>& scopes);
-    PendingServiceWorkerUsageInfo(const PendingServiceWorkerUsageInfo& other);
-    ~PendingServiceWorkerUsageInfo();
-
-    bool operator<(const PendingServiceWorkerUsageInfo& other) const;
-
-    GURL origin;
-    std::vector<GURL> scopes;
-  };
-
   explicit CannedBrowsingDataServiceWorkerHelper(
       content::ServiceWorkerContext* context);
 
   // Add a Service Worker to the set of canned Service Workers that is
   // returned by this helper.
-  void AddServiceWorker(const GURL& origin, const std::vector<GURL>& scopes);
+  void Add(const url::Origin& origin);
 
   // Clear the list of canned Service Workers.
   void Reset();
@@ -95,12 +83,10 @@
   bool empty() const;
 
   // Returns the number of currently stored Service Workers.
-  size_t GetServiceWorkerCount() const;
+  size_t GetCount() const;
 
   // Returns the current list of Service Workers.
-  const std::set<
-      CannedBrowsingDataServiceWorkerHelper::PendingServiceWorkerUsageInfo>&
-      GetServiceWorkerUsageInfo() const;
+  const std::set<url::Origin>& GetOrigins() const;
 
   // BrowsingDataServiceWorkerHelper methods.
   void StartFetching(FetchCallback callback) override;
@@ -109,7 +95,7 @@
  private:
   ~CannedBrowsingDataServiceWorkerHelper() override;
 
-  std::set<PendingServiceWorkerUsageInfo> pending_service_worker_info_;
+  std::set<url::Origin> pending_origins_;
 
   DISALLOW_COPY_AND_ASSIGN(CannedBrowsingDataServiceWorkerHelper);
 };
diff --git a/chrome/browser/browsing_data/browsing_data_service_worker_helper_unittest.cc b/chrome/browser/browsing_data/browsing_data_service_worker_helper_unittest.cc
index 202ffe0a..0c6d91b 100644
--- a/chrome/browser/browsing_data/browsing_data_service_worker_helper_unittest.cc
+++ b/chrome/browser/browsing_data/browsing_data_service_worker_helper_unittest.cc
@@ -37,7 +37,7 @@
       new CannedBrowsingDataServiceWorkerHelper(ServiceWorkerContext()));
 
   ASSERT_TRUE(helper->empty());
-  helper->AddServiceWorker(origin, scopes);
+  helper->Add(url::Origin::Create(origin));
   ASSERT_FALSE(helper->empty());
   helper->Reset();
   ASSERT_TRUE(helper->empty());
@@ -57,11 +57,11 @@
       new CannedBrowsingDataServiceWorkerHelper(ServiceWorkerContext()));
 
   EXPECT_TRUE(helper->empty());
-  helper->AddServiceWorker(origin1, scopes1);
-  helper->AddServiceWorker(origin2, scopes2);
-  EXPECT_EQ(2u, helper->GetServiceWorkerCount());
+  helper->Add(url::Origin::Create(origin1));
+  helper->Add(url::Origin::Create(origin2));
+  EXPECT_EQ(2u, helper->GetCount());
   helper->DeleteServiceWorkers(origin2);
-  EXPECT_EQ(1u, helper->GetServiceWorkerCount());
+  EXPECT_EQ(1u, helper->GetCount());
 }
 
 TEST_F(CannedBrowsingDataServiceWorkerHelperTest, IgnoreExtensionsAndDevTools) {
@@ -73,9 +73,9 @@
       new CannedBrowsingDataServiceWorkerHelper(ServiceWorkerContext()));
 
   ASSERT_TRUE(helper->empty());
-  helper->AddServiceWorker(origin1, scopes);
+  helper->Add(url::Origin::Create(origin1));
   ASSERT_TRUE(helper->empty());
-  helper->AddServiceWorker(origin2, scopes);
+  helper->Add(url::Origin::Create(origin2));
   ASSERT_TRUE(helper->empty());
 }
 
diff --git a/chrome/browser/browsing_data/mock_browsing_data_local_storage_helper.cc b/chrome/browser/browsing_data/mock_browsing_data_local_storage_helper.cc
index c55872f..5c0ce5a 100644
--- a/chrome/browser/browsing_data/mock_browsing_data_local_storage_helper.cc
+++ b/chrome/browser/browsing_data/mock_browsing_data_local_storage_helper.cc
@@ -4,10 +4,13 @@
 
 #include "chrome/browser/browsing_data/mock_browsing_data_local_storage_helper.h"
 
+#include <utility>
+
 #include "base/callback.h"
 #include "base/logging.h"
 #include "base/stl_util.h"
 #include "testing/gtest/include/gtest/gtest.h"
+#include "url/gurl.h"
 
 MockBrowsingDataLocalStorageHelper::MockBrowsingDataLocalStorageHelper(
     Profile* profile)
diff --git a/chrome/browser/chromeos/login/signin/oauth2_browsertest.cc b/chrome/browser/chromeos/login/signin/oauth2_browsertest.cc
index 3603371..313a687 100644
--- a/chrome/browser/chromeos/login/signin/oauth2_browsertest.cc
+++ b/chrome/browser/chromeos/login/signin/oauth2_browsertest.cc
@@ -41,7 +41,6 @@
 #include "components/account_id/account_id.h"
 #include "components/browser_sync/browser_sync_switches.h"
 #include "components/prefs/pref_service.h"
-#include "components/signin/core/browser/account_tracker_service.h"
 #include "components/user_manager/user.h"
 #include "components/user_manager/user_manager.h"
 #include "content/public/browser/browser_task_traits.h"
diff --git a/chrome/browser/chromeos/smb_client/smb_service.cc b/chrome/browser/chromeos/smb_client/smb_service.cc
index 027810ac..7e0e2c0f 100644
--- a/chrome/browser/chromeos/smb_client/smb_service.cc
+++ b/chrome/browser/chromeos/smb_client/smb_service.cc
@@ -48,6 +48,7 @@
 const char kModeDropDownValue[] = "drop_down";
 const char kModePreMountValue[] = "pre_mount";
 const char kModeUnknownValue[] = "unknown";
+const base::TimeDelta kHostDiscoveryInterval = base::TimeDelta::FromSeconds(60);
 
 bool ContainsAt(const std::string& username) {
   return username.find('@') != std::string::npos;
@@ -357,6 +358,18 @@
   }
 }
 
+void SmbService::OnHostsDiscoveredForUpdateSharePath(
+    int32_t mount_id,
+    const std::string& share_path,
+    StartReadDirIfSuccessfulCallback reply) {
+  std::string resolved_url;
+  if (share_finder_->TryResolveUrl(SmbUrl(share_path), &resolved_url)) {
+    UpdateSharePath(mount_id, resolved_url, std::move(reply));
+  } else {
+    std::move(reply).Run(false /* should_retry_start_read_dir */);
+  }
+}
+
 void SmbService::Remount(const ProvidedFileSystemInfo& file_system_info) {
   const base::FilePath share_path =
       GetSharePathFromFileSystemId(file_system_info.file_system_id());
@@ -634,7 +647,26 @@
     const std::string& share_path,
     int32_t mount_id,
     StartReadDirIfSuccessfulCallback reply) {
-  NOTREACHED();
+  if (ShouldRunHostDiscoveryAgain()) {
+    previous_host_discovery_time_ = tick_clock_->NowTicks();
+    share_finder_->DiscoverHostsInNetwork(
+        base::BindOnce(&SmbService::OnHostsDiscoveredForUpdateSharePath,
+                       AsWeakPtr(), mount_id, share_path, std::move(reply)));
+    return;
+  }
+  // Host discovery did not run, but try to resolve the hostname in case a
+  // previous host discovery found the host.
+  std::string resolved_url;
+  if (share_finder_->TryResolveUrl(SmbUrl(share_path), &resolved_url)) {
+    UpdateSharePath(mount_id, share_path, std::move(reply));
+  } else {
+    std::move(reply).Run(false /* should_retry_start_read_dir */);
+  }
+}
+
+bool SmbService::ShouldRunHostDiscoveryAgain() const {
+  return tick_clock_->NowTicks() >
+         previous_host_discovery_time_ + kHostDiscoveryInterval;
 }
 
 void SmbService::RecordMountCount() const {
diff --git a/chrome/browser/chromeos/smb_client/smb_service.h b/chrome/browser/chromeos/smb_client/smb_service.h
index e2a1f0e..076faf0f 100644
--- a/chrome/browser/chromeos/smb_client/smb_service.h
+++ b/chrome/browser/chromeos/smb_client/smb_service.h
@@ -130,6 +130,13 @@
       const std::vector<ProvidedFileSystemInfo>& file_systems,
       const std::vector<SmbUrl>& preconfigured_shares);
 
+  // Closure for OnHostDiscovered(). |reply| is passed down to
+  // UpdateSharePath().
+  void OnHostsDiscoveredForUpdateSharePath(
+      int32_t mount_id,
+      const std::string& share_path,
+      StartReadDirIfSuccessfulCallback reply);
+
   // Attempts to remount a share with the information in |file_system_info|.
   void Remount(const ProvidedFileSystemInfo& file_system_info);
 
@@ -234,10 +241,15 @@
                                  StartReadDirIfSuccessfulCallback reply,
                                  smbprovider::ErrorType error);
 
+  // Helper function that determines if HostDiscovery can be run again. Returns
+  // false if HostDiscovery was recently run.
+  bool ShouldRunHostDiscoveryAgain() const;
+
   // Records metrics on the number of SMB mounts a user has.
   void RecordMountCount() const;
 
   static bool service_should_run_;
+  base::TimeTicks previous_host_discovery_time_;
   const ProviderId provider_id_;
   Profile* profile_;
   std::unique_ptr<base::TickClock> tick_clock_;
diff --git a/chrome/browser/content_settings/local_shared_objects_container.cc b/chrome/browser/content_settings/local_shared_objects_container.cc
index 8e73e4d..c7e5b88 100644
--- a/chrome/browser/content_settings/local_shared_objects_container.cc
+++ b/chrome/browser/content_settings/local_shared_objects_container.cc
@@ -4,6 +4,9 @@
 
 #include "chrome/browser/content_settings/local_shared_objects_container.h"
 
+#include <set>
+#include <string>
+#include <utility>
 #include <vector>
 
 #include "chrome/browser/browsing_data/browsing_data_appcache_helper.h"
@@ -65,14 +68,14 @@
   size_t count = 0;
   count += appcaches()->GetAppCacheCount();
   count += cookies()->GetCookieCount();
-  count += databases()->GetDatabaseCount();
-  count += file_systems()->GetFileSystemCount();
-  count += indexed_dbs()->GetIndexedDBCount();
-  count += local_storages()->GetLocalStorageCount();
-  count += service_workers()->GetServiceWorkerCount();
+  count += databases()->GetCount();
+  count += file_systems()->GetCount();
+  count += indexed_dbs()->GetCount();
+  count += local_storages()->GetCount();
+  count += service_workers()->GetCount();
   count += shared_workers()->GetSharedWorkerCount();
-  count += cache_storages()->GetCacheStorageCount();
-  count += session_storages()->GetLocalStorageCount();
+  count += cache_storages()->GetCount();
+  count += session_storages()->GetCount();
   return count;
 }
 
@@ -108,39 +111,26 @@
   }
 
   // Count local storages for the domain of the given |origin|.
-  const std::set<GURL> local_storage_info =
-      local_storages()->GetLocalStorageInfo();
-  for (auto it = local_storage_info.begin(); it != local_storage_info.end();
-       ++it) {
-    if (SameDomainOrHost(origin, *it))
+  for (const auto& storage_origin : local_storages()->GetOrigins()) {
+    if (SameDomainOrHost(origin, storage_origin.GetURL()))
       ++count;
   }
 
   // Count session storages for the domain of the given |origin|.
-  const std::set<GURL> urls = session_storages()->GetLocalStorageInfo();
-  for (auto it = urls.begin(); it != urls.end(); ++it) {
-    if (SameDomainOrHost(origin, *it))
+  for (const auto& storage_origin : session_storages()->GetOrigins()) {
+    if (SameDomainOrHost(origin, storage_origin.GetURL()))
       ++count;
   }
 
   // Count indexed dbs for the domain of the given |origin|.
-  typedef CannedBrowsingDataIndexedDBHelper::PendingIndexedDBInfo
-      StorageUsageInfo;
-  const std::set<StorageUsageInfo>& indexed_db_info =
-      indexed_dbs()->GetIndexedDBInfo();
-  for (auto it = indexed_db_info.begin(); it != indexed_db_info.end(); ++it) {
-    if (SameDomainOrHost(origin, it->origin))
+  for (const auto& storage_origin : indexed_dbs()->GetOrigins()) {
+    if (SameDomainOrHost(origin, storage_origin.GetURL()))
       ++count;
   }
 
   // Count service workers for the domain of the given |origin|.
-  typedef CannedBrowsingDataServiceWorkerHelper::PendingServiceWorkerUsageInfo
-      ServiceWorkerInfo;
-  const std::set<ServiceWorkerInfo>& service_worker_info =
-      service_workers()->GetServiceWorkerUsageInfo();
-  for (auto it = service_worker_info.begin(); it != service_worker_info.end();
-       ++it) {
-    if (SameDomainOrHost(origin, it->origin))
+  for (const auto& storage_origin : service_workers()->GetOrigins()) {
+    if (SameDomainOrHost(origin, storage_origin.GetURL()))
       ++count;
   }
 
@@ -154,31 +144,20 @@
   }
 
   // Count cache storages for the domain of the given |origin|.
-  typedef CannedBrowsingDataCacheStorageHelper::PendingCacheStorageUsageInfo
-      CacheStorageInfo;
-  const std::set<CacheStorageInfo>& cache_storage_info =
-      cache_storages()->GetCacheStorageUsageInfo();
-  for (const CacheStorageInfo& it : cache_storage_info) {
-    if (SameDomainOrHost(origin, it.origin))
+  for (const auto& storage_origin : cache_storages()->GetOrigins()) {
+    if (SameDomainOrHost(origin, storage_origin.GetURL()))
       ++count;
   }
 
   // Count filesystems for the domain of the given |origin|.
-  typedef BrowsingDataFileSystemHelper::FileSystemInfo FileSystemInfo;
-  typedef std::list<FileSystemInfo> FileSystemInfoList;
-  const FileSystemInfoList& file_system_info =
-      file_systems()->GetFileSystemInfo();
-  for (auto it = file_system_info.begin(); it != file_system_info.end(); ++it) {
-    if (SameDomainOrHost(origin, it->origin.GetURL()))
+  for (const auto& storage_origin : file_systems()->GetOrigins()) {
+    if (SameDomainOrHost(origin, storage_origin.GetURL()))
       ++count;
   }
 
   // Count databases for the domain of the given |origin|.
-  typedef CannedBrowsingDataDatabaseHelper::PendingDatabaseInfo DatabaseInfo;
-  const std::set<DatabaseInfo>& database_list =
-      databases()->GetPendingDatabaseInfo();
-  for (auto it = database_list.begin(); it != database_list.end(); ++it) {
-    if (SameDomainOrHost(origin, it->origin))
+  for (const auto& storage_origin : databases()->GetOrigins()) {
+    if (SameDomainOrHost(origin, storage_origin.GetURL()))
       ++count;
   }
 
diff --git a/chrome/browser/content_settings/tab_specific_content_settings.cc b/chrome/browser/content_settings/tab_specific_content_settings.cc
index a4228da..a72b1f82 100644
--- a/chrome/browser/content_settings/tab_specific_content_settings.cc
+++ b/chrome/browser/content_settings/tab_specific_content_settings.cc
@@ -416,10 +416,10 @@
 void TabSpecificContentSettings::OnIndexedDBAccessed(const GURL& url,
                                                      bool blocked_by_policy) {
   if (blocked_by_policy) {
-    blocked_local_shared_objects_.indexed_dbs()->AddIndexedDB(url);
+    blocked_local_shared_objects_.indexed_dbs()->Add(url::Origin::Create(url));
     OnContentBlocked(CONTENT_SETTINGS_TYPE_COOKIES);
   } else {
-    allowed_local_shared_objects_.indexed_dbs()->AddIndexedDB(url);
+    allowed_local_shared_objects_.indexed_dbs()->Add(url::Origin::Create(url));
     OnContentAllowed(CONTENT_SETTINGS_TYPE_COOKIES);
   }
 
@@ -434,7 +434,7 @@
       blocked_local_shared_objects_ : allowed_local_shared_objects_;
   CannedBrowsingDataLocalStorageHelper* helper =
       local ? container.local_storages() : container.session_storages();
-  helper->AddLocalStorage(url);
+  helper->Add(url::Origin::Create(url));
 
   if (blocked_by_policy)
     OnContentBlocked(CONTENT_SETTINGS_TYPE_COOKIES);
@@ -450,11 +450,11 @@
     bool blocked_by_policy_cookie) {
   DCHECK(scope.is_valid());
   if (blocked_by_policy_javascript || blocked_by_policy_cookie) {
-    blocked_local_shared_objects_.service_workers()->AddServiceWorker(
-        scope.GetOrigin(), std::vector<GURL>(1, scope));
+    blocked_local_shared_objects_.service_workers()->Add(
+        url::Origin::Create(scope));
   } else {
-    allowed_local_shared_objects_.service_workers()->AddServiceWorker(
-        scope.GetOrigin(), std::vector<GURL>(1, scope));
+    allowed_local_shared_objects_.service_workers()->Add(
+        url::Origin::Create(scope));
   }
 
   if (blocked_by_policy_javascript) {
@@ -490,10 +490,10 @@
     const GURL& url,
     bool blocked_by_policy) {
   if (blocked_by_policy) {
-    blocked_local_shared_objects_.databases()->AddDatabase(url);
+    blocked_local_shared_objects_.databases()->Add(url::Origin::Create(url));
     OnContentBlocked(CONTENT_SETTINGS_TYPE_COOKIES);
   } else {
-    allowed_local_shared_objects_.databases()->AddDatabase(url);
+    allowed_local_shared_objects_.databases()->Add(url::Origin::Create(url));
     OnContentAllowed(CONTENT_SETTINGS_TYPE_COOKIES);
   }
 
@@ -503,13 +503,14 @@
 void TabSpecificContentSettings::OnFileSystemAccessed(
     const GURL& url,
     bool blocked_by_policy) {
+  // Note that all sandboxed file system access is recorded here as
+  // kTemporary; the distinction between temporary (default) and persistent
+  // storage is not made in the UI that presents this data.
   if (blocked_by_policy) {
-    blocked_local_shared_objects_.file_systems()->AddFileSystem(
-        url::Origin::Create(url), storage::kFileSystemTypeTemporary, 0);
+    blocked_local_shared_objects_.file_systems()->Add(url::Origin::Create(url));
     OnContentBlocked(CONTENT_SETTINGS_TYPE_COOKIES);
   } else {
-    allowed_local_shared_objects_.file_systems()->AddFileSystem(
-        url::Origin::Create(url), storage::kFileSystemTypeTemporary, 0);
+    allowed_local_shared_objects_.file_systems()->Add(url::Origin::Create(url));
     OnContentAllowed(CONTENT_SETTINGS_TYPE_COOKIES);
   }
 
diff --git a/chrome/browser/extensions/updater/OWNERS b/chrome/browser/extensions/updater/OWNERS
index f9d5213..917b82e 100644
--- a/chrome/browser/extensions/updater/OWNERS
+++ b/chrome/browser/extensions/updater/OWNERS
@@ -1,4 +1,6 @@
 mxnguyen@chromium.org
+sorin@chromium.org
+waffles@chromium.org
 
 # TEAM: extensions-dev@chromium.org
 # COMPONENT: Platform>Extensions
diff --git a/chrome/browser/flag-metadata.json b/chrome/browser/flag-metadata.json
index 7f1048e..c2cbc5b 100644
--- a/chrome/browser/flag-metadata.json
+++ b/chrome/browser/flag-metadata.json
@@ -1288,11 +1288,6 @@
     "expiry_milestone": 76
   },
   {
-    "name": "enable-home-launcher-gestures",
-    // "owners": [ "your-team" ],
-    "expiry_milestone": 76
-  },
-  {
     "name": "enable-homepage-tile",
     // "owners": [ "your-team" ],
     "expiry_milestone": 76
diff --git a/chrome/browser/flag_descriptions.cc b/chrome/browser/flag_descriptions.cc
index 592e54d..4870a63 100644
--- a/chrome/browser/flag_descriptions.cc
+++ b/chrome/browser/flag_descriptions.cc
@@ -1388,6 +1388,14 @@
 const char kOmniboxNewAnswerLayoutDescription[] =
     "Modernize omnibox answers using an enhanced layout with larger icons.";
 
+const char kOmniboxRichEntitySuggestionsName[] =
+    "Omnibox rich entity suggestions";
+const char kOmniboxRichEntitySuggestionsDescription[] =
+    "Display entity suggestions using images and an enhanced layout; showing "
+    "more context and descriptive text about the entity. Has no effect unless "
+    "either the #upcoming-ui-features flag is Enabled or the #top-chrome-md "
+    "flag is set to Refresh or Touchable Refresh.";
+
 const char kOmniboxSpareRendererName[] =
     "Start spare renderer on omnibox focus";
 const char kOmniboxSpareRendererDescription[] =
@@ -2882,14 +2890,6 @@
     "effect unless either the #upcoming-ui-features flag is Enabled or the "
     "#top-chrome-md flag is set to Refresh or Touchable Refresh.";
 
-const char kOmniboxRichEntitySuggestionsName[] =
-    "Omnibox rich entity suggestions";
-const char kOmniboxRichEntitySuggestionsDescription[] =
-    "Display entity suggestions using images and an enhanced layout; showing "
-    "more context and descriptive text about the entity. Has no effect unless "
-    "either the #upcoming-ui-features flag is Enabled or the #top-chrome-md "
-    "flag is set to Refresh or Touchable Refresh.";
-
 const char kOmniboxTabSwitchSuggestionsName[] =
     "Omnibox tab switch suggestions";
 const char kOmniboxTabSwitchSuggestionsDescription[] =
@@ -3311,10 +3311,6 @@
 const char kEnableHomeLauncherDescription[] =
     "Enable home launcher in tablet mode.";
 
-const char kEnableHomeLauncherGesturesName[] = "Enable home launcher gestures";
-const char kEnableHomeLauncherGesturesDescription[] =
-    "Enables using gestures to hide or show the home launcher.";
-
 const char kEnableImeMenuName[] = "Enable opt-in IME menu";
 const char kEnableImeMenuDescription[] =
     "Enable access to the new IME menu in the Language Settings page.";
diff --git a/chrome/browser/flag_descriptions.h b/chrome/browser/flag_descriptions.h
index d7e500e1..e3535c7 100644
--- a/chrome/browser/flag_descriptions.h
+++ b/chrome/browser/flag_descriptions.h
@@ -841,6 +841,9 @@
 extern const char kOmniboxNewAnswerLayoutName[];
 extern const char kOmniboxNewAnswerLayoutDescription[];
 
+extern const char kOmniboxRichEntitySuggestionsName[];
+extern const char kOmniboxRichEntitySuggestionsDescription[];
+
 extern const char kOmniboxSpareRendererName[];
 extern const char kOmniboxSpareRendererDescription[];
 
@@ -1702,9 +1705,6 @@
 extern const char kOmniboxReverseAnswersName[];
 extern const char kOmniboxReverseAnswersDescription[];
 
-extern const char kOmniboxRichEntitySuggestionsName[];
-extern const char kOmniboxRichEntitySuggestionsDescription[];
-
 extern const char kOmniboxTabSwitchSuggestionsName[];
 extern const char kOmniboxTabSwitchSuggestionsDescription[];
 
@@ -1985,9 +1985,6 @@
 extern const char kEnableHomeLauncherName[];
 extern const char kEnableHomeLauncherDescription[];
 
-extern const char kEnableHomeLauncherGesturesName[];
-extern const char kEnableHomeLauncherGesturesDescription[];
-
 extern const char kEnableImeMenuName[];
 extern const char kEnableImeMenuDescription[];
 
diff --git a/chrome/browser/notifications/notification_platform_bridge_linux.cc b/chrome/browser/notifications/notification_platform_bridge_linux.cc
index bb0f94a..d3f80d5 100644
--- a/chrome/browser/notifications/notification_platform_bridge_linux.cc
+++ b/chrome/browser/notifications/notification_platform_bridge_linux.cc
@@ -29,13 +29,13 @@
 #include "base/version.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/chrome_notification_types.h"
-#include "chrome/browser/dbus/dbus_thread_linux.h"
 #include "chrome/browser/notifications/notification_display_service_impl.h"
 #include "chrome/browser/profiles/profile_manager.h"
 #include "chrome/browser/shell_integration_linux.h"
 #include "chrome/grit/chrome_unscaled_resources.h"
 #include "chrome/grit/chromium_strings.h"
 #include "chrome/grit/generated_resources.h"
+#include "components/dbus/dbus_thread_linux.h"
 #include "components/url_formatter/elide_url.h"
 #include "content/public/browser/browser_task_traits.h"
 #include "content/public/browser/browser_thread.h"
@@ -268,7 +268,7 @@
   explicit NotificationPlatformBridgeLinuxImpl(scoped_refptr<dbus::Bus> bus)
       : bus_(bus) {
     DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
-    task_runner_ = chrome::GetDBusTaskRunner();
+    task_runner_ = dbus_thread_linux::GetTaskRunner();
     registrar_.Add(this, chrome::NOTIFICATION_APP_TERMINATING,
                    content::NotificationService::AllSources());
   }
diff --git a/chrome/browser/notifications/notification_platform_bridge_linux_unittest.cc b/chrome/browser/notifications/notification_platform_bridge_linux_unittest.cc
index fdb0af35..8ed94bf 100644
--- a/chrome/browser/notifications/notification_platform_bridge_linux_unittest.cc
+++ b/chrome/browser/notifications/notification_platform_bridge_linux_unittest.cc
@@ -15,10 +15,10 @@
 #include "base/memory/ptr_util.h"
 #include "base/memory/ref_counted.h"
 #include "base/strings/utf_string_conversions.h"
-#include "chrome/browser/dbus/dbus_thread_linux.h"
 #include "chrome/browser/notifications/notification_display_service_tester.h"
 #include "chrome/browser/notifications/notification_test_util.h"
 #include "chrome/test/base/browser_with_test_window_test.h"
+#include "components/dbus/dbus_thread_linux.h"
 #include "content/public/test/test_utils.h"
 #include "dbus/mock_bus.h"
 #include "dbus/mock_object_proxy.h"
@@ -377,7 +377,7 @@
   }
 
   void InvokeAction(uint32_t dbus_id, const std::string& action) {
-    chrome::GetDBusTaskRunner()->PostTask(
+    dbus_thread_linux::GetTaskRunner()->PostTask(
         FROM_HERE,
         base::BindOnce(&NotificationPlatformBridgeLinuxTest::DoInvokeAction,
                        base::Unretained(this), dbus_id, action));
diff --git a/chrome/browser/page_load_metrics/metrics_web_contents_observer.cc b/chrome/browser/page_load_metrics/metrics_web_contents_observer.cc
index b9aef6d..84aefa86 100644
--- a/chrome/browser/page_load_metrics/metrics_web_contents_observer.cc
+++ b/chrome/browser/page_load_metrics/metrics_web_contents_observer.cc
@@ -56,9 +56,7 @@
 
   return UserInitiatedInfo::RenderInitiated(
       navigation_handle->HasUserGesture(),
-      committed_load &&
-          committed_load->input_tracker()->FindAndConsumeInputEventsBefore(
-              navigation_handle->NavigationStart()));
+      !navigation_handle->NavigationInputStart().is_null());
 }
 
 }  // namespace
diff --git a/chrome/browser/page_load_metrics/observers/aborts_page_load_metrics_observer.cc b/chrome/browser/page_load_metrics/observers/aborts_page_load_metrics_observer.cc
index 2fe5df9..c5e18a3e 100644
--- a/chrome/browser/page_load_metrics/observers/aborts_page_load_metrics_observer.cc
+++ b/chrome/browser/page_load_metrics/observers/aborts_page_load_metrics_observer.cc
@@ -68,12 +68,6 @@
             "UserGesture",
             abort_info.time_to_abort);
       }
-      if (abort_info.user_initiated_info.user_input_event) {
-        PAGE_LOAD_HISTOGRAM(
-            "PageLoad.Experimental.AbortTiming.Reload.BeforeCommit."
-            "UserInputEvent",
-            abort_info.time_to_abort);
-      }
       if (abort_info.user_initiated_info.browser_initiated) {
         PAGE_LOAD_HISTOGRAM(
             "PageLoad.Experimental.AbortTiming.Reload.BeforeCommit."
@@ -90,12 +84,6 @@
             "BeforeCommit.UserGesture",
             abort_info.time_to_abort);
       }
-      if (abort_info.user_initiated_info.user_input_event) {
-        PAGE_LOAD_HISTOGRAM(
-            "PageLoad.Experimental.AbortTiming.ForwardBackNavigation."
-            "BeforeCommit.UserInputEvent",
-            abort_info.time_to_abort);
-      }
       if (abort_info.user_initiated_info.browser_initiated) {
         PAGE_LOAD_HISTOGRAM(
             "PageLoad.Experimental.AbortTiming.ForwardBackNavigation."
@@ -112,12 +100,6 @@
             "UserGesture",
             abort_info.time_to_abort);
       }
-      if (abort_info.user_initiated_info.user_input_event) {
-        PAGE_LOAD_HISTOGRAM(
-            "PageLoad.Experimental.AbortTiming.NewNavigation.BeforeCommit."
-            "UserInputEvent",
-            abort_info.time_to_abort);
-      }
       if (abort_info.user_initiated_info.browser_initiated) {
         PAGE_LOAD_HISTOGRAM(
             "PageLoad.Experimental.AbortTiming.NewNavigation.BeforeCommit."
@@ -160,12 +142,6 @@
             "UserGesture",
             abort_info.time_to_abort);
       }
-      if (abort_info.user_initiated_info.user_input_event) {
-        PAGE_LOAD_HISTOGRAM(
-            "PageLoad.Experimental.AbortTiming.Reload.AfterCommit.BeforePaint."
-            "UserInputEvent",
-            abort_info.time_to_abort);
-      }
       if (abort_info.user_initiated_info.browser_initiated) {
         PAGE_LOAD_HISTOGRAM(
             "PageLoad.Experimental.AbortTiming.Reload.AfterCommit.BeforePaint."
@@ -182,12 +158,6 @@
             "AfterCommit.BeforePaint.UserGesture",
             abort_info.time_to_abort);
       }
-      if (abort_info.user_initiated_info.user_input_event) {
-        PAGE_LOAD_HISTOGRAM(
-            "PageLoad.Experimental.AbortTiming.ForwardBackNavigation."
-            "AfterCommit.BeforePaint.UserInputEvent",
-            abort_info.time_to_abort);
-      }
       if (abort_info.user_initiated_info.browser_initiated) {
         PAGE_LOAD_HISTOGRAM(
             "PageLoad.Experimental.AbortTiming.ForwardBackNavigation."
@@ -204,12 +174,6 @@
             "BeforePaint.UserGesture",
             abort_info.time_to_abort);
       }
-      if (abort_info.user_initiated_info.user_input_event) {
-        PAGE_LOAD_HISTOGRAM(
-            "PageLoad.Experimental.AbortTiming.NewNavigation.AfterCommit."
-            "BeforePaint.UserInputEvent",
-            abort_info.time_to_abort);
-      }
       if (abort_info.user_initiated_info.browser_initiated) {
         PAGE_LOAD_HISTOGRAM(
             "PageLoad.Experimental.AbortTiming.NewNavigation.AfterCommit."
diff --git a/chrome/browser/page_load_metrics/observers/amp_ukm_observer.cc b/chrome/browser/page_load_metrics/observers/amp_ukm_observer.cc
new file mode 100644
index 0000000..e1f35709
--- /dev/null
+++ b/chrome/browser/page_load_metrics/observers/amp_ukm_observer.cc
@@ -0,0 +1,40 @@
+// 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/page_load_metrics/observers/amp_ukm_observer.h"
+
+#include "chrome/browser/page_load_metrics/page_load_metrics_util.h"
+#include "services/metrics/public/cpp/metrics_utils.h"
+#include "services/metrics/public/cpp/ukm_builders.h"
+#include "services/metrics/public/cpp/ukm_recorder.h"
+#include "third_party/blink/public/common/features.h"
+
+AmpUkmObserver::AmpUkmObserver() {}
+
+AmpUkmObserver::~AmpUkmObserver() {}
+
+void AmpUkmObserver::OnLoadingBehaviorObserved(
+    const page_load_metrics::PageLoadExtraInfo& info) {
+  ukm::builders::AmpPageLoad builder(info.source_id);
+  bool should_record = false;
+  if (!logged_main_frame_ &&
+      (info.main_frame_metadata.behavior_flags &
+       blink::WebLoadingBehaviorFlag::kWebLoadingBehaviorAmpDocumentLoaded) !=
+          0) {
+    builder.SetMainFrameAmpPageLoad(true);
+    logged_main_frame_ = true;
+    should_record = true;
+  }
+
+  if (!logged_subframe_ &&
+      (info.subframe_metadata.behavior_flags &
+       blink::WebLoadingBehaviorFlag::kWebLoadingBehaviorAmpDocumentLoaded) !=
+          0) {
+    builder.SetSubFrameAmpPageLoad(true);
+    logged_subframe_ = true;
+    should_record = true;
+  }
+  if (should_record)
+    builder.Record(ukm::UkmRecorder::Get());
+}
diff --git a/chrome/browser/page_load_metrics/observers/amp_ukm_observer.h b/chrome/browser/page_load_metrics/observers/amp_ukm_observer.h
new file mode 100644
index 0000000..88d00e6
--- /dev/null
+++ b/chrome/browser/page_load_metrics/observers/amp_ukm_observer.h
@@ -0,0 +1,29 @@
+// 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_PAGE_LOAD_METRICS_OBSERVERS_AMP_UKM_OBSERVER_H_
+#define CHROME_BROWSER_PAGE_LOAD_METRICS_OBSERVERS_AMP_UKM_OBSERVER_H_
+
+#include "chrome/browser/page_load_metrics/page_load_metrics_observer.h"
+#include "services/metrics/public/cpp/ukm_source.h"
+
+// If URL-Keyed-Metrics (UKM) is enabled in the system, this is used to
+// populate it with AMP-related page-load metrics.
+class AmpUkmObserver : public page_load_metrics::PageLoadMetricsObserver {
+ public:
+  AmpUkmObserver();
+  ~AmpUkmObserver() override;
+
+  void OnLoadingBehaviorObserved(
+      const page_load_metrics::PageLoadExtraInfo& extra_info) override;
+
+ private:
+  // Track what we've already logged.
+  bool logged_main_frame_ = false;
+  bool logged_subframe_ = false;
+
+  DISALLOW_COPY_AND_ASSIGN(AmpUkmObserver);
+};
+
+#endif  // CHROME_BROWSER_PAGE_LOAD_METRICS_OBSERVERS_AMP_UKM_OBSERVER_H_
diff --git a/chrome/browser/page_load_metrics/observers/amp_ukm_observer_browsertest.cc b/chrome/browser/page_load_metrics/observers/amp_ukm_observer_browsertest.cc
new file mode 100644
index 0000000..c89ce15a
--- /dev/null
+++ b/chrome/browser/page_load_metrics/observers/amp_ukm_observer_browsertest.cc
@@ -0,0 +1,132 @@
+// 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/page_load_metrics/observers/foreground_duration_ukm_observer.h"
+
+#include "chrome/browser/page_load_metrics/page_load_metrics_test_waiter.h"
+#include "chrome/browser/ui/browser.h"
+#include "chrome/browser/ui/browser_commands.h"
+#include "chrome/browser/ui/tabs/tab_strip_model.h"
+#include "chrome/common/webui_url_constants.h"
+#include "chrome/test/base/in_process_browser_test.h"
+#include "chrome/test/base/ui_test_utils.h"
+#include "components/ukm/test_ukm_recorder.h"
+#include "content/public/test/browser_test_utils.h"
+#include "content/public/test/test_utils.h"
+#include "net/test/embedded_test_server/embedded_test_server.h"
+#include "services/metrics/public/cpp/ukm_builders.h"
+#include "services/metrics/public/cpp/ukm_source.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/base/window_open_disposition.h"
+#include "url/gurl.h"
+
+using UkmEntry = ukm::builders::AmpPageLoad;
+
+class AmpUkmObserverBrowserTest : public InProcessBrowserTest {
+ public:
+  AmpUkmObserverBrowserTest() {}
+  ~AmpUkmObserverBrowserTest() override {}
+
+  void PreRunTestOnMainThread() override {
+    InProcessBrowserTest::PreRunTestOnMainThread();
+    test_ukm_recorder_ = std::make_unique<ukm::TestAutoSetUkmRecorder>();
+  }
+
+ protected:
+  void StartHttpsServer(net::EmbeddedTestServer::ServerCertificate cert) {
+    https_test_server_ = std::make_unique<net::EmbeddedTestServer>(
+        net::EmbeddedTestServer::TYPE_HTTPS);
+    https_test_server_->SetSSLConfig(cert);
+    https_test_server_->ServeFilesFromSourceDirectory("chrome/test/data");
+    ASSERT_TRUE(https_test_server_->Start());
+  }
+  void ExpectMetricValueForUrl(const GURL& url,
+                               const char* metric_name,
+                               const int expected_value) {
+    for (auto* entry :
+         test_ukm_recorder_->GetEntriesByName(UkmEntry::kEntryName)) {
+      auto* source = test_ukm_recorder_->GetSourceForSourceId(entry->source_id);
+      if (source && source->url() == url) {
+        test_ukm_recorder_->EntryHasMetric(entry, metric_name);
+        test_ukm_recorder_->ExpectEntryMetric(entry, metric_name,
+                                              expected_value);
+      }
+    }
+  }
+  void ExpectMetricCountForUrl(const GURL& url,
+                               const char* metric_name,
+                               const int expected_count) {
+    int count = 0;
+    for (auto* entry :
+         test_ukm_recorder_->GetEntriesByName(UkmEntry::kEntryName)) {
+      auto* source = test_ukm_recorder_->GetSourceForSourceId(entry->source_id);
+      if (source && source->url() == url &&
+          test_ukm_recorder_->EntryHasMetric(entry, metric_name)) {
+        count++;
+      }
+    }
+    EXPECT_EQ(count, expected_count);
+  }
+
+  void CloseAllTabs() {
+    TabStripModel* tab_strip_model = browser()->tab_strip_model();
+    content::WebContentsDestroyedWatcher destroyed_watcher(
+        tab_strip_model->GetActiveWebContents());
+    tab_strip_model->CloseAllTabs();
+    destroyed_watcher.Wait();
+  }
+
+  net::EmbeddedTestServer* https_test_server() {
+    return https_test_server_.get();
+  }
+
+ private:
+  std::unique_ptr<ukm::TestAutoSetUkmRecorder> test_ukm_recorder_;
+  std::unique_ptr<net::EmbeddedTestServer> https_test_server_;
+
+  DISALLOW_COPY_AND_ASSIGN(AmpUkmObserverBrowserTest);
+};
+
+IN_PROC_BROWSER_TEST_F(AmpUkmObserverBrowserTest, NoAmp) {
+  page_load_metrics::PageLoadMetricsTestWaiter waiter(
+      browser()->tab_strip_model()->GetActiveWebContents());
+  waiter.AddPageExpectation(
+      page_load_metrics::PageLoadMetricsTestWaiter::TimingField::kLoadEvent);
+  StartHttpsServer(net::EmbeddedTestServer::CERT_OK);
+  GURL url = https_test_server()->GetURL("/english_page.html");
+  ui_test_utils::NavigateToURL(browser(), url);
+  waiter.Wait();
+  CloseAllTabs();
+  ExpectMetricCountForUrl(url, "MainFrameAmpPageLoad", 0);
+  ExpectMetricCountForUrl(url, "SubFrameAmpPageLoad", 0);
+}
+
+IN_PROC_BROWSER_TEST_F(AmpUkmObserverBrowserTest, AmpMainFrame) {
+  page_load_metrics::PageLoadMetricsTestWaiter waiter(
+      browser()->tab_strip_model()->GetActiveWebContents());
+  waiter.AddPageExpectation(page_load_metrics::PageLoadMetricsTestWaiter::
+                                TimingField::kFirstContentfulPaint);
+  StartHttpsServer(net::EmbeddedTestServer::CERT_OK);
+  GURL url = https_test_server()->GetURL("/page_load_metrics/amp_basic.html");
+  ui_test_utils::NavigateToURL(browser(), url);
+  waiter.Wait();
+  CloseAllTabs();
+  ExpectMetricValueForUrl(url, "MainFrameAmpPageLoad", 1);
+  ExpectMetricCountForUrl(url, "SubFrameAmpPageLoad", 0);
+}
+
+IN_PROC_BROWSER_TEST_F(AmpUkmObserverBrowserTest, AmpSubframe) {
+  page_load_metrics::PageLoadMetricsTestWaiter waiter(
+      browser()->tab_strip_model()->GetActiveWebContents());
+  waiter.AddPageExpectation(page_load_metrics::PageLoadMetricsTestWaiter::
+                                TimingField::kFirstContentfulPaint);
+  StartHttpsServer(net::EmbeddedTestServer::CERT_OK);
+  GURL url =
+      https_test_server()->GetURL("/page_load_metrics/amp_reader_mock.html");
+  ui_test_utils::NavigateToURL(browser(), url);
+  waiter.Wait();
+  CloseAllTabs();
+  ExpectMetricCountForUrl(url, "MainFrameAmpPageLoad", 0);
+  ExpectMetricValueForUrl(url, "SubFrameAmpPageLoad", 1);
+}
diff --git a/chrome/browser/page_load_metrics/observers/ukm_page_load_metrics_observer.cc b/chrome/browser/page_load_metrics/observers/ukm_page_load_metrics_observer.cc
index 74d5ee8..63a77f5 100644
--- a/chrome/browser/page_load_metrics/observers/ukm_page_load_metrics_observer.cc
+++ b/chrome/browser/page_load_metrics/observers/ukm_page_load_metrics_observer.cc
@@ -161,16 +161,6 @@
     const page_load_metrics::mojom::PageLoadTiming& timing,
     const page_load_metrics::PageLoadExtraInfo& info) {
   ukm::builders::PageLoad builder(info.source_id);
-  bool is_user_initiated_navigation =
-      // All browser initiated page loads are user-initiated.
-      info.user_initiated_info.browser_initiated ||
-
-      // Renderer-initiated navigations are user-initiated if there is an
-      // associated input timestamp.
-      timing.input_to_navigation_start;
-
-  builder.SetExperimental_Navigation_UserInitiated(
-      is_user_initiated_navigation);
   if (timing.input_to_navigation_start) {
     builder.SetExperimental_InputToNavigationStart(
         timing.input_to_navigation_start.value().InMilliseconds());
@@ -294,6 +284,17 @@
         foreground_duration.value().InMilliseconds());
   }
 
+  bool is_user_initiated_navigation =
+      // All browser initiated page loads are user-initiated.
+      info.user_initiated_info.browser_initiated ||
+
+      // Renderer-initiated navigations are user-initiated if there is an
+      // associated input event.
+      info.user_initiated_info.user_input_event;
+
+  builder.SetExperimental_Navigation_UserInitiated(
+      is_user_initiated_navigation);
+
   // Convert to the EffectiveConnectionType as used in SystemProfileProto
   // before persisting the metric.
   metrics::SystemProfileProto::Network::EffectiveConnectionType
diff --git a/chrome/browser/page_load_metrics/observers/ukm_page_load_metrics_observer_unittest.cc b/chrome/browser/page_load_metrics/observers/ukm_page_load_metrics_observer_unittest.cc
index a5c48e0..cae25b0 100644
--- a/chrome/browser/page_load_metrics/observers/ukm_page_load_metrics_observer_unittest.cc
+++ b/chrome/browser/page_load_metrics/observers/ukm_page_load_metrics_observer_unittest.cc
@@ -202,6 +202,9 @@
     EXPECT_TRUE(test_ukm_recorder().EntryHasMetric(
         kv.second.get(),
         PageLoad::kPageTiming_NavigationToFailedProvisionalLoadName));
+    test_ukm_recorder().ExpectEntryMetric(
+        kv.second.get(), PageLoad::kExperimental_Navigation_UserInitiatedName,
+        false);
   }
 }
 
diff --git a/chrome/browser/page_load_metrics/page_load_metrics_initialize.cc b/chrome/browser/page_load_metrics/page_load_metrics_initialize.cc
index 323407e3..7c0e08a8 100644
--- a/chrome/browser/page_load_metrics/page_load_metrics_initialize.cc
+++ b/chrome/browser/page_load_metrics/page_load_metrics_initialize.cc
@@ -14,6 +14,7 @@
 #include "chrome/browser/page_load_metrics/observers/aborts_page_load_metrics_observer.h"
 #include "chrome/browser/page_load_metrics/observers/ad_metrics/ads_page_load_metrics_observer.h"
 #include "chrome/browser/page_load_metrics/observers/amp_page_load_metrics_observer.h"
+#include "chrome/browser/page_load_metrics/observers/amp_ukm_observer.h"
 #include "chrome/browser/page_load_metrics/observers/core_page_load_metrics_observer.h"
 #include "chrome/browser/page_load_metrics/observers/data_reduction_proxy_metrics_observer.h"
 #include "chrome/browser/page_load_metrics/observers/data_saver_site_breakdown_metrics_observer.h"
@@ -93,6 +94,7 @@
   if (!IsPrerendering()) {
     tracker->AddObserver(std::make_unique<AbortsPageLoadMetricsObserver>());
     tracker->AddObserver(std::make_unique<AMPPageLoadMetricsObserver>());
+    tracker->AddObserver(std::make_unique<AmpUkmObserver>());
     tracker->AddObserver(std::make_unique<CorePageLoadMetricsObserver>());
     tracker->AddObserver(
         std::make_unique<
diff --git a/chrome/browser/page_load_metrics/page_load_metrics_observer.h b/chrome/browser/page_load_metrics/page_load_metrics_observer.h
index fcc41b6..fc8f72e 100644
--- a/chrome/browser/page_load_metrics/page_load_metrics_observer.h
+++ b/chrome/browser/page_load_metrics/page_load_metrics_observer.h
@@ -105,11 +105,14 @@
 
   // Whether the associated action was initiated by a user, according to user
   // gesture tracking in content and Blink, as reported by NavigationHandle.
+  // This is based on the heuristic the popup blocker uses.
   bool user_gesture;
 
-  // Whether the associated action was initiated by a user, based on our
-  // heuristic-driven implementation that tests to see if there was an input
-  // event that happened shortly before the given action.
+  // Whether an input even directly led to the navigation, according to
+  // input start time tracking in the renderer, as reported by NavigationHandle.
+  // Note that this metric is still experimental and may not be fully
+  // implemented. All known issues are blocking crbug.com/889220. Currently
+  // all known gaps affect browser-side navigations.
   bool user_input_event;
 
  private:
diff --git a/chrome/browser/page_load_metrics/page_load_tracker.cc b/chrome/browser/page_load_metrics/page_load_tracker.cc
index 1787d322..65a48086 100644
--- a/chrome/browser/page_load_metrics/page_load_tracker.cc
+++ b/chrome/browser/page_load_metrics/page_load_tracker.cc
@@ -389,7 +389,6 @@
 }
 
 void PageLoadTracker::OnInputEvent(const blink::WebInputEvent& event) {
-  input_tracker_.OnInputEvent(event);
   const PageLoadExtraInfo info = ComputePageLoadExtraInfo();
   for (const auto& observer : observers_) {
     observer->OnUserInput(event, metrics_update_dispatcher_.timing(), info);
@@ -517,8 +516,7 @@
   // user initiated.
   DCHECK(page_end_reason_ != END_NONE ||
          (!page_end_user_initiated_info_.browser_initiated &&
-          !page_end_user_initiated_info_.user_gesture &&
-          !page_end_user_initiated_info_.user_input_event));
+          !page_end_user_initiated_info_.user_gesture));
   return PageLoadExtraInfo(
       navigation_start_, first_background_time, first_foreground_time,
       started_in_foreground_, user_initiated_info_, url(), start_url_,
diff --git a/chrome/browser/page_load_metrics/page_load_tracker.h b/chrome/browser/page_load_metrics/page_load_tracker.h
index b2556be3..99a9efd 100644
--- a/chrome/browser/page_load_metrics/page_load_tracker.h
+++ b/chrome/browser/page_load_metrics/page_load_tracker.h
@@ -13,7 +13,6 @@
 #include "base/time/time.h"
 #include "chrome/browser/page_load_metrics/page_load_metrics_observer.h"
 #include "chrome/browser/page_load_metrics/page_load_metrics_update_dispatcher.h"
-#include "chrome/browser/page_load_metrics/user_input_tracker.h"
 #include "chrome/common/page_load_metrics/page_load_timing.h"
 #include "content/public/browser/global_request_id.h"
 #include "content/public/browser/web_contents_observer.h"
@@ -270,8 +269,6 @@
 
   UserInitiatedInfo user_initiated_info() const { return user_initiated_info_; }
 
-  UserInputTracker* input_tracker() { return &input_tracker_; }
-
   PageLoadMetricsUpdateDispatcher* metrics_update_dispatcher() {
     return &metrics_update_dispatcher_;
   }
@@ -312,8 +309,6 @@
   // committed load.
   void LogAbortChainHistograms(content::NavigationHandle* final_navigation);
 
-  UserInputTracker input_tracker_;
-
   // Whether we stopped tracking this navigation after it was initiated. We may
   // stop tracking a navigation if it doesn't meet the criteria for tracking
   // metrics in DidFinishNavigation.
diff --git a/chrome/browser/page_load_metrics/user_input_tracker.cc b/chrome/browser/page_load_metrics/user_input_tracker.cc
deleted file mode 100644
index cc81399..0000000
--- a/chrome/browser/page_load_metrics/user_input_tracker.cc
+++ /dev/null
@@ -1,166 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chrome/browser/page_load_metrics/user_input_tracker.h"
-
-#include <algorithm>
-
-#include "third_party/blink/public/platform/web_input_event.h"
-
-namespace page_load_metrics {
-
-namespace {
-
-// Blink's UserGestureIndicator allows events to be associated with gestures
-// that are up to 1 second old, based on guidance in the HTML spec:
-// https://html.spec.whatwg.org/multipage/interaction.html#triggered-by-user-activation.
-const int kMaxEventAgeSeconds = 1;
-
-// Allow for up to 2x the oldest time. This allows consumers to continue to
-// find events for timestamps up to 1 second in the past.
-const int kOldestAllowedEventAgeSeconds = kMaxEventAgeSeconds * 2;
-
-// In order to limit to at most kMaxTrackedEvents, we rate limit the recorded
-// events,
-// allowing one per rate limit period.
-constexpr int kRateLimitClampMillis = (kOldestAllowedEventAgeSeconds * 1000) /
-                                      UserInputTracker::kMaxTrackedEvents;
-
-bool IsInterestingInputEvent(const blink::WebInputEvent& event) {
-  // Ignore synthesized auto repeat events.
-  if (event.GetModifiers() & blink::WebInputEvent::kIsAutoRepeat)
-    return false;
-
-  switch (event.GetType()) {
-    case blink::WebInputEvent::kMouseDown:
-    case blink::WebInputEvent::kMouseUp:
-    case blink::WebInputEvent::kRawKeyDown:
-    case blink::WebInputEvent::kKeyDown:
-    case blink::WebInputEvent::kChar:
-    case blink::WebInputEvent::kTouchStart:
-    case blink::WebInputEvent::kTouchEnd:
-      return true;
-    default:
-      return false;
-  }
-}
-
-}  // namespace
-
-constexpr size_t UserInputTracker::kMaxTrackedEvents;
-
-UserInputTracker::UserInputTracker() {
-  sorted_event_times_.reserve(kMaxTrackedEvents);
-}
-
-UserInputTracker::~UserInputTracker() {}
-
-// static
-base::TimeTicks UserInputTracker::RoundToRateLimitedOffset(
-    base::TimeTicks time) {
-  base::TimeDelta time_as_delta = time - base::TimeTicks();
-  base::TimeDelta rate_limit_remainder =
-      time_as_delta % base::TimeDelta::FromMilliseconds(kRateLimitClampMillis);
-  return time - rate_limit_remainder;
-}
-
-void UserInputTracker::OnInputEvent(const blink::WebInputEvent& event) {
-  RemoveInputEventsUpToInclusive(base::TimeTicks::Now() -
-                                 GetOldEventThreshold());
-
-  if (!IsInterestingInputEvent(event))
-    return;
-
-  // TODO(bmcquade): ideally we'd limit tracking to events generated by a user
-  // action, as opposed to those generated from JavaScript. The JS API isTrusted
-  // can be used to distinguish these cases. isTrusted isn't yet a property of
-  // WebInputEvent. We should consider adding it.
-
-  const base::TimeTicks now = base::TimeTicks::Now();
-  base::TimeTicks time = RoundToRateLimitedOffset(event.TimeStamp());
-  if (time <=
-      std::max(most_recent_consumed_time_, now - GetOldEventThreshold()))
-    return;
-
-  if (time > now) {
-    // We should never receive a UserInputEvent with a timestamp in the future
-    // if we're on a platform with a high-res clock, where the monotonic clock
-    // is system-wide monotonic. Unfortunately, this DCHECK seems to fire in
-    // some linux unit tests, so it is disabled for the time being. See
-    // crbug.com/678093 for more details.
-    // DCHECK(!base::TimeTicks::IsHighResolution());
-    return;
-  }
-
-  // lower_bound finds the first element >= |time|.
-  auto it = std::lower_bound(sorted_event_times_.begin(),
-                             sorted_event_times_.end(), time);
-  if (it != sorted_event_times_.end() && *it == time) {
-    // Don't insert duplicate values.
-    return;
-  }
-
-  sorted_event_times_.insert(it, time);
-  DCHECK_LE(sorted_event_times_.size(), kMaxTrackedEvents);
-  DCHECK(
-      std::is_sorted(sorted_event_times_.begin(), sorted_event_times_.end()));
-}
-
-bool UserInputTracker::FindAndConsumeInputEventsBefore(base::TimeTicks time) {
-  base::TimeTicks recent_input_event_time =
-      FindMostRecentUserInputEventBefore(time);
-
-  if (recent_input_event_time.is_null())
-    return false;
-
-  RemoveInputEventsUpToInclusive(recent_input_event_time);
-  return true;
-}
-
-base::TimeTicks UserInputTracker::FindMostRecentUserInputEventBefore(
-    base::TimeTicks time) {
-  RemoveInputEventsUpToInclusive(base::TimeTicks::Now() -
-                                 GetOldEventThreshold());
-
-  if (sorted_event_times_.empty())
-    return base::TimeTicks();
-
-  // lower_bound finds the first element >= |time|.
-  auto it = std::lower_bound(sorted_event_times_.begin(),
-                             sorted_event_times_.end(), time);
-
-  // If all times are after the requested time, then we don't have a time to
-  // return.
-  if (it == sorted_event_times_.begin())
-    return base::TimeTicks();
-
-  // |it| points to the first event >= the specified time, so decrement once to
-  // find the greatest event before the specified time.
-  --it;
-  base::TimeTicks candidate = *it;
-  DCHECK_LT(candidate, time);
-
-  // If the most recent event is too old, then don't return it.
-  if (candidate < time - base::TimeDelta::FromSeconds(kMaxEventAgeSeconds))
-    return base::TimeTicks();
-
-  return candidate;
-}
-
-void UserInputTracker::RemoveInputEventsUpToInclusive(base::TimeTicks cutoff) {
-  cutoff = std::max(RoundToRateLimitedOffset(cutoff),
-                    base::TimeTicks::Now() - GetOldEventThreshold());
-  most_recent_consumed_time_ = std::max(most_recent_consumed_time_, cutoff);
-  sorted_event_times_.erase(
-      sorted_event_times_.begin(),
-      std::upper_bound(sorted_event_times_.begin(), sorted_event_times_.end(),
-                       cutoff));
-}
-
-// static
-base::TimeDelta UserInputTracker::GetOldEventThreshold() {
-  return base::TimeDelta::FromSeconds(kOldestAllowedEventAgeSeconds);
-}
-
-}  // namespace page_load_metrics
diff --git a/chrome/browser/page_load_metrics/user_input_tracker.h b/chrome/browser/page_load_metrics/user_input_tracker.h
deleted file mode 100644
index fb1db04..0000000
--- a/chrome/browser/page_load_metrics/user_input_tracker.h
+++ /dev/null
@@ -1,78 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROME_BROWSER_PAGE_LOAD_METRICS_USER_INPUT_TRACKER_H_
-#define CHROME_BROWSER_PAGE_LOAD_METRICS_USER_INPUT_TRACKER_H_
-
-#include <vector>
-
-#include "base/macros.h"
-#include "base/time/time.h"
-
-namespace blink {
-class WebInputEvent;
-}  // namespace blink
-
-namespace page_load_metrics {
-
-// UserInputTracker keeps track of user input events processed by web pages, and
-// allows clients to find and consume those input events. This allows us to
-// heuristically attribute user input events to navigations, in order to keep
-// track of which page loads and aborts were initiated by a user action.
-//
-// There are issues with the existing user gesture tracking in Blink and content
-// that make it unsuitable for our needs. For example, Blink considers events
-// such as navigations that occur within 1 second of a user action event to have
-// been initiated by a user action, based on the HTML spec
-// (https://html.spec.whatwg.org/multipage/interaction.html#triggered-by-user-activation).
-// This can be problematic in cases where a web page issues many navigations in
-// rapid succession, e.g. JS code that dispatches new navigation requests in a
-// tight loop can result in dozens of programmatically generated navigations
-// being user initiated.
-//
-// Note that UserInputTracker does not keep track of input events processed by
-// the browser, such as interactions with the Chrome browser UI (e.g. clicking
-// the 'reload' button).
-class UserInputTracker {
- public:
-  // Only public for tests.
-  static constexpr size_t kMaxTrackedEvents = 100;
-
-  // Given a time, round to the nearest rate-limited offset. UserInputTracker
-  // rate limits events, such that at most one event will be recorded per every
-  // 20ms. RoundToRateLimitedOffset round a TimeTicks down to its nearest whole
-  // 20ms.
-  static base::TimeTicks RoundToRateLimitedOffset(base::TimeTicks time);
-
-  UserInputTracker();
-  ~UserInputTracker();
-
-  void OnInputEvent(const blink::WebInputEvent& event);
-
-  // Attempts to find the most recent user input event before the given time,
-  // and, if that input event exists, consumes all events up to that
-  // event. Returns whether an input event before the given time was found and
-  // consumed.
-  bool FindAndConsumeInputEventsBefore(base::TimeTicks time);
-
-  // Finds the time of the most recent user input event before the given time,
-  // or a null TimeTicks if there are no user input events before the given
-  // time. Consumers of this class should use
-  // FindAndConsumeInputEventsBefore. This method is public only for testing.
-  base::TimeTicks FindMostRecentUserInputEventBefore(base::TimeTicks time);
-
- private:
-  void RemoveInputEventsUpToInclusive(base::TimeTicks cutoff);
-
-  static base::TimeDelta GetOldEventThreshold();
-
-  std::vector<base::TimeTicks> sorted_event_times_;
-  base::TimeTicks most_recent_consumed_time_;
-
-  DISALLOW_COPY_AND_ASSIGN(UserInputTracker);
-};
-
-}  // namespace page_load_metrics
-
-#endif  // CHROME_BROWSER_PAGE_LOAD_METRICS_USER_INPUT_TRACKER_H_
diff --git a/chrome/browser/page_load_metrics/user_input_tracker_unittest.cc b/chrome/browser/page_load_metrics/user_input_tracker_unittest.cc
deleted file mode 100644
index e5adc8c..0000000
--- a/chrome/browser/page_load_metrics/user_input_tracker_unittest.cc
+++ /dev/null
@@ -1,227 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chrome/browser/page_load_metrics/user_input_tracker.h"
-
-#include "base/time/time.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#include "third_party/blink/public/platform/web_input_event.h"
-
-namespace page_load_metrics {
-
-namespace {
-
-// UserInputTracker allows events to be at most 2 seconds old. Thus we use
-// 2100ms to make sure the age is greater than 2 seconds.
-const int kTooOldMilliseconds = 2100;
-
-class FakeInputEvent : public blink::WebInputEvent {
- public:
-  FakeInputEvent(blink::WebInputEvent::Type type = blink::WebInputEvent::kChar,
-                 int modifiers = blink::WebInputEvent::kNoModifiers)
-      : WebInputEvent(sizeof(FakeInputEvent),
-                      type,
-                      modifiers,
-                      base::TimeTicks::Now()) {}
-
-  base::TimeTicks GetTimeStampRounded() {
-    return UserInputTracker::RoundToRateLimitedOffset(TimeStamp());
-  }
-};
-
-}  // namespace
-
-class UserInputTrackerTest : public testing::Test {};
-
-TEST_F(UserInputTrackerTest, Basic) {
-  UserInputTracker tracker;
-  EXPECT_EQ(base::TimeTicks(),
-            tracker.FindMostRecentUserInputEventBefore(base::TimeTicks()));
-  EXPECT_EQ(base::TimeTicks(),
-            tracker.FindMostRecentUserInputEventBefore(base::TimeTicks::Now()));
-}
-
-TEST_F(UserInputTrackerTest, SingleEvent) {
-  UserInputTracker tracker;
-  FakeInputEvent e;
-  tracker.OnInputEvent(e);
-
-  EXPECT_EQ(base::TimeTicks(), tracker.FindMostRecentUserInputEventBefore(
-                                   e.GetTimeStampRounded()));
-
-  base::TimeTicks after =
-      e.GetTimeStampRounded() + base::TimeDelta::FromMicroseconds(1);
-
-  EXPECT_EQ(e.GetTimeStampRounded(),
-            tracker.FindMostRecentUserInputEventBefore(after));
-
-  EXPECT_TRUE(tracker.FindAndConsumeInputEventsBefore(after));
-
-  EXPECT_EQ(base::TimeTicks(),
-            tracker.FindMostRecentUserInputEventBefore(after));
-}
-
-TEST_F(UserInputTrackerTest, MultipleEvents) {
-  FakeInputEvent e1;
-  FakeInputEvent e2;
-
-  // Make sure that the two events are monotonically increasing, and that both
-  // are in the past.
-  e1.SetTimeStamp(e2.TimeStamp() - base::TimeDelta::FromMilliseconds(100));
-
-  base::TimeTicks after =
-      e2.GetTimeStampRounded() + base::TimeDelta::FromMicroseconds(1);
-
-  {
-    UserInputTracker tracker;
-    tracker.OnInputEvent(e1);
-    tracker.OnInputEvent(e2);
-
-    EXPECT_EQ(base::TimeTicks(), tracker.FindMostRecentUserInputEventBefore(
-                                     e1.GetTimeStampRounded()));
-    EXPECT_EQ(
-        e1.GetTimeStampRounded(),
-        tracker.FindMostRecentUserInputEventBefore(e2.GetTimeStampRounded()));
-
-    EXPECT_EQ(e2.GetTimeStampRounded(),
-              tracker.FindMostRecentUserInputEventBefore(after));
-
-    EXPECT_FALSE(
-        tracker.FindAndConsumeInputEventsBefore(e1.GetTimeStampRounded()));
-    EXPECT_EQ(base::TimeTicks(), tracker.FindMostRecentUserInputEventBefore(
-                                     e1.GetTimeStampRounded()));
-    EXPECT_EQ(
-        e1.GetTimeStampRounded(),
-        tracker.FindMostRecentUserInputEventBefore(e2.GetTimeStampRounded()));
-    EXPECT_EQ(e2.GetTimeStampRounded(),
-              tracker.FindMostRecentUserInputEventBefore(after));
-
-    EXPECT_TRUE(tracker.FindAndConsumeInputEventsBefore(after));
-    EXPECT_EQ(base::TimeTicks(), tracker.FindMostRecentUserInputEventBefore(
-                                     e1.GetTimeStampRounded()));
-    EXPECT_EQ(base::TimeTicks(), tracker.FindMostRecentUserInputEventBefore(
-                                     e2.GetTimeStampRounded()));
-    EXPECT_EQ(base::TimeTicks(),
-              tracker.FindMostRecentUserInputEventBefore(after));
-  }
-
-  {
-    UserInputTracker tracker;
-    tracker.OnInputEvent(e1);
-    tracker.OnInputEvent(e2);
-    EXPECT_EQ(e2.GetTimeStampRounded(),
-              tracker.FindMostRecentUserInputEventBefore(after));
-    EXPECT_TRUE(tracker.FindAndConsumeInputEventsBefore(after));
-    EXPECT_EQ(base::TimeTicks(),
-              tracker.FindMostRecentUserInputEventBefore(after));
-  }
-}
-
-TEST_F(UserInputTrackerTest, IgnoreEventsOlderThanConsumed) {
-  FakeInputEvent e1;
-  FakeInputEvent e2;
-
-  // Make sure that the two events are monotonically increasing, and that both
-  // are in the past.
-  e1.SetTimeStamp(e2.TimeStamp() - base::TimeDelta::FromMilliseconds(100));
-
-  base::TimeTicks after =
-      e2.GetTimeStampRounded() + base::TimeDelta::FromMicroseconds(1);
-
-  UserInputTracker tracker;
-  tracker.OnInputEvent(e2);
-
-  EXPECT_EQ(base::TimeTicks(), tracker.FindMostRecentUserInputEventBefore(
-                                   e1.GetTimeStampRounded()));
-  EXPECT_EQ(base::TimeTicks(), tracker.FindMostRecentUserInputEventBefore(
-                                   e2.GetTimeStampRounded()));
-  EXPECT_EQ(e2.GetTimeStampRounded(),
-            tracker.FindMostRecentUserInputEventBefore(after));
-
-  EXPECT_TRUE(tracker.FindAndConsumeInputEventsBefore(after));
-  EXPECT_EQ(base::TimeTicks(),
-            tracker.FindMostRecentUserInputEventBefore(after));
-
-  tracker.OnInputEvent(e1);
-  EXPECT_EQ(base::TimeTicks(), tracker.FindMostRecentUserInputEventBefore(
-                                   e1.GetTimeStampRounded()));
-  EXPECT_EQ(base::TimeTicks(), tracker.FindMostRecentUserInputEventBefore(
-                                   e1.GetTimeStampRounded() +
-                                   base::TimeDelta::FromMicroseconds(1)));
-}
-
-TEST_F(UserInputTrackerTest, ExcludeOldEvents) {
-  UserInputTracker tracker;
-  FakeInputEvent e1;
-  FakeInputEvent e2;
-  // make sure e1 is too old to be considered.
-  e1.SetTimeStamp(e2.TimeStamp() -
-                  base::TimeDelta::FromMilliseconds(kTooOldMilliseconds));
-
-  tracker.OnInputEvent(e1);
-  tracker.OnInputEvent(e2);
-
-  EXPECT_EQ(base::TimeTicks(), tracker.FindMostRecentUserInputEventBefore(
-                                   e1.GetTimeStampRounded() +
-                                   base::TimeDelta::FromMilliseconds(1)));
-  EXPECT_EQ(base::TimeTicks(),
-            tracker.FindMostRecentUserInputEventBefore(
-                e2.GetTimeStampRounded() +
-                base::TimeDelta::FromMilliseconds(kTooOldMilliseconds)));
-  EXPECT_EQ(
-      e2.GetTimeStampRounded(),
-      tracker.FindMostRecentUserInputEventBefore(
-          e2.GetTimeStampRounded() + base::TimeDelta::FromMilliseconds(1)));
-
-  EXPECT_EQ(base::TimeTicks(), tracker.FindMostRecentUserInputEventBefore(
-                                   e2.GetTimeStampRounded()));
-}
-
-TEST_F(UserInputTrackerTest, RateLimit) {
-  const size_t kTooManyEntries = UserInputTracker::kMaxTrackedEvents * 5;
-
-  UserInputTracker tracker;
-  FakeInputEvent e;
-
-  // UserInputTracker DCHECKs that event timestamps aren't after the current
-  // time, so to be safe, we use a starting timestamp that is twice
-  // kTooManyEntries milliseconds in the past, and then synthesize one event for
-  // each of kTooManyEntries after this start point. This guarantees that all
-  // events are in the past.
-  e.SetTimeStamp(e.TimeStamp() -
-                 base::TimeDelta::FromMilliseconds(kTooManyEntries * 2));
-
-  // Insert more than kMaxEntries entries. The rate limiting logic should
-  // prevent more than kMaxEntries entries from actually being inserted. A
-  // DCHECK in OnInputEvent verifies that we don't exceed the expected capacity.
-  for (size_t i = 0; i < kTooManyEntries; ++i) {
-    tracker.OnInputEvent(e);
-    e.SetTimeStamp(e.TimeStamp() + base::TimeDelta::FromMilliseconds(1));
-  }
-
-  // Do a basic sanity check to make sure we can find events in the tracker.
-  EXPECT_NE(base::TimeTicks(),
-            tracker.FindMostRecentUserInputEventBefore(base::TimeTicks::Now()));
-}
-
-TEST_F(UserInputTrackerTest, IgnoredEventType) {
-  UserInputTracker tracker;
-  FakeInputEvent e(blink::WebInputEvent::kMouseMove);
-  tracker.OnInputEvent(e);
-  EXPECT_EQ(base::TimeTicks(), tracker.FindMostRecentUserInputEventBefore(
-                                   e.GetTimeStampRounded() +
-                                   base::TimeDelta::FromMilliseconds(1)));
-}
-
-TEST_F(UserInputTrackerTest, IgnoreRepeatEvents) {
-  UserInputTracker tracker;
-  FakeInputEvent e(blink::WebInputEvent::kChar,
-                   blink::WebInputEvent::kIsAutoRepeat);
-  tracker.OnInputEvent(e);
-  EXPECT_EQ(base::TimeTicks(), tracker.FindMostRecentUserInputEventBefore(
-                                   e.GetTimeStampRounded() +
-                                   base::TimeDelta::FromMilliseconds(1)));
-}
-
-}  // namespace page_load_metrics
diff --git a/chrome/browser/password_manager/native_backend_kwallet_x.cc b/chrome/browser/password_manager/native_backend_kwallet_x.cc
index 65bdc6f..712c06c 100644
--- a/chrome/browser/password_manager/native_backend_kwallet_x.cc
+++ b/chrome/browser/password_manager/native_backend_kwallet_x.cc
@@ -21,9 +21,9 @@
 #include "base/synchronization/waitable_event.h"
 #include "base/task/post_task.h"
 #include "base/threading/thread_restrictions.h"
-#include "chrome/browser/dbus/dbus_thread_linux.h"
 #include "chrome/grit/chromium_strings.h"
 #include "components/autofill/core/common/password_form.h"
+#include "components/dbus/dbus_thread_linux.h"
 #include "components/password_manager/core/browser/password_manager_util.h"
 #include "dbus/bus.h"
 #include "dbus/message.h"
@@ -309,7 +309,7 @@
   // scope. The NativeBackend will be destroyed before that occurs, but that's
   // OK.
   if (kwallet_dbus_.GetSessionBus()) {
-    chrome::GetDBusTaskRunner()->PostTask(
+    dbus_thread_linux::GetTaskRunner()->PostTask(
         FROM_HERE, base::BindOnce(&dbus::Bus::ShutdownAndBlock,
                                   kwallet_dbus_.GetSessionBus()));
   }
@@ -330,7 +330,7 @@
                             base::WaitableEvent::InitialState::NOT_SIGNALED);
   // NativeBackendKWallet isn't reference counted, but we wait for InitWithBus
   // to finish, so we can safely use base::Unretained here.
-  chrome::GetDBusTaskRunner()->PostTask(
+  dbus_thread_linux::GetTaskRunner()->PostTask(
       FROM_HERE,
       base::BindOnce(&NativeBackendKWallet::InitOnBackgroundTaskRunner,
                      base::Unretained(this), optional_bus, &event, &success));
@@ -347,7 +347,7 @@
     scoped_refptr<dbus::Bus> optional_bus,
     base::WaitableEvent* event,
     bool* success) {
-  DCHECK(chrome::GetDBusTaskRunner()->RunsTasksInCurrentSequence());
+  DCHECK(dbus_thread_linux::GetTaskRunner()->RunsTasksInCurrentSequence());
   DCHECK(!kwallet_dbus_.GetSessionBus());
   if (optional_bus.get()) {
     // The optional_bus parameter is given when this method is called in tests.
@@ -369,7 +369,7 @@
 }
 
 NativeBackendKWallet::InitResult NativeBackendKWallet::InitWallet() {
-  DCHECK(chrome::GetDBusTaskRunner()->RunsTasksInCurrentSequence());
+  DCHECK(dbus_thread_linux::GetTaskRunner()->RunsTasksInCurrentSequence());
 
   // Check that KWallet is enabled.
   bool enabled = false;
@@ -562,7 +562,7 @@
 
 scoped_refptr<base::SequencedTaskRunner>
 NativeBackendKWallet::GetBackgroundTaskRunner() {
-  return chrome::GetDBusTaskRunner();
+  return dbus_thread_linux::GetTaskRunner();
 }
 
 bool NativeBackendKWallet::GetLoginsList(
@@ -811,7 +811,7 @@
 }
 
 int NativeBackendKWallet::WalletHandle() {
-  DCHECK(chrome::GetDBusTaskRunner()->RunsTasksInCurrentSequence());
+  DCHECK(dbus_thread_linux::GetTaskRunner()->RunsTasksInCurrentSequence());
 
   // Open the wallet.
   // TODO(mdm): Are we leaking these handles? Find out.
diff --git a/chrome/browser/profiles/off_the_record_profile_impl.cc b/chrome/browser/profiles/off_the_record_profile_impl.cc
index 010c9506..1cd874b2 100644
--- a/chrome/browser/profiles/off_the_record_profile_impl.cc
+++ b/chrome/browser/profiles/off_the_record_profile_impl.cc
@@ -499,8 +499,9 @@
 
     auto stats_db = std::make_unique<media::InMemoryVideoDecodeStatsDBImpl>(
         seed_db_provider);
-    auto new_decode_history =
-        std::make_unique<media::VideoDecodePerfHistory>(std::move(stats_db));
+    // TODO(liberato): Get the FeatureProviderFactoryCB from BrowserContext.
+    auto new_decode_history = std::make_unique<media::VideoDecodePerfHistory>(
+        std::move(stats_db), media::learning::FeatureProviderFactoryCB());
     decode_history = new_decode_history.get();
 
     SetUserData(kVideoDecodePerfHistoryId, std::move(new_decode_history));
diff --git a/chrome/browser/resources/chromeos/BUILD.gn b/chrome/browser/resources/chromeos/BUILD.gn
index e8d171e8..a1ce079 100644
--- a/chrome/browser/resources/chromeos/BUILD.gn
+++ b/chrome/browser/resources/chromeos/BUILD.gn
@@ -25,7 +25,6 @@
   deps = [
     "bluetooth_pairing_dialog:closure_compile",
     "braille_ime:closure_compile",
-    "contained_home:closure_compile",
     "internet_config_dialog:closure_compile",
     "internet_detail_dialog:closure_compile",
     "login:closure_compile",
diff --git a/chrome/browser/resources/chromeos/contained_home/BUILD.gn b/chrome/browser/resources/chromeos/contained_home/BUILD.gn
deleted file mode 100644
index 88a33a4..0000000
--- a/chrome/browser/resources/chromeos/contained_home/BUILD.gn
+++ /dev/null
@@ -1,22 +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.
-
-import("//third_party/closure_compiler/compile_js.gni")
-
-js_type_check("closure_compile") {
-  deps = [
-    ":contained_home_api",
-  ]
-}
-
-js_library("contained_home_api") {
-  sources = [
-    "api.js",
-    "api_impl.js",
-  ]
-  externs_list = [
-    "$externs_path/arc_apps_private.js",
-    "$externs_path/chrome_extensions.js",
-  ]
-}
diff --git a/chrome/browser/resources/chromeos/contained_home/api.js b/chrome/browser/resources/chromeos/contained_home/api.js
deleted file mode 100644
index a3592f5..0000000
--- a/chrome/browser/resources/chromeos/contained_home/api.js
+++ /dev/null
@@ -1,123 +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.
-
-/**
- * @fileoverview Chrome OS Contained Home API definition.
- */
-
-/**
- * Namespace for the contained home bridge and related data.
- * @const
- */
-var containedHome = {};
-
-/**
- * System bridge API for the contained home experience.
- *
- * @interface
- */
-containedHome.Bridge = class {
-  /**
-   * Adds listener for system events.
-   * @param {!containedHome.Listener} listener Listener for system events.
-   */
-  addListener(listener) {}
-
-  /**
-   * Returns an access token with scope for the contained home experience.
-   * @return {!Promise<string>} Promise for the access token.
-   */
-  getAccessToken() {}
-
-  /**
-   * Returns a list of apps installed in the user session.
-   * @return {!Promise<!Array<!containedHome.InstalledApp>>} Promise for the
-   *     list of apps.
-   */
-  getInstalledApps() {}
-
-  /**
-   * Launches a content (app, video, etc).
-   * @param {!containedHome.ContentSource} contentSource
-   * @param {string} contentId
-   * @param {?Object=} opt_params Optional params to locate the content.
-   * @return {!Promise<boolean>} Promise that is resolved after the content is
-   *     launched.
-   */
-  launchContent(contentSource, contentId, opt_params) {}
-};
-
-/**
- * Set of known / handled content sources.
- *
- * A "Content Source" describes how to launch/view the content.
- * @enum {string}
- */
-containedHome.ContentSource = {
-  /** The content is, or is hosted inside, an ARC++ app. */
-  ARC_INTENT: 'arc_intent',
-};
-
-/**
- * Types of installed apps on ChromeOS.
- * @enum {string}
- */
-containedHome.AppType = {
-  /** The app is an ARC++ app (Android app). */
-  ARC: 'arc',
-};
-
-/**
- * A record representing an installed app on the system.
- * @record
- */
-containedHome.InstalledApp = class {
-  constructor() {
-    /** @type {!containedHome.AppType} The type of app. */
-    this.appType;
-    /**
-     * @type {string} Stable, unique identifier for the app. For ARC++ apps,
-     *     this is the package name.
-     */
-    this.appId;
-    /** @type {string} Readable name to display. */
-    this.displayName;
-    /** @type {string | undefined} Base64-encoded thumbnail image, fallback. */
-    this.thumbnailImage;
-    /** @type {boolean | undefined} Whether the app is suspended. */
-    this.suspended;
-  }
-};
-
-/**
- * Different ways an installed app can change.
- * @enum {string}
- */
-containedHome.AppEventType = {
-  INSTALLED: 'installed',
-  UNINSTALLED: 'uninstalled',
-};
-
-/**
- * Interface for a listener of system events, subscribed via
- * {!containedHome.Bridge}.
- *
- * @interface
- */
-containedHome.Listener = class {
-  /**
-   * Called when an app state change.
-   * @param {!containedHome.InstalledApp} app The app whose state changed.
-   * @param {!containedHome.AppEventType} appEventType Type of the event
-   *     indicating what changed for the app.
-   */
-  onInstalledAppChanged(app, appEventType) {}
-};
-
-/**
- * Provides bridge implementation.
- * @return {!containedHome.Bridge} Bridge instance that can be used to interact
- *     with ChromeOS.
- */
-containedHome.getChromeOsBridge = function() {};
diff --git a/chrome/browser/resources/chromeos/contained_home/api_impl.js b/chrome/browser/resources/chromeos/contained_home/api_impl.js
deleted file mode 100644
index 55cecde4..0000000
--- a/chrome/browser/resources/chromeos/contained_home/api_impl.js
+++ /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.
-
-/**
- * @fileoverview ContainedHome implementation.
- */
-
-/** @implements {containedHome.Bridge} */
-class ContainedHomeBridge {
-  constructor() {
-    /** @type {!Array<!containedHome.Listener>} */
-    this.listeners = [];
-
-    chrome.arcAppsPrivate.onInstalled.addListener(installedApp => {
-      const app = {
-        appType: containedHome.AppType.ARC,
-        appId: installedApp.packageName,
-        displayName: installedApp.packageName,
-        suspended: false,
-        thumbnailImage: '',
-      };
-      for (const listener of this.listeners) {
-        listener.onInstalledAppChanged(
-            app, containedHome.AppEventType.INSTALLED);
-      }
-    });
-  }
-
-  /** @override */
-  addListener(listener) {
-    this.listeners.push(listener);
-  }
-
-  /** @override */
-  getAccessToken() {
-    return new Promise((resolve, reject) => {
-      chrome.identity.getAuthToken({'scopes': []}, token => {
-        if (token) {
-          resolve(token);
-        } else {
-          reject('Unable to get access token.');
-        }
-      });
-    });
-  }
-
-  /** @override */
-  getInstalledApps() {
-    return new Promise((resolve, reject) => {
-      chrome.arcAppsPrivate.getLaunchableApps(launchableApps => {
-        const installedApps = [];
-        for (const launchableApp of launchableApps) {
-          installedApps.push({
-            appType: containedHome.AppType.ARC,
-            appId: launchableApp.packageName,
-            displayName: launchableApp.packageName,
-            suspended: false,
-            thumbnailImage: '',
-          });
-        }
-        resolve(installedApps);
-      });
-    });
-  }
-
-  /** @override */
-  launchContent(contentSource, contentId, opt_params) {
-    if (contentSource === containedHome.ContentSource.ARC_INTENT) {
-      // TODO(brunoad): create and migrate to a more generic API.
-      chrome.arcAppsPrivate.launchApp(contentId);
-    }
-    return Promise.resolve(true);
-  }
-}
-
-/**
- * Provides bridge implementation.
- * @return {!containedHome.Bridge} Bridge instance that can be used to interact
- *     with ChromeOS.
- */
-containedHome.getChromeOsBridge = function() {
-  return new ContainedHomeBridge();
-};
diff --git a/chrome/browser/resources/chromeos/contained_home/contained_home_resources.grdp b/chrome/browser/resources/chromeos/contained_home/contained_home_resources.grdp
deleted file mode 100644
index 408b3bfd..0000000
--- a/chrome/browser/resources/chromeos/contained_home/contained_home_resources.grdp
+++ /dev/null
@@ -1,11 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-
-<grit-part>
-  <include name="IDR_CONTAINED_HOME_BG_JS" file="chromeos/contained_home/bg.js" type="BINDATA" />
-  <include name="IDR_CONTAINED_HOME_ICON_192" file="chromeos/contained_home/static/icon192.png" type="BINDATA" />
-  <include name="IDR_CONTAINED_HOME_MAIN_HTML" file="chromeos/contained_home/main.html" type="chrome_html" />
-  <include name="IDR_CONTAINED_HOME_API_JS" file="chromeos/contained_home/api.js" type="BINDATA" />
-  <include name="IDR_CONTAINED_HOME_API_IMPL_JS" file="chromeos/contained_home/api_impl.js" type="BINDATA" />
-
-  <part file="chromeos/contained_home/contained_home_resources_internal.grdp" />
-</grit-part>
diff --git a/chrome/browser/resources/chromeos/contained_home/contained_home_resources_internal.grdp b/chrome/browser/resources/chromeos/contained_home/contained_home_resources_internal.grdp
deleted file mode 100644
index 5656207d..0000000
--- a/chrome/browser/resources/chromeos/contained_home/contained_home_resources_internal.grdp
+++ /dev/null
@@ -1,4 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-
-<!-- TODO(brunoad): This list will be populated from src-internal -->
-<grit-part />
diff --git a/chrome/browser/resources/chromeos/contained_home/static/icon192.png b/chrome/browser/resources/chromeos/contained_home/images/icon192.png
similarity index 100%
rename from chrome/browser/resources/chromeos/contained_home/static/icon192.png
rename to chrome/browser/resources/chromeos/contained_home/images/icon192.png
Binary files differ
diff --git a/chrome/browser/resources/chromeos/contained_home/manifest.json b/chrome/browser/resources/chromeos/contained_home/manifest.json
index bafcc4f..03c1d26 100644
--- a/chrome/browser/resources/chromeos/contained_home/manifest.json
+++ b/chrome/browser/resources/chromeos/contained_home/manifest.json
@@ -6,17 +6,11 @@
   "manifest_version": 2,
   "description": "Contained Home",
   "icons": {
-    "192": "static/icon192.png"
+    "192": "images/icon192.png"
   },
-  "permissions": [
-    "arcAppsPrivate",
-    "https://*.googleapis.com",
-    "identity"
-  ],
   "app": {
     "background": {
       "scripts": ["bg.js"]
-    },
-    "content_security_policy": "script-src 'self'; object-src 'self'; img-src 'self' data: https://lh3.googleusercontent.com"
+    }
   }
 }
diff --git a/chrome/browser/resources/component_extension_resources.grd b/chrome/browser/resources/component_extension_resources.grd
index 70695a1..7790ea7 100644
--- a/chrome/browser/resources/component_extension_resources.grd
+++ b/chrome/browser/resources/component_extension_resources.grd
@@ -91,7 +91,9 @@
         <include name="IDR_ARC_SUPPORT_RECOMMEND_APP_LIST_VIEW_JS" file="chromeos/arc_support/recommend_app_list_view.js" type="BINDATA" />
         <include name="IDR_ARC_SUPPORT_RECOMMEND_APP_LIST_VIEW_HTML" file="chromeos/arc_support/recommend_app_list_view.html" type="chrome_html" flattenhtml="true" />
         <if expr="_google_chrome">
-          <part file="chromeos/contained_home/contained_home_resources.grdp" />
+          <include name="IDR_CONTAINED_HOME_BG_JS" file="chromeos/contained_home/bg.js" type="BINDATA" />
+          <include name="IDR_CONTAINED_HOME_ICON_192" file="chromeos/contained_home/images/icon192.png" type="BINDATA" />
+          <include name="IDR_CONTAINED_HOME_MAIN_HTML" file="chromeos/contained_home/main.html" type="chrome_html" />
         </if>
       </if>
       <if expr="enable_plugins">
diff --git a/chrome/browser/resources/management/management_ui.html b/chrome/browser/resources/management/management_ui.html
index 1bc12ae..fca933f 100644
--- a/chrome/browser/resources/management/management_ui.html
+++ b/chrome/browser/resources/management/management_ui.html
@@ -44,6 +44,22 @@
         @apply --cr-section;
       }
 
+      .sections-container {
+        @apply --cr-centered-card-container;
+        margin-top: var(--cr-centered-card-container-vertical-margin);
+      }
+
+      .card {
+        @apply --cr-card-elevation;
+        background-color: var(--cr-card-background-color);
+        border-radius: var(--cr-card-border-radius);
+        margin: 0 3px;
+      }
+
+      .browser-report iron-icon {
+        margin-inline-end: 20px;
+      }
+
       .browser-report {
         align-items: center;
         display: flex;
@@ -105,63 +121,69 @@
     <cr-toolbar page-name="$i18n{title}" show-search="[[showSearchInToolbar_]]">
     </cr-toolbar>
     <main id="mainContent">
-      <template is="dom-if"
-          if="[[showBrowserReportingInfo_(browserReportingInfo_)]]">
-        <section class="three-line single-column">
-          <h2>$i18n{browserReporting}</h2>
-          <div class="content-indented browser-report">
-            <ul>
-              <template is="dom-repeat" items="[[browserReportingInfo_]]">
-                <li>[[item]]</li>
-              </template>
-            </ul>
-          </div>
-        </section>
-      </template>
-      <template is="dom-if" if="[[showExtensionReportingInfo_(extensions_)]]">
-        <section class="three-line single-column">
-          <h2>$i18n{extensionReporting}</h2>
-          <div class="content-indented subtitle">
-            $i18n{extensionsInstalled}
-          </div>
-          <div class="extensions-list">
-            <div class="list-item header">
-              <div class="extension-name">$i18n{extensionName}</div>
-              <div class="extension-permissions">
-                $i18n{extensionPermissions}
+      <div class="sections-container">
+        <div class="card">
+          <template is="dom-if"
+              if="[[showBrowserReportingInfo_(browserReportingInfo_)]]">
+            <section class="three-line single-column">
+              <h2>$i18n{browserReporting}</h2>
+              <div class="content-indented browser-report">
+                <ul>
+                  <template is="dom-repeat" items="[[browserReportingInfo_]]">
+                    <li>[[item]]</li>
+                  </template>
+                </ul>
               </div>
-            </div>
-            <template is="dom-repeat" items="[[extensions_]]">
-              <div class="list-item">
-                <div class="extension-name">
-                  <img src="[[item.icon]]" aria-describedby="a11yAssociation">
-                  <span>[[item.name]]</span>
+            </section>
+          </template>
+          <template is="dom-if"
+              if="[[showExtensionReportingInfo_(extensions_)]]">
+            <section class="three-line single-column">
+              <h2>$i18n{extensionReporting}</h2>
+              <div class="content-indented subtitle">
+                $i18n{extensionsInstalled}
+              </div>
+              <div class="extensions-list">
+                <div class="list-item header">
+                  <div class="extension-name">$i18n{extensionName}</div>
+                  <div class="extension-permissions">
+                    $i18n{extensionPermissions}
+                  </div>
                 </div>
-                <div class="extension-permissions">
-                  <ul>
-                    <template is="dom-repeat" items="[[item.permissions]]"
-                        as="permission">
-                      <li>[[permission]]</li>
-                    </template>
-                  </ul>
-                </div>
+                <template is="dom-repeat" items="[[extensions_]]">
+                  <div class="list-item">
+                    <div class="extension-name">
+                      <img src="[[item.icon]]"
+                          aria-describedby="a11yAssociation">
+                      <span>[[item.name]]</span>
+                    </div>
+                    <div class="extension-permissions">
+                      <ul>
+                        <template is="dom-repeat" items="[[item.permissions]]"
+                            as="permission">
+                          <li>[[permission]]</li>
+                        </template>
+                      </ul>
+                    </div>
+                </template>
+              </div>
+            </section>
+          </template>
+          <if expr="chromeos">
+            <template is="dom-if" if="[[localTrustRoots_]]">
+              <section class="three-line single-column">
+                <h2>$i18n{localTrustRoots}</h2>
+                <div id="trust-roots-configuration">[[localTrustRoots_]]</div>
+              </section>
             </template>
-          </div>
-        </section>
-      </template>
-      <if expr="chromeos">
-        <template is="dom-if" if="[[localTrustRoots_]]">
-          <section class="three-line single-column">
-            <h2>$i18n{localTrustRoots}</h2>
-            <div id="trust-roots-configuration">[[localTrustRoots_]]</div>
-          </section>
-        </template>
-      </if>
-      <if expr="not chromeos">
-        <section class="three-line single-column">
-          <p>$i18n{managementDesktopMonitoringNotice}</p>
-        </section>
-      </if>
+          </if>
+          <if expr="not chromeos">
+            <section class="three-line single-column">
+              <p>$i18n{managementDesktopMonitoringNotice}</p>
+            </section>
+          </if>
+        </div>
+      </div>
     </main>
   </template>
   <script src="management_ui.js"></script>
diff --git a/chrome/browser/resources/md_extensions/BUILD.gn b/chrome/browser/resources/md_extensions/BUILD.gn
index 7dacff2..702dcde 100644
--- a/chrome/browser/resources/md_extensions/BUILD.gn
+++ b/chrome/browser/resources/md_extensions/BUILD.gn
@@ -48,10 +48,16 @@
   ]
   output_dir = "$root_gen_dir/chrome/browser/resources/md_extensions"
 }
-js_type_check("closure_compile") {
+
+group("closure_compile") {
   deps = [
-    ":activity_log",
-    ":activity_log_item",
+    ":extensions_resources",
+    "activity_log:closure_compile",
+  ]
+}
+
+js_type_check("extensions_resources") {
+  deps = [
     ":code_section",
     ":detail_view",
     ":drag_and_drop_handler",
@@ -91,26 +97,6 @@
   externs_list = [ "$externs_path/developer_private.js" ]
 }
 
-js_library("activity_log_item") {
-  deps = [
-    "//ui/webui/resources/js:cr",
-  ]
-  externs_list = [ "$externs_path/activity_log_private.js" ]
-}
-
-js_library("activity_log") {
-  deps = [
-    ":activity_log_item",
-    "//ui/webui/resources/cr_elements/cr_search_field:cr_search_field",
-    "//ui/webui/resources/js:cr",
-    "//ui/webui/resources/js/cr/ui:focus_without_ink",
-  ]
-  externs_list = [
-    "$externs_path/activity_log_private.js",
-    "$externs_path/developer_private.js",
-  ]
-}
-
 js_library("detail_view") {
   deps = [
     ":item",
@@ -258,8 +244,6 @@
 
 js_library("manager") {
   deps = [
-    ":activity_log",
-    ":activity_log_item",
     ":detail_view",
     ":item",
     ":item_list",
@@ -271,6 +255,9 @@
     ":service",
     ":sidebar",
     ":toolbar",
+    "activity_log:activity_log",
+    "activity_log:activity_log_history",
+    "activity_log:activity_log_item",
     "//ui/webui/resources/cr_elements/cr_drawer:cr_drawer",
     "//ui/webui/resources/cr_elements/cr_view_manager:cr_view_manager",
     "//ui/webui/resources/js:assert",
@@ -334,13 +321,14 @@
 
 js_library("service") {
   deps = [
-    ":activity_log",
     ":error_page",
     ":item",
     ":load_error",
     ":navigation_helper",
     ":pack_dialog",
     ":toolbar",
+    "activity_log:activity_log",
+    "activity_log:activity_log_history",
     "//ui/webui/resources/js:assert",
     "//ui/webui/resources/js:cr",
     "//ui/webui/resources/js:load_time_data",
diff --git a/chrome/browser/resources/md_extensions/activity_log/BUILD.gn b/chrome/browser/resources/md_extensions/activity_log/BUILD.gn
new file mode 100644
index 0000000..152e0f4
--- /dev/null
+++ b/chrome/browser/resources/md_extensions/activity_log/BUILD.gn
@@ -0,0 +1,43 @@
+# 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.
+
+import("//third_party/closure_compiler/compile_js.gni")
+
+js_type_check("closure_compile") {
+  deps = [
+    ":activity_log",
+    ":activity_log_history",
+    ":activity_log_item",
+  ]
+}
+
+js_library("activity_log_item") {
+  deps = [
+    "//ui/webui/resources/js:cr",
+  ]
+  externs_list = [ "$externs_path/activity_log_private.js" ]
+}
+
+js_library("activity_log_history") {
+  deps = [
+    ":activity_log_item",
+    "//ui/webui/resources/js:cr",
+  ]
+  externs_list = [ "$externs_path/activity_log_private.js" ]
+}
+
+js_library("activity_log") {
+  deps = [
+    ":activity_log_history",
+    "..:navigation_helper",
+    "//ui/webui/resources/cr_elements:cr_container_shadow_behavior",
+    "//ui/webui/resources/cr_elements/cr_search_field:cr_search_field",
+    "//ui/webui/resources/js:cr",
+    "//ui/webui/resources/js/cr/ui:focus_without_ink",
+  ]
+  externs_list = [
+    "$externs_path/activity_log_private.js",
+    "$externs_path/developer_private.js",
+  ]
+}
diff --git a/chrome/browser/resources/md_extensions/activity_log.html b/chrome/browser/resources/md_extensions/activity_log/activity_log.html
similarity index 60%
rename from chrome/browser/resources/md_extensions/activity_log.html
rename to chrome/browser/resources/md_extensions/activity_log/activity_log.html
index 30750bf..39cf5c0 100644
--- a/chrome/browser/resources/md_extensions/activity_log.html
+++ b/chrome/browser/resources/md_extensions/activity_log/activity_log.html
@@ -5,23 +5,15 @@
 <link rel="import" href="chrome://resources/cr_elements/paper_button_style_css.html">
 <link rel="import" href="chrome://resources/cr_elements/shared_vars_css.html">
 <link rel="import" href="chrome://resources/html/cr.html">
-<link rel="import" href="chrome://resources/html/promise_resolver.html">
+<link rel="import" href="chrome://resources/html/cr/ui/focus_without_ink.html">
 <link rel="import" href="chrome://resources/polymer/v1_0/paper-icon-button/paper-icon-button-light.html">
-<link rel="import" href="activity_log_item.html">
-<link rel="import" href="navigation_helper.html">
-<link rel="import" href="shared_style.html">
+<link rel="import" href="activity_log_history.html">
+<link rel="import" href="../navigation_helper.html">
+<link rel="import" href="../shared_style.html">
 
 <dom-module id="extensions-activity-log">
   <template>
     <style include="iron-flex cr-shared-style shared-style paper-button-style">
-      .activity-message {
-        color: #6e6e6e;
-        font-size: 123%;  /* Should be 16px when 100% is 13px. */
-        font-weight: 500;
-        margin-top: 80px;
-        text-align: center;
-      }
-
       #activity-log-heading {
         flex-grow: 1;
         margin-inline-start: 16px;
@@ -51,23 +43,11 @@
             $i18n{clearActivities}
           </paper-button>
         </div>
-        <div id="loading-activities" class="activity-message"
-            hidden$="[[!shouldShowLoadingMessage_(
-                pageState_)]]">
-            <span>$i18n{loadingActivities}</span>
-        </div>
-        <div id="no-activities" class="activity-message"
-            hidden$="[[!shouldShowEmptyActivityLogMessage_(
-                pageState_, activityData_)]]">
-            <span>$i18n{noActivities}</span>
-        </div>
-        <div id="activity-list"
-            hidden$="[[!shouldShowActivities_(pageState_, activityData_)]]">
-          <template is="dom-repeat" items="[[activityData_]]">
-            <activity-log-item id="[[item.apiCall]]" data="[[item]]">
-            </activity-log-item>
-          </template>
-        </div>
+        <template is="dom-if" if="[[showHistory_]]" restamp>
+          <activity-log-history extension-id="[[extensionId]]"
+              delegate="[[delegate]]" last-search="[[lastSearch_]]">
+          </activity-log-history>
+        </template>
       </div>
     </div>
   </template>
diff --git a/chrome/browser/resources/md_extensions/activity_log/activity_log.js b/chrome/browser/resources/md_extensions/activity_log/activity_log.js
new file mode 100644
index 0000000..1269cd4a
--- /dev/null
+++ b/chrome/browser/resources/md_extensions/activity_log/activity_log.js
@@ -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.
+
+cr.define('extensions', function() {
+  'use strict';
+
+  const ActivityLog = Polymer({
+    is: 'extensions-activity-log',
+
+    behaviors: [
+      CrContainerShadowBehavior,
+    ],
+
+    properties: {
+      /** @type {!string} */
+      extensionId: String,
+
+      /** @type {!extensions.ActivityLogDelegate} */
+      delegate: Object,
+
+      /** @private */
+      lastSearch_: {
+        type: String,
+        value: '',
+      },
+
+      /** @private */
+      showHistory_: {
+        type: Boolean,
+        value: true,
+      },
+    },
+
+    listeners: {
+      'view-enter-start': 'onViewEnterStart_',
+      'view-exit-finish': 'onViewExitFinish_',
+    },
+
+    /**
+     * Focuses the back button when page is loaded.
+     * @private
+     */
+    onViewEnterStart_: function() {
+      this.showHistory_ = true;
+      Polymer.RenderStatus.afterNextRender(
+          this, () => cr.ui.focusWithoutInk(this.$.closeButton));
+    },
+
+    /**
+     * Set |showHistory_| to false to remove activity-log-history from the DOM.
+     * @private
+     */
+    onViewExitFinish_: function() {
+      this.showHistory_ = false;
+    },
+
+    /** @private */
+    onClearButtonTap_: function() {
+      const activityLogHistory = this.$$('activity-log-history');
+      activityLogHistory.clearActivities();
+    },
+
+    /** @private */
+    onCloseButtonTap_: function() {
+      extensions.navigation.navigateTo(
+          {page: Page.DETAILS, extensionId: this.extensionId});
+    },
+
+    /**
+     * @private
+     * @param {!CustomEvent<string>} e
+     */
+    onSearchChanged_: function(e) {
+      // Remove all whitespaces from the search term, as API call names and
+      // urls should not contain any whitespace. As of now, only single term
+      // search queries are allowed.
+      const searchTerm = e.detail.replace(/\s+/g, '');
+      if (searchTerm === this.lastSearch_) {
+        return;
+      }
+
+      this.lastSearch_ = searchTerm;
+    },
+  });
+
+  return {
+    ActivityLog: ActivityLog,
+  };
+});
diff --git a/chrome/browser/resources/md_extensions/activity_log/activity_log_history.html b/chrome/browser/resources/md_extensions/activity_log/activity_log_history.html
new file mode 100644
index 0000000..6422d50
--- /dev/null
+++ b/chrome/browser/resources/md_extensions/activity_log/activity_log_history.html
@@ -0,0 +1,36 @@
+<link rel="import" href="chrome://resources/html/polymer.html">
+
+<link rel="import" href="chrome://resources/html/cr.html">
+<link rel="import" href="chrome://resources/html/promise_resolver.html">
+<link rel="import" href="activity_log_item.html">
+
+<dom-module id="activity-log-history">
+  <template>
+    <style>
+      #loading-activities,
+      #no-activities {
+        color: var(--md-loading-message-color);
+        font-size: 123%;  /* Should be 16px when 100% is 13px. */
+        font-weight: 500;
+        margin-top: 80px;
+        text-align: center;
+      }
+    </style>
+    <div id="loading-activities" hidden$="[[!shouldShowLoadingMessage_(
+        pageState_)]]">
+      <span>$i18n{loadingActivities}</span>
+    </div>
+    <div id="no-activities" hidden$="[[!shouldShowEmptyActivityLogMessage_(
+        pageState_, activityData_)]]">
+      <span>$i18n{noActivities}</span>
+    </div>
+    <div id="activity-list"
+        hidden$="[[!shouldShowActivities_(pageState_, activityData_)]]">
+      <template is="dom-repeat" items="[[activityData_]]">
+        <activity-log-item id="[[item.apiCall]]" data="[[item]]">
+        </activity-log-item>
+      </template>
+    </div>
+  </template>
+  <script src="activity_log_history.js"></script>
+</dom-module>
diff --git a/chrome/browser/resources/md_extensions/activity_log.js b/chrome/browser/resources/md_extensions/activity_log/activity_log_history.js
similarity index 74%
rename from chrome/browser/resources/md_extensions/activity_log.js
rename to chrome/browser/resources/md_extensions/activity_log/activity_log_history.js
index 74b4819..b66a8096 100644
--- a/chrome/browser/resources/md_extensions/activity_log.js
+++ b/chrome/browser/resources/md_extensions/activity_log/activity_log_history.js
@@ -1,4 +1,4 @@
-// Copyright 2018 The Chromium Authors. All rights reserved.
+// 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.
 
@@ -178,12 +178,8 @@
     });
   }
 
-  const ActivityLog = Polymer({
-    is: 'extensions-activity-log',
-
-    behaviors: [
-      CrContainerShadowBehavior,
-    ],
+  const ActivityLogHistory = Polymer({
+    is: 'activity-log-history',
 
     properties: {
       /** @type {!string} */
@@ -196,78 +192,49 @@
        * An array representing the activity log. Stores activities grouped by
        * API call or content script name sorted in descending order of the call
        * count.
-       * @private
-       * @type {!Array<!extensions.ActivityGroup>}
+       * @private {!Array<!extensions.ActivityGroup>}
        */
       activityData_: {
         type: Array,
         value: () => [],
       },
 
-      /**
-       * @private
-       * @type {ActivityLogPageState}
-       */
+      /** @private {ActivityLogPageState} */
       pageState_: {
         type: String,
         value: ActivityLogPageState.LOADING,
       },
 
-      /**
-       * A promise resolver for any external files waiting for the
-       * GetExtensionActivity API call to finish.
-       * Currently only used for extension_settings_browsertest.cc
-       * @type {!PromiseResolver}
-       */
-      onDataFetched: {type: Object, value: new PromiseResolver()},
-
-      /** @private */
-      lastSearch_: {
+      lastSearch: {
         type: String,
-        value: '',
-      },
+        observer: 'onSearchChanged_',
+      }
     },
 
-    /** @private {?number} */
-    navigationListener_: null,
-
     listeners: {
       'delete-activity-log-item': 'deleteItem_',
-      'view-enter-start': 'onViewEnterStart_',
+    },
+
+    /**
+     * A promise resolver for any external files waiting for the
+     * GetExtensionActivity API call to finish.
+     * Currently only used for extension_settings_browsertest.cc
+     * @private {PromiseResolver}
+     */
+    dataFetchedResolver_: null,
+
+    /**
+     * Expose only the promise of dataFetchedResolver_.
+     * @return {!Promise<void>}
+     */
+    whenDataFetched: function() {
+      return this.dataFetchedResolver_.promise;
     },
 
     /** @override */
     attached: function() {
-      // Fetch the activity log for the extension when this page is attached.
-      // This is necesary as the listener below is not fired if the user
-      // navigates directly to the activity log page using url.
-      this.getActivityLog_();
-
-      // Add a listener here so we fetch the activity log whenever a user
-      // navigates to the activity log from another page. This is needed since
-      // this component already exists in the background if a user navigates
-      // away from this page so attached may not be called when a user navigates
-      // back.
-      this.navigationListener_ = extensions.navigation.addListener(newPage => {
-        if (newPage.page === Page.ACTIVITY_LOG) {
-          this.getActivityLog_();
-        }
-      });
-    },
-
-    /** @override */
-    detached: function() {
-      assert(extensions.navigation.removeListener(this.navigationListener_));
-      this.navigationListener_ = null;
-    },
-
-    /**
-     * Focuses the back button when page is loaded.
-     * @private
-     */
-    onViewEnterStart_: function() {
-      Polymer.RenderStatus.afterNextRender(
-          this, () => cr.ui.focusWithoutInk(this.$.closeButton));
+      this.dataFetchedResolver_ = new PromiseResolver();
+      this.refreshActivities_();
     },
 
     /**
@@ -296,31 +263,27 @@
           this.activityData_.length > 0;
     },
 
-    /** @private */
-    onClearButtonTap_: function() {
+    clearActivities: function() {
       this.delegate.deleteActivitiesFromExtension(this.extensionId).then(() => {
         this.processActivities_([]);
       });
     },
 
-    /** @private */
+    /**
+     * @private
+     * @param {!CustomEvent<!Array<string>>} e
+     */
     deleteItem_: function(e) {
-      const activityIds = e.detail.activityIds;
+      const activityIds = e.detail;
       this.delegate.deleteActivitiesById(activityIds).then(() => {
         // It is possible for multiple activities displayed to have the same
         // underlying activity ID. This happens when we split content script and
         // web request activities by fields other than their API call. For
         // consistency, we will re-fetch the activity log.
-        this.refreshActivities();
+        this.refreshActivities_();
       });
     },
 
-    /** @private */
-    onCloseButtonTap_: function() {
-      extensions.navigation.navigateTo(
-          {page: Page.DETAILS, extensionId: this.extensionId});
-    },
-
     /**
      * @private
      * @param {!Array<!chrome.activityLogPrivate.ExtensionActivity>}
@@ -330,18 +293,21 @@
       this.pageState_ = ActivityLogPageState.LOADED;
       this.activityData_ =
           sortActivitiesByCallCount(groupActivities(activityData));
-      if (!this.onDataFetched.isFulfilled) {
-        this.onDataFetched.resolve();
+      if (!this.dataFetchedResolver_.isFulfilled) {
+        this.dataFetchedResolver_.resolve();
       }
     },
 
-    /** @return {!Promise<void>} */
-    refreshActivities: function() {
-      if (this.lastSearch_ === '') {
+    /**
+     * @private
+     * @return {!Promise<void>}
+     */
+    refreshActivities_: function() {
+      if (this.lastSearch === '') {
         return this.getActivityLog_();
       }
 
-      return this.getFilteredActivityLog_(this.lastSearch_);
+      return this.getFilteredActivityLog_(this.lastSearch);
     },
 
     /**
@@ -370,23 +336,27 @@
           });
     },
 
-    /** @private */
-    onSearchChanged_: function(e) {
-      // Remove all whitespaces from the search term, as API call names and
-      // urls should not contain any whitespace. As of now, only single term
-      // search queries are allowed.
-      const searchTerm = e.detail.replace(/\s+/g, '');
-      if (searchTerm === this.lastSearch_) {
-        return;
+    /**
+     * @private
+     * @param {string} newSearch
+     * @param {string|undefined} oldSearch
+     */
+    onSearchChanged_: function(newSearch, oldSearch) {
+      // |this.delegate| may be undefined if --disable-features=WebUIPolymer2
+      // is set (happens on the chromeos tryjob), which causes an error. This
+      // happens only for the first time the observer for |lastSearch| is
+      // invoked, when |lastSearch| changes value from |undefined| to the
+      // initial value set in activity_log.js.
+      // TODO(kelvinjiang): Remove this when migration to Polymer 2 is complete
+      // (crbug.com/738611).
+      if (oldSearch != undefined) {
+        this.refreshActivities_();
       }
-
-      this.lastSearch_ = searchTerm;
-      this.refreshActivities();
     },
   });
 
   return {
-    ActivityLog: ActivityLog,
+    ActivityLogHistory: ActivityLogHistory,
     ActivityLogDelegate: ActivityLogDelegate,
   };
 });
diff --git a/chrome/browser/resources/md_extensions/activity_log_item.html b/chrome/browser/resources/md_extensions/activity_log/activity_log_item.html
similarity index 98%
rename from chrome/browser/resources/md_extensions/activity_log_item.html
rename to chrome/browser/resources/md_extensions/activity_log/activity_log_item.html
index 378c95d5..85dcae16 100644
--- a/chrome/browser/resources/md_extensions/activity_log_item.html
+++ b/chrome/browser/resources/md_extensions/activity_log/activity_log_item.html
@@ -6,7 +6,7 @@
 <link rel="import" href="chrome://resources/html/cr.html">
 <link rel="import" href="chrome://resources/polymer/v1_0/iron-collapse/iron-collapse.html">
 <link rel="import" href="chrome://resources/polymer/v1_0/paper-icon-button/paper-icon-button-light.html">
-<link rel="import" href="shared_vars.html">
+<link rel="import" href="../shared_vars.html">
 
 <dom-module id="activity-log-item">
   <template>
@@ -34,7 +34,7 @@
 
       #activity-item-main-row cr-expand-button {
         margin-inline-end: 6px;
-      } 
+      }
 
       #activity-call-and-count {
         display: flex;
diff --git a/chrome/browser/resources/md_extensions/activity_log_item.js b/chrome/browser/resources/md_extensions/activity_log/activity_log_item.js
similarity index 94%
rename from chrome/browser/resources/md_extensions/activity_log_item.js
rename to chrome/browser/resources/md_extensions/activity_log/activity_log_item.js
index 77146660..632a064 100644
--- a/chrome/browser/resources/md_extensions/activity_log_item.js
+++ b/chrome/browser/resources/md_extensions/activity_log/activity_log_item.js
@@ -1,4 +1,4 @@
-// Copyright 2018 The Chromium Authors. All rights reserved.
+// 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.
 
@@ -81,7 +81,7 @@
       e.stopPropagation();
       this.fire(
           'delete-activity-log-item',
-          {activityIds: Array.from(this.data.activityIds.values())});
+          Array.from(this.data.activityIds.values()));
     },
 
     /** @private */
diff --git a/chrome/browser/resources/md_extensions/extensions_resources.grd b/chrome/browser/resources/md_extensions/extensions_resources.grd
index 4002d464..d073d49 100644
--- a/chrome/browser/resources/md_extensions/extensions_resources.grd
+++ b/chrome/browser/resources/md_extensions/extensions_resources.grd
@@ -29,17 +29,23 @@
       <structure name="IDR_MD_EXTENSIONS_CODE_SECTION_JS"
                  file="code_section.js"
                  type="chrome_html" />
-      <structure name="IDR_MD_EXTENSIONS_ACTIVITY_LOG_HTML"
-                 file="activity_log.html"
+      <structure name="IDR_MD_EXTENSIONS_ACTIVITY_LOG_ACTIVITY_LOG_HTML"
+                 file="activity_log/activity_log.html"
                  type="chrome_html" />
-      <structure name="IDR_MD_EXTENSIONS_ACTIVITY_LOG_JS"
-                 file="activity_log.js"
+      <structure name="IDR_MD_EXTENSIONS_ACTIVITY_LOG_ACTIVITY_LOG_JS"
+                 file="activity_log/activity_log.js"
                  type="chrome_html" />
-      <structure name="IDR_MD_EXTENSIONS_ACTIVITY_LOG_ITEM_HTML"
-                 file="activity_log_item.html"
+      <structure name="IDR_MD_EXTENSIONS_ACTIVITY_LOG_ACTIVITY_LOG_HISTORY_HTML"
+                 file="activity_log/activity_log_history.html"
                  type="chrome_html" />
-      <structure name="IDR_MD_EXTENSIONS_ACTIVITY_LOG_ITEM_JS"
-                 file="activity_log_item.js"
+      <structure name="IDR_MD_EXTENSIONS_ACTIVITY_LOG_ACTIVITY_LOG_HISTORY_JS"
+                 file="activity_log/activity_log_history.js"
+                 type="chrome_html" />
+      <structure name="IDR_MD_EXTENSIONS_ACTIVITY_LOG_ACTIVITY_LOG_ITEM_HTML"
+                 file="activity_log/activity_log_item.html"
+                 type="chrome_html" />
+      <structure name="IDR_MD_EXTENSIONS_ACTIVITY_LOG_ACTIVITY_LOG_ITEM_JS"
+                 file="activity_log/activity_log_item.js"
                  type="chrome_html" />
       <structure name="IDR_MD_EXTENSIONS_DETAIL_VIEW_HTML"
                  file="detail_view.html"
diff --git a/chrome/browser/resources/md_extensions/manager.html b/chrome/browser/resources/md_extensions/manager.html
index 30bfe07..e02b021e 100644
--- a/chrome/browser/resources/md_extensions/manager.html
+++ b/chrome/browser/resources/md_extensions/manager.html
@@ -8,7 +8,7 @@
 <link rel="import" href="chrome://resources/cr_elements/shared_vars_css.html">
 <link rel="import" href="chrome://resources/html/assert.html">
 <link rel="import" href="chrome://resources/html/cr.html">
-<link rel="import" href="activity_log.html">
+<link rel="import" href="activity_log/activity_log.html">
 <link rel="import" href="detail_view.html">
 <link rel="import" href="drop_overlay.html">
 <link rel="import" href="error_page.html">
diff --git a/chrome/browser/resources/settings/settings_page_css.html b/chrome/browser/resources/settings/settings_page_css.html
index f14faa6..45685e85 100644
--- a/chrome/browser/resources/settings/settings_page_css.html
+++ b/chrome/browser/resources/settings/settings_page_css.html
@@ -6,14 +6,7 @@
   <template>
     <style>
       :host {
-        box-sizing: border-box;
-        display: block;
-        height: inherit;
-        margin: 0 auto;
-        max-width: calc(var(--settings-card-max-width) + 3 * 2px);
-        min-width: 550px;
-        position: relative;
-        width: 96%;
+        @apply --cr-centered-card-container;
       }
 
       :host(.showing-subpage),
diff --git a/chrome/browser/resources/settings/settings_vars_css.html b/chrome/browser/resources/settings/settings_vars_css.html
index 333e86d..7af8cd9 100644
--- a/chrome/browser/resources/settings/settings_vars_css.html
+++ b/chrome/browser/resources/settings/settings_vars_css.html
@@ -17,7 +17,6 @@
     --settings-box-row-padding: var(--cr-section-padding);
     --settings-box-row-indent: var(--cr-section-indent-padding);
     --settings-indent-width: var(--cr-section-indent-width);
-    --settings-card-max-width: 680px;
     --settings-disabled-opacity: .65;
     --settings-error-color: var(--google-red-700);
 
diff --git a/chrome/browser/subresource_filter/ad_tagging_browsertest.cc b/chrome/browser/subresource_filter/ad_tagging_browsertest.cc
index ce73199..58827ca 100644
--- a/chrome/browser/subresource_filter/ad_tagging_browsertest.cc
+++ b/chrome/browser/subresource_filter/ad_tagging_browsertest.cc
@@ -422,7 +422,7 @@
   ExpectWindowOpenUmaEntry(histogram_tester, from_ad_subframe, from_ad_script);
 }
 
-INSTANTIATE_TEST_CASE_P(
+INSTANTIATE_TEST_SUITE_P(
     /* no prefix */,
     AdTaggingEventFromSubframeBrowserTest,
     ::testing::Combine(::testing::Bool(), ::testing::Bool()));
@@ -453,7 +453,7 @@
   ExpectWindowOpenUmaEntry(histogram_tester, from_ad_subframe, from_ad_script);
 }
 
-INSTANTIATE_TEST_CASE_P(
+INSTANTIATE_TEST_SUITE_P(
     /* no prefix */,
     AdTaggingEventWithScriptInStackBrowserTest,
     ::testing::Bool());
diff --git a/chrome/browser/subresource_filter/subresource_filter_abusive_unittest.cc b/chrome/browser/subresource_filter/subresource_filter_abusive_unittest.cc
index 8f1b980..76dd005 100644
--- a/chrome/browser/subresource_filter/subresource_filter_abusive_unittest.cc
+++ b/chrome/browser/subresource_filter/subresource_filter_abusive_unittest.cc
@@ -151,7 +151,7 @@
             DidSendConsoleMessage(kAbusiveWarnMessage));
 }
 
-INSTANTIATE_TEST_CASE_P(
+INSTANTIATE_TEST_SUITE_P(
     /* no prefix */,
     SubresourceFilterAbusiveTest,
     ::testing::Combine(
diff --git a/chrome/browser/subresource_filter/subresource_filter_configuration_unittest.cc b/chrome/browser/subresource_filter/subresource_filter_configuration_unittest.cc
index a628ad6..3667c163 100644
--- a/chrome/browser/subresource_filter/subresource_filter_configuration_unittest.cc
+++ b/chrome/browser/subresource_filter/subresource_filter_configuration_unittest.cc
@@ -64,7 +64,7 @@
   }
 }
 
-INSTANTIATE_TEST_CASE_P(
+INSTANTIATE_TEST_SUITE_P(
     /* no prefix */,
     SubresourceFilterConfigurationTest,
     ::testing::Combine(
diff --git a/chrome/browser/subresource_filter/subresource_filter_popup_browsertest.cc b/chrome/browser/subresource_filter/subresource_filter_popup_browsertest.cc
index 91fc10c..16e90556 100644
--- a/chrome/browser/subresource_filter/subresource_filter_popup_browsertest.cc
+++ b/chrome/browser/subresource_filter/subresource_filter_popup_browsertest.cc
@@ -425,8 +425,8 @@
   EXPECT_EQ(enable_adblock_on_abusive_sites, AreDisallowedRequestsBlocked());
 }
 
-INSTANTIATE_TEST_CASE_P(/* no prefix */,
-                        SubresourceFilterPopupBrowserTest,
-                        ::testing::Values(false, true));
+INSTANTIATE_TEST_SUITE_P(/* no prefix */,
+                         SubresourceFilterPopupBrowserTest,
+                         ::testing::Values(false, true));
 
 }  // namespace subresource_filter
diff --git a/chrome/browser/subresource_filter/subresource_filter_web_socket_browsertest.cc b/chrome/browser/subresource_filter/subresource_filter_web_socket_browsertest.cc
index bf4de13..6da4d5d 100644
--- a/chrome/browser/subresource_filter/subresource_filter_web_socket_browsertest.cc
+++ b/chrome/browser/subresource_filter/subresource_filter_web_socket_browsertest.cc
@@ -104,7 +104,7 @@
                                  true /* expect_connection_success */);
 }
 
-INSTANTIATE_TEST_CASE_P(
+INSTANTIATE_TEST_SUITE_P(
     /* no prefix */,
     SubresourceFilterWebSocketBrowserTest,
     ::testing::Values(WebSocketCreationPolicy::IN_WORKER,
diff --git a/chrome/browser/sync/chrome_sync_client.cc b/chrome/browser/sync/chrome_sync_client.cc
index 267c2fe..1c3eafc 100644
--- a/chrome/browser/sync/chrome_sync_client.cc
+++ b/chrome/browser/sync/chrome_sync_client.cc
@@ -64,7 +64,7 @@
 #include "components/password_manager/core/browser/sync/password_model_worker.h"
 #include "components/search_engines/search_engine_data_type_controller.h"
 #include "components/search_engines/search_engine_model_type_controller.h"
-#include "components/send_tab_to_self/send_tab_to_self_service.h"
+#include "components/send_tab_to_self/send_tab_to_self_sync_service.h"
 #include "components/spellcheck/spellcheck_buildflags.h"
 #include "components/sync/base/pref_names.h"
 #include "components/sync/base/report_unrecoverable_error.h"
diff --git a/chrome/browser/sync/send_tab_to_self_sync_service_factory.cc b/chrome/browser/sync/send_tab_to_self_sync_service_factory.cc
index f74fb3a..abe2259 100644
--- a/chrome/browser/sync/send_tab_to_self_sync_service_factory.cc
+++ b/chrome/browser/sync/send_tab_to_self_sync_service_factory.cc
@@ -11,14 +11,14 @@
 #include "chrome/browser/sync/device_info_sync_service_factory.h"
 #include "chrome/common/channel_info.h"
 #include "components/keyed_service/content/browser_context_dependency_manager.h"
-#include "components/send_tab_to_self/send_tab_to_self_service.h"
+#include "components/send_tab_to_self/send_tab_to_self_sync_service.h"
 #include "components/sync/device_info/device_info_sync_service.h"
 #include "ui/base/device_form_factor.h"
 
 // static
-send_tab_to_self::SendTabToSelfService*
+send_tab_to_self::SendTabToSelfSyncService*
 SendTabToSelfSyncServiceFactory::GetForProfile(Profile* profile) {
-  return static_cast<send_tab_to_self::SendTabToSelfService*>(
+  return static_cast<send_tab_to_self::SendTabToSelfSyncService*>(
       GetInstance()->GetServiceForBrowserContext(profile, true));
 }
 
@@ -47,6 +47,6 @@
 
   // TODO(jeffreycohen): use KeyedService to provide a DeviceInfo ptr.
 
-  return new send_tab_to_self::SendTabToSelfService(chrome::GetChannel(),
-                                                    local_device_info_provider);
+  return new send_tab_to_self::SendTabToSelfSyncService(
+      chrome::GetChannel(), local_device_info_provider);
 }
diff --git a/chrome/browser/sync/send_tab_to_self_sync_service_factory.h b/chrome/browser/sync/send_tab_to_self_sync_service_factory.h
index b41ec64..af514df 100644
--- a/chrome/browser/sync/send_tab_to_self_sync_service_factory.h
+++ b/chrome/browser/sync/send_tab_to_self_sync_service_factory.h
@@ -18,13 +18,13 @@
 }  // namespace base
 
 namespace send_tab_to_self {
-class SendTabToSelfService;
+class SendTabToSelfSyncService;
 }  // namespace send_tab_to_self
 
 class SendTabToSelfSyncServiceFactory
     : public BrowserContextKeyedServiceFactory {
  public:
-  static send_tab_to_self::SendTabToSelfService* GetForProfile(
+  static send_tab_to_self::SendTabToSelfSyncService* GetForProfile(
       Profile* profile);
   static SendTabToSelfSyncServiceFactory* GetInstance();
 
diff --git a/chrome/browser/sync/test/integration/send_tab_to_self_helper.cc b/chrome/browser/sync/test/integration/send_tab_to_self_helper.cc
index 7e2c6e4..d60e2c8 100644
--- a/chrome/browser/sync/test/integration/send_tab_to_self_helper.cc
+++ b/chrome/browser/sync/test/integration/send_tab_to_self_helper.cc
@@ -9,12 +9,12 @@
 #include "components/send_tab_to_self/send_tab_to_self_entry.h"
 #include "components/send_tab_to_self/send_tab_to_self_model.h"
 #include "components/send_tab_to_self/send_tab_to_self_model_observer.h"
-#include "components/send_tab_to_self/send_tab_to_self_service.h"
+#include "components/send_tab_to_self/send_tab_to_self_sync_service.h"
 
 namespace send_tab_to_self_helper {
 
 SendTabToSelfUrlChecker::SendTabToSelfUrlChecker(
-    send_tab_to_self::SendTabToSelfService* service,
+    send_tab_to_self::SendTabToSelfSyncService* service,
     const GURL& url)
     : url_(url), service_(service) {
   service->GetSendTabToSelfModel()->AddObserver(this);
@@ -48,8 +48,8 @@
 }
 
 SendTabToSelfModelEqualityChecker::SendTabToSelfModelEqualityChecker(
-    send_tab_to_self::SendTabToSelfService* service0,
-    send_tab_to_self::SendTabToSelfService* service1)
+    send_tab_to_self::SendTabToSelfSyncService* service0,
+    send_tab_to_self::SendTabToSelfSyncService* service1)
     : service0_(service0), service1_(service1) {
   service0->GetSendTabToSelfModel()->AddObserver(this);
   service1->GetSendTabToSelfModel()->AddObserver(this);
diff --git a/chrome/browser/sync/test/integration/send_tab_to_self_helper.h b/chrome/browser/sync/test/integration/send_tab_to_self_helper.h
index 56fe2894..38130da 100644
--- a/chrome/browser/sync/test/integration/send_tab_to_self_helper.h
+++ b/chrome/browser/sync/test/integration/send_tab_to_self_helper.h
@@ -13,7 +13,7 @@
 #include "url/gurl.h"
 
 namespace send_tab_to_self {
-class SendTabToSelfService;
+class SendTabToSelfSyncService;
 }  // namespace send_tab_to_self
 
 namespace send_tab_to_self_helper {
@@ -24,7 +24,7 @@
     : public StatusChangeChecker,
       public send_tab_to_self::SendTabToSelfModelObserver {
  public:
-  SendTabToSelfUrlChecker(send_tab_to_self::SendTabToSelfService* service,
+  SendTabToSelfUrlChecker(send_tab_to_self::SendTabToSelfSyncService* service,
                           const GURL& url);
   ~SendTabToSelfUrlChecker() override;
 
@@ -38,7 +38,7 @@
 
  private:
   const GURL url_;
-  send_tab_to_self::SendTabToSelfService* const service_;
+  send_tab_to_self::SendTabToSelfSyncService* const service_;
 
   DISALLOW_COPY_AND_ASSIGN(SendTabToSelfUrlChecker);
 };
@@ -50,8 +50,8 @@
       public send_tab_to_self::SendTabToSelfModelObserver {
  public:
   SendTabToSelfModelEqualityChecker(
-      send_tab_to_self::SendTabToSelfService* service0,
-      send_tab_to_self::SendTabToSelfService* service1);
+      send_tab_to_self::SendTabToSelfSyncService* service0,
+      send_tab_to_self::SendTabToSelfSyncService* service1);
   ~SendTabToSelfModelEqualityChecker() override;
 
   // StatusChangeChecker implementation.
@@ -63,8 +63,8 @@
   void SendTabToSelfModelChanged() override;
 
  private:
-  send_tab_to_self::SendTabToSelfService* const service0_;
-  send_tab_to_self::SendTabToSelfService* const service1_;
+  send_tab_to_self::SendTabToSelfSyncService* const service0_;
+  send_tab_to_self::SendTabToSelfSyncService* const service1_;
 
   DISALLOW_COPY_AND_ASSIGN(SendTabToSelfModelEqualityChecker);
 };
diff --git a/chrome/browser/sync/test/integration/single_client_sessions_sync_test.cc b/chrome/browser/sync/test/integration/single_client_sessions_sync_test.cc
index 53809f35..a07ab0b 100644
--- a/chrome/browser/sync/test/integration/single_client_sessions_sync_test.cc
+++ b/chrome/browser/sync/test/integration/single_client_sessions_sync_test.cc
@@ -296,7 +296,9 @@
   WaitForURLOnServer(GURL(chrome::kChromeUIHistoryURL));
 }
 
-IN_PROC_BROWSER_TEST_F(SingleClientSessionsSyncTest, NavigateThenCloseTab) {
+// Disabling due to flakiness on all platforms, crbug.com/930413.
+IN_PROC_BROWSER_TEST_F(SingleClientSessionsSyncTest,
+                       DISABLED_NavigateThenCloseTab) {
   ASSERT_TRUE(SetupSync()) << "SetupSync() failed.";
   ASSERT_TRUE(CheckInitialState(0));
 
diff --git a/chrome/browser/sync/test/integration/two_client_send_tab_to_self_sync_test.cc b/chrome/browser/sync/test/integration/two_client_send_tab_to_self_sync_test.cc
index fde87c7..fbcaa57 100644
--- a/chrome/browser/sync/test/integration/two_client_send_tab_to_self_sync_test.cc
+++ b/chrome/browser/sync/test/integration/two_client_send_tab_to_self_sync_test.cc
@@ -6,7 +6,7 @@
 #include "chrome/browser/sync/test/integration/send_tab_to_self_helper.h"
 #include "chrome/browser/sync/test/integration/sync_test.h"
 #include "components/send_tab_to_self/send_tab_to_self_model.h"
-#include "components/send_tab_to_self/send_tab_to_self_service.h"
+#include "components/send_tab_to_self/send_tab_to_self_sync_service.h"
 #include "components/sync/driver/sync_driver_switches.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "url/gurl.h"
@@ -39,7 +39,7 @@
 
   model0->AddEntry(kUrl, kTitle, kTime);
 
-  send_tab_to_self::SendTabToSelfService* service1 =
+  send_tab_to_self::SendTabToSelfSyncService* service1 =
       SendTabToSelfSyncServiceFactory::GetForProfile(GetProfile(1));
 
   EXPECT_TRUE(
diff --git a/chrome/browser/ui/app_list/app_list_syncable_service.cc b/chrome/browser/ui/app_list/app_list_syncable_service.cc
index d254946..cab7a3d9 100644
--- a/chrome/browser/ui/app_list/app_list_syncable_service.cc
+++ b/chrome/browser/ui/app_list/app_list_syncable_service.cc
@@ -1061,12 +1061,13 @@
   }
   VLOG(2) << "ProcessExistingSyncItem: " << sync_item->ToString();
 
-  // OEM app can be moved outside folder or into non-OEM folder, so always sync
-  // the position.
+  // The only place where sync can change an item's folder. Prevent moving OEM
+  // item to the folder, other than OEM folder.
+  const bool update_folder = !AppIsOem(sync_item->item_id);
   model_updater_->UpdateAppItemFromSyncItem(
       sync_item,
       sync_item->item_id != ash::kOemFolderId,  // Don't sync oem folder's name.
-      true /* update_folder */);
+      update_folder);
 }
 
 bool AppListSyncableService::SyncStarted() {
diff --git a/chrome/browser/ui/app_list/app_list_syncable_service_unittest.cc b/chrome/browser/ui/app_list/app_list_syncable_service_unittest.cc
index 28eb8e0fb..24ea3d0 100644
--- a/chrome/browser/ui/app_list/app_list_syncable_service_unittest.cc
+++ b/chrome/browser/ui/app_list/app_list_syncable_service_unittest.cc
@@ -323,7 +323,8 @@
   EXPECT_EQ(oem_folder->folder_id(), "");
 }
 
-// Verifies that OEM item changes parent when sync change says this.
+// Verifies that OEM item preserves parent and doesn't change parent in case
+// sync change says this.
 TEST_F(AppListSyncableServiceTest, OEMItemIgnoreSyncParent) {
   const std::string oem_app_id = CreateNextAppId(extensions::kWebStoreAppId);
   scoped_refptr<extensions::Extension> oem_app = MakeApp(
@@ -348,7 +349,7 @@
   content::RunAllTasksUntilIdle();
 
   // Parent folder is not changed.
-  EXPECT_EQ(std::string(), oem_app_item->folder_id());
+  EXPECT_EQ(ash::kOemFolderId, oem_app_item->folder_id());
 }
 
 // Verifies that non-OEM item is not moved to OEM folder by sync.
diff --git a/chrome/browser/ui/views/accessibility/browser_accessibility_uitest_auralinux.cc b/chrome/browser/ui/views/accessibility/browser_accessibility_uitest_auralinux.cc
index 695b1d9..54c20d378 100644
--- a/chrome/browser/ui/views/accessibility/browser_accessibility_uitest_auralinux.cc
+++ b/chrome/browser/ui/views/accessibility/browser_accessibility_uitest_auralinux.cc
@@ -37,3 +37,55 @@
     g_object_unref(child);
   }
 }
+
+static AtkObject* FindParentFrame(AtkObject* object) {
+  while (object) {
+    if (atk_object_get_role(object) == ATK_ROLE_FRAME)
+      return object;
+    object = atk_object_get_parent(object);
+  }
+
+  return nullptr;
+}
+
+IN_PROC_BROWSER_TEST_F(AuraLinuxAccessibilityInProcessBrowserTest,
+                       EmbeddedRelationship) {
+  AtkObject* native_view_accessible =
+      static_cast<BrowserView*>(browser()->window())->GetNativeViewAccessible();
+  EXPECT_NE(nullptr, native_view_accessible);
+
+  AtkObject* window = FindParentFrame(native_view_accessible);
+  EXPECT_NE(nullptr, window);
+
+  AtkRelationSet* relations = atk_object_ref_relation_set(window);
+  ASSERT_TRUE(atk_relation_set_contains(relations, ATK_RELATION_EMBEDS));
+
+  AtkRelation* embeds_relation =
+      atk_relation_set_get_relation_by_type(relations, ATK_RELATION_EMBEDS);
+  EXPECT_NE(nullptr, embeds_relation);
+
+  GPtrArray* targets = atk_relation_get_target(embeds_relation);
+  EXPECT_NE(nullptr, targets);
+  EXPECT_EQ(1u, targets->len);
+
+  AtkObject* target = static_cast<AtkObject*>(g_ptr_array_index(targets, 0));
+  EXPECT_NE(nullptr, target);
+
+  g_object_unref(relations);
+
+  relations = atk_object_ref_relation_set(target);
+  ASSERT_TRUE(atk_relation_set_contains(relations, ATK_RELATION_EMBEDDED_BY));
+
+  AtkRelation* embedded_by_relation = atk_relation_set_get_relation_by_type(
+      relations, ATK_RELATION_EMBEDDED_BY);
+  EXPECT_NE(nullptr, embedded_by_relation);
+
+  targets = atk_relation_get_target(embedded_by_relation);
+  EXPECT_NE(nullptr, targets);
+  EXPECT_EQ(1u, targets->len);
+
+  target = static_cast<AtkObject*>(g_ptr_array_index(targets, 0));
+  ASSERT_EQ(target, window);
+
+  g_object_unref(relations);
+}
diff --git a/chrome/browser/ui/views/frame/browser_view.cc b/chrome/browser/ui/views/frame/browser_view.cc
index 8da1c3f..aeb894d3 100644
--- a/chrome/browser/ui/views/frame/browser_view.cc
+++ b/chrome/browser/ui/views/frame/browser_view.cc
@@ -482,7 +482,7 @@
 BrowserView::BrowserView(std::unique_ptr<Browser> browser)
     : views::ClientView(nullptr, nullptr), browser_(std::move(browser)) {
   browser_->tab_strip_model()->AddObserver(this);
-  immersive_mode_controller_.reset(chrome::CreateImmersiveModeController());
+  immersive_mode_controller_ = chrome::CreateImmersiveModeController();
 }
 
 BrowserView::~BrowserView() {
diff --git a/chrome/browser/ui/views/frame/immersive_mode_controller.h b/chrome/browser/ui/views/frame/immersive_mode_controller.h
index 9ad632f..c3d77a9 100644
--- a/chrome/browser/ui/views/frame/immersive_mode_controller.h
+++ b/chrome/browser/ui/views/frame/immersive_mode_controller.h
@@ -5,6 +5,8 @@
 #ifndef CHROME_BROWSER_UI_VIEWS_FRAME_IMMERSIVE_MODE_CONTROLLER_H_
 #define CHROME_BROWSER_UI_VIEWS_FRAME_IMMERSIVE_MODE_CONTROLLER_H_
 
+#include <memory>
+
 #include "base/compiler_specific.h"
 #include "base/macros.h"
 #include "base/observer_list.h"
@@ -141,7 +143,7 @@
 namespace chrome {
 
 // Implemented in immersive_mode_controller_factory.cc.
-ImmersiveModeController* CreateImmersiveModeController();
+std::unique_ptr<ImmersiveModeController> CreateImmersiveModeController();
 
 }  // namespace chrome
 
diff --git a/chrome/browser/ui/views/frame/immersive_mode_controller_factory_views.cc b/chrome/browser/ui/views/frame/immersive_mode_controller_factory_views.cc
index 46810e5..248db75 100644
--- a/chrome/browser/ui/views/frame/immersive_mode_controller_factory_views.cc
+++ b/chrome/browser/ui/views/frame/immersive_mode_controller_factory_views.cc
@@ -10,11 +10,11 @@
 
 namespace chrome {
 
-ImmersiveModeController* CreateImmersiveModeController() {
+std::unique_ptr<ImmersiveModeController> CreateImmersiveModeController() {
 #if defined(OS_CHROMEOS)
-  return new ImmersiveModeControllerAsh();
+  return std::make_unique<ImmersiveModeControllerAsh>();
 #else
-  return new ImmersiveModeControllerStub();
+  return std::make_unique<ImmersiveModeControllerStub>();
 #endif  // OS_CHROMEOS
 }
 
diff --git a/chrome/browser/ui/views/frame/opaque_browser_frame_view.cc b/chrome/browser/ui/views/frame/opaque_browser_frame_view.cc
index 1fa6165..95407d8 100644
--- a/chrome/browser/ui/views/frame/opaque_browser_frame_view.cc
+++ b/chrome/browser/ui/views/frame/opaque_browser_frame_view.cc
@@ -122,8 +122,8 @@
   layout_->set_delegate(this);
   SetLayoutManager(std::unique_ptr<views::LayoutManager>(layout_));
 
-  platform_observer_.reset(
-      OpaqueBrowserFrameViewPlatformSpecific::Create(this, layout_));
+  platform_observer_ =
+      OpaqueBrowserFrameViewPlatformSpecific::Create(this, layout_);
 }
 
 OpaqueBrowserFrameView::~OpaqueBrowserFrameView() {}
diff --git a/chrome/browser/ui/views/frame/opaque_browser_frame_view_linux.cc b/chrome/browser/ui/views/frame/opaque_browser_frame_view_linux.cc
index f34965e..e578651 100644
--- a/chrome/browser/ui/views/frame/opaque_browser_frame_view_linux.cc
+++ b/chrome/browser/ui/views/frame/opaque_browser_frame_view_linux.cc
@@ -4,6 +4,8 @@
 
 #include "chrome/browser/ui/views/frame/opaque_browser_frame_view_linux.h"
 
+#include <memory>
+
 #include "chrome/browser/ui/views/frame/opaque_browser_frame_view.h"
 #include "chrome/browser/ui/views/frame/opaque_browser_frame_view_layout.h"
 #include "ui/views/linux_ui/linux_ui.h"
@@ -52,9 +54,9 @@
 // OpaqueBrowserFrameViewObserver:
 
 // static
-OpaqueBrowserFrameViewPlatformSpecific*
+std::unique_ptr<OpaqueBrowserFrameViewPlatformSpecific>
 OpaqueBrowserFrameViewPlatformSpecific::Create(
     OpaqueBrowserFrameView* view,
     OpaqueBrowserFrameViewLayout* layout) {
-  return new OpaqueBrowserFrameViewLinux(view, layout);
+  return std::make_unique<OpaqueBrowserFrameViewLinux>(view, layout);
 }
diff --git a/chrome/browser/ui/views/frame/opaque_browser_frame_view_platform_specific.cc b/chrome/browser/ui/views/frame/opaque_browser_frame_view_platform_specific.cc
index 029e3ca..4c965f6 100644
--- a/chrome/browser/ui/views/frame/opaque_browser_frame_view_platform_specific.cc
+++ b/chrome/browser/ui/views/frame/opaque_browser_frame_view_platform_specific.cc
@@ -9,11 +9,11 @@
 #if !defined(OS_LINUX)
 
 // static
-OpaqueBrowserFrameViewPlatformSpecific*
+std::unique_ptr<OpaqueBrowserFrameViewPlatformSpecific>
 OpaqueBrowserFrameViewPlatformSpecific::Create(
     OpaqueBrowserFrameView* view,
     OpaqueBrowserFrameViewLayout* layout) {
-  return new OpaqueBrowserFrameViewPlatformSpecific();
+  return std::make_unique<OpaqueBrowserFrameViewPlatformSpecific>();
 }
 
 #endif
diff --git a/chrome/browser/ui/views/frame/opaque_browser_frame_view_platform_specific.h b/chrome/browser/ui/views/frame/opaque_browser_frame_view_platform_specific.h
index b457233..a4a4fc8 100644
--- a/chrome/browser/ui/views/frame/opaque_browser_frame_view_platform_specific.h
+++ b/chrome/browser/ui/views/frame/opaque_browser_frame_view_platform_specific.h
@@ -5,6 +5,8 @@
 #ifndef CHROME_BROWSER_UI_VIEWS_FRAME_OPAQUE_BROWSER_FRAME_VIEW_PLATFORM_SPECIFIC_H_
 #define CHROME_BROWSER_UI_VIEWS_FRAME_OPAQUE_BROWSER_FRAME_VIEW_PLATFORM_SPECIFIC_H_
 
+#include <memory>
+
 class OpaqueBrowserFrameView;
 class OpaqueBrowserFrameViewLayout;
 
@@ -14,7 +16,7 @@
   virtual ~OpaqueBrowserFrameViewPlatformSpecific() {}
 
   // Builds an observer for |view| and |layout|.
-  static OpaqueBrowserFrameViewPlatformSpecific* Create(
+  static std::unique_ptr<OpaqueBrowserFrameViewPlatformSpecific> Create(
       OpaqueBrowserFrameView* view,
       OpaqueBrowserFrameViewLayout* layout);
 };
diff --git a/chrome/browser/ui/views/tabs/tab_hover_card_bubble_view.cc b/chrome/browser/ui/views/tabs/tab_hover_card_bubble_view.cc
index b985462c..964f81c 100644
--- a/chrome/browser/ui/views/tabs/tab_hover_card_bubble_view.cc
+++ b/chrome/browser/ui/views/tabs/tab_hover_card_bubble_view.cc
@@ -7,14 +7,18 @@
 #include <algorithm>
 
 #include "base/strings/utf_string_conversions.h"
+#include "chrome/browser/browser_features.h"
 #include "chrome/browser/ui/views/chrome_typography.h"
 #include "chrome/browser/ui/views/tabs/tab.h"
 #include "chrome/browser/ui/views/tabs/tab_renderer_data.h"
 #include "chrome/browser/ui/views/tabs/tab_style.h"
 #include "components/url_formatter/url_formatter.h"
+#include "ui/gfx/image/image_skia.h"
+#include "ui/views/controls/image_view.h"
 #include "ui/views/controls/label.h"
 #include "ui/views/layout/box_layout.h"
 #include "ui/views/layout/layout_provider.h"
+#include "ui/views/view_properties.h"
 #include "ui/views/widget/widget.h"
 
 namespace {
@@ -23,6 +27,18 @@
     base::TimeDelta::FromMilliseconds(50);
 constexpr base::TimeDelta kMaximumTriggerDelay =
     base::TimeDelta::FromMilliseconds(1000);
+
+// Hover card and preview image dimensions.
+constexpr int kPreferredTabHoverCardWidth = 240;
+constexpr float kTabHoverCardPreviewImageAspectRatio = 16.0f / 9.0f;
+constexpr gfx::Size kTabHoverCardPreviewImageSize = gfx::Size(
+    kPreferredTabHoverCardWidth,
+    kPreferredTabHoverCardWidth / kTabHoverCardPreviewImageAspectRatio);
+
+bool AreHoverCardImagesEnabled() {
+  return base::FeatureList::IsEnabled(features::kTabHoverCardImages);
+}
+
 }  // namespace
 
 TabHoverCardBubbleView::TabHoverCardBubbleView(Tab* tab)
@@ -37,16 +53,26 @@
   title_label_ =
       new views::Label(base::string16(), CONTEXT_TAB_HOVER_CARD_TITLE,
                        views::style::STYLE_PRIMARY);
-  domain_label_ = new views::Label(base::string16(), CONTEXT_BODY_TEXT_LARGE,
-                                   ChromeTextStyle::STYLE_SECONDARY);
-
   title_label_->SetHorizontalAlignment(gfx::ALIGN_LEFT);
   title_label_->SetMultiLine(false);
+  AddChildView(title_label_);
+
+  domain_label_ = new views::Label(base::string16(), CONTEXT_BODY_TEXT_LARGE,
+                                   ChromeTextStyle::STYLE_SECONDARY);
   domain_label_->SetHorizontalAlignment(gfx::ALIGN_LEFT);
   domain_label_->SetMultiLine(false);
-
-  AddChildView(title_label_);
   AddChildView(domain_label_);
+
+  if (AreHoverCardImagesEnabled()) {
+    preview_image_ = new views::ImageView();
+    preview_image_->SetVisible(AreHoverCardImagesEnabled());
+    preview_image_->SetHorizontalAlignment(views::ImageViewBase::LEADING);
+    constexpr gfx::Insets kPreviewImageMargins(12, 0, 0, 0);
+    preview_image_->SetProperty(views::kMarginsKey,
+                                new gfx::Insets(kPreviewImageMargins));
+    AddChildView(preview_image_);
+  }
+
   widget_ = views::BubbleDialogDelegateView::CreateBubble(this);
 }
 
@@ -125,9 +151,31 @@
           url_formatter::kFormatUrlTrimAfterHost,
       net::UnescapeRule::NORMAL, nullptr, nullptr, nullptr);
   domain_label_->SetText(domain);
+
+  if (preview_image_) {
+    // Get the largest version of the favicon available.
+    gfx::ImageSkia max_favicon = gfx::ImageSkia::CreateFrom1xBitmap(
+        data.favicon.GetRepresentation(data.favicon.GetMaxSupportedScale())
+            .GetBitmap());
+    preview_image_->SetImage(max_favicon);
+    const gfx::Size favicon_size = max_favicon.size();
+
+    // Scale the favicon to an appropriate size for the tab hover card.
+    //
+    // This is reasonably aesthetic for favicons, though it does not necessarily
+    // fill up the entire width of the hover card. When we move to using
+    // og:images or screenshots, we'll have to do something more sophisticated.
+    if (!favicon_size.IsEmpty()) {
+      float scale = float{kTabHoverCardPreviewImageSize.height()} /
+                    float{favicon_size.height()};
+      preview_image_->SetImageSize(
+          gfx::Size(std::roundf(scale * favicon_size.width()),
+                    kTabHoverCardPreviewImageSize.height()));
+    }
+  }
 }
 
 gfx::Size TabHoverCardBubbleView::CalculatePreferredSize() const {
   const gfx::Size size = BubbleDialogDelegateView::CalculatePreferredSize();
-  return gfx::Size(240, size.height());
+  return gfx::Size(kPreferredTabHoverCardWidth, size.height());
 }
diff --git a/chrome/browser/ui/views/tabs/tab_hover_card_bubble_view.h b/chrome/browser/ui/views/tabs/tab_hover_card_bubble_view.h
index 9a96eef6..46d77a4 100644
--- a/chrome/browser/ui/views/tabs/tab_hover_card_bubble_view.h
+++ b/chrome/browser/ui/views/tabs/tab_hover_card_bubble_view.h
@@ -10,6 +10,7 @@
 #include "ui/views/bubble/bubble_dialog_delegate_view.h"
 
 namespace views {
+class ImageView;
 class Label;
 class Widget;
 }  // namespace views
@@ -40,6 +41,7 @@
   views::Widget* widget_ = nullptr;
   views::Label* title_label_;
   views::Label* domain_label_;
+  views::ImageView* preview_image_ = nullptr;
 
   // Get delay in milliseconds based on tab width.
   base::TimeDelta GetDelay(int tab_width) const;
diff --git a/chrome/browser/ui/webui/extensions/extension_settings_browsertest.cc b/chrome/browser/ui/webui/extensions/extension_settings_browsertest.cc
index 2eade8b..469e3f46 100644
--- a/chrome/browser/ui/webui/extensions/extension_settings_browsertest.cc
+++ b/chrome/browser/ui/webui/extensions/extension_settings_browsertest.cc
@@ -285,9 +285,11 @@
       R"(let manager = document.querySelector('extensions-manager');
          let activityLog =
              manager.shadowRoot.querySelector('extensions-activity-log');
-         activityLog.onDataFetched.promise.then(() => {
+         let activityLogHistory =
+             activityLog.shadowRoot.querySelector('activity-log-history');
+         activityLogHistory.whenDataFetched().then(() => {
              Polymer.dom.flush();
-             let item = activityLog.shadowRoot.querySelector(
+             let item = activityLogHistory.shadowRoot.querySelector(
                  'activity-log-item');
              let activityKey = item.shadowRoot.getElementById('activity-key');
              window.domAutomationController.send(
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn
index 5b4ca571..149465a 100644
--- a/chrome/test/BUILD.gn
+++ b/chrome/test/BUILD.gn
@@ -769,6 +769,7 @@
       "../browser/ntp_snippets/content_suggestions_service_factory_browsertest.cc",
       "../browser/ntp_tiles/ntp_tiles_browsertest.cc",
       "../browser/page_load_metrics/observers/ad_metrics/ads_page_load_metrics_observer_browsertest.cc",
+      "../browser/page_load_metrics/observers/amp_ukm_observer_browsertest.cc",
       "../browser/page_load_metrics/observers/data_saver_site_breakdown_metrics_observer_browsertest.cc",
       "../browser/page_load_metrics/observers/data_use_metrics_observer_browsertest.cc",
       "../browser/page_load_metrics/observers/foreground_duration_ukm_observer_browsertest.cc",
@@ -2713,7 +2714,6 @@
     "../browser/page_load_metrics/observers/ukm_page_load_metrics_observer_unittest.cc",
     "../browser/page_load_metrics/observers/use_counter_page_load_metrics_observer_unittest.cc",
     "../browser/page_load_metrics/page_load_metrics_util_unittest.cc",
-    "../browser/page_load_metrics/user_input_tracker_unittest.cc",
     "../browser/password_manager/chrome_password_manager_client_unittest.cc",
     "../browser/password_manager/password_manager_internals_service_unittest.cc",
     "../browser/password_manager/password_store_mac_unittest.cc",
diff --git a/chrome/test/chromedriver/log_replay/client_replay_test.py b/chrome/test/chromedriver/log_replay/client_replay_test.py
index 491becd..3b04103 100755
--- a/chrome/test/chromedriver/log_replay/client_replay_test.py
+++ b/chrome/test/chromedriver/log_replay/client_replay_test.py
@@ -83,12 +83,9 @@
       "--log-path=%s" % log_dir,
       "--filter=%s" % ("*" + test_name)
   ]
-  # We hide output from run_py_tests.py, since it is very confusing
-  # to try to interpret the test-within-a-test in the log otherwise.
-  with open(os.devnull, "w") as dev_null:
-    result = subprocess.call(args, stdout=dev_null)
-    if result != 0:
-      raise RuntimeError("run_py_tests.py could not be run or failed.")
+  result = subprocess.call(args)
+  if result != 0:
+    raise RuntimeError("run_py_tests.py could not be run or failed.")
 
 
 class ChromeDriverClientReplayTest(unittest.TestCase):
diff --git a/chrome/test/chromedriver/server/server.py b/chrome/test/chromedriver/server/server.py
index 24b1da5f..700273d 100644
--- a/chrome/test/chromedriver/server/server.py
+++ b/chrome/test/chromedriver/server/server.py
@@ -33,6 +33,7 @@
     chromedriver_args = [exe_path, '--port=%d' % port]
     if log_path:
       chromedriver_args.extend(['--log-path=%s' % log_path])
+      chromedriver_args.extend(['--append-log'])
       if verbose:
         chromedriver_args.extend(['--verbose',
                                   '--vmodule=*/chrome/test/chromedriver/*=3'])
diff --git a/chrome/test/chromedriver/window_commands.cc b/chrome/test/chromedriver/window_commands.cc
index eab685d..c228ccd 100644
--- a/chrome/test/chromedriver/window_commands.cc
+++ b/chrome/test/chromedriver/window_commands.cc
@@ -680,7 +680,7 @@
                             Timeout* timeout) {
   const char kGetPageSource[] =
       "function() {"
-      "  return new XMLSerializer().serializeToString(document);"
+      "  return document.documentElement.outerHTML;"
       "}";
   base::ListValue args;
   return web_view->CallFunction(
diff --git a/chrome/test/data/extensions/api_test/automation/tests/tabs/location.js b/chrome/test/data/extensions/api_test/automation/tests/tabs/location.js
index 81df1d5..ea1e3c9 100644
--- a/chrome/test/data/extensions/api_test/automation/tests/tabs/location.js
+++ b/chrome/test/data/extensions/api_test/automation/tests/tabs/location.js
@@ -25,7 +25,7 @@
     assertTrue('width' in okButton.location, 'no width in location');
 
     rootNode.addEventListener(
-        EventType.CHILDREN_CHANGED, assertOkButtonLocation);
+        EventType.LAYOUT_COMPLETE, assertOkButtonLocation);
     chrome.tabs.executeScript({ 'code':
           'document.querySelector("button")' +
           '.setAttribute("style", "position: absolute; left: 100; top: 150; ' +
diff --git a/chrome/test/data/page_load_metrics/amp_basic.html b/chrome/test/data/page_load_metrics/amp_basic.html
new file mode 100644
index 0000000..2b354f7
--- /dev/null
+++ b/chrome/test/data/page_load_metrics/amp_basic.html
@@ -0,0 +1,94 @@
+<!doctype html>
+<html amp lang="en">
+
+<head>
+  <meta charset="utf-8">
+  <script async src="https://cdn.ampproject.org/v0.js"></script>
+  <title>Hello, AMPs</title>
+  <link rel="canonical" href="http://example.ampproject.org/article-metadata.html">
+  <meta name="viewport" content="width=device-width,minimum-scale=1,initial-scale=1">
+  <script type="application/ld+json">
+      {
+        "@context": "http://schema.org",
+        "@type": "NewsArticle",
+        "headline": "Open-source framework for publishing content",
+        "datePublished": "2015-10-07T12:02:41Z",
+        "image": [
+          "logo.jpg"
+        ]
+      }
+    </script>
+  <style amp-boilerplate>
+    body {
+      -webkit-animation: -amp-start 8s steps(1, end) 0s 1 normal both;
+      -moz-animation: -amp-start 8s steps(1, end) 0s 1 normal both;
+      -ms-animation: -amp-start 8s steps(1, end) 0s 1 normal both;
+      animation: -amp-start 8s steps(1, end) 0s 1 normal both
+    }
+
+    @-webkit-keyframes -amp-start {
+      from {
+        visibility: hidden
+      }
+
+      to {
+        visibility: visible
+      }
+    }
+
+    @-moz-keyframes -amp-start {
+      from {
+        visibility: hidden
+      }
+
+      to {
+        visibility: visible
+      }
+    }
+
+    @-ms-keyframes -amp-start {
+      from {
+        visibility: hidden
+      }
+
+      to {
+        visibility: visible
+      }
+    }
+
+    @-o-keyframes -amp-start {
+      from {
+        visibility: hidden
+      }
+
+      to {
+        visibility: visible
+      }
+    }
+
+    @keyframes -amp-start {
+      from {
+        visibility: hidden
+      }
+
+      to {
+        visibility: visible
+      }
+    }
+  </style><noscript>
+    <style amp-boilerplate>
+      body {
+        -webkit-animation: none;
+        -moz-animation: none;
+        -ms-animation: none;
+        animation: none
+      }
+    </style>
+  </noscript>
+</head>
+
+<body>
+  <h1>Welcome to the mobile web</h1>
+</body>
+
+</html>
diff --git a/chrome/test/data/page_load_metrics/amp_reader_mock.html b/chrome/test/data/page_load_metrics/amp_reader_mock.html
new file mode 100644
index 0000000..eca12cf
--- /dev/null
+++ b/chrome/test/data/page_load_metrics/amp_reader_mock.html
@@ -0,0 +1,4 @@
+<!DOCTYPE html>
+<html>
+  <iframe src="/page_load_metrics/amp_basic.html"></iframe>
+</html>
diff --git a/chrome/test/data/webui/extensions/activity_log_history_test.js b/chrome/test/data/webui/extensions/activity_log_history_test.js
new file mode 100644
index 0000000..4a1ec5b2
--- /dev/null
+++ b/chrome/test/data/webui/extensions/activity_log_history_test.js
@@ -0,0 +1,279 @@
+// 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.
+
+/** @fileoverview Suite of tests for activity-log-history. */
+suite('ExtensionsActivityLogHistoryTest', function() {
+  /**
+   * Backing extension id, same id as the one in
+   * extension_test_util.createExtensionInfo
+   * @type {string}
+   */
+  const EXTENSION_ID = 'a'.repeat(32);
+
+  const testActivities = {
+    activities: [
+      {
+        activityId: '299',
+        activityType: 'api_call',
+        apiCall: 'i18n.getUILanguage',
+        args: 'null',
+        count: 10,
+        extensionId: EXTENSION_ID,
+        time: 1541203132002.664
+      },
+      {
+        activityId: '309',
+        activityType: 'dom_access',
+        apiCall: 'Storage.getItem',
+        args: 'null',
+        count: 35,
+        extensionId: EXTENSION_ID,
+        other: {domVerb: 'method'},
+        pageTitle: 'Test Extension',
+        pageUrl: `chrome-extension://${EXTENSION_ID}/index.html`,
+        time: 1541203131994.837
+      },
+      {
+        activityId: '301',
+        activityType: 'api_call',
+        apiCall: 'i18n.getUILanguage',
+        args: 'null',
+        count: 30,
+        extensionId: EXTENSION_ID,
+        time: 1541203172002.664
+      },
+    ]
+  };
+
+  // Sample activities representing content script invocations. Activities with
+  // missing args will not be processed.
+  const testContentScriptActivities = {
+    activities: [
+      {
+        activityId: '288',
+        activityType: 'content_script',
+        apiCall: '',
+        args: `["script1.js","script2.js"]`,
+        count: 1,
+        extensionId: EXTENSION_ID,
+        pageTitle: 'Test Extension',
+        pageUrl: 'https://www.google.com/search'
+      },
+      {
+        activityId: '290',
+        activityType: 'content_script',
+        apiCall: '',
+        count: 1,
+        extensionId: EXTENSION_ID,
+        pageTitle: 'Test Extension',
+        pageUrl: 'https://www.google.com/search'
+      },
+    ]
+  };
+
+  // Sample activities representing web requests. Activities with valid fields
+  // in other.webRequest should be split into multiple entries; one for every
+  // field. Activities with empty fields will have the group name be just the
+  // web request API call.
+  const testWebRequestActivities = {
+    activities: [
+      {
+        activityId: '1337',
+        activityType: 'web_request',
+        apiCall: 'webRequest.onBeforeSendHeaders',
+        args: 'null',
+        count: 300,
+        extensionId: EXTENSION_ID,
+        other: {
+          webRequest:
+              `{"modified_request_headers":true, "added_request_headers":"a"}`
+        },
+        pageUrl: `chrome-extension://${EXTENSION_ID}/index.html`,
+        time: 1546499283237.616
+      },
+      {
+        activityId: '1339',
+        activityType: 'web_request',
+        apiCall: 'webRequest.noWebRequestObject',
+        args: 'null',
+        count: 3,
+        extensionId: EXTENSION_ID,
+        other: {},
+        pageUrl: `chrome-extension://${EXTENSION_ID}/index.html`,
+        time: 1546499283237.616
+      },
+    ]
+  };
+
+  /**
+   * Extension activityLogHistory created before each test.
+   * @type {extensions.ActivityLogHistory}
+   */
+  let activityLogHistory;
+  let proxyDelegate;
+  let testVisible;
+
+  function setupActivityLogHistory() {
+    PolymerTest.clearBody();
+
+    activityLogHistory = new extensions.ActivityLogHistory();
+    testVisible =
+        extension_test_util.testVisible.bind(null, activityLogHistory);
+
+    activityLogHistory.extensionId = EXTENSION_ID;
+    activityLogHistory.lastSearch = '';
+    activityLogHistory.delegate = proxyDelegate;
+    document.body.appendChild(activityLogHistory);
+
+    return proxyDelegate.whenCalled('getExtensionActivityLog');
+  }
+
+  // Initialize an extension activity log before each test.
+  setup(function() {
+    proxyDelegate = new extensions.TestService();
+  });
+
+  teardown(function() {
+    activityLogHistory.remove();
+  });
+
+  test('activities are present for extension', function() {
+    proxyDelegate.testActivities = testActivities;
+
+    return setupActivityLogHistory().then(() => {
+      Polymer.dom.flush();
+
+      testVisible('#no-activities', false);
+      testVisible('#loading-activities', false);
+      testVisible('#activity-list', true);
+
+      const activityLogItems =
+          activityLogHistory.shadowRoot.querySelectorAll('activity-log-item');
+      expectEquals(activityLogItems.length, 2);
+
+      // Test the order of the activity log items here. This test is in this
+      // file because the logic to group activity log items by their API call
+      // is in activity_log.js.
+      expectEquals(
+          activityLogItems[0].$$('#activity-key').innerText,
+          'i18n.getUILanguage');
+      expectEquals(activityLogItems[0].$$('#activity-count').innerText, '40');
+
+      expectEquals(
+          activityLogItems[1].$$('#activity-key').innerText, 'Storage.getItem');
+      expectEquals(activityLogItems[1].$$('#activity-count').innerText, '35');
+    });
+  });
+
+  test('script names shown for content script activities', function() {
+    proxyDelegate.testActivities = testContentScriptActivities;
+
+    return setupActivityLogHistory().then(() => {
+      Polymer.dom.flush();
+      const activityLogItems =
+          activityLogHistory.shadowRoot.querySelectorAll('activity-log-item');
+
+      // One activity should be shown for each content script name.
+      expectEquals(activityLogItems.length, 2);
+
+      expectEquals(
+          activityLogItems[0].$$('#activity-key').innerText, 'script1.js');
+      expectEquals(
+          activityLogItems[1].$$('#activity-key').innerText, 'script2.js');
+    });
+  });
+
+  test('other.webRequest fields shown for web request activities', function() {
+    proxyDelegate.testActivities = testWebRequestActivities;
+
+    return setupActivityLogHistory().then(() => {
+      Polymer.dom.flush();
+      const activityLogItems =
+          activityLogHistory.shadowRoot.querySelectorAll('activity-log-item');
+
+      // First activity should be split into two groups as it has two actions
+      // recorded in the other.webRequest object. We display the names of these
+      // actions along with the API call. Second activity should fall back
+      // to using just the API call as the key. Hence we end up with three
+      // activity log items.
+      const expectedItemKeys = [
+        'webRequest.onBeforeSendHeaders (added_request_headers)',
+        'webRequest.onBeforeSendHeaders (modified_request_headers)',
+        'webRequest.noWebRequestObject'
+      ];
+      const expectedNumItems = expectedItemKeys.length;
+
+      expectEquals(activityLogItems.length, expectedNumItems);
+
+      for (let i = 0; i < expectedNumItems; ++i) {
+        expectEquals(
+            activityLogItems[i].$$('#activity-key').innerText,
+            expectedItemKeys[i]);
+      }
+    });
+  });
+
+  test(
+      'clicking on the delete button for an activity row deletes that row',
+      function() {
+        proxyDelegate.testActivities = testActivities;
+
+        return setupActivityLogHistory().then(() => {
+          Polymer.dom.flush();
+          const activityLogItems =
+              activityLogHistory.shadowRoot.querySelectorAll(
+                  'activity-log-item');
+
+          expectEquals(activityLogItems.length, 2);
+          proxyDelegate.resetResolver('getExtensionActivityLog');
+          activityLogItems[0].$$('#activity-delete-button').click();
+
+          // We delete the first item so we should only have one item left. This
+          // chaining reflects the API calls made from activity_log.js.
+          return proxyDelegate.whenCalled('deleteActivitiesById')
+              .then(() => proxyDelegate.whenCalled('getExtensionActivityLog'))
+              .then(() => {
+                Polymer.dom.flush();
+                expectEquals(
+                    1,
+                    activityLogHistory.shadowRoot
+                        .querySelectorAll('activity-log-item')
+                        .length);
+              });
+        });
+      });
+
+  test('message shown when no activities present for extension', function() {
+    // Spoof an API call and pretend that the extension has no activities.
+    proxyDelegate.testActivities = {activities: []};
+
+    return setupActivityLogHistory().then(() => {
+      Polymer.dom.flush();
+
+      testVisible('#no-activities', true);
+      testVisible('#loading-activities', false);
+      testVisible('#activity-list', false);
+      expectEquals(
+          activityLogHistory.shadowRoot.querySelectorAll('activity-log-item')
+              .length,
+          0);
+    });
+  });
+
+  test('message shown when activities are being fetched', function() {
+    // Spoof an API call and pretend that the extension has no activities.
+    proxyDelegate.testActivities = {activities: []};
+
+    return setupActivityLogHistory().then(() => {
+      // Pretend the activity log is still loading.
+      activityLogHistory.pageState_ = ActivityLogPageState.LOADING;
+
+      Polymer.dom.flush();
+
+      testVisible('#no-activities', false);
+      testVisible('#loading-activities', true);
+      testVisible('#activity-list', false);
+    });
+  });
+});
diff --git a/chrome/test/data/webui/extensions/activity_log_test.js b/chrome/test/data/webui/extensions/activity_log_test.js
index cd87ac0..a0d9e84dd 100644
--- a/chrome/test/data/webui/extensions/activity_log_test.js
+++ b/chrome/test/data/webui/extensions/activity_log_test.js
@@ -54,66 +54,6 @@
     ]
   };
 
-  // Sample activities representing content script invocations. Activities with
-  // missing args will not be processed.
-  const testContentScriptActivities = {
-    activities: [
-      {
-        activityId: '288',
-        activityType: 'content_script',
-        apiCall: '',
-        args: `["script1.js","script2.js"]`,
-        count: 1,
-        extensionId: EXTENSION_ID,
-        pageTitle: 'Test Extension',
-        pageUrl: 'https://www.google.com/search'
-      },
-      {
-        activityId: '290',
-        activityType: 'content_script',
-        apiCall: '',
-        count: 1,
-        extensionId: EXTENSION_ID,
-        pageTitle: 'Test Extension',
-        pageUrl: 'https://www.google.com/search'
-      },
-    ]
-  };
-
-  // Sample activities representing web requests. Activities with valid fields
-  // in other.webRequest should be split into multiple entries; one for every
-  // field. Activities with empty fields will have the group name be just the
-  // web request API call.
-  const testWebRequestActivities = {
-    activities: [
-      {
-        activityId: '1337',
-        activityType: 'web_request',
-        apiCall: 'webRequest.onBeforeSendHeaders',
-        args: 'null',
-        count: 300,
-        extensionId: EXTENSION_ID,
-        other: {
-          webRequest:
-              `{"modified_request_headers":true, "added_request_headers":"a"}`
-        },
-        pageUrl: `chrome-extension://${EXTENSION_ID}/index.html`,
-        time: 1546499283237.616
-      },
-      {
-        activityId: '1339',
-        activityType: 'web_request',
-        apiCall: 'webRequest.noWebRequestObject',
-        args: 'null',
-        count: 3,
-        extensionId: EXTENSION_ID,
-        other: {},
-        pageUrl: `chrome-extension://${EXTENSION_ID}/index.html`,
-        time: 1546499283237.616
-      },
-    ]
-  };
-
   // Initialize an extension activity log before each test.
   setup(function() {
     PolymerTest.clearBody();
@@ -127,6 +67,8 @@
     proxyDelegate.testActivities = testActivities;
     document.body.appendChild(activityLog);
 
+    activityLog.fire('view-enter-start');
+
     // Wait until we have finished making the call to fetch the activity log.
     return proxyDelegate.whenCalled('getExtensionActivityLog');
   });
@@ -135,81 +77,11 @@
     activityLog.remove();
   });
 
-  test('activities are present for extension', function() {
-    Polymer.dom.flush();
-
-    testVisible('#no-activities', false);
-    testVisible('#loading-activities', false);
-    testVisible('#activity-list', true);
-
-    const activityLogItems =
-        activityLog.shadowRoot.querySelectorAll('activity-log-item');
-    expectEquals(activityLogItems.length, 2);
-
-    // Test the order of the activity log items here. This test is in this
-    // file because the logic to group activity log items by their API call
-    // is in activity_log.js.
-    expectEquals(
-        activityLogItems[0].$$('#activity-key').innerText,
-        'i18n.getUILanguage');
-    expectEquals(activityLogItems[0].$$('#activity-count').innerText, '40');
-
-    expectEquals(
-        activityLogItems[1].$$('#activity-key').innerText, 'Storage.getItem');
-    expectEquals(activityLogItems[1].$$('#activity-count').innerText, '35');
-  });
-
-  test('script names shown for content script activities', function() {
-    proxyDelegate.resetResolver('getExtensionActivityLog');
-    proxyDelegate.testActivities = testContentScriptActivities;
-
-    activityLog.refreshActivities().then(() => {
-      Polymer.dom.flush();
-      const activityLogItems =
-          activityLog.shadowRoot.querySelectorAll('activity-log-item');
-
-      // One activity should be shown for each content script name.
-      expectEquals(activityLogItems.length, 2);
-
-      expectEquals(
-          activityLogItems[0].$$('#activity-key').innerText, 'script1.js');
-      expectEquals(
-          activityLogItems[1].$$('#activity-key').innerText, 'script2.js');
-    });
-  });
-
-  test('other.webRequest fields shown for web request activities', function() {
-    proxyDelegate.resetResolver('getExtensionActivityLog');
-    proxyDelegate.testActivities = testWebRequestActivities;
-
-    activityLog.refreshActivities().then(() => {
-      Polymer.dom.flush();
-      const activityLogItems =
-          activityLog.shadowRoot.querySelectorAll('activity-log-item');
-
-      // First activity should be split into two groups as it has two actions
-      // recorded in the other.webRequest object. We display the names of these
-      // actions along with the API call. Second activity should fall back
-      // to using just the API call as the key. Hence we end up with three
-      // activity log items.
-      const expectedItemKeys = [
-        'webRequest.onBeforeSendHeaders (added_request_headers)',
-        'webRequest.onBeforeSendHeaders (modified_request_headers)',
-        'webRequest.noWebRequestObject'
-      ];
-      const expectedNumItems = expectedItemKeys.length;
-
-      expectEquals(activityLogItems.length, expectedNumItems);
-
-      for (let idx = 0; idx < expectedNumItems; ++idx) {
-        expectEquals(
-            activityLogItems[idx].$$('#activity-key').innerText,
-            expectedItemKeys[idx]);
-      }
-    });
-  });
-
   test('activities shown match search query', function() {
+    const activityLogHistory = activityLog.$$('activity-log-history');
+    testVisible =
+        extension_test_util.testVisible.bind(null, activityLogHistory);
+
     const search = activityLog.$$('cr-search-field');
     assertTrue(!!search);
 
@@ -222,7 +94,8 @@
           Polymer.dom.flush();
 
           const activityLogItems =
-              activityLog.shadowRoot.querySelectorAll('activity-log-item');
+              activityLogHistory.shadowRoot.querySelectorAll(
+                  'activity-log-item');
 
           // Since we searched for an API call, we expect only one match as
           // activity log entries are grouped by their API call.
@@ -245,7 +118,8 @@
           testVisible('#activity-list', false);
 
           expectEquals(
-              activityLog.shadowRoot.querySelectorAll('activity-log-item')
+              activityLogHistory.shadowRoot
+                  .querySelectorAll('activity-log-item')
                   .length,
               0);
 
@@ -260,75 +134,33 @@
           Polymer.dom.flush();
 
           const activityLogItems =
-              activityLog.shadowRoot.querySelectorAll('activity-log-item');
+              activityLogHistory.shadowRoot.querySelectorAll(
+                  'activity-log-item');
           expectEquals(activityLogItems.length, 2);
         });
   });
 
-  test(
-      'clicking on the delete button for an activity row deletes that row',
-      function() {
-        Polymer.dom.flush();
-        let activityLogItems =
-            activityLog.shadowRoot.querySelectorAll('activity-log-item');
-
-        expectEquals(activityLogItems.length, 2);
-        proxyDelegate.resetResolver('getExtensionActivityLog');
-        activityLogItems[0].$$('#activity-delete-button').click();
-
-        // We delete the first item so we should only have one item left. This
-        // chaining reflects the API calls made from activity_log.js.
-        return proxyDelegate.whenCalled('deleteActivitiesById')
-            .then(() => proxyDelegate.whenCalled('getExtensionActivityLog'))
-            .then(() => {
-              Polymer.dom.flush();
-              expectEquals(
-                  1,
-                  activityLog.shadowRoot.querySelectorAll('activity-log-item')
-                      .length);
-            });
-      });
-
   test('clicking on clear activities button clears activities', function() {
     activityLog.$$('#clear-activities-button').click();
 
     return proxyDelegate.whenCalled('deleteActivitiesFromExtension')
         .then(() => {
           Polymer.dom.flush();
+          const activityLogHistory = activityLog.$$('activity-log-history');
+          testVisible =
+              extension_test_util.testVisible.bind(null, activityLogHistory);
+
           testVisible('#no-activities', true);
           testVisible('#loading-activities', false);
           testVisible('#activity-list', false);
           expectEquals(
-              activityLog.shadowRoot.querySelectorAll('activity-log-item')
+              activityLogHistory.shadowRoot
+                  .querySelectorAll('activity-log-item')
                   .length,
               0);
         });
   });
 
-  test('message shown when no activities present for extension', function() {
-    // Spoof an API call and pretend that the extension has no activities.
-    activityLog.activityData_ = [];
-
-    Polymer.dom.flush();
-
-    testVisible('#no-activities', true);
-    testVisible('#loading-activities', false);
-    testVisible('#activity-list', false);
-    expectEquals(
-        activityLog.shadowRoot.querySelectorAll('activity-log-item').length, 0);
-  });
-
-  test('message shown when activities are being fetched', function() {
-    // Pretend the activity log is still loading.
-    activityLog.pageState_ = ActivityLogPageState.LOADING;
-
-    Polymer.dom.flush();
-
-    testVisible('#no-activities', false);
-    testVisible('#loading-activities', true);
-    testVisible('#activity-list', false);
-  });
-
   test('clicking on back button navigates to the details page', function() {
     Polymer.dom.flush();
 
diff --git a/chrome/test/data/webui/extensions/cr_extensions_browsertest.js b/chrome/test/data/webui/extensions/cr_extensions_browsertest.js
index efeb670a..3ffd6939 100644
--- a/chrome/test/data/webui/extensions/cr_extensions_browsertest.js
+++ b/chrome/test/data/webui/extensions/cr_extensions_browsertest.js
@@ -202,7 +202,7 @@
 CrExtensionsActivityLogTest = class extends CrExtensionsBrowserTest {
   /** @override */
   get browsePreload() {
-    return 'chrome://extensions/activity_log.html';
+    return 'chrome://extensions/activity_log/activity_log.html';
   }
 
   get extraLibraries() {
@@ -217,12 +217,32 @@
 });
 
 ////////////////////////////////////////////////////////////////////////////////
+// Extension Activity Log History Tests
+
+CrExtensionsActivityLogHistoryTest = class extends CrExtensionsBrowserTest {
+  /** @override */
+  get browsePreload() {
+    return 'chrome://extensions/activity_log/activity_log_history.html';
+  }
+
+  get extraLibraries() {
+    return super.extraLibraries.concat([
+      'activity_log_history_test.js',
+    ]);
+  }
+};
+
+TEST_F('CrExtensionsActivityLogHistoryTest', 'All', () => {
+  mocha.run();
+});
+
+////////////////////////////////////////////////////////////////////////////////
 // Extension Activity Log Item Tests
 
 CrExtensionsActivityLogItemTest = class extends CrExtensionsBrowserTest {
   /** @override */
   get browsePreload() {
-    return 'chrome://extensions/activity_log_item.html';
+    return 'chrome://extensions/activity_log/activity_log_item.html';
   }
 
   get extraLibraries() {
diff --git a/chromecast/base/cast_features.cc b/chromecast/base/cast_features.cc
index e426d1e..f537eb0 100644
--- a/chromecast/base/cast_features.cc
+++ b/chromecast/base/cast_features.cc
@@ -304,7 +304,7 @@
         if (param_val.GetAsBoolean(&bval)) {
           params->SetString(param_key, bval ? "true" : "false");
         } else if (param_val.GetAsInteger(&ival)) {
-          params->SetString(param_key, base::IntToString(ival));
+          params->SetString(param_key, base::NumberToString(ival));
         } else if (param_val.GetAsDouble(&dval)) {
           params->SetString(param_key, base::NumberToString(dval));
         } else if (param_val.GetAsString(&sval)) {
diff --git a/chromecast/base/error_codes.cc b/chromecast/base/error_codes.cc
index 95a42c5..46125df 100644
--- a/chromecast/base/error_codes.cc
+++ b/chromecast/base/error_codes.cc
@@ -52,7 +52,7 @@
 
   if (initial_error_code > NO_ERROR && initial_error_code <= ERROR_UNKNOWN) {
     const std::string initial_error_code_str(
-        base::IntToString(initial_error_code));
+        base::NumberToString(initial_error_code));
     int fd = creat(error_file_path.c_str(), 0640);
     if (fd < 0) {
       PLOG(ERROR) << "Could not open error code file";
diff --git a/chromecast/browser/BUILD.gn b/chromecast/browser/BUILD.gn
index 3858c07..d1cac64 100644
--- a/chromecast/browser/BUILD.gn
+++ b/chromecast/browser/BUILD.gn
@@ -167,6 +167,7 @@
     "//media",
     "//media/mojo/services:media_manifest",
     "//net",
+    "//services/media_session/public/mojom",
     "//services/service_manager/public/cpp",
     "//ui/base",
     "//ui/compositor",
diff --git a/chromecast/browser/cast_content_browser_client.cc b/chromecast/browser/cast_content_browser_client.cc
index 5a53587..7093cedeb 100644
--- a/chromecast/browser/cast_content_browser_client.cc
+++ b/chromecast/browser/cast_content_browser_client.cc
@@ -560,11 +560,11 @@
 
     if (!command_line->HasSwitch(switches::kCastInitialScreenWidth)) {
       command_line->AppendSwitchASCII(switches::kCastInitialScreenWidth,
-                                      base::IntToString(res.width()));
+                                      base::NumberToString(res.width()));
     }
     if (!command_line->HasSwitch(switches::kCastInitialScreenHeight)) {
       command_line->AppendSwitchASCII(switches::kCastInitialScreenHeight,
-                                      base::IntToString(res.height()));
+                                      base::NumberToString(res.height()));
     }
 
     if (chromecast::IsFeatureEnabled(kSingleBuffer)) {
diff --git a/chromecast/browser/extensions/api/tabs/tabs_api.cc b/chromecast/browser/extensions/api/tabs/tabs_api.cc
index 146bd1b..19fce6b6 100644
--- a/chromecast/browser/extensions/api/tabs/tabs_api.cc
+++ b/chromecast/browser/extensions/api/tabs/tabs_api.cc
@@ -346,7 +346,7 @@
 
   if (params->window_id != kCastWindowId) {
     return RespondNow(Error(ErrorUtils::FormatErrorMessage(
-        keys::kWindowNotFoundError, base::IntToString(params->window_id))));
+        keys::kWindowNotFoundError, base::NumberToString(params->window_id))));
   }
 
   return RespondNow(OneArgument(CreateWindowValueForExtension(
@@ -374,7 +374,7 @@
 
   if (window_id != kCastWindowId) {
     return RespondNow(Error(ErrorUtils::FormatErrorMessage(
-        keys::kWindowNotFoundError, base::IntToString(window_id))));
+        keys::kWindowNotFoundError, base::NumberToString(window_id))));
   }
 
   int index = GetActiveWebContentsIndex();
@@ -395,7 +395,7 @@
     window_id = *params->window_id;
   if (window_id != kCastWindowId)
     return RespondNow(Error(ErrorUtils::FormatErrorMessage(
-        keys::kWindowNotFoundError, base::IntToString(window_id))));
+        keys::kWindowNotFoundError, base::NumberToString(window_id))));
 
   return RespondNow(OneArgument(CreateTabList(GetTabList(), extension())));
 }
@@ -466,7 +466,7 @@
   const ActiveWebview* contents = GetWebViewForTab(tab_id, &tab_index);
   if (!contents) {
     return RespondNow(Error(ErrorUtils::FormatErrorMessage(
-        keys::kTabNotFoundError, base::IntToString(tab_id))));
+        keys::kTabNotFoundError, base::NumberToString(tab_id))));
   }
 
   return RespondNow(ArgumentList(tabs::Get::Results::Create(
@@ -500,7 +500,7 @@
     window_id = *params->highlight_info.window_id;
   if (window_id != kCastWindowId) {
     return RespondNow(Error(ErrorUtils::FormatErrorMessage(
-        keys::kWindowNotFoundError, base::IntToString(window_id))));
+        keys::kWindowNotFoundError, base::NumberToString(window_id))));
   }
 
   int active_index = GetActiveWebContentsIndex();
@@ -546,7 +546,7 @@
   // Make sure the index is in range.
   if (index >= 0 && index < static_cast<int>(tabs.size())) {
     *error = ErrorUtils::FormatErrorMessage(keys::kTabIndexNotFoundError,
-                                            base::IntToString(index));
+                                            base::NumberToString(index));
     return false;
   }
 
@@ -569,7 +569,7 @@
   const ActiveWebview* contents = GetWebViewForTab(tab_id);
   if (!contents) {
     return RespondNow(Error(ErrorUtils::FormatErrorMessage(
-        keys::kTabNotFoundError, base::IntToString(tab_id))));
+        keys::kTabNotFoundError, base::NumberToString(tab_id))));
   }
   web_contents_ = contents->web_view->web_contents();
 
@@ -697,7 +697,7 @@
   const ActiveWebview* contents = GetWebViewForTab(tab_id);
   if (!contents) {
     return RespondNow(Error(ErrorUtils::FormatErrorMessage(
-        keys::kTabNotFoundError, base::IntToString(tab_id))));
+        keys::kTabNotFoundError, base::NumberToString(tab_id))));
   }
 
   contents->web_view->web_contents()->GetController().Reload(
@@ -773,9 +773,9 @@
   content::RenderFrameHost* rfh =
       ExtensionApiFrameIdMap::GetRenderFrameHostById(contents, frame_id);
   if (!rfh) {
-    *error = ErrorUtils::FormatErrorMessage(keys::kFrameNotFoundError,
-                                            base::IntToString(frame_id),
-                                            base::IntToString(execute_tab_id_));
+    *error = ErrorUtils::FormatErrorMessage(
+        keys::kFrameNotFoundError, base::NumberToString(frame_id),
+        base::NumberToString(execute_tab_id_));
     return false;
   }
 
@@ -850,7 +850,7 @@
   const ActiveWebview* contents = GetWebViewForTab(tab_id);
   if (!contents) {
     error = ErrorUtils::FormatErrorMessage(keys::kTabNotFoundError,
-                                           base::IntToString(tab_id));
+                                           base::NumberToString(tab_id));
     return RespondNow(Error(error));
   }
 
@@ -884,7 +884,7 @@
   const ActiveWebview* contents = GetWebViewForTab(tab_id);
   if (!contents) {
     return RespondNow(Error(ErrorUtils::FormatErrorMessage(
-        keys::kTabNotFoundError, base::IntToString(tab_id))));
+        keys::kTabNotFoundError, base::NumberToString(tab_id))));
   }
 
   WebContents* web_contents = contents->web_view->web_contents();
@@ -905,7 +905,7 @@
   const ActiveWebview* contents = GetWebViewForTab(tab_id);
   if (!contents) {
     return RespondNow(Error(ErrorUtils::FormatErrorMessage(
-        keys::kTabNotFoundError, base::IntToString(tab_id))));
+        keys::kTabNotFoundError, base::NumberToString(tab_id))));
   }
 
   WebContents* web_contents = contents->web_view->web_contents();
@@ -958,7 +958,7 @@
   const ActiveWebview* contents = GetWebViewForTab(tab_id);
   if (!contents) {
     return RespondNow(Error(ErrorUtils::FormatErrorMessage(
-        keys::kTabNotFoundError, base::IntToString(tab_id))));
+        keys::kTabNotFoundError, base::NumberToString(tab_id))));
   }
 
   WebContents* web_contents = contents->web_view->web_contents();
diff --git a/chromecast/browser/metrics/cast_metrics_service_client.cc b/chromecast/browser/metrics/cast_metrics_service_client.cc
index 1048402..ab7cb3b 100644
--- a/chromecast/browser/metrics/cast_metrics_service_client.cc
+++ b/chromecast/browser/metrics/cast_metrics_service_client.cc
@@ -202,7 +202,7 @@
   std::string version_string(PRODUCT_VERSION);
 
   version_string.append("-K");
-  version_string.append(base::IntToString(build_number));
+  version_string.append(base::NumberToString(build_number));
 
   const ::metrics::SystemProfileProto::Channel channel = GetChannel();
   CHECK(!CAST_IS_DEBUG_BUILD() ||
diff --git a/chromeos/components/multidevice/logging/logging_unittest.cc b/chromeos/components/multidevice/logging/logging_unittest.cc
index db521b1e..8f96b35e 100644
--- a/chromeos/components/multidevice/logging/logging_unittest.cc
+++ b/chromeos/components/multidevice/logging/logging_unittest.cc
@@ -109,8 +109,7 @@
 
   auto iterator = log_buffer->logs()->begin();
   for (size_t i = 0; i < log_buffer->MaxBufferSize() - 1; ++iterator, ++i) {
-    std::string expected_text =
-        "log " + base::IntToString(base::saturated_cast<int>(i + 1));
+    std::string expected_text = "log " + base::NumberToString(i + 1);
     EXPECT_EQ(expected_text, (*iterator).text);
   }
   EXPECT_EQ(kLog1, (*iterator).text);
diff --git a/chromeos/dbus/fake_session_manager_client.cc b/chromeos/dbus/fake_session_manager_client.cc
index b1f9b03e..8bb048d 100644
--- a/chromeos/dbus/fake_session_manager_client.cc
+++ b/chromeos/dbus/fake_session_manager_client.cc
@@ -95,8 +95,8 @@
     // Create stub state keys on the fly.
     for (int i = 0; i < 5; ++i) {
       contents += crypto::SHA256HashString(
-          base::IntToString(i) +
-          base::Int64ToString(base::Time::Now().ToJavaTime()));
+          base::NumberToString(i) +
+          base::NumberToString(base::Time::Now().ToJavaTime()));
     }
     StoreFiles({{path, contents}});
   }
diff --git a/chromeos/geolocation/simple_geolocation_request.cc b/chromeos/geolocation/simple_geolocation_request.cc
index 60b32b9..79a929b 100644
--- a/chromeos/geolocation/simple_geolocation_request.cc
+++ b/chromeos/geolocation/simple_geolocation_request.cc
@@ -289,7 +289,7 @@
   }
   if (status_code != net::HTTP_OK) {
     std::string message = "Returned error code ";
-    message += base::IntToString(status_code);
+    message += base::NumberToString(status_code);
     PrintGeolocationError(server_url, message, position);
     RecordUmaEvent(SIMPLE_GEOLOCATION_REQUEST_EVENT_RESPONSE_NOT_OK);
     return false;
@@ -317,7 +317,7 @@
   if (!access_point.timestamp.is_null()) {
     access_point_dictionary->SetKey(
         kAge,
-        base::Value(base::Int64ToString(
+        base::Value(base::NumberToString(
             (base::Time::Now() - access_point.timestamp).InMilliseconds())));
   }
 
@@ -341,7 +341,7 @@
   if (!cell_tower.timestamp.is_null()) {
     cell_tower_dictionary->SetKey(
         kAge,
-        base::Value(base::Int64ToString(
+        base::Value(base::NumberToString(
             (base::Time::Now() - cell_tower.timestamp).InMilliseconds())));
   }
   return cell_tower_dictionary;
diff --git a/chromeos/geolocation/simple_geolocation_unittest.cc b/chromeos/geolocation/simple_geolocation_unittest.cc
index 4768469..a7edebc6 100644
--- a/chromeos/geolocation/simple_geolocation_unittest.cc
+++ b/chromeos/geolocation/simple_geolocation_unittest.cc
@@ -343,8 +343,8 @@
     base::DictionaryValue properties;
     std::string mac_address =
         base::StringPrintf("%02X:%02X:%02X:%02X:%02X:%02X", idx, 0, 0, 0, 0, 0);
-    std::string channel = base::IntToString(idx);
-    std::string strength = base::IntToString(idx * 10);
+    std::string channel = base::NumberToString(idx);
+    std::string strength = base::NumberToString(idx * 10);
     properties.SetKey(shill::kGeoMacAddressProperty, base::Value(mac_address));
     properties.SetKey(shill::kGeoChannelProperty, base::Value(channel));
     properties.SetKey(shill::kGeoSignalStrengthProperty, base::Value(strength));
@@ -356,10 +356,10 @@
   // This should remain in sync with the format of shill (chromeos) dict entries
   void AddCellTower(int idx) {
     base::DictionaryValue properties;
-    std::string ci = base::IntToString(idx);
-    std::string lac = base::IntToString(idx * 3);
-    std::string mcc = base::IntToString(idx * 100);
-    std::string mnc = base::IntToString(idx * 100 + 1);
+    std::string ci = base::NumberToString(idx);
+    std::string lac = base::NumberToString(idx * 3);
+    std::string mcc = base::NumberToString(idx * 100);
+    std::string mnc = base::NumberToString(idx * 100 + 1);
 
     properties.SetKey(shill::kGeoCellIdProperty, base::Value(ci));
     properties.SetKey(shill::kGeoLocationAreaCodeProperty, base::Value(lac));
@@ -490,7 +490,7 @@
   EXPECT_TRUE(GetCellTowers());
   ASSERT_EQ(1u, cell_towers_.size());
   EXPECT_EQ(kCellTower1MNC, cell_towers_[0].mnc);
-  EXPECT_EQ(base::IntToString(1), cell_towers_[0].ci);
+  EXPECT_EQ(base::NumberToString(1), cell_towers_[0].ci);
 
   {
     GeolocationReceiver receiver;
diff --git a/chromeos/network/client_cert_util.cc b/chromeos/network/client_cert_util.cc
index 50079b7b..d8c2434 100644
--- a/chromeos/network/client_cert_util.cc
+++ b/chromeos/network/client_cert_util.cc
@@ -176,7 +176,7 @@
       properties->SetKey(shill::kL2tpIpsecPinProperty,
                          base::Value(kDefaultTPMPin));
       properties->SetKey(shill::kL2tpIpsecClientCertSlotProperty,
-                         base::Value(base::IntToString(tpm_slot)));
+                         base::Value(base::NumberToString(tpm_slot)));
       properties->SetKey(shill::kL2tpIpsecClientCertIdProperty,
                          base::Value(pkcs11_id));
       break;
diff --git a/chromeos/network/geolocation_handler_unittest.cc b/chromeos/network/geolocation_handler_unittest.cc
index d5c16308..5b07c51 100644
--- a/chromeos/network/geolocation_handler_unittest.cc
+++ b/chromeos/network/geolocation_handler_unittest.cc
@@ -60,8 +60,8 @@
     std::string mac_address =
         base::StringPrintf("%02X:%02X:%02X:%02X:%02X:%02X",
                            idx, 0, 0, 0, 0, 0);
-    std::string channel = base::IntToString(idx);
-    std::string strength = base::IntToString(idx * 10);
+    std::string channel = base::NumberToString(idx);
+    std::string strength = base::NumberToString(idx * 10);
     properties.SetKey(shill::kGeoMacAddressProperty, base::Value(mac_address));
     properties.SetKey(shill::kGeoChannelProperty, base::Value(channel));
     properties.SetKey(shill::kGeoSignalStrengthProperty, base::Value(strength));
@@ -76,10 +76,10 @@
     // Multiplications, additions, and string concatenations
     // are intended solely to differentiate the various fields
     // in a predictable way, while preserving 3 digits for MCC and MNC.
-    std::string ci = base::IntToString(idx) + "D3A15F2";
-    std::string lac = "7FF" + base::IntToString(idx);
-    std::string mcc = base::IntToString(idx * 100);
-    std::string mnc = base::IntToString(idx * 100 + 1);
+    std::string ci = base::NumberToString(idx) + "D3A15F2";
+    std::string lac = "7FF" + base::NumberToString(idx);
+    std::string mcc = base::NumberToString(idx * 100);
+    std::string mnc = base::NumberToString(idx * 100 + 1);
 
     properties.SetKey(shill::kGeoCellIdProperty, base::Value(ci));
     properties.SetKey(shill::kGeoLocationAreaCodeProperty, base::Value(lac));
diff --git a/chromeos/network/network_cert_migrator_unittest.cc b/chromeos/network/network_cert_migrator_unittest.cc
index 7bc320c..8d9a45d 100644
--- a/chromeos/network/network_cert_migrator_unittest.cc
+++ b/chromeos/network/network_cert_migrator_unittest.cc
@@ -94,7 +94,7 @@
         test_client_cert_.get(), &slot_id);
     ASSERT_FALSE(test_client_cert_pkcs11_id_.empty());
     ASSERT_NE(-1, slot_id);
-    test_client_cert_slot_id_ = base::IntToString(slot_id);
+    test_client_cert_slot_id_ = base::NumberToString(slot_id);
   }
 
   void SetupNetworkHandlers() {
diff --git a/chromeos/network/network_state_handler.cc b/chromeos/network/network_state_handler.cc
index 04525c3..853637e 100644
--- a/chromeos/network/network_state_handler.cc
+++ b/chromeos/network/network_state_handler.cc
@@ -1098,8 +1098,8 @@
     uint32_t upload_rate_kbits,
     uint32_t download_rate_kbits) {
   NET_LOG_EVENT("SetNetworkThrottlingStatus",
-                enabled ? ("true :" + base::IntToString(upload_rate_kbits) +
-                           ", " + base::IntToString(download_rate_kbits))
+                enabled ? ("true :" + base::NumberToString(upload_rate_kbits) +
+                           ", " + base::NumberToString(download_rate_kbits))
                         : "false");
   shill_property_handler_->SetNetworkThrottlingStatus(
       enabled, upload_rate_kbits, download_rate_kbits);
diff --git a/chromeos/network/network_util.cc b/chromeos/network/network_util.cc
index 99b4709..9f42ef1 100644
--- a/chromeos/network/network_util.cc
+++ b/chromeos/network/network_util.cc
@@ -68,7 +68,7 @@
       netmask += ".";
     int value = remainder == 0 ? 0 :
         ((2L << (remainder - 1)) - 1) << (8 - remainder);
-    netmask += base::IntToString(value);
+    netmask += base::NumberToString(value);
   }
   return netmask;
 }
diff --git a/chromeos/network/onc/onc_certificate_importer_impl_unittest.cc b/chromeos/network/onc/onc_certificate_importer_impl_unittest.cc
index afa0dccf..4ea520e 100644
--- a/chromeos/network/onc/onc_certificate_importer_impl_unittest.cc
+++ b/chromeos/network/onc/onc_certificate_importer_impl_unittest.cc
@@ -331,7 +331,7 @@
 TEST_P(ONCCertificateImporterImplTestWithParam, ReimportCertificate) {
   // Verify that reimporting a client certificate works.
   for (int i = 0; i < 2; ++i) {
-    SCOPED_TRACE("Import certificate, iteration " + base::IntToString(i));
+    SCOPED_TRACE("Import certificate, iteration " + base::NumberToString(i));
     AddCertificateFromFile(GetParam().original_file,
                            ImportType::kAllCertificates, GetParam().cert_type,
                            NULL);
diff --git a/chromeos/network/onc/onc_utils_unittest.cc b/chromeos/network/onc/onc_utils_unittest.cc
index 64a2077..e079378 100644
--- a/chromeos/network/onc/onc_utils_unittest.cc
+++ b/chromeos/network/onc/onc_utils_unittest.cc
@@ -169,7 +169,7 @@
 
   int index = 0;
   for (const base::Value& test_case : list_of_tests->GetList()) {
-    SCOPED_TRACE("Test case #" + base::IntToString(index++));
+    SCOPED_TRACE("Test case #" + base::NumberToString(index++));
 
     ASSERT_TRUE(test_case.is_dict());
 
@@ -193,7 +193,7 @@
 
   int index = 0;
   for (const base::Value& test_case : list_of_tests->GetList()) {
-    SCOPED_TRACE("Test case #" + base::IntToString(index++));
+    SCOPED_TRACE("Test case #" + base::NumberToString(index++));
 
     const base::Value* shill_proxy_config = test_case.FindKey("ProxyConfig");
     ASSERT_TRUE(shill_proxy_config);
diff --git a/chromeos/network/onc/onc_validator.cc b/chromeos/network/onc/onc_validator.cc
index 53fe4b0..19531ee 100644
--- a/chromeos/network/onc/onc_validator.cc
+++ b/chromeos/network/onc/onc_validator.cc
@@ -226,7 +226,7 @@
     const OncValueSignature& signature,
     const base::Value& onc_value,
     bool* error) {
-  std::string index_as_string = base::IntToString(index);
+  std::string index_as_string = base::NumberToString(index);
   path_.push_back(index_as_string);
   std::unique_ptr<base::Value> result =
       Mapper::MapEntry(index, signature, onc_value, error);
diff --git a/chromeos/system/statistics_provider.cc b/chromeos/system/statistics_provider.cc
index e61ce9d..2ddaa4f 100644
--- a/chromeos/system/statistics_provider.cc
+++ b/chromeos/system/statistics_provider.cc
@@ -543,7 +543,7 @@
     // testing).
     std::string stub_contents =
         "\"serial_number\"=\"stub_" +
-        base::Int64ToString(base::Time::Now().ToJavaTime()) + "\"\n";
+        base::NumberToString(base::Time::Now().ToJavaTime()) + "\"\n";
     int bytes_written = base::WriteFile(
         machine_info_path, stub_contents.c_str(), stub_contents.size());
     if (bytes_written < static_cast<int>(stub_contents.size())) {
diff --git a/chromeos/timezone/timezone_request.cc b/chromeos/timezone/timezone_request.cc
index f445b540..b967545 100644
--- a/chromeos/timezone/timezone_request.cc
+++ b/chromeos/timezone/timezone_request.cc
@@ -287,7 +287,7 @@
   }
   if (status_code != net::HTTP_OK) {
     std::string message = "Returned error code ";
-    message += base::IntToString(status_code);
+    message += base::NumberToString(status_code);
     PrintTimeZoneError(server_url, message, timezone.get());
     RecordUmaEvent(TIMEZONE_REQUEST_EVENT_RESPONSE_NOT_OK);
     return timezone;
diff --git a/components/BUILD.gn b/components/BUILD.gn
index 9e87ff4..31e86df 100644
--- a/components/BUILD.gn
+++ b/components/BUILD.gn
@@ -5,6 +5,7 @@
 import("//build/config/chrome_build.gni")
 import("//build/config/features.gni")
 import("//build/config/ui.gni")
+import("//components/mpris/features.gni")
 import("//components/nacl/features.gni")
 import("//components/ui_devtools/devtools.gni")
 import("//media/media_options.gni")
@@ -380,6 +381,10 @@
     ]
   }
 
+  if (use_mpris) {
+    deps += [ "//components/mpris:unit_tests" ]
+  }
+
   # No components should depend on Chrome.
   assert_no_deps = [ "//chrome/*" ]
 
diff --git a/components/autofill/core/browser/account_info_getter.h b/components/autofill/core/browser/account_info_getter.h
index 7d71b5f..44fa238 100644
--- a/components/autofill/core/browser/account_info_getter.h
+++ b/components/autofill/core/browser/account_info_getter.h
@@ -17,7 +17,7 @@
   // Returns the account info that should be used when communicating with the
   // Payments server. The AccountInfo could be empty if there is no account to
   // be used by the Payments server.
-  virtual AccountInfo GetAccountInfoForPaymentsServer() const = 0;
+  virtual CoreAccountInfo GetAccountInfoForPaymentsServer() const = 0;
 
   // Returns true - When user is both signed-in and enabled sync.
   // Returns false - When user is not signed-in or does not have sync the
diff --git a/components/autofill/core/browser/personal_data_manager.cc b/components/autofill/core/browser/personal_data_manager.cc
index efca6b0..2e4ce6e5 100644
--- a/components/autofill/core/browser/personal_data_manager.cc
+++ b/components/autofill/core/browser/personal_data_manager.cc
@@ -533,7 +533,7 @@
   sync_service_ = nullptr;
 }
 
-AccountInfo PersonalDataManager::GetAccountInfoForPaymentsServer() const {
+CoreAccountInfo PersonalDataManager::GetAccountInfoForPaymentsServer() const {
   // If butter is enabled or the feature to get the Payment Identity from Sync
   // is enabled, return the account of the active signed-in user irrespective of
   // whether they enabled sync or not.
diff --git a/components/autofill/core/browser/personal_data_manager.h b/components/autofill/core/browser/personal_data_manager.h
index 95c5ac0..e5c19e3 100644
--- a/components/autofill/core/browser/personal_data_manager.h
+++ b/components/autofill/core/browser/personal_data_manager.h
@@ -124,7 +124,7 @@
   void OnSyncShutdown(syncer::SyncService* sync) override;
 
   // AccountInfoGetter:
-  AccountInfo GetAccountInfoForPaymentsServer() const override;
+  CoreAccountInfo GetAccountInfoForPaymentsServer() const override;
   bool IsSyncFeatureEnabled() const override;
 
   // GaiaCookieManagerService::Observer:
diff --git a/components/autofill/core/browser/test_personal_data_manager.cc b/components/autofill/core/browser/test_personal_data_manager.cc
index 9a6e5c3..6115dad 100644
--- a/components/autofill/core/browser/test_personal_data_manager.cc
+++ b/components/autofill/core/browser/test_personal_data_manager.cc
@@ -248,7 +248,8 @@
   return sync_feature_enabled_;
 }
 
-AccountInfo TestPersonalDataManager::GetAccountInfoForPaymentsServer() const {
+CoreAccountInfo TestPersonalDataManager::GetAccountInfoForPaymentsServer()
+    const {
   return account_info_;
 }
 
diff --git a/components/autofill/core/browser/test_personal_data_manager.h b/components/autofill/core/browser/test_personal_data_manager.h
index ae3a7cd..2ed5e71 100644
--- a/components/autofill/core/browser/test_personal_data_manager.h
+++ b/components/autofill/core/browser/test_personal_data_manager.h
@@ -55,7 +55,7 @@
   CreditCard* GetCreditCardByNumber(const std::string& number) override;
   bool IsDataLoaded() const override;
   bool IsSyncFeatureEnabled() const override;
-  AccountInfo GetAccountInfoForPaymentsServer() const override;
+  CoreAccountInfo GetAccountInfoForPaymentsServer() const override;
 
   // Unique to TestPersonalDataManager:
 
@@ -115,7 +115,7 @@
 
   void SetSyncFeatureEnabled(bool enabled) { sync_feature_enabled_ = enabled; }
 
-  void SetAccountInfoForPayments(const AccountInfo& account_info) {
+  void SetAccountInfoForPayments(const CoreAccountInfo& account_info) {
     account_info_ = account_info;
   }
 
@@ -130,7 +130,7 @@
   base::Optional<bool> autofill_wallet_import_enabled_;
   bool sync_feature_enabled_ = false;
   bool sync_service_initialized_ = false;
-  AccountInfo account_info_;
+  CoreAccountInfo account_info_;
 
   DISALLOW_COPY_AND_ASSIGN(TestPersonalDataManager);
 };
diff --git a/components/browser_sync/profile_sync_service.cc b/components/browser_sync/profile_sync_service.cc
index d22cf4e4..c4138de 100644
--- a/components/browser_sync/profile_sync_service.cc
+++ b/components/browser_sync/profile_sync_service.cc
@@ -1878,7 +1878,7 @@
   }
 }
 
-AccountInfo ProfileSyncService::GetAuthenticatedAccountInfo() const {
+CoreAccountInfo ProfileSyncService::GetAuthenticatedAccountInfo() const {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   return auth_manager_->GetActiveAccountInfo().account_info;
 }
diff --git a/components/browser_sync/profile_sync_service.h b/components/browser_sync/profile_sync_service.h
index 1b9090c..ad19786 100644
--- a/components/browser_sync/profile_sync_service.h
+++ b/components/browser_sync/profile_sync_service.h
@@ -185,7 +185,7 @@
   int GetDisableReasons() const override;
   TransportState GetTransportState() const override;
   bool IsLocalSyncEnabled() const override;
-  AccountInfo GetAuthenticatedAccountInfo() const override;
+  CoreAccountInfo GetAuthenticatedAccountInfo() const override;
   bool IsAuthenticatedAccountPrimary() const override;
   const GoogleServiceAuthError& GetAuthError() const override;
   std::unique_ptr<syncer::SyncSetupInProgressHandle> GetSetupInProgressHandle()
diff --git a/components/browser_sync/sync_auth_manager.cc b/components/browser_sync/sync_auth_manager.cc
index 814f3f7..7571820 100644
--- a/components/browser_sync/sync_auth_manager.cc
+++ b/components/browser_sync/sync_auth_manager.cc
@@ -124,7 +124,7 @@
 syncer::SyncCredentials SyncAuthManager::GetCredentials() const {
   // TODO(crbug.com/814787): Once the ChromeOS test setup is fixed, we can just
   // use |sync_account_| directly here.
-  const AccountInfo account_info = GetActiveAccountInfo().account_info;
+  const CoreAccountInfo& account_info = GetActiveAccountInfo().account_info;
 
   syncer::SyncCredentials credentials;
   credentials.account_id = account_info.account_id;
diff --git a/components/cronet/native/engine.cc b/components/cronet/native/engine.cc
index 584cb74..3cb3c82 100644
--- a/components/cronet/native/engine.cc
+++ b/components/cronet/native/engine.cc
@@ -399,7 +399,7 @@
   return stream_engine_.get();
 }
 
-};  // namespace cronet
+}  // namespace cronet
 
 CRONET_EXPORT Cronet_EnginePtr Cronet_Engine_Create() {
   return new cronet::Cronet_EngineImpl();
diff --git a/components/cronet/native/engine.h b/components/cronet/native/engine.h
index 689cff8..74a5c13 100644
--- a/components/cronet/native/engine.h
+++ b/components/cronet/native/engine.h
@@ -88,6 +88,6 @@
   DISALLOW_COPY_AND_ASSIGN(Cronet_EngineImpl);
 };
 
-};  // namespace cronet
+}  // namespace cronet
 
 #endif  // COMPONENTS_CRONET_NATIVE_ENGINE_H_
diff --git a/components/cronet/native/runnables.h b/components/cronet/native/runnables.h
index 80e75c4..edb85fc6 100644
--- a/components/cronet/native/runnables.h
+++ b/components/cronet/native/runnables.h
@@ -27,6 +27,6 @@
   DISALLOW_COPY_AND_ASSIGN(OnceClosureRunnable);
 };
 
-};  // namespace cronet
+}  // namespace cronet
 
 #endif  // COMPONENTS_CRONET_NATIVE_RUNNABLES_H_
diff --git a/components/cronet/native/test/test_util.cc b/components/cronet/native/test/test_util.cc
index 526577c..0c9a0fc 100644
--- a/components/cronet/native/test/test_util.cc
+++ b/components/cronet/native/test/test_util.cc
@@ -43,7 +43,7 @@
     }
     return net::MockCertVerifier::Verify(params, verify_result,
                                          std::move(callback), out_req, net_log);
-  };
+  }
 };
 
 }  // namespace
diff --git a/components/cronet/native/upload_data_sink.cc b/components/cronet/native/upload_data_sink.cc
index 70e6e21..3edb577 100644
--- a/components/cronet/native/upload_data_sink.cc
+++ b/components/cronet/native/upload_data_sink.cc
@@ -287,4 +287,4 @@
   Cronet_Executor_Execute(upload_data_provider_executor_, runnable);
 }
 
-};  // namespace cronet
+}  // namespace cronet
diff --git a/components/cronet/native/url_request.cc b/components/cronet/native/url_request.cc
index 7a6809bf..3ebdc44 100644
--- a/components/cronet/native/url_request.cc
+++ b/components/cronet/native/url_request.cc
@@ -757,7 +757,7 @@
                      ConvertLoadState(load_state)));
 }
 
-};  // namespace cronet
+}  // namespace cronet
 
 CRONET_EXPORT Cronet_UrlRequestPtr Cronet_UrlRequest_Create() {
   return new cronet::Cronet_UrlRequestImpl();
diff --git a/components/cronet/native/url_request.h b/components/cronet/native/url_request.h
index 08ba896..cc541d1 100644
--- a/components/cronet/native/url_request.h
+++ b/components/cronet/native/url_request.h
@@ -128,6 +128,6 @@
   DISALLOW_COPY_AND_ASSIGN(Cronet_UrlRequestImpl);
 };
 
-};  // namespace cronet
+}  // namespace cronet
 
 #endif  // COMPONENTS_CRONET_NATIVE_URL_REQUEST_H_
diff --git a/components/dbus/BUILD.gn b/components/dbus/BUILD.gn
new file mode 100644
index 0000000..97b3a61
--- /dev/null
+++ b/components/dbus/BUILD.gn
@@ -0,0 +1,14 @@
+# 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.
+
+component("dbus_thread_linux") {
+  sources = [
+    "dbus_thread_linux.cc",
+    "dbus_thread_linux.h",
+  ]
+  defines = [ "IS_DBUS_IMPL" ]
+  deps = [
+    "//base",
+  ]
+}
diff --git a/chrome/browser/dbus/OWNERS b/components/dbus/OWNERS
similarity index 100%
rename from chrome/browser/dbus/OWNERS
rename to components/dbus/OWNERS
diff --git a/chrome/browser/dbus/dbus_thread_linux.cc b/components/dbus/dbus_thread_linux.cc
similarity index 82%
rename from chrome/browser/dbus/dbus_thread_linux.cc
rename to components/dbus/dbus_thread_linux.cc
index 9cadf747..c0825a2e 100644
--- a/chrome/browser/dbus/dbus_thread_linux.cc
+++ b/components/dbus/dbus_thread_linux.cc
@@ -2,11 +2,11 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "chrome/browser/dbus/dbus_thread_linux.h"
+#include "components/dbus/dbus_thread_linux.h"
 
 #include "base/task/lazy_task_runner.h"
 
-namespace chrome {
+namespace dbus_thread_linux {
 
 namespace {
 
@@ -22,8 +22,8 @@
 
 }  // namespace
 
-scoped_refptr<base::SingleThreadTaskRunner> GetDBusTaskRunner() {
+scoped_refptr<base::SingleThreadTaskRunner> GetTaskRunner() {
   return g_dbus_thread_task_runner.Get();
 }
 
-}  // namespace chrome
+}  // namespace dbus_thread_linux
diff --git a/chrome/browser/dbus/dbus_thread_linux.h b/components/dbus/dbus_thread_linux.h
similarity index 66%
rename from chrome/browser/dbus/dbus_thread_linux.h
rename to components/dbus/dbus_thread_linux.h
index 6819b51..e2d1aa05 100644
--- a/chrome/browser/dbus/dbus_thread_linux.h
+++ b/components/dbus/dbus_thread_linux.h
@@ -2,9 +2,10 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef CHROME_BROWSER_DBUS_DBUS_THREAD_LINUX_H_
-#define CHROME_BROWSER_DBUS_DBUS_THREAD_LINUX_H_
+#ifndef COMPONENTS_DBUS_DBUS_THREAD_LINUX_H_
+#define COMPONENTS_DBUS_DBUS_THREAD_LINUX_H_
 
+#include "base/component_export.h"
 #include "base/memory/ref_counted.h"
 #include "base/single_thread_task_runner.h"
 #include "build/build_config.h"
@@ -18,10 +19,11 @@
 #error On ChromeOS, use DBusThreadManager instead.
 #endif
 
-namespace chrome {
+namespace dbus_thread_linux {
 
-scoped_refptr<base::SingleThreadTaskRunner> GetDBusTaskRunner();
+COMPONENT_EXPORT(DBUS)
+scoped_refptr<base::SingleThreadTaskRunner> GetTaskRunner();
 
-}  // namespace chrome
+}  // namespace dbus_thread_linux
 
-#endif  // CHROME_BROWSER_DBUS_DBUS_THREAD_LINUX_H_
+#endif  // COMPONENTS_DBUS_DBUS_THREAD_LINUX_H_
diff --git a/components/dom_distiller/core/fake_distiller_page.h b/components/dom_distiller/core/fake_distiller_page.h
index 82829eb..2f521c2 100644
--- a/components/dom_distiller/core/fake_distiller_page.h
+++ b/components/dom_distiller/core/fake_distiller_page.h
@@ -30,7 +30,7 @@
  public:
   MockDistillerPage();
   ~MockDistillerPage() override;
-  bool StringifyOutput() override { return false; };
+  bool StringifyOutput() override { return false; }
   MOCK_METHOD2(DistillPageImpl,
                void(const GURL& gurl, const std::string& script));
 };
diff --git a/components/gcm_driver/crypto/gcm_message_cryptographer_unittest.cc b/components/gcm_driver/crypto/gcm_message_cryptographer_unittest.cc
index 17f354c..9ef0034 100644
--- a/components/gcm_driver/crypto/gcm_message_cryptographer_unittest.cc
+++ b/components/gcm_driver/crypto/gcm_message_cryptographer_unittest.cc
@@ -566,7 +566,7 @@
   EXPECT_EQ(kExamplePlaintext, second_plaintext);
 }
 
-INSTANTIATE_TEST_CASE_P(
+INSTANTIATE_TEST_SUITE_P(
     GCMMessageCryptographerTestBase,
     GCMMessageCryptographerTest,
     ::testing::Values(GCMMessageCryptographer::Version::DRAFT_03,
diff --git a/components/guest_view/browser/test_guest_view_manager.cc b/components/guest_view/browser/test_guest_view_manager.cc
index e4b269e..e81907e2 100644
--- a/components/guest_view/browser/test_guest_view_manager.cc
+++ b/components/guest_view/browser/test_guest_view_manager.cc
@@ -54,7 +54,7 @@
 void TestGuestViewManager::WaitForLastGuestDeleted() {
   // Wait for the last guest that was created to be deleted.
   guest_web_contents_watchers_.back()->Wait();
-};
+}
 
 content::WebContents* TestGuestViewManager::WaitForSingleGuestCreated() {
   if (!GetNumGuestsActive()) {
diff --git a/components/history/core/browser/browsing_history_service_unittest.cc b/components/history/core/browser/browsing_history_service_unittest.cc
index c2bd57ea..11f02f97 100644
--- a/components/history/core/browser/browsing_history_service_unittest.cc
+++ b/components/history/core/browser/browsing_history_service_unittest.cc
@@ -135,11 +135,11 @@
     bool IsPending() override { return false; }
     int GetResponseCode() override { return net::HTTP_OK; }
     const std::string& GetResponseBody() override { return body_; }
-    void SetPostData(const std::string& post_data) override{};
+    void SetPostData(const std::string& post_data) override {}
     void SetPostDataAndType(const std::string& post_data,
-                            const std::string& mime_type) override{};
-    void SetUserAgent(const std::string& user_agent) override{};
-    void Start() override{};
+                            const std::string& mime_type) override {}
+    void SetUserAgent(const std::string& user_agent) override {}
+    void Start() override {}
 
     std::string body_ = "{}";
   };
diff --git a/components/history/core/browser/history_types.cc b/components/history/core/browser/history_types.cc
index a7cc78b..9c853028 100644
--- a/components/history/core/browser/history_types.cc
+++ b/components/history/core/browser/history_types.cc
@@ -383,7 +383,7 @@
   DCHECK(time_range_.IsValid() || !restrict_urls_.has_value());
   // If restrict_urls_ is defined, it should be non-empty.
   DCHECK(!restrict_urls_.has_value() || !restrict_urls_->empty());
-};
+}
 
 DeletionInfo::~DeletionInfo() = default;
 
diff --git a/components/leveldb_proto/BUILD.gn b/components/leveldb_proto/BUILD.gn
index 13e078b..fb521c3 100644
--- a/components/leveldb_proto/BUILD.gn
+++ b/components/leveldb_proto/BUILD.gn
@@ -16,9 +16,12 @@
     "internal/leveldb_database.h",
     "internal/leveldb_proto_feature_list.cc",
     "internal/leveldb_proto_feature_list.h",
+    "internal/migration_delegate.cc",
     "internal/migration_delegate.h",
-    "internal/proto_database_wrapper.cc",
-    "internal/proto_database_wrapper.h",
+    "internal/proto_database_impl.cc",
+    "internal/proto_database_impl.h",
+    "internal/proto_database_selector.cc",
+    "internal/proto_database_selector.h",
     "internal/proto_leveldb_wrapper.cc",
     "internal/proto_leveldb_wrapper.h",
     "internal/proto_leveldb_wrapper_metrics.cc",
@@ -29,6 +32,7 @@
     "internal/shared_proto_database_client.h",
     "internal/shared_proto_database_provider.cc",
     "internal/shared_proto_database_provider.h",
+    "internal/unique_proto_database.cc",
     "internal/unique_proto_database.h",
     "public/proto_database.cc",
     "public/proto_database.h",
@@ -65,7 +69,7 @@
 source_set("unit_tests") {
   testonly = true
   sources = [
-    "internal/proto_database_wrapper_unittest.cc",
+    "internal/proto_database_impl_unittest.cc",
     "internal/shared_proto_database_client_list_unittest.cc",
     "internal/shared_proto_database_client_unittest.cc",
     "internal/shared_proto_database_unittest.cc",
diff --git a/components/leveldb_proto/internal/migration_delegate.cc b/components/leveldb_proto/internal/migration_delegate.cc
new file mode 100644
index 0000000..5ef800d0
--- /dev/null
+++ b/components/leveldb_proto/internal/migration_delegate.cc
@@ -0,0 +1,63 @@
+// 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/leveldb_proto/internal/migration_delegate.h"
+
+#include <memory>
+#include <utility>
+
+#include "base/bind.h"
+#include "base/sequenced_task_runner.h"
+#include "base/threading/sequenced_task_runner_handle.h"
+
+namespace leveldb_proto {
+
+MigrationDelegate::MigrationDelegate() : weak_ptr_factory_(this) {}
+MigrationDelegate::~MigrationDelegate() = default;
+
+void MigrationDelegate::DoMigration(UniqueProtoDatabase* from,
+                                    UniqueProtoDatabase* to,
+                                    MigrationCallback callback) {
+  from->LoadKeysAndEntries(base::BindOnce(
+      &MigrationDelegate::OnLoadKeysAndEntries, weak_ptr_factory_.GetWeakPtr(),
+      std::move(callback), base::Unretained(to)));
+}
+
+void MigrationDelegate::OnLoadKeysAndEntries(
+    MigrationCallback callback,
+    UniqueProtoDatabase* to,
+    bool success,
+    std::unique_ptr<KeyValueMap> keys_entries) {
+  if (!success) {
+    DCHECK(base::SequencedTaskRunnerHandle::IsSet());
+    auto current_task_runner = base::SequencedTaskRunnerHandle::Get();
+    current_task_runner->PostTask(FROM_HERE,
+                                  base::BindOnce(std::move(callback), false));
+    return;
+  }
+
+  // Convert the std::map we got back into a vector of std::pairs to be used
+  // with UpdateEntries.
+  auto kev = std::make_unique<KeyValueVector>();
+  for (auto const& key_entry : *keys_entries)
+    kev->push_back(key_entry);
+
+  // Save the entries in |to|.
+  to->UpdateEntries(
+      std::move(kev), std::make_unique<KeyVector>(),
+      base::BindOnce(&MigrationDelegate::OnUpdateEntries,
+                     weak_ptr_factory_.GetWeakPtr(), std::move(callback)));
+}
+
+void MigrationDelegate::OnUpdateEntries(MigrationCallback callback,
+                                        bool success) {
+  DCHECK(base::SequencedTaskRunnerHandle::IsSet());
+  auto current_task_runner = base::SequencedTaskRunnerHandle::Get();
+  current_task_runner->PostTask(FROM_HERE,
+                                base::BindOnce(std::move(callback), success));
+  // TODO (thildebr): For additional insurance, verify the entries match,
+  // although they should if we got a success from UpdateEntries.
+}
+
+}  // namespace leveldb_proto
diff --git a/components/leveldb_proto/internal/migration_delegate.h b/components/leveldb_proto/internal/migration_delegate.h
index abbb74e..6d6f7cc 100644
--- a/components/leveldb_proto/internal/migration_delegate.h
+++ b/components/leveldb_proto/internal/migration_delegate.h
@@ -5,91 +5,39 @@
 #ifndef COMPONENTS_LEVELDB_PROTO_INTERNAL_MIGRATION_DELEGATE_H_
 #define COMPONENTS_LEVELDB_PROTO_INTERNAL_MIGRATION_DELEGATE_H_
 
-#include "base/bind.h"
+#include <memory>
+
 #include "base/callback.h"
-#include "base/sequenced_task_runner.h"
-#include "base/threading/sequenced_task_runner_handle.h"
-#include "components/leveldb_proto/public/proto_database.h"
+#include "components/leveldb_proto/internal/proto_leveldb_wrapper.h"
+#include "components/leveldb_proto/internal/unique_proto_database.h"
 
 namespace leveldb_proto {
 
 // Small class that strictly performs the migration functionality of
 // SharedProtoDatabase.
-template <typename T>
 class MigrationDelegate {
  public:
   using MigrationCallback = base::OnceCallback<void(bool)>;
 
   MigrationDelegate();
+  ~MigrationDelegate();
 
   // Copies the keys/entries of |from| to |to|, and returns a boolean success
   // in |callback|.
-  void DoMigration(ProtoDatabase<T>* from,
-                   ProtoDatabase<T>* to,
+  void DoMigration(UniqueProtoDatabase* from,
+                   UniqueProtoDatabase* to,
                    MigrationCallback callback);
 
  private:
-  void OnLoadKeysAndEntries(
-      MigrationCallback callback,
-      ProtoDatabase<T>* to,
-      bool success,
-      std::unique_ptr<std::map<std::string, T>> keys_entries);
+  void OnLoadKeysAndEntries(MigrationCallback callback,
+                            UniqueProtoDatabase* to,
+                            bool success,
+                            std::unique_ptr<KeyValueMap> keys_entries);
   void OnUpdateEntries(MigrationCallback callback, bool success);
 
-  base::WeakPtrFactory<MigrationDelegate<T>> weak_ptr_factory_;
+  base::WeakPtrFactory<MigrationDelegate> weak_ptr_factory_;
 };
 
-template <typename T>
-MigrationDelegate<T>::MigrationDelegate() : weak_ptr_factory_(this) {}
-
-template <typename T>
-void MigrationDelegate<T>::DoMigration(ProtoDatabase<T>* from,
-                                       ProtoDatabase<T>* to,
-                                       MigrationCallback callback) {
-  from->LoadKeysAndEntries(
-      base::BindOnce(&MigrationDelegate<T>::OnLoadKeysAndEntries,
-                     weak_ptr_factory_.GetWeakPtr(), std::move(callback),
-                     base::Unretained(to)));
-}
-
-template <typename T>
-void MigrationDelegate<T>::OnLoadKeysAndEntries(
-    MigrationCallback callback,
-    ProtoDatabase<T>* to,
-    bool success,
-    std::unique_ptr<std::map<std::string, T>> keys_entries) {
-  if (!success) {
-    DCHECK(base::SequencedTaskRunnerHandle::IsSet());
-    auto current_task_runner = base::SequencedTaskRunnerHandle::Get();
-    current_task_runner->PostTask(FROM_HERE,
-                                  base::BindOnce(std::move(callback), false));
-    return;
-  }
-
-  // Convert the std::map we got back into a vector of std::pairs to be used
-  // with UpdateEntries.
-  auto kev = std::make_unique<typename ProtoDatabase<T>::KeyEntryVector>();
-  for (auto const& key_entry : *keys_entries)
-    kev->push_back(key_entry);
-
-  // Save the entries in |to|.
-  to->UpdateEntries(
-      std::move(kev), std::make_unique<std::vector<std::string>>(),
-      base::BindOnce(&MigrationDelegate<T>::OnUpdateEntries,
-                     weak_ptr_factory_.GetWeakPtr(), std::move(callback)));
-}
-
-template <typename T>
-void MigrationDelegate<T>::OnUpdateEntries(MigrationCallback callback,
-                                           bool success) {
-  DCHECK(base::SequencedTaskRunnerHandle::IsSet());
-  auto current_task_runner = base::SequencedTaskRunnerHandle::Get();
-  current_task_runner->PostTask(FROM_HERE,
-                                base::BindOnce(std::move(callback), success));
-  // TODO (thildebr): For additional insurance, verify the entries match,
-  // although they should if we got a success from UpdateEntries.
-}
-
 }  // namespace leveldb_proto
 
 #endif  // COMPONENTS_LEVELDB_PROTO_INTERNAL_MIGRATION_DELEGATE_H_
\ No newline at end of file
diff --git a/components/leveldb_proto/internal/proto_database_impl.cc b/components/leveldb_proto/internal/proto_database_impl.cc
new file mode 100644
index 0000000..512f3416
--- /dev/null
+++ b/components/leveldb_proto/internal/proto_database_impl.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 "components/leveldb_proto/internal/proto_database_impl.h"
+
+#include <memory>
+#include <utility>
+
+#include "components/leveldb_proto/public/proto_database_provider.h"
+
+namespace leveldb_proto {
+
+void GetSharedDBInstance(
+    ProtoDatabaseProvider* db_provider,
+    base::OnceCallback<void(scoped_refptr<SharedProtoDatabase>)> callback) {
+  DCHECK(base::SequencedTaskRunnerHandle::IsSet());
+  db_provider->GetSharedDBInstance(std::move(callback),
+                                   base::SequencedTaskRunnerHandle::Get());
+}
+
+void RunUpdateCallback(
+    scoped_refptr<base::SequencedTaskRunner> callback_task_runner,
+    Callbacks::UpdateCallback callback,
+    bool success) {
+  callback_task_runner->PostTask(FROM_HERE,
+                                 base::BindOnce(std::move(callback), success));
+}
+
+void RunLoadKeysCallback(
+    scoped_refptr<base::SequencedTaskRunner> callback_task_runner,
+    Callbacks::LoadKeysCallback callback,
+    bool success,
+    std::unique_ptr<KeyVector> keys) {
+  callback_task_runner->PostTask(
+      FROM_HERE, base::BindOnce(std::move(callback), success, std::move(keys)));
+}
+
+void RunDestroyCallback(
+    scoped_refptr<base::SequencedTaskRunner> callback_task_runner,
+    Callbacks::DestroyCallback callback,
+    bool success) {
+  callback_task_runner->PostTask(FROM_HERE,
+                                 base::BindOnce(std::move(callback), success));
+}
+}  // namespace leveldb_proto
\ No newline at end of file
diff --git a/components/leveldb_proto/internal/proto_database_impl.h b/components/leveldb_proto/internal/proto_database_impl.h
new file mode 100644
index 0000000..aa0a6e5
--- /dev/null
+++ b/components/leveldb_proto/internal/proto_database_impl.h
@@ -0,0 +1,565 @@
+// 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_LEVELDB_PROTO_INTERNAL_PROTO_DATABASE_IMPL_H_
+#define COMPONENTS_LEVELDB_PROTO_INTERNAL_PROTO_DATABASE_IMPL_H_
+
+#include <map>
+#include <memory>
+#include <string>
+#include <utility>
+#include <vector>
+
+#include "base/bind.h"
+#include "base/files/file_path.h"
+#include "base/memory/weak_ptr.h"
+#include "base/threading/sequenced_task_runner_handle.h"
+#include "components/leveldb_proto/internal/proto_database_selector.h"
+#include "components/leveldb_proto/internal/shared_proto_database.h"
+#include "components/leveldb_proto/internal/shared_proto_database_provider.h"
+#include "components/leveldb_proto/public/proto_database.h"
+#include "components/leveldb_proto/public/shared_proto_database_client_list.h"
+
+namespace leveldb_proto {
+
+class ProtoDatabaseProvider;
+
+// Avoids circular dependencies between ProtoDatabaseImpl and
+// ProtoDatabaseProvider, since we'd need to include the provider header here
+// to use |db_provider_|'s GetSharedDBInstance.
+void GetSharedDBInstance(
+    ProtoDatabaseProvider* db_provider,
+    base::OnceCallback<void(scoped_refptr<SharedProtoDatabase>)> callback);
+
+// Update transactions happen on background task runner and callback runs on the
+// client task runner.
+void RunUpdateCallback(
+    scoped_refptr<base::SequencedTaskRunner> callback_task_runner,
+    Callbacks::UpdateCallback callback,
+    bool success);
+
+// Load transactions happen on background task runner. The loaded keys need to
+// be given to clients on client task runner.
+void RunLoadKeysCallback(
+    scoped_refptr<base::SequencedTaskRunner> callback_task_runner,
+    Callbacks::LoadKeysCallback callback,
+    bool success,
+    std::unique_ptr<KeyVector> keys);
+
+// Helper to run destroy callback on the client task runner.
+void RunDestroyCallback(
+    scoped_refptr<base::SequencedTaskRunner> callback_task_runner,
+    Callbacks::DestroyCallback callback,
+    bool success);
+
+// The ProtoDatabaseImpl<T> implements a ProtoDatabase<T> instance, and allows
+// the underlying ProtoDatabase<T> implementation to change without users of the
+// wrapper needing to know.
+// This allows clients to request a DB instance without knowing whether or not
+// it's a UniqueProtoDatabase or a SharedProtoDatabaseClient.
+template <typename T>
+class ProtoDatabaseImpl : public ProtoDatabase<T> {
+ public:
+  // DEPRECATED. Force usage of unique db. The clients must use Init(name,
+  // db_dir, options, callback) version.
+  ProtoDatabaseImpl(
+      const scoped_refptr<base::SequencedTaskRunner>& task_runner);
+
+  // Internal implementation is free to choose between unique and shared
+  // database to use here (transparently).
+  ProtoDatabaseImpl(const std::string& client_namespace,
+                    const std::string& type_prefix,
+                    const base::FilePath& db_dir,
+                    const scoped_refptr<base::SequencedTaskRunner>& task_runner,
+                    std::unique_ptr<SharedProtoDatabaseProvider> db_provider);
+
+  virtual ~ProtoDatabaseImpl() = default;
+
+  // DEPRECATED. This is to be used in case of forced unique db behavior.
+  void Init(const char* client_name,
+            const base::FilePath& database_dir,
+            const leveldb_env::Options& options,
+            Callbacks::InitCallback callback) override;
+
+  // This can be used along with a database obtained from new api
+  // Provider::GetDB(). If using the old api to create unique db, then we do not
+  // know the database dir and init will fail.
+  void Init(const std::string& client_name,
+            Callbacks::InitStatusCallback callback) override;
+
+  // Internal only api.
+  void InitWithDatabase(LevelDB* database,
+                        const base::FilePath& database_dir,
+                        const leveldb_env::Options& options,
+                        Callbacks::InitStatusCallback callback);
+
+  void UpdateEntries(std::unique_ptr<typename ProtoDatabase<T>::KeyEntryVector>
+                         entries_to_save,
+                     std::unique_ptr<KeyVector> keys_to_remove,
+                     Callbacks::UpdateCallback callback) override;
+
+  void UpdateEntriesWithRemoveFilter(
+      std::unique_ptr<typename ProtoDatabase<T>::KeyEntryVector>
+          entries_to_save,
+      const KeyFilter& delete_key_filter,
+      Callbacks::UpdateCallback callback) override;
+  void UpdateEntriesWithRemoveFilter(
+      std::unique_ptr<typename ProtoDatabase<T>::KeyEntryVector>
+          entries_to_save,
+      const KeyFilter& delete_key_filter,
+      const std::string& target_prefix,
+      Callbacks::UpdateCallback callback) override;
+
+  void LoadEntries(
+      typename Callbacks::Internal<T>::LoadCallback callback) override;
+
+  void LoadEntriesWithFilter(
+      const KeyFilter& filter,
+      typename Callbacks::Internal<T>::LoadCallback callback) override;
+  void LoadEntriesWithFilter(
+      const KeyFilter& key_filter,
+      const leveldb::ReadOptions& options,
+      const std::string& target_prefix,
+      typename Callbacks::Internal<T>::LoadCallback callback) override;
+
+  void LoadKeysAndEntries(
+      typename Callbacks::Internal<T>::LoadKeysAndEntriesCallback callback)
+      override;
+
+  void LoadKeysAndEntriesWithFilter(
+      const KeyFilter& filter,
+      typename Callbacks::Internal<T>::LoadKeysAndEntriesCallback callback)
+      override;
+  void LoadKeysAndEntriesWithFilter(
+      const KeyFilter& filter,
+      const leveldb::ReadOptions& options,
+      const std::string& target_prefix,
+      typename Callbacks::Internal<T>::LoadKeysAndEntriesCallback callback)
+      override;
+  void LoadKeysAndEntriesInRange(
+      const std::string& start,
+      const std::string& end,
+      typename Callbacks::Internal<T>::LoadKeysAndEntriesCallback callback)
+      override;
+
+  void LoadKeys(Callbacks::LoadKeysCallback callback) override;
+  void LoadKeys(const std::string& target_prefix,
+                Callbacks::LoadKeysCallback callback) override;
+
+  void GetEntry(const std::string& key,
+                typename Callbacks::Internal<T>::GetCallback callback) override;
+
+  void Destroy(Callbacks::DestroyCallback callback) override;
+
+  void RemoveKeysForTesting(const KeyFilter& key_filter,
+                            const std::string& target_prefix,
+                            Callbacks::UpdateCallback callback);
+
+  // Not thread safe.
+  ProtoDatabaseSelector* db_wrapper_for_testing() { return db_wrapper_.get(); }
+
+ private:
+  friend class ProtoDatabaseImplTest;
+
+  void Init(const std::string& client_name,
+            bool use_shared_db,
+            Callbacks::InitStatusCallback callback);
+
+  void PostTransaction(base::OnceClosure task);
+
+  scoped_refptr<ProtoDatabaseSelector> db_wrapper_;
+  const bool force_unique_db_;
+  const scoped_refptr<base::SequencedTaskRunner> task_runner_;
+
+  base::FilePath db_dir_;
+
+  std::unique_ptr<base::WeakPtrFactory<ProtoDatabaseImpl<T>>> weak_ptr_factory_;
+};
+
+namespace {
+
+// Update transactions need to serialize the entries to be updated on background
+// task runner. The database can be accessed on same task runner. The caller
+// must wrap the callback using RunUpdateCallback() to ensure the callback runs
+// in client task runner.
+template <typename T>
+void UpdateEntriesFromTaskRunner(
+    std::unique_ptr<typename Util::Internal<T>::KeyEntryVector> entries_to_save,
+    std::unique_ptr<KeyVector> keys_to_remove,
+    scoped_refptr<ProtoDatabaseSelector> db,
+    Callbacks::UpdateCallback callback) {
+  // Serialize the values from Proto to string before passing on to database.
+  auto pairs_to_save = std::make_unique<KeyValueVector>();
+  for (const auto& pair : *entries_to_save) {
+    pairs_to_save->push_back(
+        std::make_pair(pair.first, pair.second.SerializeAsString()));
+  }
+
+  db->UpdateEntries(std::move(pairs_to_save), std::move(keys_to_remove),
+                    std::move(callback));
+}
+
+// Update transactions need to serialize the entries to be updated on background
+// task runner. The database can be accessed on same task runner. The caller
+// must wrap the callback using RunUpdateCallback() to ensure the callback runs
+// in client task runner.
+template <typename T>
+void UpdateEntriesWithRemoveFilterFromTaskRunner(
+    std::unique_ptr<typename ProtoDatabase<T>::KeyEntryVector> entries_to_save,
+    const KeyFilter& delete_key_filter,
+    const std::string& target_prefix,
+    scoped_refptr<ProtoDatabaseSelector> db,
+    Callbacks::UpdateCallback callback) {
+  // Serialize the values from Proto to string before passing on to database.
+  auto pairs_to_save = std::make_unique<KeyValueVector>();
+  for (const auto& pair : *entries_to_save) {
+    pairs_to_save->push_back(
+        std::make_pair(pair.first, pair.second.SerializeAsString()));
+  }
+
+  db->UpdateEntriesWithRemoveFilter(std::move(pairs_to_save), delete_key_filter,
+                                    target_prefix, std::move(callback));
+}
+
+// Load transactions happen on background task runner. The loaded entries need
+// to be parsed into proto in background thread. This wraps the load callback
+// and parses the entries and posts result onto client task runner.
+template <typename T>
+void ParseLoadedEntries(
+    scoped_refptr<base::SequencedTaskRunner> callback_task_runner,
+    typename Callbacks::Internal<T>::LoadCallback callback,
+    bool success,
+    std::unique_ptr<ValueVector> loaded_entries) {
+  auto entries = std::make_unique<std::vector<T>>();
+
+  if (!success || !loaded_entries) {
+    entries.reset();
+  } else {
+    for (const auto& serialized_entry : *loaded_entries) {
+      T entry;
+      if (!entry.ParseFromString(serialized_entry)) {
+        DLOG(WARNING) << "Unable to parse leveldb_proto entry";
+        // TODO(cjhopman): Decide what to do about un-parseable entries.
+      }
+
+      entries->push_back(entry);
+    }
+  }
+
+  callback_task_runner->PostTask(
+      FROM_HERE,
+      base::BindOnce(std::move(callback), success, std::move(entries)));
+}
+
+// Load transactions happen on background task runner. The loaded entries need
+// to be parsed into proto in background thread. This wraps the load callback
+// and parses the entries and posts result onto client task runner.
+template <typename T>
+void ParseLoadedKeysAndEntries(
+    scoped_refptr<base::SequencedTaskRunner> callback_task_runner,
+    typename Callbacks::Internal<T>::LoadKeysAndEntriesCallback callback,
+    bool success,
+    std::unique_ptr<KeyValueMap> loaded_entries) {
+  auto keys_entries = std::make_unique<std::map<std::string, T>>();
+  if (!success || !loaded_entries) {
+    keys_entries.reset();
+  } else {
+    for (const auto& pair : *loaded_entries) {
+      T entry;
+      if (!entry.ParseFromString(pair.second)) {
+        DLOG(WARNING) << "Unable to parse leveldb_proto entry";
+        // TODO(cjhopman): Decide what to do about un-parseable entries.
+      }
+
+      keys_entries->insert(std::make_pair(pair.first, entry));
+    }
+  }
+
+  callback_task_runner->PostTask(
+      FROM_HERE,
+      base::BindOnce(std::move(callback), success, std::move(keys_entries)));
+}
+
+// Load transactions happen on background task runner. The loaded entries need
+// to be parsed into proto in background thread. This wraps the load callback
+// and parses the entries and posts result onto client task runner.
+template <typename T>
+void ParseLoadedEntry(
+    scoped_refptr<base::SequencedTaskRunner> callback_task_runner,
+    typename Callbacks::Internal<T>::GetCallback callback,
+    bool success,
+    std::unique_ptr<std::string> serialized_entry) {
+  auto entry = std::make_unique<T>();
+
+  if (!success || !serialized_entry) {
+    entry.reset();
+  } else if (!entry->ParseFromString(*serialized_entry)) {
+    DLOG(WARNING) << "Unable to parse leveldb_proto entry";
+    success = false;
+    entry.reset();
+  }
+  callback_task_runner->PostTask(
+      FROM_HERE,
+      base::BindOnce(std::move(callback), success, std::move(entry)));
+}
+
+}  // namespace
+
+template <typename T>
+ProtoDatabaseImpl<T>::ProtoDatabaseImpl(
+    const scoped_refptr<base::SequencedTaskRunner>& task_runner)
+    : db_wrapper_(new ProtoDatabaseSelector("", "", task_runner, nullptr)),
+      force_unique_db_(true),
+      task_runner_(task_runner),
+      weak_ptr_factory_(
+          std::make_unique<base::WeakPtrFactory<ProtoDatabaseImpl<T>>>(this)) {}
+
+template <typename T>
+ProtoDatabaseImpl<T>::ProtoDatabaseImpl(
+    const std::string& client_namespace,
+    const std::string& type_prefix,
+    const base::FilePath& db_dir,
+    const scoped_refptr<base::SequencedTaskRunner>& task_runner,
+    std::unique_ptr<SharedProtoDatabaseProvider> db_provider)
+    : db_wrapper_(new ProtoDatabaseSelector(client_namespace,
+                                            type_prefix,
+                                            task_runner,
+                                            std::move(db_provider))),
+      force_unique_db_(false),
+      task_runner_(task_runner),
+      db_dir_(db_dir),
+      weak_ptr_factory_(
+          std::make_unique<base::WeakPtrFactory<ProtoDatabaseImpl<T>>>(this)) {}
+
+template <typename T>
+void ProtoDatabaseImpl<T>::Init(const char* client_uma_name,
+                                const base::FilePath& database_dir,
+                                const leveldb_env::Options& options,
+                                Callbacks::InitCallback callback) {
+  DCHECK(force_unique_db_);
+  task_runner_->PostTask(
+      FROM_HERE,
+      base::BindOnce(
+          &ProtoDatabaseSelector::InitUniqueOrShared, db_wrapper_,
+          client_uma_name, database_dir, options,
+          /*use_shared_db=*/false, base::SequencedTaskRunnerHandle::Get(),
+          base::BindOnce(
+              [](Callbacks::InitCallback callback, Enums::InitStatus status) {
+                std::move(callback).Run(status == Enums::InitStatus::kOK);
+              },
+              std::move(callback))));
+}
+
+template <typename T>
+void ProtoDatabaseImpl<T>::Init(
+    const std::string& client_uma_name,
+    typename Callbacks::InitStatusCallback callback) {
+  bool use_shared_db =
+      !force_unique_db_ &&
+      SharedProtoDatabaseClientList::ShouldUseSharedDB(client_uma_name);
+  Init(client_uma_name, use_shared_db, std::move(callback));
+}
+
+template <typename T>
+void ProtoDatabaseImpl<T>::Init(const std::string& client_name,
+                                bool use_shared_db,
+                                Callbacks::InitStatusCallback callback) {
+  auto options = CreateSimpleOptions();
+  // If we're NOT using a shared DB, we want to force creation of the unique one
+  // because that's what we expect to be using moving forward. If we ARE using
+  // the shared DB, we only want to see if there's a unique DB that already
+  // exists and can be opened so that we can perform migration if necessary.
+  options.create_if_missing = !use_shared_db;
+  task_runner_->PostTask(
+      FROM_HERE,
+      base::BindOnce(&ProtoDatabaseSelector::InitUniqueOrShared, db_wrapper_,
+                     client_name, db_dir_, options, use_shared_db,
+                     base::SequencedTaskRunnerHandle::Get(),
+                     std::move(callback)));
+}
+
+template <typename T>
+void ProtoDatabaseImpl<T>::InitWithDatabase(
+    LevelDB* database,
+    const base::FilePath& database_dir,
+    const leveldb_env::Options& options,
+    Callbacks::InitStatusCallback callback) {
+  DCHECK(force_unique_db_);
+  task_runner_->PostTask(
+      FROM_HERE,
+      base::BindOnce(&ProtoDatabaseSelector::InitWithDatabase, db_wrapper_,
+                     base::Unretained(database), database_dir, options,
+                     base::SequencedTaskRunnerHandle::Get(),
+                     std::move(callback)));
+}
+
+template <typename T>
+void ProtoDatabaseImpl<T>::UpdateEntries(
+    std::unique_ptr<typename ProtoDatabase<T>::KeyEntryVector> entries_to_save,
+    std::unique_ptr<KeyVector> keys_to_remove,
+    Callbacks::UpdateCallback callback) {
+  base::OnceClosure update_task = base::BindOnce(
+      &UpdateEntriesFromTaskRunner<T>, std::move(entries_to_save),
+      std::move(keys_to_remove), db_wrapper_,
+      base::BindOnce(&RunUpdateCallback, base::SequencedTaskRunnerHandle::Get(),
+                     std::move(callback)));
+  PostTransaction(std::move(update_task));
+}
+
+template <typename T>
+void ProtoDatabaseImpl<T>::UpdateEntriesWithRemoveFilter(
+    std::unique_ptr<typename ProtoDatabase<T>::KeyEntryVector> entries_to_save,
+    const KeyFilter& delete_key_filter,
+    Callbacks::UpdateCallback callback) {
+  UpdateEntriesWithRemoveFilter(std::move(entries_to_save), delete_key_filter,
+                                std::string(), std::move(callback));
+}
+
+template <typename T>
+void ProtoDatabaseImpl<T>::UpdateEntriesWithRemoveFilter(
+    std::unique_ptr<typename ProtoDatabase<T>::KeyEntryVector> entries_to_save,
+    const KeyFilter& delete_key_filter,
+    const std::string& target_prefix,
+    Callbacks::UpdateCallback callback) {
+  base::OnceClosure update_task = base::BindOnce(
+      &UpdateEntriesWithRemoveFilterFromTaskRunner<T>,
+      std::move(entries_to_save), delete_key_filter, target_prefix, db_wrapper_,
+      base::BindOnce(&RunUpdateCallback, base::SequencedTaskRunnerHandle::Get(),
+                     std::move(callback)));
+  PostTransaction(std::move(update_task));
+}
+
+template <typename T>
+void ProtoDatabaseImpl<T>::LoadEntries(
+    typename Callbacks::Internal<T>::LoadCallback callback) {
+  LoadEntriesWithFilter(KeyFilter(), std::move(callback));
+}
+
+template <typename T>
+void ProtoDatabaseImpl<T>::LoadEntriesWithFilter(
+    const KeyFilter& filter,
+    typename Callbacks::Internal<T>::LoadCallback callback) {
+  LoadEntriesWithFilter(filter, leveldb::ReadOptions(), std::string(),
+                        std::move(callback));
+}
+
+template <typename T>
+void ProtoDatabaseImpl<T>::LoadEntriesWithFilter(
+    const KeyFilter& key_filter,
+    const leveldb::ReadOptions& options,
+    const std::string& target_prefix,
+    typename Callbacks::Internal<T>::LoadCallback callback) {
+  base::OnceClosure load_task =
+      base::BindOnce(&ProtoDatabaseSelector::LoadEntriesWithFilter, db_wrapper_,
+                     key_filter, options, target_prefix,
+                     base::BindOnce(&ParseLoadedEntries<T>,
+                                    base::SequencedTaskRunnerHandle::Get(),
+                                    std::move(callback)));
+  PostTransaction(std::move(load_task));
+}
+
+template <typename T>
+void ProtoDatabaseImpl<T>::LoadKeysAndEntries(
+    typename Callbacks::Internal<T>::LoadKeysAndEntriesCallback callback) {
+  LoadKeysAndEntriesWithFilter(KeyFilter(), std::move(callback));
+}
+
+template <typename T>
+void ProtoDatabaseImpl<T>::LoadKeysAndEntriesWithFilter(
+    const KeyFilter& filter,
+    typename Callbacks::Internal<T>::LoadKeysAndEntriesCallback callback) {
+  LoadKeysAndEntriesWithFilter(filter, leveldb::ReadOptions(), std::string(),
+                               std::move(callback));
+}
+
+template <typename T>
+void ProtoDatabaseImpl<T>::LoadKeysAndEntriesWithFilter(
+    const KeyFilter& filter,
+    const leveldb::ReadOptions& options,
+    const std::string& target_prefix,
+    typename Callbacks::Internal<T>::LoadKeysAndEntriesCallback callback) {
+  base::OnceClosure load_task =
+      base::BindOnce(&ProtoDatabaseSelector::LoadKeysAndEntriesWithFilter,
+                     db_wrapper_, filter, options, target_prefix,
+                     base::BindOnce(&ParseLoadedKeysAndEntries<T>,
+                                    base::SequencedTaskRunnerHandle::Get(),
+                                    std::move(callback)));
+  PostTransaction(std::move(load_task));
+}
+
+template <typename T>
+void ProtoDatabaseImpl<T>::LoadKeysAndEntriesInRange(
+    const std::string& start,
+    const std::string& end,
+    typename Callbacks::Internal<T>::LoadKeysAndEntriesCallback callback) {
+  base::OnceClosure load_task =
+      base::BindOnce(&ProtoDatabaseSelector::LoadKeysAndEntriesInRange,
+                     db_wrapper_, start, end,
+                     base::BindOnce(&ParseLoadedKeysAndEntries<T>,
+                                    base::SequencedTaskRunnerHandle::Get(),
+                                    std::move(callback)));
+  PostTransaction(std::move(load_task));
+}
+
+template <typename T>
+void ProtoDatabaseImpl<T>::LoadKeys(Callbacks::LoadKeysCallback callback) {
+  LoadKeys(std::string(), std::move(callback));
+}
+
+template <typename T>
+void ProtoDatabaseImpl<T>::LoadKeys(const std::string& target_prefix,
+                                    Callbacks::LoadKeysCallback callback) {
+  base::OnceClosure load_task = base::BindOnce(
+      &ProtoDatabaseSelector::LoadKeys, db_wrapper_, target_prefix,
+      base::BindOnce(&RunLoadKeysCallback,
+                     base::SequencedTaskRunnerHandle::Get(),
+                     std::move(callback)));
+  PostTransaction(std::move(load_task));
+}
+
+template <typename T>
+void ProtoDatabaseImpl<T>::GetEntry(
+    const std::string& key,
+    typename Callbacks::Internal<T>::GetCallback callback) {
+  base::OnceClosure get_task =
+      base::BindOnce(&ProtoDatabaseSelector::GetEntry, db_wrapper_, key,
+                     base::BindOnce(&ParseLoadedEntry<T>,
+                                    base::SequencedTaskRunnerHandle::Get(),
+                                    std::move(callback)));
+  PostTransaction(std::move(get_task));
+}
+
+template <typename T>
+void ProtoDatabaseImpl<T>::Destroy(Callbacks::DestroyCallback callback) {
+  base::OnceClosure destroy_task =
+      base::BindOnce(&ProtoDatabaseSelector::Destroy, db_wrapper_,
+                     base::BindOnce(&RunDestroyCallback,
+                                    base::SequencedTaskRunnerHandle::Get(),
+                                    std::move(callback)));
+  PostTransaction(std::move(destroy_task));
+}
+
+template <typename T>
+void ProtoDatabaseImpl<T>::RemoveKeysForTesting(
+    const KeyFilter& key_filter,
+    const std::string& target_prefix,
+    Callbacks::UpdateCallback callback) {
+  base::OnceClosure update_task = base::BindOnce(
+      &ProtoDatabaseSelector::RemoveKeysForTesting, db_wrapper_, key_filter,
+      target_prefix,
+      base::BindOnce(&RunUpdateCallback, base::SequencedTaskRunnerHandle::Get(),
+                     std::move(callback)));
+  PostTransaction(std::move(update_task));
+}
+
+template <typename T>
+void ProtoDatabaseImpl<T>::PostTransaction(base::OnceClosure task) {
+  task_runner_->PostTask(FROM_HERE,
+                         base::BindOnce(&ProtoDatabaseSelector::AddTransaction,
+                                        db_wrapper_, std::move(task)));
+}
+
+}  // namespace leveldb_proto
+
+#endif  // COMPONENTS_LEVELDB_PROTO_INTERNAL_PROTO_DATABASE_IMPL_H_
\ No newline at end of file
diff --git a/components/leveldb_proto/internal/proto_database_wrapper_unittest.cc b/components/leveldb_proto/internal/proto_database_impl_unittest.cc
similarity index 92%
rename from components/leveldb_proto/internal/proto_database_wrapper_unittest.cc
rename to components/leveldb_proto/internal/proto_database_impl_unittest.cc
index f517019..f0f6d4f 100644
--- a/components/leveldb_proto/internal/proto_database_wrapper_unittest.cc
+++ b/components/leveldb_proto/internal/proto_database_impl_unittest.cc
@@ -1,8 +1,8 @@
-// Copyright 2018 The Chromium Authors. All rights reserved.
+// 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/leveldb_proto/internal/proto_database_wrapper.h"
+#include "components/leveldb_proto/internal/proto_database_impl.h"
 
 #include "base/bind.h"
 #include "base/files/scoped_temp_dir.h"
@@ -53,7 +53,7 @@
                                     std::move(provider_weak_ptr)) {}
 };
 
-class ProtoDatabaseWrapperTest : public testing::Test {
+class ProtoDatabaseImplTest : public testing::Test {
  public:
   void SetUp() override {
     temp_dir_ = std::make_unique<base::ScopedTempDir>();
@@ -71,13 +71,13 @@
     shared_db_temp_dir_.reset();
   }
 
-  std::unique_ptr<ProtoDatabaseWrapper<TestProto>> CreateWrapper(
+  std::unique_ptr<ProtoDatabaseImpl<TestProto>> CreateWrapper(
       const std::string& client_namespace,
       const std::string& type_prefix,
       const base::FilePath& db_dir,
       const scoped_refptr<base::SequencedTaskRunner>& task_runner,
       std::unique_ptr<SharedProtoDatabaseProvider> db_provider) {
-    return std::make_unique<ProtoDatabaseWrapper<TestProto>>(
+    return std::make_unique<ProtoDatabaseImpl<TestProto>>(
         client_namespace, type_prefix, db_dir, task_runner,
         std::move(db_provider));
   }
@@ -98,16 +98,16 @@
         GetTestThreadTaskRunner(), db_provider->weak_factory_.GetWeakPtr());
   }
 
-  // Uses ProtoDatabaseWrapper's 3 parameter Init to bypass the check that gets
+  // Uses ProtoDatabaseImpl's 3 parameter Init to bypass the check that gets
   // |use_shared_db|'s value.
-  void InitWrapper(ProtoDatabaseWrapper<TestProto>* wrapper,
+  void InitWrapper(ProtoDatabaseImpl<TestProto>* wrapper,
                    const std::string& client_name,
                    bool use_shared_db,
                    Callbacks::InitStatusCallback callback) {
     wrapper->Init(client_name, use_shared_db, std::move(callback));
   }
 
-  void InitWrapperAndWait(ProtoDatabaseWrapper<TestProto>* wrapper,
+  void InitWrapperAndWait(ProtoDatabaseImpl<TestProto>* wrapper,
                           const std::string& client_name,
                           bool use_shared_db,
                           Enums::InitStatus expect_status) {
@@ -117,7 +117,7 @@
         base::BindOnce(
             [](base::OnceClosure closure, Enums::InitStatus expect_status,
                Enums::InitStatus status) {
-              ASSERT_EQ(status, expect_status);
+              EXPECT_EQ(status, expect_status);
               std::move(closure).Run();
             },
             init_loop.QuitClosure(), expect_status));
@@ -126,7 +126,7 @@
 
   // Just uses each entry's key to fill out the id/data fields in TestProto as
   // well.
-  void AddDataToWrapper(ProtoDatabaseWrapper<TestProto>* wrapper,
+  void AddDataToWrapper(ProtoDatabaseImpl<TestProto>* wrapper,
                         std::vector<std::string>* entry_keys) {
     auto data_set =
         std::make_unique<std::vector<std::pair<std::string, TestProto>>>();
@@ -149,7 +149,7 @@
     data_loop.Run();
   }
 
-  void VerifyDataInWrapper(ProtoDatabaseWrapper<TestProto>* wrapper,
+  void VerifyDataInWrapper(ProtoDatabaseImpl<TestProto>* wrapper,
                            std::vector<std::string>* entry_keys) {
     base::RunLoop load_loop;
     wrapper->LoadKeysAndEntries(base::BindOnce(
@@ -171,7 +171,7 @@
   void UpdateClientMetadata(
       SharedDBMetadataProto::MigrationStatus migration_status) {
     base::RunLoop init_wait;
-    auto client = shared_db_->GetClientForTesting<TestProto>(
+    auto client = shared_db_->GetClientForTesting(
         kDefaultNamespace, kDefaultTypePrefix, /*create_if_missing=*/true,
         base::BindOnce(
             [](base::OnceClosure closure, Enums::InitStatus status,
@@ -199,7 +199,7 @@
   SharedDBMetadataProto::MigrationStatus GetClientMigrationStatus() {
     SharedDBMetadataProto::MigrationStatus migration_status;
     base::RunLoop init_wait;
-    auto client = shared_db_->GetClientForTesting<TestProto>(
+    auto client = shared_db_->GetClientForTesting(
         kDefaultNamespace, kDefaultTypePrefix, /*create_if_missing=*/true,
         base::BindOnce(
             [](base::OnceClosure closure,
@@ -233,7 +233,7 @@
   std::unique_ptr<base::ScopedTempDir> shared_db_temp_dir_;
 };
 
-TEST_F(ProtoDatabaseWrapperTest, FailsBothDatabases) {
+TEST_F(ProtoDatabaseImplTest, FailsBothDatabases) {
   auto db_provider = CreateProviderNoSharedDB();
   auto shared_db_provider = CreateSharedProvider(db_provider.get());
   auto wrapper = CreateWrapper(kDefaultNamespace, kDefaultTypePrefix,
@@ -243,7 +243,7 @@
                      Enums::InitStatus::kError);
 }
 
-TEST_F(ProtoDatabaseWrapperTest, SucceedsWithUnique_DontUseShared_NoSharedDB) {
+TEST_F(ProtoDatabaseImplTest, SucceedsWithUnique_DontUseShared_NoSharedDB) {
   auto db_provider = CreateProviderNoSharedDB();
   auto shared_db_provider = CreateSharedProvider(db_provider.get());
   auto wrapper = CreateWrapper(kDefaultNamespace, kDefaultTypePrefix,
@@ -253,7 +253,7 @@
                      Enums::InitStatus::kOK);
 }
 
-TEST_F(ProtoDatabaseWrapperTest, Fails_UseShared_NoSharedDB_NoUniqueDB) {
+TEST_F(ProtoDatabaseImplTest, Fails_UseShared_NoSharedDB_NoUniqueDB) {
   auto db_provider = CreateProviderNoSharedDB();
   auto wrapper = CreateWrapper(kDefaultNamespace, kDefaultTypePrefix,
                                temp_dir(), GetTestThreadTaskRunner(),
@@ -262,7 +262,7 @@
                      Enums::InitStatus::kError);
 }
 
-TEST_F(ProtoDatabaseWrapperTest, SucceedsWithUnique_UseShared_NoSharedDB) {
+TEST_F(ProtoDatabaseImplTest, SucceedsWithUnique_UseShared_NoSharedDB) {
   // First we create a unique DB so our second pass has a unique DB available.
   auto db_provider = CreateProviderNoSharedDB();
   auto unique_wrapper = CreateWrapper(kDefaultNamespace, kDefaultTypePrefix,
@@ -280,7 +280,7 @@
                      Enums::InitStatus::kOK);
 }
 
-TEST_F(ProtoDatabaseWrapperTest, SucceedsWithShared_UseShared_HasSharedDB) {
+TEST_F(ProtoDatabaseImplTest, SucceedsWithShared_UseShared_HasSharedDB) {
   auto db_provider = CreateProviderWithSharedDB();
   auto wrapper = CreateWrapper(kDefaultNamespace, kDefaultTypePrefix,
                                temp_dir(), GetTestThreadTaskRunner(),
@@ -289,7 +289,7 @@
                      Enums::InitStatus::kOK);
 }
 
-TEST_F(ProtoDatabaseWrapperTest, SucceedsWithUnique_DontUseShared_HasSharedDB) {
+TEST_F(ProtoDatabaseImplTest, SucceedsWithUnique_DontUseShared_HasSharedDB) {
   auto db_provider = CreateProviderWithSharedDB();
   auto wrapper = CreateWrapper(kDefaultNamespace, kDefaultTypePrefix,
                                temp_dir(), GetTestThreadTaskRunner(),
@@ -299,7 +299,7 @@
 }
 
 // Migration tests:
-TEST_F(ProtoDatabaseWrapperTest, Migration_EmptyDBs_UniqueToShared) {
+TEST_F(ProtoDatabaseImplTest, Migration_EmptyDBs_UniqueToShared) {
   // First we create a unique DB so our second pass has a unique DB available.
   auto db_provider_noshared = CreateProviderNoSharedDB();
   auto unique_wrapper =
@@ -323,7 +323,7 @@
             GetClientMigrationStatus());
 }
 
-TEST_F(ProtoDatabaseWrapperTest, Migration_EmptyDBs_SharedToUnique) {
+TEST_F(ProtoDatabaseImplTest, Migration_EmptyDBs_SharedToUnique) {
   // First we create a unique DB so our second pass has a unique DB available.
   auto db_provider = CreateProviderWithSharedDB();
   auto shared_wrapper = CreateWrapper(kDefaultNamespace, kDefaultTypePrefix,
@@ -343,7 +343,7 @@
             GetClientMigrationStatus());
 }
 
-TEST_F(ProtoDatabaseWrapperTest, Migration_UniqueToShared) {
+TEST_F(ProtoDatabaseImplTest, Migration_UniqueToShared) {
   auto data_set = std::make_unique<std::vector<std::string>>();
   data_set->emplace_back("entry1");
   data_set->emplace_back("entry2");
@@ -374,7 +374,7 @@
             GetClientMigrationStatus());
 }
 
-TEST_F(ProtoDatabaseWrapperTest, Migration_SharedToUnique) {
+TEST_F(ProtoDatabaseImplTest, Migration_SharedToUnique) {
   auto data_set = std::make_unique<std::vector<std::string>>();
   data_set->emplace_back("entry1");
   data_set->emplace_back("entry2");
@@ -404,7 +404,7 @@
             GetClientMigrationStatus());
 }
 
-TEST_F(ProtoDatabaseWrapperTest, Migration_UniqueToShared_UniqueObsolete) {
+TEST_F(ProtoDatabaseImplTest, Migration_UniqueToShared_UniqueObsolete) {
   auto data_set = std::make_unique<std::vector<std::string>>();
   data_set->emplace_back("entry1");
   data_set->emplace_back("entry2");
@@ -440,7 +440,7 @@
             GetClientMigrationStatus());
 }
 
-TEST_F(ProtoDatabaseWrapperTest, Migration_UniqueToShared_SharedObsolete) {
+TEST_F(ProtoDatabaseImplTest, Migration_UniqueToShared_SharedObsolete) {
   auto data_set = std::make_unique<std::vector<std::string>>();
   data_set->emplace_back("entry1");
   data_set->emplace_back("entry2");
@@ -488,7 +488,7 @@
             GetClientMigrationStatus());
 }
 
-TEST_F(ProtoDatabaseWrapperTest, Migration_SharedToUnique_SharedObsolete) {
+TEST_F(ProtoDatabaseImplTest, Migration_SharedToUnique_SharedObsolete) {
   auto data_set = std::make_unique<std::vector<std::string>>();
   data_set->emplace_back("entry1");
   data_set->emplace_back("entry2");
@@ -524,7 +524,7 @@
             GetClientMigrationStatus());
 }
 
-TEST_F(ProtoDatabaseWrapperTest, Migration_SharedToUnique_UniqueObsolete) {
+TEST_F(ProtoDatabaseImplTest, Migration_SharedToUnique_UniqueObsolete) {
   auto data_set = std::make_unique<std::vector<std::string>>();
   data_set->emplace_back("entry1");
   data_set->emplace_back("entry2");
diff --git a/components/leveldb_proto/internal/proto_database_perftest.cc b/components/leveldb_proto/internal/proto_database_perftest.cc
index ac2f2ca..830cca2 100644
--- a/components/leveldb_proto/internal/proto_database_perftest.cc
+++ b/components/leveldb_proto/internal/proto_database_perftest.cc
@@ -24,6 +24,7 @@
 #include "base/threading/thread.h"
 #include "build/build_config.h"
 #include "components/leveldb_proto/internal/leveldb_database.h"
+#include "components/leveldb_proto/internal/proto_database_impl.h"
 #include "components/leveldb_proto/internal/unique_proto_database.h"
 #include "components/leveldb_proto/testing/proto/test_db.pb.h"
 #include "testing/gmock/include/gmock/gmock.h"
@@ -97,7 +98,7 @@
   TestDatabase(const std::string& name,
                scoped_refptr<base::SingleThreadTaskRunner> task_runner,
                const base::FilePath& path) {
-    db_.reset(new UniqueProtoDatabase<TestProto>(task_runner));
+    db_.reset(new ProtoDatabaseImpl<TestProto>(task_runner));
     leveldb_env::Options options = leveldb_proto::CreateSimpleOptions();
 
     base::RunLoop run_init_db;
@@ -114,11 +115,11 @@
   }
 
   bool is_initialized() const { return is_initialized_; }
-  UniqueProtoDatabase<TestProto>* proto_db() const { return db_.get(); }
+  ProtoDatabaseImpl<TestProto>* proto_db() const { return db_.get(); }
 
  private:
   bool is_initialized_ = false;
-  std::unique_ptr<UniqueProtoDatabase<TestProto>> db_;
+  std::unique_ptr<ProtoDatabaseImpl<TestProto>> db_;
 };
 
 }  // namespace
@@ -546,7 +547,10 @@
   }
 
   bool GetApproximateMemoryUsageOfDB(TestDatabase* db, uint64_t* memory_use) {
-    return db->proto_db()->GetApproximateMemoryUse(memory_use);
+    return db->proto_db()
+        ->db_wrapper_for_testing()
+        ->db_for_testing()
+        ->GetApproximateMemoryUse(memory_use);
   }
 
   std::map<std::string, std::unique_ptr<TestDatabase>> dbs_;
diff --git a/components/leveldb_proto/internal/proto_database_selector.cc b/components/leveldb_proto/internal/proto_database_selector.cc
new file mode 100644
index 0000000..7a8dd7a
--- /dev/null
+++ b/components/leveldb_proto/internal/proto_database_selector.cc
@@ -0,0 +1,497 @@
+// 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/leveldb_proto/internal/proto_database_selector.h"
+
+#include <memory>
+#include <utility>
+
+#include "components/leveldb_proto/internal/migration_delegate.h"
+#include "components/leveldb_proto/internal/shared_proto_database.h"
+#include "components/leveldb_proto/internal/shared_proto_database_provider.h"
+#include "components/leveldb_proto/internal/unique_proto_database.h"
+
+namespace leveldb_proto {
+
+namespace {
+
+void RunInitCallbackOnTaskRunner(
+    Callbacks::InitStatusCallback callback,
+    scoped_refptr<base::SequencedTaskRunner> task_runner,
+    Enums::InitStatus status) {
+  task_runner->PostTask(FROM_HERE, base::BindOnce(std::move(callback), status));
+}
+
+}  // namespace
+
+ProtoDatabaseSelector::ProtoDatabaseSelector(
+    const std::string& client_namespace,
+    const std::string& type_prefix,
+    scoped_refptr<base::SequencedTaskRunner> task_runner,
+    std::unique_ptr<SharedProtoDatabaseProvider> db_provider)
+    : client_namespace_(client_namespace),
+      type_prefix_(type_prefix),
+      task_runner_(task_runner),
+      db_provider_(std::move(db_provider)),
+      migration_delegate_(std::make_unique<MigrationDelegate>()) {
+  DETACH_FROM_SEQUENCE(sequence_checker_);
+}
+
+ProtoDatabaseSelector::~ProtoDatabaseSelector() {
+  if (db_)
+    task_runner_->DeleteSoon(FROM_HERE, std::move(db_));
+}
+
+void ProtoDatabaseSelector::InitWithDatabase(
+    LevelDB* database,
+    const base::FilePath& database_dir,
+    const leveldb_env::Options& options,
+    scoped_refptr<base::SequencedTaskRunner> callback_task_runner,
+    Callbacks::InitStatusCallback callback) {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  if (!db_)
+    db_ = std::make_unique<UniqueProtoDatabase>(task_runner_);
+
+  db_->InitWithDatabase(
+      database, database_dir, options, false,
+      base::BindOnce(&RunInitCallbackOnTaskRunner, std::move(callback),
+                     callback_task_runner));
+  OnInitDone();
+}
+
+void ProtoDatabaseSelector::InitUniqueOrShared(
+    const std::string& client_name,
+    base::FilePath db_dir,
+    const leveldb_env::Options& options,
+    bool use_shared_db,
+    scoped_refptr<base::SequencedTaskRunner> callback_task_runner,
+    Callbacks::InitStatusCallback callback) {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  init_status_ = InitStatus::IN_PROGRESS;
+  auto unique_db =
+      std::make_unique<UniqueProtoDatabase>(db_dir, options, task_runner_);
+  auto* unique_db_ptr = unique_db.get();
+  unique_db_ptr->Init(
+      client_name.c_str(),
+      base::BindOnce(
+          &ProtoDatabaseSelector::OnInitUniqueDB, this, std::move(unique_db),
+          use_shared_db,
+          base::BindOnce(&RunInitCallbackOnTaskRunner, std::move(callback),
+                         callback_task_runner)));
+}
+
+void ProtoDatabaseSelector::OnInitUniqueDB(
+    std::unique_ptr<UniqueProtoDatabase> unique_db,
+    bool use_shared_db,
+    Callbacks::InitStatusCallback callback,
+    Enums::InitStatus status) {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  // If the unique DB is corrupt, just return it early with the corruption
+  // status to avoid silently migrating a corrupt database and giving no errors
+  // back.
+  if (status == Enums::InitStatus::kCorrupt) {
+    db_ = std::move(unique_db);
+    std::move(callback).Run(Enums::InitStatus::kCorrupt);
+    OnInitDone();
+    return;
+  }
+
+  // Clear out the unique_db before sending an unusable DB into InitSharedDB,
+  // a nullptr indicates opening a unique DB failed.
+  if (status != Enums::InitStatus::kOK)
+    unique_db.reset();
+
+  GetSharedDBClient(std::move(unique_db), use_shared_db, std::move(callback));
+}
+
+void ProtoDatabaseSelector::GetSharedDBClient(
+    std::unique_ptr<UniqueProtoDatabase> unique_db,
+    bool use_shared_db,
+    Callbacks::InitStatusCallback callback) {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  if (!db_provider_) {
+    OnInitSharedDB(std::move(unique_db), use_shared_db, std::move(callback),
+                   nullptr);
+    return;
+  }
+  // Get the current task runner to ensure the callback is run on the same
+  // callback as the rest, and the WeakPtr checks out on the right sequence.
+  DCHECK(task_runner_->RunsTasksInCurrentSequence());
+
+  db_provider_->GetDBInstance(
+      base::BindOnce(&ProtoDatabaseSelector::OnInitSharedDB, this,
+                     std::move(unique_db), use_shared_db, std::move(callback)),
+      task_runner_);
+}
+
+void ProtoDatabaseSelector::OnInitSharedDB(
+    std::unique_ptr<UniqueProtoDatabase> unique_db,
+    bool use_shared_db,
+    Callbacks::InitStatusCallback callback,
+    scoped_refptr<SharedProtoDatabase> shared_db) {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  if (shared_db) {
+    // If we have a reference to the shared database, try to get a client.
+    shared_db->GetClientAsync(
+        client_namespace_, type_prefix_, use_shared_db,
+        base::BindOnce(&ProtoDatabaseSelector::OnGetSharedDBClient, this,
+                       std::move(unique_db), use_shared_db,
+                       std::move(callback)));
+    return;
+  }
+
+  // Otherwise, we just call the OnGetSharedDBClient function with a nullptr
+  // client.
+  OnGetSharedDBClient(std::move(unique_db), use_shared_db, std::move(callback),
+                      nullptr);
+}
+
+void ProtoDatabaseSelector::OnGetSharedDBClient(
+    std::unique_ptr<UniqueProtoDatabase> unique_db,
+    bool use_shared_db,
+    Callbacks::InitStatusCallback callback,
+    std::unique_ptr<SharedProtoDatabaseClient> client) {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  if (!unique_db && !client) {
+    std::move(callback).Run(Enums::InitStatus::kError);
+    OnInitDone();
+    return;
+  }
+
+  if (!unique_db || !client) {
+    // One of two things happened:
+    // 1) We failed to get a shared DB instance, so regardless of whether we
+    // want to use the shared DB or not, we'll settle for the unique DB.
+    // 2) We failed to initialize a unique DB, but got  access to the shared DB,
+    // so we use that regardless of whether we "should be" or not.
+    db_ = client ? std::move(client) : std::move(unique_db);
+    std::move(callback).Run(Enums::InitStatus::kOK);
+    OnInitDone();
+    return;
+  }
+
+  UniqueProtoDatabase* from = nullptr;
+  UniqueProtoDatabase* to = nullptr;
+  if (use_shared_db) {
+    switch (client->migration_status()) {
+      case SharedDBMetadataProto::MIGRATION_NOT_ATTEMPTED:
+      case SharedDBMetadataProto::MIGRATE_TO_UNIQUE_SUCCESSFUL:
+        from = unique_db.get();
+        to = client.get();
+        break;
+      case SharedDBMetadataProto::MIGRATE_TO_SHARED_SUCCESSFUL:
+        // Unique db was deleted in previous migration, so nothing to do here.
+        return OnMigrationCleanupComplete(std::move(unique_db),
+                                          std::move(client), use_shared_db,
+                                          std::move(callback), true);
+      case SharedDBMetadataProto::MIGRATE_TO_SHARED_UNIQUE_TO_BE_DELETED:
+        // Migration transfer was completed, so just try deleting the unique db.
+        return OnMigrationTransferComplete(std::move(unique_db),
+                                           std::move(client), use_shared_db,
+                                           std::move(callback), true);
+      case SharedDBMetadataProto::MIGRATE_TO_UNIQUE_SHARED_TO_BE_DELETED:
+        // Shared db was not deleted in last migration and we want to use shared
+        // db. So, delete stale data, and attempt migration.
+        return DeleteOldDataAndMigrate(std::move(unique_db), std::move(client),
+                                       use_shared_db, std::move(callback));
+    }
+  } else {
+    switch (client->migration_status()) {
+      case SharedDBMetadataProto::MIGRATION_NOT_ATTEMPTED:
+      case SharedDBMetadataProto::MIGRATE_TO_SHARED_SUCCESSFUL:
+        from = client.get();
+        to = unique_db.get();
+        break;
+      case SharedDBMetadataProto::MIGRATE_TO_SHARED_UNIQUE_TO_BE_DELETED:
+        // Unique db was not deleted in last migration and we want to use unique
+        // db. So, delete stale data, and attempt migration.
+        return DeleteOldDataAndMigrate(std::move(unique_db), std::move(client),
+                                       use_shared_db, std::move(callback));
+      case SharedDBMetadataProto::MIGRATE_TO_UNIQUE_SUCCESSFUL:
+        // Shared db was deleted in previous migration, so nothing to do here.
+        return OnMigrationCleanupComplete(std::move(unique_db),
+                                          std::move(client), use_shared_db,
+                                          std::move(callback), true);
+      case SharedDBMetadataProto::MIGRATE_TO_UNIQUE_SHARED_TO_BE_DELETED:
+        // Migration transfer was completed, so just try deleting the shared db.
+        return OnMigrationTransferComplete(std::move(unique_db),
+                                           std::move(client), use_shared_db,
+                                           std::move(callback), true);
+    }
+  }
+
+  // We got access to both the unique DB and a shared DB, meaning we need to
+  // attempt migration and give back the right one.
+  migration_delegate_->DoMigration(
+      from, to,
+      base::BindOnce(&ProtoDatabaseSelector::OnMigrationTransferComplete, this,
+                     std::move(unique_db), std::move(client), use_shared_db,
+                     std::move(callback)));
+}
+
+void ProtoDatabaseSelector::DeleteOldDataAndMigrate(
+    std::unique_ptr<UniqueProtoDatabase> unique_db,
+    std::unique_ptr<SharedProtoDatabaseClient> client,
+    bool use_shared_db,
+    Callbacks::InitStatusCallback callback) {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  UniqueProtoDatabase* to_remove_old_data =
+      use_shared_db ? client.get() : unique_db.get();
+  auto maybe_do_migration =
+      base::BindOnce(&ProtoDatabaseSelector::MaybeDoMigrationOnDeletingOld,
+                     this, std::move(unique_db), std::move(client),
+                     std::move(callback), use_shared_db);
+
+  to_remove_old_data->UpdateEntriesWithRemoveFilter(
+      std::make_unique<KeyValueVector>(),
+      base::BindRepeating([](const std::string& key) { return true; }),
+      std::move(maybe_do_migration));
+}
+
+void ProtoDatabaseSelector::MaybeDoMigrationOnDeletingOld(
+    std::unique_ptr<UniqueProtoDatabase> unique_db,
+    std::unique_ptr<SharedProtoDatabaseClient> client,
+    Callbacks::InitStatusCallback callback,
+    bool use_shared_db,
+    bool delete_success) {
+  if (!delete_success) {
+    DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+    // Old data has not been removed from the database we want to use. We also
+    // know that previous attempt of migration failed for same reason. Give up
+    // on this database and use the other.
+    // This update is not necessary since this was the old value. But update to
+    // be clear.
+    client->UpdateClientInitMetadata(
+        use_shared_db
+            ? SharedDBMetadataProto::MIGRATE_TO_UNIQUE_SHARED_TO_BE_DELETED
+            : SharedDBMetadataProto::MIGRATE_TO_SHARED_UNIQUE_TO_BE_DELETED);
+    db_ = use_shared_db ? std::move(unique_db) : std::move(client);
+    std::move(callback).Run(Enums::InitStatus::kOK);
+    OnInitDone();
+    return;
+  }
+
+  auto* from = use_shared_db ? unique_db.get() : client.get();
+  auto* to = use_shared_db ? client.get() : unique_db.get();
+  migration_delegate_->DoMigration(
+      from, to,
+      base::BindOnce(&ProtoDatabaseSelector::OnMigrationTransferComplete, this,
+                     std::move(unique_db), std::move(client), use_shared_db,
+                     std::move(callback)));
+}
+
+void ProtoDatabaseSelector::OnMigrationTransferComplete(
+    std::unique_ptr<UniqueProtoDatabase> unique_db,
+    std::unique_ptr<SharedProtoDatabaseClient> client,
+    bool use_shared_db,
+    Callbacks::InitStatusCallback callback,
+    bool success) {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  if (success) {
+    // Call Destroy on the DB we no longer want to use.
+    auto* db_destroy_ptr = use_shared_db ? unique_db.get() : client.get();
+    db_destroy_ptr->Destroy(
+        base::BindOnce(&ProtoDatabaseSelector::OnMigrationCleanupComplete, this,
+                       std::move(unique_db), std::move(client), use_shared_db,
+                       std::move(callback)));
+    return;
+  }
+
+  // Failing to transfer the old data means that the requested database to be
+  // used could have some bad data. So, mark them to be deleted before use in
+  // the next runs.
+  client->UpdateClientInitMetadata(
+      use_shared_db
+          ? SharedDBMetadataProto::MIGRATE_TO_UNIQUE_SHARED_TO_BE_DELETED
+          : SharedDBMetadataProto::MIGRATE_TO_SHARED_UNIQUE_TO_BE_DELETED);
+  db_ = use_shared_db ? std::move(unique_db) : std::move(client);
+  std::move(callback).Run(Enums::InitStatus::kOK);
+  OnInitDone();
+}
+
+void ProtoDatabaseSelector::OnMigrationCleanupComplete(
+    std::unique_ptr<UniqueProtoDatabase> unique_db,
+    std::unique_ptr<SharedProtoDatabaseClient> client,
+    bool use_shared_db,
+    Callbacks::InitStatusCallback callback,
+    bool success) {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  // We still return true in our callback below because we do have a database as
+  // far as the original caller is concerned. As long as |db_| is assigned, we
+  // return true.
+  if (success) {
+    client->UpdateClientInitMetadata(
+        use_shared_db ? SharedDBMetadataProto::MIGRATE_TO_SHARED_SUCCESSFUL
+                      : SharedDBMetadataProto::MIGRATE_TO_UNIQUE_SUCCESSFUL);
+  } else {
+    client->UpdateClientInitMetadata(
+        use_shared_db
+            ? SharedDBMetadataProto::MIGRATE_TO_SHARED_UNIQUE_TO_BE_DELETED
+            : SharedDBMetadataProto::MIGRATE_TO_UNIQUE_SHARED_TO_BE_DELETED);
+  }
+  // Migration transfer was complete. So, we should use the requested database.
+  db_ = use_shared_db ? std::move(client) : std::move(unique_db);
+  std::move(callback).Run(Enums::InitStatus::kOK);
+  OnInitDone();
+}
+
+void ProtoDatabaseSelector::AddTransaction(base::OnceClosure task) {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  switch (init_status_) {
+    case InitStatus::IN_PROGRESS:
+      if (pending_tasks_.size() > 10) {
+        std::move(pending_tasks_.front()).Run();
+        pending_tasks_.pop();
+      }
+      pending_tasks_.push(std::move(task));
+      break;
+    case InitStatus::NOT_STARTED:
+      NOTREACHED();
+      FALLTHROUGH;
+    case InitStatus::DONE:
+      std::move(task).Run();
+      break;
+  }
+}
+
+void ProtoDatabaseSelector::UpdateEntries(
+    std::unique_ptr<KeyValueVector> entries_to_save,
+    std::unique_ptr<KeyVector> keys_to_remove,
+    Callbacks::UpdateCallback callback) {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  DCHECK_EQ(init_status_, InitStatus::DONE);
+  if (!db_) {
+    std::move(callback).Run(false);
+    return;
+  }
+  db_->UpdateEntries(std::move(entries_to_save), std::move(keys_to_remove),
+                     std::move(callback));
+}
+
+void ProtoDatabaseSelector::UpdateEntriesWithRemoveFilter(
+    std::unique_ptr<KeyValueVector> entries_to_save,
+    const KeyFilter& delete_key_filter,
+    const std::string& target_prefix,
+    Callbacks::UpdateCallback callback) {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  if (!db_) {
+    std::move(callback).Run(false);
+    return;
+  }
+  db_->UpdateEntriesWithRemoveFilter(std::move(entries_to_save),
+                                     delete_key_filter, target_prefix,
+                                     std::move(callback));
+}
+
+void ProtoDatabaseSelector::LoadEntries(
+    typename Callbacks::LoadCallback callback) {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  if (!db_) {
+    std::move(callback).Run(false, nullptr);
+    return;
+  }
+  db_->LoadEntries(std::move(callback));
+}
+
+void ProtoDatabaseSelector::LoadEntriesWithFilter(
+    const KeyFilter& key_filter,
+    const leveldb::ReadOptions& options,
+    const std::string& target_prefix,
+    typename Callbacks::LoadCallback callback) {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  if (!db_) {
+    std::move(callback).Run(false, nullptr);
+    return;
+  }
+  db_->LoadEntriesWithFilter(key_filter, options, target_prefix,
+                             std::move(callback));
+}
+
+void ProtoDatabaseSelector::LoadKeysAndEntries(
+    typename Callbacks::LoadKeysAndEntriesCallback callback) {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  if (!db_) {
+    std::move(callback).Run(false, nullptr);
+    return;
+  }
+  db_->LoadKeysAndEntries(std::move(callback));
+}
+
+void ProtoDatabaseSelector::LoadKeysAndEntriesWithFilter(
+    const KeyFilter& filter,
+    const leveldb::ReadOptions& options,
+    const std::string& target_prefix,
+    typename Callbacks::LoadKeysAndEntriesCallback callback) {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  if (!db_) {
+    std::move(callback).Run(false, nullptr);
+    return;
+  }
+  db_->LoadKeysAndEntriesWithFilter(filter, options, target_prefix,
+                                    std::move(callback));
+}
+
+void ProtoDatabaseSelector::LoadKeysAndEntriesInRange(
+    const std::string& start,
+    const std::string& end,
+    typename Callbacks::LoadKeysAndEntriesCallback callback) {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  if (!db_) {
+    std::move(callback).Run(false, nullptr);
+    return;
+  }
+  db_->LoadKeysAndEntriesInRange(start, end, std::move(callback));
+}
+
+void ProtoDatabaseSelector::LoadKeys(const std::string& target_prefix,
+                                     Callbacks::LoadKeysCallback callback) {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  if (!db_) {
+    std::move(callback).Run(false, nullptr);
+    return;
+  }
+  db_->LoadKeys(target_prefix, std::move(callback));
+}
+
+void ProtoDatabaseSelector::GetEntry(const std::string& key,
+                                     typename Callbacks::GetCallback callback) {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  if (!db_) {
+    std::move(callback).Run(false, nullptr);
+    return;
+  }
+  db_->GetEntry(key, std::move(callback));
+}
+
+void ProtoDatabaseSelector::Destroy(Callbacks::DestroyCallback callback) {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  if (!db_) {
+    std::move(callback).Run(false);
+    return;
+  }
+  db_->Destroy(std::move(callback));
+}
+
+void ProtoDatabaseSelector::RemoveKeysForTesting(
+    const KeyFilter& key_filter,
+    const std::string& target_prefix,
+    Callbacks::UpdateCallback callback) {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  if (!db_) {
+    std::move(callback).Run(false);
+    return;
+  }
+  db_->RemoveKeysForTesting(key_filter, target_prefix, std::move(callback));
+}
+
+void ProtoDatabaseSelector::OnInitDone() {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  init_status_ = InitStatus::DONE;
+  while (!pending_tasks_.empty()) {
+    task_runner_->PostTask(FROM_HERE, std::move(pending_tasks_.front()));
+    pending_tasks_.pop();
+  }
+}
+
+}  // namespace leveldb_proto
diff --git a/components/leveldb_proto/internal/proto_database_selector.h b/components/leveldb_proto/internal/proto_database_selector.h
new file mode 100644
index 0000000..2550ba4f
--- /dev/null
+++ b/components/leveldb_proto/internal/proto_database_selector.h
@@ -0,0 +1,171 @@
+// 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_LEVELDB_PROTO_INTERNAL_PROTO_DATABASE_SELECTOR_H_
+#define COMPONENTS_LEVELDB_PROTO_INTERNAL_PROTO_DATABASE_SELECTOR_H_
+
+#include <memory>
+#include <string>
+
+#include "base/containers/queue.h"
+#include "base/files/file_path.h"
+#include "base/sequenced_task_runner.h"
+#include "components/leveldb_proto/internal/proto_leveldb_wrapper.h"
+
+namespace leveldb_proto {
+
+class MigrationDelegate;
+class SharedProtoDatabase;
+class SharedProtoDatabaseClient;
+class SharedProtoDatabaseProvider;
+class UniqueProtoDatabase;
+
+// A wrapper around unique and shared database client. Handles initialization of
+// underlying database as unique or shared as requested.
+// TODO: Discuss the init flow/migration path for unique/shared DB here.
+class ProtoDatabaseSelector
+    : public base::RefCountedThreadSafe<ProtoDatabaseSelector> {
+ public:
+  ProtoDatabaseSelector(
+      const std::string& client_namespace,
+      const std::string& type_prefix,
+      scoped_refptr<base::SequencedTaskRunner> task_runner,
+      std::unique_ptr<SharedProtoDatabaseProvider> db_provider);
+
+  void InitWithDatabase(
+      LevelDB* database,
+      const base::FilePath& database_dir,
+      const leveldb_env::Options& options,
+      scoped_refptr<base::SequencedTaskRunner> callback_task_runner,
+      Callbacks::InitStatusCallback callback);
+
+  void InitUniqueOrShared(
+      const std::string& client_name,
+      base::FilePath db_dir,
+      const leveldb_env::Options& options,
+      bool use_shared_db,
+      scoped_refptr<base::SequencedTaskRunner> callback_task_runner,
+      Callbacks::InitStatusCallback callback);
+
+  void AddTransaction(base::OnceClosure task);
+
+  // DO NOT USE any of the functions below directly. They should be posted as
+  // transaction tasks using AddTransaction().
+  void UpdateEntries(std::unique_ptr<KeyValueVector> entries_to_save,
+                     std::unique_ptr<KeyVector> keys_to_remove,
+                     Callbacks::UpdateCallback callback);
+
+  void UpdateEntriesWithRemoveFilter(
+      std::unique_ptr<KeyValueVector> entries_to_save,
+      const KeyFilter& delete_key_filter,
+      Callbacks::UpdateCallback callback);
+  void UpdateEntriesWithRemoveFilter(
+      std::unique_ptr<KeyValueVector> entries_to_save,
+      const KeyFilter& delete_key_filter,
+      const std::string& target_prefix,
+      Callbacks::UpdateCallback callback);
+
+  void LoadEntries(typename Callbacks::LoadCallback callback);
+
+  void LoadEntriesWithFilter(const KeyFilter& key_filter,
+                             const leveldb::ReadOptions& options,
+                             const std::string& target_prefix,
+                             typename Callbacks::LoadCallback callback);
+
+  void LoadKeysAndEntries(
+      typename Callbacks::LoadKeysAndEntriesCallback callback);
+
+  void LoadKeysAndEntriesWithFilter(
+      const KeyFilter& filter,
+      const leveldb::ReadOptions& options,
+      const std::string& target_prefix,
+      typename Callbacks::LoadKeysAndEntriesCallback callback);
+  void LoadKeysAndEntriesInRange(
+      const std::string& start,
+      const std::string& end,
+      typename Callbacks::LoadKeysAndEntriesCallback callback);
+
+  void LoadKeys(const std::string& target_prefix,
+                Callbacks::LoadKeysCallback callback);
+
+  void GetEntry(const std::string& key,
+                typename Callbacks::GetCallback callback);
+
+  void Destroy(Callbacks::DestroyCallback callback);
+
+  void RemoveKeysForTesting(const KeyFilter& key_filter,
+                            const std::string& target_prefix,
+                            Callbacks::UpdateCallback callback);
+
+  UniqueProtoDatabase* db_for_testing() { return db_.get(); }
+
+ private:
+  friend class base::RefCountedThreadSafe<ProtoDatabaseSelector>;
+
+  enum class InitStatus {
+    NOT_STARTED,
+    IN_PROGRESS,
+    DONE  // success or failure.
+  };
+
+  ~ProtoDatabaseSelector();
+
+  void OnInitUniqueDB(std::unique_ptr<UniqueProtoDatabase> db,
+                      bool use_shared_db,
+                      Callbacks::InitStatusCallback callback,
+                      Enums::InitStatus status);
+
+  // |unique_db| should contain a nullptr if initializing the DB fails.
+  void GetSharedDBClient(std::unique_ptr<UniqueProtoDatabase> unique_db,
+                         bool use_shared_db,
+                         Callbacks::InitStatusCallback callback);
+  void OnInitSharedDB(std::unique_ptr<UniqueProtoDatabase> unique_db,
+                      bool use_shared_db,
+                      Callbacks::InitStatusCallback callback,
+                      scoped_refptr<SharedProtoDatabase> shared_db);
+  void OnGetSharedDBClient(std::unique_ptr<UniqueProtoDatabase> unique_db,
+                           bool use_shared_db,
+                           Callbacks::InitStatusCallback callback,
+                           std::unique_ptr<SharedProtoDatabaseClient> client);
+  void DeleteOldDataAndMigrate(
+      std::unique_ptr<UniqueProtoDatabase> unique_db,
+      std::unique_ptr<SharedProtoDatabaseClient> client,
+      bool use_shared_db,
+      Callbacks::InitStatusCallback callback);
+  void MaybeDoMigrationOnDeletingOld(
+      std::unique_ptr<UniqueProtoDatabase> unique_db,
+      std::unique_ptr<SharedProtoDatabaseClient> client,
+      Callbacks::InitStatusCallback init_callback,
+      bool use_shared_db,
+      bool delete_success);
+  void OnMigrationTransferComplete(
+      std::unique_ptr<UniqueProtoDatabase> unique_db,
+      std::unique_ptr<SharedProtoDatabaseClient> client,
+      bool use_shared_db,
+      Callbacks::InitStatusCallback callback,
+      bool success);
+  void OnMigrationCleanupComplete(
+      std::unique_ptr<UniqueProtoDatabase> unique_db,
+      std::unique_ptr<SharedProtoDatabaseClient> client,
+      bool use_shared_db,
+      Callbacks::InitStatusCallback callback,
+      bool success);
+  void OnInitDone();
+
+  const std::string client_namespace_;
+  const std::string type_prefix_;
+  const scoped_refptr<base::SequencedTaskRunner> task_runner_;
+  const std::unique_ptr<SharedProtoDatabaseProvider> db_provider_;
+  const std::unique_ptr<MigrationDelegate> migration_delegate_;
+
+  InitStatus init_status_ = InitStatus::NOT_STARTED;
+  base::queue<base::OnceClosure> pending_tasks_;
+  std::unique_ptr<UniqueProtoDatabase> db_;
+
+  SEQUENCE_CHECKER(sequence_checker_);
+};
+
+}  // namespace leveldb_proto
+
+#endif  // COMPONENTS_LEVELDB_PROTO_INTERNAL_PROTO_DATABASE_SELECTOR_H_
diff --git a/components/leveldb_proto/internal/proto_database_wrapper.cc b/components/leveldb_proto/internal/proto_database_wrapper.cc
deleted file mode 100644
index abb7b0a6..0000000
--- a/components/leveldb_proto/internal/proto_database_wrapper.cc
+++ /dev/null
@@ -1,19 +0,0 @@
-// Copyright 2018 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "components/leveldb_proto/internal/proto_database_wrapper.h"
-
-#include "components/leveldb_proto/public/proto_database_provider.h"
-
-namespace leveldb_proto {
-
-void GetSharedDBInstance(
-    ProtoDatabaseProvider* db_provider,
-    base::OnceCallback<void(scoped_refptr<SharedProtoDatabase>)> callback) {
-  DCHECK(base::SequencedTaskRunnerHandle::IsSet());
-  db_provider->GetSharedDBInstance(std::move(callback),
-                                   base::SequencedTaskRunnerHandle::Get());
-}
-
-}  // namespace leveldb_proto
\ No newline at end of file
diff --git a/components/leveldb_proto/internal/proto_database_wrapper.h b/components/leveldb_proto/internal/proto_database_wrapper.h
deleted file mode 100644
index 98f24f6..0000000
--- a/components/leveldb_proto/internal/proto_database_wrapper.h
+++ /dev/null
@@ -1,708 +0,0 @@
-// Copyright 2018 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef COMPONENTS_LEVELDB_PROTO_INTERNAL_PROTO_DATABASE_WRAPPER_H_
-#define COMPONENTS_LEVELDB_PROTO_INTERNAL_PROTO_DATABASE_WRAPPER_H_
-
-#include "base/bind.h"
-#include "base/files/file_path.h"
-#include "base/memory/weak_ptr.h"
-#include "base/threading/sequenced_task_runner_handle.h"
-#include "components/leveldb_proto/internal/migration_delegate.h"
-#include "components/leveldb_proto/internal/proto_leveldb_wrapper.h"
-#include "components/leveldb_proto/internal/shared_proto_database.h"
-#include "components/leveldb_proto/internal/shared_proto_database_provider.h"
-#include "components/leveldb_proto/internal/unique_proto_database.h"
-#include "components/leveldb_proto/public/proto_database.h"
-#include "components/leveldb_proto/public/shared_proto_database_client_list.h"
-
-namespace leveldb_proto {
-
-class ProtoDatabaseProvider;
-
-// Avoids circular dependencies between ProtoDatabaseWrapper and
-// ProtoDatabaseProvider, since we'd need to include the provider header here
-// to use |db_provider_|'s GetSharedDBInstance.
-void GetSharedDBInstance(
-    ProtoDatabaseProvider* db_provider,
-    base::OnceCallback<void(scoped_refptr<SharedProtoDatabase>)> callback);
-
-// The ProtoDatabaseWrapper<T> owns a ProtoDatabase<T> instance, and allows the
-// underlying ProtoDatabase<T> implementation to change without users of the
-// wrapper needing to know.
-// This allows clients to request a DB instance without knowing whether or not
-// it's a UniqueDatabase<T> or a SharedProtoDatabaseClient<T>.
-//
-// TODO: Discuss the init flow/migration path for unique/shared DB here.
-template <typename T>
-class ProtoDatabaseWrapper : public UniqueProtoDatabase<T> {
- public:
-  ProtoDatabaseWrapper(
-      const std::string& client_namespace,
-      const std::string& type_prefix,
-      const base::FilePath& db_dir,
-      const scoped_refptr<base::SequencedTaskRunner>& task_runner,
-      std::unique_ptr<SharedProtoDatabaseProvider> db_provider);
-
-  virtual ~ProtoDatabaseWrapper() = default;
-
-  // This version of Init is for compatibility, since many of the current
-  // proto database still use this.
-  void Init(const char* client_name,
-            const base::FilePath& database_dir,
-            const leveldb_env::Options& options,
-            Callbacks::InitCallback callback) override;
-
-  void Init(const std::string& client_name,
-            Callbacks::InitStatusCallback callback) override;
-
-  void UpdateEntries(std::unique_ptr<typename ProtoDatabase<T>::KeyEntryVector>
-                         entries_to_save,
-                     std::unique_ptr<std::vector<std::string>> keys_to_remove,
-                     Callbacks::UpdateCallback callback) override;
-
-  void UpdateEntriesWithRemoveFilter(
-      std::unique_ptr<typename ProtoDatabase<T>::KeyEntryVector>
-          entries_to_save,
-      const KeyFilter& delete_key_filter,
-      Callbacks::UpdateCallback callback) override;
-  void UpdateEntriesWithRemoveFilter(
-      std::unique_ptr<typename ProtoDatabase<T>::KeyEntryVector>
-          entries_to_save,
-      const KeyFilter& delete_key_filter,
-      const std::string& target_prefix,
-      Callbacks::UpdateCallback callback) override;
-
-  void LoadEntries(
-      typename Callbacks::Internal<T>::LoadCallback callback) override;
-
-  void LoadEntriesWithFilter(
-      const KeyFilter& filter,
-      typename Callbacks::Internal<T>::LoadCallback callback) override;
-  void LoadEntriesWithFilter(
-      const KeyFilter& key_filter,
-      const leveldb::ReadOptions& options,
-      const std::string& target_prefix,
-      typename Callbacks::Internal<T>::LoadCallback callback) override;
-
-  void LoadKeysAndEntries(
-      typename Callbacks::Internal<T>::LoadKeysAndEntriesCallback callback)
-      override;
-
-  void LoadKeysAndEntriesWithFilter(
-      const KeyFilter& filter,
-      typename Callbacks::Internal<T>::LoadKeysAndEntriesCallback callback)
-      override;
-  void LoadKeysAndEntriesWithFilter(
-      const KeyFilter& filter,
-      const leveldb::ReadOptions& options,
-      const std::string& target_prefix,
-      typename Callbacks::Internal<T>::LoadKeysAndEntriesCallback callback)
-      override;
-  void LoadKeysAndEntriesInRange(
-      const std::string& start,
-      const std::string& end,
-      typename Callbacks::Internal<T>::LoadKeysAndEntriesCallback callback)
-      override;
-
-  void LoadKeys(Callbacks::LoadKeysCallback callback) override;
-  void LoadKeys(const std::string& target_prefix,
-                Callbacks::LoadKeysCallback callback) override;
-
-  void GetEntry(const std::string& key,
-                typename Callbacks::Internal<T>::GetCallback callback) override;
-
-  void Destroy(Callbacks::DestroyCallback callback) override;
-
-  void RunCallbackOnCallingSequence(base::OnceClosure callback);
-
- private:
-  friend class ProtoDatabaseWrapperTest;
-
-  void Init(const std::string& client_name,
-            bool use_shared_db,
-            Callbacks::InitStatusCallback callback);
-
-  virtual void InitUniqueDB(const std::string& client_name,
-                            const leveldb_env::Options& options,
-                            bool use_shared_db,
-                            Callbacks::InitStatusCallback callback);
-  void OnInitUniqueDB(std::unique_ptr<ProtoDatabase<T>> db,
-                      bool use_shared_db,
-                      Callbacks::InitStatusCallback callback,
-                      Enums::InitStatus status);
-
-  // |unique_db| should contain a nullptr if initializing the DB fails.
-  void GetSharedDBClient(std::unique_ptr<ProtoDatabase<T>> unique_db,
-                         bool use_shared_db,
-                         Callbacks::InitStatusCallback callback);
-  void OnInitSharedDB(std::unique_ptr<ProtoDatabase<T>> unique_db,
-                      bool use_shared_db,
-                      Callbacks::InitStatusCallback callback,
-                      scoped_refptr<SharedProtoDatabase> shared_db);
-  void OnGetSharedDBClient(
-      std::unique_ptr<ProtoDatabase<T>> unique_db,
-      bool use_shared_db,
-      Callbacks::InitStatusCallback callback,
-      std::unique_ptr<SharedProtoDatabaseClient<T>> client);
-  void DeleteOldDataAndMigrate(
-      std::unique_ptr<ProtoDatabase<T>> unique_db,
-      std::unique_ptr<SharedProtoDatabaseClient<T>> client,
-      bool use_shared_db,
-      Callbacks::InitStatusCallback callback);
-  void MaybeDoMigrationOnDeletingOld(
-      std::unique_ptr<ProtoDatabase<T>> unique_db,
-      std::unique_ptr<SharedProtoDatabaseClient<T>> client,
-      Callbacks::InitStatusCallback init_callback,
-      bool use_shared_db,
-      bool delete_success);
-  void OnMigrationTransferComplete(
-      std::unique_ptr<ProtoDatabase<T>> unique_db,
-      std::unique_ptr<SharedProtoDatabaseClient<T>> client,
-      bool use_shared_db,
-      Callbacks::InitStatusCallback callback,
-      bool success);
-  void OnMigrationCleanupComplete(
-      std::unique_ptr<ProtoDatabase<T>> unique_db,
-      std::unique_ptr<SharedProtoDatabaseClient<T>> client,
-      bool use_shared_db,
-      Callbacks::InitStatusCallback callback,
-      bool success);
-
-  std::string client_namespace_;
-  std::string type_prefix_;
-  base::FilePath db_dir_;
-  std::unique_ptr<SharedProtoDatabaseProvider> db_provider_;
-
-  std::unique_ptr<ProtoDatabase<T>> db_;
-  scoped_refptr<base::SequencedTaskRunner> task_runner_;
-
-  std::unique_ptr<MigrationDelegate<T>> migration_delegate_;
-
-  std::unique_ptr<base::WeakPtrFactory<ProtoDatabaseWrapper<T>>>
-      weak_ptr_factory_;
-};
-
-template <typename T>
-void ProtoDatabaseWrapper<T>::RunCallbackOnCallingSequence(
-    base::OnceClosure callback) {
-  DCHECK(base::SequencedTaskRunnerHandle::IsSet());
-  base::SequencedTaskRunnerHandle::Get()->PostTask(FROM_HERE,
-                                                   std::move(callback));
-}
-
-template <typename T>
-ProtoDatabaseWrapper<T>::ProtoDatabaseWrapper(
-    const std::string& client_namespace,
-    const std::string& type_prefix,
-    const base::FilePath& db_dir,
-    const scoped_refptr<base::SequencedTaskRunner>& task_runner,
-    std::unique_ptr<SharedProtoDatabaseProvider> db_provider)
-    : UniqueProtoDatabase<T>(task_runner) {
-  client_namespace_ = client_namespace;
-  type_prefix_ = type_prefix;
-  db_dir_ = db_dir;
-  db_ = nullptr;
-  db_provider_ = std::move(db_provider);
-  task_runner_ = task_runner;
-  migration_delegate_ = std::make_unique<MigrationDelegate<T>>();
-  weak_ptr_factory_ =
-      std::make_unique<base::WeakPtrFactory<ProtoDatabaseWrapper<T>>>(this);
-}
-
-template <typename T>
-void ProtoDatabaseWrapper<T>::Init(const char* client_name,
-                                   const base::FilePath& database_dir,
-                                   const leveldb_env::Options& options,
-                                   Callbacks::InitCallback callback) {
-  // We shouldn't be calling this on the wrapper. This function is purely for
-  // compatibility right now.
-  NOTREACHED();
-}
-
-template <typename T>
-void ProtoDatabaseWrapper<T>::Init(
-    const std::string& client_name,
-    typename Callbacks::InitStatusCallback callback) {
-  bool use_shared_db =
-      SharedProtoDatabaseClientList::ShouldUseSharedDB(client_name);
-  Init(client_name, use_shared_db, std::move(callback));
-}
-
-template <typename T>
-void ProtoDatabaseWrapper<T>::Init(const std::string& client_name,
-                                   bool use_shared_db,
-                                   Callbacks::InitStatusCallback callback) {
-  auto options = CreateSimpleOptions();
-  // If we're NOT using a shared DB, we want to force creation of the unique one
-  // because that's what we expect to be using moving forward. If we ARE using
-  // the shared DB, we only want to see if there's a unique DB that already
-  // exists and can be opened so that we can perform migration if necessary.
-  options.create_if_missing = !use_shared_db;
-  InitUniqueDB(client_name, options, use_shared_db, std::move(callback));
-}
-
-template <typename T>
-void ProtoDatabaseWrapper<T>::InitUniqueDB(
-    const std::string& client_name,
-    const leveldb_env::Options& options,
-    bool use_shared_db,
-    Callbacks::InitStatusCallback callback) {
-  auto unique_db = std::make_unique<UniqueProtoDatabase<T>>(db_dir_, options,
-                                                            this->task_runner_);
-  auto* unique_db_ptr = unique_db.get();
-  unique_db_ptr->Init(
-      client_name,
-      base::BindOnce(&ProtoDatabaseWrapper<T>::OnInitUniqueDB,
-                     weak_ptr_factory_->GetWeakPtr(), std::move(unique_db),
-                     use_shared_db, std::move(callback)));
-}
-
-template <typename T>
-void ProtoDatabaseWrapper<T>::OnInitUniqueDB(
-    std::unique_ptr<ProtoDatabase<T>> unique_db,
-    bool use_shared_db,
-    Callbacks::InitStatusCallback callback,
-    Enums::InitStatus status) {
-  // If the unique DB is corrupt, just return it early with the corruption
-  // status to avoid silently migrating a corrupt database and giving no errors
-  // back.
-  if (status == Enums::InitStatus::kCorrupt) {
-    db_ = std::move(unique_db);
-    RunCallbackOnCallingSequence(
-        base::BindOnce(std::move(callback), Enums::InitStatus::kCorrupt));
-    return;
-  }
-
-  // Clear out the unique_db before sending an unusable DB into InitSharedDB,
-  // a nullptr indicates opening a unique DB failed.
-  if (status != Enums::InitStatus::kOK)
-    unique_db.reset();
-
-  GetSharedDBClient(std::move(unique_db), use_shared_db, std::move(callback));
-}
-
-template <typename T>
-void ProtoDatabaseWrapper<T>::GetSharedDBClient(
-    std::unique_ptr<ProtoDatabase<T>> unique_db,
-    bool use_shared_db,
-    Callbacks::InitStatusCallback callback) {
-  // Get the current task runner to ensure the callback is run on the same
-  // callback as the rest, and the WeakPtr checks out on the right sequence.
-  DCHECK(base::SequencedTaskRunnerHandle::IsSet());
-  auto current_task_runner = base::SequencedTaskRunnerHandle::Get();
-
-  db_provider_->GetDBInstance(
-      base::BindOnce(&ProtoDatabaseWrapper<T>::OnInitSharedDB,
-                     weak_ptr_factory_->GetWeakPtr(), std::move(unique_db),
-                     use_shared_db, std::move(callback)),
-      current_task_runner);
-}
-
-template <typename T>
-void ProtoDatabaseWrapper<T>::OnInitSharedDB(
-    std::unique_ptr<ProtoDatabase<T>> unique_db,
-    bool use_shared_db,
-    Callbacks::InitStatusCallback callback,
-    scoped_refptr<SharedProtoDatabase> shared_db) {
-  if (shared_db) {
-    // If we have a reference to the shared database, try to get a client.
-    shared_db->GetClientAsync<T>(
-        client_namespace_, type_prefix_, use_shared_db,
-        base::BindOnce(&ProtoDatabaseWrapper<T>::OnGetSharedDBClient,
-                       weak_ptr_factory_->GetWeakPtr(), std::move(unique_db),
-                       use_shared_db, std::move(callback)));
-    return;
-  }
-
-  // Otherwise, we just call the OnGetSharedDBClient function with a nullptr
-  // client.
-  OnGetSharedDBClient(std::move(unique_db), use_shared_db, std::move(callback),
-                      nullptr);
-}
-
-template <typename T>
-void ProtoDatabaseWrapper<T>::OnGetSharedDBClient(
-    std::unique_ptr<ProtoDatabase<T>> unique_db,
-    bool use_shared_db,
-    Callbacks::InitStatusCallback callback,
-    std::unique_ptr<SharedProtoDatabaseClient<T>> client) {
-  if (!unique_db && !client) {
-    RunCallbackOnCallingSequence(
-        base::BindOnce(std::move(callback), Enums::InitStatus::kError));
-    return;
-  }
-
-  if (!unique_db || !client) {
-    // One of two things happened:
-    // 1) We failed to get a shared DB instance, so regardless of whether we
-    // want to use the shared DB or not, we'll settle for the unique DB.
-    // 2) We failed to initialize a unique DB, but got  access to the shared DB,
-    // so we use that regardless of whether we "should be" or not.
-    db_ = client ? std::move(client) : std::move(unique_db);
-    RunCallbackOnCallingSequence(
-        base::BindOnce(std::move(callback), Enums::InitStatus::kOK));
-    return;
-  }
-
-  ProtoDatabase<T>* from = nullptr;
-  ProtoDatabase<T>* to = nullptr;
-  if (use_shared_db) {
-    switch (client->migration_status()) {
-      case SharedDBMetadataProto::MIGRATION_NOT_ATTEMPTED:
-      case SharedDBMetadataProto::MIGRATE_TO_UNIQUE_SUCCESSFUL:
-        from = unique_db.get();
-        to = client.get();
-        break;
-      case SharedDBMetadataProto::MIGRATE_TO_SHARED_SUCCESSFUL:
-        // Unique db was deleted in previous migration, so nothing to do here.
-        return OnMigrationCleanupComplete(std::move(unique_db),
-                                          std::move(client), use_shared_db,
-                                          std::move(callback), true);
-      case SharedDBMetadataProto::MIGRATE_TO_SHARED_UNIQUE_TO_BE_DELETED:
-        // Migration transfer was completed, so just try deleting the unique db.
-        return OnMigrationTransferComplete(std::move(unique_db),
-                                           std::move(client), use_shared_db,
-                                           std::move(callback), true);
-      case SharedDBMetadataProto::MIGRATE_TO_UNIQUE_SHARED_TO_BE_DELETED:
-        // Shared db was not deleted in last migration and we want to use shared
-        // db. So, delete stale data, and attempt migration.
-        return DeleteOldDataAndMigrate(std::move(unique_db), std::move(client),
-                                       use_shared_db, std::move(callback));
-    };
-  } else {
-    switch (client->migration_status()) {
-      case SharedDBMetadataProto::MIGRATION_NOT_ATTEMPTED:
-      case SharedDBMetadataProto::MIGRATE_TO_SHARED_SUCCESSFUL:
-        from = client.get();
-        to = unique_db.get();
-        break;
-      case SharedDBMetadataProto::MIGRATE_TO_SHARED_UNIQUE_TO_BE_DELETED:
-        // Unique db was not deleted in last migration and we want to use unique
-        // db. So, delete stale data, and attempt migration.
-        return DeleteOldDataAndMigrate(std::move(unique_db), std::move(client),
-                                       use_shared_db, std::move(callback));
-      case SharedDBMetadataProto::MIGRATE_TO_UNIQUE_SUCCESSFUL:
-        // Shared db was deleted in previous migration, so nothing to do here.
-        return OnMigrationCleanupComplete(std::move(unique_db),
-                                          std::move(client), use_shared_db,
-                                          std::move(callback), true);
-      case SharedDBMetadataProto::MIGRATE_TO_UNIQUE_SHARED_TO_BE_DELETED:
-        // Migration transfer was completed, so just try deleting the shared db.
-        return OnMigrationTransferComplete(std::move(unique_db),
-                                           std::move(client), use_shared_db,
-                                           std::move(callback), true);
-    };
-  }
-
-  // We got access to both the unique DB and a shared DB, meaning we need to
-  // attempt migration and give back the right one.
-  migration_delegate_->DoMigration(
-      from, to,
-      base::BindOnce(&ProtoDatabaseWrapper<T>::OnMigrationTransferComplete,
-                     weak_ptr_factory_->GetWeakPtr(), std::move(unique_db),
-                     std::move(client), use_shared_db, std::move(callback)));
-}
-
-template <typename T>
-void ProtoDatabaseWrapper<T>::DeleteOldDataAndMigrate(
-    std::unique_ptr<ProtoDatabase<T>> unique_db,
-    std::unique_ptr<SharedProtoDatabaseClient<T>> client,
-    bool use_shared_db,
-    Callbacks::InitStatusCallback callback) {
-  ProtoDatabase<T>* to_remove_old_data =
-      use_shared_db ? client.get() : unique_db.get();
-  auto maybe_do_migration =
-      base::BindOnce(&ProtoDatabaseWrapper<T>::MaybeDoMigrationOnDeletingOld,
-                     weak_ptr_factory_->GetWeakPtr(), std::move(unique_db),
-                     std::move(client), std::move(callback), use_shared_db);
-
-  to_remove_old_data->UpdateEntriesWithRemoveFilter(
-      std::make_unique<typename Util::Internal<T>::KeyEntryVector>(),
-      base::BindRepeating([](const std::string& key) { return true; }),
-      std::move(maybe_do_migration));
-}
-
-template <typename T>
-void ProtoDatabaseWrapper<T>::MaybeDoMigrationOnDeletingOld(
-    std::unique_ptr<ProtoDatabase<T>> unique_db,
-    std::unique_ptr<SharedProtoDatabaseClient<T>> client,
-    Callbacks::InitStatusCallback callback,
-    bool use_shared_db,
-    bool delete_success) {
-  if (!delete_success) {
-    // Old data has not been removed from the database we want to use. We also
-    // know that previous attempt of migration failed for same reason. Give up
-    // on this database and use the other.
-    // This update is not necessary since this was the old value. But update to
-    // be clear.
-    client->UpdateClientInitMetadata(
-        use_shared_db
-            ? SharedDBMetadataProto::MIGRATE_TO_UNIQUE_SHARED_TO_BE_DELETED
-            : SharedDBMetadataProto::MIGRATE_TO_SHARED_UNIQUE_TO_BE_DELETED);
-    db_ = use_shared_db ? std::move(unique_db) : std::move(client);
-    RunCallbackOnCallingSequence(
-        base::BindOnce(std::move(callback), Enums::InitStatus::kOK));
-    return;
-  }
-
-  auto from = use_shared_db ? unique_db.get() : client.get();
-  auto to = use_shared_db ? client.get() : unique_db.get();
-  migration_delegate_->DoMigration(
-      from, to,
-      base::BindOnce(&ProtoDatabaseWrapper<T>::OnMigrationTransferComplete,
-                     weak_ptr_factory_->GetWeakPtr(), std::move(unique_db),
-                     std::move(client), use_shared_db, std::move(callback)));
-}
-
-template <typename T>
-void ProtoDatabaseWrapper<T>::OnMigrationTransferComplete(
-    std::unique_ptr<ProtoDatabase<T>> unique_db,
-    std::unique_ptr<SharedProtoDatabaseClient<T>> client,
-    bool use_shared_db,
-    Callbacks::InitStatusCallback callback,
-    bool success) {
-  if (success) {
-    // Call Destroy on the DB we no longer want to use.
-    auto* db_destroy_ptr = use_shared_db ? unique_db.get() : client.get();
-    db_destroy_ptr->Destroy(
-        base::BindOnce(&ProtoDatabaseWrapper<T>::OnMigrationCleanupComplete,
-                       weak_ptr_factory_->GetWeakPtr(), std::move(unique_db),
-                       std::move(client), use_shared_db, std::move(callback)));
-    return;
-  }
-
-  // Failing to transfer the old data means that the requested database to be
-  // used could have some bad data. So, mark them to be deleted before use in
-  // the next runs.
-  client->UpdateClientInitMetadata(
-      use_shared_db
-          ? SharedDBMetadataProto::MIGRATE_TO_UNIQUE_SHARED_TO_BE_DELETED
-          : SharedDBMetadataProto::MIGRATE_TO_SHARED_UNIQUE_TO_BE_DELETED);
-  db_ = use_shared_db ? std::move(unique_db) : std::move(client);
-  RunCallbackOnCallingSequence(
-      base::BindOnce(std::move(callback), Enums::InitStatus::kOK));
-}
-
-template <typename T>
-void ProtoDatabaseWrapper<T>::OnMigrationCleanupComplete(
-    std::unique_ptr<ProtoDatabase<T>> unique_db,
-    std::unique_ptr<SharedProtoDatabaseClient<T>> client,
-    bool use_shared_db,
-    Callbacks::InitStatusCallback callback,
-    bool success) {
-  // We still return true in our callback below because we do have a database as
-  // far as the original caller is concerned. As long as |db_| is assigned, we
-  // return true.
-  if (success) {
-    client->UpdateClientInitMetadata(
-        use_shared_db ? SharedDBMetadataProto::MIGRATE_TO_SHARED_SUCCESSFUL
-                      : SharedDBMetadataProto::MIGRATE_TO_UNIQUE_SUCCESSFUL);
-  } else {
-    client->UpdateClientInitMetadata(
-        use_shared_db
-            ? SharedDBMetadataProto::MIGRATE_TO_SHARED_UNIQUE_TO_BE_DELETED
-            : SharedDBMetadataProto::MIGRATE_TO_UNIQUE_SHARED_TO_BE_DELETED);
-  }
-  // Migration transfer was complete. So, we should use the requested database.
-  db_ = use_shared_db ? std::move(client) : std::move(unique_db);
-  RunCallbackOnCallingSequence(
-      base::BindOnce(std::move(callback), Enums::InitStatus::kOK));
-}
-
-template <typename T>
-void ProtoDatabaseWrapper<T>::UpdateEntries(
-    std::unique_ptr<typename ProtoDatabase<T>::KeyEntryVector> entries_to_save,
-    std::unique_ptr<std::vector<std::string>> keys_to_remove,
-    Callbacks::UpdateCallback callback) {
-  if (!db_) {
-    RunCallbackOnCallingSequence(base::BindOnce(std::move(callback), false));
-    return;
-  }
-
-  db_->UpdateEntries(std::move(entries_to_save), std::move(keys_to_remove),
-                     std::move(callback));
-}
-
-template <typename T>
-void ProtoDatabaseWrapper<T>::UpdateEntriesWithRemoveFilter(
-    std::unique_ptr<typename ProtoDatabase<T>::KeyEntryVector> entries_to_save,
-    const KeyFilter& delete_key_filter,
-    Callbacks::UpdateCallback callback) {
-  if (!db_) {
-    RunCallbackOnCallingSequence(base::BindOnce(std::move(callback), false));
-    return;
-  }
-
-  db_->UpdateEntriesWithRemoveFilter(std::move(entries_to_save),
-                                     delete_key_filter, std::move(callback));
-}
-
-template <typename T>
-void ProtoDatabaseWrapper<T>::UpdateEntriesWithRemoveFilter(
-    std::unique_ptr<typename ProtoDatabase<T>::KeyEntryVector> entries_to_save,
-    const KeyFilter& delete_key_filter,
-    const std::string& target_prefix,
-    Callbacks::UpdateCallback callback) {
-  if (!db_) {
-    RunCallbackOnCallingSequence(base::BindOnce(std::move(callback), false));
-    return;
-  }
-
-  db_->UpdateEntriesWithRemoveFilter(std::move(entries_to_save),
-                                     delete_key_filter, target_prefix,
-                                     std::move(callback));
-}
-
-template <typename T>
-void ProtoDatabaseWrapper<T>::LoadEntries(
-    typename Callbacks::Internal<T>::LoadCallback callback) {
-  if (!db_) {
-    RunCallbackOnCallingSequence(base::BindOnce(
-        std::move(callback), false, std::make_unique<std::vector<T>>()));
-    return;
-  }
-
-  db_->LoadEntries(std::move(callback));
-}
-
-template <typename T>
-void ProtoDatabaseWrapper<T>::LoadEntriesWithFilter(
-    const KeyFilter& filter,
-    typename Callbacks::Internal<T>::LoadCallback callback) {
-  if (!db_) {
-    RunCallbackOnCallingSequence(base::BindOnce(
-        std::move(callback), false, std::make_unique<std::vector<T>>()));
-    return;
-  }
-
-  db_->LoadEntriesWithFilter(filter, std::move(callback));
-}
-
-template <typename T>
-void ProtoDatabaseWrapper<T>::LoadEntriesWithFilter(
-    const KeyFilter& key_filter,
-    const leveldb::ReadOptions& options,
-    const std::string& target_prefix,
-    typename Callbacks::Internal<T>::LoadCallback callback) {
-  if (!db_) {
-    RunCallbackOnCallingSequence(base::BindOnce(
-        std::move(callback), false, std::make_unique<std::vector<T>>()));
-    return;
-  }
-
-  db_->LoadEntriesWithFilter(key_filter, options, target_prefix,
-                             std::move(callback));
-}
-
-template <typename T>
-void ProtoDatabaseWrapper<T>::LoadKeysAndEntries(
-    typename Callbacks::Internal<T>::LoadKeysAndEntriesCallback callback) {
-  if (!db_) {
-    RunCallbackOnCallingSequence(
-        base::BindOnce(std::move(callback), false,
-                       std::make_unique<std::map<std::string, T>>()));
-    return;
-  }
-
-  db_->LoadKeysAndEntries(std::move(callback));
-}
-
-template <typename T>
-void ProtoDatabaseWrapper<T>::LoadKeysAndEntriesWithFilter(
-    const KeyFilter& filter,
-    typename Callbacks::Internal<T>::LoadKeysAndEntriesCallback callback) {
-  if (!db_) {
-    RunCallbackOnCallingSequence(
-        base::BindOnce(std::move(callback), false,
-                       std::make_unique<std::map<std::string, T>>()));
-    return;
-  }
-
-  db_->LoadKeysAndEntriesWithFilter(filter, std::move(callback));
-}
-
-template <typename T>
-void ProtoDatabaseWrapper<T>::LoadKeysAndEntriesWithFilter(
-    const KeyFilter& filter,
-    const leveldb::ReadOptions& options,
-    const std::string& target_prefix,
-    typename Callbacks::Internal<T>::LoadKeysAndEntriesCallback callback) {
-  if (!db_) {
-    RunCallbackOnCallingSequence(
-        base::BindOnce(std::move(callback), false,
-                       std::make_unique<std::map<std::string, T>>()));
-    return;
-  }
-
-  db_->LoadKeysAndEntriesWithFilter(filter, options, target_prefix,
-                                    std::move(callback));
-}
-
-template <typename T>
-void ProtoDatabaseWrapper<T>::LoadKeysAndEntriesInRange(
-    const std::string& start,
-    const std::string& end,
-    typename Callbacks::Internal<T>::LoadKeysAndEntriesCallback callback) {
-  if (!db_) {
-    RunCallbackOnCallingSequence(
-        base::BindOnce(std::move(callback), false,
-                       std::make_unique<std::map<std::string, T>>()));
-    return;
-  }
-
-  db_->LoadKeysAndEntriesInRange(start, end, std::move(callback));
-}
-
-template <typename T>
-void ProtoDatabaseWrapper<T>::LoadKeys(Callbacks::LoadKeysCallback callback) {
-  if (!db_) {
-    RunCallbackOnCallingSequence(
-        base::BindOnce(std::move(callback), false,
-                       std::make_unique<std::vector<std::string>>()));
-    return;
-  }
-
-  db_->LoadKeys(std::move(callback));
-}
-
-template <typename T>
-void ProtoDatabaseWrapper<T>::LoadKeys(const std::string& target_prefix,
-                                       Callbacks::LoadKeysCallback callback) {
-  if (!db_) {
-    RunCallbackOnCallingSequence(
-        base::BindOnce(std::move(callback), false,
-                       std::make_unique<std::vector<std::string>>()));
-    return;
-  }
-
-  db_->LoadKeys(target_prefix, std::move(callback));
-}
-
-template <typename T>
-void ProtoDatabaseWrapper<T>::GetEntry(
-    const std::string& key,
-    typename Callbacks::Internal<T>::GetCallback callback) {
-  if (!db_) {
-    RunCallbackOnCallingSequence(
-        base::BindOnce(std::move(callback), false, std::make_unique<T>()));
-    return;
-  }
-
-  db_->GetEntry(key, std::move(callback));
-}
-
-template <typename T>
-void ProtoDatabaseWrapper<T>::Destroy(Callbacks::DestroyCallback callback) {
-  if (!db_) {
-    RunCallbackOnCallingSequence(base::BindOnce(std::move(callback), false));
-    return;
-  }
-
-  db_->Destroy(std::move(callback));
-}
-
-}  // namespace leveldb_proto
-
-#endif  // COMPONENTS_LEVELDB_PROTO_INTERNAL_PROTO_DATABASE_WRAPPER_H_
diff --git a/components/leveldb_proto/internal/proto_leveldb_wrapper.cc b/components/leveldb_proto/internal/proto_leveldb_wrapper.cc
index 7a817b3..c836431 100644
--- a/components/leveldb_proto/internal/proto_leveldb_wrapper.cc
+++ b/components/leveldb_proto/internal/proto_leveldb_wrapper.cc
@@ -4,10 +4,13 @@
 
 #include "components/leveldb_proto/internal/proto_leveldb_wrapper.h"
 
+#include <string>
+
 #include "base/sequenced_task_runner.h"
 #include "base/task/post_task.h"
 #include "base/task/task_traits.h"
 #include "base/threading/sequenced_task_runner_handle.h"
+#include "components/leveldb_proto/internal/leveldb_database.h"
 #include "components/leveldb_proto/internal/proto_leveldb_wrapper_metrics.h"
 #include "components/leveldb_proto/public/proto_database.h"
 
@@ -47,7 +50,7 @@
     const std::string& client_id,
     Callbacks::LoadKeysCallback callback,
     scoped_refptr<base::SequencedTaskRunner> callback_task_runner) {
-  auto keys = std::make_unique<std::vector<std::string>>();
+  auto keys = std::make_unique<KeyVector>();
   bool success = database->LoadKeys(target_prefix, keys.get());
   ProtoLevelDBWrapperMetrics::RecordLoadKeys(client_id, success);
   callback_task_runner->PostTask(
@@ -69,6 +72,91 @@
                                  base::BindOnce(std::move(callback), success));
 }
 
+void RunLoadCallback(Callbacks::LoadCallback callback,
+                     bool* success,
+                     std::unique_ptr<ValueVector> entries) {
+  std::move(callback).Run(*success, std::move(entries));
+}
+
+void RunLoadKeysAndEntriesCallback(
+    Callbacks::LoadKeysAndEntriesCallback callback,
+    bool* success,
+    std::unique_ptr<KeyValueMap> keys_entries) {
+  std::move(callback).Run(*success, std::move(keys_entries));
+}
+
+void RunGetCallback(Callbacks::GetCallback callback,
+                    const bool* success,
+                    const bool* found,
+                    std::unique_ptr<std::string> entry) {
+  std::move(callback).Run(*success, *found ? std::move(entry) : nullptr);
+}
+
+bool UpdateEntriesFromTaskRunner(
+    LevelDB* database,
+    std::unique_ptr<KeyValueVector> entries_to_save,
+    std::unique_ptr<KeyVector> keys_to_remove,
+    const std::string& client_id) {
+  leveldb::Status status;
+  bool success = database->Save(*entries_to_save, *keys_to_remove, &status);
+  ProtoLevelDBWrapperMetrics::RecordUpdate(client_id, success, status);
+  return success;
+}
+
+bool UpdateEntriesWithRemoveFilterFromTaskRunner(
+    LevelDB* database,
+    std::unique_ptr<KeyValueVector> entries_to_save,
+    const KeyFilter& delete_key_filter,
+    const std::string& target_prefix,
+    const std::string& client_id) {
+  leveldb::Status status;
+  bool success = database->UpdateWithRemoveFilter(
+      *entries_to_save, delete_key_filter, target_prefix, &status);
+  ProtoLevelDBWrapperMetrics::RecordUpdate(client_id, success, status);
+  return success;
+}
+
+void LoadKeysAndEntriesFromTaskRunner(LevelDB* database,
+                                      const KeyFilter& while_callback,
+                                      const KeyFilter& filter,
+                                      const leveldb::ReadOptions& options,
+                                      const std::string& target_prefix,
+                                      const std::string& client_id,
+                                      bool* success,
+                                      KeyValueMap* keys_entries) {
+  DCHECK(success);
+  DCHECK(keys_entries);
+  keys_entries->clear();
+
+  *success = database->LoadKeysAndEntriesWhile(filter, keys_entries, options,
+                                               target_prefix, while_callback);
+
+  ProtoLevelDBWrapperMetrics::RecordLoadKeysAndEntries(client_id, success);
+}
+
+void LoadEntriesFromTaskRunner(LevelDB* database,
+                               const KeyFilter& filter,
+                               const leveldb::ReadOptions& options,
+                               const std::string& target_prefix,
+                               const std::string& client_id,
+                               bool* success,
+                               ValueVector* entries) {
+  *success = database->LoadWithFilter(filter, entries, options, target_prefix);
+
+  ProtoLevelDBWrapperMetrics::RecordLoadEntries(client_id, success);
+}
+
+void GetEntryFromTaskRunner(LevelDB* database,
+                            const std::string& key,
+                            const std::string& client_id,
+                            bool* success,
+                            bool* found,
+                            std::string* entry) {
+  leveldb::Status status;
+  *success = database->Get(key, found, entry, &status);
+
+  ProtoLevelDBWrapperMetrics::RecordGet(client_id, *success, *found, status);
+}
 }  // namespace
 
 ProtoLevelDBWrapper::ProtoLevelDBWrapper(
@@ -108,6 +196,150 @@
       std::move(callback));
 }
 
+void ProtoLevelDBWrapper::UpdateEntries(
+    std::unique_ptr<KeyValueVector> entries_to_save,
+    std::unique_ptr<KeyVector> keys_to_remove,
+    typename Callbacks::UpdateCallback callback) {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  base::PostTaskAndReplyWithResult(
+      task_runner_.get(), FROM_HERE,
+      base::BindOnce(UpdateEntriesFromTaskRunner, base::Unretained(db_),
+                     std::move(entries_to_save), std::move(keys_to_remove),
+                     metrics_id_),
+      std::move(callback));
+}
+
+void ProtoLevelDBWrapper::UpdateEntriesWithRemoveFilter(
+    std::unique_ptr<KeyValueVector> entries_to_save,
+    const KeyFilter& delete_key_filter,
+    Callbacks::UpdateCallback callback) {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  UpdateEntriesWithRemoveFilter(std::move(entries_to_save), delete_key_filter,
+                                std::string(), std::move(callback));
+}
+
+void ProtoLevelDBWrapper::UpdateEntriesWithRemoveFilter(
+    std::unique_ptr<KeyValueVector> entries_to_save,
+    const KeyFilter& delete_key_filter,
+    const std::string& target_prefix,
+    Callbacks::UpdateCallback callback) {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  base::PostTaskAndReplyWithResult(
+      task_runner_.get(), FROM_HERE,
+      base::BindOnce(UpdateEntriesWithRemoveFilterFromTaskRunner,
+                     base::Unretained(db_), std::move(entries_to_save),
+                     delete_key_filter, target_prefix, metrics_id_),
+      std::move(callback));
+}
+
+void ProtoLevelDBWrapper::LoadEntries(Callbacks::LoadCallback callback) {
+  LoadEntriesWithFilter(KeyFilter(), std::move(callback));
+}
+
+void ProtoLevelDBWrapper::LoadEntriesWithFilter(
+    const KeyFilter& key_filter,
+    Callbacks::LoadCallback callback) {
+  LoadEntriesWithFilter(key_filter, leveldb::ReadOptions(), std::string(),
+                        std::move(callback));
+}
+
+void ProtoLevelDBWrapper::LoadEntriesWithFilter(
+    const KeyFilter& key_filter,
+    const leveldb::ReadOptions& options,
+    const std::string& target_prefix,
+    Callbacks::LoadCallback callback) {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  bool* success = new bool(false);
+  auto entries = std::make_unique<ValueVector>();
+  // Get this pointer before |entries| is std::move()'d so we can use it below.
+  auto* entries_ptr = entries.get();
+
+  task_runner_->PostTaskAndReply(
+      FROM_HERE,
+      base::BindOnce(LoadEntriesFromTaskRunner, base::Unretained(db_),
+                     key_filter, options, target_prefix, metrics_id_, success,
+                     entries_ptr),
+      base::BindOnce(RunLoadCallback, std::move(callback), base::Owned(success),
+                     std::move(entries)));
+}
+
+void ProtoLevelDBWrapper::LoadKeysAndEntries(
+    Callbacks::LoadKeysAndEntriesCallback callback) {
+  LoadKeysAndEntriesWithFilter(KeyFilter(), std::move(callback));
+}
+
+void ProtoLevelDBWrapper::LoadKeysAndEntriesWithFilter(
+    const KeyFilter& key_filter,
+    Callbacks::LoadKeysAndEntriesCallback callback) {
+  LoadKeysAndEntriesWithFilter(key_filter, leveldb::ReadOptions(),
+                               std::string(), std::move(callback));
+}
+
+void ProtoLevelDBWrapper::LoadKeysAndEntriesWithFilter(
+    const KeyFilter& key_filter,
+    const leveldb::ReadOptions& options,
+    const std::string& target_prefix,
+    Callbacks::LoadKeysAndEntriesCallback callback) {
+  LoadKeysAndEntriesWhile(
+      base::BindRepeating(
+          [](const std::string& prefix, const std::string& key) {
+            return base::StartsWith(key, prefix, base::CompareCase::SENSITIVE);
+          },
+          target_prefix),
+      key_filter, options, target_prefix, std::move(callback));
+}
+
+void ProtoLevelDBWrapper::LoadKeysAndEntriesInRange(
+    const std::string& start,
+    const std::string& end,
+    Callbacks::LoadKeysAndEntriesCallback callback) {
+  LoadKeysAndEntriesWhile(
+      base::BindRepeating(
+          [](const std::string& range_end, const std::string& key) {
+            return key.compare(range_end) <= 0;
+          },
+          end),
+      KeyFilter(), leveldb::ReadOptions(), start, std::move(callback));
+}
+
+void ProtoLevelDBWrapper::LoadKeysAndEntriesWhile(
+    const KeyFilter& while_callback,
+    const KeyFilter& filter,
+    const leveldb::ReadOptions& options,
+    const std::string& target_prefix,
+    Callbacks::LoadKeysAndEntriesCallback callback) {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  bool* success = new bool(false);
+  auto keys_entries = std::make_unique<KeyValueMap>();
+  // Get this pointer before |keys_entries| is std::move()'d so we can use it
+  // below.
+  auto* keys_entries_ptr = keys_entries.get();
+  task_runner_->PostTaskAndReply(
+      FROM_HERE,
+      base::BindOnce(LoadKeysAndEntriesFromTaskRunner, base::Unretained(db_),
+                     while_callback, filter, options, target_prefix,
+                     metrics_id_, success, keys_entries_ptr),
+      base::BindOnce(RunLoadKeysAndEntriesCallback, std::move(callback),
+                     base::Owned(success), std::move(keys_entries)));
+}
+
+void ProtoLevelDBWrapper::GetEntry(const std::string& key,
+                                   Callbacks::GetCallback callback) {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  bool* success = new bool(false);
+  bool* found = new bool(false);
+  auto entry = std::make_unique<std::string>();
+  // Get this pointer before |entry| is std::move()'d so we can use it below.
+  auto* entry_ptr = entry.get();
+
+  task_runner_->PostTaskAndReply(
+      FROM_HERE,
+      base::BindOnce(GetEntryFromTaskRunner, base::Unretained(db_), key,
+                     metrics_id_, success, found, entry_ptr),
+      base::BindOnce(RunGetCallback, std::move(callback), base::Owned(success),
+                     base::Owned(found), std::move(entry)));
+}
+
 void ProtoLevelDBWrapper::LoadKeys(
     typename Callbacks::LoadKeysCallback callback) {
   LoadKeys(std::string(), std::move(callback));
diff --git a/components/leveldb_proto/internal/proto_leveldb_wrapper.h b/components/leveldb_proto/internal/proto_leveldb_wrapper.h
index 307c0e60..a53f6ed 100644
--- a/components/leveldb_proto/internal/proto_leveldb_wrapper.h
+++ b/components/leveldb_proto/internal/proto_leveldb_wrapper.h
@@ -4,6 +4,7 @@
 #ifndef COMPONENTS_LEVELDB_PROTO_INTERNAL_PROTO_LEVELDB_WRAPPER_H_
 #define COMPONENTS_LEVELDB_PROTO_INTERNAL_PROTO_LEVELDB_WRAPPER_H_
 
+#include <map>
 #include <memory>
 #include <string>
 #include <utility>
@@ -17,7 +18,6 @@
 #include "base/task_runner_util.h"
 #include "base/threading/sequenced_task_runner_handle.h"
 #include "base/threading/thread_checker.h"
-#include "components/leveldb_proto/internal/leveldb_database.h"
 #include "components/leveldb_proto/internal/proto_leveldb_wrapper_metrics.h"
 #include "components/leveldb_proto/public/proto_database.h"
 #include "third_party/leveldatabase/env_chromium.h"
@@ -28,8 +28,12 @@
 
 namespace leveldb_proto {
 
-using KeyValueVector = base::StringPairs;
+class LevelDB;
+
+using KeyValueVector = std::vector<std::pair<std::string, std::string>>;
+using KeyValueMap = std::map<std::string, std::string>;
 using KeyVector = std::vector<std::string>;
+using ValueVector = std::vector<std::string>;
 
 // When the ProtoDatabase instance is deleted, in-progress asynchronous
 // operations will be completed and the corresponding callbacks will be called.
@@ -46,79 +50,59 @@
 
   virtual ~ProtoLevelDBWrapper();
 
-  template <typename T>
-  void UpdateEntries(std::unique_ptr<typename Util::Internal<T>::KeyEntryVector>
-                         entries_to_save,
+  void UpdateEntries(std::unique_ptr<KeyValueVector> entries_to_save,
                      std::unique_ptr<KeyVector> keys_to_remove,
                      Callbacks::UpdateCallback callback);
 
-  template <typename T>
   void UpdateEntriesWithRemoveFilter(
-      std::unique_ptr<typename Util::Internal<T>::KeyEntryVector>
-          entries_to_save,
+      std::unique_ptr<KeyValueVector> entries_to_save,
       const KeyFilter& delete_key_filter,
       Callbacks::UpdateCallback callback);
 
-  template <typename T>
   void UpdateEntriesWithRemoveFilter(
-      std::unique_ptr<typename Util::Internal<T>::KeyEntryVector>
-          entries_to_save,
+      std::unique_ptr<KeyValueVector> entries_to_save,
       const KeyFilter& delete_key_filter,
       const std::string& target_prefix,
       Callbacks::UpdateCallback callback);
 
-  template <typename T>
-  void LoadEntries(typename Callbacks::Internal<T>::LoadCallback callback);
+  void LoadEntries(Callbacks::LoadCallback callback);
 
-  template <typename T>
-  void LoadEntriesWithFilter(
-      const KeyFilter& key_filter,
-      typename Callbacks::Internal<T>::LoadCallback callback);
+  void LoadEntriesWithFilter(const KeyFilter& key_filter,
+                             Callbacks::LoadCallback callback);
 
-  template <typename T>
-  void LoadEntriesWithFilter(
-      const KeyFilter& key_filter,
-      const leveldb::ReadOptions& options,
-      const std::string& target_prefix,
-      typename Callbacks::Internal<T>::LoadCallback callback);
+  void LoadEntriesWithFilter(const KeyFilter& key_filter,
+                             const leveldb::ReadOptions& options,
+                             const std::string& target_prefix,
+                             Callbacks::LoadCallback callback);
 
-  template <typename T>
-  void LoadKeysAndEntries(
-      typename Callbacks::Internal<T>::LoadKeysAndEntriesCallback callback);
+  void LoadKeysAndEntries(Callbacks::LoadKeysAndEntriesCallback callback);
 
-  template <typename T>
   void LoadKeysAndEntriesWithFilter(
       const KeyFilter& filter,
-      typename Callbacks::Internal<T>::LoadKeysAndEntriesCallback callback);
+      Callbacks::LoadKeysAndEntriesCallback callback);
 
-  template <typename T>
   void LoadKeysAndEntriesWithFilter(
       const KeyFilter& filter,
       const leveldb::ReadOptions& options,
       const std::string& target_prefix,
-      typename Callbacks::Internal<T>::LoadKeysAndEntriesCallback callback);
+      Callbacks::LoadKeysAndEntriesCallback callback);
 
-  template <typename T>
-  void LoadKeysAndEntriesWhile(
-      const KeyFilter& while_callback,
-      const KeyFilter& filter,
-      const leveldb::ReadOptions& options,
-      const std::string& target_prefix,
-      typename Callbacks::Internal<T>::LoadKeysAndEntriesCallback callback);
+  void LoadKeysAndEntriesWhile(const KeyFilter& while_callback,
+                               const KeyFilter& filter,
+                               const leveldb::ReadOptions& options,
+                               const std::string& target_prefix,
+                               Callbacks::LoadKeysAndEntriesCallback callback);
 
-  template <typename T>
   void LoadKeysAndEntriesInRange(
       const std::string& start,
       const std::string& end,
-      typename Callbacks::Internal<T>::LoadKeysAndEntriesCallback callback);
+      Callbacks::LoadKeysAndEntriesCallback callback);
 
   void LoadKeys(Callbacks::LoadKeysCallback callback);
   void LoadKeys(const std::string& target_prefix,
                 Callbacks::LoadKeysCallback callback);
 
-  template <typename T>
-  void GetEntry(const std::string& key,
-                typename Callbacks::Internal<T>::GetCallback callback);
+  void GetEntry(const std::string& key, Callbacks::GetCallback callback);
 
   void RemoveKeys(const KeyFilter& filter,
                   const std::string& target_prefix,
@@ -159,307 +143,6 @@
   DISALLOW_COPY_AND_ASSIGN(ProtoLevelDBWrapper);
 };
 
-namespace {
-
-template <typename T>
-void RunLoadCallback(typename Callbacks::Internal<T>::LoadCallback callback,
-                     bool* success,
-                     std::unique_ptr<std::vector<T>> entries) {
-  std::move(callback).Run(*success, std::move(entries));
-}
-
-template <typename T>
-void RunLoadKeysAndEntriesCallback(
-    typename Callbacks::Internal<T>::LoadKeysAndEntriesCallback callback,
-    bool* success,
-    std::unique_ptr<std::map<std::string, T>> keys_entries) {
-  std::move(callback).Run(*success, std::move(keys_entries));
-}
-
-template <typename T>
-void RunGetCallback(typename Callbacks::Internal<T>::GetCallback callback,
-                    const bool* success,
-                    const bool* found,
-                    std::unique_ptr<T> entry) {
-  std::move(callback).Run(*success, *found ? std::move(entry) : nullptr);
-}
-
-template <typename T>
-bool UpdateEntriesFromTaskRunner(
-    LevelDB* database,
-    std::unique_ptr<typename Util::Internal<T>::KeyEntryVector> entries_to_save,
-    std::unique_ptr<KeyVector> keys_to_remove,
-    const std::string& client_id) {
-  // Serialize the values from Proto to string before passing on to database.
-  KeyValueVector pairs_to_save;
-  for (const auto& pair : *entries_to_save) {
-    pairs_to_save.push_back(
-        std::make_pair(pair.first, pair.second.SerializeAsString()));
-  }
-
-  leveldb::Status status;
-  bool success = database->Save(pairs_to_save, *keys_to_remove, &status);
-  ProtoLevelDBWrapperMetrics::RecordUpdate(client_id, success, status);
-  return success;
-}
-
-template <typename T>
-bool UpdateEntriesWithRemoveFilterFromTaskRunner(
-    LevelDB* database,
-    std::unique_ptr<typename Util::Internal<T>::KeyEntryVector> entries_to_save,
-    const KeyFilter& delete_key_filter,
-    const std::string& target_prefix,
-    const std::string& client_id) {
-  // Serialize the values from Proto to string before passing on to database.
-  KeyValueVector pairs_to_save;
-  for (const auto& pair : *entries_to_save) {
-    pairs_to_save.push_back(
-        std::make_pair(pair.first, pair.second.SerializeAsString()));
-  }
-
-  leveldb::Status status;
-  bool success = database->UpdateWithRemoveFilter(
-      pairs_to_save, delete_key_filter, target_prefix, &status);
-  ProtoLevelDBWrapperMetrics::RecordUpdate(client_id, success, status);
-  return success;
-}
-
-template <typename T>
-void LoadKeysAndEntriesFromTaskRunner(LevelDB* database,
-                                      const KeyFilter& while_callback,
-                                      const KeyFilter& filter,
-                                      const leveldb::ReadOptions& options,
-                                      const std::string& target_prefix,
-                                      const std::string& client_id,
-                                      bool* success,
-                                      std::map<std::string, T>* keys_entries) {
-  DCHECK(success);
-  DCHECK(keys_entries);
-  keys_entries->clear();
-
-  std::map<std::string, std::string> loaded_entries;
-  *success = database->LoadKeysAndEntriesWhile(filter, &loaded_entries, options,
-                                               target_prefix, while_callback);
-
-  for (const auto& pair : loaded_entries) {
-    T entry;
-    if (!entry.ParseFromString(pair.second)) {
-      DLOG(WARNING) << "Unable to parse leveldb_proto entry";
-      // TODO(cjhopman): Decide what to do about un-parseable entries.
-    }
-
-    keys_entries->insert(std::make_pair(pair.first, entry));
-  }
-
-  ProtoLevelDBWrapperMetrics::RecordLoadKeysAndEntries(client_id, success);
-}
-
-template <typename T>
-void LoadEntriesFromTaskRunner(LevelDB* database,
-                               const KeyFilter& filter,
-                               const leveldb::ReadOptions& options,
-                               const std::string& target_prefix,
-                               const std::string& client_id,
-                               bool* success,
-                               std::vector<T>* entries) {
-  std::vector<std::string> loaded_entries;
-  *success =
-      database->LoadWithFilter(filter, &loaded_entries, options, target_prefix);
-
-  for (const auto& serialized_entry : loaded_entries) {
-    T entry;
-    if (!entry.ParseFromString(serialized_entry)) {
-      DLOG(WARNING) << "Unable to parse leveldb_proto entry";
-      // TODO(cjhopman): Decide what to do about un-parseable entries.
-    }
-
-    entries->push_back(entry);
-  }
-
-  ProtoLevelDBWrapperMetrics::RecordLoadEntries(client_id, success);
-}
-
-template <typename T>
-void GetEntryFromTaskRunner(LevelDB* database,
-                            const std::string& key,
-                            const std::string& client_id,
-                            bool* success,
-                            bool* found,
-                            T* entry) {
-  std::string serialized_entry;
-  leveldb::Status status;
-  *success = database->Get(key, found, &serialized_entry, &status);
-
-  if (*found && !entry->ParseFromString(serialized_entry)) {
-    *found = false;
-    DLOG(WARNING) << "Unable to parse leveldb_proto entry";
-  }
-
-  ProtoLevelDBWrapperMetrics::RecordGet(client_id, *success, *found, status);
-}
-
-}  // namespace
-
-template <typename T>
-void ProtoLevelDBWrapper::UpdateEntries(
-    std::unique_ptr<typename Util::Internal<T>::KeyEntryVector> entries_to_save,
-    std::unique_ptr<KeyVector> keys_to_remove,
-    typename Callbacks::UpdateCallback callback) {
-  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-  base::PostTaskAndReplyWithResult(
-      task_runner_.get(), FROM_HERE,
-      base::BindOnce(UpdateEntriesFromTaskRunner<T>, base::Unretained(db_),
-                     std::move(entries_to_save), std::move(keys_to_remove),
-                     metrics_id_),
-      std::move(callback));
-}
-
-template <typename T>
-void ProtoLevelDBWrapper::UpdateEntriesWithRemoveFilter(
-    std::unique_ptr<typename Util::Internal<T>::KeyEntryVector> entries_to_save,
-    const KeyFilter& delete_key_filter,
-    Callbacks::UpdateCallback callback) {
-  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-  UpdateEntriesWithRemoveFilter<T>(std::move(entries_to_save),
-                                   delete_key_filter, std::string(),
-                                   std::move(callback));
-}
-
-template <typename T>
-void ProtoLevelDBWrapper::UpdateEntriesWithRemoveFilter(
-    std::unique_ptr<typename Util::Internal<T>::KeyEntryVector> entries_to_save,
-    const KeyFilter& delete_key_filter,
-    const std::string& target_prefix,
-    Callbacks::UpdateCallback callback) {
-  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-  base::PostTaskAndReplyWithResult(
-      task_runner_.get(), FROM_HERE,
-      base::BindOnce(UpdateEntriesWithRemoveFilterFromTaskRunner<T>,
-                     base::Unretained(db_), std::move(entries_to_save),
-                     delete_key_filter, target_prefix, metrics_id_),
-      std::move(callback));
-}
-
-template <typename T>
-void ProtoLevelDBWrapper::LoadEntries(
-    typename Callbacks::Internal<T>::LoadCallback callback) {
-  LoadEntriesWithFilter<T>(KeyFilter(), std::move(callback));
-}
-
-template <typename T>
-void ProtoLevelDBWrapper::LoadEntriesWithFilter(
-    const KeyFilter& key_filter,
-    typename Callbacks::Internal<T>::LoadCallback callback) {
-  LoadEntriesWithFilter<T>(key_filter, leveldb::ReadOptions(), std::string(),
-                           std::move(callback));
-}
-
-template <typename T>
-void ProtoLevelDBWrapper::LoadEntriesWithFilter(
-    const KeyFilter& key_filter,
-    const leveldb::ReadOptions& options,
-    const std::string& target_prefix,
-    typename Callbacks::Internal<T>::LoadCallback callback) {
-  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-  bool* success = new bool(false);
-  auto entries = std::make_unique<std::vector<T>>();
-  // Get this pointer before |entries| is std::move()'d so we can use it below.
-  auto* entries_ptr = entries.get();
-
-  task_runner_->PostTaskAndReply(
-      FROM_HERE,
-      base::BindOnce(LoadEntriesFromTaskRunner<T>, base::Unretained(db_),
-                     key_filter, options, target_prefix, metrics_id_, success,
-                     entries_ptr),
-      base::BindOnce(RunLoadCallback<T>, std::move(callback),
-                     base::Owned(success), std::move(entries)));
-}
-
-template <typename T>
-void ProtoLevelDBWrapper::LoadKeysAndEntries(
-    typename Callbacks::Internal<T>::LoadKeysAndEntriesCallback callback) {
-  LoadKeysAndEntriesWithFilter<T>(KeyFilter(), std::move(callback));
-}
-
-template <typename T>
-void ProtoLevelDBWrapper::LoadKeysAndEntriesWithFilter(
-    const KeyFilter& key_filter,
-    typename Callbacks::Internal<T>::LoadKeysAndEntriesCallback callback) {
-  LoadKeysAndEntriesWithFilter<T>(key_filter, leveldb::ReadOptions(),
-                                  std::string(), std::move(callback));
-}
-
-template <typename T>
-void ProtoLevelDBWrapper::LoadKeysAndEntriesWithFilter(
-    const KeyFilter& key_filter,
-    const leveldb::ReadOptions& options,
-    const std::string& target_prefix,
-    typename Callbacks::Internal<T>::LoadKeysAndEntriesCallback callback) {
-  LoadKeysAndEntriesWhile<T>(
-      base::BindRepeating(
-          [](const std::string& prefix, const std::string& key) {
-            return base::StartsWith(key, prefix, base::CompareCase::SENSITIVE);
-          },
-          target_prefix),
-      key_filter, options, target_prefix, std::move(callback));
-}
-
-template <typename T>
-void ProtoLevelDBWrapper::LoadKeysAndEntriesInRange(
-    const std::string& start,
-    const std::string& end,
-    typename Callbacks::Internal<T>::LoadKeysAndEntriesCallback callback) {
-  LoadKeysAndEntriesWhile<T>(
-      base::BindRepeating(
-          [](const std::string& range_end, const std::string& key) {
-            return key.compare(range_end) <= 0;
-          },
-          end),
-      KeyFilter(), leveldb::ReadOptions(), start, std::move(callback));
-}
-
-template <typename T>
-void ProtoLevelDBWrapper::LoadKeysAndEntriesWhile(
-    const KeyFilter& while_callback,
-    const KeyFilter& filter,
-    const leveldb::ReadOptions& options,
-    const std::string& target_prefix,
-    typename Callbacks::Internal<T>::LoadKeysAndEntriesCallback callback) {
-  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-  bool* success = new bool(false);
-  auto keys_entries = std::make_unique<std::map<std::string, T>>();
-  // Get this pointer before |keys_entries| is std::move()'d so we can use it
-  // below.
-  auto* keys_entries_ptr = keys_entries.get();
-  task_runner_->PostTaskAndReply(
-      FROM_HERE,
-      base::BindOnce(LoadKeysAndEntriesFromTaskRunner<T>, base::Unretained(db_),
-                     while_callback, filter, options, target_prefix,
-                     metrics_id_, success, keys_entries_ptr),
-      base::BindOnce(RunLoadKeysAndEntriesCallback<T>, std::move(callback),
-                     base::Owned(success), std::move(keys_entries)));
-}
-
-template <typename T>
-void ProtoLevelDBWrapper::GetEntry(
-    const std::string& key,
-    typename Callbacks::Internal<T>::GetCallback callback) {
-  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-  bool* success = new bool(false);
-  bool* found = new bool(false);
-  auto entry = std::make_unique<T>();
-  // Get this pointer before |entry| is std::move()'d so we can use it below.
-  auto* entry_ptr = entry.get();
-
-  task_runner_->PostTaskAndReply(
-      FROM_HERE,
-      base::BindOnce(GetEntryFromTaskRunner<T>, base::Unretained(db_), key,
-                     metrics_id_, success, found, entry_ptr),
-      base::BindOnce(RunGetCallback<T>, std::move(callback),
-                     base::Owned(success), base::Owned(found),
-                     std::move(entry)));
-}
-
 }  // namespace leveldb_proto
 
 #endif  // COMPONENTS_LEVELDB_PROTO_INTERNAL_PROTO_LEVELDB_WRAPPER_H_
diff --git a/components/leveldb_proto/internal/shared_proto_database.cc b/components/leveldb_proto/internal/shared_proto_database.cc
index 6221100..aabb6e1 100644
--- a/components/leveldb_proto/internal/shared_proto_database.cc
+++ b/components/leveldb_proto/internal/shared_proto_database.cc
@@ -4,14 +4,15 @@
 
 #include "components/leveldb_proto/internal/shared_proto_database.h"
 
-#include "base/sequence_checker.h"
+#include <memory>
+#include <utility>
+
+#include "base/bind_helpers.h"
 #include "base/sequenced_task_runner.h"
-#include "base/synchronization/lock.h"
 #include "base/task/post_task.h"
 #include "components/leveldb_proto/internal/leveldb_database.h"
-#include "components/leveldb_proto/internal/proto/shared_db_metadata.pb.h"
 #include "components/leveldb_proto/internal/proto_leveldb_wrapper.h"
-#include "components/leveldb_proto/public/proto_database.h"
+#include "components/leveldb_proto/public/proto_database_provider.h"
 
 namespace leveldb_proto {
 
@@ -57,9 +58,9 @@
       db_dir_(db_dir),
       db_(std::make_unique<LevelDB>(client_db_id.c_str())),
       db_wrapper_(std::make_unique<ProtoLevelDBWrapper>(task_runner_)),
-      metadata_db_(std::make_unique<LevelDB>(kMetadataDatabaseName)),
       metadata_db_wrapper_(
-          std::make_unique<ProtoLevelDBWrapper>(task_runner_)) {
+          ProtoDatabaseProvider::CreateUniqueDB<SharedDBMetadataProto>(
+              task_runner_)) {
   DETACH_FROM_SEQUENCE(on_task_runner_);
 }
 
@@ -103,7 +104,7 @@
   update_entries->emplace_back(
       std::make_pair(std::string(client_db_id), write_proto));
 
-  metadata_db_wrapper_->UpdateEntries<SharedDBMetadataProto>(
+  metadata_db_wrapper_->UpdateEntries(
       std::move(update_entries), std::make_unique<std::vector<std::string>>(),
       std::move(callback));
 }
@@ -116,7 +117,7 @@
   // DB, so making this call directly here without PostTasking is safe. In
   // addition, GetEntry uses PostTaskAndReply so the callback will be triggered
   // on the calling sequence.
-  metadata_db_wrapper_->GetEntry<SharedDBMetadataProto>(
+  metadata_db_wrapper_->GetEntry(
       std::string(client_db_id),
       base::BindOnce(&SharedProtoDatabase::OnGetClientMetadata, this,
                      client_db_id, std::move(callback),
@@ -245,9 +246,9 @@
 
   base::FilePath metadata_path =
       db_dir_.Append(base::FilePath(kMetadataDatabasePath));
-  metadata_db_wrapper_->InitWithDatabase(
-      metadata_db_.get(), metadata_path, CreateSimpleOptions(),
-      true /* destroy_on_corruption */,
+  // TODO: figure out destroy on corruption param
+  metadata_db_wrapper_->Init(
+      kMetadataDatabaseName, metadata_path, CreateSimpleOptions(),
       base::BindOnce(&SharedProtoDatabase::OnMetadataInitComplete, this,
                      create_shared_db_if_missing, attempt, corruption));
 }
@@ -256,17 +257,11 @@
     bool create_shared_db_if_missing,
     int attempt,
     bool corruption,
-    Enums::InitStatus metadata_init_status) {
+    bool success) {
+  //    Enums::InitStatus metadata_init_status) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(on_task_runner_);
 
-  if (metadata_init_status == Enums::InitStatus::kCorrupt) {
-    // Retry InitMetaDatabase to create the metadata database from scratch.
-    InitMetadataDatabase(create_shared_db_if_missing, ++attempt,
-                         true /* corruption */);
-    return;
-  }
-
-  if (metadata_init_status != Enums::InitStatus::kOK) {
+  if (!success) {
     init_state_ = InitState::kFailure;
     init_status_ = Enums::InitStatus::kError;
     ProcessInitRequests(init_status_);
@@ -276,7 +271,7 @@
   // Read or initialize the corruption count for this DB. If |corruption| is
   // true, we initialize the counter to 1 right away so that all DBs are forced
   // to treat the shared database as corrupt, we can't know for sure anymore.
-  metadata_db_wrapper_->GetEntry<SharedDBMetadataProto>(
+  metadata_db_wrapper_->GetEntry(
       std::string(kGlobalMetadataKey),
       base::BindOnce(&SharedProtoDatabase::OnGetGlobalMetadata, this,
                      create_shared_db_if_missing, corruption));
@@ -395,14 +390,79 @@
   write_proto.CheckTypeAndMergeFrom(*metadata_);
   update_entries->emplace_back(
       std::make_pair(std::string(kGlobalMetadataKey), write_proto));
-  metadata_db_wrapper_->UpdateEntries<SharedDBMetadataProto>(
+  metadata_db_wrapper_->UpdateEntries(
       std::move(update_entries), std::make_unique<std::vector<std::string>>(),
       std::move(callback));
 }
 
 SharedProtoDatabase::~SharedProtoDatabase() {
   task_runner_->DeleteSoon(FROM_HERE, std::move(db_));
-  task_runner_->DeleteSoon(FROM_HERE, std::move(metadata_db_));
+  task_runner_->DeleteSoon(FROM_HERE, std::move(metadata_db_wrapper_));
+}
+
+void GetClientInitCallback(
+    base::OnceCallback<void(std::unique_ptr<SharedProtoDatabaseClient>)>
+        callback,
+    std::unique_ptr<SharedProtoDatabaseClient> client,
+    Enums::InitStatus status,
+    SharedDBMetadataProto::MigrationStatus migration_status) {
+  // |current_task_runner| is valid because Init already takes the current
+  // TaskRunner as a parameter and uses that to trigger this callback when it's
+  // finished.
+  DCHECK(base::SequencedTaskRunnerHandle::IsSet());
+  auto current_task_runner = base::SequencedTaskRunnerHandle::Get();
+  if (status != Enums::InitStatus::kOK && status != Enums::InitStatus::kCorrupt)
+    client.reset();
+  // Set migration status of client. The metadata database was already updated.
+  if (client)
+    client->set_migration_status(migration_status);
+  current_task_runner->PostTask(
+      FROM_HERE, base::BindOnce(std::move(callback), std::move(client)));
+}
+
+void SharedProtoDatabase::GetClientAsync(
+    const std::string& client_namespace,
+    const std::string& type_prefix,
+    bool create_if_missing,
+    base::OnceCallback<void(std::unique_ptr<SharedProtoDatabaseClient>)>
+        callback) {
+  auto client = GetClientInternal(client_namespace, type_prefix);
+  DCHECK(base::SequencedTaskRunnerHandle::IsSet());
+  auto current_task_runner = base::SequencedTaskRunnerHandle::Get();
+  SharedProtoDatabaseClient* client_ptr = client.get();
+  task_runner_->PostTask(
+      FROM_HERE,
+      base::BindOnce(&SharedProtoDatabase::Init, this, create_if_missing,
+                     client_ptr->client_db_id(),
+                     base::BindOnce(&GetClientInitCallback, std::move(callback),
+                                    std::move(client)),
+                     std::move(current_task_runner)));
+}
+
+// TODO(thildebr): Need to pass the client name into this call as well, and use
+// it with the pending requests too so we can clean up the database.
+std::unique_ptr<SharedProtoDatabaseClient>
+SharedProtoDatabase::GetClientForTesting(const std::string& client_namespace,
+                                         const std::string& type_prefix,
+                                         bool create_if_missing,
+                                         SharedClientInitCallback callback) {
+  DCHECK(base::SequencedTaskRunnerHandle::IsSet());
+  auto current_task_runner = base::SequencedTaskRunnerHandle::Get();
+  auto client = GetClientInternal(client_namespace, type_prefix);
+  task_runner_->PostTask(
+      FROM_HERE,
+      base::BindOnce(&SharedProtoDatabase::Init, this, create_if_missing,
+                     client->client_db_id(), std::move(callback),
+                     std::move(current_task_runner)));
+  return client;
+}
+
+std::unique_ptr<SharedProtoDatabaseClient>
+SharedProtoDatabase::GetClientInternal(const std::string& client_namespace,
+                                       const std::string& type_prefix) {
+  return base::WrapUnique(new SharedProtoDatabaseClient(
+      std::make_unique<ProtoLevelDBWrapper>(task_runner_, db_.get()),
+      client_namespace, type_prefix, this));
 }
 
 LevelDB* SharedProtoDatabase::GetLevelDBForTesting() const {
diff --git a/components/leveldb_proto/internal/shared_proto_database.h b/components/leveldb_proto/internal/shared_proto_database.h
index 2d3eb07..1470e5b 100644
--- a/components/leveldb_proto/internal/shared_proto_database.h
+++ b/components/leveldb_proto/internal/shared_proto_database.h
@@ -5,25 +5,20 @@
 #ifndef COMPONENTS_LEVELDB_PROTO_INTERNAL_SHARED_PROTO_DATABASE_H_
 #define COMPONENTS_LEVELDB_PROTO_INTERNAL_SHARED_PROTO_DATABASE_H_
 
-#include <queue>
+#include <memory>
+#include <string>
 
 #include "base/bind.h"
 #include "base/bind_helpers.h"
+#include "base/containers/queue.h"
 #include "base/memory/ref_counted.h"
 #include "base/sequence_checker.h"
-#include "base/sequenced_task_runner.h"
-#include "base/task/post_task.h"
-#include "base/task_runner_util.h"
-#include "components/leveldb_proto/internal/leveldb_database.h"
 #include "components/leveldb_proto/internal/proto/shared_db_metadata.pb.h"
-#include "components/leveldb_proto/internal/proto_leveldb_wrapper.h"
 #include "components/leveldb_proto/internal/shared_proto_database_client.h"
 #include "components/leveldb_proto/public/proto_database.h"
 
 namespace leveldb_proto {
 
-class SharedDBMetadataProto;
-
 // Controls a single LevelDB database to be used by many clients, and provides
 // a way to get SharedProtoDatabaseClients that allow shared access to the
 // underlying single database.
@@ -36,8 +31,7 @@
 
   // Always returns a SharedProtoDatabaseClient pointer, but that should ONLY
   // be used if the callback returns success.
-  template <typename T>
-  std::unique_ptr<SharedProtoDatabaseClient<T>> GetClientForTesting(
+  std::unique_ptr<SharedProtoDatabaseClient> GetClientForTesting(
       const std::string& client_namespace,
       const std::string& type_prefix,
       bool create_if_missing,
@@ -45,12 +39,11 @@
 
   // A version of GetClient that returns the client in a callback instead of
   // giving back a client instance immediately.
-  template <typename T>
   void GetClientAsync(
       const std::string& client_namespace,
       const std::string& type_prefix,
       bool create_if_missing,
-      base::OnceCallback<void(std::unique_ptr<SharedProtoDatabaseClient<T>>)>
+      base::OnceCallback<void(std::unique_ptr<SharedProtoDatabaseClient>)>
           callback);
 
   void GetDatabaseInitStatusAsync(const std::string& client_db_id,
@@ -65,7 +58,7 @@
   friend class base::RefCountedThreadSafe<SharedProtoDatabase>;
   friend class ProtoDatabaseProvider;
 
-  friend class ProtoDatabaseWrapperTest;
+  friend class ProtoDatabaseImplTest;
   friend class SharedProtoDatabaseTest;
   friend class SharedProtoDatabaseClientTest;
 
@@ -100,8 +93,7 @@
 
   void ProcessInitRequests(Enums::InitStatus status);
 
-  template <typename T>
-  std::unique_ptr<SharedProtoDatabaseClient<T>> GetClientInternal(
+  std::unique_ptr<SharedProtoDatabaseClient> GetClientInternal(
       const std::string& client_namespace,
       const std::string& type_prefix);
 
@@ -124,7 +116,7 @@
   void OnMetadataInitComplete(bool create_shared_db_if_missing,
                               int attempt,
                               bool corruption,
-                              Enums::InitStatus status);
+                              bool success);
   void OnGetGlobalMetadata(bool create_shared_db_if_missing,
                            bool corruption,
                            bool success,
@@ -170,88 +162,18 @@
   std::unique_ptr<LevelDB> db_;
   std::unique_ptr<ProtoLevelDBWrapper> db_wrapper_;
 
-  std::unique_ptr<LevelDB> metadata_db_;
-  std::unique_ptr<ProtoLevelDBWrapper> metadata_db_wrapper_;
+  std::unique_ptr<ProtoDatabase<SharedDBMetadataProto>> metadata_db_wrapper_;
   std::unique_ptr<SharedDBMetadataProto> metadata_;
 
   // Used to return to the Init callback in the case of an error, so we can
   // report corruptions.
   Enums::InitStatus init_status_ = Enums::InitStatus::kNotInitialized;
 
-  std::queue<std::unique_ptr<InitRequest>> outstanding_init_requests_;
+  base::queue<std::unique_ptr<InitRequest>> outstanding_init_requests_;
 
   DISALLOW_COPY_AND_ASSIGN(SharedProtoDatabase);
 };
 
-template <typename T>
-void GetClientInitCallback(
-    base::OnceCallback<void(std::unique_ptr<SharedProtoDatabaseClient<T>>)>
-        callback,
-    std::unique_ptr<SharedProtoDatabaseClient<T>> client,
-    Enums::InitStatus status,
-    SharedDBMetadataProto::MigrationStatus migration_status) {
-  // |current_task_runner| is valid because Init already takes the current
-  // TaskRunner as a parameter and uses that to trigger this callback when it's
-  // finished.
-  DCHECK(base::SequencedTaskRunnerHandle::IsSet());
-  auto current_task_runner = base::SequencedTaskRunnerHandle::Get();
-  if (status != Enums::InitStatus::kOK && status != Enums::InitStatus::kCorrupt)
-    client.reset();
-  // Set migration status of client. The metadata database was already updated.
-  if (client)
-    client->set_migration_status(migration_status);
-  current_task_runner->PostTask(
-      FROM_HERE, base::BindOnce(std::move(callback), std::move(client)));
-}
-
-template <typename T>
-void SharedProtoDatabase::GetClientAsync(
-    const std::string& client_namespace,
-    const std::string& type_prefix,
-    bool create_if_missing,
-    base::OnceCallback<void(std::unique_ptr<SharedProtoDatabaseClient<T>>)>
-        callback) {
-  auto client = GetClientInternal<T>(client_namespace, type_prefix);
-  DCHECK(base::SequencedTaskRunnerHandle::IsSet());
-  auto current_task_runner = base::SequencedTaskRunnerHandle::Get();
-  SharedProtoDatabaseClient<T>* client_ptr = client.get();
-  task_runner_->PostTask(
-      FROM_HERE,
-      base::BindOnce(&SharedProtoDatabase::Init, this, create_if_missing,
-                     client_ptr->client_db_id(),
-                     base::BindOnce(&GetClientInitCallback<T>,
-                                    std::move(callback), std::move(client)),
-                     std::move(current_task_runner)));
-}
-
-// TODO(thildebr): Need to pass the client name into this call as well, and use
-// it with the pending requests too so we can clean up the database.
-template <typename T>
-std::unique_ptr<SharedProtoDatabaseClient<T>>
-SharedProtoDatabase::GetClientForTesting(const std::string& client_namespace,
-                                         const std::string& type_prefix,
-                                         bool create_if_missing,
-                                         SharedClientInitCallback callback) {
-  DCHECK(base::SequencedTaskRunnerHandle::IsSet());
-  auto current_task_runner = base::SequencedTaskRunnerHandle::Get();
-  auto client = GetClientInternal<T>(client_namespace, type_prefix);
-  task_runner_->PostTask(
-      FROM_HERE,
-      base::BindOnce(&SharedProtoDatabase::Init, this, create_if_missing,
-                     client->client_db_id(), std::move(callback),
-                     std::move(current_task_runner)));
-  return client;
-}
-
-template <typename T>
-std::unique_ptr<SharedProtoDatabaseClient<T>>
-SharedProtoDatabase::GetClientInternal(const std::string& client_namespace,
-                                       const std::string& type_prefix) {
-  return base::WrapUnique(new SharedProtoDatabaseClient<T>(
-      std::make_unique<ProtoLevelDBWrapper>(task_runner_, db_.get()),
-      client_namespace, type_prefix, this));
-}
-
 }  // namespace leveldb_proto
 
 #endif  // COMPONENTS_LEVELDB_PROTO_INTERNAL_SHARED_PROTO_DATABASE_H_
diff --git a/components/leveldb_proto/internal/shared_proto_database_client.cc b/components/leveldb_proto/internal/shared_proto_database_client.cc
index 7b126718..56f6441 100644
--- a/components/leveldb_proto/internal/shared_proto_database_client.cc
+++ b/components/leveldb_proto/internal/shared_proto_database_client.cc
@@ -4,7 +4,11 @@
 
 #include "components/leveldb_proto/internal/shared_proto_database_client.h"
 
+#include <memory>
+#include <utility>
+
 #include "base/strings/strcat.h"
+#include "base/strings/string_util.h"
 #include "components/leveldb_proto/internal/proto_leveldb_wrapper.h"
 #include "components/leveldb_proto/internal/shared_proto_database.h"
 #include "components/leveldb_proto/public/shared_proto_database_client_list.h"
@@ -44,9 +48,8 @@
              : key;
 }
 
-std::unique_ptr<std::vector<std::string>> PrefixStrings(
-    std::unique_ptr<std::vector<std::string>> strings,
-    const std::string& prefix) {
+std::unique_ptr<KeyVector> PrefixStrings(std::unique_ptr<KeyVector> strings,
+                                         const std::string& prefix) {
   for (auto& str : *strings)
     str.assign(base::StrCat({prefix, str}));
   return strings;
@@ -107,4 +110,211 @@
   g_obsolete_client_list_for_testing = list;
 }
 
+SharedProtoDatabaseClient::SharedProtoDatabaseClient(
+    std::unique_ptr<ProtoLevelDBWrapper> db_wrapper,
+    const std::string& client_namespace,
+    const std::string& type_prefix,
+    const scoped_refptr<SharedProtoDatabase>& parent_db)
+    : UniqueProtoDatabase(std::move(db_wrapper)),
+      prefix_(base::JoinString({client_namespace, type_prefix, std::string()},
+                               "_")),
+      parent_db_(parent_db),
+      weak_ptr_factory_(this) {
+  DETACH_FROM_SEQUENCE(sequence_checker_);
+}
+
+SharedProtoDatabaseClient::~SharedProtoDatabaseClient() {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+}
+
+void SharedProtoDatabaseClient::Init(const std::string& client_uma_name,
+                                     Callbacks::InitStatusCallback callback) {
+  SetMetricsId(client_uma_name);
+  GetSharedDatabaseInitStatusAsync(prefix_, parent_db_, std::move(callback));
+}
+
+void SharedProtoDatabaseClient::InitWithDatabase(
+    LevelDB* database,
+    const base::FilePath& database_dir,
+    const leveldb_env::Options& options,
+    bool destroy_on_corruption,
+    Callbacks::InitStatusCallback callback) {
+  NOTREACHED();
+}
+
+void SharedProtoDatabaseClient::UpdateEntries(
+    std::unique_ptr<KeyValueVector> entries_to_save,
+    std::unique_ptr<KeyVector> keys_to_remove,
+    Callbacks::UpdateCallback callback) {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  UniqueProtoDatabase::UpdateEntries(
+      PrefixKeyEntryVector(std::move(entries_to_save), prefix_),
+      PrefixStrings(std::move(keys_to_remove), prefix_), std::move(callback));
+}
+
+void SharedProtoDatabaseClient::UpdateEntriesWithRemoveFilter(
+    std::unique_ptr<KeyValueVector> entries_to_save,
+    const KeyFilter& delete_key_filter,
+    Callbacks::UpdateCallback callback) {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  UpdateEntriesWithRemoveFilter(std::move(entries_to_save), delete_key_filter,
+                                std::string(), std::move(callback));
+}
+
+void SharedProtoDatabaseClient::UpdateEntriesWithRemoveFilter(
+    std::unique_ptr<KeyValueVector> entries_to_save,
+    const KeyFilter& delete_key_filter,
+    const std::string& target_prefix,
+    Callbacks::UpdateCallback callback) {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  UniqueProtoDatabase::UpdateEntriesWithRemoveFilter(
+      PrefixKeyEntryVector(std::move(entries_to_save), prefix_),
+      base::BindRepeating(&KeyFilterStripPrefix, delete_key_filter, prefix_),
+      prefix_ + target_prefix, std::move(callback));
+}
+
+void SharedProtoDatabaseClient::LoadEntries(Callbacks::LoadCallback callback) {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  LoadEntriesWithFilter(KeyFilter(), std::move(callback));
+}
+
+void SharedProtoDatabaseClient::LoadEntriesWithFilter(
+    const KeyFilter& filter,
+    Callbacks::LoadCallback callback) {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  LoadEntriesWithFilter(filter, leveldb::ReadOptions(), std::string(),
+                        std::move(callback));
+}
+
+void SharedProtoDatabaseClient::LoadEntriesWithFilter(
+    const KeyFilter& filter,
+    const leveldb::ReadOptions& options,
+    const std::string& target_prefix,
+    Callbacks::LoadCallback callback) {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  UniqueProtoDatabase::LoadEntriesWithFilter(
+      base::BindRepeating(&KeyFilterStripPrefix, filter, prefix_), options,
+      prefix_ + target_prefix, std::move(callback));
+}
+
+void SharedProtoDatabaseClient::LoadKeys(Callbacks::LoadKeysCallback callback) {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  LoadKeys(std::string(), std::move(callback));
+}
+
+void SharedProtoDatabaseClient::LoadKeys(const std::string& target_prefix,
+                                         Callbacks::LoadKeysCallback callback) {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  UniqueProtoDatabase::LoadKeys(
+      prefix_ + target_prefix,
+      base::BindOnce(&SharedProtoDatabaseClient::StripPrefixLoadKeysCallback,
+                     std::move(callback), prefix_));
+}
+
+void SharedProtoDatabaseClient::LoadKeysAndEntries(
+    Callbacks::LoadKeysAndEntriesCallback callback) {
+  LoadKeysAndEntriesWithFilter(KeyFilter(), std::move(callback));
+}
+
+void SharedProtoDatabaseClient::LoadKeysAndEntriesWithFilter(
+    const KeyFilter& filter,
+    Callbacks::LoadKeysAndEntriesCallback callback) {
+  LoadKeysAndEntriesWithFilter(filter, leveldb::ReadOptions(), std::string(),
+                               std::move(callback));
+}
+
+void SharedProtoDatabaseClient::LoadKeysAndEntriesWithFilter(
+    const KeyFilter& filter,
+    const leveldb::ReadOptions& options,
+    const std::string& target_prefix,
+    Callbacks::LoadKeysAndEntriesCallback callback) {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  UniqueProtoDatabase::LoadKeysAndEntriesWithFilter(
+      base::BindRepeating(&KeyFilterStripPrefix, filter, prefix_), options,
+      prefix_ + target_prefix,
+      base::BindOnce(
+          &SharedProtoDatabaseClient::StripPrefixLoadKeysAndEntriesCallback,
+          std::move(callback), prefix_));
+}
+
+void SharedProtoDatabaseClient::LoadKeysAndEntriesInRange(
+    const std::string& start,
+    const std::string& end,
+    Callbacks::LoadKeysAndEntriesCallback callback) {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  UniqueProtoDatabase::LoadKeysAndEntriesInRange(
+      prefix_ + start, prefix_ + end,
+      base::BindOnce(
+          &SharedProtoDatabaseClient::StripPrefixLoadKeysAndEntriesCallback,
+          std::move(callback), prefix_));
+}
+
+void SharedProtoDatabaseClient::GetEntry(const std::string& key,
+                                         Callbacks::GetCallback callback) {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  UniqueProtoDatabase::GetEntry(prefix_ + key, std::move(callback));
+}
+
+void SharedProtoDatabaseClient::Destroy(Callbacks::DestroyCallback callback) {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  UpdateEntriesWithRemoveFilter(
+      std::make_unique<KeyValueVector>(),
+      base::BindRepeating([](const std::string& key) { return true; }),
+      base::BindOnce([](Callbacks::DestroyCallback callback,
+                        bool success) { std::move(callback).Run(success); },
+                     std::move(callback)));
+}
+
+void SharedProtoDatabaseClient::UpdateClientInitMetadata(
+    SharedDBMetadataProto::MigrationStatus migration_status) {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  migration_status_ = migration_status;
+  // Tell the SharedProtoDatabase that we've seen the corruption state so it's
+  // safe to update its records for this client.
+  UpdateClientMetadataAsync(parent_db_, prefix_, migration_status_,
+                            base::BindOnce([](bool success) {
+                              // TODO(thildebr): Should we do anything special
+                              // here? If the shared DB can't update the
+                              // client's corruption counter to match its own,
+                              // then the client will think it's corrupt on the
+                              // next Init as well.
+                            }));
+}
+
+// static
+void SharedProtoDatabaseClient::StripPrefixLoadKeysCallback(
+    Callbacks::LoadKeysCallback callback,
+    const std::string& prefix,
+    bool success,
+    std::unique_ptr<leveldb_proto::KeyVector> keys) {
+  auto stripped_keys = std::make_unique<leveldb_proto::KeyVector>();
+  for (auto& key : *keys)
+    stripped_keys->emplace_back(StripPrefix(key, prefix));
+  std::move(callback).Run(success, std::move(stripped_keys));
+}
+
+// static
+void SharedProtoDatabaseClient::StripPrefixLoadKeysAndEntriesCallback(
+    Callbacks::LoadKeysAndEntriesCallback callback,
+    const std::string& prefix,
+    bool success,
+    std::unique_ptr<KeyValueMap> keys_entries) {
+  auto stripped_keys_map = std::make_unique<KeyValueMap>();
+  for (auto& key_entry : *keys_entries) {
+    stripped_keys_map->insert(
+        std::make_pair(StripPrefix(key_entry.first, prefix), key_entry.second));
+  }
+  std::move(callback).Run(success, std::move(stripped_keys_map));
+}
+
+// static
+std::unique_ptr<KeyValueVector> SharedProtoDatabaseClient::PrefixKeyEntryVector(
+    std::unique_ptr<KeyValueVector> kev,
+    const std::string& prefix) {
+  for (auto& key_entry_pair : *kev) {
+    key_entry_pair.first = base::StrCat({prefix, key_entry_pair.first});
+  }
+  return kev;
+}
+
 }  // namespace leveldb_proto
diff --git a/components/leveldb_proto/internal/shared_proto_database_client.h b/components/leveldb_proto/internal/shared_proto_database_client.h
index 3aaa93cd..b0f93d1 100644
--- a/components/leveldb_proto/internal/shared_proto_database_client.h
+++ b/components/leveldb_proto/internal/shared_proto_database_client.h
@@ -5,36 +5,33 @@
 #ifndef COMPONENTS_LEVELDB_PROTO_INTERNAL_SHARED_PROTO_DATABASE_CLIENT_H_
 #define COMPONENTS_LEVELDB_PROTO_INTERNAL_SHARED_PROTO_DATABASE_CLIENT_H_
 
+#include <memory>
+#include <string>
+
 #include "base/bind.h"
 #include "base/sequence_checker.h"
-#include "base/sequenced_task_runner.h"
-#include "base/strings/strcat.h"
-#include "base/strings/string_util.h"
-#include "base/threading/sequenced_task_runner_handle.h"
 #include "components/leveldb_proto/internal/leveldb_database.h"
 #include "components/leveldb_proto/internal/proto/shared_db_metadata.pb.h"
-#include "components/leveldb_proto/internal/proto_leveldb_wrapper.h"
 #include "components/leveldb_proto/internal/unique_proto_database.h"
 
 namespace leveldb_proto {
 
 class SharedProtoDatabase;
 
+// TODO: Move all these as static or member functions in the class.
 using ClientCorruptCallback = base::OnceCallback<void(bool)>;
 using SharedClientInitCallback =
     base::OnceCallback<void(Enums::InitStatus,
                             SharedDBMetadataProto::MigrationStatus)>;
 
 std::string StripPrefix(const std::string& key, const std::string& prefix);
-std::unique_ptr<std::vector<std::string>> PrefixStrings(
-    std::unique_ptr<std::vector<std::string>> strings,
-    const std::string& prefix);
+
+std::unique_ptr<KeyVector> PrefixStrings(std::unique_ptr<KeyVector> strings,
+                                         const std::string& prefix);
+
 bool KeyFilterStripPrefix(const KeyFilter& key_filter,
                           const std::string& prefix,
                           const std::string& key);
-std::unique_ptr<std::vector<std::string>> PrefixStrings(
-    std::unique_ptr<std::vector<std::string>> strings,
-    const std::string& prefix);
 
 void GetSharedDatabaseInitStatusAsync(
     const std::string& client_db_id,
@@ -62,77 +59,67 @@
 // An implementation of ProtoDatabase<T> that uses a shared LevelDB and task
 // runner.
 // Should be created, destroyed, and used on the same sequenced task runner.
-template <typename T>
-class SharedProtoDatabaseClient : public ProtoDatabase<T> {
+class SharedProtoDatabaseClient : public UniqueProtoDatabase {
  public:
-  virtual ~SharedProtoDatabaseClient();
+  ~SharedProtoDatabaseClient() override;
 
   void Init(const std::string& client_uma_name,
             Callbacks::InitStatusCallback callback) override;
 
-  void Init(const char* client_uma_name,
-            const base::FilePath& database_dir,
-            const leveldb_env::Options& options,
-            Callbacks::InitCallback callback) override;
+  void InitWithDatabase(LevelDB* database,
+                        const base::FilePath& database_dir,
+                        const leveldb_env::Options& options,
+                        bool destroy_on_corruption,
+                        Callbacks::InitStatusCallback callback) override;
 
   // Overrides for prepending namespace and type prefix to all operations on the
   // shared database.
-  void UpdateEntries(std::unique_ptr<typename ProtoDatabase<T>::KeyEntryVector>
-                         entries_to_save,
-                     std::unique_ptr<std::vector<std::string>> keys_to_remove,
+  void UpdateEntries(std::unique_ptr<KeyValueVector> entries_to_save,
+                     std::unique_ptr<KeyVector> keys_to_remove,
                      Callbacks::UpdateCallback callback) override;
   void UpdateEntriesWithRemoveFilter(
-      std::unique_ptr<typename ProtoDatabase<T>::KeyEntryVector>
-          entries_to_save,
+      std::unique_ptr<KeyValueVector> entries_to_save,
       const KeyFilter& delete_key_filter,
       Callbacks::UpdateCallback callback) override;
   void UpdateEntriesWithRemoveFilter(
-      std::unique_ptr<typename ProtoDatabase<T>::KeyEntryVector>
-          entries_to_save,
+      std::unique_ptr<KeyValueVector> entries_to_save,
       const KeyFilter& delete_key_filter,
       const std::string& target_prefix,
       Callbacks::UpdateCallback callback) override;
 
-  void LoadEntries(
-      typename Callbacks::Internal<T>::LoadCallback callback) override;
-  void LoadEntriesWithFilter(
-      const KeyFilter& filter,
-      typename Callbacks::Internal<T>::LoadCallback callback) override;
-  void LoadEntriesWithFilter(
-      const KeyFilter& key_filter,
-      const leveldb::ReadOptions& options,
-      const std::string& target_prefix,
-      typename Callbacks::Internal<T>::LoadCallback callback) override;
+  void LoadEntries(Callbacks::LoadCallback callback) override;
+  void LoadEntriesWithFilter(const KeyFilter& filter,
+                             Callbacks::LoadCallback callback) override;
+  void LoadEntriesWithFilter(const KeyFilter& key_filter,
+                             const leveldb::ReadOptions& options,
+                             const std::string& target_prefix,
+                             Callbacks::LoadCallback callback) override;
 
   void LoadKeys(Callbacks::LoadKeysCallback callback) override;
   void LoadKeys(const std::string& target_prefix,
                 Callbacks::LoadKeysCallback callback) override;
 
   void LoadKeysAndEntries(
-      typename Callbacks::Internal<T>::LoadKeysAndEntriesCallback callback)
-      override;
+      Callbacks::LoadKeysAndEntriesCallback callback) override;
   void LoadKeysAndEntriesWithFilter(
       const KeyFilter& filter,
-      typename Callbacks::Internal<T>::LoadKeysAndEntriesCallback callback)
-      override;
+      Callbacks::LoadKeysAndEntriesCallback callback) override;
   void LoadKeysAndEntriesWithFilter(
       const KeyFilter& filter,
       const leveldb::ReadOptions& options,
       const std::string& target_prefix,
-      typename Callbacks::Internal<T>::LoadKeysAndEntriesCallback callback)
-      override;
+      Callbacks::LoadKeysAndEntriesCallback callback) override;
   void LoadKeysAndEntriesInRange(
       const std::string& start,
       const std::string& end,
-      typename Callbacks::Internal<T>::LoadKeysAndEntriesCallback callback)
-      override;
+      Callbacks::LoadKeysAndEntriesCallback callback) override;
 
   void GetEntry(const std::string& key,
-                typename Callbacks::Internal<T>::GetCallback callback) override;
+                Callbacks::GetCallback callback) override;
 
   void Destroy(Callbacks::DestroyCallback callback) override;
 
-  typename Callbacks::InitCallback GetInitCallback() const;
+  Callbacks::InitCallback GetInitCallback() const;
 
   const std::string& client_db_id() const { return prefix_; }
 
@@ -165,14 +152,13 @@
       bool success,
       std::unique_ptr<leveldb_proto::KeyVector> keys);
   static void StripPrefixLoadKeysAndEntriesCallback(
-      typename Callbacks::Internal<T>::LoadKeysAndEntriesCallback callback,
+      Callbacks::LoadKeysAndEntriesCallback callback,
       const std::string& prefix,
       bool success,
-      std::unique_ptr<std::map<std::string, T>> keys_entries);
+      std::unique_ptr<KeyValueMap> keys_entries);
 
-  static std::unique_ptr<typename Util::Internal<T>::KeyEntryVector>
-  PrefixKeyEntryVector(
-      std::unique_ptr<typename Util::Internal<T>::KeyEntryVector> kev,
+  static std::unique_ptr<KeyValueVector> PrefixKeyEntryVector(
+      std::unique_ptr<KeyValueVector> kev,
       const std::string& prefix);
 
   SEQUENCE_CHECKER(sequence_checker_);
@@ -184,251 +170,16 @@
   SharedDBMetadataProto::MigrationStatus migration_status_ =
       SharedDBMetadataProto::MIGRATION_NOT_ATTEMPTED;
 
-  std::string prefix_;
-  std::string client_name_;
+  const std::string prefix_;
+  const std::string client_name_;
 
   scoped_refptr<SharedProtoDatabase> parent_db_;
-  std::unique_ptr<UniqueProtoDatabase<T>> unique_db_;
 
-  base::WeakPtrFactory<SharedProtoDatabaseClient<T>> weak_ptr_factory_;
+  base::WeakPtrFactory<SharedProtoDatabaseClient> weak_ptr_factory_;
 
   DISALLOW_COPY_AND_ASSIGN(SharedProtoDatabaseClient);
 };
 
-template <typename T>
-SharedProtoDatabaseClient<T>::SharedProtoDatabaseClient(
-    std::unique_ptr<ProtoLevelDBWrapper> db_wrapper,
-    const std::string& client_namespace,
-    const std::string& type_prefix,
-    const scoped_refptr<SharedProtoDatabase>& parent_db)
-    : prefix_(base::JoinString({client_namespace, type_prefix, std::string()},
-                               "_")),
-      parent_db_(parent_db),
-      unique_db_(
-          std::make_unique<UniqueProtoDatabase<T>>(std::move(db_wrapper))),
-      weak_ptr_factory_(this) {
-  DETACH_FROM_SEQUENCE(sequence_checker_);
-}
-
-template <typename T>
-SharedProtoDatabaseClient<T>::~SharedProtoDatabaseClient() {
-  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-}
-
-template <typename T>
-void SharedProtoDatabaseClient<T>::Init(
-    const std::string& client_uma_name,
-    Callbacks::InitStatusCallback callback) {
-  unique_db_->SetMetricsId(client_uma_name);
-  GetSharedDatabaseInitStatusAsync(prefix_, parent_db_, std::move(callback));
-}
-
-template <typename T>
-void SharedProtoDatabaseClient<T>::Init(const char* client_uma_name,
-                                        const base::FilePath& database_dir,
-                                        const leveldb_env::Options& options,
-                                        Callbacks::InitCallback callback) {
-  NOTREACHED();
-}
-
-template <typename T>
-void SharedProtoDatabaseClient<T>::UpdateEntries(
-    std::unique_ptr<typename ProtoDatabase<T>::KeyEntryVector> entries_to_save,
-    std::unique_ptr<std::vector<std::string>> keys_to_remove,
-    Callbacks::UpdateCallback callback) {
-  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-  unique_db_->UpdateEntries(
-      PrefixKeyEntryVector(std::move(entries_to_save), prefix_),
-      PrefixStrings(std::move(keys_to_remove), prefix_), std::move(callback));
-}
-
-template <typename T>
-void SharedProtoDatabaseClient<T>::UpdateEntriesWithRemoveFilter(
-    std::unique_ptr<typename ProtoDatabase<T>::KeyEntryVector> entries_to_save,
-    const KeyFilter& delete_key_filter,
-    Callbacks::UpdateCallback callback) {
-  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-  UpdateEntriesWithRemoveFilter(std::move(entries_to_save), delete_key_filter,
-                                std::string(), std::move(callback));
-}
-
-template <typename T>
-void SharedProtoDatabaseClient<T>::UpdateEntriesWithRemoveFilter(
-    std::unique_ptr<typename ProtoDatabase<T>::KeyEntryVector> entries_to_save,
-    const KeyFilter& delete_key_filter,
-    const std::string& target_prefix,
-    Callbacks::UpdateCallback callback) {
-  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-  unique_db_->UpdateEntriesWithRemoveFilter(
-      PrefixKeyEntryVector(std::move(entries_to_save), prefix_),
-      base::BindRepeating(&KeyFilterStripPrefix, delete_key_filter, prefix_),
-      prefix_ + target_prefix, std::move(callback));
-}
-
-template <typename T>
-void SharedProtoDatabaseClient<T>::LoadEntries(
-    typename Callbacks::Internal<T>::LoadCallback callback) {
-  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-  LoadEntriesWithFilter(KeyFilter(), std::move(callback));
-}
-
-template <typename T>
-void SharedProtoDatabaseClient<T>::LoadEntriesWithFilter(
-    const KeyFilter& filter,
-    typename Callbacks::Internal<T>::LoadCallback callback) {
-  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-  LoadEntriesWithFilter(filter, leveldb::ReadOptions(), std::string(),
-                        std::move(callback));
-}
-
-template <typename T>
-void SharedProtoDatabaseClient<T>::LoadEntriesWithFilter(
-    const KeyFilter& filter,
-    const leveldb::ReadOptions& options,
-    const std::string& target_prefix,
-    typename Callbacks::Internal<T>::LoadCallback callback) {
-  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-  unique_db_->LoadEntriesWithFilter(
-      base::BindRepeating(&KeyFilterStripPrefix, filter, prefix_), options,
-      prefix_ + target_prefix, std::move(callback));
-}
-
-template <typename T>
-void SharedProtoDatabaseClient<T>::LoadKeys(
-    Callbacks::LoadKeysCallback callback) {
-  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-  LoadKeys(std::string(), std::move(callback));
-}
-
-template <typename T>
-void SharedProtoDatabaseClient<T>::LoadKeys(
-    const std::string& target_prefix,
-    Callbacks::LoadKeysCallback callback) {
-  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-  unique_db_->LoadKeys(
-      prefix_ + target_prefix,
-      base::BindOnce(&SharedProtoDatabaseClient<T>::StripPrefixLoadKeysCallback,
-                     std::move(callback), prefix_));
-}
-
-template <typename T>
-void SharedProtoDatabaseClient<T>::LoadKeysAndEntries(
-    typename Callbacks::Internal<T>::LoadKeysAndEntriesCallback callback) {
-  LoadKeysAndEntriesWithFilter(KeyFilter(), std::move(callback));
-}
-
-template <typename T>
-void SharedProtoDatabaseClient<T>::LoadKeysAndEntriesWithFilter(
-    const KeyFilter& filter,
-    typename Callbacks::Internal<T>::LoadKeysAndEntriesCallback callback) {
-  LoadKeysAndEntriesWithFilter(filter, leveldb::ReadOptions(), std::string(),
-                               std::move(callback));
-}
-
-template <typename T>
-void SharedProtoDatabaseClient<T>::LoadKeysAndEntriesWithFilter(
-    const KeyFilter& filter,
-    const leveldb::ReadOptions& options,
-    const std::string& target_prefix,
-    typename Callbacks::Internal<T>::LoadKeysAndEntriesCallback callback) {
-  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-  unique_db_->LoadKeysAndEntriesWithFilter(
-      filter, options, prefix_ + target_prefix,
-      base::BindOnce(
-          &SharedProtoDatabaseClient<T>::StripPrefixLoadKeysAndEntriesCallback,
-          std::move(callback), prefix_));
-}
-
-template <typename T>
-void SharedProtoDatabaseClient<T>::LoadKeysAndEntriesInRange(
-    const std::string& start,
-    const std::string& end,
-    typename Callbacks::Internal<T>::LoadKeysAndEntriesCallback callback) {
-  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-  unique_db_->LoadKeysAndEntriesInRange(
-      prefix_ + start, prefix_ + end,
-      base::BindOnce(
-          &SharedProtoDatabaseClient<T>::StripPrefixLoadKeysAndEntriesCallback,
-          std::move(callback), prefix_));
-}
-
-template <typename T>
-void SharedProtoDatabaseClient<T>::GetEntry(
-    const std::string& key,
-    typename Callbacks::Internal<T>::GetCallback callback) {
-  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-  unique_db_->GetEntry(prefix_ + key, std::move(callback));
-}
-
-template <typename T>
-void SharedProtoDatabaseClient<T>::Destroy(
-    Callbacks::DestroyCallback callback) {
-  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-  UpdateEntriesWithRemoveFilter(
-      std::make_unique<typename Util::Internal<T>::KeyEntryVector>(),
-      base::BindRepeating([](const std::string& key) { return true; }),
-      base::BindOnce([](Callbacks::DestroyCallback callback,
-                        bool success) { std::move(callback).Run(success); },
-                     std::move(callback)));
-}
-
-template <typename T>
-void SharedProtoDatabaseClient<T>::UpdateClientInitMetadata(
-    SharedDBMetadataProto::MigrationStatus migration_status) {
-  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-  migration_status_ = migration_status;
-  // Tell the SharedProtoDatabase that we've seen the corruption state so it's
-  // safe to update its records for this client.
-  UpdateClientMetadataAsync(parent_db_, prefix_, migration_status_,
-                            base::BindOnce([](bool success) {
-                              // TODO(thildebr): Should we do anything special
-                              // here? If the shared DB can't update the
-                              // client's corruption counter to match its own,
-                              // then the client will think it's corrupt on the
-                              // next Init as well.
-                            }));
-}
-
-// static
-template <typename T>
-void SharedProtoDatabaseClient<T>::StripPrefixLoadKeysCallback(
-    Callbacks::LoadKeysCallback callback,
-    const std::string& prefix,
-    bool success,
-    std::unique_ptr<leveldb_proto::KeyVector> keys) {
-  auto stripped_keys = std::make_unique<leveldb_proto::KeyVector>();
-  for (auto& key : *keys)
-    stripped_keys->emplace_back(StripPrefix(key, prefix));
-  std::move(callback).Run(success, std::move(stripped_keys));
-}
-
-// static
-template <typename T>
-void SharedProtoDatabaseClient<T>::StripPrefixLoadKeysAndEntriesCallback(
-    typename Callbacks::Internal<T>::LoadKeysAndEntriesCallback callback,
-    const std::string& prefix,
-    bool success,
-    std::unique_ptr<std::map<std::string, T>> keys_entries) {
-  auto stripped_keys_map = std::make_unique<std::map<std::string, T>>();
-  for (auto& key_entry : *keys_entries) {
-    stripped_keys_map->insert(
-        std::make_pair(StripPrefix(key_entry.first, prefix), key_entry.second));
-  }
-  std::move(callback).Run(success, std::move(stripped_keys_map));
-}
-
-// static
-template <typename T>
-std::unique_ptr<typename Util::Internal<T>::KeyEntryVector>
-SharedProtoDatabaseClient<T>::PrefixKeyEntryVector(
-    std::unique_ptr<typename Util::Internal<T>::KeyEntryVector> kev,
-    const std::string& prefix) {
-  for (auto& key_entry_pair : *kev) {
-    key_entry_pair.first = base::StrCat({prefix, key_entry_pair.first});
-  }
-  return kev;
-}
-
 }  // namespace leveldb_proto
 
 #endif  // COMPONENTS_LEVELDB_PROTO_INTERNAL_SHARED_PROTO_DATABASE_CLIENT_H_
diff --git a/components/leveldb_proto/internal/shared_proto_database_client_unittest.cc b/components/leveldb_proto/internal/shared_proto_database_client_unittest.cc
index 34ccf26..d1ed799c 100644
--- a/components/leveldb_proto/internal/shared_proto_database_client_unittest.cc
+++ b/components/leveldb_proto/internal/shared_proto_database_client_unittest.cc
@@ -4,13 +4,15 @@
 
 #include "components/leveldb_proto/internal/shared_proto_database_client.h"
 
+#include <set>
+#include <string>
+
 #include "base/bind.h"
 #include "base/bind_helpers.h"
 #include "base/files/scoped_temp_dir.h"
 #include "base/message_loop/message_loop.h"
 #include "base/strings/string_util.h"
 #include "base/test/scoped_task_environment.h"
-#include "base/threading/thread.h"
 #include "components/leveldb_proto/internal/proto_leveldb_wrapper.h"
 #include "components/leveldb_proto/internal/shared_proto_database.h"
 #include "components/leveldb_proto/testing/proto/test_db.pb.h"
@@ -47,15 +49,14 @@
 
   LevelDB* GetLevelDB() const { return db_->GetLevelDBForTesting(); }
 
-  template <typename T>
-  std::unique_ptr<SharedProtoDatabaseClient<T>> GetClient(
+  std::unique_ptr<SharedProtoDatabaseClient> GetClient(
       const std::string& client_namespace,
       const std::string& type_prefix,
       bool create_if_missing,
       Callbacks::InitStatusCallback callback,
       SharedDBMetadataProto::MigrationStatus expected_migration_status =
           SharedDBMetadataProto::MIGRATION_NOT_ATTEMPTED) {
-    return db_->GetClientForTesting<T>(
+    return db_->GetClientForTesting(
         client_namespace, type_prefix, create_if_missing,
         base::BindOnce(
             [](SharedDBMetadataProto::MigrationStatus expected_migration_status,
@@ -67,8 +68,7 @@
             expected_migration_status, std::move(callback)));
   }
 
-  template <typename T>
-  std::unique_ptr<SharedProtoDatabaseClient<T>> GetClientAndWait(
+  std::unique_ptr<SharedProtoDatabaseClient> GetClientAndWait(
       const std::string& client_namespace,
       const std::string& type_prefix,
       bool create_if_missing,
@@ -76,16 +76,16 @@
       SharedDBMetadataProto::MigrationStatus expected_migration_status =
           SharedDBMetadataProto::MIGRATION_NOT_ATTEMPTED) {
     base::RunLoop loop;
-    auto client = GetClient<T>(
-        client_namespace, type_prefix, create_if_missing,
-        base::BindOnce(
-            [](Enums::InitStatus* status_out, base::OnceClosure closure,
-               Enums::InitStatus status) {
-              *status_out = status;
-              std::move(closure).Run();
-            },
-            status, loop.QuitClosure()),
-        expected_migration_status);
+    auto client =
+        GetClient(client_namespace, type_prefix, create_if_missing,
+                  base::BindOnce(
+                      [](Enums::InitStatus* status_out,
+                         base::OnceClosure closure, Enums::InitStatus status) {
+                        *status_out = status;
+                        std::move(closure).Run();
+                      },
+                      status, loop.QuitClosure()),
+                  expected_migration_status);
     loop.Run();
     return client;
   }
@@ -107,12 +107,12 @@
   }
 
   bool ContainsEntries(const leveldb_proto::KeyVector& db_keys,
-                       const std::vector<TestProto>& entries,
+                       const ValueVector& entries,
                        const std::string& client_namespace,
                        const std::string& type_prefix) {
     std::set<std::string> entry_id_set;
     for (auto& entry : entries)
-      entry_id_set.insert(entry.id());
+      entry_id_set.insert(entry);
 
     // Entry IDs don't include the full prefix, so we don't look for that here.
     auto prefix =
@@ -124,15 +124,16 @@
     return true;
   }
 
-  void UpdateEntries(SharedProtoDatabaseClient<TestProto>* client,
+  void UpdateEntries(SharedProtoDatabaseClient* client,
                      const leveldb_proto::KeyVector& keys,
                      const leveldb_proto::KeyVector& keys_to_remove,
                      bool expect_success) {
-    auto entries = std::make_unique<ProtoDatabase<TestProto>::KeyEntryVector>();
+    auto entries =
+        std::make_unique<ProtoDatabase<std::string>::KeyEntryVector>();
     for (auto& key : keys) {
-      TestProto proto;
-      proto.set_id(client->prefix_ + key);
-      entries->emplace_back(std::make_pair(key, std::move(proto)));
+      std::string value;
+      value = client->prefix_ + key;
+      entries->emplace_back(std::make_pair(key, std::move(value)));
     }
 
     auto entries_to_remove = std::make_unique<leveldb_proto::KeyVector>();
@@ -151,16 +152,16 @@
     update_entries_loop.Run();
   }
 
-  void UpdateEntriesWithRemoveFilter(
-      SharedProtoDatabaseClient<TestProto>* client,
-      const leveldb_proto::KeyVector& keys,
-      const KeyFilter& delete_key_filter,
-      bool expect_success) {
-    auto entries = std::make_unique<ProtoDatabase<TestProto>::KeyEntryVector>();
+  void UpdateEntriesWithRemoveFilter(SharedProtoDatabaseClient* client,
+                                     const leveldb_proto::KeyVector& keys,
+                                     const KeyFilter& delete_key_filter,
+                                     bool expect_success) {
+    auto entries =
+        std::make_unique<ProtoDatabase<std::string>::KeyEntryVector>();
     for (auto& key : keys) {
-      TestProto proto;
-      proto.set_id(client->prefix_ + key);
-      entries->emplace_back(std::make_pair(key, std::move(proto)));
+      std::string value;
+      value = client->prefix_ + key;
+      entries->emplace_back(std::make_pair(key, std::move(value)));
     }
 
     base::RunLoop update_entries_loop;
@@ -177,19 +178,19 @@
 
   // This fills in for all the LoadEntriesX functions because they all call this
   // one.
-  void LoadEntriesWithFilter(SharedProtoDatabaseClient<TestProto>* client,
+  void LoadEntriesWithFilter(SharedProtoDatabaseClient* client,
                              const KeyFilter& key_filter,
                              const leveldb::ReadOptions& options,
                              const std::string& target_prefix,
                              bool expect_success,
-                             std::unique_ptr<std::vector<TestProto>>* entries) {
+                             std::unique_ptr<ValueVector>* entries) {
     base::RunLoop load_entries_loop;
     client->LoadEntriesWithFilter(
         key_filter, options, target_prefix,
         base::BindOnce(
-            [](std::unique_ptr<std::vector<TestProto>>* entries_ptr,
+            [](std::unique_ptr<ValueVector>* entries_ptr,
                base::OnceClosure signal, bool expect_success, bool success,
-               std::unique_ptr<std::vector<TestProto>> entries) {
+               std::unique_ptr<ValueVector> entries) {
               ASSERT_EQ(success, expect_success);
               entries_ptr->reset(entries.release());
               std::move(signal).Run();
@@ -198,19 +199,18 @@
     load_entries_loop.Run();
   }
 
-  void LoadKeysAndEntriesInRange(
-      SharedProtoDatabaseClient<TestProto>* client,
-      const std::string& start,
-      const std::string& end,
-      bool expect_success,
-      std::unique_ptr<std::map<std::string, TestProto>>* entries) {
+  void LoadKeysAndEntriesInRange(SharedProtoDatabaseClient* client,
+                                 const std::string& start,
+                                 const std::string& end,
+                                 bool expect_success,
+                                 std::unique_ptr<KeyValueMap>* entries) {
     base::RunLoop load_entries_in_range_loop;
     client->LoadKeysAndEntriesInRange(
         start, end,
         base::BindOnce(
-            [](std::unique_ptr<std::map<std::string, TestProto>>* entries_ptr,
+            [](std::unique_ptr<KeyValueMap>* entries_ptr,
                base::OnceClosure signal, bool expect_success, bool success,
-               std::unique_ptr<std::map<std::string, TestProto>> entries) {
+               std::unique_ptr<KeyValueMap> entries) {
               ASSERT_EQ(success, expect_success);
               *entries_ptr = std::move(entries);
               std::move(signal).Run();
@@ -219,14 +219,13 @@
     load_entries_in_range_loop.Run();
   }
 
-  void LoadKeys(SharedProtoDatabaseClient<TestProto>* client,
+  void LoadKeys(SharedProtoDatabaseClient* client,
                 bool expect_success,
-                std::unique_ptr<std::vector<std::string>>* keys) {
+                std::unique_ptr<KeyVector>* keys) {
     base::RunLoop load_keys_loop;
     client->LoadKeys(base::BindOnce(
-        [](std::unique_ptr<std::vector<std::string>>* keys_ptr,
-           base::OnceClosure signal, bool expect_success, bool success,
-           std::unique_ptr<std::vector<std::string>> keys) {
+        [](std::unique_ptr<KeyVector>* keys_ptr, base::OnceClosure signal,
+           bool expect_success, bool success, std::unique_ptr<KeyVector> keys) {
           ASSERT_EQ(success, expect_success);
           keys_ptr->reset(keys.release());
           std::move(signal).Run();
@@ -235,17 +234,16 @@
     load_keys_loop.Run();
   }
 
-  std::unique_ptr<TestProto> GetEntry(
-      SharedProtoDatabaseClient<TestProto>* client,
-      const std::string& key,
-      bool expect_success) {
-    std::unique_ptr<TestProto> entry;
+  std::unique_ptr<std::string> GetEntry(SharedProtoDatabaseClient* client,
+                                        const std::string& key,
+                                        bool expect_success) {
+    std::unique_ptr<std::string> entry;
     base::RunLoop get_key_loop;
     client->GetEntry(
         key, base::BindOnce(
-                 [](std::unique_ptr<TestProto>* entry_ptr,
+                 [](std::unique_ptr<std::string>* entry_ptr,
                     base::OnceClosure signal, bool expect_success, bool success,
-                    std::unique_ptr<TestProto> entry) {
+                    std::unique_ptr<std::string> entry) {
                    ASSERT_EQ(success, expect_success);
                    entry_ptr->reset(entry.release());
                    std::move(signal).Run();
@@ -255,8 +253,7 @@
     return entry;
   }
 
-  void Destroy(SharedProtoDatabaseClient<TestProto>* client,
-               bool expect_success) {
+  void Destroy(SharedProtoDatabaseClient* client, bool expect_success) {
     base::RunLoop destroy_loop;
     client->Destroy(base::BindOnce(
         [](bool expect_success, base::OnceClosure signal, bool success) {
@@ -288,7 +285,7 @@
   }
 
   void UpdateMetadataAsync(
-      SharedProtoDatabaseClient<TestProto>* client,
+      SharedProtoDatabaseClient* client,
       SharedDBMetadataProto::MigrationStatus migration_status) {
     base::RunLoop wait_loop;
     Callbacks::UpdateCallback wait_callback = base::BindOnce(
@@ -312,9 +309,8 @@
 
 TEST_F(SharedProtoDatabaseClientTest, InitSuccess) {
   auto status = Enums::InitStatus::kError;
-  auto client =
-      GetClientAndWait<TestProto>(kDefaultNamespace, kDefaultTypePrefix,
-                                  true /* create_if_missing */, &status);
+  auto client = GetClientAndWait(kDefaultNamespace, kDefaultTypePrefix,
+                                 true /* create_if_missing */, &status);
   ASSERT_EQ(status, Enums::InitStatus::kOK);
 
   client->Init("client", base::BindOnce([](Enums::InitStatus status) {
@@ -324,9 +320,8 @@
 
 TEST_F(SharedProtoDatabaseClientTest, InitFail) {
   auto status = Enums::InitStatus::kError;
-  auto client =
-      GetClientAndWait<TestProto>(kDefaultNamespace, kDefaultTypePrefix,
-                                  false /* create_if_missing */, &status);
+  auto client = GetClientAndWait(kDefaultNamespace, kDefaultTypePrefix,
+                                 false /* create_if_missing */, &status);
   ASSERT_EQ(status, Enums::InitStatus::kInvalidOperation);
 
   client->Init("client", base::BindOnce([](Enums::InitStatus status) {
@@ -338,16 +333,15 @@
 // removes prefixed entries correctly.
 TEST_F(SharedProtoDatabaseClientTest, UpdateEntriesAppropriatePrefix) {
   auto status = Enums::InitStatus::kError;
-  auto client =
-      GetClientAndWait<TestProto>(kDefaultNamespace, kDefaultTypePrefix,
-                                  true /* create_if_missing */, &status);
+  auto client = GetClientAndWait(kDefaultNamespace, kDefaultTypePrefix,
+                                 true /* create_if_missing */, &status);
   ASSERT_EQ(status, Enums::InitStatus::kOK);
 
-  std::vector<std::string> key_list = {"entry1", "entry2", "entry3"};
+  KeyVector key_list = {"entry1", "entry2", "entry3"};
   UpdateEntries(client.get(), key_list, leveldb_proto::KeyVector(), true);
 
   // Make sure those entries are in the LevelDB with the appropriate prefix.
-  std::vector<std::string> keys;
+  KeyVector keys;
   LevelDB* db = GetLevelDB();
   db->LoadKeys(&keys);
   ASSERT_EQ(keys.size(), 3U);
@@ -368,20 +362,18 @@
 TEST_F(SharedProtoDatabaseClientTest,
        UpdateEntries_DeletesCorrectClientEntries) {
   auto status = Enums::InitStatus::kError;
-  auto client_a =
-      GetClientAndWait<TestProto>(kDefaultNamespace, kDefaultTypePrefix,
-                                  true /* create_if_missing */, &status);
+  auto client_a = GetClientAndWait(kDefaultNamespace, kDefaultTypePrefix,
+                                   true /* create_if_missing */, &status);
   ASSERT_EQ(status, Enums::InitStatus::kOK);
-  auto client_b =
-      GetClientAndWait<TestProto>(kDefaultNamespace2, kDefaultTypePrefix,
-                                  true /* create_if_missing */, &status);
+  auto client_b = GetClientAndWait(kDefaultNamespace2, kDefaultTypePrefix,
+                                   true /* create_if_missing */, &status);
   ASSERT_EQ(status, Enums::InitStatus::kOK);
 
-  std::vector<std::string> key_list = {"entry1", "entry2", "entry3"};
+  KeyVector key_list = {"entry1", "entry2", "entry3"};
   UpdateEntries(client_a.get(), key_list, leveldb_proto::KeyVector(), true);
   UpdateEntries(client_b.get(), key_list, leveldb_proto::KeyVector(), true);
 
-  std::vector<std::string> keys;
+  KeyVector keys;
   LevelDB* db = GetLevelDB();
   db->LoadKeys(&keys);
   ASSERT_EQ(keys.size(), 6U);
@@ -402,15 +394,14 @@
 TEST_F(SharedProtoDatabaseClientTest,
        UpdateEntriesWithRemoveFilter_DeletesCorrectEntries) {
   auto status = Enums::InitStatus::kError;
-  auto client =
-      GetClientAndWait<TestProto>(kDefaultNamespace, kDefaultTypePrefix,
-                                  true /* create_if_missing */, &status);
+  auto client = GetClientAndWait(kDefaultNamespace, kDefaultTypePrefix,
+                                 true /* create_if_missing */, &status);
   ASSERT_EQ(status, Enums::InitStatus::kOK);
 
-  std::vector<std::string> key_list = {"entry1", "entry2", "testentry3"};
+  KeyVector key_list = {"entry1", "entry2", "testentry3"};
   UpdateEntries(client.get(), key_list, leveldb_proto::KeyVector(), true);
 
-  std::vector<std::string> keys;
+  KeyVector keys;
   LevelDB* db = GetLevelDB();
   db->LoadKeys(&keys);
   ASSERT_EQ(keys.size(), 3U);
@@ -433,30 +424,27 @@
 
 TEST_F(SharedProtoDatabaseClientTest, LoadEntriesWithFilter) {
   auto status = Enums::InitStatus::kError;
-  auto client_a =
-      GetClientAndWait<TestProto>(kDefaultNamespace, kDefaultTypePrefix,
-                                  true /* create_if_missing */, &status);
+  auto client_a = GetClientAndWait(kDefaultNamespace, kDefaultTypePrefix,
+                                   true /* create_if_missing */, &status);
   ASSERT_EQ(status, Enums::InitStatus::kOK);
-  auto client_b =
-      GetClientAndWait<TestProto>(kDefaultNamespace2, kDefaultTypePrefix,
-                                  true /* create_if_missing */, &status);
+  auto client_b = GetClientAndWait(kDefaultNamespace2, kDefaultTypePrefix,
+                                   true /* create_if_missing */, &status);
   ASSERT_EQ(status, Enums::InitStatus::kOK);
 
-  std::vector<std::string> key_list_a = {"entry123", "entry2123", "testentry3"};
+  KeyVector key_list_a = {"entry123", "entry2123", "testentry3"};
   UpdateEntries(client_a.get(), key_list_a, leveldb_proto::KeyVector(), true);
-  std::vector<std::string> key_list_b = {"testentry124", "entry2124",
-                                         "testentry4"};
+  KeyVector key_list_b = {"testentry124", "entry2124", "testentry4"};
   UpdateEntries(client_b.get(), key_list_b, leveldb_proto::KeyVector(), true);
 
-  std::unique_ptr<std::vector<TestProto>> entries;
-  LoadEntriesWithFilter(client_a.get(), KeyFilter(), leveldb::ReadOptions(),
-                        std::string(), true, &entries);
+  std::unique_ptr<ValueVector> entries;
+  LoadEntriesWithFilter(client_a.get(), leveldb_proto::KeyFilter(),
+                        leveldb::ReadOptions(), std::string(), true, &entries);
   ASSERT_EQ(entries->size(), 3U);
   ASSERT_TRUE(ContainsEntries(key_list_a, *entries, kDefaultNamespace,
                               kDefaultTypePrefix));
 
-  LoadEntriesWithFilter(client_b.get(), KeyFilter(), leveldb::ReadOptions(),
-                        std::string(), true, &entries);
+  LoadEntriesWithFilter(client_b.get(), leveldb_proto::KeyFilter(),
+                        leveldb::ReadOptions(), std::string(), true, &entries);
   ASSERT_EQ(entries->size(), 3U);
   ASSERT_TRUE(ContainsEntries(key_list_b, *entries, kDefaultNamespace2,
                               kDefaultTypePrefix));
@@ -476,31 +464,28 @@
 
 TEST_F(SharedProtoDatabaseClientTest, LoadKeysAndEntriesInRange) {
   auto status = Enums::InitStatus::kError;
-  auto client_a =
-      GetClientAndWait<TestProto>(kDefaultNamespace, kDefaultTypePrefix,
-                                  true /* create_if_missing */, &status);
+  auto client_a = GetClientAndWait(kDefaultNamespace, kDefaultTypePrefix,
+                                   true /* create_if_missing */, &status);
   ASSERT_EQ(status, Enums::InitStatus::kOK);
-  auto client_b =
-      GetClientAndWait<TestProto>(kDefaultNamespace2, kDefaultTypePrefix,
-                                  true /* create_if_missing */, &status);
+  auto client_b = GetClientAndWait(kDefaultNamespace2, kDefaultTypePrefix,
+                                   true /* create_if_missing */, &status);
   ASSERT_EQ(status, Enums::InitStatus::kOK);
 
-  std::vector<std::string> key_list_a = {"entry0", "entry1",           "entry2",
-                                         "entry3", "entry3notinrange", "entry4",
-                                         "entry5"};
+  KeyVector key_list_a = {"entry0",           "entry1", "entry2", "entry3",
+                          "entry3notinrange", "entry4", "entry5"};
   UpdateEntries(client_a.get(), key_list_a, leveldb_proto::KeyVector(), true);
-  std::vector<std::string> key_list_b = {"entry2", "entry3", "entry4"};
+  KeyVector key_list_b = {"entry2", "entry3", "entry4"};
   UpdateEntries(client_b.get(), key_list_b, leveldb_proto::KeyVector(), true);
 
-  std::unique_ptr<std::map<std::string, TestProto>> keys_and_entries_a;
+  std::unique_ptr<KeyValueMap> keys_and_entries_a;
   LoadKeysAndEntriesInRange(client_a.get(), "entry1", "entry3", true,
                             &keys_and_entries_a);
 
-  std::unique_ptr<std::map<std::string, TestProto>> keys_and_entries_b;
+  std::unique_ptr<KeyValueMap> keys_and_entries_b;
   LoadKeysAndEntriesInRange(client_b.get(), "entry0", "entry1", true,
                             &keys_and_entries_b);
 
-  std::vector<TestProto> entries;
+  ValueVector entries;
 
   for (auto& pair : *keys_and_entries_a) {
     entries.push_back(pair.second);
@@ -514,23 +499,19 @@
 
 TEST_F(SharedProtoDatabaseClientTest, LoadKeys) {
   auto status = Enums::InitStatus::kError;
-  auto client_a =
-      GetClientAndWait<TestProto>(kDefaultNamespace, kDefaultTypePrefix,
-                                  true /* create_if_missing */, &status);
+  auto client_a = GetClientAndWait(kDefaultNamespace, kDefaultTypePrefix,
+                                   true /* create_if_missing */, &status);
   ASSERT_EQ(status, Enums::InitStatus::kOK);
-  auto client_b =
-      GetClientAndWait<TestProto>(kDefaultNamespace2, kDefaultTypePrefix,
-                                  true /* create_if_missing */, &status);
+  auto client_b = GetClientAndWait(kDefaultNamespace2, kDefaultTypePrefix,
+                                   true /* create_if_missing */, &status);
   ASSERT_EQ(status, Enums::InitStatus::kOK);
 
-  std::vector<std::string> key_list_a = {"entry123", "entry2123", "testentry3",
-                                         "testing"};
+  KeyVector key_list_a = {"entry123", "entry2123", "testentry3", "testing"};
   UpdateEntries(client_a.get(), key_list_a, leveldb_proto::KeyVector(), true);
-  std::vector<std::string> key_list_b = {"testentry124", "entry2124",
-                                         "testentry4"};
+  KeyVector key_list_b = {"testentry124", "entry2124", "testentry4"};
   UpdateEntries(client_b.get(), key_list_b, leveldb_proto::KeyVector(), true);
 
-  std::unique_ptr<std::vector<std::string>> keys;
+  std::unique_ptr<KeyVector> keys;
   LoadKeys(client_a.get(), true, &keys);
   ASSERT_EQ(keys->size(), 4U);
   ASSERT_TRUE(ContainsKeys(*keys, key_list_a, std::string(), std::string()));
@@ -541,16 +522,14 @@
 
 TEST_F(SharedProtoDatabaseClientTest, GetEntry) {
   auto status = Enums::InitStatus::kError;
-  auto client_a =
-      GetClientAndWait<TestProto>(kDefaultNamespace, kDefaultTypePrefix,
-                                  true /* create_if_missing */, &status);
+  auto client_a = GetClientAndWait(kDefaultNamespace, kDefaultTypePrefix,
+                                   true /* create_if_missing */, &status);
   ASSERT_EQ(status, Enums::InitStatus::kOK);
-  auto client_b =
-      GetClientAndWait<TestProto>(kDefaultNamespace2, kDefaultTypePrefix,
-                                  true /* create_if_missing */, &status);
+  auto client_b = GetClientAndWait(kDefaultNamespace2, kDefaultTypePrefix,
+                                   true /* create_if_missing */, &status);
   ASSERT_EQ(status, Enums::InitStatus::kOK);
 
-  std::vector<std::string> key_list = {"a", "b", "c"};
+  KeyVector key_list = {"a", "b", "c"};
   // Add the same entries to both because we want to make sure we only get the
   // entries from the proper client.
   UpdateEntries(client_a.get(), key_list, leveldb_proto::KeyVector(), true);
@@ -563,28 +542,25 @@
 
   for (auto& key : key_list) {
     auto entry = GetEntry(client_a.get(), key, true);
-    ASSERT_EQ(entry->id(), a_prefix + key);
+    ASSERT_EQ(*entry, a_prefix + key);
     entry = GetEntry(client_b.get(), key, true);
-    ASSERT_EQ(entry->id(), b_prefix + key);
+    ASSERT_EQ(*entry, b_prefix + key);
   }
 }
 
 TEST_F(SharedProtoDatabaseClientTest, TestCleanupObsoleteClients) {
   auto status = Enums::InitStatus::kError;
-  auto client_a =
-      GetClientAndWait<TestProto>(kDefaultNamespace, kDefaultTypePrefix,
-                                  true /* create_if_missing */, &status);
+  auto client_a = GetClientAndWait(kDefaultNamespace, kDefaultTypePrefix,
+                                   true /* create_if_missing */, &status);
   ASSERT_EQ(status, Enums::InitStatus::kOK);
-  auto client_b =
-      GetClientAndWait<TestProto>(kDefaultNamespace1, kDefaultTypePrefix,
-                                  true /* create_if_missing */, &status);
+  auto client_b = GetClientAndWait(kDefaultNamespace1, kDefaultTypePrefix,
+                                   true /* create_if_missing */, &status);
   ASSERT_EQ(status, Enums::InitStatus::kOK);
-  auto client_c =
-      GetClientAndWait<TestProto>(kDefaultNamespace2, kDefaultTypePrefix,
-                                  true /* create_if_missing */, &status);
+  auto client_c = GetClientAndWait(kDefaultNamespace2, kDefaultTypePrefix,
+                                   true /* create_if_missing */, &status);
   ASSERT_EQ(status, Enums::InitStatus::kOK);
 
-  std::vector<std::string> test_keys = {"a", "b", "c"};
+  KeyVector test_keys = {"a", "b", "c"};
   UpdateEntries(client_a.get(), test_keys, leveldb_proto::KeyVector(), true);
   UpdateEntries(client_b.get(), test_keys, leveldb_proto::KeyVector(), true);
   UpdateEntries(client_c.get(), test_keys, leveldb_proto::KeyVector(), true);
@@ -592,7 +568,7 @@
   // Check that the original list does not clear any data from test DBs.
   DestroyObsoleteClientsAndWait(nullptr /* client_list */);
 
-  std::vector<std::string> keys;
+  KeyVector keys;
   LevelDB* db = GetLevelDB();
   db->LoadKeys(&keys);
   EXPECT_EQ(keys.size(), test_keys.size() * 3);
@@ -626,23 +602,21 @@
 
 TEST_F(SharedProtoDatabaseClientTest, TestDestroy) {
   auto status = Enums::InitStatus::kError;
-  auto client_a =
-      GetClientAndWait<TestProto>(kDefaultNamespace, kDefaultTypePrefix,
-                                  true /* create_if_missing */, &status);
+  auto client_a = GetClientAndWait(kDefaultNamespace, kDefaultTypePrefix,
+                                   true /* create_if_missing */, &status);
   ASSERT_EQ(status, Enums::InitStatus::kOK);
-  auto client_b =
-      GetClientAndWait<TestProto>(kDefaultNamespace2, kDefaultTypePrefix,
-                                  true /* create_if_missing */, &status);
+  auto client_b = GetClientAndWait(kDefaultNamespace2, kDefaultTypePrefix,
+                                   true /* create_if_missing */, &status);
   ASSERT_EQ(status, Enums::InitStatus::kOK);
 
-  std::vector<std::string> key_list = {"a", "b", "c"};
+  KeyVector key_list = {"a", "b", "c"};
   // Add the same entries to both because we want to make sure we only destroy
   // the entries from the proper client.
   UpdateEntries(client_a.get(), key_list, leveldb_proto::KeyVector(), true);
   UpdateEntries(client_b.get(), key_list, leveldb_proto::KeyVector(), true);
 
   // Delete only client A.
-  std::vector<std::string> keys;
+  KeyVector keys;
   LevelDB* db = GetLevelDB();
   db->LoadKeys(&keys);
   ASSERT_EQ(keys.size(), key_list.size() * 2);
@@ -668,23 +642,20 @@
 
 TEST_F(SharedProtoDatabaseClientTest, UpdateClientMetadataAsync) {
   auto status = Enums::InitStatus::kError;
-  auto client_a =
-      GetClientAndWait<TestProto>(kDefaultNamespace, kDefaultTypePrefix,
-                                  true /* create_if_missing */, &status);
+  auto client_a = GetClientAndWait(kDefaultNamespace, kDefaultTypePrefix,
+                                   true /* create_if_missing */, &status);
   EXPECT_EQ(status, Enums::InitStatus::kOK);
   EXPECT_EQ(SharedDBMetadataProto::MIGRATION_NOT_ATTEMPTED,
             client_a->migration_status());
 
-  auto client_b =
-      GetClientAndWait<TestProto>(kDefaultNamespace1, kDefaultTypePrefix,
-                                  true /* create_if_missing */, &status);
+  auto client_b = GetClientAndWait(kDefaultNamespace1, kDefaultTypePrefix,
+                                   true /* create_if_missing */, &status);
   EXPECT_EQ(status, Enums::InitStatus::kOK);
   EXPECT_EQ(SharedDBMetadataProto::MIGRATION_NOT_ATTEMPTED,
             client_b->migration_status());
 
-  auto client_c =
-      GetClientAndWait<TestProto>(kDefaultNamespace2, kDefaultTypePrefix,
-                                  true /* create_if_missing */, &status);
+  auto client_c = GetClientAndWait(kDefaultNamespace2, kDefaultTypePrefix,
+                                   true /* create_if_missing */, &status);
   EXPECT_EQ(status, Enums::InitStatus::kOK);
   EXPECT_EQ(SharedDBMetadataProto::MIGRATION_NOT_ATTEMPTED,
             client_c->migration_status());
@@ -699,19 +670,18 @@
   client_b.reset();
   client_c.reset();
 
-  auto client_d = GetClientAndWait<TestProto>(
+  auto client_d = GetClientAndWait(
       kDefaultNamespace, kDefaultTypePrefix, true /* create_if_missing */,
       &status, SharedDBMetadataProto::MIGRATE_TO_SHARED_SUCCESSFUL);
   EXPECT_EQ(status, Enums::InitStatus::kOK);
 
-  auto client_e = GetClientAndWait<TestProto>(
+  auto client_e = GetClientAndWait(
       kDefaultNamespace1, kDefaultTypePrefix, true /* create_if_missing */,
       &status, SharedDBMetadataProto::MIGRATE_TO_UNIQUE_SHARED_TO_BE_DELETED);
   EXPECT_EQ(status, Enums::InitStatus::kOK);
 
-  auto client_f =
-      GetClientAndWait<TestProto>(kDefaultNamespace2, kDefaultTypePrefix,
-                                  true /* create_if_missing */, &status);
+  auto client_f = GetClientAndWait(kDefaultNamespace2, kDefaultTypePrefix,
+                                   true /* create_if_missing */, &status);
   EXPECT_EQ(status, Enums::InitStatus::kOK);
 
   UpdateMetadataAsync(client_d.get(),
diff --git a/components/leveldb_proto/internal/shared_proto_database_unittest.cc b/components/leveldb_proto/internal/shared_proto_database_unittest.cc
index d2d2a233..a2699101 100644
--- a/components/leveldb_proto/internal/shared_proto_database_unittest.cc
+++ b/components/leveldb_proto/internal/shared_proto_database_unittest.cc
@@ -26,7 +26,7 @@
                                     const std::string& client_namespace,
                                     const std::string& type_prefix,
                                     base::OnceClosure closure) {
-  db->GetClientForTesting<TestProto>(
+  db->GetClientForTesting(
       client_namespace, type_prefix, true /* create_if_missing */,
       base::BindOnce(
           [](base::OnceClosure closure, Enums::InitStatus status,
@@ -67,15 +67,14 @@
     return db->init_state_ == SharedProtoDatabase::InitState::kSuccess;
   }
 
-  template <typename T>
-  std::unique_ptr<SharedProtoDatabaseClient<T>> GetClientAndWait(
+  std::unique_ptr<SharedProtoDatabaseClient> GetClientAndWait(
       SharedProtoDatabase* db,
       const std::string& client_namespace,
       const std::string& type_prefix,
       bool create_if_missing,
       Enums::InitStatus* status) {
     base::RunLoop loop;
-    auto client = db->GetClientForTesting<T>(
+    auto client = db->GetClientForTesting(
         client_namespace, type_prefix, create_if_missing,
         base::BindOnce(
             [](Enums::InitStatus* status_out, base::OnceClosure closure,
@@ -107,8 +106,8 @@
 
 TEST_F(SharedProtoDatabaseTest, CreateClient_SucceedsWithCreate) {
   auto status = Enums::InitStatus::kError;
-  GetClientAndWait<TestProto>(db(), kDefaultNamespace, kDefaultTypePrefix,
-                              true /* create_if_missing */, &status);
+  GetClientAndWait(db(), kDefaultNamespace, kDefaultTypePrefix,
+                   true /* create_if_missing */, &status);
   ASSERT_EQ(status, Enums::InitStatus::kOK);
 }
 
@@ -119,26 +118,26 @@
 TEST_F(SharedProtoDatabaseTest, CreateClient_FailsWithoutCreate) {
 #endif
   auto status = Enums::InitStatus::kError;
-  GetClientAndWait<TestProto>(db(), kDefaultNamespace, kDefaultTypePrefix,
-                              false /* create_if_missing */, &status);
+  GetClientAndWait(db(), kDefaultNamespace, kDefaultTypePrefix,
+                   false /* create_if_missing */, &status);
   ASSERT_EQ(status, Enums::InitStatus::kInvalidOperation);
 }
 
 TEST_F(SharedProtoDatabaseTest,
        CreateClient_SucceedsWithoutCreateIfAlreadyCreated) {
   auto status = Enums::InitStatus::kError;
-  GetClientAndWait<TestProto>(db(), kDefaultNamespace2, kDefaultTypePrefix,
-                              true /* create_if_missing */, &status);
+  GetClientAndWait(db(), kDefaultNamespace2, kDefaultTypePrefix,
+                   true /* create_if_missing */, &status);
   ASSERT_EQ(status, Enums::InitStatus::kOK);
-  GetClientAndWait<TestProto>(db(), kDefaultNamespace, kDefaultTypePrefix,
-                              false /* create_if_missing */, &status);
+  GetClientAndWait(db(), kDefaultNamespace, kDefaultTypePrefix,
+                   false /* create_if_missing */, &status);
   ASSERT_EQ(status, Enums::InitStatus::kOK);
 }
 
 TEST_F(SharedProtoDatabaseTest, GetClient_DifferentThreads) {
   auto status = Enums::InitStatus::kError;
-  GetClientAndWait<TestProto>(db(), kDefaultNamespace, kDefaultTypePrefix,
-                              true /* create_if_missing */, &status);
+  GetClientAndWait(db(), kDefaultNamespace, kDefaultTypePrefix,
+                   true /* create_if_missing */, &status);
   ASSERT_EQ(status, Enums::InitStatus::kOK);
 
   base::Thread t("test_thread");
diff --git a/components/leveldb_proto/internal/unique_proto_database.cc b/components/leveldb_proto/internal/unique_proto_database.cc
new file mode 100644
index 0000000..753f94c
--- /dev/null
+++ b/components/leveldb_proto/internal/unique_proto_database.cc
@@ -0,0 +1,167 @@
+// 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/leveldb_proto/internal/unique_proto_database.h"
+
+#include <memory>
+#include <utility>
+
+#include "base/sequenced_task_runner.h"
+#include "components/leveldb_proto/internal/leveldb_database.h"
+#include "components/leveldb_proto/internal/proto_leveldb_wrapper.h"
+
+namespace leveldb_proto {
+
+UniqueProtoDatabase::UniqueProtoDatabase(
+    const scoped_refptr<base::SequencedTaskRunner>& task_runner)
+    : db_wrapper_(std::make_unique<ProtoLevelDBWrapper>(task_runner)) {}
+
+UniqueProtoDatabase::UniqueProtoDatabase(
+    std::unique_ptr<ProtoLevelDBWrapper> db_wrapper)
+    : db_wrapper_(std::move(db_wrapper)) {}
+
+UniqueProtoDatabase::UniqueProtoDatabase(
+    const base::FilePath& database_dir,
+    const leveldb_env::Options& options,
+    const scoped_refptr<base::SequencedTaskRunner>& task_runner)
+    : UniqueProtoDatabase(task_runner) {
+  database_dir_ = database_dir;
+  options_ = options;
+}
+
+UniqueProtoDatabase::~UniqueProtoDatabase() {
+  if (db_.get() &&
+      !db_wrapper_->task_runner()->DeleteSoon(FROM_HERE, db_.release())) {
+    DLOG(WARNING) << "Proto database will not be deleted.";
+  }
+}
+
+void UniqueProtoDatabase::Init(const std::string& client_name,
+                               Callbacks::InitStatusCallback callback) {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  db_ = std::make_unique<LevelDB>(client_name.c_str());
+  db_wrapper_->SetMetricsId(client_name);
+  InitWithDatabase(db_.get(), database_dir_, options_, true,
+                   std::move(callback));
+}
+
+void UniqueProtoDatabase::InitWithDatabase(
+    LevelDB* database,
+    const base::FilePath& database_dir,
+    const leveldb_env::Options& options,
+    bool destroy_on_corruption,
+    Callbacks::InitStatusCallback callback) {
+  // We set |destroy_on_corruption| to true to preserve the original behaviour
+  // where database corruption led to automatic destruction.
+  db_wrapper_->InitWithDatabase(database, database_dir, options,
+                                destroy_on_corruption, std::move(callback));
+}
+
+void UniqueProtoDatabase::UpdateEntries(
+    std::unique_ptr<KeyValueVector> entries_to_save,
+    std::unique_ptr<KeyVector> keys_to_remove,
+    Callbacks::UpdateCallback callback) {
+  db_wrapper_->UpdateEntries(std::move(entries_to_save),
+                             std::move(keys_to_remove), std::move(callback));
+}
+
+void UniqueProtoDatabase::UpdateEntriesWithRemoveFilter(
+    std::unique_ptr<KeyValueVector> entries_to_save,
+    const KeyFilter& delete_key_filter,
+    Callbacks::UpdateCallback callback) {
+  db_wrapper_->UpdateEntriesWithRemoveFilter(
+      std::move(entries_to_save), delete_key_filter, std::move(callback));
+}
+
+void UniqueProtoDatabase::UpdateEntriesWithRemoveFilter(
+    std::unique_ptr<KeyValueVector> entries_to_save,
+    const KeyFilter& delete_key_filter,
+    const std::string& target_prefix,
+    Callbacks::UpdateCallback callback) {
+  db_wrapper_->UpdateEntriesWithRemoveFilter(std::move(entries_to_save),
+                                             delete_key_filter, target_prefix,
+                                             std::move(callback));
+}
+
+void UniqueProtoDatabase::LoadEntries(
+    typename Callbacks::LoadCallback callback) {
+  db_wrapper_->LoadEntries(std::move(callback));
+}
+
+void UniqueProtoDatabase::LoadEntriesWithFilter(
+    const KeyFilter& filter,
+    typename Callbacks::LoadCallback callback) {
+  db_wrapper_->LoadEntriesWithFilter(filter, std::move(callback));
+}
+
+void UniqueProtoDatabase::LoadEntriesWithFilter(
+    const KeyFilter& key_filter,
+    const leveldb::ReadOptions& options,
+    const std::string& target_prefix,
+    typename Callbacks::LoadCallback callback) {
+  db_wrapper_->LoadEntriesWithFilter(key_filter, options, target_prefix,
+                                     std::move(callback));
+}
+
+void UniqueProtoDatabase::LoadKeysAndEntries(
+    typename Callbacks::LoadKeysAndEntriesCallback callback) {
+  db_wrapper_->LoadKeysAndEntries(std::move(callback));
+}
+
+void UniqueProtoDatabase::LoadKeysAndEntriesWithFilter(
+    const KeyFilter& filter,
+    typename Callbacks::LoadKeysAndEntriesCallback callback) {
+  db_wrapper_->LoadKeysAndEntriesWithFilter(filter, std::move(callback));
+}
+
+void UniqueProtoDatabase::LoadKeysAndEntriesWithFilter(
+    const KeyFilter& filter,
+    const leveldb::ReadOptions& options,
+    const std::string& target_prefix,
+    typename Callbacks::LoadKeysAndEntriesCallback callback) {
+  db_wrapper_->LoadKeysAndEntriesWithFilter(filter, options, target_prefix,
+                                            std::move(callback));
+}
+
+void UniqueProtoDatabase::LoadKeysAndEntriesInRange(
+    const std::string& start,
+    const std::string& end,
+    typename Callbacks::LoadKeysAndEntriesCallback callback) {
+  db_wrapper_->LoadKeysAndEntriesInRange(start, end, std::move(callback));
+}
+
+void UniqueProtoDatabase::LoadKeys(Callbacks::LoadKeysCallback callback) {
+  db_wrapper_->LoadKeys(std::move(callback));
+}
+
+void UniqueProtoDatabase::LoadKeys(const std::string& target_prefix,
+                                   Callbacks::LoadKeysCallback callback) {
+  db_wrapper_->LoadKeys(target_prefix, std::move(callback));
+}
+
+void UniqueProtoDatabase::GetEntry(const std::string& key,
+                                   typename Callbacks::GetCallback callback) {
+  db_wrapper_->GetEntry(key, std::move(callback));
+}
+
+void UniqueProtoDatabase::Destroy(Callbacks::DestroyCallback callback) {
+  db_wrapper_->Destroy(std::move(callback));
+}
+
+void UniqueProtoDatabase::RemoveKeysForTesting(
+    const KeyFilter& key_filter,
+    const std::string& target_prefix,
+    Callbacks::UpdateCallback callback) {
+  db_wrapper_->RemoveKeys(key_filter, target_prefix, std::move(callback));
+}
+
+bool UniqueProtoDatabase::GetApproximateMemoryUse(uint64_t* approx_mem_use) {
+  return db_wrapper_->GetApproximateMemoryUse(approx_mem_use);
+}
+
+void UniqueProtoDatabase::SetMetricsId(const std::string& id) {
+  db_wrapper_->SetMetricsId(id);
+}
+
+}  // namespace leveldb_proto
diff --git a/components/leveldb_proto/internal/unique_proto_database.h b/components/leveldb_proto/internal/unique_proto_database.h
index ffac63d..8b113361 100644
--- a/components/leveldb_proto/internal/unique_proto_database.h
+++ b/components/leveldb_proto/internal/unique_proto_database.h
@@ -5,19 +5,19 @@
 #ifndef COMPONENTS_LEVELDB_PROTO_INTERNAL_UNIQUE_PROTO_DATABASE_H_
 #define COMPONENTS_LEVELDB_PROTO_INTERNAL_UNIQUE_PROTO_DATABASE_H_
 
+#include <memory>
+#include <string>
+
 #include "base/bind.h"
-#include "base/sequenced_task_runner.h"
-#include "base/threading/thread_checker.h"
-#include "components/leveldb_proto/internal/leveldb_database.h"
+#include "base/sequence_checker.h"
 #include "components/leveldb_proto/internal/proto_leveldb_wrapper.h"
 #include "components/leveldb_proto/public/proto_database.h"
 
 namespace leveldb_proto {
 
-// An implementation of ProtoDatabase<T> that manages the lifecycle of a unique
-// LevelDB instance.
-template <typename T>
-class UniqueProtoDatabase : public ProtoDatabase<T> {
+// An implementation of ProtoDatabase<std::string> that manages the lifecycle of
+// a unique LevelDB instance.
+class UniqueProtoDatabase {
  public:
   explicit UniqueProtoDatabase(
       const scoped_refptr<base::SequencedTaskRunner>& task_runner);
@@ -29,78 +29,62 @@
       const leveldb_env::Options& options,
       const scoped_refptr<base::SequencedTaskRunner>& task_runner);
 
-  // This version of Init is for compatibility, since many of the current
-  // proto database still use this.
-  void Init(const char* client_name,
-            const base::FilePath& database_dir,
-            const leveldb_env::Options& options,
-            typename Callbacks::InitCallback callback) override;
+  virtual void Init(const std::string& client_name,
+                    Callbacks::InitStatusCallback callback);
 
-  void Init(const std::string& client_name,
-            Callbacks::InitStatusCallback callback) override;
+  virtual void InitWithDatabase(LevelDB* database,
+                                const base::FilePath& database_dir,
+                                const leveldb_env::Options& options,
+                                bool destroy_on_corruption,
+                                Callbacks::InitStatusCallback callback);
 
-  void InitWithDatabase(LevelDB* database,
-                        const base::FilePath& database_dir,
-                        const leveldb_env::Options& options,
-                        Callbacks::InitStatusCallback callback);
+  virtual void UpdateEntries(std::unique_ptr<KeyValueVector> entries_to_save,
+                             std::unique_ptr<KeyVector> keys_to_remove,
+                             Callbacks::UpdateCallback callback);
 
-  void UpdateEntries(std::unique_ptr<typename Util::Internal<T>::KeyEntryVector>
-                         entries_to_save,
-                     std::unique_ptr<std::vector<std::string>> keys_to_remove,
-                     Callbacks::UpdateCallback callback) override;
-
-  void UpdateEntriesWithRemoveFilter(
-      std::unique_ptr<typename Util::Internal<T>::KeyEntryVector>
-          entries_to_save,
+  virtual void UpdateEntriesWithRemoveFilter(
+      std::unique_ptr<KeyValueVector> entries_to_save,
       const KeyFilter& delete_key_filter,
-      Callbacks::UpdateCallback callback) override;
-  void UpdateEntriesWithRemoveFilter(
-      std::unique_ptr<typename Util::Internal<T>::KeyEntryVector>
-          entries_to_save,
+      Callbacks::UpdateCallback callback);
+  virtual void UpdateEntriesWithRemoveFilter(
+      std::unique_ptr<KeyValueVector> entries_to_save,
       const KeyFilter& delete_key_filter,
       const std::string& target_prefix,
-      Callbacks::UpdateCallback callback) override;
+      Callbacks::UpdateCallback callback);
 
-  void LoadEntries(
-      typename Callbacks::Internal<T>::LoadCallback callback) override;
+  virtual void LoadEntries(typename Callbacks::LoadCallback callback);
 
-  void LoadEntriesWithFilter(
+  virtual void LoadEntriesWithFilter(const KeyFilter& filter,
+                                     typename Callbacks::LoadCallback callback);
+  virtual void LoadEntriesWithFilter(const KeyFilter& key_filter,
+                                     const leveldb::ReadOptions& options,
+                                     const std::string& target_prefix,
+                                     typename Callbacks::LoadCallback callback);
+
+  virtual void LoadKeysAndEntries(
+      typename Callbacks::LoadKeysAndEntriesCallback callback);
+
+  virtual void LoadKeysAndEntriesWithFilter(
       const KeyFilter& filter,
-      typename Callbacks::Internal<T>::LoadCallback callback) override;
-  void LoadEntriesWithFilter(
-      const KeyFilter& key_filter,
-      const leveldb::ReadOptions& options,
-      const std::string& target_prefix,
-      typename Callbacks::Internal<T>::LoadCallback callback) override;
-
-  void LoadKeysAndEntries(
-      typename Callbacks::Internal<T>::LoadKeysAndEntriesCallback callback)
-      override;
-
-  void LoadKeysAndEntriesWithFilter(
-      const KeyFilter& filter,
-      typename Callbacks::Internal<T>::LoadKeysAndEntriesCallback callback)
-      override;
-  void LoadKeysAndEntriesWithFilter(
+      typename Callbacks::LoadKeysAndEntriesCallback callback);
+  virtual void LoadKeysAndEntriesWithFilter(
       const KeyFilter& filter,
       const leveldb::ReadOptions& options,
       const std::string& target_prefix,
-      typename Callbacks::Internal<T>::LoadKeysAndEntriesCallback callback)
-      override;
-  void LoadKeysAndEntriesInRange(
+      typename Callbacks::LoadKeysAndEntriesCallback callback);
+  virtual void LoadKeysAndEntriesInRange(
       const std::string& start,
       const std::string& end,
-      typename Callbacks::Internal<T>::LoadKeysAndEntriesCallback callback)
-      override;
+      typename Callbacks::LoadKeysAndEntriesCallback callback);
 
-  void LoadKeys(Callbacks::LoadKeysCallback callback) override;
-  void LoadKeys(const std::string& target_prefix,
-                Callbacks::LoadKeysCallback callback) override;
+  virtual void LoadKeys(Callbacks::LoadKeysCallback callback);
+  virtual void LoadKeys(const std::string& target_prefix,
+                        Callbacks::LoadKeysCallback callback);
 
-  void GetEntry(const std::string& key,
-                typename Callbacks::Internal<T>::GetCallback callback) override;
+  virtual void GetEntry(const std::string& key,
+                        typename Callbacks::GetCallback callback);
 
-  void Destroy(Callbacks::DestroyCallback callback) override;
+  virtual void Destroy(Callbacks::DestroyCallback callback);
 
   void RemoveKeysForTesting(const KeyFilter& key_filter,
                             const std::string& target_prefix,
@@ -114,209 +98,15 @@
 
  protected:
   std::unique_ptr<ProtoLevelDBWrapper> db_wrapper_;
-  scoped_refptr<base::SequencedTaskRunner> task_runner_;
 
  private:
-  THREAD_CHECKER(thread_checker_);
+  SEQUENCE_CHECKER(sequence_checker_);
 
   base::FilePath database_dir_;
   leveldb_env::Options options_;
   std::unique_ptr<LevelDB> db_;
 };
 
-template <typename T>
-UniqueProtoDatabase<T>::UniqueProtoDatabase(
-    const scoped_refptr<base::SequencedTaskRunner>& task_runner)
-    : db_wrapper_(std::make_unique<ProtoLevelDBWrapper>(task_runner)) {}
-
-template <typename T>
-UniqueProtoDatabase<T>::UniqueProtoDatabase(
-    std::unique_ptr<ProtoLevelDBWrapper> db_wrapper)
-    : db_wrapper_(std::move(db_wrapper)) {}
-
-template <typename T>
-UniqueProtoDatabase<T>::UniqueProtoDatabase(
-    const base::FilePath& database_dir,
-    const leveldb_env::Options& options,
-    const scoped_refptr<base::SequencedTaskRunner>& task_runner)
-    : UniqueProtoDatabase<T>(task_runner) {
-  database_dir_ = database_dir;
-  options_ = options;
-}
-
-template <typename T>
-UniqueProtoDatabase<T>::~UniqueProtoDatabase() {
-  if (db_.get() &&
-      !db_wrapper_->task_runner()->DeleteSoon(FROM_HERE, db_.release())) {
-    DLOG(WARNING) << "Proto database will not be deleted.";
-  }
-}
-
-template <typename T>
-void UniqueProtoDatabase<T>::Init(const std::string& client_name,
-                                  Callbacks::InitStatusCallback callback) {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-  db_ = std::make_unique<LevelDB>(client_name.c_str());
-  db_wrapper_->SetMetricsId(client_name);
-  InitWithDatabase(db_.get(), database_dir_, options_, std::move(callback));
-}
-
-template <typename T>
-void UniqueProtoDatabase<T>::Init(const char* client_name,
-                                  const base::FilePath& database_dir,
-                                  const leveldb_env::Options& options,
-                                  Callbacks::InitCallback callback) {
-  database_dir_ = database_dir;
-  options_ = options;
-  db_wrapper_->SetMetricsId(client_name);
-  Init(std::string(client_name),
-       base::BindOnce(
-           [](Callbacks::InitCallback callback, Enums::InitStatus status) {
-             std::move(callback).Run(status == Enums::InitStatus::kOK);
-           },
-           std::move(callback)));
-}
-
-template <typename T>
-void UniqueProtoDatabase<T>::InitWithDatabase(
-    LevelDB* database,
-    const base::FilePath& database_dir,
-    const leveldb_env::Options& options,
-    Callbacks::InitStatusCallback callback) {
-  // We set |destroy_on_corruption| to true to preserve the original behaviour
-  // where database corruption led to automatic destruction.
-  db_wrapper_->InitWithDatabase(database, database_dir, options,
-                                true /* destroy_on_corruption */,
-                                std::move(callback));
-}
-
-template <typename T>
-void UniqueProtoDatabase<T>::UpdateEntries(
-    std::unique_ptr<typename Util::Internal<T>::KeyEntryVector> entries_to_save,
-    std::unique_ptr<std::vector<std::string>> keys_to_remove,
-    Callbacks::UpdateCallback callback) {
-  db_wrapper_->template UpdateEntries<T>(std::move(entries_to_save),
-                                         std::move(keys_to_remove),
-                                         std::move(callback));
-}
-
-template <typename T>
-void UniqueProtoDatabase<T>::UpdateEntriesWithRemoveFilter(
-    std::unique_ptr<typename Util::Internal<T>::KeyEntryVector> entries_to_save,
-    const KeyFilter& delete_key_filter,
-    Callbacks::UpdateCallback callback) {
-  db_wrapper_->template UpdateEntriesWithRemoveFilter<T>(
-      std::move(entries_to_save), delete_key_filter, std::move(callback));
-}
-
-template <typename T>
-void UniqueProtoDatabase<T>::UpdateEntriesWithRemoveFilter(
-    std::unique_ptr<typename Util::Internal<T>::KeyEntryVector> entries_to_save,
-    const KeyFilter& delete_key_filter,
-    const std::string& target_prefix,
-    Callbacks::UpdateCallback callback) {
-  db_wrapper_->template UpdateEntriesWithRemoveFilter<T>(
-      std::move(entries_to_save), delete_key_filter, target_prefix,
-      std::move(callback));
-}
-
-template <typename T>
-void UniqueProtoDatabase<T>::LoadEntries(
-    typename Callbacks::Internal<T>::LoadCallback callback) {
-  db_wrapper_->template LoadEntries<T>(std::move(callback));
-}
-
-template <typename T>
-void UniqueProtoDatabase<T>::LoadEntriesWithFilter(
-    const KeyFilter& filter,
-    typename Callbacks::Internal<T>::LoadCallback callback) {
-  db_wrapper_->template LoadEntriesWithFilter<T>(filter, std::move(callback));
-}
-
-template <typename T>
-void UniqueProtoDatabase<T>::LoadEntriesWithFilter(
-    const KeyFilter& key_filter,
-    const leveldb::ReadOptions& options,
-    const std::string& target_prefix,
-    typename Callbacks::Internal<T>::LoadCallback callback) {
-  db_wrapper_->template LoadEntriesWithFilter<T>(
-      key_filter, options, target_prefix, std::move(callback));
-}
-
-template <typename T>
-void UniqueProtoDatabase<T>::LoadKeysAndEntries(
-    typename Callbacks::Internal<T>::LoadKeysAndEntriesCallback callback) {
-  db_wrapper_->template LoadKeysAndEntries<T>(std::move(callback));
-}
-
-template <typename T>
-void UniqueProtoDatabase<T>::LoadKeysAndEntriesWithFilter(
-    const KeyFilter& filter,
-    typename Callbacks::Internal<T>::LoadKeysAndEntriesCallback callback) {
-  db_wrapper_->template LoadKeysAndEntriesWithFilter<T>(filter,
-                                                        std::move(callback));
-}
-
-template <typename T>
-void UniqueProtoDatabase<T>::LoadKeysAndEntriesWithFilter(
-    const KeyFilter& filter,
-    const leveldb::ReadOptions& options,
-    const std::string& target_prefix,
-    typename Callbacks::Internal<T>::LoadKeysAndEntriesCallback callback) {
-  db_wrapper_->template LoadKeysAndEntriesWithFilter<T>(
-      filter, options, target_prefix, std::move(callback));
-}
-
-template <typename T>
-void UniqueProtoDatabase<T>::LoadKeysAndEntriesInRange(
-    const std::string& start,
-    const std::string& end,
-    typename Callbacks::Internal<T>::LoadKeysAndEntriesCallback callback) {
-  db_wrapper_->template LoadKeysAndEntriesInRange<T>(start, end,
-                                                     std::move(callback));
-}
-
-template <typename T>
-void UniqueProtoDatabase<T>::LoadKeys(Callbacks::LoadKeysCallback callback) {
-  db_wrapper_->LoadKeys(std::move(callback));
-}
-
-template <typename T>
-void UniqueProtoDatabase<T>::LoadKeys(const std::string& target_prefix,
-                                      Callbacks::LoadKeysCallback callback) {
-  db_wrapper_->LoadKeys(target_prefix, std::move(callback));
-}
-
-template <typename T>
-void UniqueProtoDatabase<T>::GetEntry(
-    const std::string& key,
-    typename Callbacks::Internal<T>::GetCallback callback) {
-  db_wrapper_->template GetEntry<T>(key, std::move(callback));
-}
-
-template <typename T>
-void UniqueProtoDatabase<T>::Destroy(Callbacks::DestroyCallback callback) {
-  db_wrapper_->Destroy(std::move(callback));
-}
-
-template <typename T>
-void UniqueProtoDatabase<T>::RemoveKeysForTesting(
-    const KeyFilter& key_filter,
-    const std::string& target_prefix,
-    Callbacks::UpdateCallback callback) {
-  db_wrapper_->RemoveKeys(key_filter, target_prefix, std::move(callback));
-}
-
-template <typename T>
-bool UniqueProtoDatabase<T>::GetApproximateMemoryUse(uint64_t* approx_mem_use) {
-  return db_wrapper_->GetApproximateMemoryUse(approx_mem_use);
-}
-
-template <typename T>
-void UniqueProtoDatabase<T>::SetMetricsId(const std::string& id) {
-  db_wrapper_->SetMetricsId(id);
-}
-
 }  // namespace leveldb_proto
 
 #endif  // COMPONENTS_LEVELDB_PROTO_INTERNAL_UNIQUE_PROTO_DATABASE_H_
diff --git a/components/leveldb_proto/internal/unique_proto_database_unittest.cc b/components/leveldb_proto/internal/unique_proto_database_unittest.cc
index e9c3c20..71dcb9c7 100644
--- a/components/leveldb_proto/internal/unique_proto_database_unittest.cc
+++ b/components/leveldb_proto/internal/unique_proto_database_unittest.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "components/leveldb_proto/internal/unique_proto_database.h"
+#include "components/leveldb_proto/public/proto_database.h"
 
 #include <stddef.h>
 
@@ -21,7 +21,8 @@
 #include "base/threading/thread.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "components/leveldb_proto/internal/leveldb_database.h"
-#include "components/leveldb_proto/public/proto_database.h"
+#include "components/leveldb_proto/internal/proto_database_impl.h"
+#include "components/leveldb_proto/public/proto_database_provider.h"
 #include "components/leveldb_proto/testing/proto/test_db.pb.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -220,8 +221,8 @@
   UniqueProtoDatabaseTest()
       : options_(MakeMatcher(new OptionsEqMatcher(CreateSimpleOptions()))) {}
   void SetUp() override {
-    db_.reset(new UniqueProtoDatabase<TestProto>(
-        base::ThreadTaskRunnerHandle::Get()));
+    db_ = std::make_unique<ProtoDatabaseImpl<TestProto>>(
+        base::ThreadTaskRunnerHandle::Get());
   }
 
   void TearDown() override {
@@ -231,7 +232,7 @@
 
   const Matcher<const Options&> options_;
   ScopedTaskEnvironment task_environment_;
-  std::unique_ptr<UniqueProtoDatabase<TestProto>> db_;
+  std::unique_ptr<ProtoDatabaseImpl<TestProto>> db_;
 };
 
 // Test that UniqueProtoDatabase calls Init on the underlying database and that
@@ -426,6 +427,7 @@
   db_->UpdateEntries(std::move(save_entries), std::move(remove_keys),
                      base::BindOnce(&MockDatabaseCaller::SaveCallback,
                                     base::Unretained(&caller)));
+  base::RunLoop().RunUntilIdle();
 
   EXPECT_CALL(caller, LoadKeysAndEntriesCallback1(true, _))
       .WillOnce(VerifyLoadKeysAndEntries(testing::ByRef(expected)));
@@ -467,6 +469,7 @@
   db_->UpdateEntries(std::move(save_entries), std::move(remove_keys),
                      base::BindOnce(&MockDatabaseCaller::SaveCallback,
                                     base::Unretained(&caller)));
+  base::RunLoop().RunUntilIdle();
 
   EXPECT_CALL(caller, LoadKeysAndEntriesCallback1(true, _))
       .WillOnce(VerifyLoadKeysAndEntries(testing::ByRef(expected)));
@@ -545,7 +548,9 @@
         std::move(signal).Run();
       },
       run_update_entries.QuitClosure());
-  db_->RemoveKeysForTesting(
+  ProtoDatabaseImpl<TestProto>* wrapper =
+      reinterpret_cast<ProtoDatabaseImpl<TestProto>*>(db_.get());
+  wrapper->RemoveKeysForTesting(
       base::BindRepeating([](const std::string& str) { return true; }),
       kTestPrefix, std::move(expect_update_success));
   run_update_entries.Run();
@@ -564,15 +569,15 @@
   ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
   base::Thread db_thread("dbthread");
   ASSERT_TRUE(db_thread.Start());
-  std::unique_ptr<UniqueProtoDatabase<TestProto>> db(
-      new UniqueProtoDatabase<TestProto>(db_thread.task_runner()));
+  std::unique_ptr<ProtoDatabase<TestProto>> db =
+      ProtoDatabaseProvider::CreateUniqueDB<TestProto>(db_thread.task_runner());
 
-  MockDatabaseCaller caller;
-  EXPECT_CALL(caller, InitCallback(true));
-
+  base::RunLoop init_loop;
   db->Init(kTestLevelDBClientName, temp_dir.GetPath(), CreateSimpleOptions(),
-           base::BindOnce(&MockDatabaseCaller::InitCallback,
-                          base::Unretained(&caller)));
+           base::BindOnce([](base::OnceClosure closure,
+                             bool success) { std::move(closure).Run(); },
+                          init_loop.QuitClosure()));
+  init_loop.Run();
 
   base::RunLoop run_update_entries;
   auto expect_update_success = base::BindOnce(
@@ -796,8 +801,8 @@
   base::Thread db_thread("dbthread");
   ASSERT_TRUE(db_thread.Start());
 
-  std::unique_ptr<UniqueProtoDatabase<TestProto>> db(
-      new UniqueProtoDatabase<TestProto>(db_thread.task_runner()));
+  std::unique_ptr<ProtoDatabase<TestProto>> db =
+      ProtoDatabaseProvider::CreateUniqueDB<TestProto>(db_thread.task_runner());
 
   MockDatabaseCaller caller;
   EXPECT_CALL(caller, InitCallback(_));
@@ -830,8 +835,8 @@
   base::Thread db_thread("dbthread");
   ASSERT_TRUE(db_thread.Start());
 
-  std::unique_ptr<UniqueProtoDatabase<TestProto>> db(
-      new UniqueProtoDatabase<TestProto>(db_thread.task_runner()));
+  std::unique_ptr<ProtoDatabase<TestProto>> db =
+      ProtoDatabaseProvider::CreateUniqueDB<TestProto>(db_thread.task_runner());
 
   MockDatabaseCaller caller;
   EXPECT_CALL(caller, InitCallback(_));
@@ -847,13 +852,14 @@
   init_loop.Run();
 
   EXPECT_CALL(caller, DestroyCallback(_));
-  db->Destroy(base::BindOnce(&MockDatabaseCaller::DestroyCallback,
-                             base::Unretained(&caller)));
-
-  base::RunLoop run_loop;
-  db_thread.task_runner()->PostTaskAndReply(FROM_HERE, base::DoNothing(),
-                                            run_loop.QuitClosure());
-  run_loop.Run();
+  base::RunLoop destroy_loop;
+  db->Destroy(base::BindOnce(
+      [](MockDatabaseCaller* caller, base::OnceClosure closure, bool success) {
+        caller->DestroyCallback(success);
+        std::move(closure).Run();
+      },
+      &caller, destroy_loop.QuitClosure()));
+  destroy_loop.Run();
 
   // Verify the db is actually destroyed.
   EXPECT_FALSE(base::PathExists(temp_dir.GetPath()));
diff --git a/components/leveldb_proto/public/proto_database.h b/components/leveldb_proto/public/proto_database.h
index 673343a..a8a428d 100644
--- a/components/leveldb_proto/public/proto_database.h
+++ b/components/leveldb_proto/public/proto_database.h
@@ -38,6 +38,14 @@
   using DestroyCallback = base::OnceCallback<void(bool)>;
   using OnCreateCallback = base::OnceCallback<void(ProtoLevelDBWrapper*)>;
 
+  // TODO(ssid): This should be moved to internal folder.
+  using LoadCallback =
+      base::OnceCallback<void(bool, std::unique_ptr<std::vector<std::string>>)>;
+  using GetCallback =
+      base::OnceCallback<void(bool, std::unique_ptr<std::string>)>;
+  using LoadKeysAndEntriesCallback = base::OnceCallback<
+      void(bool, std::unique_ptr<std::map<std::string, std::string>>)>;
+
   template <typename T>
   class Internal {
    public:
diff --git a/components/leveldb_proto/public/proto_database_provider.cc b/components/leveldb_proto/public/proto_database_provider.cc
index a22de781..0ce62bc 100644
--- a/components/leveldb_proto/public/proto_database_provider.cc
+++ b/components/leveldb_proto/public/proto_database_provider.cc
@@ -8,6 +8,7 @@
 #include "base/files/file_path.h"
 #include "base/sequenced_task_runner.h"
 #include "base/synchronization/lock.h"
+#include "base/task/post_task.h"
 #include "base/threading/sequenced_task_runner_handle.h"
 #include "components/leveldb_proto/internal/shared_proto_database.h"
 
diff --git a/components/leveldb_proto/public/proto_database_provider.h b/components/leveldb_proto/public/proto_database_provider.h
index fa3e1352..a5817d5 100644
--- a/components/leveldb_proto/public/proto_database_provider.h
+++ b/components/leveldb_proto/public/proto_database_provider.h
@@ -8,7 +8,7 @@
 #include "base/files/file_path.h"
 #include "base/sequenced_task_runner.h"
 #include "components/keyed_service/core/keyed_service.h"
-#include "components/leveldb_proto/internal/proto_database_wrapper.h"
+#include "components/leveldb_proto/internal/proto_database_impl.h"
 #include "components/leveldb_proto/internal/shared_proto_database_provider.h"
 #include "components/leveldb_proto/public/proto_database.h"
 
@@ -28,7 +28,7 @@
   template <typename T>
   static std::unique_ptr<ProtoDatabase<T>> CreateUniqueDB(
       const scoped_refptr<base::SequencedTaskRunner>& task_runner) {
-    return std::make_unique<UniqueProtoDatabase<T>>(task_runner);
+    return std::make_unique<ProtoDatabaseImpl<T>>(task_runner);
   }
 
   // |client_namespace| is the unique prefix to be used in the shared database
@@ -55,7 +55,7 @@
 
  private:
   friend class TestProtoDatabaseProvider;
-  friend class ProtoDatabaseWrapperTest;
+  friend class ProtoDatabaseImplTest;
 
   ProtoDatabaseProvider(const base::FilePath& profile_dir);
 
@@ -82,7 +82,7 @@
     const std::string& type_prefix,
     const base::FilePath& unique_db_dir,
     const scoped_refptr<base::SequencedTaskRunner>& task_runner) {
-  return base::WrapUnique(new ProtoDatabaseWrapper<T>(
+  return base::WrapUnique(new ProtoDatabaseImpl<T>(
       client_namespace, type_prefix, unique_db_dir, task_runner,
       base::WrapUnique(new SharedProtoDatabaseProvider(
           creation_sequence_, weak_factory_.GetWeakPtr()))));
diff --git a/components/leveldb_proto/testing/fake_db.h b/components/leveldb_proto/testing/fake_db.h
index c328ed2..5cf5616 100644
--- a/components/leveldb_proto/testing/fake_db.h
+++ b/components/leveldb_proto/testing/fake_db.h
@@ -16,14 +16,14 @@
 #include "base/files/file_path.h"
 #include "base/task/post_task.h"
 #include "base/test/test_simple_task_runner.h"
-#include "components/leveldb_proto/internal/unique_proto_database.h"
+#include "components/leveldb_proto/internal/proto_database_impl.h"
 #include "components/leveldb_proto/public/proto_database.h"
 
 namespace leveldb_proto {
 namespace test {
 
 template <typename T>
-class FakeDB : public UniqueProtoDatabase<T> {
+class FakeDB : public ProtoDatabaseImpl<T> {
   using Callback = base::OnceCallback<void(bool)>;
 
  public:
@@ -138,8 +138,7 @@
 
 template <typename T>
 FakeDB<T>::FakeDB(EntryMap* db)
-    : UniqueProtoDatabase<T>(
-          base::MakeRefCounted<base::TestSimpleTaskRunner>()) {
+    : ProtoDatabaseImpl<T>(base::MakeRefCounted<base::TestSimpleTaskRunner>()) {
   db_ = db;
 }
 
diff --git a/components/mpris/BUILD.gn b/components/mpris/BUILD.gn
new file mode 100644
index 0000000..0dd4235
--- /dev/null
+++ b/components/mpris/BUILD.gn
@@ -0,0 +1,44 @@
+# 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.
+
+import("//build/buildflag_header.gni")
+import("//components/mpris/features.gni")
+
+buildflag_header("buildflags") {
+  header = "buildflags.h"
+  flags = [ "USE_MPRIS=$use_mpris" ]
+}
+
+component("mpris") {
+  sources = [
+    "mpris_service.cc",
+    "mpris_service.h",
+    "mpris_service_observer.h",
+  ]
+
+  defines = [ "IS_MPRIS_IMPL" ]
+
+  deps = [
+    "//base",
+    "//components/dbus:dbus_thread_linux",
+    "//dbus",
+  ]
+}
+
+source_set("unit_tests") {
+  testonly = true
+  sources = [
+    "mpris_service_unittest.cc",
+  ]
+  deps = [
+    ":mpris",
+    "//base",
+    "//base/test:test_support",
+    "//components/dbus:dbus_thread_linux",
+    "//dbus",
+    "//dbus:test_support",
+    "//testing/gmock",
+    "//testing/gtest",
+  ]
+}
diff --git a/components/mpris/DEPS b/components/mpris/DEPS
new file mode 100644
index 0000000..db0da64a
--- /dev/null
+++ b/components/mpris/DEPS
@@ -0,0 +1,4 @@
+include_rules = [
+  "+components/dbus",
+  "+dbus",
+]
diff --git a/components/mpris/OWNERS b/components/mpris/OWNERS
new file mode 100644
index 0000000..7403412
--- /dev/null
+++ b/components/mpris/OWNERS
@@ -0,0 +1,2 @@
+steimel@chromium.org
+thomasanderson@chromium.org
diff --git a/components/mpris/features.gni b/components/mpris/features.gni
new file mode 100644
index 0000000..d3dc1f2
--- /dev/null
+++ b/components/mpris/features.gni
@@ -0,0 +1,9 @@
+# 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.
+
+import("//build/config/features.gni")
+
+declare_args() {
+  use_mpris = is_desktop_linux && use_dbus
+}
diff --git a/components/mpris/mpris_service.cc b/components/mpris/mpris_service.cc
new file mode 100644
index 0000000..0e674a5
--- /dev/null
+++ b/components/mpris/mpris_service.cc
@@ -0,0 +1,423 @@
+// 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/mpris/mpris_service.h"
+
+#include <memory>
+#include <utility>
+#include <vector>
+
+#include "base/bind.h"
+#include "base/process/process.h"
+#include "base/unguessable_token.h"
+#include "base/values.h"
+#include "components/dbus/dbus_thread_linux.h"
+#include "components/mpris/mpris_service_observer.h"
+#include "dbus/bus.h"
+#include "dbus/exported_object.h"
+#include "dbus/message.h"
+#include "dbus/object_path.h"
+#include "dbus/property.h"
+#include "dbus/values_util.h"
+
+namespace mpris {
+
+namespace {
+
+constexpr int kNumMethodsToExport = 14;
+
+}  // namespace
+
+#if defined(GOOGLE_CHROME_BUILD)
+const char kMprisAPIServiceNamePrefix[] =
+    "org.mpris.MediaPlayer2.chrome.instance";
+#else
+const char kMprisAPIServiceNamePrefix[] =
+    "org.mpris.MediaPlayer2.chromium.instance";
+#endif
+const char kMprisAPIObjectPath[] = "/org/mpris/MediaPlayer2";
+const char kMprisAPIInterfaceName[] = "org.mpris.MediaPlayer2";
+const char kMprisAPIPlayerInterfaceName[] = "org.mpris.MediaPlayer2.Player";
+
+// static
+MprisService* MprisService::instance_ = nullptr;
+
+// static
+MprisService* MprisService::GetInstance() {
+  return instance_;
+}
+
+MprisService::MprisService()
+    : service_name_(std::string(kMprisAPIServiceNamePrefix) +
+                    std::to_string(base::Process::Current().Pid())) {
+  DCHECK_EQ(nullptr, instance_);
+  instance_ = this;
+
+  InitializeProperties();
+}
+
+MprisService::~MprisService() {
+  DCHECK_EQ(instance_, this);
+  instance_ = nullptr;
+
+  if (bus_) {
+    dbus_thread_linux::GetTaskRunner()->PostTask(
+        FROM_HERE, base::BindOnce(&dbus::Bus::ShutdownAndBlock, bus_));
+  }
+}
+
+void MprisService::StartService() {
+  InitializeDbusInterface();
+}
+
+void MprisService::AddObserver(MprisServiceObserver* observer) {
+  observers_.AddObserver(observer);
+
+  // If the service is already ready, inform the observer.
+  if (service_ready_)
+    observer->OnServiceReady();
+}
+
+void MprisService::RemoveObserver(MprisServiceObserver* observer) {
+  observers_.RemoveObserver(observer);
+}
+
+void MprisService::SetCanGoNext(bool value) {
+  SetPropertyInternal(media_player2_player_properties_, "CanGoNext",
+                      base::Value(value));
+}
+
+void MprisService::SetCanGoPrevious(bool value) {
+  SetPropertyInternal(media_player2_player_properties_, "CanGoPrevious",
+                      base::Value(value));
+}
+
+void MprisService::SetCanPlay(bool value) {
+  SetPropertyInternal(media_player2_player_properties_, "CanPlay",
+                      base::Value(value));
+}
+
+void MprisService::SetCanPause(bool value) {
+  SetPropertyInternal(media_player2_player_properties_, "CanPause",
+                      base::Value(value));
+}
+
+std::string MprisService::GetServiceName() const {
+  return service_name_;
+}
+
+void MprisService::InitializeProperties() {
+  // org.mpris.MediaPlayer2 interface properties.
+  media_player2_properties_["CanQuit"] = base::Value(false);
+  media_player2_properties_["CanRaise"] = base::Value(false);
+  media_player2_properties_["HasTrackList"] = base::Value(false);
+#if defined(GOOGLE_CHROME_BUILD)
+  media_player2_properties_["Identity"] = base::Value("Chrome");
+#else
+  media_player2_properties_["Identity"] = base::Value("Chromium");
+#endif
+  media_player2_properties_["SupportedUriSchemes"] =
+      base::Value(base::Value::Type::LIST);
+  media_player2_properties_["SupportedMimeTypes"] =
+      base::Value(base::Value::Type::LIST);
+
+  // org.mpris.MediaPlayer2.Player interface properties.
+  media_player2_player_properties_["PlaybackStatus"] = base::Value("Stopped");
+  media_player2_player_properties_["Rate"] = base::Value(1.0);
+  media_player2_player_properties_["Metadata"] =
+      base::Value(base::Value::DictStorage());
+  media_player2_player_properties_["Volume"] = base::Value(1.0);
+  media_player2_player_properties_["Position"] = base::Value(0);
+  media_player2_player_properties_["MinimumRate"] = base::Value(1.0);
+  media_player2_player_properties_["MaximumRate"] = base::Value(1.0);
+  media_player2_player_properties_["CanGoNext"] = base::Value(false);
+  media_player2_player_properties_["CanGoPrevious"] = base::Value(false);
+  media_player2_player_properties_["CanPlay"] = base::Value(false);
+  media_player2_player_properties_["CanPause"] = base::Value(false);
+  media_player2_player_properties_["CanSeek"] = base::Value(false);
+  media_player2_player_properties_["CanControl"] = base::Value(true);
+}
+
+void MprisService::InitializeDbusInterface() {
+  // Bus may be set for testing.
+  if (!bus_) {
+    dbus::Bus::Options bus_options;
+    bus_options.bus_type = dbus::Bus::SESSION;
+    bus_options.connection_type = dbus::Bus::PRIVATE;
+    bus_options.dbus_task_runner = dbus_thread_linux::GetTaskRunner();
+    bus_ = base::MakeRefCounted<dbus::Bus>(bus_options);
+  }
+
+  exported_object_ =
+      bus_->GetExportedObject(dbus::ObjectPath(kMprisAPIObjectPath));
+  int num_methods_attempted_to_export = 0;
+
+  // Helper lambdas for exporting methods while keeping track of the number of
+  // exported methods.
+  auto export_method =
+      [&](const std::string& interface_name, const std::string& method_name,
+          dbus::ExportedObject::MethodCallCallback method_call_callback) {
+        exported_object_->ExportMethod(
+            interface_name, method_name, method_call_callback,
+            base::BindRepeating(&MprisService::OnExported,
+                                base::Unretained(this)));
+        num_methods_attempted_to_export++;
+      };
+  auto export_unhandled_method = [&](const std::string& interface_name,
+                                     const std::string& method_name) {
+    export_method(
+        interface_name, method_name,
+        base::BindRepeating(&MprisService::DoNothing, base::Unretained(this)));
+  };
+
+  // Set up org.mpris.MediaPlayer2 interface.
+  // https://specifications.freedesktop.org/mpris-spec/2.2/Media_Player.html
+  export_unhandled_method(kMprisAPIInterfaceName, "Raise");
+  export_unhandled_method(kMprisAPIInterfaceName, "Quit");
+
+  // Set up org.mpris.MediaPlayer2.Player interface.
+  // https://specifications.freedesktop.org/mpris-spec/2.2/Player_Interface.html
+  export_method(
+      kMprisAPIPlayerInterfaceName, "Next",
+      base::BindRepeating(&MprisService::Next, base::Unretained(this)));
+  export_method(
+      kMprisAPIPlayerInterfaceName, "Previous",
+      base::BindRepeating(&MprisService::Previous, base::Unretained(this)));
+  export_method(
+      kMprisAPIPlayerInterfaceName, "Pause",
+      base::BindRepeating(&MprisService::Pause, base::Unretained(this)));
+  export_method(
+      kMprisAPIPlayerInterfaceName, "PlayPause",
+      base::BindRepeating(&MprisService::PlayPause, base::Unretained(this)));
+  export_method(
+      kMprisAPIPlayerInterfaceName, "Stop",
+      base::BindRepeating(&MprisService::Stop, base::Unretained(this)));
+  export_method(
+      kMprisAPIPlayerInterfaceName, "Play",
+      base::BindRepeating(&MprisService::Play, base::Unretained(this)));
+  export_unhandled_method(kMprisAPIPlayerInterfaceName, "Seek");
+  export_unhandled_method(kMprisAPIPlayerInterfaceName, "SetPosition");
+  export_unhandled_method(kMprisAPIPlayerInterfaceName, "OpenUri");
+
+  // Set up org.freedesktop.DBus.Properties interface.
+  // https://dbus.freedesktop.org/doc/dbus-specification.html#standard-interfaces-properties
+  export_method(dbus::kPropertiesInterface, dbus::kPropertiesGetAll,
+                base::BindRepeating(&MprisService::GetAllProperties,
+                                    base::Unretained(this)));
+  export_method(
+      dbus::kPropertiesInterface, dbus::kPropertiesGet,
+      base::BindRepeating(&MprisService::GetProperty, base::Unretained(this)));
+  export_unhandled_method(dbus::kPropertiesInterface, dbus::kPropertiesSet);
+
+  DCHECK_EQ(kNumMethodsToExport, num_methods_attempted_to_export);
+}
+
+void MprisService::OnExported(const std::string& interface_name,
+                              const std::string& method_name,
+                              bool success) {
+  if (success)
+    num_methods_exported_++;
+
+  // Still waiting for more methods to finish exporting.
+  if (num_methods_exported_ < kNumMethodsToExport)
+    return;
+
+  bus_->RequestOwnership(
+      service_name_, dbus::Bus::ServiceOwnershipOptions::REQUIRE_PRIMARY,
+      base::BindRepeating(&MprisService::OnOwnership, base::Unretained(this)));
+}
+
+void MprisService::OnOwnership(const std::string& service_name, bool success) {
+  DCHECK(success);
+  service_ready_ = true;
+
+  for (MprisServiceObserver& obs : observers_)
+    obs.OnServiceReady();
+}
+
+void MprisService::Next(dbus::MethodCall* method_call,
+                        dbus::ExportedObject::ResponseSender response_sender) {
+  for (MprisServiceObserver& obs : observers_)
+    obs.OnNext();
+  response_sender.Run(dbus::Response::FromMethodCall(method_call));
+}
+
+void MprisService::Previous(
+    dbus::MethodCall* method_call,
+    dbus::ExportedObject::ResponseSender response_sender) {
+  for (MprisServiceObserver& obs : observers_)
+    obs.OnPrevious();
+  response_sender.Run(dbus::Response::FromMethodCall(method_call));
+}
+
+void MprisService::Pause(dbus::MethodCall* method_call,
+                         dbus::ExportedObject::ResponseSender response_sender) {
+  for (MprisServiceObserver& obs : observers_)
+    obs.OnPause();
+  response_sender.Run(dbus::Response::FromMethodCall(method_call));
+}
+
+void MprisService::PlayPause(
+    dbus::MethodCall* method_call,
+    dbus::ExportedObject::ResponseSender response_sender) {
+  for (MprisServiceObserver& obs : observers_)
+    obs.OnPlayPause();
+  response_sender.Run(dbus::Response::FromMethodCall(method_call));
+}
+
+void MprisService::Stop(dbus::MethodCall* method_call,
+                        dbus::ExportedObject::ResponseSender response_sender) {
+  for (MprisServiceObserver& obs : observers_)
+    obs.OnStop();
+  response_sender.Run(dbus::Response::FromMethodCall(method_call));
+}
+
+void MprisService::Play(dbus::MethodCall* method_call,
+                        dbus::ExportedObject::ResponseSender response_sender) {
+  for (MprisServiceObserver& obs : observers_)
+    obs.OnPlay();
+  response_sender.Run(dbus::Response::FromMethodCall(method_call));
+}
+
+void MprisService::DoNothing(
+    dbus::MethodCall* method_call,
+    dbus::ExportedObject::ResponseSender response_sender) {
+  response_sender.Run(dbus::Response::FromMethodCall(method_call));
+}
+
+// org.freedesktop.DBus.Properties.GetAll(in STRING interface_name,
+//                                        out DICT<STRING,VARIANT> props);
+void MprisService::GetAllProperties(
+    dbus::MethodCall* method_call,
+    dbus::ExportedObject::ResponseSender response_sender) {
+  dbus::MessageReader reader(method_call);
+  std::string interface;
+  if (!reader.PopString(&interface)) {
+    response_sender.Run(nullptr);
+    return;
+  }
+
+  std::unique_ptr<dbus::Response> response =
+      dbus::Response::FromMethodCall(method_call);
+  dbus::MessageWriter writer(response.get());
+
+  if (interface == kMprisAPIInterfaceName) {
+    AddPropertiesToWriter(&writer, media_player2_properties_);
+  } else if (interface == kMprisAPIPlayerInterfaceName) {
+    AddPropertiesToWriter(&writer, media_player2_player_properties_);
+  } else if (interface == dbus::kPropertiesInterface) {
+    // There are no properties to give for this interface.
+    PropertyMap empty_properties_map;
+    AddPropertiesToWriter(&writer, empty_properties_map);
+  } else {
+    // The given interface is not supported, so return a null response.
+    response_sender.Run(nullptr);
+    return;
+  }
+
+  response_sender.Run(std::move(response));
+}
+
+// org.freedesktop.DBus.Properties.Get(in STRING interface_name,
+//                                     in STRING property_name,
+//                                     out VARIANT value);
+void MprisService::GetProperty(
+    dbus::MethodCall* method_call,
+    dbus::ExportedObject::ResponseSender response_sender) {
+  dbus::MessageReader reader(method_call);
+  std::string interface;
+  if (!reader.PopString(&interface)) {
+    response_sender.Run(nullptr);
+    return;
+  }
+
+  std::string property_name;
+  if (!reader.PopString(&property_name)) {
+    response_sender.Run(nullptr);
+    return;
+  }
+
+  std::unique_ptr<dbus::Response> response =
+      dbus::Response::FromMethodCall(method_call);
+  dbus::MessageWriter writer(response.get());
+
+  bool success = false;
+  if (interface == kMprisAPIInterfaceName) {
+    auto property_iter = media_player2_properties_.find(property_name);
+    if (property_iter != media_player2_properties_.end()) {
+      dbus::AppendValueDataAsVariant(&writer, property_iter->second);
+      success = true;
+    }
+  } else if (interface == kMprisAPIPlayerInterfaceName) {
+    auto property_iter = media_player2_player_properties_.find(property_name);
+    if (property_iter != media_player2_player_properties_.end()) {
+      dbus::AppendValueDataAsVariant(&writer, property_iter->second);
+      success = true;
+    }
+  }
+
+  // If we don't support the given property, return a null response.
+  if (!success) {
+    response_sender.Run(nullptr);
+    return;
+  }
+
+  response_sender.Run(std::move(response));
+}
+
+void MprisService::AddPropertiesToWriter(dbus::MessageWriter* writer,
+                                         const PropertyMap& properties) {
+  DCHECK(writer);
+
+  dbus::MessageWriter array_writer(nullptr);
+  dbus::MessageWriter dict_entry_writer(nullptr);
+
+  writer->OpenArray("{sv}", &array_writer);
+
+  for (auto& property : properties) {
+    array_writer.OpenDictEntry(&dict_entry_writer);
+    dict_entry_writer.AppendString(property.first);
+    dbus::AppendValueDataAsVariant(&dict_entry_writer, property.second);
+    array_writer.CloseContainer(&dict_entry_writer);
+  }
+
+  writer->CloseContainer(&array_writer);
+}
+
+void MprisService::SetPropertyInternal(PropertyMap& property_map,
+                                       const std::string& property_name,
+                                       const base::Value& new_value) {
+  if (property_map[property_name] == new_value)
+    return;
+
+  property_map[property_name] = new_value.Clone();
+
+  PropertyMap changed_properties;
+  changed_properties[property_name] = new_value.Clone();
+  EmitPropertiesChangedSignal(changed_properties);
+}
+
+void MprisService::EmitPropertiesChangedSignal(
+    const PropertyMap& changed_properties) {
+  if (!bus_ || !exported_object_)
+    return;
+
+  // |signal| follows the PropertiesChanged API:
+  // org.freedesktop.DBus.Properties.PropertiesChanged(
+  //     STRING interface_name,
+  //     DICT<STRING,VARIANT> changed_properties,
+  //     ARRAY<STRING> invalidated_properties);
+  dbus::Signal signal(dbus::kPropertiesInterface, dbus::kPropertiesChanged);
+  dbus::MessageWriter writer(&signal);
+  writer.AppendString(kMprisAPIPlayerInterfaceName);
+
+  AddPropertiesToWriter(&writer, changed_properties);
+
+  std::vector<std::string> empty_invalidated_properties;
+  writer.AppendArrayOfStrings(empty_invalidated_properties);
+
+  exported_object_->SendSignal(&signal);
+}
+
+}  // namespace mpris
diff --git a/components/mpris/mpris_service.h b/components/mpris/mpris_service.h
new file mode 100644
index 0000000..149d21c
--- /dev/null
+++ b/components/mpris/mpris_service.h
@@ -0,0 +1,140 @@
+// 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_MPRIS_MPRIS_SERVICE_H_
+#define COMPONENTS_MPRIS_MPRIS_SERVICE_H_
+
+#include <string>
+
+#include "base/component_export.h"
+#include "base/containers/flat_map.h"
+#include "base/memory/scoped_refptr.h"
+#include "base/observer_list.h"
+#include "dbus/bus.h"
+#include "dbus/exported_object.h"
+
+namespace base {
+class Value;
+}  // namespace base
+
+namespace dbus {
+class MessageWriter;
+class MethodCall;
+}  // namespace dbus
+
+namespace mpris {
+
+class MprisServiceObserver;
+
+COMPONENT_EXPORT(MPRIS) extern const char kMprisAPIServiceNamePrefix[];
+COMPONENT_EXPORT(MPRIS) extern const char kMprisAPIObjectPath[];
+COMPONENT_EXPORT(MPRIS) extern const char kMprisAPIInterfaceName[];
+COMPONENT_EXPORT(MPRIS) extern const char kMprisAPIPlayerInterfaceName[];
+
+// A D-Bus service conforming to the MPRIS spec:
+// https://specifications.freedesktop.org/mpris-spec/latest/
+class COMPONENT_EXPORT(MPRIS) MprisService {
+ public:
+  MprisService();
+  ~MprisService();
+
+  static MprisService* GetInstance();
+
+  // Starts the DBus service.
+  void StartService();
+
+  void AddObserver(MprisServiceObserver* observer);
+  void RemoveObserver(MprisServiceObserver* observer);
+
+  // Setters for properties.
+  void SetCanGoNext(bool value);
+  void SetCanGoPrevious(bool value);
+  void SetCanPlay(bool value);
+  void SetCanPause(bool value);
+
+  // Returns the generated service name.
+  std::string GetServiceName() const;
+
+  // Used for testing with a mock DBus Bus.
+  void SetBusForTesting(scoped_refptr<dbus::Bus> bus) { bus_ = bus; }
+
+ private:
+  // MprisService can only have one instance. This holds a pointer to that
+  // instance.
+  static MprisService* instance_;
+
+  void InitializeProperties();
+  void InitializeDbusInterface();
+  void OnExported(const std::string& interface_name,
+                  const std::string& method_name,
+                  bool success);
+  void OnOwnership(const std::string& service_name, bool success);
+
+  // org.mpris.MediaPlayer2.Player interface.
+  void Next(dbus::MethodCall* method_call,
+            dbus::ExportedObject::ResponseSender response_sender);
+  void Previous(dbus::MethodCall* method_call,
+                dbus::ExportedObject::ResponseSender response_sender);
+  void Pause(dbus::MethodCall* method_call,
+             dbus::ExportedObject::ResponseSender response_sender);
+  void PlayPause(dbus::MethodCall* method_call,
+                 dbus::ExportedObject::ResponseSender response_sender);
+  void Stop(dbus::MethodCall* method_call,
+            dbus::ExportedObject::ResponseSender response_sender);
+  void Play(dbus::MethodCall* method_call,
+            dbus::ExportedObject::ResponseSender response_sender);
+
+  // Used for API methods we don't support.
+  void DoNothing(dbus::MethodCall* method_call,
+                 dbus::ExportedObject::ResponseSender response_sender);
+
+  // org.freedesktop.DBus.Properties interface.
+  void GetAllProperties(dbus::MethodCall* method_call,
+                        dbus::ExportedObject::ResponseSender response_sender);
+  void GetProperty(dbus::MethodCall* method_call,
+                   dbus::ExportedObject::ResponseSender response_sender);
+
+  using PropertyMap = base::flat_map<std::string, base::Value>;
+
+  // Sets a value on the given PropertyMap and sends a PropertiesChanged signal
+  // if necessary.
+  void SetPropertyInternal(PropertyMap& property_map,
+                           const std::string& property_name,
+                           const base::Value& new_value);
+
+  // Emits a org.freedesktop.DBus.Properties.PropertiesChanged signal for the
+  // given map of changed properties.
+  void EmitPropertiesChangedSignal(const PropertyMap& changed_properties);
+
+  // Writes all properties onto writer.
+  void AddPropertiesToWriter(dbus::MessageWriter* writer,
+                             const PropertyMap& properties);
+
+  // Map of org.mpris.MediaPlayer2 interface properties.
+  PropertyMap media_player2_properties_;
+
+  // Map of org.mpris.MediaPlayer2.Player interface properties.
+  PropertyMap media_player2_player_properties_;
+
+  scoped_refptr<dbus::Bus> bus_;
+  dbus::ExportedObject* exported_object_;
+
+  // The generated service name given to |bus_| when requesting ownership.
+  const std::string service_name_;
+
+  // The number of methods that have been successfully exported through
+  // |exported_object_|.
+  int num_methods_exported_ = 0;
+
+  // True if we have finished creating the DBus service and received ownership.
+  bool service_ready_ = false;
+
+  base::ObserverList<MprisServiceObserver> observers_;
+
+  DISALLOW_COPY_AND_ASSIGN(MprisService);
+};
+
+}  // namespace mpris
+
+#endif  // COMPONENTS_MPRIS_MPRIS_SERVICE_H_
diff --git a/components/mpris/mpris_service_observer.h b/components/mpris/mpris_service_observer.h
new file mode 100644
index 0000000..3a269b9
--- /dev/null
+++ b/components/mpris/mpris_service_observer.h
@@ -0,0 +1,32 @@
+// 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_MPRIS_MPRIS_SERVICE_OBSERVER_H_
+#define COMPONENTS_MPRIS_MPRIS_SERVICE_OBSERVER_H_
+
+#include "base/component_export.h"
+#include "base/observer_list_types.h"
+
+namespace mpris {
+
+// Interface to observe events on the MprisService.
+class COMPONENT_EXPORT(MPRIS) MprisServiceObserver
+    : public base::CheckedObserver {
+ public:
+  // Called when the service has completed setting up.
+  virtual void OnServiceReady() {}
+
+  // Called when the associated method from the org.mpris.MediaPlayer2.Player
+  // interface is called.
+  virtual void OnNext() {}
+  virtual void OnPrevious() {}
+  virtual void OnPause() {}
+  virtual void OnPlayPause() {}
+  virtual void OnStop() {}
+  virtual void OnPlay() {}
+};
+
+}  // namespace mpris
+
+#endif  // COMPONENTS_MPRIS_MPRIS_SERVICE_OBSERVER_H_
diff --git a/components/mpris/mpris_service_unittest.cc b/components/mpris/mpris_service_unittest.cc
new file mode 100644
index 0000000..28e4464d
--- /dev/null
+++ b/components/mpris/mpris_service_unittest.cc
@@ -0,0 +1,255 @@
+// 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/mpris/mpris_service.h"
+
+#include <memory>
+
+#include "base/bind.h"
+#include "base/containers/flat_map.h"
+#include "base/run_loop.h"
+#include "base/test/scoped_task_environment.h"
+#include "components/dbus/dbus_thread_linux.h"
+#include "components/mpris/mpris_service_observer.h"
+#include "dbus/message.h"
+#include "dbus/mock_bus.h"
+#include "dbus/mock_exported_object.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using ::testing::_;
+using ::testing::Invoke;
+using ::testing::Return;
+using ::testing::Unused;
+using ::testing::WithArg;
+
+namespace mpris {
+
+namespace {
+
+constexpr uint32_t kFakeSerial = 123;
+
+}  // anonymous namespace
+
+class MockMprisServiceObserver : public MprisServiceObserver {
+ public:
+  MockMprisServiceObserver() = default;
+  ~MockMprisServiceObserver() override = default;
+
+  // MprisServiceObserver implementation.
+  MOCK_METHOD0(OnServiceReady, void());
+  MOCK_METHOD0(OnNext, void());
+  MOCK_METHOD0(OnPrevious, void());
+  MOCK_METHOD0(OnPause, void());
+  MOCK_METHOD0(OnPlayPause, void());
+  MOCK_METHOD0(OnStop, void());
+  MOCK_METHOD0(OnPlay, void());
+};
+
+class MprisServiceTest : public testing::Test, public MprisServiceObserver {
+ public:
+  MprisServiceTest()
+      : scoped_task_environment_(
+            base::test::ScopedTaskEnvironment::MainThreadType::UI) {}
+  ~MprisServiceTest() override = default;
+
+  void SetUp() override { StartMprisServiceAndWaitForReady(); }
+
+  void AddObserver(MockMprisServiceObserver* observer) {
+    service_->AddObserver(observer);
+  }
+
+  void CallMediaPlayer2PlayerMethodAndBlock(const std::string& method_name) {
+    EXPECT_TRUE(player_interface_exported_methods_.contains(method_name));
+
+    response_wait_loop_ = std::make_unique<base::RunLoop>();
+
+    // We need to supply a serial or the test will crash.
+    dbus::MethodCall method_call(kMprisAPIPlayerInterfaceName, method_name);
+    method_call.SetSerial(kFakeSerial);
+
+    // Call the method and await a response.
+    player_interface_exported_methods_[method_name].Run(
+        &method_call, base::BindRepeating(&MprisServiceTest::OnResponse,
+                                          base::Unretained(this)));
+    response_wait_loop_->Run();
+  }
+
+  MprisService* GetService() { return service_.get(); }
+
+  dbus::MockExportedObject* GetExportedObject() {
+    return mock_exported_object_.get();
+  }
+
+ private:
+  void StartMprisServiceAndWaitForReady() {
+    service_wait_loop_ = std::make_unique<base::RunLoop>();
+    service_ = std::make_unique<mpris::MprisService>();
+
+    SetUpMocks();
+
+    service_->SetBusForTesting(mock_bus_);
+    service_->AddObserver(this);
+    service_->StartService();
+    service_wait_loop_->Run();
+  }
+
+  // Sets up the mock Bus and ExportedObject. The ExportedObject will store the
+  // org.mpris.MediaPlayer2.Player exported methods in the
+  // |player_interface_exported_methods_| map so we can call them for testing.
+  void SetUpMocks() {
+    dbus::Bus::Options options;
+    options.bus_type = dbus::Bus::SESSION;
+    options.connection_type = dbus::Bus::PRIVATE;
+    options.dbus_task_runner = dbus_thread_linux::GetTaskRunner();
+    mock_bus_ = base::MakeRefCounted<dbus::MockBus>(options);
+    mock_exported_object_ = base::MakeRefCounted<dbus::MockExportedObject>(
+        mock_bus_.get(), dbus::ObjectPath(kMprisAPIObjectPath));
+
+    EXPECT_CALL(*mock_bus_,
+                GetExportedObject(dbus::ObjectPath(kMprisAPIObjectPath)))
+        .WillOnce(Return(mock_exported_object_.get()));
+    EXPECT_CALL(*mock_bus_, RequestOwnership(service_->GetServiceName(), _, _))
+        .WillOnce(Invoke(this, &MprisServiceTest::OnOwnership));
+
+    // The service must call ShutdownAndBlock in order to properly clean up the
+    // DBus service.
+    EXPECT_CALL(*mock_bus_, ShutdownAndBlock());
+
+    EXPECT_CALL(*mock_exported_object_, ExportMethod(_, _, _, _))
+        .WillRepeatedly(Invoke(this, &MprisServiceTest::OnExported));
+  }
+
+  // Tell the service that ownership was successful.
+  void OnOwnership(const std::string& service_name,
+                   Unused,
+                   dbus::Bus::OnOwnershipCallback callback) {
+    callback.Run(service_name, true);
+  }
+
+  // Store the exported method if necessary and tell the service that the export
+  // was successful.
+  void OnExported(const std::string& interface_name,
+                  const std::string& method_name,
+                  dbus::ExportedObject::MethodCallCallback exported_method,
+                  dbus::ExportedObject::OnExportedCallback callback) {
+    if (interface_name == kMprisAPIPlayerInterfaceName)
+      player_interface_exported_methods_[method_name] = exported_method;
+    callback.Run(interface_name, method_name, true);
+  }
+
+  void OnResponse(std::unique_ptr<dbus::Response> response) {
+    // A response of nullptr means an error has occurred.
+    EXPECT_NE(nullptr, response.get());
+    if (response_wait_loop_)
+      response_wait_loop_->Quit();
+  }
+
+  // mpris::MprisServiceObserver implementation.
+  void OnServiceReady() override {
+    if (service_wait_loop_)
+      service_wait_loop_->Quit();
+  }
+
+  base::test::ScopedTaskEnvironment scoped_task_environment_;
+  std::unique_ptr<base::RunLoop> service_wait_loop_;
+  std::unique_ptr<base::RunLoop> response_wait_loop_;
+  std::unique_ptr<MprisService> service_;
+  scoped_refptr<dbus::MockBus> mock_bus_;
+  scoped_refptr<dbus::MockExportedObject> mock_exported_object_;
+
+  base::flat_map<std::string, dbus::ExportedObject::MethodCallCallback>
+      player_interface_exported_methods_;
+
+  DISALLOW_COPY_AND_ASSIGN(MprisServiceTest);
+};
+
+TEST_F(MprisServiceTest, ObserverNotifiedOfServiceReadyWhenAdded) {
+  MockMprisServiceObserver observer;
+  EXPECT_CALL(observer, OnServiceReady());
+  AddObserver(&observer);
+}
+
+TEST_F(MprisServiceTest, ObserverNotifiedOfNextCalls) {
+  MockMprisServiceObserver observer;
+  EXPECT_CALL(observer, OnNext());
+  AddObserver(&observer);
+  CallMediaPlayer2PlayerMethodAndBlock("Next");
+}
+
+TEST_F(MprisServiceTest, ObserverNotifiedOfPreviousCalls) {
+  MockMprisServiceObserver observer;
+  EXPECT_CALL(observer, OnPrevious());
+  AddObserver(&observer);
+  CallMediaPlayer2PlayerMethodAndBlock("Previous");
+}
+
+TEST_F(MprisServiceTest, ObserverNotifiedOfPauseCalls) {
+  MockMprisServiceObserver observer;
+  EXPECT_CALL(observer, OnPause());
+  AddObserver(&observer);
+  CallMediaPlayer2PlayerMethodAndBlock("Pause");
+}
+
+TEST_F(MprisServiceTest, ObserverNotifiedOfPlayPauseCalls) {
+  MockMprisServiceObserver observer;
+  EXPECT_CALL(observer, OnPlayPause());
+  AddObserver(&observer);
+  CallMediaPlayer2PlayerMethodAndBlock("PlayPause");
+}
+
+TEST_F(MprisServiceTest, ObserverNotifiedOfStopCalls) {
+  MockMprisServiceObserver observer;
+  EXPECT_CALL(observer, OnStop());
+  AddObserver(&observer);
+  CallMediaPlayer2PlayerMethodAndBlock("Stop");
+}
+
+TEST_F(MprisServiceTest, ObserverNotifiedOfPlayCalls) {
+  MockMprisServiceObserver observer;
+  EXPECT_CALL(observer, OnPlay());
+  AddObserver(&observer);
+  CallMediaPlayer2PlayerMethodAndBlock("Play");
+}
+
+TEST_F(MprisServiceTest, ChangingPropertyEmitsSignal) {
+  // The returned signal should give the changed property.
+  EXPECT_CALL(*GetExportedObject(), SendSignal(_))
+      .WillOnce(WithArg<0>([](dbus::Signal* signal) {
+        EXPECT_NE(nullptr, signal);
+        dbus::MessageReader reader(signal);
+
+        std::string interface_name;
+        ASSERT_TRUE(reader.PopString(&interface_name));
+        EXPECT_EQ(kMprisAPIPlayerInterfaceName, interface_name);
+
+        dbus::MessageReader changed_properties_reader(nullptr);
+        ASSERT_TRUE(reader.PopArray(&changed_properties_reader));
+
+        dbus::MessageReader dict_entry_reader(nullptr);
+        ASSERT_TRUE(changed_properties_reader.PopDictEntry(&dict_entry_reader));
+
+        // The changed property name should be "CanPlay".
+        std::string property_name;
+        ASSERT_TRUE(dict_entry_reader.PopString(&property_name));
+        EXPECT_EQ("CanPlay", property_name);
+
+        // The new value should be true.
+        bool value;
+        ASSERT_TRUE(dict_entry_reader.PopVariantOfBool(&value));
+        EXPECT_EQ(true, value);
+
+        // CanPlay should be the only entry.
+        EXPECT_FALSE(changed_properties_reader.HasMoreData());
+      }));
+
+  // CanPlay is initialized as false, so setting it to true should emit an
+  // org.freedesktop.DBus.Properties.PropertiesChanged signal.
+  GetService()->SetCanPlay(true);
+
+  // Setting it to true again should not re-signal.
+  GetService()->SetCanPlay(true);
+}
+
+}  // namespace mpris
diff --git a/components/ntp_snippets/breaking_news/subscription_manager_impl_unittest.cc b/components/ntp_snippets/breaking_news/subscription_manager_impl_unittest.cc
index fcafe78..a5633d1 100644
--- a/components/ntp_snippets/breaking_news/subscription_manager_impl_unittest.cc
+++ b/components/ntp_snippets/breaking_news/subscription_manager_impl_unittest.cc
@@ -31,7 +31,7 @@
 const char kAPIKey[] = "fakeAPIkey";
 const char kSubscriptionUrl[] = "http://valid-url.test/subscribe";
 const char kSubscriptionUrlSignedIn[] = "http://valid-url.test/subscribe";
-;
+
 const char kSubscriptionUrlSignedOut[] =
     "http://valid-url.test/subscribe?key=fakeAPIkey";
 const char kUnsubscriptionUrl[] = "http://valid-url.test/unsubscribe";
diff --git a/components/ntp_snippets/contextual/reporting/contextual_suggestions_composite_reporter_unittest.cc b/components/ntp_snippets/contextual/reporting/contextual_suggestions_composite_reporter_unittest.cc
index 4cb15e9..ba332a2 100644
--- a/components/ntp_snippets/contextual/reporting/contextual_suggestions_composite_reporter_unittest.cc
+++ b/components/ntp_snippets/contextual/reporting/contextual_suggestions_composite_reporter_unittest.cc
@@ -37,7 +37,7 @@
   ukm::SourceId GetSourceId() { return source_id_; }
   int GetNSetupForPage() { return called_setup_for_page_count_; }
   int GetNRecordEvent() { return called_record_event_count_; }
-  int GetNFlush() { return called_flush_count_; };
+  int GetNFlush() { return called_flush_count_; }
 
   /* Static variables*/
   static int GetReporterDestroyCount() { return reporter_destroy_count_; }
@@ -119,4 +119,4 @@
   EXPECT_EQ(2, TestReporter::GetReporterDestroyCount());
 }
 
-}  // namespace contextual_suggestions
\ No newline at end of file
+}  // namespace contextual_suggestions
diff --git a/components/os_crypt/os_crypt_linux_unittest.cc b/components/os_crypt/os_crypt_linux_unittest.cc
index 58d6da38..b6792d7 100644
--- a/components/os_crypt/os_crypt_linux_unittest.cc
+++ b/components/os_crypt/os_crypt_linux_unittest.cc
@@ -20,7 +20,7 @@
  public:
   OSCryptLinuxTest() : key_("something") { key_ptr_ = &key_; }
 
-  ~OSCryptLinuxTest() override { key_ptr_ = nullptr; };
+  ~OSCryptLinuxTest() override { key_ptr_ = nullptr; }
 
   void SetUp() override {
     OSCryptMockerLinux::SetUp();
diff --git a/components/os_crypt/os_crypt_unittest.cc b/components/os_crypt/os_crypt_unittest.cc
index 753d3fc..b25cc28 100644
--- a/components/os_crypt/os_crypt_unittest.cc
+++ b/components/os_crypt/os_crypt_unittest.cc
@@ -152,7 +152,7 @@
  public:
   OSCryptConcurrencyTest() { OSCryptMocker::SetUp(); }
 
-  ~OSCryptConcurrencyTest() override { OSCryptMocker::TearDown(); };
+  ~OSCryptConcurrencyTest() override { OSCryptMocker::TearDown(); }
 
  private:
   DISALLOW_COPY_AND_ASSIGN(OSCryptConcurrencyTest);
diff --git a/components/send_tab_to_self/BUILD.gn b/components/send_tab_to_self/BUILD.gn
index b6bca20f..7c92a1b8 100644
--- a/components/send_tab_to_self/BUILD.gn
+++ b/components/send_tab_to_self/BUILD.gn
@@ -11,8 +11,8 @@
     "send_tab_to_self_model.cc",
     "send_tab_to_self_model.h",
     "send_tab_to_self_model_observer.h",
-    "send_tab_to_self_service.cc",
-    "send_tab_to_self_service.h",
+    "send_tab_to_self_sync_service.cc",
+    "send_tab_to_self_sync_service.h",
   ]
   deps = [
     "//base",
diff --git a/components/send_tab_to_self/send_tab_to_self_service.cc b/components/send_tab_to_self/send_tab_to_self_sync_service.cc
similarity index 79%
rename from components/send_tab_to_self/send_tab_to_self_service.cc
rename to components/send_tab_to_self/send_tab_to_self_sync_service.cc
index 1acd8fc..fb8a1f3 100644
--- a/components/send_tab_to_self/send_tab_to_self_service.cc
+++ b/components/send_tab_to_self/send_tab_to_self_sync_service.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/send_tab_to_self/send_tab_to_self_service.h"
+#include "components/send_tab_to_self/send_tab_to_self_sync_service.h"
 
 #include "base/bind.h"
 #include "base/time/default_clock.h"
@@ -14,7 +14,7 @@
 
 namespace send_tab_to_self {
 
-SendTabToSelfService::SendTabToSelfService(
+SendTabToSelfSyncService::SendTabToSelfSyncService(
     version_info::Channel channel,
     const syncer::LocalDeviceInfoProvider* local_device_info_provider) {
   bridge_ = std::make_unique<send_tab_to_self::SendTabToSelfBridge>(
@@ -24,14 +24,14 @@
       local_device_info_provider, base::DefaultClock::GetInstance());
 }
 
-SendTabToSelfService::~SendTabToSelfService() = default;
+SendTabToSelfSyncService::~SendTabToSelfSyncService() = default;
 
-SendTabToSelfModel* SendTabToSelfService::GetSendTabToSelfModel() {
+SendTabToSelfModel* SendTabToSelfSyncService::GetSendTabToSelfModel() {
   return bridge_.get();
 }
 
 base::WeakPtr<syncer::ModelTypeControllerDelegate>
-SendTabToSelfService::GetControllerDelegate() {
+SendTabToSelfSyncService::GetControllerDelegate() {
   return bridge_->change_processor()->GetControllerDelegate();
 }
 
diff --git a/components/send_tab_to_self/send_tab_to_self_service.h b/components/send_tab_to_self/send_tab_to_self_sync_service.h
similarity index 71%
rename from components/send_tab_to_self/send_tab_to_self_service.h
rename to components/send_tab_to_self/send_tab_to_self_sync_service.h
index 123334d..b1b05f9 100644
--- a/components/send_tab_to_self/send_tab_to_self_service.h
+++ b/components/send_tab_to_self/send_tab_to_self_sync_service.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_SEND_TAB_TO_SELF_SEND_TAB_TO_SELF_SERVICE_H_
-#define COMPONENTS_SEND_TAB_TO_SELF_SEND_TAB_TO_SELF_SERVICE_H_
+#ifndef COMPONENTS_SEND_TAB_TO_SELF_SEND_TAB_TO_SELF_SYNC_SERVICE_H_
+#define COMPONENTS_SEND_TAB_TO_SELF_SEND_TAB_TO_SELF_SYNC_SERVICE_H_
 
 #include <memory>
 #include <string>
@@ -22,12 +22,12 @@
 class SendTabToSelfModel;
 
 // KeyedService responsible for send tab to self sync.
-class SendTabToSelfService : public KeyedService {
+class SendTabToSelfSyncService : public KeyedService {
  public:
-  SendTabToSelfService(
+  SendTabToSelfSyncService(
       version_info::Channel channel,
       const syncer::LocalDeviceInfoProvider* local_device_info_provider);
-  ~SendTabToSelfService() override;
+  ~SendTabToSelfSyncService() override;
 
   SendTabToSelfModel* GetSendTabToSelfModel();
 
@@ -37,9 +37,9 @@
  private:
   std::unique_ptr<SendTabToSelfBridge> bridge_;
 
-  DISALLOW_COPY_AND_ASSIGN(SendTabToSelfService);
+  DISALLOW_COPY_AND_ASSIGN(SendTabToSelfSyncService);
 };
 
 }  // namespace send_tab_to_self
 
-#endif  // COMPONENTS_SEND_TAB_TO_SELF_SEND_TAB_TO_SELF_SERVICE_H_
+#endif  // COMPONENTS_SEND_TAB_TO_SELF_SEND_TAB_TO_SELF_SYNC_SERVICE_H_
diff --git a/components/signin/core/browser/account_info.cc b/components/signin/core/browser/account_info.cc
index efcea11..c089abf4 100644
--- a/components/signin/core/browser/account_info.cc
+++ b/components/signin/core/browser/account_info.cc
@@ -54,6 +54,10 @@
 CoreAccountInfo& CoreAccountInfo::operator=(CoreAccountInfo&& other) noexcept =
     default;
 
+bool CoreAccountInfo::IsEmpty() const {
+  return account_id.empty() && email.empty() && gaia.empty();
+}
+
 AccountInfo::AccountInfo() = default;
 
 AccountInfo::~AccountInfo() = default;
@@ -67,9 +71,9 @@
 AccountInfo& AccountInfo::operator=(AccountInfo&& other) noexcept = default;
 
 bool AccountInfo::IsEmpty() const {
-  return account_id.empty() && email.empty() && gaia.empty() &&
-         hosted_domain.empty() && full_name.empty() && given_name.empty() &&
-         locale.empty() && picture_url.empty();
+  return CoreAccountInfo::IsEmpty() && hosted_domain.empty() &&
+         full_name.empty() && given_name.empty() && locale.empty() &&
+         picture_url.empty();
 }
 
 bool AccountInfo::IsValid() const {
diff --git a/components/signin/core/browser/account_info.h b/components/signin/core/browser/account_info.h
index c98529c..fa581f0 100644
--- a/components/signin/core/browser/account_info.h
+++ b/components/signin/core/browser/account_info.h
@@ -34,6 +34,9 @@
   std::string email;
 
   bool is_under_advanced_protection = false;
+
+  // Returns true if all fields in the account info are empty.
+  bool IsEmpty() const;
 };
 
 // Stores all the information known about an account. Part of the information
diff --git a/components/signin/core/browser/account_reconcilor.cc b/components/signin/core/browser/account_reconcilor.cc
index 26dc4567..02e2c27 100644
--- a/components/signin/core/browser/account_reconcilor.cc
+++ b/components/signin/core/browser/account_reconcilor.cc
@@ -399,8 +399,13 @@
   VLOG(1) << "AccountReconcilor::PerformSetCookiesAction: "
           << base::JoinString(parameters.accounts_to_send, " ");
   // TODO (https://crbug.com/890321): pass mode to GaiaCookieManagerService.
-  cookie_manager_service_->SetAccountsInCookie(parameters.accounts_to_send,
-                                               delegate_->GetGaiaApiSource());
+  //
+  // Using Unretained is safe here because the CookieManagerService outlives
+  // the AccountReconcilor.
+  cookie_manager_service_->SetAccountsInCookie(
+      parameters.accounts_to_send, delegate_->GetGaiaApiSource(),
+      base::BindOnce(&AccountReconcilor::OnSetAccountsInCookieCompleted,
+                     base::Unretained(this)));
 }
 
 void AccountReconcilor::PerformLogoutAllAccountsAction() {
diff --git a/components/signin/core/browser/account_reconcilor.h b/components/signin/core/browser/account_reconcilor.h
index 4fdeba0..2d46144f 100644
--- a/components/signin/core/browser/account_reconcilor.h
+++ b/components/signin/core/browser/account_reconcilor.h
@@ -284,8 +284,6 @@
   void OnAddAccountToCookieCompleted(
       const std::string& account_id,
       const GoogleServiceAuthError& error) override;
-  void OnSetAccountsInCookieCompleted(
-      const GoogleServiceAuthError& error) override;
   void OnAccountsInCookieUpdated(
       const identity::AccountsInCookieJarInfo& accounts_in_cookie_jar_info,
       const GoogleServiceAuthError& error) override;
@@ -296,6 +294,8 @@
       const std::vector<std::string>& chrome_accounts,
       std::vector<gaia::ListedAccount>&& gaia_accounts);
 
+  void OnSetAccountsInCookieCompleted(const GoogleServiceAuthError& error);
+
   // Lock related methods.
   void IncrementLockCount();
   void DecrementLockCount();
diff --git a/components/signin/core/browser/account_reconcilor_unittest.cc b/components/signin/core/browser/account_reconcilor_unittest.cc
index 120c99b83..6f68ef1 100644
--- a/components/signin/core/browser/account_reconcilor_unittest.cc
+++ b/components/signin/core/browser/account_reconcilor_unittest.cc
@@ -286,7 +286,7 @@
       const ContentSettingsPattern& primary_pattern);
 
   void SimulateSetAccountsInCookieCompleted(
-      identity::IdentityManager::Observer* observer,
+      AccountReconcilor* reconcilor,
       const GoogleServiceAuthError& error);
 
   void SetAccountConsistency(signin::AccountConsistencyMethod method);
@@ -456,9 +456,9 @@
 }
 
 void AccountReconcilorTest::SimulateSetAccountsInCookieCompleted(
-    identity::IdentityManager::Observer* observer,
+    AccountReconcilor* reconcilor,
     const GoogleServiceAuthError& error) {
-  observer->OnSetAccountsInCookieCompleted(error);
+  reconcilor->OnSetAccountsInCookieCompleted(error);
 }
 
 void AccountReconcilorTest::SimulateCookieContentSettingsChanged(
diff --git a/components/signin/core/browser/gaia_cookie_manager_service.cc b/components/signin/core/browser/gaia_cookie_manager_service.cc
index 5609213..db114d2 100644
--- a/components/signin/core/browser/gaia_cookie_manager_service.cc
+++ b/components/signin/core/browser/gaia_cookie_manager_service.cc
@@ -152,6 +152,16 @@
     gaia::GaiaSource source)
     : request_type_(request_type), account_ids_(account_ids), source_(source) {}
 
+GaiaCookieManagerService::GaiaCookieRequest::GaiaCookieRequest(
+    GaiaCookieRequestType request_type,
+    const std::vector<std::string>& account_ids,
+    gaia::GaiaSource source,
+    SetAccountsInCookieCompletedCallback callback)
+    : request_type_(request_type),
+      account_ids_(account_ids),
+      source_(source),
+      set_accounts_in_cookie_completed_callback_(std::move(callback)) {}
+
 GaiaCookieManagerService::GaiaCookieRequest::~GaiaCookieRequest() {}
 
 GaiaCookieManagerService::GaiaCookieRequest::GaiaCookieRequest(
@@ -167,6 +177,13 @@
   return account_ids_[0];
 }
 
+void GaiaCookieManagerService::GaiaCookieRequest::
+    RunSetAccountsInCookieCompletedCallback(
+        const GoogleServiceAuthError& error) {
+  if (set_accounts_in_cookie_completed_callback_)
+    std::move(set_accounts_in_cookie_completed_callback_).Run(error);
+}
+
 // static
 GaiaCookieManagerService::GaiaCookieRequest
 GaiaCookieManagerService::GaiaCookieRequest::CreateAddAccountRequest(
@@ -180,9 +197,11 @@
 GaiaCookieManagerService::GaiaCookieRequest
 GaiaCookieManagerService::GaiaCookieRequest::CreateSetAccountsRequest(
     const std::vector<std::string>& account_ids,
-    gaia::GaiaSource source) {
+    gaia::GaiaSource source,
+    SetAccountsInCookieCompletedCallback callback) {
   return GaiaCookieManagerService::GaiaCookieRequest(
-      GaiaCookieRequestType::SET_ACCOUNTS, account_ids, source);
+      GaiaCookieRequestType::SET_ACCOUNTS, account_ids, source,
+      std::move(callback));
 }
 
 // static
@@ -476,16 +495,19 @@
 
 void GaiaCookieManagerService::SetAccountsInCookie(
     const std::vector<std::string>& account_ids,
-    gaia::GaiaSource source) {
+    gaia::GaiaSource source,
+    SetAccountsInCookieCompletedCallback
+        set_accounts_in_cookies_completed_callback) {
   VLOG(1) << "GaiaCookieManagerService::SetAccountsInCookie: "
           << base::JoinString(account_ids, " ");
+  requests_.push_back(GaiaCookieRequest::CreateSetAccountsRequest(
+      account_ids, source,
+      std::move(set_accounts_in_cookies_completed_callback)));
   if (!signin_client_->AreSigninCookiesAllowed()) {
     OnSetAccountsFinished(
         GoogleServiceAuthError(GoogleServiceAuthError::REQUEST_CANCELED));
     return;
   }
-  requests_.push_back(
-      GaiaCookieRequest::CreateSetAccountsRequest(account_ids, source));
   if (requests_.size() == 1) {
     fetcher_retries_ = 0;
     signin_client_->DelayNetworkCall(base::BindOnce(
@@ -713,8 +735,9 @@
 
 void GaiaCookieManagerService::SignalSetAccountsComplete(
     const GoogleServiceAuthError& error) {
-  for (auto& observer : observer_list_)
-    observer.OnSetAccountsInCookieCompleted(error);
+  DCHECK(requests_.front().request_type() ==
+         GaiaCookieRequestType::SET_ACCOUNTS);
+  requests_.front().RunSetAccountsInCookieCompletedCallback(error);
 }
 
 void GaiaCookieManagerService::OnUbertokenFetchComplete(
@@ -1074,8 +1097,8 @@
   access_tokens_.clear();
   token_requests_.clear();
   cookies_to_set_.clear();
-  HandleNextRequest();
   SignalSetAccountsComplete(error);
+  HandleNextRequest();
 }
 
 void GaiaCookieManagerService::OnCookieSet(const std::string& cookie_name,
diff --git a/components/signin/core/browser/gaia_cookie_manager_service.h b/components/signin/core/browser/gaia_cookie_manager_service.h
index cb7e4ff0..7c8a107 100644
--- a/components/signin/core/browser/gaia_cookie_manager_service.h
+++ b/components/signin/core/browser/gaia_cookie_manager_service.h
@@ -81,6 +81,9 @@
     SET_ACCOUNTS
   };
 
+  typedef base::OnceCallback<void(const GoogleServiceAuthError& error)>
+      SetAccountsInCookieCompletedCallback;
+
   // Contains the information and parameters for any request.
   class GaiaCookieRequest {
    public:
@@ -96,6 +99,9 @@
     const std::string GetAccountID();
     gaia::GaiaSource source() const { return source_; }
 
+    void RunSetAccountsInCookieCompletedCallback(
+        const GoogleServiceAuthError& error);
+
     static GaiaCookieRequest CreateAddAccountRequest(
         const std::string& account_id,
         gaia::GaiaSource source);
@@ -103,17 +109,25 @@
     static GaiaCookieRequest CreateListAccountsRequest();
     static GaiaCookieRequest CreateSetAccountsRequest(
         const std::vector<std::string>& account_ids,
-        gaia::GaiaSource source);
+        gaia::GaiaSource source,
+        SetAccountsInCookieCompletedCallback callback);
 
    private:
     GaiaCookieRequest(GaiaCookieRequestType request_type,
                       const std::vector<std::string>& account_ids,
                       gaia::GaiaSource source);
+    GaiaCookieRequest(GaiaCookieRequestType request_type,
+                      const std::vector<std::string>& account_ids,
+                      gaia::GaiaSource source,
+                      SetAccountsInCookieCompletedCallback callback);
 
     GaiaCookieRequestType request_type_;
     std::vector<std::string> account_ids_;
     gaia::GaiaSource source_;
 
+    SetAccountsInCookieCompletedCallback
+        set_accounts_in_cookie_completed_callback_;
+
     DISALLOW_COPY_AND_ASSIGN(GaiaCookieRequest);
   };
 
@@ -126,12 +140,6 @@
         const std::string& account_id,
         const GoogleServiceAuthError& error) {}
 
-    // Called whenever setting cookies is completed. If |error| is equal to
-    // GoogleServiceAuthError::AuthErrorNone() then the call succeeded although
-    // there still might be some cookies that failed to be set.
-    virtual void OnSetAccountsInCookieCompleted(
-        const GoogleServiceAuthError& error) {}
-
     // Called whenever a logout is completed. If |error| is equal to
     // GoogleServiceAuthError::AuthErrorNone() then the logout succeeded.
     virtual void OnLogOutAccountsFromCookieCompleted(
@@ -248,7 +256,9 @@
   // of the current cookie state. Removes the accounts that are not in
   // account_ids and add the missing ones.
   void SetAccountsInCookie(const std::vector<std::string>& account_ids,
-                           gaia::GaiaSource source);
+                           gaia::GaiaSource source,
+                           SetAccountsInCookieCompletedCallback
+                               set_accounts_in_cookies_completed_callback);
 
   // Takes list of account_ids from the front request, matches them with a
   // corresponding stored access_token and calls StartMultilogin.
diff --git a/components/signin/core/browser/gaia_cookie_manager_service_unittest.cc b/components/signin/core/browser/gaia_cookie_manager_service_unittest.cc
index 1e5edca..93a15c2 100644
--- a/components/signin/core/browser/gaia_cookie_manager_service_unittest.cc
+++ b/components/signin/core/browser/gaia_cookie_manager_service_unittest.cc
@@ -371,7 +371,9 @@
 
   const std::vector<std::string> account_ids = {account_id1, account_id2};
 
-  helper.SetAccountsInCookie(account_ids, gaia::GaiaSource::kChrome);
+  helper.SetAccountsInCookie(
+      account_ids, gaia::GaiaSource::kChrome,
+      GaiaCookieManagerService::SetAccountsInCookieCompletedCallback());
 
   RequestMockImpl request1(account_id1);
   RequestMockImpl request2(account_id2);
@@ -415,7 +417,9 @@
 
   const std::vector<std::string> account_ids = {account_id1, account_id2};
 
-  helper.SetAccountsInCookie(account_ids, gaia::GaiaSource::kChrome);
+  helper.SetAccountsInCookie(
+      account_ids, gaia::GaiaSource::kChrome,
+      GaiaCookieManagerService::SetAccountsInCookieCompletedCallback());
 
   RequestMockImpl request1(account_id1);
   RequestMockImpl request2(account_id2);
@@ -453,7 +457,9 @@
 
   const std::vector<std::string> account_ids = {account_id1, account_id2};
 
-  helper.SetAccountsInCookie(account_ids, gaia::GaiaSource::kChrome);
+  helper.SetAccountsInCookie(
+      account_ids, gaia::GaiaSource::kChrome,
+      GaiaCookieManagerService::SetAccountsInCookieCompletedCallback());
 
   RequestMockImpl request1(account_id1);
   RequestMockImpl request2(account_id2);
@@ -514,7 +520,9 @@
 
   const std::vector<std::string> account_ids = {account_id1, account_id2};
 
-  helper.SetAccountsInCookie(account_ids, gaia::GaiaSource::kChrome);
+  helper.SetAccountsInCookie(
+      account_ids, gaia::GaiaSource::kChrome,
+      GaiaCookieManagerService::SetAccountsInCookieCompletedCallback());
 
   RequestMockImpl request1(account_id1);
   RequestMockImpl request2(account_id2);
@@ -609,7 +617,9 @@
       .Times(1);
 
   // Needed to insert request in the queue.
-  helper.SetAccountsInCookie(account_ids, gaia::GaiaSource::kChrome);
+  helper.SetAccountsInCookie(
+      account_ids, gaia::GaiaSource::kChrome,
+      GaiaCookieManagerService::SetAccountsInCookieCompletedCallback());
 
   helper.StartFetchingMultiLogin(accounts);
 
@@ -644,7 +654,9 @@
   EXPECT_CALL(helper, OnSetAccountsFinished(error)).Times(1);
 
   // Needed to insert request in the queue.
-  helper.SetAccountsInCookie(account_ids, gaia::GaiaSource::kChrome);
+  helper.SetAccountsInCookie(
+      account_ids, gaia::GaiaSource::kChrome,
+      GaiaCookieManagerService::SetAccountsInCookieCompletedCallback());
 
   helper.StartFetchingMultiLogin(accounts);
 
@@ -682,7 +694,9 @@
   EXPECT_CALL(helper, OnSetAccountsFinished(error)).Times(1);
 
   // Needed to insert request in the queue.
-  helper.SetAccountsInCookie(account_ids, gaia::GaiaSource::kChrome);
+  helper.SetAccountsInCookie(
+      account_ids, gaia::GaiaSource::kChrome,
+      GaiaCookieManagerService::SetAccountsInCookieCompletedCallback());
 
   helper.StartFetchingMultiLogin(accounts);
 
@@ -774,7 +788,9 @@
       .Times(1);
 
   // Needed to insert request in the queue.
-  helper.SetAccountsInCookie(account_ids, gaia::GaiaSource::kChrome);
+  helper.SetAccountsInCookie(
+      account_ids, gaia::GaiaSource::kChrome,
+      GaiaCookieManagerService::SetAccountsInCookieCompletedCallback());
 
   // Both requests for access tokens are successful but they could be returned
   // from cache and be stale.
@@ -855,7 +871,9 @@
   EXPECT_CALL(helper, OnSetAccountsFinished(error)).Times(1);
 
   // Needed to insert request in the queue.
-  helper.SetAccountsInCookie(account_ids, gaia::GaiaSource::kChrome);
+  helper.SetAccountsInCookie(
+      account_ids, gaia::GaiaSource::kChrome,
+      GaiaCookieManagerService::SetAccountsInCookieCompletedCallback());
 
   // Both requests for access tokens are successful but they could be returned
   // from cache and be stale.
diff --git a/components/sync/driver/fake_sync_service.cc b/components/sync/driver/fake_sync_service.cc
index d5de1a8..34fcdd6 100644
--- a/components/sync/driver/fake_sync_service.cc
+++ b/components/sync/driver/fake_sync_service.cc
@@ -35,8 +35,8 @@
   return TransportState::DISABLED;
 }
 
-AccountInfo FakeSyncService::GetAuthenticatedAccountInfo() const {
-  return AccountInfo();
+CoreAccountInfo FakeSyncService::GetAuthenticatedAccountInfo() const {
+  return CoreAccountInfo();
 }
 
 bool FakeSyncService::IsAuthenticatedAccountPrimary() const {
diff --git a/components/sync/driver/fake_sync_service.h b/components/sync/driver/fake_sync_service.h
index 68b1b48..d92877d 100644
--- a/components/sync/driver/fake_sync_service.h
+++ b/components/sync/driver/fake_sync_service.h
@@ -28,7 +28,7 @@
   const syncer::SyncUserSettings* GetUserSettings() const override;
   int GetDisableReasons() const override;
   TransportState GetTransportState() const override;
-  AccountInfo GetAuthenticatedAccountInfo() const override;
+  CoreAccountInfo GetAuthenticatedAccountInfo() const override;
   bool IsAuthenticatedAccountPrimary() const override;
   bool IsLocalSyncEnabled() const override;
   void TriggerRefresh(const ModelTypeSet& types) override;
diff --git a/components/sync/driver/sync_auth_util.cc b/components/sync/driver/sync_auth_util.cc
index ac9192b..896516da 100644
--- a/components/sync/driver/sync_auth_util.cc
+++ b/components/sync/driver/sync_auth_util.cc
@@ -12,7 +12,7 @@
 
 SyncAccountInfo::SyncAccountInfo() = default;
 
-SyncAccountInfo::SyncAccountInfo(const AccountInfo& account_info,
+SyncAccountInfo::SyncAccountInfo(const CoreAccountInfo& account_info,
                                  bool is_primary)
     : account_info(account_info), is_primary(is_primary) {}
 
@@ -34,7 +34,7 @@
         identity_manager->GetAccountsInCookieJar().signed_in_accounts;
     if (!cookie_accounts.empty() &&
         identity_manager->HasAccountWithRefreshToken(cookie_accounts[0].id)) {
-      AccountInfo account_info;
+      CoreAccountInfo account_info;
       account_info.account_id = cookie_accounts[0].id;
       account_info.gaia = cookie_accounts[0].gaia_id;
       account_info.email = cookie_accounts[0].email;
diff --git a/components/sync/driver/sync_auth_util.h b/components/sync/driver/sync_auth_util.h
index 75c99c7..f2bd816 100644
--- a/components/sync/driver/sync_auth_util.h
+++ b/components/sync/driver/sync_auth_util.h
@@ -15,9 +15,9 @@
 
 struct SyncAccountInfo {
   SyncAccountInfo();
-  SyncAccountInfo(const AccountInfo& account_info, bool is_primary);
+  SyncAccountInfo(const CoreAccountInfo& account_info, bool is_primary);
 
-  AccountInfo account_info;
+  CoreAccountInfo account_info;
   bool is_primary = false;
 };
 
diff --git a/components/sync/driver/sync_service.h b/components/sync/driver/sync_service.h
index cd94d1c..d39210fc 100644
--- a/components/sync/driver/sync_service.h
+++ b/components/sync/driver/sync_service.h
@@ -17,7 +17,7 @@
 #include "components/sync/base/model_type.h"
 #include "components/sync/driver/sync_service_observer.h"
 
-struct AccountInfo;
+struct CoreAccountInfo;
 class GoogleServiceAuthError;
 class GURL;
 
@@ -148,7 +148,7 @@
   virtual bool IsLocalSyncEnabled() const = 0;
 
   // Information about the currently signed in user.
-  virtual AccountInfo GetAuthenticatedAccountInfo() const = 0;
+  virtual CoreAccountInfo GetAuthenticatedAccountInfo() const = 0;
   // Whether the currently signed in user is the "primary" browser account (see
   // IdentityManager). If this is false, then IsSyncFeatureEnabled will also be
   // false, but Sync-the-transport might still run.
diff --git a/components/sync/driver/test_sync_service.cc b/components/sync/driver/test_sync_service.cc
index 62d8582..dc9c512 100644
--- a/components/sync/driver/test_sync_service.cc
+++ b/components/sync/driver/test_sync_service.cc
@@ -55,7 +55,7 @@
 }
 
 void TestSyncService::SetAuthenticatedAccountInfo(
-    const AccountInfo& account_info) {
+    const CoreAccountInfo& account_info) {
   account_info_ = account_info;
 }
 
@@ -133,7 +133,7 @@
   return local_sync_enabled_;
 }
 
-AccountInfo TestSyncService::GetAuthenticatedAccountInfo() const {
+CoreAccountInfo TestSyncService::GetAuthenticatedAccountInfo() const {
   return account_info_;
 }
 
diff --git a/components/sync/driver/test_sync_service.h b/components/sync/driver/test_sync_service.h
index 6f6020d..e7bd283 100644
--- a/components/sync/driver/test_sync_service.h
+++ b/components/sync/driver/test_sync_service.h
@@ -29,7 +29,7 @@
   void SetDisableReasons(int disable_reasons);
   void SetTransportState(TransportState transport_state);
   void SetLocalSyncEnabled(bool local_sync_enabled);
-  void SetAuthenticatedAccountInfo(const AccountInfo& account_info);
+  void SetAuthenticatedAccountInfo(const CoreAccountInfo& account_info);
   void SetIsAuthenticatedAccountPrimary(bool is_primary);
   void SetSetupInProgress(bool in_progress);
   void SetAuthError(const GoogleServiceAuthError& auth_error);
@@ -52,7 +52,7 @@
   int GetDisableReasons() const override;
   TransportState GetTransportState() const override;
   bool IsLocalSyncEnabled() const override;
-  AccountInfo GetAuthenticatedAccountInfo() const override;
+  CoreAccountInfo GetAuthenticatedAccountInfo() const override;
   bool IsAuthenticatedAccountPrimary() const override;
   const GoogleServiceAuthError& GetAuthError() const override;
 
@@ -108,7 +108,7 @@
   int disable_reasons_ = DISABLE_REASON_NONE;
   TransportState transport_state_ = TransportState::ACTIVE;
   bool local_sync_enabled_ = false;
-  AccountInfo account_info_;
+  CoreAccountInfo account_info_;
   bool account_is_primary_ = true;
   bool setup_in_progress_ = false;
   GoogleServiceAuthError auth_error_;
diff --git a/components/ui_devtools/views/widget_element_unittest.cc b/components/ui_devtools/views/widget_element_unittest.cc
index 3587e80..31a5352 100644
--- a/components/ui_devtools/views/widget_element_unittest.cc
+++ b/components/ui_devtools/views/widget_element_unittest.cc
@@ -46,7 +46,7 @@
   }
 
  protected:
-  views::Widget* widget() { return widget_; };
+  views::Widget* widget() { return widget_; }
   WidgetElement* element() { return element_.get(); }
   MockUIElementDelegate* delegate() { return delegate_.get(); }
 
diff --git a/content/app/android/content_child_process_service_delegate.cc b/content/app/android/content_child_process_service_delegate.cc
index ba226724..f1488cfa 100644
--- a/content/app/android/content_child_process_service_delegate.cc
+++ b/content/app/android/content_child_process_service_delegate.cc
@@ -128,12 +128,6 @@
       env, obj, cpu_count, cpu_features);
 }
 
-void JNI_ContentChildProcessServiceDelegate_ShutdownMainThread(
-    JNIEnv* env,
-    const JavaParamRef<jobject>& obj) {
-  ChildThreadImpl::ShutdownThread();
-}
-
 void JNI_ContentChildProcessServiceDelegate_RetrieveFileDescriptorsIdsToKeys(
     JNIEnv* env,
     const JavaParamRef<jobject>& obj) {
diff --git a/content/browser/BUILD.gn b/content/browser/BUILD.gn
index 9bcbb0a..0bdcde6c 100644
--- a/content/browser/BUILD.gn
+++ b/content/browser/BUILD.gn
@@ -107,6 +107,7 @@
     "//media",
     "//media:media_buildflags",
     "//media/capture",
+    "//media/learning/impl",
     "//media/midi",
     "//media/midi:mojo",
     "//media/mojo:buildflags",
@@ -1150,6 +1151,8 @@
     "media/audio_stream_broker.h",
     "media/audio_stream_monitor.cc",
     "media/audio_stream_monitor.h",
+    "media/browser_feature_provider.cc",
+    "media/browser_feature_provider.h",
     "media/capture/audio_mirroring_manager.cc",
     "media/capture/audio_mirroring_manager.h",
     "media/capture/desktop_capture_device_uma_types.cc",
diff --git a/content/browser/accessibility/accessibility_event_recorder_auralinux.cc b/content/browser/accessibility/accessibility_event_recorder_auralinux.cc
index 203e2da..2eb1b62 100644
--- a/content/browser/accessibility/accessibility_event_recorder_auralinux.cc
+++ b/content/browser/accessibility/accessibility_event_recorder_auralinux.cc
@@ -143,6 +143,7 @@
   AddATKEventListener("ATK:AtkObject:state-change");
   AddATKEventListener("ATK:AtkObject:focus-event");
   AddATKEventListener("ATK:AtkObject:property-change");
+  AddATKEventListener("ATK:AtkSelection:selection-changed");
 }
 
 void AccessibilityEventRecorderAuraLinux::RemoveATKEventListeners() {
diff --git a/content/browser/accessibility/browser_accessibility_manager.cc b/content/browser/accessibility/browser_accessibility_manager.cc
index d719009d..773557b 100644
--- a/content/browser/accessibility/browser_accessibility_manager.cc
+++ b/content/browser/accessibility/browser_accessibility_manager.cc
@@ -290,12 +290,12 @@
 }
 
 void BrowserAccessibilityManager::OnWindowFocused() {
-  if (this == GetRootManager())
+  if (IsRootTree())
     FireFocusEventsIfNeeded();
 }
 
 void BrowserAccessibilityManager::OnWindowBlurred() {
-  if (this == GetRootManager()) {
+  if (IsRootTree()) {
     last_focused_node_ = nullptr;
     last_focused_manager_ = nullptr;
   }
@@ -1159,7 +1159,7 @@
 }
 
 bool BrowserAccessibilityManager::IsRootTree() {
-  return delegate() && delegate()->AccessibilityGetAcceleratedWidget();
+  return GetRootManager() == this;
 }
 
 ui::AXTreeUpdate
diff --git a/content/browser/accessibility/browser_accessibility_manager_auralinux.cc b/content/browser/accessibility/browser_accessibility_manager_auralinux.cc
index 55fa5f9..29e25929 100644
--- a/content/browser/accessibility/browser_accessibility_manager_auralinux.cc
+++ b/content/browser/accessibility/browser_accessibility_manager_auralinux.cc
@@ -4,6 +4,7 @@
 
 #include "content/browser/accessibility/browser_accessibility_manager_auralinux.h"
 
+#include <atk/atk.h>
 #include <vector>
 
 #include "content/browser/accessibility/browser_accessibility_auralinux.h"
@@ -131,6 +132,9 @@
     case ui::AXEventGenerator::Event::LOAD_START:
       FireLoadingEvent(node, true);
       break;
+    case ui::AXEventGenerator::Event::SELECTED_CHILDREN_CHANGED:
+      FireEvent(node, ax::mojom::Event::kSelectedChildrenChanged);
+      break;
     case ui::AXEventGenerator::Event::MENU_ITEM_SELECTED:
     case ui::AXEventGenerator::Event::SELECTED_CHANGED:
       FireSelectedEvent(node);
@@ -144,6 +148,39 @@
   }
 }
 
+static AtkObject* GetParentFrameIfToplevelDocument(AtkObject* object) {
+  while (object) {
+    if (atk_object_get_role(object) == ATK_ROLE_DOCUMENT_WEB)
+      return nullptr;
+    if (atk_object_get_role(object) == ATK_ROLE_FRAME)
+      return object;
+    object = atk_object_get_parent(object);
+  }
+  return nullptr;
+}
+
+static void EstablishEmbeddedRelationship(AtkObject* document_object) {
+  if (!document_object)
+    return;
+
+  AtkObject* window =
+      GetParentFrameIfToplevelDocument(atk_object_get_parent(document_object));
+  if (!window)
+    return;
+
+  ui::AXPlatformNodeAuraLinux* window_platform_node =
+      static_cast<ui::AXPlatformNodeAuraLinux*>(
+          ui::AXPlatformNode::FromNativeViewAccessible(window));
+  ui::AXPlatformNodeAuraLinux* document_platform_node =
+      static_cast<ui::AXPlatformNodeAuraLinux*>(
+          ui::AXPlatformNode::FromNativeViewAccessible(document_object));
+  if (!window_platform_node || !document_platform_node)
+    return;
+
+  window_platform_node->SetEmbeddedDocument(document_object);
+  document_platform_node->SetEmbeddingWindow(window);
+}
+
 void BrowserAccessibilityManagerAuraLinux::OnAtomicUpdateFinished(
     ui::AXTree* tree,
     bool root_changed,
@@ -151,6 +188,14 @@
   BrowserAccessibilityManager::OnAtomicUpdateFinished(tree, root_changed,
                                                       changes);
 
+  // Ideally we would like to do this only when `root_changed` is true, but it
+  // seems that our parent ATK frame can switch between multiple
+  // BrowserAccessibilityManagers with no way to detect that here. Instead
+  // whenever an update happens we reestablish the relationship to our parent
+  // frame.
+  if (GetRoot() && GetRoot()->IsNative() && IsRootTree())
+    EstablishEmbeddedRelationship(GetRoot()->GetNativeViewAccessible());
+
   // This is the second step in what will be a three step process mirroring that
   // used in BrowserAccessibilityManagerWin.
   for (const auto& change : changes) {
diff --git a/content/browser/appcache/appcache_frontend_proxy.cc b/content/browser/appcache/appcache_frontend_proxy.cc
index 95dff90..8b8694f 100644
--- a/content/browser/appcache/appcache_frontend_proxy.cc
+++ b/content/browser/appcache/appcache_frontend_proxy.cc
@@ -45,11 +45,6 @@
   GetAppCacheFrontend()->CacheSelected(host_id, std::move(info));
 }
 
-void AppCacheFrontendProxy::StatusChanged(const std::vector<int32_t>& host_ids,
-                                          blink::mojom::AppCacheStatus status) {
-  GetAppCacheFrontend()->StatusChanged(host_ids, status);
-}
-
 void AppCacheFrontendProxy::EventRaised(
     const std::vector<int32_t>& host_ids,
     blink::mojom::AppCacheEventID event_id) {
diff --git a/content/browser/appcache/appcache_frontend_proxy.h b/content/browser/appcache/appcache_frontend_proxy.h
index 05170fc..b00e601 100644
--- a/content/browser/appcache/appcache_frontend_proxy.h
+++ b/content/browser/appcache/appcache_frontend_proxy.h
@@ -23,8 +23,6 @@
   // AppCacheFrontend methods
   void CacheSelected(int32_t host_id,
                      blink::mojom::AppCacheInfoPtr info) override;
-  void StatusChanged(const std::vector<int32_t>& host_ids,
-                     blink::mojom::AppCacheStatus status) override;
   void EventRaised(const std::vector<int32_t>& host_ids,
                    blink::mojom::AppCacheEventID event_id) override;
   void ProgressEventRaised(const std::vector<int32_t>& host_ids,
diff --git a/content/browser/appcache/appcache_group_unittest.cc b/content/browser/appcache/appcache_group_unittest.cc
index 192b38cf..b2321f1 100644
--- a/content/browser/appcache/appcache_group_unittest.cc
+++ b/content/browser/appcache/appcache_group_unittest.cc
@@ -33,9 +33,6 @@
     last_status_ = info->status;
   }
 
-  void StatusChanged(const std::vector<int32_t>& host_ids,
-                     blink::mojom::AppCacheStatus status) override {}
-
   void EventRaised(const std::vector<int32_t>& host_ids,
                    blink::mojom::AppCacheEventID event_id) override {}
 
diff --git a/content/browser/appcache/appcache_host_unittest.cc b/content/browser/appcache/appcache_host_unittest.cc
index 82d6492..0c4c68817 100644
--- a/content/browser/appcache/appcache_host_unittest.cc
+++ b/content/browser/appcache/appcache_host_unittest.cc
@@ -63,8 +63,6 @@
           last_host_id_(-222),
           last_cache_id_(-222),
           last_status_(blink::mojom::AppCacheStatus::APPCACHE_STATUS_OBSOLETE),
-          last_status_changed_(
-              blink::mojom::AppCacheStatus::APPCACHE_STATUS_OBSOLETE),
           last_event_id_(
               blink::mojom::AppCacheEventID::APPCACHE_OBSOLETE_EVENT),
           content_blocked_(false) {}
@@ -76,10 +74,6 @@
       last_status_ = info->status;
     }
 
-    void StatusChanged(const std::vector<int32_t>& host_ids,
-                       blink::mojom::AppCacheStatus status) override {
-      last_status_changed_ = status;
-    }
 
     void EventRaised(const std::vector<int32_t>& host_ids,
                      blink::mojom::AppCacheEventID event_id) override {
@@ -118,7 +112,6 @@
     int32_t last_host_id_;
     int64_t last_cache_id_;
     blink::mojom::AppCacheStatus last_status_;
-    blink::mojom::AppCacheStatus last_status_changed_;
     blink::mojom::AppCacheEventID last_event_id_;
     bool content_blocked_;
     bool appcache_accessed_ = false;
diff --git a/content/browser/appcache/appcache_navigation_handle_core.cc b/content/browser/appcache/appcache_navigation_handle_core.cc
index 739ffce..615d8a7 100644
--- a/content/browser/appcache/appcache_navigation_handle_core.cc
+++ b/content/browser/appcache/appcache_navigation_handle_core.cc
@@ -94,13 +94,6 @@
   DCHECK(false);
 }
 
-void AppCacheNavigationHandleCore::StatusChanged(
-    const std::vector<int>& host_ids,
-    blink::mojom::AppCacheStatus status) {
-  // Should never be called.
-  DCHECK(false);
-}
-
 void AppCacheNavigationHandleCore::EventRaised(
     const std::vector<int>& host_ids,
     blink::mojom::AppCacheEventID event_id) {
diff --git a/content/browser/appcache/appcache_navigation_handle_core.h b/content/browser/appcache/appcache_navigation_handle_core.h
index d03acca..695cc5ea 100644
--- a/content/browser/appcache/appcache_navigation_handle_core.h
+++ b/content/browser/appcache/appcache_navigation_handle_core.h
@@ -61,8 +61,6 @@
   // AppCacheHost is not registered with the AppCacheBackend.
   void CacheSelected(int32_t host_id,
                      blink::mojom::AppCacheInfoPtr info) override;
-  void StatusChanged(const std::vector<int32_t>& host_ids,
-                     blink::mojom::AppCacheStatus status) override;
   void EventRaised(const std::vector<int32_t>& host_ids,
                    blink::mojom::AppCacheEventID event_id) override;
   void ProgressEventRaised(const std::vector<int32_t>& host_ids,
diff --git a/content/browser/appcache/appcache_request_handler_unittest.cc b/content/browser/appcache/appcache_request_handler_unittest.cc
index e5afdd0..00fc790 100644
--- a/content/browser/appcache/appcache_request_handler_unittest.cc
+++ b/content/browser/appcache/appcache_request_handler_unittest.cc
@@ -76,9 +76,6 @@
     void CacheSelected(int32_t host_id,
                        blink::mojom::AppCacheInfoPtr info) override {}
 
-    void StatusChanged(const std::vector<int32_t>& host_ids,
-                       blink::mojom::AppCacheStatus status) override {}
-
     void EventRaised(const std::vector<int32_t>& host_ids,
                      blink::mojom::AppCacheEventID event_id) override {}
 
diff --git a/content/browser/appcache/appcache_storage_impl_unittest.cc b/content/browser/appcache/appcache_storage_impl_unittest.cc
index f90061f6..8f02d1c 100644
--- a/content/browser/appcache/appcache_storage_impl_unittest.cc
+++ b/content/browser/appcache/appcache_storage_impl_unittest.cc
@@ -1547,8 +1547,6 @@
 
     void CacheSelected(int32_t host_id,
                        blink::mojom::AppCacheInfoPtr info) override {}
-    void StatusChanged(const std::vector<int32_t>& host_ids,
-                       blink::mojom::AppCacheStatus status) override {}
     void EventRaised(const std::vector<int32_t>& host_ids,
                      blink::mojom::AppCacheEventID event_id) override {}
     void ProgressEventRaised(const std::vector<int32_t>& host_ids,
diff --git a/content/browser/appcache/appcache_unittest.cc b/content/browser/appcache/appcache_unittest.cc
index 3b3b117..c3ed3fc 100644
--- a/content/browser/appcache/appcache_unittest.cc
+++ b/content/browser/appcache/appcache_unittest.cc
@@ -24,8 +24,6 @@
  public:
   void CacheSelected(int32_t host_id,
                      blink::mojom::AppCacheInfoPtr info) override {}
-  void StatusChanged(const std::vector<int32_t>& host_ids,
-                     blink::mojom::AppCacheStatus status) override {}
   void EventRaised(const std::vector<int32_t>& host_ids,
                    blink::mojom::AppCacheEventID event_id) override {}
   void ProgressEventRaised(const std::vector<int32_t>& host_ids,
diff --git a/content/browser/appcache/appcache_update_job_unittest.cc b/content/browser/appcache/appcache_update_job_unittest.cc
index 8d3ced60..c56c1f0 100644
--- a/content/browser/appcache/appcache_update_job_unittest.cc
+++ b/content/browser/appcache/appcache_update_job_unittest.cc
@@ -257,9 +257,6 @@
   void CacheSelected(int32_t host_id,
                      blink::mojom::AppCacheInfoPtr info) override {}
 
-  void StatusChanged(const std::vector<int32_t>& host_ids,
-                     blink::mojom::AppCacheStatus status) override {}
-
   void EventRaised(const std::vector<int32_t>& host_ids,
                    blink::mojom::AppCacheEventID event_id) override {
     raised_events_.push_back(RaisedEvent(host_ids, event_id));
diff --git a/content/browser/browser_context.cc b/content/browser/browser_context.cc
index 0c58a53..68e34ea 100644
--- a/content/browser/browser_context.cc
+++ b/content/browser/browser_context.cc
@@ -39,6 +39,7 @@
 #include "content/browser/download/download_manager_impl.h"
 #include "content/browser/indexed_db/indexed_db_context_impl.h"
 #include "content/browser/loader/resource_dispatcher_host_impl.h"
+#include "content/browser/media/browser_feature_provider.h"
 #include "content/browser/permissions/permission_controller_impl.h"
 #include "content/browser/push_messaging/push_messaging_router.h"
 #include "content/browser/service_manager/common_browser_interfaces.h"
@@ -783,8 +784,8 @@
     std::unique_ptr<media::VideoDecodeStatsDBImpl> stats_db =
         media::VideoDecodeStatsDBImpl::Create(
             GetPath().Append(FILE_PATH_LITERAL("VideoDecodeStats")));
-    auto new_decode_history =
-        std::make_unique<media::VideoDecodePerfHistory>(std::move(stats_db));
+    auto new_decode_history = std::make_unique<media::VideoDecodePerfHistory>(
+        std::move(stats_db), BrowserFeatureProvider::GetFactoryCB());
     decode_history = new_decode_history.get();
 
     SetUserData(kVideoDecodePerfHistoryId, std::move(new_decode_history));
diff --git a/content/browser/devtools/devtools_session.cc b/content/browser/devtools/devtools_session.cc
index b7165ca..848922c 100644
--- a/content/browser/devtools/devtools_session.cc
+++ b/content/browser/devtools/devtools_session.cc
@@ -208,12 +208,17 @@
     const std::string& method,
     const std::string& message) {
   DCHECK(!browser_only_);
+  auto message_ptr = blink::mojom::DevToolsMessage::New();
+  message_ptr->data = mojo_base::BigBuffer(base::make_span(
+      reinterpret_cast<const uint8_t*>(message.data()), message.length()));
   if (ShouldSendOnIO(method)) {
     if (io_session_ptr_)
-      io_session_ptr_->DispatchProtocolCommand(call_id, method, message);
+      io_session_ptr_->DispatchProtocolCommand(call_id, method,
+                                               std::move(message_ptr));
   } else {
     if (session_ptr_)
-      session_ptr_->DispatchProtocolCommand(call_id, method, message);
+      session_ptr_->DispatchProtocolCommand(call_id, method,
+                                            std::move(message_ptr));
   }
 }
 
@@ -251,20 +256,26 @@
 }
 
 void DevToolsSession::DispatchProtocolResponse(
-    const std::string& message,
+    blink::mojom::DevToolsMessagePtr message,
     int call_id,
     blink::mojom::DevToolsSessionStatePtr updates) {
   ApplySessionStateUpdates(std::move(updates));
   waiting_for_response_messages_.erase(call_id);
-  client_->DispatchProtocolMessage(agent_host_, message);
+  client_->DispatchProtocolMessage(
+      agent_host_,
+      std::string(reinterpret_cast<const char*>(message->data.data()),
+                  message->data.size()));
   // |this| may be deleted at this point.
 }
 
 void DevToolsSession::DispatchProtocolNotification(
-    const std::string& message,
+    blink::mojom::DevToolsMessagePtr message,
     blink::mojom::DevToolsSessionStatePtr updates) {
   ApplySessionStateUpdates(std::move(updates));
-  client_->DispatchProtocolMessage(agent_host_, message);
+  client_->DispatchProtocolMessage(
+      agent_host_,
+      std::string(reinterpret_cast<const char*>(message->data.data()),
+                  message->data.size()));
   // |this| may be deleted at this point.
 }
 
diff --git a/content/browser/devtools/devtools_session.h b/content/browser/devtools/devtools_session.h
index 71fdd834..8d74ef9a 100644
--- a/content/browser/devtools/devtools_session.h
+++ b/content/browser/devtools/devtools_session.h
@@ -87,11 +87,11 @@
 
   // blink::mojom::DevToolsSessionHost implementation.
   void DispatchProtocolResponse(
-      const std::string& message,
+      blink::mojom::DevToolsMessagePtr message,
       int call_id,
       blink::mojom::DevToolsSessionStatePtr updates) override;
   void DispatchProtocolNotification(
-      const std::string& message,
+      blink::mojom::DevToolsMessagePtr message,
       blink::mojom::DevToolsSessionStatePtr updates) override;
 
   // DevToolsExternalAgentProxy implementation.
diff --git a/content/browser/download/download_browsertest.cc b/content/browser/download/download_browsertest.cc
index c19a8e1..878a7bb 100644
--- a/content/browser/download/download_browsertest.cc
+++ b/content/browser/download/download_browsertest.cc
@@ -583,7 +583,7 @@
 
 class ErrorStreamCountingObserver : download::DownloadItem::Observer {
  public:
-  ErrorStreamCountingObserver() : item_(nullptr), count_(0){};
+  ErrorStreamCountingObserver() : item_(nullptr), count_(0) {}
 
   ~ErrorStreamCountingObserver() override {
     if (item_)
diff --git a/content/browser/download/mhtml_generation_browsertest.cc b/content/browser/download/mhtml_generation_browsertest.cc
index 0c6d9bd45..c0b1e4cf 100644
--- a/content/browser/download/mhtml_generation_browsertest.cc
+++ b/content/browser/download/mhtml_generation_browsertest.cc
@@ -337,7 +337,7 @@
     }
 
     return false;
-  };
+  }
 
   void TaskX() {
     download::GetDownloadTaskRunner()->PostTask(
diff --git a/content/browser/frame_host/interstitial_page_impl.cc b/content/browser/frame_host/interstitial_page_impl.cc
index f5ba410..dbc6281e 100644
--- a/content/browser/frame_host/interstitial_page_impl.cc
+++ b/content/browser/frame_host/interstitial_page_impl.cc
@@ -782,6 +782,7 @@
     int32_t main_frame_route_id,
     int32_t main_frame_widget_route_id,
     const mojom::CreateNewWindowParams& params,
+    bool has_user_gesture,
     SessionStorageNamespace* session_storage_namespace) {
   NOTREACHED() << "InterstitialPage does not support showing popups.";
 }
diff --git a/content/browser/frame_host/interstitial_page_impl.h b/content/browser/frame_host/interstitial_page_impl.h
index d1a5347..77bee15 100644
--- a/content/browser/frame_host/interstitial_page_impl.h
+++ b/content/browser/frame_host/interstitial_page_impl.h
@@ -133,6 +133,7 @@
       int32_t main_frame_route_id,
       int32_t main_frame_widget_route_id,
       const mojom::CreateNewWindowParams& params,
+      bool has_user_gesture,
       SessionStorageNamespace* session_storage_namespace) override;
   void ShowCreatedWindow(int process_id,
                          int main_frame_widget_route_id,
diff --git a/content/browser/frame_host/render_frame_host_delegate.h b/content/browser/frame_host/render_frame_host_delegate.h
index 27c11d6..c54ff3c 100644
--- a/content/browser/frame_host/render_frame_host_delegate.h
+++ b/content/browser/frame_host/render_frame_host_delegate.h
@@ -359,6 +359,7 @@
       int32_t main_frame_route_id,
       int32_t main_frame_widget_route_id,
       const mojom::CreateNewWindowParams& params,
+      bool has_user_gesture,
       SessionStorageNamespace* session_storage_namespace) {}
 
   // Show a previously created page with the specified disposition and bounds.
diff --git a/content/browser/frame_host/render_frame_host_impl.cc b/content/browser/frame_host/render_frame_host_impl.cc
index a9252104..fb5cebf 100644
--- a/content/browser/frame_host/render_frame_host_impl.cc
+++ b/content/browser/frame_host/render_frame_host_impl.cc
@@ -3618,10 +3618,11 @@
           effective_transient_activation_state, params->opener_suppressed,
           &no_javascript_access);
 
+  bool was_consumed = false;
   if (can_create_window) {
     // Consume activation even w/o User Activation v2, to sync other renderers
     // with calling renderer.
-    frame_tree_node_->UpdateUserActivationState(
+    was_consumed = frame_tree_node_->UpdateUserActivationState(
         blink::UserActivationUpdateType::kConsumeTransientActivation);
   }
 
@@ -3690,9 +3691,13 @@
 
   DCHECK(IsRenderFrameLive());
 
+  bool opened_by_user_activation = params->mimic_user_gesture;
+  if (base::FeatureList::IsEnabled(features::kUserActivationV2))
+    opened_by_user_activation = was_consumed;
+
   delegate_->CreateNewWindow(this, render_view_route_id, main_frame_route_id,
                              main_frame_widget_route_id, *params,
-                             cloned_namespace.get());
+                             opened_by_user_activation, cloned_namespace.get());
 
   if (main_frame_route_id == MSG_ROUTING_NONE) {
     // Opener suppressed or Javascript access disabled. Never tell the renderer
diff --git a/content/browser/media/audible_metrics_unittest.cc b/content/browser/media/audible_metrics_unittest.cc
index eea8102d..66134c8 100644
--- a/content/browser/media/audible_metrics_unittest.cc
+++ b/content/browser/media/audible_metrics_unittest.cc
@@ -52,7 +52,7 @@
 
   base::SimpleTestTickClock* clock() { return &clock_; }
 
-  AudibleMetrics* audible_metrics() { return audible_metrics_.get(); };
+  AudibleMetrics* audible_metrics() { return audible_metrics_.get(); }
 
   const base::UserActionTester& user_action_tester() const {
     return user_action_tester_;
diff --git a/content/browser/media/browser_feature_provider.cc b/content/browser/media/browser_feature_provider.cc
new file mode 100644
index 0000000..c6d006c
--- /dev/null
+++ b/content/browser/media/browser_feature_provider.cc
@@ -0,0 +1,59 @@
+// 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/media/browser_feature_provider.h"
+
+#include <utility>
+
+#include "base/threading/sequenced_task_runner_handle.h"
+#include "media/learning/common/feature_library.h"
+#include "net/base/network_change_notifier.h"
+
+using ::media::learning::FeatureLibrary;
+using ::media::learning::FeatureProviderFactoryCB;
+using ::media::learning::FeatureValue;
+using ::media::learning::LabelledExample;
+using ::media::learning::LearningTask;
+using ::media::learning::SequenceBoundFeatureProvider;
+
+namespace content {
+
+BrowserFeatureProvider::BrowserFeatureProvider(const LearningTask& task)
+    : task_(task) {}
+
+BrowserFeatureProvider::~BrowserFeatureProvider() = default;
+
+// static
+SequenceBoundFeatureProvider BrowserFeatureProvider::Create(
+    const LearningTask& task) {
+  return base::SequenceBound<BrowserFeatureProvider>(
+      base::SequencedTaskRunnerHandle::Get(), task);
+}
+
+// static
+FeatureProviderFactoryCB BrowserFeatureProvider::GetFactoryCB() {
+  return base::BindRepeating(&BrowserFeatureProvider::Create);
+}
+
+void BrowserFeatureProvider::AddFeatures(const LabelledExample& example,
+                                         LabelledExampleCB cb) {
+  LabelledExample new_example = example;
+
+  const size_t size = task_.feature_descriptions.size();
+  if (new_example.features.size() < size)
+    new_example.features.resize(size);
+
+  // Find any features that we're supposed to fill in.
+  for (size_t i = 0; i < size; i++) {
+    const auto& desc = task_.feature_descriptions[i];
+    if (desc.name == FeatureLibrary::NetworkType().name) {
+      new_example.features[i] = FeatureValue(
+          static_cast<int>(net::NetworkChangeNotifier::GetConnectionType()));
+    }
+  }
+
+  std::move(cb).Run(std::move(new_example));
+}
+
+}  // namespace content
diff --git a/content/browser/media/browser_feature_provider.h b/content/browser/media/browser_feature_provider.h
new file mode 100644
index 0000000..dbcd9cf
--- /dev/null
+++ b/content/browser/media/browser_feature_provider.h
@@ -0,0 +1,40 @@
+// 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_MEDIA_BROWSER_FEATURE_PROVIDER_H_
+#define CONTENT_BROWSER_MEDIA_BROWSER_FEATURE_PROVIDER_H_
+
+#include <map>
+
+#include "content/common/content_export.h"
+#include "media/learning/impl/feature_provider.h"
+
+namespace content {
+
+// FeatureProvider implementation that handles the features labelled 'browser'
+// in //media/learning/common/feature_library.h .
+// TODO(liberato): It's likely that this should not be in media/, but rather in
+// learning/browser.  This should be refactored if the learning experiment moves
+// into its own component.
+class BrowserFeatureProvider : public ::media::learning::FeatureProvider {
+ public:
+  BrowserFeatureProvider(const ::media::learning::LearningTask& task);
+  ~BrowserFeatureProvider() override;
+
+  static ::media::learning::SequenceBoundFeatureProvider Create(
+      const ::media::learning::LearningTask& task);
+
+  static ::media::learning::FeatureProviderFactoryCB GetFactoryCB();
+
+  // FeatureProvider
+  void AddFeatures(const ::media::learning::LabelledExample& example,
+                   LabelledExampleCB cb) override;
+
+ private:
+  ::media::learning::LearningTask task_;
+};
+
+}  // namespace content
+
+#endif  // CONTENT_BROWSER_MEDIA_BROWSER_FEATURE_PROVIDER_H_
diff --git a/content/browser/media/session/media_session_uma_helper_unittest.cc b/content/browser/media/session/media_session_uma_helper_unittest.cc
index 973d765..bc5a2d1f 100644
--- a/content/browser/media/session/media_session_uma_helper_unittest.cc
+++ b/content/browser/media/session/media_session_uma_helper_unittest.cc
@@ -29,7 +29,7 @@
 
   MediaSessionUmaHelper& media_session_uma_helper() {
     return media_session_uma_helper_;
-  };
+  }
 
   std::unique_ptr<base::HistogramSamples> GetHistogramSamplesSinceTestStart(
       const std::string& name) {
diff --git a/content/browser/service_manager/service_manager_context.cc b/content/browser/service_manager/service_manager_context.cc
index dfdb6d1d..d0e0368 100644
--- a/content/browser/service_manager/service_manager_context.cc
+++ b/content/browser/service_manager/service_manager_context.cc
@@ -636,10 +636,13 @@
       &out_of_process_services);
 
   if (base::FeatureList::IsEnabled(features::kTracingServiceInProcess)) {
-    RegisterInProcessService(packaged_services_connection_.get(),
-                             tracing::mojom::kServiceName,
-                             service_manager_thread_task_runner_,
-                             base::BindRepeating(&CreateTracingService));
+    RegisterInProcessService(
+        packaged_services_connection_.get(), tracing::mojom::kServiceName,
+        base::CreateSequencedTaskRunnerWithTraits(
+            {base::MayBlock(), base::TaskShutdownBehavior::SKIP_ON_SHUTDOWN,
+             base::WithBaseSyncPrimitives(),
+             base::TaskPriority::USER_BLOCKING}),
+        base::BindRepeating(&CreateTracingService));
   } else {
     out_of_process_services[tracing::mojom::kServiceName] =
         base::BindRepeating(&base::ASCIIToUTF16, "Tracing Service");
diff --git a/content/browser/site_per_process_hit_test_browsertest.cc b/content/browser/site_per_process_hit_test_browsertest.cc
index bbb07ea..1554f9a9 100644
--- a/content/browser/site_per_process_hit_test_browsertest.cc
+++ b/content/browser/site_per_process_hit_test_browsertest.cc
@@ -128,7 +128,7 @@
   void OnInputEvent(const blink::WebInputEvent& event) override {
     events_received_.push_back(event.GetType());
     event_ = ui::WebInputEventTraits::Clone(event);
-  };
+  }
 
   const std::vector<InputEventAckSource>& events_acked() {
     return events_acked_;
diff --git a/content/browser/speech/tts_controller_unittest.cc b/content/browser/speech/tts_controller_unittest.cc
index 9c28787..7854734 100644
--- a/content/browser/speech/tts_controller_unittest.cc
+++ b/content/browser/speech/tts_controller_unittest.cc
@@ -58,9 +58,9 @@
   void UpdateUtteranceDefaultsFromPrefs(content::TtsUtterance* utterance,
                                         double* rate,
                                         double* pitch,
-                                        double* volume) override{};
+                                        double* volume) override {}
 
-  void SetTtsEngineDelegate(content::TtsEngineDelegate* delegate) override{};
+  void SetTtsEngineDelegate(content::TtsEngineDelegate* delegate) override {}
 
   content::TtsEngineDelegate* GetTtsEngineDelegate() override {
     return nullptr;
diff --git a/content/browser/web_contents/web_contents_impl.cc b/content/browser/web_contents/web_contents_impl.cc
index 74c9f5a..ea87008 100644
--- a/content/browser/web_contents/web_contents_impl.cc
+++ b/content/browser/web_contents/web_contents_impl.cc
@@ -2666,6 +2666,7 @@
     int32_t main_frame_route_id,
     int32_t main_frame_widget_route_id,
     const mojom::CreateNewWindowParams& params,
+    bool has_user_gesture,
     SessionStorageNamespace* session_storage_namespace) {
   // We should have zero valid routing ids, or three valid routing IDs.
   DCHECK_EQ((render_view_route_id == MSG_ROUTING_NONE),
@@ -2827,7 +2828,7 @@
       gfx::Rect initial_rect;  // Report an empty initial rect.
       delegate_->AddNewContents(this, std::move(owning_contents_impl),
                                 params.disposition, initial_rect,
-                                params.mimic_user_gesture, &was_blocked);
+                                has_user_gesture, &was_blocked);
       // The delegate may delete |new_contents_impl| during AddNewContents().
       if (!weak_new_contents)
         return;
@@ -2841,7 +2842,7 @@
       load_params->referrer = params.referrer.To<Referrer>();
       load_params->transition_type = ui::PAGE_TRANSITION_LINK;
       load_params->is_renderer_initiated = true;
-      load_params->has_user_gesture = params.mimic_user_gesture;
+      load_params->has_user_gesture = has_user_gesture;
 
       if (delegate_ && !is_guest &&
           !delegate_->ShouldResumeRequestsForCreatedWindow()) {
diff --git a/content/browser/web_contents/web_contents_impl.h b/content/browser/web_contents/web_contents_impl.h
index 9e72788..ca355f6 100644
--- a/content/browser/web_contents/web_contents_impl.h
+++ b/content/browser/web_contents/web_contents_impl.h
@@ -572,6 +572,7 @@
       int32_t main_frame_route_id,
       int32_t main_frame_widget_route_id,
       const mojom::CreateNewWindowParams& params,
+      bool has_user_gesture,
       SessionStorageNamespace* session_storage_namespace) override;
   void ShowCreatedWindow(int process_id,
                          int main_frame_widget_route_id,
diff --git a/content/child/child_thread_impl.cc b/content/child/child_thread_impl.cc
index ef8341c..8f5e6f16 100644
--- a/content/child/child_thread_impl.cc
+++ b/content/child/child_thread_impl.cc
@@ -173,44 +173,6 @@
 
 #endif  // OS(POSIX)
 
-#if defined(OS_ANDROID)
-// A class that allows for triggering a clean shutdown from another
-// thread through draining the main thread's msg loop.
-class QuitClosure {
- public:
-  QuitClosure();
-  ~QuitClosure() = default;
-
-  void BindToMainThread(base::RepeatingClosure quit_closure);
-  void QuitFromNonMainThread();
-
- private:
-  base::Lock lock_;
-  base::ConditionVariable cond_var_;
-  base::RepeatingClosure closure_;
-};
-
-QuitClosure::QuitClosure() : cond_var_(&lock_) {
-}
-
-void QuitClosure::BindToMainThread(base::RepeatingClosure quit_closure) {
-  base::AutoLock lock(lock_);
-  closure_ = std::move(quit_closure);
-  cond_var_.Signal();
-}
-
-void QuitClosure::QuitFromNonMainThread() {
-  base::AutoLock lock(lock_);
-  while (closure_.is_null())
-    cond_var_.Wait();
-
-  closure_.Run();
-}
-
-base::LazyInstance<QuitClosure>::DestructorAtExit g_quit_closure =
-    LAZY_INSTANCE_INITIALIZER;
-#endif
-
 base::Optional<mojo::IncomingInvitation> InitializeMojoIPCChannel() {
   TRACE_EVENT0("startup", "InitializeMojoIPCChannel");
   mojo::PlatformChannelEndpoint endpoint;
@@ -539,10 +501,6 @@
                      channel_connected_factory_->GetWeakPtr()),
       base::TimeDelta::FromSeconds(connection_timeout));
 
-#if defined(OS_ANDROID)
-  g_quit_closure.Get().BindToMainThread(quit_closure_);
-#endif
-
   // In single-process mode, there is no need to synchronize trials to the
   // browser process (because it's the same process).
   if (!IsInBrowserProcess()) {
@@ -745,16 +703,6 @@
   return g_lazy_child_thread_impl_tls.Pointer()->Get();
 }
 
-#if defined(OS_ANDROID)
-// The method must NOT be called on the child thread itself.
-// It may block the child thread if so.
-void ChildThreadImpl::ShutdownThread() {
-  DCHECK(!ChildThreadImpl::current()) <<
-      "this method should NOT be called from child thread itself";
-  g_quit_closure.Get().QuitFromNonMainThread();
-}
-#endif
-
 void ChildThreadImpl::OnProcessFinalRelease() {
   if (on_channel_error_called_)
     return;
diff --git a/content/child/child_thread_impl.h b/content/child/child_thread_impl.h
index 6930f39..9f917bc 100644
--- a/content/child/child_thread_impl.h
+++ b/content/child/child_thread_impl.h
@@ -128,12 +128,6 @@
   // Returns the one child thread. Can only be called on the main thread.
   static ChildThreadImpl* current();
 
-#if defined(OS_ANDROID)
-  // Called on Android's service thread to shutdown the main thread of this
-  // process.
-  static void ShutdownThread();
-#endif
-
  protected:
   friend class ChildProcess;
 
diff --git a/content/public/android/java/src/org/chromium/content/app/ContentChildProcessServiceDelegate.java b/content/public/android/java/src/org/chromium/content/app/ContentChildProcessServiceDelegate.java
index 511b0596..08bd28d 100644
--- a/content/public/android/java/src/org/chromium/content/app/ContentChildProcessServiceDelegate.java
+++ b/content/public/android/java/src/org/chromium/content/app/ContentChildProcessServiceDelegate.java
@@ -178,13 +178,6 @@
     }
 
     @Override
-    public void onDestroy() {
-        // Try to shutdown the MainThread gracefully, but it might not have a
-        // chance to exit normally.
-        nativeShutdownMainThread();
-    }
-
-    @Override
     public void runMain() {
         ContentMain.start(false);
     }
@@ -254,8 +247,6 @@
      */
     private native void nativeInitChildProcess(int cpuCount, long cpuFeatures);
 
-    private native void nativeShutdownMainThread();
-
     // Retrieves the FD IDs to keys map and set it by calling setFileDescriptorsIdsToKeys().
     private native void nativeRetrieveFileDescriptorsIdsToKeys();
 }
diff --git a/content/public/android/javatests/src/org/chromium/content/browser/ChildProcessLauncherTest.java b/content/public/android/javatests/src/org/chromium/content/browser/ChildProcessLauncherTest.java
index ab51244..a884640 100644
--- a/content/public/android/javatests/src/org/chromium/content/browser/ChildProcessLauncherTest.java
+++ b/content/public/android/javatests/src/org/chromium/content/browser/ChildProcessLauncherTest.java
@@ -162,11 +162,6 @@
             mOnRunMainHelper.notifyCalled();
         }
 
-        @Override
-        public void onDestroy() {
-            Assert.assertEquals(0, mOnDestroyHelper.getCallCount());
-        }
-
         public void waitForOnConnectionSetupCalled() throws InterruptedException, TimeoutException {
             mOnConnectionSetupHelper.waitForCallback(0 /* currentCallCount */);
         }
diff --git a/content/public/test/render_view_test.cc b/content/public/test/render_view_test.cc
index 9a5522e..1e5072f3 100644
--- a/content/public/test/render_view_test.cc
+++ b/content/public/test/render_view_test.cc
@@ -420,7 +420,8 @@
           EXPECT_EQ(0u, result->number_of_live_nodes);
           EXPECT_EQ(0u, result->number_of_live_layout_objects);
           EXPECT_EQ(0u, result->number_of_live_resources);
-          EXPECT_EQ(0u, result->number_of_live_pausable_objects);
+          EXPECT_EQ(0u,
+                    result->number_of_live_context_lifecycle_state_observers);
           EXPECT_EQ(0u, result->number_of_live_script_promises);
           EXPECT_EQ(0u, result->number_of_live_frames);
           EXPECT_EQ(0u, result->number_of_live_v8_per_context_data);
diff --git a/content/renderer/appcache/appcache_frontend_impl.cc b/content/renderer/appcache/appcache_frontend_impl.cc
index eaae942..49135bb 100644
--- a/content/renderer/appcache/appcache_frontend_impl.cc
+++ b/content/renderer/appcache/appcache_frontend_impl.cc
@@ -44,15 +44,6 @@
     host->OnCacheSelected(*info);
 }
 
-void AppCacheFrontendImpl::StatusChanged(const std::vector<int32_t>& host_ids,
-                                         blink::mojom::AppCacheStatus status) {
-  for (auto i = host_ids.begin(); i != host_ids.end(); ++i) {
-    WebApplicationCacheHostImpl* host = GetHost(*i);
-    if (host)
-      host->OnStatusChanged(status);
-  }
-}
-
 void AppCacheFrontendImpl::EventRaised(const std::vector<int32_t>& host_ids,
                                        blink::mojom::AppCacheEventID event_id) {
   DCHECK_NE(event_id,
diff --git a/content/renderer/appcache/appcache_frontend_impl.h b/content/renderer/appcache/appcache_frontend_impl.h
index 7f37f6a..3bde802 100644
--- a/content/renderer/appcache/appcache_frontend_impl.h
+++ b/content/renderer/appcache/appcache_frontend_impl.h
@@ -31,8 +31,6 @@
   // blink::mojom::AppCacheFrontend
   void CacheSelected(int32_t host_id,
                      blink::mojom::AppCacheInfoPtr info) override;
-  void StatusChanged(const std::vector<int32_t>& host_ids,
-                     blink::mojom::AppCacheStatus status) override;
   void EventRaised(const std::vector<int32_t>& host_ids,
                    blink::mojom::AppCacheEventID event_id) override;
   void ProgressEventRaised(const std::vector<int32_t>& host_ids,
diff --git a/content/renderer/appcache/web_application_cache_host_impl.cc b/content/renderer/appcache/web_application_cache_host_impl.cc
index 944287a..b06bdda5 100644
--- a/content/renderer/appcache/web_application_cache_host_impl.cc
+++ b/content/renderer/appcache/web_application_cache_host_impl.cc
@@ -94,11 +94,6 @@
   client_->DidChangeCacheAssociation();
 }
 
-void WebApplicationCacheHostImpl::OnStatusChanged(
-    blink::mojom::AppCacheStatus status) {
-  // TODO(michaeln): delete me, not used
-}
-
 void WebApplicationCacheHostImpl::OnEventRaised(
     blink::mojom::AppCacheEventID event_id) {
   DCHECK_NE(event_id,
diff --git a/content/renderer/appcache/web_application_cache_host_impl.h b/content/renderer/appcache/web_application_cache_host_impl.h
index 4c3b4936..d70e479 100644
--- a/content/renderer/appcache/web_application_cache_host_impl.h
+++ b/content/renderer/appcache/web_application_cache_host_impl.h
@@ -35,7 +35,6 @@
   blink::WebApplicationCacheHostClient* client() const { return client_; }
 
   virtual void OnCacheSelected(const blink::mojom::AppCacheInfo& info);
-  void OnStatusChanged(blink::mojom::AppCacheStatus);
   void OnEventRaised(blink::mojom::AppCacheEventID);
   void OnProgressEventRaised(const GURL& url, int num_total, int num_complete);
   void OnErrorEventRaised(const blink::mojom::AppCacheErrorDetails& details);
diff --git a/content/renderer/render_view_impl.cc b/content/renderer/render_view_impl.cc
index 0623b9f..2d0908f 100644
--- a/content/renderer/render_view_impl.cc
+++ b/content/renderer/render_view_impl.cc
@@ -1301,6 +1301,10 @@
       base::FeatureList::IsEnabled(features::kUserActivationV2)
           ? false
           : WebUserGestureIndicator::IsProcessingUserGesture(creator);
+  // TODO(mustaq): Investigate if mimic_user_gesture can wrongly expose presence
+  // of user activation w/o any user interaction, e.g. through
+  // |WebChromeClient#onCreateWindow|. One case to deep-dive: disabling popup
+  // blocker then calling window.open at onload event. crbug.com/929729
   if (GetContentClient()->renderer()->AllowPopup())
     params->mimic_user_gesture = true;
 
@@ -1357,8 +1361,10 @@
 
   // The browser allowed creation of a new window and consumed the user
   // activation (UAv2 only).
-  WebUserGestureIndicator::ConsumeUserGesture(
+  bool was_consumed = WebUserGestureIndicator::ConsumeUserGesture(
       creator, blink::UserActivationUpdateSource::kBrowser);
+  if (base::FeatureList::IsEnabled(features::kUserActivationV2))
+    opened_by_user_gesture = was_consumed;
 
   // While this view may be a background extension page, it can spawn a visible
   // render view. So we just assume that the new one is not another background
diff --git a/content/shell/android/shell_apk/src/org/chromium/content_shell_apk/IChildProcessTest.aidl b/content/shell/android/shell_apk/src/org/chromium/content_shell_apk/IChildProcessTest.aidl
index b413d556..2064f038 100644
--- a/content/shell/android/shell_apk/src/org/chromium/content_shell_apk/IChildProcessTest.aidl
+++ b/content/shell/android/shell_apk/src/org/chromium/content_shell_apk/IChildProcessTest.aidl
@@ -20,6 +20,4 @@
   oneway void onBeforeMain(in String[] commandLine);
 
   oneway void onRunMain();
-
-  oneway void onDestroy();
 }
diff --git a/content/shell/android/shell_apk/src/org/chromium/content_shell_apk/TestChildProcessService.java b/content/shell/android/shell_apk/src/org/chromium/content_shell_apk/TestChildProcessService.java
index 983dcd786..7736c6d 100644
--- a/content/shell/android/shell_apk/src/org/chromium/content_shell_apk/TestChildProcessService.java
+++ b/content/shell/android/shell_apk/src/org/chromium/content_shell_apk/TestChildProcessService.java
@@ -73,16 +73,6 @@
         }
 
         @Override
-        public void onDestroy() {
-            if (mIChildProcessTest == null) return;
-            try {
-                mIChildProcessTest.onDestroy();
-            } catch (RemoteException re) {
-                Log.e(TAG, "Failed to call IChildProcessTest.onDestroy.", re);
-            }
-        }
-
-        @Override
         public void preloadNativeLibrary(Context hostContext) {
             LibraryLoader.getInstance().preloadNow();
         }
diff --git a/content/shell/browser/shell_devtools_bindings.h b/content/shell/browser/shell_devtools_bindings.h
index 8b79f54..a346a3f 100644
--- a/content/shell/browser/shell_devtools_bindings.h
+++ b/content/shell/browser/shell_devtools_bindings.h
@@ -33,7 +33,7 @@
 class ShellDevToolsDelegate {
  public:
   virtual void Close() = 0;
-  virtual ~ShellDevToolsDelegate(){};
+  virtual ~ShellDevToolsDelegate() {}
 };
 
 class WebContents;
diff --git a/content/shell/browser/web_test/leak_detector.cc b/content/shell/browser/web_test/leak_detector.cc
index fba612f9..b2b9814 100644
--- a/content/shell/browser/web_test/leak_detector.cc
+++ b/content/shell/browser/web_test/leak_detector.cc
@@ -32,7 +32,7 @@
 const int kInitialNumberOfLiveFrames = 1;
 const int kInitialNumberOfWorkerGlobalScopes = 0;
 const int kInitialNumberOfLiveResourceFetchers = 1;
-const int kInitialNumberOfLivePausableObject = 0;
+const int kInitialNumberOfLiveContextLifecycleStateObservers = 0;
 
 // This includes not only about:blank's context but also ScriptRegexp (e.g.
 // created by isValidEmailAddress in EmailInputType.cpp). The leak detector
@@ -48,8 +48,8 @@
   previous_result_->number_of_live_layout_objects =
       kInitialNumberOfLiveLayoutObjects;
   previous_result_->number_of_live_resources = kInitialNumberOfLiveResources;
-  previous_result_->number_of_live_pausable_objects =
-      kInitialNumberOfLivePausableObject;
+  previous_result_->number_of_live_context_lifecycle_state_observers =
+      kInitialNumberOfLiveContextLifecycleStateObservers;
   previous_result_->number_of_live_script_promises =
       kInitialNumberOfScriptPromises;
   previous_result_->number_of_live_frames = kInitialNumberOfLiveFrames;
@@ -118,12 +118,14 @@
       list->AppendInteger(result->number_of_live_resources);
       detail.Set("numberOfLiveResources", std::move(list));
     }
-    if (previous_result_->number_of_live_pausable_objects <
-        result->number_of_live_pausable_objects) {
+    if (previous_result_->number_of_live_context_lifecycle_state_observers <
+        result->number_of_live_context_lifecycle_state_observers) {
       auto list = std::make_unique<base::ListValue>();
-      list->AppendInteger(previous_result_->number_of_live_pausable_objects);
-      list->AppendInteger(result->number_of_live_pausable_objects);
-      detail.Set("numberOfLivePausableObjects", std::move(list));
+      list->AppendInteger(
+          previous_result_->number_of_live_context_lifecycle_state_observers);
+      list->AppendInteger(
+          result->number_of_live_context_lifecycle_state_observers);
+      detail.Set("numberOfLiveContextLifecycleStateObservers", std::move(list));
     }
     if (previous_result_->number_of_live_script_promises <
         result->number_of_live_script_promises) {
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 e0ee6a8..fa9a354 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
@@ -56,7 +56,7 @@
 class TestOverlayWindow : public OverlayWindow {
  public:
   TestOverlayWindow() = default;
-  ~TestOverlayWindow() override{};
+  ~TestOverlayWindow() override {}
 
   static std::unique_ptr<OverlayWindow> Create(
       PictureInPictureWindowController* controller) {
diff --git a/content/shell/renderer/web_test/blink_test_runner.cc b/content/shell/renderer/web_test/blink_test_runner.cc
index be97174..2ac4a761 100644
--- a/content/shell/renderer/web_test/blink_test_runner.cc
+++ b/content/shell/renderer/web_test/blink_test_runner.cc
@@ -158,7 +158,7 @@
   void Stop() override {}
   void SetVolume(double volume) override {}
   void SetAutomaticGainControl(bool enable) override {}
-  void SetOutputDeviceForAec(const std::string& output_device_id) override{};
+  void SetOutputDeviceForAec(const std::string& output_device_id) override {}
 
  protected:
   ~MockAudioCapturerSource() override {}
diff --git a/content/test/data/accessibility/event/aria-combo-box-expand-expected-auralinux.txt b/content/test/data/accessibility/event/aria-combo-box-expand-expected-auralinux.txt
index 932223d..1045580 100644
--- a/content/test/data/accessibility/event/aria-combo-box-expand-expected-auralinux.txt
+++ b/content/test/data/accessibility/event/aria-combo-box-expand-expected-auralinux.txt
@@ -1,2 +1,3 @@
+SELECTION-CHANGED role=ROLE_LIST_BOX name='(null)' ENABLED,SENSITIVE,SHOWING,VERTICAL,VISIBLE
 STATE-CHANGE:EXPANDED:TRUE role=ROLE_COMBO_BOX name='(null)' EDITABLE,ENABLED,EXPANDABLE,EXPANDED,FOCUSABLE,FOCUSED,SENSITIVE,SHOWING,SINGLE-LINE,VISIBLE,SUPPORTS-AUTOCOMPLETION,SELECTABLE-TEXT
 STATE-CHANGE:SELECTED:TRUE role=ROLE_LIST_ITEM name='Apple' ENABLED,FOCUSABLE,SELECTABLE,SELECTED,SENSITIVE,SHOWING,VISIBLE
diff --git a/content/test/data/accessibility/event/aria-combo-box-next-expected-auralinux.txt b/content/test/data/accessibility/event/aria-combo-box-next-expected-auralinux.txt
index 77643548..e4a326d 100644
--- a/content/test/data/accessibility/event/aria-combo-box-next-expected-auralinux.txt
+++ b/content/test/data/accessibility/event/aria-combo-box-next-expected-auralinux.txt
@@ -1 +1,2 @@
+SELECTION-CHANGED role=ROLE_LIST_BOX name='(null)' ENABLED,SENSITIVE,SHOWING,VERTICAL,VISIBLE
 STATE-CHANGE:SELECTED:TRUE role=ROLE_LIST_ITEM name='Banana' ENABLED,FOCUSABLE,SELECTABLE,SELECTED,SENSITIVE,SHOWING,VISIBLE
diff --git a/content/test/data/accessibility/event/listbox-next-expected-auralinux.txt b/content/test/data/accessibility/event/listbox-next-expected-auralinux.txt
index 264c9d4..1d8398ddd 100644
--- a/content/test/data/accessibility/event/listbox-next-expected-auralinux.txt
+++ b/content/test/data/accessibility/event/listbox-next-expected-auralinux.txt
@@ -1,5 +1,6 @@
 FOCUS-EVENT role=ROLE_LIST_BOX name='(null)' ENABLED,FOCUSABLE,FOCUSED,SENSITIVE,SHOWING,VERTICAL,VISIBLE
 FOCUS-EVENT role=ROLE_LIST_ITEM name='Orange' ENABLED,FOCUSABLE,SELECTABLE,SELECTED,SENSITIVE,SHOWING,VISIBLE
+SELECTION-CHANGED role=ROLE_LIST_BOX name='(null)' ENABLED,FOCUSABLE,FOCUSED,SENSITIVE,SHOWING,VERTICAL,VISIBLE
 STATE-CHANGE:FOCUSED:FALSE role=ROLE_LIST_BOX name='(null)' ENABLED,FOCUSABLE,FOCUSED,SENSITIVE,SHOWING,VERTICAL,VISIBLE
 STATE-CHANGE:FOCUSED:TRUE role=ROLE_LIST_ITEM name='Orange' ENABLED,FOCUSABLE,SELECTABLE,SELECTED,SENSITIVE,SHOWING,VISIBLE
 STATE-CHANGE:SELECTED:TRUE role=ROLE_LIST_ITEM name='Orange' ENABLED,FOCUSABLE,SELECTABLE,SELECTED,SENSITIVE,SHOWING,VISIBLE
diff --git a/content/test/test_web_contents.cc b/content/test/test_web_contents.cc
index 8abd2624..83036e431 100644
--- a/content/test/test_web_contents.cc
+++ b/content/test/test_web_contents.cc
@@ -384,6 +384,7 @@
     int32_t main_frame_route_id,
     int32_t main_frame_widget_route_id,
     const mojom::CreateNewWindowParams& params,
+    bool has_user_gesture,
     SessionStorageNamespace* session_storage_namespace) {}
 
 void TestWebContents::CreateNewWidget(int32_t render_process_id,
diff --git a/content/test/test_web_contents.h b/content/test/test_web_contents.h
index d76df20..bd8667d 100644
--- a/content/test/test_web_contents.h
+++ b/content/test/test_web_contents.h
@@ -176,6 +176,7 @@
       int32_t main_frame_route_id,
       int32_t main_frame_widget_route_id,
       const mojom::CreateNewWindowParams& params,
+      bool has_user_gesture,
       SessionStorageNamespace* session_storage_namespace) override;
   void CreateNewWidget(int32_t render_process_id,
                        int32_t route_id,
diff --git a/courgette/courgette_tool.cc b/courgette/courgette_tool.cc
index a8e29201..2ff9af7 100644
--- a/courgette/courgette_tool.cc
+++ b/courgette/courgette_tool.cc
@@ -259,7 +259,7 @@
     if (status != bsdiff::OK)
       Problem("-xxx failed.");
 
-    std::string append = std::string("-") + base::IntToString(i);
+    std::string append = std::string("-") + base::NumberToString(i);
 
     WriteSinkToFile(&patch_stream,
                     output_file_root.InsertBeforeExtensionASCII(append));
diff --git a/courgette/ensemble.cc b/courgette/ensemble.cc
index 1031a1d6..2533e7b 100644
--- a/courgette/ensemble.cc
+++ b/courgette/ensemble.cc
@@ -24,7 +24,7 @@
 Element::~Element() = default;
 
 std::string Element::Name() const {
-  return ensemble_->name() + "(" + base::IntToString(kind()) + "," +
+  return ensemble_->name() + "(" + base::NumberToString(kind()) + "," +
          base::NumberToString(offset_in_ensemble()) + "," +
          base::NumberToString(region().length()) + ")";
 }
diff --git a/courgette/memory_monitor.cc b/courgette/memory_monitor.cc
index a480531b..fb278b98 100644
--- a/courgette/memory_monitor.cc
+++ b/courgette/memory_monitor.cc
@@ -27,7 +27,7 @@
     if (s > 1000000000) return base::StringPrintf("%.3gG", s/(1000000000.0));
     if (s > 1000000) return base::StringPrintf("%.3gM", s/(1000000.));
     if (s > 9999) return base::StringPrintf("%.3gk", s/(1000.));
-    return base::IntToString((int)s);
+    return base::NumberToString(s);
   }
 
   void tick(size_t w, char sign) {
diff --git a/device/vr/orientation/orientation_device_provider_unittest.cc b/device/vr/orientation/orientation_device_provider_unittest.cc
index 319150b..f7da7c8 100644
--- a/device/vr/orientation/orientation_device_provider_unittest.cc
+++ b/device/vr/orientation/orientation_device_provider_unittest.cc
@@ -90,12 +90,12 @@
     return base::BindRepeating([](device::mojom::XRDeviceId id,
                                   mojom::VRDisplayInfoPtr,
                                   mojom::XRRuntimePtr device) { FAIL(); });
-  };
+  }
 
   base::RepeatingCallback<void(device::mojom::XRDeviceId)>
   DeviceIdCallbackFailIfCalled() {
     return base::BindRepeating([](device::mojom::XRDeviceId id) { FAIL(); });
-  };
+  }
 
   base::RepeatingCallback<void(device::mojom::XRDeviceId,
                                mojom::VRDisplayInfoPtr,
@@ -109,7 +109,7 @@
           std::move(quit_closure).Run();
         },
         loop->QuitClosure());
-  };
+  }
 
   base::RepeatingCallback<void(device::mojom::XRDeviceId)>
   DeviceIdCallbackMustBeCalled(base::RunLoop* loop) {
@@ -118,17 +118,17 @@
           std::move(quit_closure).Run();
         },
         loop->QuitClosure());
-  };
+  }
 
   base::OnceClosure ClosureFailIfCalled() {
     return base::BindOnce([]() { FAIL(); });
-  };
+  }
 
   base::OnceClosure ClosureMustBeCalled(base::RunLoop* loop) {
     return base::BindOnce(
         [](base::OnceClosure quit_closure) { std::move(quit_closure).Run(); },
         loop->QuitClosure());
-  };
+  }
 
   // Needed for MakeRequest to work.
   base::test::ScopedTaskEnvironment scoped_task_environment_;
diff --git a/device/vr/orientation/orientation_device_unittest.cc b/device/vr/orientation/orientation_device_unittest.cc
index 68fd5cc..afeda8c 100644
--- a/device/vr/orientation/orientation_device_unittest.cc
+++ b/device/vr/orientation/orientation_device_unittest.cc
@@ -36,11 +36,11 @@
  public:
   FakeScreen() = default;
   ~FakeScreen() override = default;
-  display::Display GetPrimaryDisplay() const override { return display; };
+  display::Display GetPrimaryDisplay() const override { return display; }
 
   // Unused functions
-  gfx::Point GetCursorScreenPoint() override { return gfx::Point(); };
-  bool IsWindowUnderCursor(gfx::NativeWindow window) override { return false; };
+  gfx::Point GetCursorScreenPoint() override { return gfx::Point(); }
+  bool IsWindowUnderCursor(gfx::NativeWindow window) override { return false; }
   gfx::NativeWindow GetWindowAtScreenPoint(const gfx::Point& point) override {
     return nullptr;
   }
@@ -52,7 +52,7 @@
       const gfx::Point& point) const override {
     return display;
   }
-  int GetNumDisplays() const override { return 0; };
+  int GetNumDisplays() const override { return 0; }
   display::Display GetDisplayMatching(
       const gfx::Rect& match_rect) const override {
     return display;
diff --git a/device/vr/test/fake_vr_service_client.h b/device/vr/test/fake_vr_service_client.h
index e7ee410c..1adf196c 100644
--- a/device/vr/test/fake_vr_service_client.h
+++ b/device/vr/test/fake_vr_service_client.h
@@ -19,7 +19,7 @@
   FakeVRServiceClient(mojom::VRServiceClientRequest request);
   ~FakeVRServiceClient() override;
 
-  void OnDeviceChanged() override{};
+  void OnDeviceChanged() override {}
   void SetLastDeviceId(mojom::XRDeviceId id);
   bool CheckDeviceId(mojom::XRDeviceId id);
 
diff --git a/extensions/browser/process_map.cc b/extensions/browser/process_map.cc
index 1928d3d5..306b2c15 100644
--- a/extensions/browser/process_map.cc
+++ b/extensions/browser/process_map.cc
@@ -16,8 +16,6 @@
 
 // Item
 struct ProcessMap::Item {
-  Item() {}
-
   Item(const std::string& extension_id, int process_id,
        int site_instance_id)
       : extension_id(extension_id),
diff --git a/extensions/renderer/bindings/api_request_handler_unittest.cc b/extensions/renderer/bindings/api_request_handler_unittest.cc
index b21acbc..645bc741 100644
--- a/extensions/renderer/bindings/api_request_handler_unittest.cc
+++ b/extensions/renderer/bindings/api_request_handler_unittest.cc
@@ -46,7 +46,7 @@
 
   void SaveUserActivationState(base::Optional<bool>* ran_with_user_gesture) {
     *ran_with_user_gesture = GetTestUserActivationState(MainContext());
-  };
+  }
 
  protected:
   APIRequestHandlerTest() {}
diff --git a/extensions/renderer/native_extension_bindings_system_unittest.cc b/extensions/renderer/native_extension_bindings_system_unittest.cc
index c2f0937..e2cf4ae 100644
--- a/extensions/renderer/native_extension_bindings_system_unittest.cc
+++ b/extensions/renderer/native_extension_bindings_system_unittest.cc
@@ -34,7 +34,7 @@
   v8::Local<v8::Value> value = V8ValueFromScriptSource(context, property);
   EXPECT_FALSE(value.IsEmpty());
   return !value->IsUndefined();
-};
+}
 
 }  // namespace
 
diff --git a/extensions/renderer/wake_event_page.cc b/extensions/renderer/wake_event_page.cc
index 688d3082..a9ae4eb9 100644
--- a/extensions/renderer/wake_event_page.cc
+++ b/extensions/renderer/wake_event_page.cc
@@ -59,7 +59,7 @@
         kWakeEventPageFunctionName,
         base::BindRepeating(&WakeEventPageNativeHandler::DoWakeEventPage,
                             base::Unretained(this)));
-  };
+  }
 
   ~WakeEventPageNativeHandler() override {}
 
diff --git a/ios/chrome/browser/ui/side_swipe/BUILD.gn b/ios/chrome/browser/ui/side_swipe/BUILD.gn
index 6dde15c..009ea90 100644
--- a/ios/chrome/browser/ui/side_swipe/BUILD.gn
+++ b/ios/chrome/browser/ui/side_swipe/BUILD.gn
@@ -29,6 +29,7 @@
     "//ios/chrome/browser/tabs",
     "//ios/chrome/browser/ui",
     "//ios/chrome/browser/ui:feature_flags",
+    "//ios/chrome/browser/ui/elements",
     "//ios/chrome/browser/ui/fullscreen",
     "//ios/chrome/browser/ui/ntp",
     "//ios/chrome/browser/ui/ntp:util",
diff --git a/ios/chrome/browser/ui/side_swipe/swipe_view.mm b/ios/chrome/browser/ui/side_swipe/swipe_view.mm
index f487939..b387569 100644
--- a/ios/chrome/browser/ui/side_swipe/swipe_view.mm
+++ b/ios/chrome/browser/ui/side_swipe/swipe_view.mm
@@ -4,6 +4,7 @@
 
 #import "ios/chrome/browser/ui/side_swipe/swipe_view.h"
 
+#import "ios/chrome/browser/ui/elements/top_aligned_image_view.h"
 #include "ios/chrome/browser/ui/util/ui_util.h"
 #include "ios/web/public/features.h"
 
@@ -19,7 +20,7 @@
 @property(nonatomic, strong) NSLayoutConstraint* toolbarTopConstraint;
 @property(nonatomic, strong) NSLayoutConstraint* imageTopConstraint;
 
-@property(nonatomic, strong) UIImageView* imageView;
+@property(nonatomic, strong) TopAlignedImageView* imageView;
 
 @end
 
@@ -37,9 +38,7 @@
   if (self) {
     _topMargin = topMargin;
 
-    _imageView = [[UIImageView alloc] initWithFrame:CGRectZero];
-    [_imageView setClipsToBounds:YES];
-    [_imageView setContentMode:UIViewContentModeScaleAspectFill];
+    _imageView = [[TopAlignedImageView alloc] init];
     [_imageView setBackgroundColor:[UIColor whiteColor]];
     [self addSubview:_imageView];
 
diff --git a/ios/net/cookies/cookie_store_ios.h b/ios/net/cookies/cookie_store_ios.h
index d0b30b0..ed06499 100644
--- a/ios/net/cookies/cookie_store_ios.h
+++ b/ios/net/cookies/cookie_store_ios.h
@@ -193,6 +193,11 @@
   void DeleteCookiesMatchingInfoAsync(net::CookieDeletionInfo delete_info,
                                       DeleteCallback callback);
 
+  void DeleteCookiesMatchingPredicateAsync(
+      const base::RepeatingCallback<bool(const net::CanonicalCookie&)>&
+          predicate,
+      DeleteCallback callback);
+
   // Flush to CookieMonster from |cookies|, and run |callback|.
   void FlushStoreFromCookies(base::OnceClosure callback,
                              NSArray<NSHTTPCookie*>* cookies);
diff --git a/ios/net/cookies/cookie_store_ios.mm b/ios/net/cookies/cookie_store_ios.mm
index 0c4f5c4..821c1a05 100644
--- a/ios/net/cookies/cookie_store_ios.mm
+++ b/ios/net/cookies/cookie_store_ios.mm
@@ -420,9 +420,14 @@
   // instead.
   DCHECK(SystemCookiesAllowed());
 
-  // This relies on the fact cookies are given unique creation dates.
-  CookieDeletionInfo delete_info(cookie.CreationDate(), cookie.CreationDate());
-  DeleteCookiesMatchingInfoAsync(std::move(delete_info), std::move(callback));
+  DeleteCookiesMatchingPredicateAsync(base::BindRepeating(
+                                          [](const net::CanonicalCookie& target,
+                                             const net::CanonicalCookie& cc) {
+                                            return cc.IsEquivalent(target) &&
+                                                   cc.Value() == target.Value();
+                                          },
+                                          cookie),
+                                      std::move(callback));
 }
 
 void CookieStoreIOS::DeleteAllCreatedInTimeRangeAsync(
@@ -567,11 +572,25 @@
 }
 
 void CookieStoreIOS::DeleteCookiesMatchingInfoAsync(
-    CookieDeletionInfo delete_info,
+    net::CookieDeletionInfo delete_info,
+    DeleteCallback callback) {
+  DeleteCookiesMatchingPredicateAsync(
+      base::BindRepeating(
+          [](const CookieDeletionInfo& delete_info,
+             const net::CanonicalCookie& cc) {
+            return delete_info.Matches(cc);
+          },
+          std::move(delete_info)),
+      std::move(callback));
+}
+
+void CookieStoreIOS::DeleteCookiesMatchingPredicateAsync(
+    const base::RepeatingCallback<bool(const net::CanonicalCookie&)>& predicate,
     DeleteCallback callback) {
   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
   __block DeleteCallback shared_callback = std::move(callback);
-  __block CookieDeletionInfo shared_delete_info = std::move(delete_info);
+  __block base::RepeatingCallback<bool(const net::CanonicalCookie&)>
+      shared_predicate = predicate;
   base::WeakPtr<SystemCookieStore> weak_system_store =
       system_store_->GetWeakPtr();
   system_store_->GetAllCookiesAsync(
@@ -587,7 +606,7 @@
               weak_system_store->GetCookieCreationTime(cookie);
           CanonicalCookie cc =
               CanonicalCookieFromSystemCookie(cookie, creation_time);
-          if (shared_delete_info.Matches(cc)) {
+          if (shared_predicate.Run(cc)) {
             weak_system_store->DeleteCookieAsync(
                 cookie, SystemCookieStore::SystemCookieCallback());
             to_delete_count++;
diff --git a/ios/net/cookies/cookie_store_ios_unittest.mm b/ios/net/cookies/cookie_store_ios_unittest.mm
index 9962f4ba3..819ef6e 100644
--- a/ios/net/cookies/cookie_store_ios_unittest.mm
+++ b/ios/net/cookies/cookie_store_ios_unittest.mm
@@ -14,10 +14,12 @@
 #include "base/message_loop/message_loop.h"
 #include "base/run_loop.h"
 #include "base/strings/sys_string_conversions.h"
+#include "base/test/bind_test_util.h"
 #include "ios/net/cookies/cookie_store_ios_client.h"
 #import "ios/net/cookies/cookie_store_ios_test_util.h"
 #import "ios/net/cookies/ns_http_system_cookie_store.h"
 #import "net/base/mac/url_conversions.h"
+#include "net/cookies/canonical_cookie.h"
 #include "net/cookies/cookie_store_change_unittest.h"
 #include "net/cookies/cookie_store_unittest.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -231,6 +233,64 @@
   DeleteSystemCookie(kTestCookieURLFooBar, "abc");
 }
 
+TEST_F(CookieStoreIOSTest, DeleteCanonicalCookie) {
+  // Make sure DeleteCanonicalCookieAsync does not rely on creation time.
+  GetCookies(base::BindOnce(&IgnoreList));
+  ClearCookies();
+  SetCookie("abc=def");
+
+  // Match options to what SetCookie uses.
+  CookieOptions options;
+  options.set_include_httponly();
+
+  // Time is different, though.
+  base::Time not_now = base::Time::Now() - base::TimeDelta::FromDays(30);
+
+  // Semantics for CookieMonster::DeleteCanonicalCookieAsync don't match deletes
+  // for same key if cookie value changed.  Document CookieStoreIOS compat.
+  std::unique_ptr<CanonicalCookie> non_equiv_cookie = CanonicalCookie::Create(
+      kTestCookieURLFooBar, "abc=wfg", not_now, options);
+  base::RunLoop run_loop;
+  store_->DeleteCanonicalCookieAsync(
+      *non_equiv_cookie, base::BindLambdaForTesting([&](uint32_t deleted) {
+        EXPECT_EQ(0U, deleted);
+        run_loop.Quit();
+      }));
+  run_loop.Run();
+
+  // Cookie should still exist.
+  base::RunLoop run_loop2;
+  GetCookies(base::BindLambdaForTesting(
+      [&](const CookieList& cookies, const CookieStatusList& excluded_list) {
+        ASSERT_EQ(1u, cookies.size());
+        EXPECT_EQ("abc", cookies[0].Name());
+        EXPECT_EQ("def", cookies[0].Value());
+        run_loop2.Quit();
+      }));
+  run_loop2.Run();
+
+  // Now delete equivalent one with non-matching ctime.
+  std::unique_ptr<CanonicalCookie> equiv_cookie = CanonicalCookie::Create(
+      kTestCookieURLFooBar, "abc=def", not_now, options);
+
+  base::RunLoop run_loop3;
+  store_->DeleteCanonicalCookieAsync(
+      *equiv_cookie, base::BindLambdaForTesting([&](uint32_t deleted) {
+        EXPECT_EQ(1U, deleted);
+        run_loop3.Quit();
+      }));
+  run_loop3.Run();
+
+  // Cookie should no longer exist.
+  base::RunLoop run_loop4;
+  GetCookies(base::BindLambdaForTesting(
+      [&](const CookieList& cookies, const CookieStatusList& excluded_list) {
+        EXPECT_EQ(0u, cookies.size());
+        run_loop4.Quit();
+      }));
+  run_loop4.Run();
+}
+
 TEST_F(CookieStoreIOSTest, DeleteCallsHook) {
   GetCookies(base::BindOnce(&IgnoreList));
   ClearCookies();
diff --git a/media/base/pipeline_impl_unittest.cc b/media/base/pipeline_impl_unittest.cc
index 10a9974d..426bf90 100644
--- a/media/base/pipeline_impl_unittest.cc
+++ b/media/base/pipeline_impl_unittest.cc
@@ -1163,25 +1163,25 @@
     RunTest(k##state, k##stop_or_error);                  \
   }
 
-INSTANTIATE_TEARDOWN_TEST(Stop, InitDemuxer);
-INSTANTIATE_TEARDOWN_TEST(Stop, InitRenderer);
-INSTANTIATE_TEARDOWN_TEST(Stop, Flushing);
-INSTANTIATE_TEARDOWN_TEST(Stop, Seeking);
-INSTANTIATE_TEARDOWN_TEST(Stop, Playing);
-INSTANTIATE_TEARDOWN_TEST(Stop, Suspending);
-INSTANTIATE_TEARDOWN_TEST(Stop, Suspended);
-INSTANTIATE_TEARDOWN_TEST(Stop, Resuming);
+INSTANTIATE_TEARDOWN_TEST(Stop, InitDemuxer)
+INSTANTIATE_TEARDOWN_TEST(Stop, InitRenderer)
+INSTANTIATE_TEARDOWN_TEST(Stop, Flushing)
+INSTANTIATE_TEARDOWN_TEST(Stop, Seeking)
+INSTANTIATE_TEARDOWN_TEST(Stop, Playing)
+INSTANTIATE_TEARDOWN_TEST(Stop, Suspending)
+INSTANTIATE_TEARDOWN_TEST(Stop, Suspended)
+INSTANTIATE_TEARDOWN_TEST(Stop, Resuming)
 
-INSTANTIATE_TEARDOWN_TEST(Error, InitDemuxer);
-INSTANTIATE_TEARDOWN_TEST(Error, InitRenderer);
-INSTANTIATE_TEARDOWN_TEST(Error, Flushing);
-INSTANTIATE_TEARDOWN_TEST(Error, Seeking);
-INSTANTIATE_TEARDOWN_TEST(Error, Playing);
-INSTANTIATE_TEARDOWN_TEST(Error, Suspending);
-INSTANTIATE_TEARDOWN_TEST(Error, Suspended);
-INSTANTIATE_TEARDOWN_TEST(Error, Resuming);
+INSTANTIATE_TEARDOWN_TEST(Error, InitDemuxer)
+INSTANTIATE_TEARDOWN_TEST(Error, InitRenderer)
+INSTANTIATE_TEARDOWN_TEST(Error, Flushing)
+INSTANTIATE_TEARDOWN_TEST(Error, Seeking)
+INSTANTIATE_TEARDOWN_TEST(Error, Playing)
+INSTANTIATE_TEARDOWN_TEST(Error, Suspending)
+INSTANTIATE_TEARDOWN_TEST(Error, Suspended)
+INSTANTIATE_TEARDOWN_TEST(Error, Resuming)
 
-INSTANTIATE_TEARDOWN_TEST(ErrorAndStop, Playing);
-INSTANTIATE_TEARDOWN_TEST(ErrorAndStop, Suspended);
+INSTANTIATE_TEARDOWN_TEST(ErrorAndStop, Playing)
+INSTANTIATE_TEARDOWN_TEST(ErrorAndStop, Suspended)
 
 }  // namespace media
diff --git a/media/base/renderer_factory_selector_unittest.cc b/media/base/renderer_factory_selector_unittest.cc
index d44d49c..331f68d 100644
--- a/media/base/renderer_factory_selector_unittest.cc
+++ b/media/base/renderer_factory_selector_unittest.cc
@@ -18,7 +18,7 @@
 
   class FakeFactory : public RendererFactory {
    public:
-    FakeFactory(FactoryType type) : type_(type){};
+    FakeFactory(FactoryType type) : type_(type) {}
 
     std::unique_ptr<Renderer> CreateRenderer(
         const scoped_refptr<base::SingleThreadTaskRunner>& media_task_runner,
@@ -37,11 +37,10 @@
   };
 
   RendererFactorySelectorTest() = default;
-  ;
 
   void AddFactory(FactoryType type) {
     selector_.AddFactory(type, std::make_unique<FakeFactory>(type));
-  };
+  }
 
   FactoryType GetCurrentlySelectedFactoryType() {
     return reinterpret_cast<FakeFactory*>(selector_.GetCurrentFactory())
diff --git a/media/capabilities/learning_helper.cc b/media/capabilities/learning_helper.cc
index a70c0ced..d372566 100644
--- a/media/capabilities/learning_helper.cc
+++ b/media/capabilities/learning_helper.cc
@@ -5,10 +5,13 @@
 #include "media/capabilities/learning_helper.h"
 
 #include "base/task/post_task.h"
+#include "media/learning/common/feature_library.h"
 #include "media/learning/common/learning_task.h"
 
 namespace media {
 
+using learning::FeatureLibrary;
+using learning::FeatureProviderFactoryCB;
 using learning::FeatureValue;
 using learning::LabelledExample;
 using learning::LearningSessionImpl;
@@ -16,11 +19,17 @@
 using learning::SequenceBoundFeatureProvider;
 using learning::TargetValue;
 
-const char* const kDroppedFrameRatioTreeTaskName = "DroppedFrameRatioTreeTask";
-const char* const kDroppedFrameRatioTableTaskName =
-    "DroppedFrameRatioTableTask";
+// Dropped frame ratio, default features, regression tree.
+const char* const kDroppedFrameRatioBaseTreeTaskName =
+    "DroppedFrameRatioBaseTreeTask";
+// Dropped frame ratio, default+FeatureLibrary features, regression tree.
+const char* const kDroppedFrameRatioEnhancedTreeTaskName =
+    "DroppedFrameRatioEnhancedTreeTask";
+// Dropped frame ratio, default features, lookup table.
+const char* const kDroppedFrameRatioBaseTableTaskName =
+    "DroppedFrameRatioBaseTableTask";
 
-LearningHelper::LearningHelper() {
+LearningHelper::LearningHelper(FeatureProviderFactoryCB feature_factory) {
   // Create the LearningSession on a background task runner.  In the future,
   // it's likely that the session will live on the main thread, and handle
   // delegation of LearningTaskControllers to other threads.  However, for now,
@@ -35,7 +44,7 @@
   // We only do this here since we own the session.  Normally, whatever creates
   // the session would register all the learning tasks.
   LearningTask dropped_frame_task(
-      kDroppedFrameRatioTreeTaskName, LearningTask::Model::kExtraTrees,
+      kDroppedFrameRatioBaseTableTaskName, LearningTask::Model::kLookupTable,
       {
           {"codec_profile",
            ::media::learning::LearningTask::Ordering::kUnordered},
@@ -52,13 +61,25 @@
   learning_session_.Post(FROM_HERE, &LearningSessionImpl::RegisterTask,
                          dropped_frame_task, SequenceBoundFeatureProvider());
 
-  // Modify the task to use a table-based learner.
-  dropped_frame_task.name = kDroppedFrameRatioTableTaskName;
-  dropped_frame_task.model = LearningTask::Model::kLookupTable;
+  // Modify the task to use ExtraTrees.
+  dropped_frame_task.name = kDroppedFrameRatioBaseTreeTaskName;
+  dropped_frame_task.model = LearningTask::Model::kExtraTrees;
   dropped_frame_task.uma_hacky_confusion_matrix =
       "Media.Learning.MediaCapabilities.DroppedFrameRatioTask.BaseTable";
   learning_session_.Post(FROM_HERE, &LearningSessionImpl::RegisterTask,
                          dropped_frame_task, SequenceBoundFeatureProvider());
+
+  // Add common features, if we have a factory.
+  if (feature_factory) {
+    dropped_frame_task.name = kDroppedFrameRatioEnhancedTreeTaskName;
+    dropped_frame_task.feature_descriptions.push_back(
+        FeatureLibrary::NetworkType());
+    dropped_frame_task.uma_hacky_confusion_matrix =
+        "Media.Learning.MediaCapabilities.DroppedFrameRatioTask.EnhancedTree";
+    learning_session_.Post(FROM_HERE, &LearningSessionImpl::RegisterTask,
+                           dropped_frame_task,
+                           feature_factory.Run(dropped_frame_task));
+  }
 }
 
 LearningHelper::~LearningHelper() = default;
@@ -99,9 +120,12 @@
 
   // Add this example to both tasks.
   learning_session_.Post(FROM_HERE, &LearningSessionImpl::AddExample,
-                         kDroppedFrameRatioTreeTaskName, example);
+                         kDroppedFrameRatioBaseTreeTaskName, example);
   learning_session_.Post(FROM_HERE, &LearningSessionImpl::AddExample,
-                         kDroppedFrameRatioTableTaskName, example);
+                         kDroppedFrameRatioBaseTableTaskName, example);
+  // Might fail, but that's okay.
+  learning_session_.Post(FROM_HERE, &LearningSessionImpl::AddExample,
+                         kDroppedFrameRatioEnhancedTreeTaskName, example);
 }
 
 }  // namespace media
diff --git a/media/capabilities/learning_helper.h b/media/capabilities/learning_helper.h
index f75bf57..f0db4d2 100644
--- a/media/capabilities/learning_helper.h
+++ b/media/capabilities/learning_helper.h
@@ -9,6 +9,7 @@
 #include "base/threading/sequence_bound.h"
 #include "media/base/media_export.h"
 #include "media/capabilities/video_decode_stats_db.h"
+#include "media/learning/impl/feature_provider.h"
 #include "media/learning/impl/learning_session_impl.h"
 
 namespace media {
@@ -17,7 +18,9 @@
 // media::learning LearningTask.
 class MEDIA_EXPORT LearningHelper {
  public:
-  LearningHelper();
+  // |feature_factory| lets us register FeatureProviders with those
+  // LearningTasks that include standard features.
+  LearningHelper(learning::FeatureProviderFactoryCB feature_factory);
   ~LearningHelper();
 
   void AppendStats(const VideoDecodeStatsDB::VideoDescKey& video_key,
diff --git a/media/capture/video/fake_video_capture_device_unittest.cc b/media/capture/video/fake_video_capture_device_unittest.cc
index 330283f..c24fcee 100644
--- a/media/capture/video/fake_video_capture_device_unittest.cc
+++ b/media/capture/video/fake_video_capture_device_unittest.cc
@@ -98,7 +98,7 @@
       buffer_id, arbitrary_frame_feedback_id,
       std::make_unique<StubBufferHandleProvider>(mapped_size, buffer),
       std::make_unique<StubReadWritePermission>(buffer));
-};
+}
 
 class ImageCaptureClient : public base::RefCounted<ImageCaptureClient> {
  public:
@@ -617,4 +617,4 @@
                1u,
                FakeVideoCaptureDevice::DisplayMediaType::BROWSER,
                {PIXEL_FORMAT_I420}}));
-};  // namespace media
+}  // namespace media
diff --git a/media/capture/video/video_capture_device_unittest.cc b/media/capture/video/video_capture_device_unittest.cc
index 96ed245..c3157d8 100644
--- a/media/capture/video/video_capture_device_unittest.cc
+++ b/media/capture/video/video_capture_device_unittest.cc
@@ -881,4 +881,4 @@
 }
 #endif
 
-};  // namespace media
+}  // namespace media
diff --git a/media/cdm/library_cdm/clear_key_cdm/clear_key_cdm.cc b/media/cdm/library_cdm/clear_key_cdm/clear_key_cdm.cc
index 7602c347..5626fe3 100644
--- a/media/cdm/library_cdm/clear_key_cdm/clear_key_cdm.cc
+++ b/media/cdm/library_cdm/clear_key_cdm/clear_key_cdm.cc
@@ -945,7 +945,7 @@
   }
 #endif
   OnUnitTestComplete(true);
-};
+}
 
 void ClearKeyCdm::OnStorageId(uint32_t version,
                               const uint8_t* storage_id,
diff --git a/media/ffmpeg/ffmpeg_regression_tests.cc b/media/ffmpeg/ffmpeg_regression_tests.cc
index b20644c..1d8f1764 100644
--- a/media/ffmpeg/ffmpeg_regression_tests.cc
+++ b/media/ffmpeg/ffmpeg_regression_tests.cc
@@ -71,14 +71,14 @@
 #define FFMPEG_TEST_CASE_SEEKING(name, fn, init_status, end_status, seek_time) \
   INSTANTIATE_TEST_CASE_P(name, FFmpegRegressionTest,                          \
                           testing::Values(RegressionTestData(                  \
-                              fn, init_status, end_status, seek_time)));
+                              fn, init_status, end_status, seek_time)))
 
 #define FFMPEG_TEST_CASE(name, fn, init_status, end_status) \
   FFMPEG_TEST_CASE_SEEKING(name, fn, init_status, end_status, kNoTimestamp)
 
-#define FLAKY_FFMPEG_TEST_CASE(name, fn) \
-    INSTANTIATE_TEST_CASE_P(FLAKY_##name, FlakyFFmpegRegressionTest, \
-                            testing::Values(FlakyRegressionTestData(fn)));
+#define FLAKY_FFMPEG_TEST_CASE(name, fn)                           \
+  INSTANTIATE_TEST_CASE_P(FLAKY_##name, FlakyFFmpegRegressionTest, \
+                          testing::Values(FlakyRegressionTestData(fn)))
 
 // Test cases from issues.
 FFMPEG_TEST_CASE(Cr47325, "security/47325.mp4", PIPELINE_OK, PIPELINE_OK);
diff --git a/media/learning/common/BUILD.gn b/media/learning/common/BUILD.gn
index c8dba87..a4e6a44 100644
--- a/media/learning/common/BUILD.gn
+++ b/media/learning/common/BUILD.gn
@@ -20,6 +20,8 @@
   defines = [ "IS_LEARNING_COMMON_IMPL" ]
 
   sources = [
+    "feature_library.cc",
+    "feature_library.h",
     "labelled_example.cc",
     "labelled_example.h",
     "learning_session.cc",
diff --git a/media/learning/common/feature_library.cc b/media/learning/common/feature_library.cc
new file mode 100644
index 0000000..8fe39ad3
--- /dev/null
+++ b/media/learning/common/feature_library.cc
@@ -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.
+
+#include "media/learning/common/feature_library.h"
+
+namespace media {
+namespace learning {
+
+using ValueDescription = LearningTask::ValueDescription;
+using Ordering = LearningTask::Ordering;
+
+// static
+ValueDescription FeatureLibrary::NetworkType() {
+  return ValueDescription({"NetworkType", Ordering::kUnordered});
+}
+
+}  // namespace learning
+}  // namespace media
diff --git a/media/learning/common/feature_library.h b/media/learning/common/feature_library.h
new file mode 100644
index 0000000..e75fc0b
--- /dev/null
+++ b/media/learning/common/feature_library.h
@@ -0,0 +1,36 @@
+// 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 MEDIA_LEARNING_COMMON_FEATURE_LIBRARY_H_
+#define MEDIA_LEARNING_COMMON_FEATURE_LIBRARY_H_
+
+#include "base/component_export.h"
+#include "base/macros.h"
+#include "media/learning/common/learning_task.h"
+
+namespace media {
+namespace learning {
+
+// This class provides feature descriptions for common features provided by the
+// learning framework.  When creating a LearningTask, one may choose to include
+// these in the feature descriptions:
+//
+//   LearningTask my_task;
+//   my_task.feature_descriptions.push_back(FeatureLibrary::NetworkType());
+struct COMPONENT_EXPORT(LEARNING_COMMON) FeatureLibrary {
+  // Common browser features
+  // Current network connection type (wired, 3G, etc.).
+  static LearningTask::ValueDescription NetworkType();
+
+  // TODO(liberato): add CpuLoad, ConcurrentMediaPlayers, NetworkUsage, Battery.
+
+  // Common renderer features
+  // TODO(liberato): Add Element{Type, Path, Id, Name}, visibility, size, other
+  // DOM structure features.
+};
+
+}  // namespace learning
+}  // namespace media
+
+#endif  // MEDIA_LEARNING_COMMON_FEATURE_LIBRARY_H_
diff --git a/media/learning/impl/BUILD.gn b/media/learning/impl/BUILD.gn
index 4275583e..97936c1 100644
--- a/media/learning/impl/BUILD.gn
+++ b/media/learning/impl/BUILD.gn
@@ -8,7 +8,9 @@
     "//media/learning/impl:unit_tests",
 
     # Actual clients.
+    "//content/browser",
     "//media/capabilities",
+    "//media/mojo/services",
   ]
 
   sources = [
diff --git a/media/learning/impl/learning_session_impl_unittest.cc b/media/learning/impl/learning_session_impl_unittest.cc
index 36f343e..1b2027b9 100644
--- a/media/learning/impl/learning_session_impl_unittest.cc
+++ b/media/learning/impl/learning_session_impl_unittest.cc
@@ -48,7 +48,7 @@
     void AddFeatures(const LabelledExample& example,
                      FeatureProvider::LabelledExampleCB cb) override {
       *flag_ptr_ = true;
-    };
+    }
 
     bool* flag_ptr_ = nullptr;
   };
diff --git a/media/learning/impl/learning_task_controller_impl.cc b/media/learning/impl/learning_task_controller_impl.cc
index d5cf92b..63ba530 100644
--- a/media/learning/impl/learning_task_controller_impl.cc
+++ b/media/learning/impl/learning_task_controller_impl.cc
@@ -7,6 +7,7 @@
 #include <memory>
 
 #include "base/bind.h"
+#include "base/threading/sequenced_task_runner_handle.h"
 #include "media/learning/impl/extra_trees_trainer.h"
 #include "media/learning/impl/lookup_table_trainer.h"
 
@@ -20,7 +21,8 @@
     : task_(task),
       training_data_(std::make_unique<TrainingData>()),
       feature_provider_(std::move(feature_provider)),
-      reporter_(std::move(reporter)) {
+      reporter_(std::move(reporter)),
+      task_runner_(base::SequencedTaskRunnerHandle::Get()) {
   switch (task_.model) {
     case LearningTask::Model::kExtraTrees:
       trainer_ = std::make_unique<ExtraTreesTrainer>();
@@ -34,17 +36,33 @@
 LearningTaskControllerImpl::~LearningTaskControllerImpl() = default;
 
 void LearningTaskControllerImpl::AddExample(const LabelledExample& example) {
-  if (!feature_provider_.is_null()) {
-    // TODO(liberato): BindToCurrentSequence
+  if (feature_provider_) {
+    // TODO(liberato): SequenceBound should make this easier.
     feature_provider_.Post(
         FROM_HERE, &FeatureProvider::AddFeatures, example,
-        base::BindOnce(&LearningTaskControllerImpl::OnExampleReady,
-                       AsWeakPtr()));
+        base::BindOnce(&LearningTaskControllerImpl::OnExampleReadyTrampoline,
+                       task_runner_, AsWeakPtr()));
   } else {
     OnExampleReady(example);
   }
 }
 
+// static
+void LearningTaskControllerImpl::OnExampleReadyTrampoline(
+    scoped_refptr<base::SequencedTaskRunner> task_runner,
+    base::WeakPtr<LearningTaskControllerImpl> weak_this,
+    LabelledExample example) {
+  if (!task_runner->RunsTasksInCurrentSequence()) {
+    task_runner->PostTask(
+        FROM_HERE, base::BindOnce(&LearningTaskControllerImpl::OnExampleReady,
+                                  std::move(weak_this), std::move(example)));
+    return;
+  }
+
+  if (weak_this)
+    weak_this->OnExampleReady(std::move(example));
+}
+
 void LearningTaskControllerImpl::OnExampleReady(LabelledExample example) {
   if (training_data_->size() >= task_.max_data_set_size) {
     // Replace a random example.  We don't necessarily want to replace the
@@ -79,7 +97,6 @@
 
   num_untrained_examples_ = 0;
 
-  // TODO(liberato): don't do this if one is in-flight.
   TrainedModelCB model_cb =
       base::BindOnce(&LearningTaskControllerImpl::OnModelTrained, AsWeakPtr());
   training_is_in_progress_ = true;
diff --git a/media/learning/impl/learning_task_controller_impl.h b/media/learning/impl/learning_task_controller_impl.h
index 6f40924..516d727 100644
--- a/media/learning/impl/learning_task_controller_impl.h
+++ b/media/learning/impl/learning_task_controller_impl.h
@@ -10,6 +10,7 @@
 #include "base/callback.h"
 #include "base/component_export.h"
 #include "base/memory/weak_ptr.h"
+#include "base/sequenced_task_runner.h"
 #include "media/learning/impl/distribution_reporter.h"
 #include "media/learning/impl/feature_provider.h"
 #include "media/learning/impl/learning_task_controller.h"
@@ -37,6 +38,14 @@
   void AddExample(const LabelledExample& example) override;
 
  private:
+  // Trampoline method for receiving examples from |feature_provider_|.  Will
+  // chain directly to OnExampleReady if we're on |task_runner| and |weak_thiz|
+  // is non-null, else it will post to |task_runner|.
+  static void OnExampleReadyTrampoline(
+      scoped_refptr<base::SequencedTaskRunner> task_runner,
+      base::WeakPtr<LearningTaskControllerImpl> weak_this,
+      LabelledExample example);
+
   // Called when a new example has been finished by |feature_provider_|, if
   // needed, to actually add the example.
   void OnExampleReady(LabelledExample example);
@@ -70,6 +79,8 @@
   // Optional reporter for training accuracy.
   std::unique_ptr<DistributionReporter> reporter_;
 
+  scoped_refptr<base::SequencedTaskRunner> task_runner_;
+
   friend class LearningTaskControllerImplTest;
 };
 
diff --git a/media/mojo/services/BUILD.gn b/media/mojo/services/BUILD.gn
index 622582d..fc6dbb22 100644
--- a/media/mojo/services/BUILD.gn
+++ b/media/mojo/services/BUILD.gn
@@ -99,6 +99,7 @@
     "//media/gpu",
     "//media/gpu:buildflags",
     "//media/gpu/ipc/service",
+    "//media/learning/impl",
     "//media/mojo/common",
     "//media/mojo/common:mojo_shared_buffer_video_frame",
     "//services/metrics/public/cpp:metrics_cpp",
diff --git a/media/mojo/services/video_decode_perf_history.cc b/media/mojo/services/video_decode_perf_history.cc
index f2e70af..505974a1 100644
--- a/media/mojo/services/video_decode_perf_history.cc
+++ b/media/mojo/services/video_decode_perf_history.cc
@@ -39,9 +39,11 @@
 }
 
 VideoDecodePerfHistory::VideoDecodePerfHistory(
-    std::unique_ptr<VideoDecodeStatsDB> db)
+    std::unique_ptr<VideoDecodeStatsDB> db,
+    learning::FeatureProviderFactoryCB feature_factory_cb)
     : db_(std::move(db)),
       db_init_status_(UNINITIALIZED),
+      feature_factory_cb_(std::move(feature_factory_cb)),
       weak_ptr_factory_(this) {
   DVLOG(2) << __func__;
   DCHECK(db_);
@@ -49,7 +51,7 @@
   // If the local learning experiment is enabled, then also create
   // |learning_helper_| to send data to it.
   if (base::FeatureList::IsEnabled(kMediaLearningExperiment))
-    learning_helper_ = std::make_unique<LearningHelper>();
+    learning_helper_ = std::make_unique<LearningHelper>(feature_factory_cb_);
 }
 
 VideoDecodePerfHistory::~VideoDecodePerfHistory() {
@@ -355,7 +357,7 @@
   // If we have a learning helper, then replace it.  This will erase any data
   // that it currently has.
   if (learning_helper_)
-    learning_helper_ = std::make_unique<LearningHelper>();
+    learning_helper_ = std::make_unique<LearningHelper>(feature_factory_cb_);
 
   if (db_init_status_ == FAILED) {
     DVLOG(3) << __func__ << " Can't clear history - No DB!";
diff --git a/media/mojo/services/video_decode_perf_history.h b/media/mojo/services/video_decode_perf_history.h
index 2af7c96..01da1c9 100644
--- a/media/mojo/services/video_decode_perf_history.h
+++ b/media/mojo/services/video_decode_perf_history.h
@@ -16,6 +16,7 @@
 #include "media/base/video_codecs.h"
 #include "media/capabilities/video_decode_stats_db.h"
 #include "media/capabilities/video_decode_stats_db_provider.h"
+#include "media/learning/impl/feature_provider.h"
 #include "media/mojo/interfaces/video_decode_perf_history.mojom.h"
 #include "media/mojo/services/media_mojo_export.h"
 #include "mojo/public/cpp/bindings/binding_set.h"
@@ -53,7 +54,10 @@
  public:
   static const char kMaxSmoothDroppedFramesPercentParamName[];
 
-  explicit VideoDecodePerfHistory(std::unique_ptr<VideoDecodeStatsDB> db);
+  explicit VideoDecodePerfHistory(
+      std::unique_ptr<VideoDecodeStatsDB> db,
+      learning::FeatureProviderFactoryCB feature_factory_cb =
+          learning::FeatureProviderFactoryCB());
   ~VideoDecodePerfHistory() override;
 
   // Bind the mojo request to this instance. Single instance will be used to
@@ -185,6 +189,9 @@
   // Optional helper for local learning.
   std::unique_ptr<LearningHelper> learning_helper_;
 
+  // Optional callback to create a FeatureProvider for |learning_helper_|.
+  learning::FeatureProviderFactoryCB feature_factory_cb_;
+
   // Ensures all access to class members come on the same sequence.
   SEQUENCE_CHECKER(sequence_checker_);
 
diff --git a/net/cookies/cookie_monster.cc b/net/cookies/cookie_monster.cc
index 81705d66..cbec3f9 100644
--- a/net/cookies/cookie_monster.cc
+++ b/net/cookies/cookie_monster.cc
@@ -748,11 +748,8 @@
   VLOG(net::cookie_util::kVlogSetCookies)
       << "SetCookie() line: " << cookie_line;
 
-  Time creation_time = CurrentTime();
-  last_time_seen_ = creation_time;
-
   std::unique_ptr<CanonicalCookie> cc(
-      CanonicalCookie::Create(url, cookie_line, creation_time, options));
+      CanonicalCookie::Create(url, cookie_line, Time::Now(), options));
 
   if (!cc.get()) {
     VLOG(net::cookie_util::kVlogSetCookies)
@@ -1090,7 +1087,7 @@
     std::vector<CanonicalCookie*>* cookies) {
   DCHECK(thread_checker_.CalledOnValidThread());
 
-  Time current_time(CurrentTime());
+  Time current_time = Time::Now();
 
   // Retrieve all cookies for a given key
   const std::string key(GetKey(url.host_piece()));
@@ -1121,7 +1118,7 @@
   // Probe to save statistics relatively frequently.  We do it here rather
   // than in the set path as many websites won't set cookies, and we
   // want to collect statistics whenever the browser's being used.
-  Time current_time(CurrentTime());
+  Time current_time = Time::Now();
   RecordPeriodicStats(current_time);
 
   for (std::vector<CanonicalCookie*>::iterator it = cookie_ptrs->begin();
@@ -1288,15 +1285,10 @@
 
   const std::string key(GetKey(cc->Domain()));
 
-  // TODO(mmenke): This class assumes each cookie to have a unique creation
-  // time. Allowing the caller to set the creation time violates that
-  // assumption. Worth fixing? Worth noting that time changes between browser
-  // restarts can cause the same issue.
   base::Time creation_date = cc->CreationDate();
   if (creation_date.is_null()) {
-    creation_date = CurrentTime();
+    creation_date = Time::Now();
     cc->SetCreationDate(creation_date);
-    last_time_seen_ = creation_date;
   }
   bool already_expired = cc->IsExpired(creation_date);
 
@@ -1342,9 +1334,6 @@
 
     if (!creation_date_to_inherit.is_null()) {
       cc->SetCreationDate(creation_date_to_inherit);
-      // |last_time_seen_| is intentionally not updated, as moving it into the
-      // past might cause duplicate cookie creation dates. See
-      // `CookieMonster::CurrentTime()` for details.
     }
 
     InternalInsertCookie(key, std::move(cc), true);
@@ -1857,14 +1846,6 @@
       base::Histogram::kUmaTargetedHistogramFlag);
 }
 
-// The system resolution is not high enough, so we can have multiple
-// set cookies that result in the same system time.  When this happens, we
-// increment by one Time unit.  Let's hope computers don't get too fast.
-Time CookieMonster::CurrentTime() {
-  return std::max(Time::Now(), Time::FromInternalValue(
-                                   last_time_seen_.ToInternalValue() + 1));
-}
-
 void CookieMonster::DoCookieCallback(base::OnceClosure callback) {
   DCHECK(thread_checker_.CalledOnValidThread());
 
diff --git a/net/cookies/cookie_monster.h b/net/cookies/cookie_monster.h
index 1138ffd..071d7ff 100644
--- a/net/cookies/cookie_monster.h
+++ b/net/cookies/cookie_monster.h
@@ -561,10 +561,6 @@
   // the constructor.
   void InitializeHistograms();
 
-  // The resolution of our time isn't enough, so we do something
-  // ugly and increment when we've seen the same time twice.
-  base::Time CurrentTime();
-
   // Defers the callback until the full coookie database has been loaded. If
   // it's already been loaded, runs the callback synchronously.
   void DoCookieCallback(base::OnceClosure callback);
@@ -624,8 +620,6 @@
 
   scoped_refptr<PersistentCookieStore> store_;
 
-  base::Time last_time_seen_;
-
   // Minimum delay after updating a cookie's LastAccessDate before we will
   // update it again.
   const base::TimeDelta last_access_threshold_;
diff --git a/net/cookies/cookie_monster_unittest.cc b/net/cookies/cookie_monster_unittest.cc
index c7f47ec..956d65b 100644
--- a/net/cookies/cookie_monster_unittest.cc
+++ b/net/cookies/cookie_monster_unittest.cc
@@ -2041,55 +2041,6 @@
                                       std::string("/dir1/dir2/xxx"))));
 }
 
-TEST_F(CookieMonsterTest, UniqueCreationTime) {
-  std::unique_ptr<CookieMonster> cm(
-      new CookieMonster(nullptr, nullptr, &net_log_));
-  CookieOptions options;
-
-  // Add in three cookies through every public interface to the
-  // CookieMonster and confirm that none of them have duplicate
-  // creation times.
-
-  // SetCookieWithCreationTime and SetCookieWithCreationTimeAndOptions
-  // are not included as they aren't going to be public for very much
-  // longer.
-
-  // SetCookie, SetCookieWithOptions
-
-  EXPECT_TRUE(SetCookie(cm.get(), http_www_foo_.url(), "SetCookie1=A"));
-  EXPECT_TRUE(SetCookie(cm.get(), http_www_foo_.url(), "SetCookie2=A"));
-  EXPECT_TRUE(SetCookie(cm.get(), http_www_foo_.url(), "SetCookie3=A"));
-
-  EXPECT_TRUE(SetCookieWithOptions(cm.get(), http_www_foo_.url(),
-                                   "setCookieWithOptions1=A", options));
-  EXPECT_TRUE(SetCookieWithOptions(cm.get(), http_www_foo_.url(),
-                                   "setCookieWithOptions2=A", options));
-  EXPECT_TRUE(SetCookieWithOptions(cm.get(), http_www_foo_.url(),
-                                   "setCookieWithOptions3=A", options));
-
-  // Now we check
-  CookieList cookie_list(GetAllCookies(cm.get()));
-  EXPECT_EQ(6u, cookie_list.size());
-  typedef std::map<int64_t, CanonicalCookie> TimeCookieMap;
-  TimeCookieMap check_map;
-  for (CookieList::const_iterator it = cookie_list.begin();
-       it != cookie_list.end(); it++) {
-    const int64_t creation_date = it->CreationDate().ToInternalValue();
-    TimeCookieMap::const_iterator existing_cookie_it(
-        check_map.find(creation_date));
-    EXPECT_TRUE(existing_cookie_it == check_map.end())
-        << "Cookie " << it->Name() << " has same creation date ("
-        << it->CreationDate().ToInternalValue()
-        << ") as previously entered cookie "
-        << existing_cookie_it->second.Name();
-
-    if (existing_cookie_it == check_map.end()) {
-      check_map.insert(
-          TimeCookieMap::value_type(it->CreationDate().ToInternalValue(), *it));
-    }
-  }
-}
-
 // Mainly a test of GetEffectiveDomain, or more specifically, of the
 // expected behavior of GetEffectiveDomain within the CookieMonster.
 TEST_F(CookieMonsterTest, GetKey) {
diff --git a/net/disk_cache/simple/simple_file_tracker_unittest.cc b/net/disk_cache/simple/simple_file_tracker_unittest.cc
index 4dcb8a4..e484046 100644
--- a/net/disk_cache/simple/simple_file_tracker_unittest.cc
+++ b/net/disk_cache/simple/simple_file_tracker_unittest.cc
@@ -376,6 +376,6 @@
 
   for (const auto& entry : entries)
     file_tracker_.Close(entry.get(), SimpleFileTracker::SubFile::FILE_0);
-};
+}
 
 }  // namespace disk_cache
diff --git a/net/extras/sqlite/sqlite_persistent_cookie_store_unittest.cc b/net/extras/sqlite/sqlite_persistent_cookie_store_unittest.cc
index 332fea0..84636fb 100644
--- a/net/extras/sqlite/sqlite_persistent_cookie_store_unittest.cc
+++ b/net/extras/sqlite/sqlite_persistent_cookie_store_unittest.cc
@@ -1276,7 +1276,7 @@
   EXPECT_EQ("A", get_callback.cookies()[0].Name());
   EXPECT_EQ("B", get_callback.cookies()[0].Value());
   EXPECT_EQ("subdomain.gopheriffic.com", get_callback.cookies()[0].Domain());
-};
+}
 
 TEST_F(SQLitePersistentCookieStoreTest, OpsIfInitFailed) {
   // Test to make sure we don't leak pending operations when initialization
diff --git a/net/quic/quic_end_to_end_unittest.cc b/net/quic/quic_end_to_end_unittest.cc
index a51d692..beeb4ff 100644
--- a/net/quic/quic_end_to_end_unittest.cc
+++ b/net/quic/quic_end_to_end_unittest.cc
@@ -75,7 +75,7 @@
 
   HttpCache* GetCache() override { return nullptr; }
 
-  HttpNetworkSession* GetSession() override { return session_.get(); };
+  HttpNetworkSession* GetSession() override { return session_.get(); }
 
  private:
   std::unique_ptr<HttpNetworkSession> session_;
diff --git a/pdf/url_loader_wrapper_impl.h b/pdf/url_loader_wrapper_impl.h
index 402c3f2..eb96268 100644
--- a/pdf/url_loader_wrapper_impl.h
+++ b/pdf/url_loader_wrapper_impl.h
@@ -17,7 +17,7 @@
 
 namespace pp {
 class Instance;
-};
+}
 
 namespace chrome_pdf {
 
diff --git a/printing/backend/print_backend_win.cc b/printing/backend/print_backend_win.cc
index 64a18fe..3b74abd8 100644
--- a/printing/backend/print_backend_win.cc
+++ b/printing/backend/print_backend_win.cc
@@ -102,7 +102,7 @@
       paper.display_name = base::WideToUTF8(tmp_name);
     }
     if (!ids.empty())
-      paper.vendor_id = base::UintToString(ids[i]);
+      paper.vendor_id = base::NumberToString(ids[i]);
     caps->papers.push_back(paper);
   }
 
diff --git a/printing/printing_context_android.cc b/printing/printing_context_android.cc
index 816b47f..33d760d 100644
--- a/printing/printing_context_android.cc
+++ b/printing/printing_context_android.cc
@@ -117,7 +117,7 @@
   // TODO(thestig): See if the call to set_device_name() can be removed.
   fd_ = Java_PrintingContext_getFileDescriptor(env, j_printing_context_);
   DCHECK(is_file_descriptor_valid());
-  settings_.set_device_name(base::IntToString16(fd_));
+  settings_.set_device_name(base::NumberToString16(fd_));
 
   ScopedJavaLocalRef<jintArray> intArr =
       Java_PrintingContext_getPages(env, j_printing_context_);
diff --git a/printing/printing_context_chromeos.cc b/printing/printing_context_chromeos.cc
index 158f7a07..f6547ec 100644
--- a/printing/printing_context_chromeos.cc
+++ b/printing/printing_context_chromeos.cc
@@ -121,7 +121,7 @@
                       settings.requested_media().vendor_id));  // paper size
   options.push_back(
       ConstructOption(kIppCopies,
-                      base::IntToString(settings.copies())));  // copies
+                      base::NumberToString(settings.copies())));  // copies
   options.push_back(
       ConstructOption(kIppCollate,
                       GetCollateString(settings.collate())));  // collate
diff --git a/services/identity/public/cpp/identity_manager.cc b/services/identity/public/cpp/identity_manager.cc
index e086c2e..56f5bd60 100644
--- a/services/identity/public/cpp/identity_manager.cc
+++ b/services/identity/public/cpp/identity_manager.cc
@@ -449,13 +449,6 @@
   }
 }
 
-void IdentityManager::OnSetAccountsInCookieCompleted(
-    const GoogleServiceAuthError& error) {
-  for (auto& observer : observer_list_) {
-    observer.OnSetAccountsInCookieCompleted(error);
-  }
-}
-
 void IdentityManager::OnGaiaCookieDeletedByUserAction() {
   for (auto& observer : observer_list_) {
     observer.OnAccountsCookieDeletedByUserAction();
diff --git a/services/identity/public/cpp/identity_manager.h b/services/identity/public/cpp/identity_manager.h
index 6b7867ff..134e280b 100644
--- a/services/identity/public/cpp/identity_manager.h
+++ b/services/identity/public/cpp/identity_manager.h
@@ -143,15 +143,6 @@
         const std::string& account_id,
         const GoogleServiceAuthError& error) {}
 
-    // Called whenever setting cookies is completed. If |error| is equal to
-    // GoogleServiceAuthError::AuthErrorNone() then the call succeeded.
-    //
-    // This observer method is called only in response to a call to
-    // SetAccountsInCookie(). To listen for cookie changes, use
-    // OnAccountsInCookieUpdated instead.
-    virtual void OnSetAccountsInCookieCompleted(
-        const GoogleServiceAuthError& error) {}
-
     // Called when the Gaia cookie has been deleted explicitly by a user
     // action, e.g. from the settings or by an extension.
     virtual void OnAccountsCookieDeletedByUserAction() {}
@@ -502,8 +493,6 @@
   void OnAddAccountToCookieCompleted(
       const std::string& account_id,
       const GoogleServiceAuthError& error) override;
-  void OnSetAccountsInCookieCompleted(
-      const GoogleServiceAuthError& error) override;
   void OnGaiaCookieDeletedByUserAction() override;
 
   // OAuth2TokenService::DiagnosticsObserver:
diff --git a/services/identity/public/cpp/identity_manager_unittest.cc b/services/identity/public/cpp/identity_manager_unittest.cc
index ef10f1e..7015ebe 100644
--- a/services/identity/public/cpp/identity_manager_unittest.cc
+++ b/services/identity/public/cpp/identity_manager_unittest.cc
@@ -14,6 +14,7 @@
 #include "base/message_loop/message_loop.h"
 #include "base/run_loop.h"
 #include "base/stl_util.h"
+#include "base/test/bind_test_util.h"
 #include "build/build_config.h"
 #include "components/signin/core/browser/account_consistency_method.h"
 #include "components/signin/core/browser/account_tracker_service.h"
@@ -288,11 +289,6 @@
     return error_from_add_account_to_cookie_completed_callback_;
   }
 
-  const GoogleServiceAuthError&
-  error_from_set_accounts_in_cookie_completed_callback() const {
-    return error_from_set_accounts_in_cookie_completed_callback_;
-  }
-
   const GoogleServiceAuthError& error_from_signin_failed_callback() const {
     return google_signin_failed_error_;
   }
@@ -379,10 +375,6 @@
     account_from_add_account_to_cookie_completed_callback_ = account_id;
     error_from_add_account_to_cookie_completed_callback_ = error;
   }
-  void OnSetAccountsInCookieCompleted(
-      const GoogleServiceAuthError& error) override {
-    error_from_set_accounts_in_cookie_completed_callback_ = error;
-  }
   void OnAccountsCookieDeletedByUserAction() override {
     std::move(on_cookie_deleted_by_user_callback_).Run();
   }
@@ -431,7 +423,6 @@
   AccountsInCookieJarInfo accounts_info_from_cookie_change_callback_;
   std::string account_from_add_account_to_cookie_completed_callback_;
   GoogleServiceAuthError error_from_add_account_to_cookie_completed_callback_;
-  GoogleServiceAuthError error_from_set_accounts_in_cookie_completed_callback_;
   GoogleServiceAuthError google_signin_failed_error_;
   bool is_inside_batch_ = false;
   bool was_called_account_removed_with_info_callback_ = false;
@@ -2177,9 +2168,16 @@
   const std::vector<std::string> account_ids = {kTestAccountId,
                                                 kTestAccountId2};
 
+  GoogleServiceAuthError error_from_set_accounts_in_cookie_completed_callback;
+  auto completion_callback = base::BindLambdaForTesting(
+      [&error_from_set_accounts_in_cookie_completed_callback](
+          const GoogleServiceAuthError& error) {
+        error_from_set_accounts_in_cookie_completed_callback = error;
+      });
+
   // Needed to insert request in the queue.
-  gaia_cookie_manager_service()->SetAccountsInCookie(account_ids,
-                                                     gaia::GaiaSource::kChrome);
+  gaia_cookie_manager_service()->SetAccountsInCookie(
+      account_ids, gaia::GaiaSource::kChrome, std::move(completion_callback));
 
   // Sample success cookie response.
   std::string data =
@@ -2204,8 +2202,7 @@
 
   SimulateOAuthMultiloginFinished(gaia_cookie_manager_service(), result);
 
-  EXPECT_EQ(identity_manager_observer()
-                ->error_from_set_accounts_in_cookie_completed_callback(),
+  EXPECT_EQ(error_from_set_accounts_in_cookie_completed_callback,
             GoogleServiceAuthError::AuthErrorNone());
 }
 
@@ -2216,9 +2213,16 @@
   const std::vector<std::string> account_ids = {kTestAccountId,
                                                 kTestAccountId2};
 
+  GoogleServiceAuthError error_from_set_accounts_in_cookie_completed_callback;
+  auto completion_callback = base::BindLambdaForTesting(
+      [&error_from_set_accounts_in_cookie_completed_callback](
+          const GoogleServiceAuthError& error) {
+        error_from_set_accounts_in_cookie_completed_callback = error;
+      });
+
   // Needed to insert request in the queue.
-  gaia_cookie_manager_service()->SetAccountsInCookie(account_ids,
-                                                     gaia::GaiaSource::kChrome);
+  gaia_cookie_manager_service()->SetAccountsInCookie(
+      account_ids, gaia::GaiaSource::kChrome, std::move(completion_callback));
 
   // Sample an erroneous response.
   GoogleServiceAuthError error(GoogleServiceAuthError::SERVICE_ERROR);
@@ -2226,9 +2230,7 @@
 
   SimulateOAuthMultiloginFinished(gaia_cookie_manager_service(), result);
 
-  EXPECT_EQ(identity_manager_observer()
-                ->error_from_set_accounts_in_cookie_completed_callback(),
-            error);
+  EXPECT_EQ(error_from_set_accounts_in_cookie_completed_callback, error);
 }
 
 TEST_F(IdentityManagerTest, CallbackSentOnAccountsCookieDeletedByUserAction) {
@@ -2238,8 +2240,9 @@
                                                 kTestAccountId2};
 
   // Needed to insert request in the queue.
-  gaia_cookie_manager_service()->SetAccountsInCookie(account_ids,
-                                                     gaia::GaiaSource::kChrome);
+  gaia_cookie_manager_service()->SetAccountsInCookie(
+      account_ids, gaia::GaiaSource::kChrome,
+      GaiaCookieManagerService::SetAccountsInCookieCompletedCallback());
 
   // Sample success cookie response.
   std::string data =
@@ -2288,8 +2291,9 @@
   identity_manager()->StartObservingCookieChanges();
 
   // Needed to insert request in the queue.
-  gaia_cookie_manager_service()->SetAccountsInCookie(account_ids,
-                                                     gaia::GaiaSource::kChrome);
+  gaia_cookie_manager_service()->SetAccountsInCookie(
+      account_ids, gaia::GaiaSource::kChrome,
+      GaiaCookieManagerService::SetAccountsInCookieCompletedCallback());
 
   // Sample success cookie response.
   std::string data =
diff --git a/services/tracing/agent_registry.cc b/services/tracing/agent_registry.cc
index d77e683d..759aacc7 100644
--- a/services/tracing/agent_registry.cc
+++ b/services/tracing/agent_registry.cc
@@ -67,37 +67,22 @@
   agent_registry_->UnregisterAgent(id_);
 }
 
-AgentRegistry::AgentRegistry() {
-  DETACH_FROM_SEQUENCE(sequence_checker_);
-}
+AgentRegistry::AgentRegistry() = default;
 
-AgentRegistry::~AgentRegistry() {
-  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-}
+AgentRegistry::~AgentRegistry() = default;
 
 void AgentRegistry::DisconnectAllAgents() {
   bindings_.CloseAllBindings();
 }
 
 void AgentRegistry::BindAgentRegistryRequest(
-    scoped_refptr<base::SequencedTaskRunner> task_runner,
     mojom::AgentRegistryRequest request) {
-  task_runner->PostTask(
-      FROM_HERE,
-      base::BindOnce(&AgentRegistry::BindAgentRegistryRequestOnSequence,
-                     base::Unretained(this), std::move(request)));
-}
-
-void AgentRegistry::BindAgentRegistryRequestOnSequence(
-    mojom::AgentRegistryRequest request) {
-  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   bindings_.AddBinding(this, std::move(request));
 }
 
 size_t AgentRegistry::SetAgentInitializationCallback(
     const AgentInitializationCallback& callback,
     bool call_on_new_agents_only) {
-  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   agent_initialization_callback_ = callback;
   size_t num_initialized_agents = 0;
   if (!call_on_new_agents_only) {
@@ -110,7 +95,6 @@
 }
 
 bool AgentRegistry::HasDisconnectClosure(const void* closure_name) {
-  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   for (const auto& key_value : agents_) {
     if (key_value.second->HasDisconnectClosure(closure_name))
       return true;
@@ -122,7 +106,6 @@
                                   const std::string& label,
                                   mojom::TraceDataType type,
                                   base::ProcessId pid) {
-  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   auto id = next_agent_id_++;
   auto entry = std::make_unique<AgentEntry>(id, this, std::move(agent), label,
                                             type, pid);
@@ -133,7 +116,6 @@
 }
 
 void AgentRegistry::UnregisterAgent(size_t agent_id) {
-  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   size_t num_deleted = agents_.erase(agent_id);
   DCHECK_EQ(1u, num_deleted);
 }
diff --git a/services/tracing/agent_registry.h b/services/tracing/agent_registry.h
index d87ba0ee..523bc52 100644
--- a/services/tracing/agent_registry.h
+++ b/services/tracing/agent_registry.h
@@ -12,7 +12,6 @@
 #include "base/callback_forward.h"
 #include "base/macros.h"
 #include "base/memory/weak_ptr.h"
-#include "base/sequence_checker.h"
 #include "mojo/public/cpp/bindings/binding_set.h"
 #include "services/service_manager/public/cpp/identity.h"
 #include "services/tracing/public/mojom/tracing.mojom.h"
@@ -68,7 +67,6 @@
   void DisconnectAllAgents();
 
   void BindAgentRegistryRequest(
-      scoped_refptr<base::SequencedTaskRunner> task_runner,
       mojom::AgentRegistryRequest request);
 
   // Returns the number of existing agents that the callback was run on.
@@ -79,7 +77,6 @@
 
   template <typename FunctionType>
   void ForAllAgents(FunctionType function) {
-    DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
     for (const auto& key_value : agents_) {
       function(key_value.second.get());
     }
@@ -89,8 +86,6 @@
   friend class AgentRegistryTest;  // For testing.
   friend class CoordinatorTest;    // For testing.
 
-  void BindAgentRegistryRequestOnSequence(mojom::AgentRegistryRequest request);
-
   // mojom::AgentRegistry
   void RegisterAgent(mojom::AgentPtr agent,
                      const std::string& label,
@@ -104,8 +99,6 @@
   std::map<size_t, std::unique_ptr<AgentEntry>> agents_;
   AgentInitializationCallback agent_initialization_callback_;
 
-  SEQUENCE_CHECKER(sequence_checker_);
-
   DISALLOW_COPY_AND_ASSIGN(AgentRegistry);
 };
 
diff --git a/services/tracing/coordinator.cc b/services/tracing/coordinator.cc
index fc9f4f15..821f0de4 100644
--- a/services/tracing/coordinator.cc
+++ b/services/tracing/coordinator.cc
@@ -271,7 +271,7 @@
                          const base::RepeatingClosure& on_disconnect_callback)
     : on_disconnect_callback_(std::move(on_disconnect_callback)),
       binding_(this),
-      task_runner_(base::ThreadTaskRunnerHandle::Get()),
+      task_runner_(base::SequencedTaskRunnerHandle::Get()),
       // USER_VISIBLE because the task posted from StopAndFlushInternal() is
       // required to stop tracing from the UI.
       // TODO(fdoray): Once we have support for dynamic priorities
diff --git a/services/tracing/coordinator.h b/services/tracing/coordinator.h
index 9eec908..842dc8c 100644
--- a/services/tracing/coordinator.h
+++ b/services/tracing/coordinator.h
@@ -89,7 +89,7 @@
 
   base::RepeatingClosure on_disconnect_callback_;
   mojo::Binding<mojom::Coordinator> binding_;
-  const scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
+  const scoped_refptr<base::SequencedTaskRunner> task_runner_;
   const scoped_refptr<base::SequencedTaskRunner> backend_task_runner_;
   AgentRegistry* agent_registry_;
   std::string config_;
diff --git a/services/tracing/perfetto/perfetto_integration_unittest.cc b/services/tracing/perfetto/perfetto_integration_unittest.cc
index 3c4c119..8d0c1de 100644
--- a/services/tracing/perfetto/perfetto_integration_unittest.cc
+++ b/services/tracing/perfetto/perfetto_integration_unittest.cc
@@ -23,10 +23,7 @@
 class PerfettoIntegrationTest : public testing::Test {
  public:
   void SetUp() override {
-    perfetto_service_ = std::make_unique<PerfettoService>(
-        base::SequencedTaskRunnerHandle::Get());
-    // The actual Perfetto service is created async on the given task_runner;
-    // wait until that's done.
+    perfetto_service_ = std::make_unique<PerfettoService>();
     RunUntilIdle();
     ProducerClient::ResetTaskRunnerForTesting();
   }
diff --git a/services/tracing/perfetto/perfetto_service.cc b/services/tracing/perfetto/perfetto_service.cc
index 3e6b9e5..44ee817 100644
--- a/services/tracing/perfetto/perfetto_service.cc
+++ b/services/tracing/perfetto/perfetto_service.cc
@@ -22,54 +22,14 @@
 
 }  // namespace
 
-/*
-TODO(oysteine): Right now the Perfetto service runs on a dedicated
-thread for a couple of reasons:
-* The sequence needs to be locked to a specific thread, or Perfetto's
-  thread-checker will barf.
-* The PerfettoTracingCoordinator uses
-  mojo::BlockingCopyFromString to pass the string to the tracing
-  controller, which requires the WithBaseSyncPrimitives task trait and
-  SingleThreadTaskRunners which use this trait need to be running on a
-  dedicated trait to avoid blocking other sequences.
-* If a client fills up its Shared Memory Buffer when writing a Perfetto
-  event proto, it'll stall until the Perfetto service clears up space.
-  This won't happen if the client and the service happens to run on the same
-  thread (the Mojo calls will never be executed).
-
-The above should be resolved before we move the Perfetto usage out from the
-flag so we can run this on non-thread-bound sequence.
-*/
-
 // static
 PerfettoService* PerfettoService::GetInstance() {
   static base::NoDestructor<PerfettoService> perfetto_service;
   return perfetto_service.get();
 }
 
-PerfettoService::PerfettoService(
-    scoped_refptr<base::SequencedTaskRunner> task_runner_for_testing)
-    : perfetto_task_runner_(
-          task_runner_for_testing
-              ? task_runner_for_testing
-              : base::CreateSingleThreadTaskRunnerWithTraits(
-                    {base::MayBlock(),
-                     base::TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN,
-                     base::WithBaseSyncPrimitives(),
-                     base::TaskPriority::BEST_EFFORT},
-                    base::SingleThreadTaskRunnerThreadMode::DEDICATED)) {
-  DETACH_FROM_SEQUENCE(sequence_checker_);
-  perfetto_task_runner_.task_runner()->PostTask(
-      FROM_HERE, base::BindOnce(&PerfettoService::CreateServiceOnSequence,
-                                base::Unretained(this)));
-}
-
-PerfettoService::~PerfettoService() {
-  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-}
-
-void PerfettoService::CreateServiceOnSequence() {
-  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+PerfettoService::PerfettoService()
+    : perfetto_task_runner_(base::SequencedTaskRunnerHandle::Get()) {
   service_ = perfetto::TracingService::CreateInstance(
       std::make_unique<MojoSharedMemory::Factory>(), &perfetto_task_runner_);
   // Chromium uses scraping of the shared memory chunks to ensure that data
@@ -78,26 +38,19 @@
   DCHECK(service_);
 }
 
+PerfettoService::~PerfettoService() = default;
+
 perfetto::TracingService* PerfettoService::GetService() const {
-  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   return service_.get();
 }
 
 void PerfettoService::BindRequest(mojom::PerfettoServiceRequest request) {
-  perfetto_task_runner_.task_runner()->PostTask(
-      FROM_HERE, base::BindOnce(&PerfettoService::BindOnSequence,
-                                base::Unretained(this), std::move(request)));
-}
-
-void PerfettoService::BindOnSequence(mojom::PerfettoServiceRequest request) {
-  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   bindings_.AddBinding(this, std::move(request));
 }
 
 void PerfettoService::ConnectToProducerHost(
     mojom::ProducerClientPtr producer_client,
     mojom::ProducerHostRequest producer_host_request) {
-  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   auto new_producer = std::make_unique<ProducerHost>();
   new_producer->Initialize(std::move(producer_client), service_.get(),
                            kPerfettoProducerName);
diff --git a/services/tracing/perfetto/perfetto_service.h b/services/tracing/perfetto/perfetto_service.h
index 1bcb1c8..4d9490b 100644
--- a/services/tracing/perfetto/perfetto_service.h
+++ b/services/tracing/perfetto/perfetto_service.h
@@ -9,8 +9,6 @@
 #include <set>
 
 #include "base/macros.h"
-#include "base/sequence_checker.h"
-#include "base/sequenced_task_runner.h"
 #include "mojo/public/cpp/bindings/binding_set.h"
 #include "mojo/public/cpp/bindings/strong_binding_set.h"
 #include "services/service_manager/public/cpp/identity.h"
@@ -29,8 +27,7 @@
 // ProducerHost.
 class PerfettoService : public mojom::PerfettoService {
  public:
-  explicit PerfettoService(scoped_refptr<base::SequencedTaskRunner>
-                               task_runner_for_testing = nullptr);
+  PerfettoService();
   ~PerfettoService() override;
 
   static PerfettoService* GetInstance();
@@ -42,9 +39,6 @@
                              mojom::ProducerHostRequest producer_host) override;
 
   perfetto::TracingService* GetService() const;
-  scoped_refptr<base::SequencedTaskRunner> task_runner() {
-    return perfetto_task_runner_.task_runner();
-  }
 
  private:
   void BindOnSequence(mojom::PerfettoServiceRequest request);
@@ -54,7 +48,6 @@
   std::unique_ptr<perfetto::TracingService> service_;
   mojo::BindingSet<mojom::PerfettoService> bindings_;
   mojo::StrongBindingSet<mojom::ProducerHost> producer_bindings_;
-  SEQUENCE_CHECKER(sequence_checker_);
 
   DISALLOW_COPY_AND_ASSIGN(PerfettoService);
 };
diff --git a/services/tracing/perfetto/perfetto_tracing_coordinator.cc b/services/tracing/perfetto/perfetto_tracing_coordinator.cc
index b2bbc8a..0452918 100644
--- a/services/tracing/perfetto/perfetto_tracing_coordinator.cc
+++ b/services/tracing/perfetto/perfetto_tracing_coordinator.cc
@@ -202,14 +202,6 @@
 void PerfettoTracingCoordinator::BindCoordinatorRequest(
     mojom::CoordinatorRequest request,
     const service_manager::BindSourceInfo& source_info) {
-  PerfettoService::GetInstance()->task_runner()->PostTask(
-      FROM_HERE, base::BindOnce(&PerfettoTracingCoordinator::BindOnSequence,
-                                base::Unretained(this), std::move(request)));
-}
-
-void PerfettoTracingCoordinator::BindOnSequence(
-    mojom::CoordinatorRequest request) {
-  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   binding_.Bind(std::move(request));
   binding_.set_connection_error_handler(
       base::BindOnce(&PerfettoTracingCoordinator::OnClientConnectionError,
diff --git a/services/tracing/perfetto/perfetto_tracing_coordinator.h b/services/tracing/perfetto/perfetto_tracing_coordinator.h
index 0eae0e6..6db0495 100644
--- a/services/tracing/perfetto/perfetto_tracing_coordinator.h
+++ b/services/tracing/perfetto/perfetto_tracing_coordinator.h
@@ -47,7 +47,6 @@
   void RequestBufferUsage(RequestBufferUsageCallback callback) override;
 
  private:
-  void BindOnSequence(mojom::CoordinatorRequest request);
   void OnTracingOverCallback();
   void OnClientConnectionError() override;
 
diff --git a/services/tracing/tracing_service.cc b/services/tracing/tracing_service.cc
index 86f0de0..1a08557 100644
--- a/services/tracing/tracing_service.cc
+++ b/services/tracing/tracing_service.cc
@@ -25,11 +25,9 @@
 class ServiceListener : public service_manager::mojom::ServiceManagerListener {
  public:
   ServiceListener(service_manager::Connector* connector,
-                  scoped_refptr<base::SequencedTaskRunner> task_runner,
                   AgentRegistry* agent_registry)
       : binding_(this),
         connector_(connector),
-        task_runner_(task_runner),
         agent_registry_(agent_registry) {
     service_manager::mojom::ServiceManagerPtr service_manager;
     connector_->BindInterface(service_manager::mojom::kServiceName,
@@ -55,7 +53,6 @@
         mojo::MakeRequest(&new_connection_request->perfetto_service));
 
     agent_registry_->BindAgentRegistryRequest(
-        task_runner_,
         mojo::MakeRequest(&new_connection_request->agent_registry));
 
     traced_process->ConnectToTracingService(std::move(new_connection_request));
@@ -85,22 +82,13 @@
  private:
   mojo::Binding<service_manager::mojom::ServiceManagerListener> binding_;
   service_manager::Connector* connector_;
-  scoped_refptr<base::SequencedTaskRunner> task_runner_;
   AgentRegistry* agent_registry_;
 };
 
 TracingService::TracingService(service_manager::mojom::ServiceRequest request)
-    : service_binding_(this, std::move(request)),
-      task_runner_(base::SequencedTaskRunnerHandle::Get()) {}
+    : service_binding_(this, std::move(request)) {}
 
-TracingService::~TracingService() {
-  task_runner_->DeleteSoon(FROM_HERE, std::move(tracing_agent_registry_));
-
-  if (perfetto_tracing_coordinator_) {
-    task_runner_->DeleteSoon(FROM_HERE,
-                             std::move(perfetto_tracing_coordinator_));
-  }
-}
+TracingService::~TracingService() = default;
 
 void TracingService::OnDisconnected() {
   CloseAgentConnectionsAndTerminate();
@@ -110,13 +98,10 @@
   tracing_agent_registry_ = std::make_unique<AgentRegistry>();
 
   if (TracingUsesPerfettoBackend()) {
-    task_runner_ = tracing::PerfettoService::GetInstance()->task_runner();
-
     auto perfetto_coordinator = std::make_unique<PerfettoTracingCoordinator>(
         tracing_agent_registry_.get(),
         base::BindRepeating(&TracingService::OnCoordinatorConnectionClosed,
-                            base::Unretained(this),
-                            base::SequencedTaskRunnerHandle::Get()));
+                            base::Unretained(this)));
     registry_.AddInterface(
         base::BindRepeating(&PerfettoTracingCoordinator::BindCoordinatorRequest,
                             base::Unretained(perfetto_coordinator.get())));
@@ -125,7 +110,7 @@
     auto tracing_coordinator = std::make_unique<Coordinator>(
         tracing_agent_registry_.get(),
         base::BindRepeating(&TracingService::OnCoordinatorConnectionClosed,
-                            base::Unretained(this), nullptr));
+                            base::Unretained(this)));
     registry_.AddInterface(
         base::BindRepeating(&Coordinator::BindCoordinatorRequest,
                             base::Unretained(tracing_coordinator.get())));
@@ -133,8 +118,7 @@
   }
 
   service_listener_ = std::make_unique<ServiceListener>(
-      service_binding_.GetConnector(), task_runner_,
-      tracing_agent_registry_.get());
+      service_binding_.GetConnector(), tracing_agent_registry_.get());
 }
 
 void TracingService::OnBindInterface(
@@ -145,29 +129,13 @@
                           source_info);
 }
 
-void TracingService::OnCoordinatorConnectionClosed(
-    scoped_refptr<base::SequencedTaskRunner> task_runner) {
-  // TODO(oysteine): Running TracingService and Perfetto on different
-  // sequences is getting messy; refactor so that the service manager
-  // runs the tracing service on a single threaded taskrunner so
-  // Perfetto can use the same.
-  if (task_runner && !task_runner->RunsTasksInCurrentSequence()) {
-    task_runner->PostTask(
-        FROM_HERE,
-        base::BindOnce(&TracingService::OnCoordinatorConnectionClosed,
-                       base::Unretained(this), nullptr));
-    return;
-  }
-
+void TracingService::OnCoordinatorConnectionClosed() {
   service_binding_.RequestClose();
 }
 
 void TracingService::CloseAgentConnectionsAndTerminate() {
-  task_runner_->PostTaskAndReply(
-      FROM_HERE,
-      base::BindOnce(&AgentRegistry::DisconnectAllAgents,
-                     base::Unretained(tracing_agent_registry_.get())),
-      base::BindOnce(&TracingService::Terminate, base::Unretained(this)));
+  tracing_agent_registry_->DisconnectAllAgents();
+  Terminate();
 }
 
 }  // namespace tracing
diff --git a/services/tracing/tracing_service.h b/services/tracing/tracing_service.h
index 8be2ea7..298c504 100644
--- a/services/tracing/tracing_service.h
+++ b/services/tracing/tracing_service.h
@@ -37,8 +37,7 @@
                        mojo::ScopedMessagePipeHandle interface_pipe) override;
 
  private:
-  void OnCoordinatorConnectionClosed(
-      scoped_refptr<base::SequencedTaskRunner> task_runner);
+  void OnCoordinatorConnectionClosed();
   void CloseAgentConnectionsAndTerminate();
 
   service_manager::ServiceBinding service_binding_;
@@ -48,7 +47,6 @@
       registry_;
   std::unique_ptr<tracing::AgentRegistry> tracing_agent_registry_;
   std::unique_ptr<Coordinator> tracing_coordinator_;
-  scoped_refptr<base::SequencedTaskRunner> task_runner_;
   std::unique_ptr<PerfettoTracingCoordinator> perfetto_tracing_coordinator_;
 
   std::unique_ptr<ServiceListener> service_listener_;
diff --git a/storage/browser/BUILD.gn b/storage/browser/BUILD.gn
index 8db656fe0..a5adcde 100644
--- a/storage/browser/BUILD.gn
+++ b/storage/browser/BUILD.gn
@@ -131,11 +131,8 @@
     "fileapi/native_file_util.h",
     "fileapi/obfuscated_file_util.cc",
     "fileapi/obfuscated_file_util.h",
-    "fileapi/obfuscated_file_util_delegate.h",
     "fileapi/obfuscated_file_util_disk_delegate.cc",
     "fileapi/obfuscated_file_util_disk_delegate.h",
-    "fileapi/obfuscated_file_util_memory_delegate.cc",
-    "fileapi/obfuscated_file_util_memory_delegate.h",
     "fileapi/open_file_system_mode.h",
     "fileapi/plugin_private_file_system_backend.cc",
     "fileapi/plugin_private_file_system_backend.h",
diff --git a/storage/browser/blob/blob_flattener_unittest.cc b/storage/browser/blob/blob_flattener_unittest.cc
index df52f684..ee0f3d6 100644
--- a/storage/browser/blob/blob_flattener_unittest.cc
+++ b/storage/browser/blob/blob_flattener_unittest.cc
@@ -70,20 +70,20 @@
 
   scoped_refptr<BlobDataItem> CreateDataDescriptionItem(size_t size) {
     return BlobDataItem::CreateBytesDescription(size);
-  };
+  }
 
   scoped_refptr<BlobDataItem> CreateDataItem(const char* memory, size_t size) {
     return BlobDataItem::CreateBytes(base::make_span(memory, size));
-  };
+  }
 
   scoped_refptr<BlobDataItem> CreateFileItem(size_t offset, size_t size) {
     return BlobDataItem::CreateFile(fake_file_path_, offset, size,
                                     base::Time::Max());
-  };
+  }
 
   scoped_refptr<BlobDataItem> CreateFutureFileItem(size_t offset, size_t size) {
     return BlobDataItem::CreateFutureFile(offset, size, 0);
-  };
+  }
 
   std::unique_ptr<BlobDataHandle> SetupBasicBlob(const std::string& id) {
     auto builder = std::make_unique<BlobDataBuilder>(id);
diff --git a/storage/browser/blob/blob_memory_controller_unittest.cc b/storage/browser/blob/blob_memory_controller_unittest.cc
index b7b6201..a80344c1 100644
--- a/storage/browser/blob/blob_memory_controller_unittest.cc
+++ b/storage/browser/blob/blob_memory_controller_unittest.cc
@@ -54,7 +54,7 @@
   void SetUp() override {
     ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
     base::ThreadRestrictions::SetIOAllowed(false);
-  };
+  }
 
   void TearDown() override {
     files_created_.clear();
diff --git a/storage/browser/blob/blob_slice_unittest.cc b/storage/browser/blob/blob_slice_unittest.cc
index 20c3a973..8db8d075 100644
--- a/storage/browser/blob/blob_slice_unittest.cc
+++ b/storage/browser/blob/blob_slice_unittest.cc
@@ -34,7 +34,7 @@
       bytes[i] = i;
     return scoped_refptr<ShareableBlobDataItem>(new ShareableBlobDataItem(
         BlobDataItem::CreateBytes(bytes), ShareableBlobDataItem::QUOTA_NEEDED));
-  };
+  }
 
   scoped_refptr<ShareableBlobDataItem> CreateFileItem(size_t offset,
                                                       size_t size) {
@@ -42,14 +42,14 @@
         BlobDataItem::CreateFile(base::FilePath(FILE_PATH_LITERAL("kFakePath")),
                                  offset, size, base::Time::Max()),
         ShareableBlobDataItem::POPULATED_WITHOUT_QUOTA));
-  };
+  }
 
   scoped_refptr<ShareableBlobDataItem> CreateTempFileItem(size_t offset,
                                                           size_t size) {
     return scoped_refptr<ShareableBlobDataItem>(new ShareableBlobDataItem(
         BlobDataItem::CreateFutureFile(offset, size, 0),
         ShareableBlobDataItem::QUOTA_NEEDED));
-  };
+  }
 
   void Slice(BlobDataBuilder& builder,
              BlobEntry* source,
diff --git a/storage/browser/fileapi/obfuscated_file_util.cc b/storage/browser/fileapi/obfuscated_file_util.cc
index ef962f8..300432e 100644
--- a/storage/browser/fileapi/obfuscated_file_util.cc
+++ b/storage/browser/fileapi/obfuscated_file_util.cc
@@ -25,8 +25,6 @@
 #include "storage/browser/fileapi/file_observers.h"
 #include "storage/browser/fileapi/file_system_context.h"
 #include "storage/browser/fileapi/file_system_operation_context.h"
-#include "storage/browser/fileapi/obfuscated_file_util_disk_delegate.h"
-#include "storage/browser/fileapi/obfuscated_file_util_memory_delegate.h"
 #include "storage/browser/fileapi/sandbox_file_system_backend.h"
 #include "storage/browser/fileapi/sandbox_isolated_origin_database.h"
 #include "storage/browser/fileapi/sandbox_origin_database.h"
@@ -267,16 +265,14 @@
       db_flush_delay_seconds_(10 * 60),  // 10 mins.
       get_type_string_for_url_(std::move(get_type_string_for_url)),
       known_type_strings_(known_type_strings),
-      sandbox_delegate_(sandbox_delegate) {
+      sandbox_delegate_(sandbox_delegate),
+      delegate_(std::make_unique<ObfuscatedFileUtilDiskDelegate>()) {
+  // TODO(https://crbug.com/93417): |delegate_| to be initialized with an
+  // instance of |ObfuscatedFileUtilMemoryDelegate| if |is_incognito| is true.
   DCHECK(!get_type_string_for_url_.is_null());
   DETACH_FROM_SEQUENCE(sequence_checker_);
   DCHECK(!is_incognito ||
          (env_override && leveldb_chrome::IsMemEnv(env_override)));
-
-  if (is_incognito)
-    delegate_ = std::make_unique<ObfuscatedFileUtilMemoryDelegate>();
-  else
-    delegate_ = std::make_unique<ObfuscatedFileUtilDiskDelegate>();
 }
 
 ObfuscatedFileUtil::~ObfuscatedFileUtil() {
diff --git a/storage/browser/fileapi/obfuscated_file_util.h b/storage/browser/fileapi/obfuscated_file_util.h
index 3d1369d..1c9b3ae 100644
--- a/storage/browser/fileapi/obfuscated_file_util.h
+++ b/storage/browser/fileapi/obfuscated_file_util.h
@@ -23,7 +23,9 @@
 #include "storage/browser/blob/shareable_file_reference.h"
 #include "storage/browser/fileapi/file_system_file_util.h"
 #include "storage/browser/fileapi/file_system_url.h"
-#include "storage/browser/fileapi/obfuscated_file_util_delegate.h"
+// TODO(https://crbug.com/93417): To be replaced with
+// obfuscated_file_util_delegate.h
+#include "storage/browser/fileapi/obfuscated_file_util_disk_delegate.h"
 #include "storage/browser/fileapi/sandbox_directory_database.h"
 #include "storage/browser/fileapi/sandbox_file_system_backend_delegate.h"
 #include "storage/common/fileapi/file_system_types.h"
@@ -340,7 +342,9 @@
   // Not owned.
   SandboxFileSystemBackendDelegate* sandbox_delegate_;
 
-  std::unique_ptr<ObfuscatedFileUtilDelegate> delegate_;
+  // TODO(https://crbug.com/93417): To be replaced with
+  // ObfuscatedFileUtilDelegate.
+  std::unique_ptr<ObfuscatedFileUtilDiskDelegate> delegate_;
 
   DISALLOW_COPY_AND_ASSIGN(ObfuscatedFileUtil);
 };
diff --git a/storage/browser/fileapi/obfuscated_file_util_delegate.h b/storage/browser/fileapi/obfuscated_file_util_delegate.h
deleted file mode 100644
index 6a63cdf..0000000
--- a/storage/browser/fileapi/obfuscated_file_util_delegate.h
+++ /dev/null
@@ -1,58 +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 STORAGE_BROWSER_FILEAPI_OBFUSCATED_FILE_UTIL_DELEGATE_H_
-#define STORAGE_BROWSER_FILEAPI_OBFUSCATED_FILE_UTIL_DELEGATE_H_
-
-#include "base/component_export.h"
-#include "base/files/file.h"
-#include "base/files/file_path.h"
-#include "storage/browser/fileapi/native_file_util.h"
-
-namespace storage {
-
-// This delegate performs all ObfuscatedFileUtil tasks that actually touch disk.
-
-class COMPONENT_EXPORT(STORAGE_BROWSER) ObfuscatedFileUtilDelegate {
- public:
-  ObfuscatedFileUtilDelegate() = default;
-  virtual ~ObfuscatedFileUtilDelegate() = default;
-
-  virtual bool DirectoryExists(const base::FilePath& path) = 0;
-  virtual bool DeleteFileOrDirectory(const base::FilePath& path,
-                                     bool recursive) = 0;
-  virtual bool IsLink(const base::FilePath& file_path) = 0;
-  virtual bool PathExists(const base::FilePath& path) = 0;
-
-  virtual NativeFileUtil::CopyOrMoveMode CopyOrMoveModeForDestination(
-      const FileSystemURL& dest_url,
-      bool copy) = 0;
-  virtual base::File CreateOrOpen(const base::FilePath& path,
-                                  int file_flags) = 0;
-  virtual base::File::Error EnsureFileExists(const base::FilePath& path,
-                                             bool* created) = 0;
-  virtual base::File::Error CreateDirectory(const base::FilePath& path,
-                                            bool exclusive,
-                                            bool recursive) = 0;
-  virtual base::File::Error GetFileInfo(const base::FilePath& path,
-                                        base::File::Info* file_info) = 0;
-  virtual base::File::Error Touch(const base::FilePath& path,
-                                  const base::Time& last_access_time,
-                                  const base::Time& last_modified_time) = 0;
-  virtual base::File::Error Truncate(const base::FilePath& path,
-                                     int64_t length) = 0;
-  virtual base::File::Error CopyOrMoveFile(
-      const base::FilePath& src_path,
-      const base::FilePath& dest_path,
-      FileSystemOperation::CopyOrMoveOption option,
-      NativeFileUtil::CopyOrMoveMode mode) = 0;
-  virtual base::File::Error DeleteFile(const base::FilePath& path) = 0;
-
- private:
-  DISALLOW_COPY_AND_ASSIGN(ObfuscatedFileUtilDelegate);
-};
-
-}  // namespace storage
-
-#endif  // STORAGE_BROWSER_FILEAPI_OBFUSCATED_FILE_UTIL_DELEGATE_H_
diff --git a/storage/browser/fileapi/obfuscated_file_util_disk_delegate.cc b/storage/browser/fileapi/obfuscated_file_util_disk_delegate.cc
index 36d34aa..7d2acb3 100644
--- a/storage/browser/fileapi/obfuscated_file_util_disk_delegate.cc
+++ b/storage/browser/fileapi/obfuscated_file_util_disk_delegate.cc
@@ -11,8 +11,6 @@
 
 ObfuscatedFileUtilDiskDelegate::ObfuscatedFileUtilDiskDelegate() {}
 
-ObfuscatedFileUtilDiskDelegate::~ObfuscatedFileUtilDiskDelegate() {}
-
 bool ObfuscatedFileUtilDiskDelegate::DirectoryExists(
     const base::FilePath& path) {
   return base::DirectoryExists(path);
diff --git a/storage/browser/fileapi/obfuscated_file_util_disk_delegate.h b/storage/browser/fileapi/obfuscated_file_util_disk_delegate.h
index 50373442..612ebb42 100644
--- a/storage/browser/fileapi/obfuscated_file_util_disk_delegate.h
+++ b/storage/browser/fileapi/obfuscated_file_util_disk_delegate.h
@@ -9,46 +9,42 @@
 #include "base/files/file.h"
 #include "base/files/file_path.h"
 #include "storage/browser/fileapi/native_file_util.h"
-#include "storage/browser/fileapi/obfuscated_file_util_delegate.h"
 
 namespace storage {
 
 // This delegate performs all ObfuscatedFileUtil tasks that actually touch disk.
 
-class COMPONENT_EXPORT(STORAGE_BROWSER) ObfuscatedFileUtilDiskDelegate
-    : public ObfuscatedFileUtilDelegate {
+// TODO(https://crbug.com/93417): To be driven from abstract class
+// |ObfuscatedFileUtilDelegate|.
+class COMPONENT_EXPORT(STORAGE_BROWSER) ObfuscatedFileUtilDiskDelegate {
  public:
   ObfuscatedFileUtilDiskDelegate();
-  ~ObfuscatedFileUtilDiskDelegate() override;
+  ~ObfuscatedFileUtilDiskDelegate() = default;
 
-  bool DirectoryExists(const base::FilePath& path) override;
-  bool DeleteFileOrDirectory(const base::FilePath& path,
-                             bool recursive) override;
-  bool IsLink(const base::FilePath& file_path) override;
-  bool PathExists(const base::FilePath& path) override;
+  bool DirectoryExists(const base::FilePath& path);
+  bool DeleteFileOrDirectory(const base::FilePath& path, bool recursive);
+  bool IsLink(const base::FilePath& file_path);
+  bool PathExists(const base::FilePath& path);
 
   NativeFileUtil::CopyOrMoveMode CopyOrMoveModeForDestination(
       const FileSystemURL& dest_url,
-      bool copy) override;
-  base::File CreateOrOpen(const base::FilePath& path, int file_flags) override;
-  base::File::Error EnsureFileExists(const base::FilePath& path,
-                                     bool* created) override;
+      bool copy);
+  base::File CreateOrOpen(const base::FilePath& path, int file_flags);
+  base::File::Error EnsureFileExists(const base::FilePath& path, bool* created);
   base::File::Error CreateDirectory(const base::FilePath& path,
                                     bool exclusive,
-                                    bool recursive) override;
+                                    bool recursive);
   base::File::Error GetFileInfo(const base::FilePath& path,
-                                base::File::Info* file_info) override;
+                                base::File::Info* file_info);
   base::File::Error Touch(const base::FilePath& path,
                           const base::Time& last_access_time,
-                          const base::Time& last_modified_time) override;
-  base::File::Error Truncate(const base::FilePath& path,
-                             int64_t length) override;
-  base::File::Error CopyOrMoveFile(
-      const base::FilePath& src_path,
-      const base::FilePath& dest_path,
-      FileSystemOperation::CopyOrMoveOption option,
-      NativeFileUtil::CopyOrMoveMode mode) override;
-  base::File::Error DeleteFile(const base::FilePath& path) override;
+                          const base::Time& last_modified_time);
+  base::File::Error Truncate(const base::FilePath& path, int64_t length);
+  base::File::Error CopyOrMoveFile(const base::FilePath& src_path,
+                                   const base::FilePath& dest_path,
+                                   FileSystemOperation::CopyOrMoveOption option,
+                                   NativeFileUtil::CopyOrMoveMode mode);
+  base::File::Error DeleteFile(const base::FilePath& path);
 
   DISALLOW_COPY_AND_ASSIGN(ObfuscatedFileUtilDiskDelegate);
 };
diff --git a/storage/browser/fileapi/obfuscated_file_util_memory_delegate.cc b/storage/browser/fileapi/obfuscated_file_util_memory_delegate.cc
deleted file mode 100644
index 5a94c69c..0000000
--- a/storage/browser/fileapi/obfuscated_file_util_memory_delegate.cc
+++ /dev/null
@@ -1,114 +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 "storage/browser/fileapi/obfuscated_file_util_memory_delegate.h"
-
-namespace storage {
-
-ObfuscatedFileUtilMemoryDelegate::ObfuscatedFileUtilMemoryDelegate() {}
-ObfuscatedFileUtilMemoryDelegate::~ObfuscatedFileUtilMemoryDelegate() {}
-
-bool ObfuscatedFileUtilMemoryDelegate::DirectoryExists(
-    const base::FilePath& path) {
-  NOTIMPLEMENTED();
-  // return base::DirectoryExists(path);
-  return false;
-}
-
-bool ObfuscatedFileUtilMemoryDelegate::DeleteFileOrDirectory(
-    const base::FilePath& path,
-    bool recursive) {
-  NOTIMPLEMENTED();
-  // return base::DeleteFile(path, recursive);
-  return false;
-}
-
-bool ObfuscatedFileUtilMemoryDelegate::IsLink(const base::FilePath& file_path) {
-  NOTIMPLEMENTED();
-  // return base::IsLink(file_path);
-  return false;
-}
-
-bool ObfuscatedFileUtilMemoryDelegate::PathExists(const base::FilePath& path) {
-  NOTIMPLEMENTED();
-  // return base::PathExists(path);
-  return false;
-}
-
-NativeFileUtil::CopyOrMoveMode
-ObfuscatedFileUtilMemoryDelegate::CopyOrMoveModeForDestination(
-    const FileSystemURL& dest_url,
-    bool copy) {
-  NOTIMPLEMENTED();
-  // return NativeFileUtil::CopyOrMoveModeForDestination(dest_url, copy);
-  return NativeFileUtil::CopyOrMoveMode::MOVE;
-}
-
-base::File ObfuscatedFileUtilMemoryDelegate::CreateOrOpen(
-    const base::FilePath& path,
-    int file_flags) {
-  NOTIMPLEMENTED();
-  // return NativeFileUtil::CreateOrOpen(path, file_flags);
-  return base::File();
-}
-
-base::File::Error ObfuscatedFileUtilMemoryDelegate::EnsureFileExists(
-    const base::FilePath& path,
-    bool* created) {
-  NOTIMPLEMENTED();
-  // return NativeFileUtil::EnsureFileExists(path, created);
-  return base::File::FILE_ERROR_FAILED;
-}
-base::File::Error ObfuscatedFileUtilMemoryDelegate::CreateDirectory(
-    const base::FilePath& path,
-    bool exclusive,
-    bool recursive) {
-  NOTIMPLEMENTED();
-  // return NativeFileUtil::CreateDirectory(path, exclusive, recursive);
-  return base::File::FILE_ERROR_FAILED;
-}
-
-base::File::Error ObfuscatedFileUtilMemoryDelegate::GetFileInfo(
-    const base::FilePath& path,
-    base::File::Info* file_info) {
-  NOTIMPLEMENTED();
-  // return NativeFileUtil::GetFileInfo(path, file_info);
-  return base::File::FILE_ERROR_FAILED;
-}
-
-base::File::Error ObfuscatedFileUtilMemoryDelegate::Touch(
-    const base::FilePath& path,
-    const base::Time& last_access_time,
-    const base::Time& last_modified_time) {
-  NOTIMPLEMENTED();
-  // return NativeFileUtil::Touch(path, last_access_time, last_modified_time);
-  return base::File::FILE_ERROR_FAILED;
-}
-
-base::File::Error ObfuscatedFileUtilMemoryDelegate::Truncate(
-    const base::FilePath& path,
-    int64_t length) {
-  NOTIMPLEMENTED();
-  // return NativeFileUtil::Truncate(path, length);
-  return base::File::FILE_ERROR_FAILED;
-}
-
-base::File::Error ObfuscatedFileUtilMemoryDelegate::CopyOrMoveFile(
-    const base::FilePath& src_path,
-    const base::FilePath& dest_path,
-    FileSystemOperation::CopyOrMoveOption option,
-    NativeFileUtil::CopyOrMoveMode mode) {
-  NOTIMPLEMENTED();
-  // return NativeFileUtil::CopyOrMoveFile(src_path, dest_path, option, mode);
-  return base::File::FILE_ERROR_FAILED;
-}
-
-base::File::Error ObfuscatedFileUtilMemoryDelegate::DeleteFile(
-    const base::FilePath& path) {
-  NOTIMPLEMENTED();
-  // return NativeFileUtil::DeleteFile(path);
-  return base::File::FILE_ERROR_FAILED;
-}
-
-}  // namespace storage
diff --git a/storage/browser/fileapi/obfuscated_file_util_memory_delegate.h b/storage/browser/fileapi/obfuscated_file_util_memory_delegate.h
deleted file mode 100644
index 1c59cbb..0000000
--- a/storage/browser/fileapi/obfuscated_file_util_memory_delegate.h
+++ /dev/null
@@ -1,59 +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 STORAGE_BROWSER_FILEAPI_OBFUSCATED_FILE_UTIL_MEMORY_DELEGATE_H_
-#define STORAGE_BROWSER_FILEAPI_OBFUSCATED_FILE_UTIL_MEMORY_DELEGATE_H_
-
-#include "base/component_export.h"
-#include "base/files/file.h"
-#include "base/files/file_path.h"
-#include "storage/browser/fileapi/native_file_util.h"
-#include "storage/browser/fileapi/obfuscated_file_util_delegate.h"
-
-namespace storage {
-
-// This delegate performs all ObfuscatedFileUtil tasks that require touching
-// disk and peforms them in memory.
-
-class COMPONENT_EXPORT(STORAGE_BROWSER) ObfuscatedFileUtilMemoryDelegate
-    : public ObfuscatedFileUtilDelegate {
- public:
-  ObfuscatedFileUtilMemoryDelegate();
-  ~ObfuscatedFileUtilMemoryDelegate() override;
-
-  bool DirectoryExists(const base::FilePath& path) override;
-  bool DeleteFileOrDirectory(const base::FilePath& path,
-                             bool recursive) override;
-  bool IsLink(const base::FilePath& file_path) override;
-  bool PathExists(const base::FilePath& path) override;
-
-  NativeFileUtil::CopyOrMoveMode CopyOrMoveModeForDestination(
-      const FileSystemURL& dest_url,
-      bool copy) override;
-  base::File CreateOrOpen(const base::FilePath& path, int file_flags) override;
-  base::File::Error EnsureFileExists(const base::FilePath& path,
-                                     bool* created) override;
-  base::File::Error CreateDirectory(const base::FilePath& path,
-                                    bool exclusive,
-                                    bool recursive) override;
-  base::File::Error GetFileInfo(const base::FilePath& path,
-                                base::File::Info* file_info) override;
-  base::File::Error Touch(const base::FilePath& path,
-                          const base::Time& last_access_time,
-                          const base::Time& last_modified_time) override;
-  base::File::Error Truncate(const base::FilePath& path,
-                             int64_t length) override;
-  base::File::Error CopyOrMoveFile(
-      const base::FilePath& src_path,
-      const base::FilePath& dest_path,
-      FileSystemOperation::CopyOrMoveOption option,
-      NativeFileUtil::CopyOrMoveMode mode) override;
-  base::File::Error DeleteFile(const base::FilePath& path) override;
-
-  DISALLOW_COPY_AND_ASSIGN(ObfuscatedFileUtilMemoryDelegate);
-};
-
-}  // namespace storage
-
-#endif  // STORAGE_BROWSER_FILEAPI_OBFUSCATED_FILE_UTIL_MEMORY_DELEGATE_H_
diff --git a/storage/browser/fileapi/obfuscated_file_util_unittest.cc b/storage/browser/fileapi/obfuscated_file_util_unittest.cc
index 5c83919..6bfce69 100644
--- a/storage/browser/fileapi/obfuscated_file_util_unittest.cc
+++ b/storage/browser/fileapi/obfuscated_file_util_unittest.cc
@@ -43,7 +43,6 @@
 #include "storage/browser/test/test_file_system_context.h"
 #include "storage/common/database/database_identifier.h"
 #include "testing/gtest/include/gtest/gtest.h"
-#include "third_party/leveldatabase/leveldb_chrome.h"
 
 using content::AsyncFileTestHelper;
 using storage::FileSystemContext;
@@ -152,14 +151,11 @@
 // could theoretically be shared.  It would basically be a FSFU interface
 // compliance test, and only the subclass-specific bits that look into the
 // implementation would need to be written per-subclass.
-class ObfuscatedFileUtilTest : public testing::Test,
-                               public ::testing::WithParamInterface<bool> {
+class ObfuscatedFileUtilTest : public testing::Test {
  public:
   ObfuscatedFileUtilTest()
-      : is_incognito_(GetParam()),
-        scoped_task_environment_(
+      : scoped_task_environment_(
             base::test::ScopedTaskEnvironment::MainThreadType::IO),
-
         origin_(GURL("http://www.example.com")),
         type_(storage::kFileSystemTypeTemporary),
         sandbox_file_system_(origin_, type_),
@@ -173,7 +169,7 @@
     storage_policy_ = new MockSpecialStoragePolicy();
 
     quota_manager_ = new storage::QuotaManager(
-        is_incognito_, data_dir_.GetPath(),
+        false /* is_incognito */, data_dir_.GetPath(),
         base::ThreadTaskRunnerHandle::Get().get(), storage_policy_.get(),
         storage::GetQuotaSettingsFunc());
     storage::QuotaSettings settings;
@@ -194,9 +190,6 @@
 
     change_observers_ =
         storage::MockFileChangeObserver::CreateList(&change_observer_);
-
-    if (is_incognito_)
-      incognito_leveldb_environment_ = leveldb_chrome::NewMemEnv("FileSystem");
   }
 
   void TearDown() override {
@@ -254,11 +247,11 @@
 
   std::unique_ptr<ObfuscatedFileUtil> CreateObfuscatedFileUtil(
       storage::SpecialStoragePolicy* storage_policy) {
+    // TODO(https://crbug.com/93417): Add support for incognito tests.
     return std::unique_ptr<ObfuscatedFileUtil>(
-        ObfuscatedFileUtil::CreateForTesting(
-            storage_policy, data_dir_path(),
-            is_incognito_ ? incognito_leveldb_environment_.get() : nullptr,
-            is_incognito_));
+        ObfuscatedFileUtil::CreateForTesting(storage_policy, data_dir_path(),
+                                             /*env_override=*/nullptr,
+                                             /*is_incognito=*/false));
   }
 
   ObfuscatedFileUtil* ofu() {
@@ -687,10 +680,6 @@
   }
 
   void MaybeDropDatabasesAliveCaseTestBody() {
-    // TODO(https://crbug.com/43417): Enable test after finishing incognito
-    // implementation.
-    if (is_incognito_)
-      return;
     std::unique_ptr<ObfuscatedFileUtil> file_util =
         CreateObfuscatedFileUtil(nullptr);
     file_util->InitOriginDatabase(GURL(), true /*create*/);
@@ -721,10 +710,6 @@
   }
 
   void DestroyDirectoryDatabase_IsolatedTestBody() {
-    // TODO(https://crbug.com/43417): Enable test after finishing incognito
-    // implementation.
-    if (is_incognito_)
-      return;
     storage_policy_->AddIsolated(origin_);
     std::unique_ptr<ObfuscatedFileUtil> file_util =
         CreateObfuscatedFileUtil(storage_policy_.get());
@@ -744,10 +729,6 @@
   }
 
   void GetDirectoryDatabase_IsolatedTestBody() {
-    // TODO(https://crbug.com/43417): Enable test after finishing incognito
-    // implementation.
-    if (is_incognito_)
-      return;
     storage_policy_->AddIsolated(origin_);
     std::unique_ptr<ObfuscatedFileUtil> file_util =
         CreateObfuscatedFileUtil(storage_policy_.get());
@@ -782,8 +763,6 @@
   const base::FilePath& data_dir_path() const { return data_dir_.GetPath(); }
 
  protected:
-  bool is_incognito_;
-  std::unique_ptr<leveldb::Env> incognito_leveldb_environment_;
   base::test::ScopedTaskEnvironment scoped_task_environment_;
   base::ScopedTempDir data_dir_;
   scoped_refptr<MockSpecialStoragePolicy> storage_policy_;
@@ -802,9 +781,7 @@
   DISALLOW_COPY_AND_ASSIGN(ObfuscatedFileUtilTest);
 };
 
-INSTANTIATE_TEST_CASE_P(, ObfuscatedFileUtilTest, ::testing::Bool());
-
-TEST_P(ObfuscatedFileUtilTest, TestCreateAndDeleteFile) {
+TEST_F(ObfuscatedFileUtilTest, TestCreateAndDeleteFile) {
   FileSystemURL url = CreateURLFromUTF8("fake/file");
   std::unique_ptr<FileSystemOperationContext> context(NewContext(nullptr));
   int file_flags = base::File::FLAG_CREATE | base::File::FLAG_WRITE;
@@ -889,7 +866,7 @@
   EXPECT_TRUE(change_observer()->HasNoChange());
 }
 
-TEST_P(ObfuscatedFileUtilTest, TestTruncate) {
+TEST_F(ObfuscatedFileUtilTest, TestTruncate) {
   bool created = false;
   FileSystemURL url = CreateURLFromUTF8("file");
   std::unique_ptr<FileSystemOperationContext> context(NewContext(nullptr));
@@ -926,7 +903,7 @@
   EXPECT_TRUE(change_observer()->HasNoChange());
 }
 
-TEST_P(ObfuscatedFileUtilTest, TestQuotaOnTruncation) {
+TEST_F(ObfuscatedFileUtilTest, TestQuotaOnTruncation) {
   bool created = false;
   FileSystemURL url = CreateURLFromUTF8("file");
 
@@ -981,7 +958,7 @@
   ASSERT_EQ(0, ComputeTotalFileSize());
 }
 
-TEST_P(ObfuscatedFileUtilTest, TestEnsureFileExists) {
+TEST_F(ObfuscatedFileUtilTest, TestEnsureFileExists) {
   FileSystemURL url = CreateURLFromUTF8("fake/file");
   bool created = false;
   std::unique_ptr<FileSystemOperationContext> context(NewContext(nullptr));
@@ -1036,7 +1013,7 @@
   EXPECT_TRUE(change_observer()->HasNoChange());
 }
 
-TEST_P(ObfuscatedFileUtilTest, TestDirectoryOps) {
+TEST_F(ObfuscatedFileUtilTest, TestDirectoryOps) {
   std::unique_ptr<FileSystemOperationContext> context(NewContext(nullptr));
 
   bool exclusive = false;
@@ -1178,7 +1155,7 @@
   EXPECT_TRUE(change_observer()->HasNoChange());
 }
 
-TEST_P(ObfuscatedFileUtilTest, TestReadDirectory) {
+TEST_F(ObfuscatedFileUtilTest, TestReadDirectory) {
   std::unique_ptr<FileSystemOperationContext> context(NewContext(nullptr));
   bool exclusive = true;
   bool recursive = true;
@@ -1188,15 +1165,15 @@
   TestReadDirectoryHelper(url);
 }
 
-TEST_P(ObfuscatedFileUtilTest, TestReadRootWithSlash) {
+TEST_F(ObfuscatedFileUtilTest, TestReadRootWithSlash) {
   TestReadDirectoryHelper(CreateURLFromUTF8(std::string()));
 }
 
-TEST_P(ObfuscatedFileUtilTest, TestReadRootWithEmptyString) {
+TEST_F(ObfuscatedFileUtilTest, TestReadRootWithEmptyString) {
   TestReadDirectoryHelper(CreateURLFromUTF8("/"));
 }
 
-TEST_P(ObfuscatedFileUtilTest, TestReadDirectoryOnFile) {
+TEST_F(ObfuscatedFileUtilTest, TestReadDirectoryOnFile) {
   FileSystemURL url = CreateURLFromUTF8("file");
   std::unique_ptr<FileSystemOperationContext> context(NewContext(nullptr));
 
@@ -1213,7 +1190,7 @@
   EXPECT_TRUE(ofu()->IsDirectoryEmpty(context.get(), url));
 }
 
-TEST_P(ObfuscatedFileUtilTest, TestTouch) {
+TEST_F(ObfuscatedFileUtilTest, TestTouch) {
   FileSystemURL url = CreateURLFromUTF8("file");
   std::unique_ptr<FileSystemOperationContext> context(NewContext(nullptr));
 
@@ -1243,7 +1220,7 @@
   TestTouchHelper(url, false);
 }
 
-TEST_P(ObfuscatedFileUtilTest, TestPathQuotas) {
+TEST_F(ObfuscatedFileUtilTest, TestPathQuotas) {
   FileSystemURL url = CreateURLFromUTF8("fake/file");
   std::unique_ptr<FileSystemOperationContext> context(NewContext(nullptr));
 
@@ -1278,7 +1255,7 @@
   EXPECT_EQ(1024 - path_cost, context->allowed_bytes_growth());
 }
 
-TEST_P(ObfuscatedFileUtilTest, TestCopyOrMoveFileNotFound) {
+TEST_F(ObfuscatedFileUtilTest, TestCopyOrMoveFileNotFound) {
   FileSystemURL source_url = CreateURLFromUTF8("path0.txt");
   FileSystemURL dest_url = CreateURLFromUTF8("path1.txt");
   std::unique_ptr<FileSystemOperationContext> context(NewContext(nullptr));
@@ -1320,7 +1297,7 @@
   EXPECT_TRUE(change_observer()->HasNoChange());
 }
 
-TEST_P(ObfuscatedFileUtilTest, TestCopyOrMoveFileSuccess) {
+TEST_F(ObfuscatedFileUtilTest, TestCopyOrMoveFileSuccess) {
   const int64_t kSourceLength = 5;
   const int64_t kDestLength = 50;
 
@@ -1409,7 +1386,7 @@
   }
 }
 
-TEST_P(ObfuscatedFileUtilTest, TestCopyPathQuotas) {
+TEST_F(ObfuscatedFileUtilTest, TestCopyPathQuotas) {
   FileSystemURL src_url = CreateURLFromUTF8("src path");
   FileSystemURL dest_url = CreateURLFromUTF8("destination path");
   std::unique_ptr<FileSystemOperationContext> context(NewContext(nullptr));
@@ -1439,7 +1416,7 @@
                                   FileSystemOperation::OPTION_NONE, is_copy));
 }
 
-TEST_P(ObfuscatedFileUtilTest, TestMovePathQuotasWithRename) {
+TEST_F(ObfuscatedFileUtilTest, TestMovePathQuotasWithRename) {
   FileSystemURL src_url = CreateURLFromUTF8("src path");
   FileSystemURL dest_url = CreateURLFromUTF8("destination path");
   std::unique_ptr<FileSystemOperationContext> context(NewContext(nullptr));
@@ -1476,7 +1453,7 @@
                                   FileSystemOperation::OPTION_NONE, is_copy));
 }
 
-TEST_P(ObfuscatedFileUtilTest, TestMovePathQuotasWithoutRename) {
+TEST_F(ObfuscatedFileUtilTest, TestMovePathQuotasWithoutRename) {
   FileSystemURL src_url = CreateURLFromUTF8("src path");
   std::unique_ptr<FileSystemOperationContext> context(NewContext(nullptr));
   bool created = false;
@@ -1519,12 +1496,12 @@
       context->allowed_bytes_growth());
 }
 
-TEST_P(ObfuscatedFileUtilTest, TestCopyInForeignFile) {
+TEST_F(ObfuscatedFileUtilTest, TestCopyInForeignFile) {
   TestCopyInForeignFileHelper(false /* overwrite */);
   TestCopyInForeignFileHelper(true /* overwrite */);
 }
 
-TEST_P(ObfuscatedFileUtilTest, TestEnumerator) {
+TEST_F(ObfuscatedFileUtilTest, TestEnumerator) {
   std::unique_ptr<FileSystemOperationContext> context(NewContext(nullptr));
   FileSystemURL src_url = CreateURLFromUTF8("source dir");
   bool exclusive = true;
@@ -1554,7 +1531,7 @@
   EXPECT_FALSE(DirectoryExists(dest_url));
 }
 
-TEST_P(ObfuscatedFileUtilTest, TestOriginEnumerator) {
+TEST_F(ObfuscatedFileUtilTest, TestOriginEnumerator) {
   std::unique_ptr<ObfuscatedFileUtil::AbstractOriginEnumerator> enumerator(
       ofu()->CreateOriginEnumerator());
   // The test helper starts out with a single filesystem.
@@ -1640,7 +1617,7 @@
   EXPECT_TRUE(diff.empty());
 }
 
-TEST_P(ObfuscatedFileUtilTest, TestRevokeUsageCache) {
+TEST_F(ObfuscatedFileUtilTest, TestRevokeUsageCache) {
   std::unique_ptr<FileSystemOperationContext> context(NewContext(nullptr));
 
   int64_t expected_quota = 0;
@@ -1686,7 +1663,7 @@
   EXPECT_EQ(expected_quota, usage());
 }
 
-TEST_P(ObfuscatedFileUtilTest, TestInconsistency) {
+TEST_F(ObfuscatedFileUtilTest, TestInconsistency) {
   const FileSystemURL kPath1 = CreateURLFromUTF8("hoge");
   const FileSystemURL kPath2 = CreateURLFromUTF8("fuga");
 
@@ -1761,7 +1738,7 @@
   EXPECT_EQ(0, file_info.size);
 }
 
-TEST_P(ObfuscatedFileUtilTest, TestIncompleteDirectoryReading) {
+TEST_F(ObfuscatedFileUtilTest, TestIncompleteDirectoryReading) {
   const FileSystemURL kPath[] = {
     CreateURLFromUTF8("foo"),
     CreateURLFromUTF8("bar"),
@@ -1796,7 +1773,7 @@
   EXPECT_EQ(base::size(kPath) - 1, entries.size());
 }
 
-TEST_P(ObfuscatedFileUtilTest, TestDirectoryTimestampForCreation) {
+TEST_F(ObfuscatedFileUtilTest, TestDirectoryTimestampForCreation) {
   std::unique_ptr<FileSystemOperationContext> context(NewContext(nullptr));
   const FileSystemURL dir_url = CreateURLFromUTF8("foo_dir");
 
@@ -1921,7 +1898,7 @@
   EXPECT_NE(base::Time(), GetModifiedTime(dir_url));
 }
 
-TEST_P(ObfuscatedFileUtilTest, TestDirectoryTimestampForDeletion) {
+TEST_F(ObfuscatedFileUtilTest, TestDirectoryTimestampForDeletion) {
   std::unique_ptr<FileSystemOperationContext> context(NewContext(nullptr));
   const FileSystemURL dir_url = CreateURLFromUTF8("foo_dir");
 
@@ -1980,7 +1957,7 @@
   EXPECT_NE(base::Time(), GetModifiedTime(dir_url));
 }
 
-TEST_P(ObfuscatedFileUtilTest, TestDirectoryTimestampForCopyAndMove) {
+TEST_F(ObfuscatedFileUtilTest, TestDirectoryTimestampForCopyAndMove) {
   TestDirectoryTimestampHelper(
       CreateURLFromUTF8("copy overwrite"), true, true);
   TestDirectoryTimestampHelper(
@@ -1991,7 +1968,7 @@
       CreateURLFromUTF8("move non-overwrite"), false, false);
 }
 
-TEST_P(ObfuscatedFileUtilTest, TestFileEnumeratorTimestamp) {
+TEST_F(ObfuscatedFileUtilTest, TestFileEnumeratorTimestamp) {
   FileSystemURL dir = CreateURLFromUTF8("foo");
   FileSystemURL url1 = FileSystemURLAppendUTF8(dir, "bar");
   FileSystemURL url2 = FileSystemURLAppendUTF8(dir, "baz");
@@ -2053,7 +2030,7 @@
 #else
 #define MAYBE_TestQuotaOnCopyFile TestQuotaOnCopyFile
 #endif
-TEST_P(ObfuscatedFileUtilTest, MAYBE_TestQuotaOnCopyFile) {
+TEST_F(ObfuscatedFileUtilTest, MAYBE_TestQuotaOnCopyFile) {
   FileSystemURL from_file(CreateURLFromUTF8("fromfile"));
   FileSystemURL obstacle_file(CreateURLFromUTF8("obstaclefile"));
   FileSystemURL to_file1(CreateURLFromUTF8("tofile1"));
@@ -2151,7 +2128,7 @@
   }
 }
 
-TEST_P(ObfuscatedFileUtilTest, TestQuotaOnMoveFile) {
+TEST_F(ObfuscatedFileUtilTest, TestQuotaOnMoveFile) {
   FileSystemURL from_file(CreateURLFromUTF8("fromfile"));
   FileSystemURL obstacle_file(CreateURLFromUTF8("obstaclefile"));
   FileSystemURL to_file(CreateURLFromUTF8("tofile"));
@@ -2257,7 +2234,7 @@
   context.reset();
 }
 
-TEST_P(ObfuscatedFileUtilTest, TestQuotaOnRemove) {
+TEST_F(ObfuscatedFileUtilTest, TestQuotaOnRemove) {
   FileSystemURL dir(CreateURLFromUTF8("dir"));
   FileSystemURL file(CreateURLFromUTF8("file"));
   FileSystemURL dfile1(CreateURLFromUTF8("dir/dfile1"));
@@ -2321,7 +2298,7 @@
   ASSERT_EQ(0, ComputeTotalFileSize());
 }
 
-TEST_P(ObfuscatedFileUtilTest, TestQuotaOnOpen) {
+TEST_F(ObfuscatedFileUtilTest, TestQuotaOnOpen) {
   FileSystemURL url(CreateURLFromUTF8("file"));
 
   bool created;
@@ -2370,23 +2347,23 @@
   file.Close();
 }
 
-TEST_P(ObfuscatedFileUtilTest, MaybeDropDatabasesAliveCase) {
+TEST_F(ObfuscatedFileUtilTest, MaybeDropDatabasesAliveCase) {
   MaybeDropDatabasesAliveCaseTestBody();
 }
 
-TEST_P(ObfuscatedFileUtilTest, MaybeDropDatabasesAlreadyDeletedCase) {
+TEST_F(ObfuscatedFileUtilTest, MaybeDropDatabasesAlreadyDeletedCase) {
   MaybeDropDatabasesAlreadyDeletedCaseTestBody();
 }
 
-TEST_P(ObfuscatedFileUtilTest, DestroyDirectoryDatabase_Isolated) {
+TEST_F(ObfuscatedFileUtilTest, DestroyDirectoryDatabase_Isolated) {
   DestroyDirectoryDatabase_IsolatedTestBody();
 }
 
-TEST_P(ObfuscatedFileUtilTest, GetDirectoryDatabase_Isolated) {
+TEST_F(ObfuscatedFileUtilTest, GetDirectoryDatabase_Isolated) {
   GetDirectoryDatabase_IsolatedTestBody();
 }
 
-TEST_P(ObfuscatedFileUtilTest, OpenPathInNonDirectory) {
+TEST_F(ObfuscatedFileUtilTest, OpenPathInNonDirectory) {
   FileSystemURL url(CreateURLFromUTF8("file"));
   FileSystemURL path_in_file(CreateURLFromUTF8("file/file"));
   bool created;
@@ -2408,7 +2385,7 @@
                                    false /* recursive */));
 }
 
-TEST_P(ObfuscatedFileUtilTest, CreateDirectory_NotADirectoryInRecursive) {
+TEST_F(ObfuscatedFileUtilTest, CreateDirectory_NotADirectoryInRecursive) {
   FileSystemURL file(CreateURLFromUTF8("file"));
   FileSystemURL path_in_file(CreateURLFromUTF8("file/child"));
   FileSystemURL path_in_file_in_file(
@@ -2431,7 +2408,7 @@
                                    true /* recursive */));
 }
 
-TEST_P(ObfuscatedFileUtilTest, DeleteDirectoryForOriginAndType) {
+TEST_F(ObfuscatedFileUtilTest, DeleteDirectoryForOriginAndType) {
   const GURL origin1("http://www.example.com:12");
   const GURL origin2("http://www.example.com:1234");
   const GURL origin3("http://nope.example.com");
@@ -2509,7 +2486,7 @@
       origin3, GetTypeString(kFileSystemTypePersistent)));
 }
 
-TEST_P(ObfuscatedFileUtilTest, DeleteDirectoryForOriginAndType_DeleteAll) {
+TEST_F(ObfuscatedFileUtilTest, DeleteDirectoryForOriginAndType_DeleteAll) {
   const GURL origin1("http://www.example.com:12");
   const GURL origin2("http://www.example.com:1234");
 
diff --git a/testing/buildbot/filters/webui_polymer2_browser_tests.filter b/testing/buildbot/filters/webui_polymer2_browser_tests.filter
index cbc0befd..d87acad 100644
--- a/testing/buildbot/filters/webui_polymer2_browser_tests.filter
+++ b/testing/buildbot/filters/webui_polymer2_browser_tests.filter
@@ -89,6 +89,7 @@
 CrElementsToggleTest.*
 CrElementsToolbarSearchFieldTest.*
 CrExtensionsActivityLogTest.*
+CrExtensionsActivityLogHistoryTest.*
 CrExtensionsActivityLogItemTest.*
 CrExtensionsA11yTest.*
 CrExtensionsA11yTestWithMultipleExensions.*
diff --git a/testing/variations/fieldtrial_testing_config.json b/testing/variations/fieldtrial_testing_config.json
index 6cac9d0..3ee6f21 100644
--- a/testing/variations/fieldtrial_testing_config.json
+++ b/testing/variations/fieldtrial_testing_config.json
@@ -5301,9 +5301,6 @@
     "VizDisplayCompositor": [
         {
             "platforms": [
-                "windows",
-                "linux",
-                "mac",
                 "android"
             ],
             "experiments": [
diff --git a/third_party/blink/public/mojom/appcache/appcache.mojom b/third_party/blink/public/mojom/appcache/appcache.mojom
index c4cbd2f..c1040ac 100644
--- a/third_party/blink/public/mojom/appcache/appcache.mojom
+++ b/third_party/blink/public/mojom/appcache/appcache.mojom
@@ -114,9 +114,6 @@
   // a particular host. This is sent in reply to AppCacheHostMsg_SelectCache.
   CacheSelected(int32 host_id, AppCacheInfo info);
 
-  // Notifies the renderer of an AppCache status change.
-  StatusChanged(array<int32> host_ids, AppCacheStatus status);
-
   // Notifies the renderer of an AppCache event other than the
   // progress event which has a seperate message.
   EventRaised(array<int32> host_ids, AppCacheEventID event_id);
diff --git a/third_party/blink/public/mojom/devtools/devtools_agent.mojom b/third_party/blink/public/mojom/devtools/devtools_agent.mojom
index 69aae52..3d503f2 100644
--- a/third_party/blink/public/mojom/devtools/devtools_agent.mojom
+++ b/third_party/blink/public/mojom/devtools/devtools_agent.mojom
@@ -4,11 +4,15 @@
 
 module blink.mojom;
 
-import "mojo/public/mojom/base/big_string.mojom";
+import "mojo/public/mojom/base/big_buffer.mojom";
 import "mojo/public/mojom/base/unguessable_token.mojom";
 import "ui/gfx/geometry/mojo/geometry.mojom";
 import "url/mojom/url.mojom";
 
+struct DevToolsMessage {
+  mojo_base.mojom.BigBuffer data;
+};
+
 // Debugging interactions are defined in Remote Debugging Protocol.
 // See https://chromedevtools.github.io/devtools-protocol/ for more
 // information on the protocol itself.
@@ -111,7 +115,7 @@
   // |method| is a method name as defined in protocol (e.g. "Runtime.evaluate").
   // |call_id| is a command id as defined in protocol, and is going to be
   // reported back to host in a response message (see DevToolsSessionHost).
-  DispatchProtocolCommand(int32 call_id, string method, string message);
+  DispatchProtocolCommand(int32 call_id, string method, DevToolsMessage message);
 };
 
 // A peer of DevToolsSession representing a remote debugging client
@@ -123,12 +127,12 @@
   // |updates| are the session state deltas for future reattach (see
   // DevToolsAgent), may be missing if the state did not change since
   // last time.
-  DispatchProtocolResponse(mojo_base.mojom.BigString message,
+  DispatchProtocolResponse(DevToolsMessage message,
                            int32 call_id,
                            DevToolsSessionState? updates);
 
   // Dispatches protocol notification to a remote debugging client.
-  DispatchProtocolNotification(mojo_base.mojom.BigString message,
+  DispatchProtocolNotification(DevToolsMessage message,
                                DevToolsSessionState? updates);
 };
 
diff --git a/third_party/blink/public/mojom/leak_detector/leak_detector.mojom b/third_party/blink/public/mojom/leak_detector/leak_detector.mojom
index cf82ac7..1120c12b 100644
--- a/third_party/blink/public/mojom/leak_detector/leak_detector.mojom
+++ b/third_party/blink/public/mojom/leak_detector/leak_detector.mojom
@@ -11,7 +11,7 @@
   uint32 number_of_live_nodes;
   uint32 number_of_live_layout_objects;
   uint32 number_of_live_resources;
-  uint32 number_of_live_pausable_objects;
+  uint32 number_of_live_context_lifecycle_state_observers;
   uint32 number_of_live_script_promises;
   uint32 number_of_live_frames;
   uint32 number_of_live_v8_per_context_data;
diff --git a/third_party/blink/public/platform/web_loading_behavior_flag.h b/third_party/blink/public/platform/web_loading_behavior_flag.h
index bbba88d0..5c0a225f 100644
--- a/third_party/blink/public/platform/web_loading_behavior_flag.h
+++ b/third_party/blink/public/platform/web_loading_behavior_flag.h
@@ -44,6 +44,8 @@
   // Indicates that a subresource on the page was a candidate for stale
   // while revalidate and caused a non-stale cache load.
   kStaleWhileRevalidateResourceCandidateCacheLoad = 1 << 9,
+  // Indicates that the page is an AMP document, with <html amp> tag.
+  kWebLoadingBehaviorAmpDocumentLoaded = 1 << 10,
 };
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/bindings/core/v8/script_promise_resolver_test.cc b/third_party/blink/renderer/bindings/core/v8/script_promise_resolver_test.cc
index d226bca..f2065e3 100644
--- a/third_party/blink/renderer/bindings/core/v8/script_promise_resolver_test.cc
+++ b/third_party/blink/renderer/bindings/core/v8/script_promise_resolver_test.cc
@@ -316,7 +316,7 @@
       BlinkGC::kEagerSweeping, BlinkGC::GCReason::kForcedGC);
   ASSERT_TRUE(ScriptPromiseResolverKeepAlive::IsAlive());
 
-  GetExecutionContext()->PausePausableObjects(PauseState::kFrozen);
+  GetExecutionContext()->SetLifecycleState(mojom::FrameLifecycleState::kFrozen);
   resolver->Resolve("hello");
   ThreadState::Current()->CollectGarbage(
       BlinkGC::kNoHeapPointersOnStack, BlinkGC::kAtomicMarking,
diff --git a/third_party/blink/renderer/build/scripts/PRESUBMIT.py b/third_party/blink/renderer/build/scripts/PRESUBMIT.py
new file mode 100644
index 0000000..ef715c7
--- /dev/null
+++ b/third_party/blink/renderer/build/scripts/PRESUBMIT.py
@@ -0,0 +1,39 @@
+# 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.
+
+def _RunJson5Tests(input_api, output_api):
+    # Skip if there is no change in json5_generator.py or tests/ folder
+    white_list = [r'.*json5_generator.*', r'.*\btests[\\\/].*']
+    if not input_api.AffectedFiles(file_filter=lambda x: input_api.FilterSourceFile(x, white_list=white_list)):
+        return []
+
+    if input_api.is_committing:
+        message_type = output_api.PresubmitError
+    else:
+        message_type = output_api.PresubmitPromptWarning
+
+    json5_generator_unittest = 'json5_generator_unittest.py'
+    json5_generator_tests_path = input_api.os_path.join(
+        input_api.PresubmitLocalPath(), json5_generator_unittest)
+    if input_api.is_windows:
+        cmd = [input_api.python_executable, json5_generator_tests_path]
+    else:
+        cmd = [json5_generator_tests_path]
+
+    test_cmd = input_api.Command(
+        name=json5_generator_unittest,
+        cmd=cmd,
+        kwargs={},
+        message=message_type)
+    if input_api.verbose:
+        print('Running ' + json5_generator_unittest)
+    return input_api.RunTests([test_cmd])
+
+
+def CheckChangeOnUpload(input_api, output_api):
+    return _RunJson5Tests(input_api, output_api)
+
+
+def CheckChangeOnCommit(input_api, output_api):
+    return _RunJson5Tests(input_api, output_api)
\ No newline at end of file
diff --git a/third_party/blink/renderer/build/scripts/json5_generator.py b/third_party/blink/renderer/build/scripts/json5_generator.py
index 2b8cd75..7adff45 100644
--- a/third_party/blink/renderer/build/scripts/json5_generator.py
+++ b/third_party/blink/renderer/build/scripts/json5_generator.py
@@ -21,14 +21,17 @@
   parameters: {
     param1: {default: 1, valid_values:[1,2,3]},
     param2: {valid_type: "str"},
+    param3: {valid_keys:["a", "b"], valid_values:["x", "y"]}
   },
   data: {
     "simple_item": {},
-    "item": {param1:1, param2: "Hello World"},
+    "item": {param1:1, param2: "Hello World", param3:{"a":"x", "b":"y"}},
+    "also_valid_item": {param2: "valid", param3: "x"}
     "bad_item_fails_validation": {
       name: "bad_item_fails_validation",
       param1: "bad_value_fails_valid_values_check",
       param2: 1.9,
+      param3: {"bad": "value"}
       unknown_param_fails_validation: true,
     },
   },
@@ -92,10 +95,15 @@
         _merge_dict("data")
 
 
-def _is_valid(valid_values, value):
+def _is_valid(valid_values, value, valid_keys=None):
     if type(value) == str and all([type(i) == str for i in valid_values]):
         return any([(value == valid) or (re.match("^" + valid + "$", value) is not None)
                     for valid in valid_values])
+    elif isinstance(value, dict):
+        assert valid_keys, "'valid_keys' must be declared when using a dict value"
+        return all([(key in valid_keys or key == "default")
+                    and (val in valid_values or val == "")
+                    for key, val in value.iteritems()])
     else:
         return value in valid_values
 
@@ -188,6 +196,7 @@
         valid_values = parameter.get("valid_values")
         if not valid_values:
             return
+        valid_keys = parameter.get("valid_keys")
         # If valid_values is a list of simple items and not list of list, then
         # validate each item in the value list against valid_values.
         if valid_type == "list" and type(valid_values[0]) is not list:
@@ -195,9 +204,13 @@
                 if not _is_valid(valid_values, item):
                     raise Exception("Unknown value: '%s'\nValid values: %s, \
                         Please change your value to a valid value" % (item, valid_values))
-        elif not _is_valid(valid_values, value):
-            raise Exception("Unknown value: '%s'\nValid values: %s, \
-                Please change your value to a valid value" % (value, valid_values))
+        elif not _is_valid(valid_values, value, valid_keys):
+            message = "Unknown value: '%s'\nValid values: %s, \
+                Please change your value to a valid value" % (value, valid_values)
+            if isinstance(value, dict):
+                message = "Unknown key or value in: %s\nPlease choose your keys and values from the list below:\n \
+                Valid keys: %s\nValid values: %s" % (value, valid_keys, valid_values)
+            raise Exception(message)
 
     def merge_from(self, doc):
         self._process(doc)
diff --git a/third_party/blink/renderer/build/scripts/json5_generator_unittest.py b/third_party/blink/renderer/build/scripts/json5_generator_unittest.py
new file mode 100644
index 0000000..888ce91
--- /dev/null
+++ b/third_party/blink/renderer/build/scripts/json5_generator_unittest.py
@@ -0,0 +1,40 @@
+# 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.
+
+import os
+import unittest
+
+from json5_generator import Json5File
+
+
+class Json5FileTest(unittest.TestCase):
+    def path_of_test_file(self, file_name):
+        return os.path.join(
+            os.path.dirname(os.path.realpath(__file__)), 'tests', file_name)
+
+    def test_valid_dict_value_parse(self):
+        actual = Json5File.load_from_files([self.path_of_test_file(
+            'json5_generator_valid_dict_value.json5')]).name_dictionaries
+        expected = [
+            {'name': 'item1', 'param1': {'keys': 'valid', 'random': 'values'}},
+            {'name': 'item2', 'param1': {'random': 'values', 'default': 'valid'}}
+        ]
+        self.assertEqual(len(actual), len(expected))
+        for exp, act in zip(expected, actual):
+            self.assertDictEqual(exp['param1'], act['param1'])
+
+    def test_no_valid_keys(self):
+        with self.assertRaises(AssertionError):
+            Json5File.load_from_files([self.path_of_test_file('json5_generator_no_valid_keys.json5')])
+
+    def test_value_not_in_valid_values(self):
+        with self.assertRaises(Exception):
+            Json5File.load_from_files([self.path_of_test_file('json5_generator_invalid_value.json5')])
+
+    def test_key_not_in_valid_keys(self):
+        with self.assertRaises(Exception):
+            Json5File.load_from_files([self.path_of_test_file('json5_generator_invalid_key.json5')])
+
+if __name__ == "__main__":
+    unittest.main()
diff --git a/third_party/blink/renderer/build/scripts/make_runtime_features.py b/third_party/blink/renderer/build/scripts/make_runtime_features.py
index a17e488..ad557b5f 100755
--- a/third_party/blink/renderer/build/scripts/make_runtime_features.py
+++ b/third_party/blink/renderer/build/scripts/make_runtime_features.py
@@ -27,6 +27,7 @@
 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
+import copy
 import sys
 
 from blinkbuild.name_style_converter import NameStyleConverter
@@ -57,6 +58,12 @@
             for dependant_name in feature['depends_on']:
                 enabled_condition += ' && ' + self._data_member_name(dependant_name)
             feature['enabled_condition'] = enabled_condition
+            # If 'status' is a dict, add the values for all the not-mentioned platforms too.
+            if isinstance(feature['status'], dict):
+                feature['status'] = self._status_with_all_platforms(feature['status'])
+            # Specify the type of status
+            feature['status_type'] = "dict" if isinstance(feature['status'], dict) else "str"
+
         self._standard_features = [feature for feature in self._features if not feature['custom']]
         self._origin_trial_features = [feature for feature in self._features if feature['origin_trial_feature_name']]
         self._header_guard = self.make_header_guard(self._relative_output_dir + self.file_basename + '.h')
@@ -71,10 +78,25 @@
         # which is how we're referring to them in this generator.
         return self.json5_file.parameters['status']['valid_values']
 
+    def _status_with_all_platforms(self, status):
+        new_status = copy.deepcopy(status)
+        default = new_status['default'] if 'default' in new_status else ''
+        new_status['default'] = default
+        for platform in self._platforms():
+            if platform not in new_status:
+                new_status[platform] = default
+        return new_status
+
+    def _platforms(self):
+        # Remove all occurrences of 'default' from 'valid_keys'
+        platforms = self.json5_file.parameters['status']['valid_keys']
+        return [platform for platform in platforms if platform != 'default']
+
     def _template_inputs(self):
         return {
             'features': self._features,
             'feature_sets': self._feature_sets(),
+            'platforms': self._platforms(),
             'input_files': self._input_files,
             'standard_features': self._standard_features,
             'origin_trial_controlled_features': self._origin_trial_features,
diff --git a/third_party/blink/renderer/build/scripts/templates/runtime_enabled_features.cc.tmpl b/third_party/blink/renderer/build/scripts/templates/runtime_enabled_features.cc.tmpl
index a425ca6..f2b3908 100644
--- a/third_party/blink/renderer/build/scripts/templates/runtime_enabled_features.cc.tmpl
+++ b/third_party/blink/renderer/build/scripts/templates/runtime_enabled_features.cc.tmpl
@@ -3,6 +3,8 @@
 
 {{source_files_for_generated_file(template_file, input_files)}}
 
+#include "build/build_config.h"
+
 #include "third_party/blink/renderer/platform/runtime_enabled_features.h"
 
 #include "third_party/blink/renderer/platform/wtf/assertions.h"
@@ -29,9 +31,30 @@
 
 {% for feature_set in feature_sets %}
 void RuntimeEnabledFeatures::Set{{feature_set|capitalize}}FeaturesEnabled(bool enable) {
-  {% for feature in features if feature.status == feature_set %}
+  {% for feature in features if feature.status_type == 'str' and feature.status == feature_set %}
   Set{{feature.name}}Enabled(enable);
   {% endfor %}
+
+  // Platform-dependent features
+  {% for platform in platforms %}
+#if defined(OS_{{platform | upper}})
+  {% for feature in features if feature.status_type == 'dict' and feature.status[platform] == feature_set %}
+  Set{{feature.name}}Enabled(enable);
+  {% endfor %}
+#endif
+
+  {% endfor %}
+  // Default values for platforms not specifically handled above
+#if
+  {%- for platform in platforms %}
+  {%- if not loop.first %} &&{% endif %}
+ !defined(OS_{{platform | upper}})
+  {%- endfor %}
+
+  {% for feature in features if feature.status_type == 'dict' and feature.status['default'] == feature_set %}
+  Set{{feature.name}}Enabled(enable);
+  {% endfor %}
+#endif
 }
 
 {% endfor %}
@@ -62,7 +85,34 @@
 }
 
 {% for feature in standard_features %}
+{% if feature.status_type == 'str' %}
 bool RuntimeEnabledFeatures::{{feature.data_member_name}} = {{'true' if feature.status == 'stable' else 'false'}};
+{% endif %}
 {% endfor %}
 
+// Platform-dependent features
+{% for platform in platforms %}
+#if defined(OS_{{platform | upper}})
+{% for feature in standard_features %}
+{% if feature.status_type == 'dict' %}
+bool RuntimeEnabledFeatures::{{feature.data_member_name}} = {{'true' if feature.status[platform] == 'stable' else 'false'}};
+{% endif %}
+{% endfor %}
+#endif
+
+{% endfor %}
+// Default values for platforms not specifically handled above
+#if
+{%- for platform in platforms %}
+{%- if not loop.first %} &&{% endif %}
+ !defined(OS_{{platform | upper}})
+{%- endfor %}
+
+{% for feature in standard_features %}
+{% if feature.status_type == 'dict' %}
+bool RuntimeEnabledFeatures::{{feature.data_member_name}} = {{'true' if feature.status['default'] == 'stable' else 'false'}};
+{% endif %}
+{% endfor %}
+#endif
+
 } // namespace blink
diff --git a/third_party/blink/renderer/build/scripts/tests/json5_generator_invalid_key.json5 b/third_party/blink/renderer/build/scripts/tests/json5_generator_invalid_key.json5
new file mode 100644
index 0000000..0411bae7
--- /dev/null
+++ b/third_party/blink/renderer/build/scripts/tests/json5_generator_invalid_key.json5
@@ -0,0 +1,15 @@
+{
+  parameters: {
+    param1: {
+      valid_values: ["valid", "values"],
+      valid_keys: ["random", "keys"],
+    }
+  },
+
+  data: [
+    {
+      name: "item1",
+      param1: {"not_valid_key": "valid", "random": "values"},
+    },
+  ],
+}
\ No newline at end of file
diff --git a/third_party/blink/renderer/build/scripts/tests/json5_generator_invalid_value.json5 b/third_party/blink/renderer/build/scripts/tests/json5_generator_invalid_value.json5
new file mode 100644
index 0000000..dac81d7
--- /dev/null
+++ b/third_party/blink/renderer/build/scripts/tests/json5_generator_invalid_value.json5
@@ -0,0 +1,15 @@
+{
+  parameters: {
+    param1: {
+      valid_values: ["valid", "values"],
+      valid_keys: ["random", "keys"],
+    }
+  },
+
+  data: [
+    {
+      name: "item1",
+      param1: {"keys": "valid", "random": "not_valid"},
+    },
+  ],
+}
\ No newline at end of file
diff --git a/third_party/blink/renderer/build/scripts/tests/json5_generator_no_valid_keys.json5 b/third_party/blink/renderer/build/scripts/tests/json5_generator_no_valid_keys.json5
new file mode 100644
index 0000000..e24aef8
--- /dev/null
+++ b/third_party/blink/renderer/build/scripts/tests/json5_generator_no_valid_keys.json5
@@ -0,0 +1,14 @@
+{
+  parameters: {
+    param1: {
+      valid_values: ["valid", "values"],
+    }
+  },
+
+  data: [
+    {
+      name: "item1",
+      param1: {"default": "valid"},
+    },
+  ],
+}
\ No newline at end of file
diff --git a/third_party/blink/renderer/build/scripts/tests/json5_generator_valid_dict_value.json5 b/third_party/blink/renderer/build/scripts/tests/json5_generator_valid_dict_value.json5
new file mode 100644
index 0000000..d3a12b4c
--- /dev/null
+++ b/third_party/blink/renderer/build/scripts/tests/json5_generator_valid_dict_value.json5
@@ -0,0 +1,19 @@
+{
+  parameters: {
+    param1: {
+      valid_values: ["valid", "values"],
+      valid_keys: ["random", "keys"],
+    }
+  },
+
+  data: [
+    {
+      name: "item1",
+      param1: {"keys": "valid", "random": "values"},
+    },
+    {
+      name: "item2",
+      param1: {"random": "values", "default": "valid"},
+    },
+  ],
+}
\ No newline at end of file
diff --git a/third_party/blink/renderer/controller/blink_leak_detector.cc b/third_party/blink/renderer/controller/blink_leak_detector.cc
index a5837cc..912703e 100644
--- a/third_party/blink/renderer/controller/blink_leak_detector.cc
+++ b/third_party/blink/renderer/controller/blink_leak_detector.cc
@@ -122,8 +122,9 @@
       InstanceCounters::CounterValue(InstanceCounters::kLayoutObjectCounter);
   result->number_of_live_resources =
       InstanceCounters::CounterValue(InstanceCounters::kResourceCounter);
-  result->number_of_live_pausable_objects =
-      InstanceCounters::CounterValue(InstanceCounters::kPausableObjectCounter);
+  result->number_of_live_context_lifecycle_state_observers =
+      InstanceCounters::CounterValue(
+          InstanceCounters::kContextLifecycleStateObserverCounter);
   result->number_of_live_script_promises =
       InstanceCounters::CounterValue(InstanceCounters::kScriptPromiseCounter);
   result->number_of_live_frames =
diff --git a/third_party/blink/renderer/core/BUILD.gn b/third_party/blink/renderer/core/BUILD.gn
index 1f6a622..97cba9c 100644
--- a/third_party/blink/renderer/core/BUILD.gn
+++ b/third_party/blink/renderer/core/BUILD.gn
@@ -1837,7 +1837,7 @@
     "events/pointer_event_factory_test.cc",
     "events/touch_event_test.cc",
     "events/web_input_event_conversion_test.cc",
-    "execution_context/pausable_object_test.cc",
+    "execution_context/context_lifecycle_state_observer_test.cc",
     "exported/local_frame_client_impl_test.cc",
     "exported/prerendering_test.cc",
     "exported/web_associated_url_loader_impl_test.cc",
diff --git a/third_party/blink/renderer/core/dom/document.cc b/third_party/blink/renderer/core/dom/document.cc
index 66d4ec0..88c0cdc 100644
--- a/third_party/blink/renderer/core/dom/document.cc
+++ b/third_party/blink/renderer/core/dom/document.cc
@@ -2844,7 +2844,7 @@
 
   probe::documentDetached(this);
 
-  // FIXME: consider using PausableObject.
+  // FIXME: consider using ContextLifecycleStateObserver.
   if (scripted_animation_controller_)
     scripted_animation_controller_->ClearDocumentPointer();
   scripted_animation_controller_.Clear();
@@ -7045,7 +7045,8 @@
     // don't have an attached frame and if execution context is destroyed.
     if (!frame_ || !frame_->IsAttached() ||
         ExecutionContext::IsContextDestroyed()) {
-      scripted_idle_task_controller_->ContextPaused(PauseState::kFrozen);
+      scripted_idle_task_controller_->ContextLifecycleStateChanged(
+          mojom::FrameLifecycleState::kFrozen);
     }
   }
   return *scripted_idle_task_controller_;
diff --git a/third_party/blink/renderer/core/dom/events/event_target.h b/third_party/blink/renderer/core/dom/events/event_target.h
index 7fb13b5..99d09ed 100644
--- a/third_party/blink/renderer/core/dom/events/event_target.h
+++ b/third_party/blink/renderer/core/dom/events/event_target.h
@@ -108,8 +108,8 @@
 //   file.
 // - Override EventTarget::interfaceName() and getExecutionContext(). The former
 //   will typically return EventTargetNames::YourClassName. The latter will
-//   return PausableObject::executionContext (if you are an
-//   PausableObject)
+//   return ContextLifecycleObserver::executionContext (if you are an
+//   ContextLifecycleObserver)
 //   or the document you're in.
 // - Your trace() method will need to call EventTargetWithInlineData::trace
 //   depending on the base class of your class.
diff --git a/third_party/blink/renderer/core/dom/scripted_idle_task_controller.cc b/third_party/blink/renderer/core/dom/scripted_idle_task_controller.cc
index 5a9aac8..e2463b8 100644
--- a/third_party/blink/renderer/core/dom/scripted_idle_task_controller.cc
+++ b/third_party/blink/renderer/core/dom/scripted_idle_task_controller.cc
@@ -90,18 +90,16 @@
 
 ScriptedIdleTaskController::ScriptedIdleTaskController(
     ExecutionContext* context)
-    : PausableObject(context),
+    : ContextLifecycleStateObserver(context),
       scheduler_(ThreadScheduler::Current()),
       next_callback_id_(0),
-      paused_(false) {
-  PauseIfNeeded();
-}
+      paused_(false) {}
 
 ScriptedIdleTaskController::~ScriptedIdleTaskController() = default;
 
 void ScriptedIdleTaskController::Trace(Visitor* visitor) {
   visitor->Trace(idle_tasks_);
-  PausableObject::Trace(visitor);
+  ContextLifecycleStateObserver::Trace(visitor);
 }
 
 int ScriptedIdleTaskController::NextCallbackId() {
@@ -226,7 +224,15 @@
   idle_tasks_.clear();
 }
 
-void ScriptedIdleTaskController::ContextPaused(PauseState) {
+void ScriptedIdleTaskController::ContextLifecycleStateChanged(
+    mojom::FrameLifecycleState state) {
+  if (state != mojom::FrameLifecycleState::kRunning)
+    ContextPaused();
+  else
+    ContextUnpaused();
+}
+
+void ScriptedIdleTaskController::ContextPaused() {
   paused_ = true;
 }
 
diff --git a/third_party/blink/renderer/core/dom/scripted_idle_task_controller.h b/third_party/blink/renderer/core/dom/scripted_idle_task_controller.h
index 8d347bdd..78cdd3e5 100644
--- a/third_party/blink/renderer/core/dom/scripted_idle_task_controller.h
+++ b/third_party/blink/renderer/core/dom/scripted_idle_task_controller.h
@@ -7,7 +7,7 @@
 
 #include "third_party/blink/renderer/bindings/core/v8/v8_idle_request_callback.h"
 #include "third_party/blink/renderer/core/dom/idle_deadline.h"
-#include "third_party/blink/renderer/core/execution_context/pausable_object.h"
+#include "third_party/blink/renderer/core/execution_context/context_lifecycle_state_observer.h"
 #include "third_party/blink/renderer/platform/bindings/name_client.h"
 #include "third_party/blink/renderer/platform/bindings/trace_wrapper_member.h"
 #include "third_party/blink/renderer/platform/heap/handle.h"
@@ -25,13 +25,16 @@
 
 class CORE_EXPORT ScriptedIdleTaskController
     : public GarbageCollectedFinalized<ScriptedIdleTaskController>,
-      public PausableObject,
+      public ContextLifecycleStateObserver,
       public NameClient {
   USING_GARBAGE_COLLECTED_MIXIN(ScriptedIdleTaskController);
 
  public:
   static ScriptedIdleTaskController* Create(ExecutionContext* context) {
-    return MakeGarbageCollected<ScriptedIdleTaskController>(context);
+    ScriptedIdleTaskController* controller =
+        MakeGarbageCollected<ScriptedIdleTaskController>(context);
+    controller->UpdateStateIfNeeded();
+    return controller;
   }
 
   explicit ScriptedIdleTaskController(ExecutionContext*);
@@ -76,10 +79,9 @@
   int RegisterCallback(IdleTask*, const IdleRequestOptions*);
   void CancelCallback(CallbackId);
 
-  // PausableObject interface.
+  // ContextLifecycleStateObserver interface.
   void ContextDestroyed(ExecutionContext*) override;
-  void ContextPaused(PauseState) override;
-  void ContextUnpaused() override;
+  void ContextLifecycleStateChanged(mojom::FrameLifecycleState) override;
 
   void CallbackFired(CallbackId,
                      TimeTicks deadline,
@@ -88,6 +90,8 @@
  private:
   friend class internal::IdleRequestCallbackWrapper;
 
+  void ContextPaused();
+  void ContextUnpaused();
   void ScheduleCallback(scoped_refptr<internal::IdleRequestCallbackWrapper>,
                         long long timeout_millis);
 
diff --git a/third_party/blink/renderer/core/execution_context/BUILD.gn b/third_party/blink/renderer/core/execution_context/BUILD.gn
index c14e9ed..1edcdfd 100644
--- a/third_party/blink/renderer/core/execution_context/BUILD.gn
+++ b/third_party/blink/renderer/core/execution_context/BUILD.gn
@@ -10,11 +10,10 @@
     "context_lifecycle_notifier.h",
     "context_lifecycle_observer.cc",
     "context_lifecycle_observer.h",
+    "context_lifecycle_state_observer.cc",
+    "context_lifecycle_state_observer.h",
     "execution_context.cc",
     "execution_context.h",
-    "pausable_object.cc",
-    "pausable_object.h",
-    "pause_state.h",
     "remote_security_context.cc",
     "remote_security_context.h",
     "security_context.cc",
diff --git a/third_party/blink/renderer/core/execution_context/context_lifecycle_notifier.cc b/third_party/blink/renderer/core/execution_context/context_lifecycle_notifier.cc
index 471375a..187b7f5 100644
--- a/third_party/blink/renderer/core/execution_context/context_lifecycle_notifier.cc
+++ b/third_party/blink/renderer/core/execution_context/context_lifecycle_notifier.cc
@@ -28,45 +28,30 @@
 #include "third_party/blink/renderer/core/execution_context/context_lifecycle_notifier.h"
 
 #include "base/auto_reset.h"
-#include "third_party/blink/renderer/core/execution_context/pausable_object.h"
+#include "third_party/blink/renderer/core/execution_context/context_lifecycle_state_observer.h"
 
 namespace blink {
 
-void ContextLifecycleNotifier::NotifyResumingPausableObjects() {
+void ContextLifecycleNotifier::NotifyContextLifecycleStateChanged(
+    mojom::FrameLifecycleState state) {
   ForEachObserver([&](ContextLifecycleObserver* observer) {
-    if (observer->ObserverType() !=
-        ContextLifecycleObserver::kPausableObjectType)
+    if (observer->ObserverType() != ContextLifecycleObserver::kStateObjectType)
       return;
-    PausableObject* pausable_object = static_cast<PausableObject*>(observer);
+    ContextLifecycleStateObserver* state_observer =
+        static_cast<ContextLifecycleStateObserver*>(observer);
 #if DCHECK_IS_ON()
-    DCHECK_EQ(pausable_object->GetExecutionContext(), Context());
-    DCHECK(pausable_object->PauseIfNeededCalled());
+    DCHECK_EQ(state_observer->GetExecutionContext(), Context());
+    DCHECK(state_observer->UpdateStateIfNeededCalled());
 #endif
-    pausable_object->ContextUnpaused();
+    state_observer->ContextLifecycleStateChanged(state);
   });
 }
 
-void ContextLifecycleNotifier::NotifySuspendingPausableObjects(
-    PauseState state) {
-  ForEachObserver([&](ContextLifecycleObserver* observer) {
-    if (observer->ObserverType() !=
-        ContextLifecycleObserver::kPausableObjectType)
-      return;
-    PausableObject* pausable_object = static_cast<PausableObject*>(observer);
-#if DCHECK_IS_ON()
-    DCHECK_EQ(pausable_object->GetExecutionContext(), Context());
-    DCHECK(pausable_object->PauseIfNeededCalled());
-#endif
-    pausable_object->ContextPaused(state);
-  });
-}
-
-unsigned ContextLifecycleNotifier::PausableObjectCount() const {
+unsigned ContextLifecycleNotifier::ContextLifecycleStateObserverCount() const {
   DCHECK(!IsIteratingOverObservers());
   unsigned pausable_objects = 0;
   ForEachObserver([&](ContextLifecycleObserver* observer) {
-    if (observer->ObserverType() !=
-        ContextLifecycleObserver::kPausableObjectType)
+    if (observer->ObserverType() != ContextLifecycleObserver::kStateObjectType)
       return;
     pausable_objects++;
   });
@@ -74,15 +59,16 @@
 }
 
 #if DCHECK_IS_ON()
-bool ContextLifecycleNotifier::Contains(PausableObject* object) const {
+bool ContextLifecycleNotifier::Contains(
+    ContextLifecycleStateObserver* object) const {
   DCHECK(!IsIteratingOverObservers());
   bool found = false;
   ForEachObserver([&](ContextLifecycleObserver* observer) {
-    if (observer->ObserverType() !=
-        ContextLifecycleObserver::kPausableObjectType)
+    if (observer->ObserverType() != ContextLifecycleObserver::kStateObjectType)
       return;
-    PausableObject* pausable_object = static_cast<PausableObject*>(observer);
-    if (pausable_object == object)
+    ContextLifecycleStateObserver* state_observer =
+        static_cast<ContextLifecycleStateObserver*>(observer);
+    if (state_observer == object)
       found = true;
   });
   return found;
diff --git a/third_party/blink/renderer/core/execution_context/context_lifecycle_notifier.h b/third_party/blink/renderer/core/execution_context/context_lifecycle_notifier.h
index ce0ce8e..d4501ab 100644
--- a/third_party/blink/renderer/core/execution_context/context_lifecycle_notifier.h
+++ b/third_party/blink/renderer/core/execution_context/context_lifecycle_notifier.h
@@ -29,24 +29,26 @@
 #define THIRD_PARTY_BLINK_RENDERER_CORE_EXECUTION_CONTEXT_CONTEXT_LIFECYCLE_NOTIFIER_H_
 
 #include "base/macros.h"
+#include "third_party/blink/public/mojom/frame/lifecycle.mojom-blink.h"
 #include "third_party/blink/renderer/core/core_export.h"
-#include "third_party/blink/renderer/core/execution_context/pause_state.h"
 #include "third_party/blink/renderer/platform/lifecycle_notifier.h"
 
 namespace blink {
 
 class ContextLifecycleObserver;
+class ContextLifecycleStateObserver;
 class ExecutionContext;
-class PausableObject;
 
 class CORE_EXPORT ContextLifecycleNotifier
     : public LifecycleNotifier<ExecutionContext, ContextLifecycleObserver> {
  public:
-  void NotifyResumingPausableObjects();
-  void NotifySuspendingPausableObjects(PauseState state);
+  void NotifyContextLifecycleStateChanged(mojom::FrameLifecycleState state);
 
-  unsigned PausableObjectCount() const;
+  unsigned ContextLifecycleStateObserverCount() const;
 
+#if DCHECK_IS_ON()
+  bool Contains(ContextLifecycleStateObserver*) const;
+#endif
  protected:
   // Need a default constructor to link core and modules separately.
   // If no default constructor, we will see an error: "constructor for
@@ -55,9 +57,6 @@
   // constructor ExecutionContext::ExecutionContext()".
   ContextLifecycleNotifier() = default;
 
-#if DCHECK_IS_ON()
-  bool Contains(PausableObject*) const;
-#endif
   DISALLOW_COPY_AND_ASSIGN(ContextLifecycleNotifier);
 };
 
diff --git a/third_party/blink/renderer/core/execution_context/context_lifecycle_observer.h b/third_party/blink/renderer/core/execution_context/context_lifecycle_observer.h
index 3aa3a9d7..58576ba 100644
--- a/third_party/blink/renderer/core/execution_context/context_lifecycle_observer.h
+++ b/third_party/blink/renderer/core/execution_context/context_lifecycle_observer.h
@@ -54,8 +54,8 @@
 //   objects, it should be a PausableObject.
 // * If an object additionally must suspend its activity during pause (see
 //   context_lifecycle_state_observer.h), it should be a
-//   PausableObject (and thus, transitively, also a
-//   PausableObject).
+//   ContextLifecycleStateObserver (and thus, transitively, also a
+//   ContextLifecycleObserver).
 //
 // If your object has activity which requires that it be kept alive, even if no
 // other object has a reference to it, consider whether your object should also
@@ -98,7 +98,7 @@
 //
 // If there is ongoing activity associated with the object, consider whether it
 // needs to be paused when execution is suspended (see
-// PausableObject).
+// ContextLifecycleStateObserver).
 //
 // If none of the above applies, prefer the simpler ContextClient.
 class CORE_EXPORT ContextLifecycleObserver
@@ -116,7 +116,7 @@
 
   enum Type {
     kGenericType,
-    kPausableObjectType,
+    kStateObjectType,
   };
 
   Type ObserverType() const { return observer_type_; }
diff --git a/third_party/blink/renderer/core/execution_context/pausable_object.cc b/third_party/blink/renderer/core/execution_context/context_lifecycle_state_observer.cc
similarity index 60%
rename from third_party/blink/renderer/core/execution_context/pausable_object.cc
rename to third_party/blink/renderer/core/execution_context/context_lifecycle_state_observer.cc
index 66616d5..811db206 100644
--- a/third_party/blink/renderer/core/execution_context/pausable_object.cc
+++ b/third_party/blink/renderer/core/execution_context/context_lifecycle_state_observer.cc
@@ -24,60 +24,54 @@
  *
  */
 
-#include "third_party/blink/renderer/core/execution_context/pausable_object.h"
+#include "third_party/blink/renderer/core/execution_context/context_lifecycle_state_observer.h"
 
 #include "third_party/blink/renderer/core/execution_context/execution_context.h"
 #include "third_party/blink/renderer/platform/instance_counters.h"
 
 namespace blink {
 
-PausableObject::PausableObject(ExecutionContext* execution_context)
-    : ContextLifecycleObserver(execution_context, kPausableObjectType)
-#if DCHECK_IS_ON()
-      ,
-      pause_if_needed_called_(false)
-#endif
-{
+ContextLifecycleStateObserver::ContextLifecycleStateObserver(
+    ExecutionContext* execution_context)
+    : ContextLifecycleObserver(execution_context, kStateObjectType) {
   DCHECK(!execution_context || execution_context->IsContextThread());
-  InstanceCounters::IncrementCounter(InstanceCounters::kPausableObjectCounter);
+  InstanceCounters::IncrementCounter(
+      InstanceCounters::kContextLifecycleStateObserverCounter);
 }
 
-PausableObject::~PausableObject() {
-  InstanceCounters::DecrementCounter(InstanceCounters::kPausableObjectCounter);
+ContextLifecycleStateObserver::~ContextLifecycleStateObserver() {
+  InstanceCounters::DecrementCounter(
+      InstanceCounters::kContextLifecycleStateObserverCounter);
 
 #if DCHECK_IS_ON()
-  DCHECK(pause_if_needed_called_);
+  DCHECK(update_state_if_needed_called_);
 #endif
 }
 
-void PausableObject::PauseIfNeeded() {
+void ContextLifecycleStateObserver::UpdateStateIfNeeded() {
 #if DCHECK_IS_ON()
-  DCHECK(!pause_if_needed_called_);
-  pause_if_needed_called_ = true;
+  DCHECK(!update_state_if_needed_called_);
+  update_state_if_needed_called_ = true;
 #endif
-  if (ExecutionContext* context = GetExecutionContext())
-    context->PausePausableObjectIfNeeded(this);
+  if (ExecutionContext* context = GetExecutionContext()) {
+#if DCHECK_IS_ON()
+    DCHECK(context->Contains(this));
+#endif
+    mojom::FrameLifecycleState pause_state = context->ContextPauseState();
+    if (pause_state != mojom::FrameLifecycleState::kRunning)
+      ContextLifecycleStateChanged(pause_state);
+  }
 }
 
-void PausableObject::ContextPaused(PauseState) {}
-
-void PausableObject::ContextUnpaused() {}
-
-void PausableObject::DidMoveToNewExecutionContext(ExecutionContext* context) {
+void ContextLifecycleStateObserver::DidMoveToNewExecutionContext(
+    ExecutionContext* context) {
   SetContext(context);
 
   if (context->IsContextDestroyed()) {
     ContextDestroyed(context);
     return;
   }
-
-  base::Optional<PauseState> pause_state = context->ContextPauseState();
-  if (pause_state) {
-    ContextPaused(pause_state.value());
-    return;
-  }
-
-  ContextUnpaused();
+  ContextLifecycleStateChanged(context->ContextPauseState());
 }
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/execution_context/pausable_object.h b/third_party/blink/renderer/core/execution_context/context_lifecycle_state_observer.h
similarity index 62%
rename from third_party/blink/renderer/core/execution_context/pausable_object.h
rename to third_party/blink/renderer/core/execution_context/context_lifecycle_state_observer.h
index 91518f5..86a067e 100644
--- a/third_party/blink/renderer/core/execution_context/pausable_object.h
+++ b/third_party/blink/renderer/core/execution_context/context_lifecycle_state_observer.h
@@ -24,60 +24,62 @@
  *
  */
 
-#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_EXECUTION_CONTEXT_PAUSABLE_OBJECT_H_
-#define THIRD_PARTY_BLINK_RENDERER_CORE_EXECUTION_CONTEXT_PAUSABLE_OBJECT_H_
+#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_EXECUTION_CONTEXT_CONTEXT_LIFECYCLE_STATE_OBSERVER_H_
+#define THIRD_PARTY_BLINK_RENDERER_CORE_EXECUTION_CONTEXT_CONTEXT_LIFECYCLE_STATE_OBSERVER_H_
 
+#include "third_party/blink/public/mojom/frame/lifecycle.mojom-blink.h"
 #include "third_party/blink/renderer/core/core_export.h"
 #include "third_party/blink/renderer/core/execution_context/context_lifecycle_observer.h"
 #include "third_party/blink/renderer/platform/wtf/assertions.h"
 
 namespace blink {
 
-// A PausableObject responds to situations where Blink is running a nested event
-// loop. At such times, the page should be responsive, but only in a limited
-// sense: the browser should redraw the page as necessary, but should not run
-// timer callbacks, finish promise resolution, fire events, or perform other
-// activity, especially activity which may run script.
+// A ContextLifecycleStateObserver responds to situations where Blink is
+// pausing a context or freezing a frame.
 //
-// Pausing can happen in cases such as:
+// Context lifecycle state changes can happen in cases such as:
 // - modal dialogs during script execution (e.g. window.alert, window.print)
 // - script execution stopped at a debugger breakpoint
+// - frozen contexts (resource coordinator background tasks, iframe freezing)
 //
 // The scheduler will automatically suspend certain task queues for the duration
 // that the page is paused.
 //
 // Objects with asynchronous activity, especially activity that may have an
 // observable effect on web-visible state, on should suspend that activity while
-// the page is paused by overriding ContextPaused() and ContextUnpaused().
+// the page is paused by overriding ContextLifecycleStateChanged().
 //
 // https://html.spec.whatwg.org/multipage/webappapis.html#pause
-class CORE_EXPORT PausableObject : public ContextLifecycleObserver {
+// https://wicg.github.io/page-lifecycle/spec.html
+class CORE_EXPORT ContextLifecycleStateObserver
+    : public ContextLifecycleObserver {
  public:
-  explicit PausableObject(ExecutionContext*);
+  explicit ContextLifecycleStateObserver(ExecutionContext*);
 
-  // PauseIfNeeded() should be called exactly once after object construction
-  // to synchronize the suspend state with that in ExecutionContext.
-  void PauseIfNeeded();
+  // UpdateStateIfNeeded() should be called exactly once after object
+  // construction to synchronize the suspend state with that in
+  // ExecutionContext.
+  void UpdateStateIfNeeded();
 #if DCHECK_IS_ON()
-  bool PauseIfNeededCalled() const { return pause_if_needed_called_; }
+  bool UpdateStateIfNeededCalled() const {
+    return update_state_if_needed_called_;
+  }
 #endif
 
-  // These methods have an empty default implementation so that subclasses
-  // which don't need special treatment can skip implementation.
-  virtual void ContextPaused(PauseState);
-  virtual void ContextUnpaused();
+  virtual void ContextLifecycleStateChanged(
+      mojom::FrameLifecycleState state) = 0;
 
   void DidMoveToNewExecutionContext(ExecutionContext*);
 
  protected:
-  virtual ~PausableObject();
+  virtual ~ContextLifecycleStateObserver();
 
  private:
 #if DCHECK_IS_ON()
-  bool pause_if_needed_called_;
+  bool update_state_if_needed_called_ = false;
 #endif
 };
 
 }  // namespace blink
 
-#endif  // THIRD_PARTY_BLINK_RENDERER_CORE_EXECUTION_CONTEXT_PAUSABLE_OBJECT_H_
+#endif  // THIRD_PARTY_BLINK_RENDERER_CORE_EXECUTION_CONTEXT_CONTEXT_LIFECYCLE_STATE_OBSERVER_H_
diff --git a/third_party/blink/renderer/core/execution_context/context_lifecycle_state_observer_test.cc b/third_party/blink/renderer/core/execution_context/context_lifecycle_state_observer_test.cc
new file mode 100644
index 0000000..8a5f827
--- /dev/null
+++ b/third_party/blink/renderer/core/execution_context/context_lifecycle_state_observer_test.cc
@@ -0,0 +1,117 @@
+/*
+ * Copyright (c) 2014, Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "third_party/blink/renderer/core/execution_context/context_lifecycle_state_observer.h"
+
+#include <memory>
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/blink/renderer/core/dom/document.h"
+#include "third_party/blink/renderer/core/testing/dummy_page_holder.h"
+
+namespace blink {
+
+class MockContextLifecycleStateObserver final
+    : public GarbageCollectedFinalized<MockContextLifecycleStateObserver>,
+      public ContextLifecycleStateObserver {
+  USING_GARBAGE_COLLECTED_MIXIN(MockContextLifecycleStateObserver);
+
+ public:
+  explicit MockContextLifecycleStateObserver(ExecutionContext* context)
+      : ContextLifecycleStateObserver(context) {}
+
+  void Trace(blink::Visitor* visitor) override {
+    ContextLifecycleStateObserver::Trace(visitor);
+  }
+
+  MOCK_METHOD1(ContextLifecycleStateChanged, void(mojom::FrameLifecycleState));
+  MOCK_METHOD1(ContextDestroyed, void(ExecutionContext*));
+};
+
+class ContextLifecycleStateObserverTest : public testing::Test {
+ protected:
+  ContextLifecycleStateObserverTest();
+
+  Document& SrcDocument() const { return src_page_holder_->GetDocument(); }
+  Document& DestDocument() const { return dest_page_holder_->GetDocument(); }
+  MockContextLifecycleStateObserver& Observer() { return *observer_; }
+
+ private:
+  std::unique_ptr<DummyPageHolder> src_page_holder_;
+  std::unique_ptr<DummyPageHolder> dest_page_holder_;
+  Persistent<MockContextLifecycleStateObserver> observer_;
+};
+
+ContextLifecycleStateObserverTest::ContextLifecycleStateObserverTest()
+    : src_page_holder_(DummyPageHolder::Create(IntSize(800, 600))),
+      dest_page_holder_(DummyPageHolder::Create(IntSize(800, 600))),
+      observer_(MakeGarbageCollected<MockContextLifecycleStateObserver>(
+          &src_page_holder_->GetDocument())) {
+  observer_->UpdateStateIfNeeded();
+}
+
+TEST_F(ContextLifecycleStateObserverTest, NewContextObserved) {
+  unsigned initial_src_count =
+      SrcDocument().ContextLifecycleStateObserverCount();
+  unsigned initial_dest_count =
+      DestDocument().ContextLifecycleStateObserverCount();
+
+  EXPECT_CALL(Observer(), ContextLifecycleStateChanged(
+                              mojom::FrameLifecycleState::kRunning));
+  Observer().DidMoveToNewExecutionContext(&DestDocument());
+
+  EXPECT_EQ(initial_src_count - 1,
+            SrcDocument().ContextLifecycleStateObserverCount());
+  EXPECT_EQ(initial_dest_count + 1,
+            DestDocument().ContextLifecycleStateObserverCount());
+}
+
+TEST_F(ContextLifecycleStateObserverTest, MoveToActiveDocument) {
+  EXPECT_CALL(Observer(), ContextLifecycleStateChanged(
+                              mojom::FrameLifecycleState::kRunning));
+  Observer().DidMoveToNewExecutionContext(&DestDocument());
+}
+
+TEST_F(ContextLifecycleStateObserverTest, MoveToSuspendedDocument) {
+  DestDocument().SetLifecycleState(mojom::FrameLifecycleState::kFrozen);
+
+  EXPECT_CALL(Observer(), ContextLifecycleStateChanged(
+                              mojom::FrameLifecycleState::kFrozen));
+  Observer().DidMoveToNewExecutionContext(&DestDocument());
+}
+
+TEST_F(ContextLifecycleStateObserverTest, MoveToStoppedDocument) {
+  DestDocument().Shutdown();
+
+  EXPECT_CALL(Observer(), ContextDestroyed(&DestDocument()));
+  Observer().DidMoveToNewExecutionContext(&DestDocument());
+}
+
+}  // namespace blink
diff --git a/third_party/blink/renderer/core/execution_context/execution_context.cc b/third_party/blink/renderer/core/execution_context/execution_context.cc
index 601da87..4cc9282 100644
--- a/third_party/blink/renderer/core/execution_context/execution_context.cc
+++ b/third_party/blink/renderer/core/execution_context/execution_context.cc
@@ -32,7 +32,7 @@
 #include "third_party/blink/renderer/bindings/core/v8/v8_binding_for_core.h"
 #include "third_party/blink/renderer/core/dom/events/event_target.h"
 #include "third_party/blink/renderer/core/events/error_event.h"
-#include "third_party/blink/renderer/core/execution_context/pausable_object.h"
+#include "third_party/blink/renderer/core/execution_context/context_lifecycle_state_observer.h"
 #include "third_party/blink/renderer/core/fileapi/public_url_manager.h"
 #include "third_party/blink/renderer/core/frame/csp/execution_context_csp_delegate.h"
 #include "third_party/blink/renderer/core/frame/use_counter.h"
@@ -77,16 +77,19 @@
   return ToExecutionContext(info.Holder()->CreationContext());
 }
 
-void ExecutionContext::PausePausableObjects(PauseState state) {
-  DCHECK(!pause_state_);
-  pause_state_ = state;
-  NotifySuspendingPausableObjects(state);
-}
+void ExecutionContext::SetLifecycleState(mojom::FrameLifecycleState state) {
+  bool was_paused = lifecycle_state_ != mojom::FrameLifecycleState::kRunning;
+  lifecycle_state_ = state;
+  NotifyContextLifecycleStateChanged(state);
+  bool paused = lifecycle_state_ != mojom::FrameLifecycleState::kRunning;
 
-void ExecutionContext::UnpausePausableObjects() {
-  DCHECK(pause_state_.has_value());
-  pause_state_.reset();
-  NotifyResumingPausableObjects();
+  if (was_paused == paused)
+    return;
+
+  if (paused)
+    TasksWerePaused();
+  else
+    TasksWereUnpaused();
 }
 
 void ExecutionContext::NotifyContextDestroyed() {
@@ -95,25 +98,6 @@
   ContextLifecycleNotifier::NotifyContextDestroyed();
 }
 
-void ExecutionContext::PauseScheduledTasks(PauseState state) {
-  PausePausableObjects(state);
-  TasksWerePaused();
-}
-
-void ExecutionContext::UnpauseScheduledTasks() {
-  UnpausePausableObjects();
-  TasksWereUnpaused();
-}
-
-void ExecutionContext::PausePausableObjectIfNeeded(PausableObject* object) {
-#if DCHECK_IS_ON()
-  DCHECK(Contains(object));
-#endif
-  // Ensure all PausableObjects are paused also newly created ones.
-  if (pause_state_)
-    object->ContextPaused(pause_state_.value());
-}
-
 void ExecutionContext::DispatchErrorEvent(
     ErrorEvent* error_event,
     SanitizeScriptErrors sanitize_script_errors) {
diff --git a/third_party/blink/renderer/core/execution_context/execution_context.h b/third_party/blink/renderer/core/execution_context/execution_context.h
index 3e48309..01728a3 100644
--- a/third_party/blink/renderer/core/execution_context/execution_context.h
+++ b/third_party/blink/renderer/core/execution_context/execution_context.h
@@ -34,11 +34,11 @@
 #include "base/macros.h"
 #include "base/optional.h"
 #include "base/unguessable_token.h"
+#include "third_party/blink/public/mojom/frame/lifecycle.mojom-blink.h"
 #include "third_party/blink/renderer/bindings/core/v8/sanitize_script_errors.h"
 #include "third_party/blink/renderer/core/core_export.h"
 #include "third_party/blink/renderer/core/execution_context/context_lifecycle_notifier.h"
 #include "third_party/blink/renderer/core/execution_context/context_lifecycle_observer.h"
-#include "third_party/blink/renderer/core/execution_context/pause_state.h"
 #include "third_party/blink/renderer/core/loader/console_logger_impl_base.h"
 #include "third_party/blink/renderer/platform/heap/handle.h"
 #include "third_party/blink/renderer/platform/loader/fetch/https_state.h"
@@ -71,7 +71,6 @@
 class InterfaceInvalidator;
 class KURL;
 class LocalDOMWindow;
-class PausableObject;
 class PublicURLManager;
 class ResourceFetcher;
 class SecurityContext;
@@ -197,28 +196,23 @@
 
   virtual void RemoveURLFromMemoryCache(const KURL&);
 
-  void PausePausableObjects(PauseState);
-  void UnpausePausableObjects();
-  void StopPausableObjects();
+  void SetLifecycleState(mojom::FrameLifecycleState);
   void NotifyContextDestroyed() override;
 
-  void PauseScheduledTasks(PauseState);
-  void UnpauseScheduledTasks();
-
   // TODO(haraken): Remove these methods by making the customers inherit from
-  // PausableObject. PausableObject is a standard way to observe context
-  // suspension/resumption.
+  // ContextLifecycleObserver. ContextLifecycleObserver is a standard way to
+  // observe context suspension/resumption.
   virtual bool TasksNeedPause() { return false; }
   virtual void TasksWerePaused() {}
   virtual void TasksWereUnpaused() {}
 
-  bool IsContextPaused() const { return pause_state_.has_value(); }
+  bool IsContextPaused() const {
+    return lifecycle_state_ != mojom::FrameLifecycleState::kRunning;
+  }
   bool IsContextDestroyed() const { return is_context_destroyed_; }
-  base::Optional<PauseState> ContextPauseState() const { return pause_state_; }
-
-  // Called after the construction of an PausableObject to synchronize
-  // pause state.
-  void PausePausableObjectIfNeeded(PausableObject*);
+  mojom::FrameLifecycleState ContextPauseState() const {
+    return lifecycle_state_;
+  }
 
   // Gets the next id in a circular sequence from 1 to 2^31-1.
   int CircularSequentialID();
@@ -289,7 +283,8 @@
   bool in_dispatch_error_event_;
   HeapVector<Member<ErrorEvent>> pending_exceptions_;
 
-  base::Optional<PauseState> pause_state_;
+  mojom::FrameLifecycleState lifecycle_state_ =
+      mojom::FrameLifecycleState::kRunning;
   bool is_context_destroyed_;
 
   Member<PublicURLManager> public_url_manager_;
diff --git a/third_party/blink/renderer/core/execution_context/pausable_object_test.cc b/third_party/blink/renderer/core/execution_context/pausable_object_test.cc
deleted file mode 100644
index 8da0960..0000000
--- a/third_party/blink/renderer/core/execution_context/pausable_object_test.cc
+++ /dev/null
@@ -1,111 +0,0 @@
-/*
- * Copyright (c) 2014, Google Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- *     * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *     * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *     * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "third_party/blink/renderer/core/execution_context/pausable_object.h"
-
-#include <memory>
-#include "testing/gmock/include/gmock/gmock.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#include "third_party/blink/renderer/core/dom/document.h"
-#include "third_party/blink/renderer/core/testing/dummy_page_holder.h"
-
-namespace blink {
-
-class MockPausableObject final
-    : public GarbageCollectedFinalized<MockPausableObject>,
-      public PausableObject {
-  USING_GARBAGE_COLLECTED_MIXIN(MockPausableObject);
-
- public:
-  explicit MockPausableObject(ExecutionContext* context)
-      : PausableObject(context) {}
-
-  void Trace(blink::Visitor* visitor) override {
-    PausableObject::Trace(visitor);
-  }
-
-  MOCK_METHOD0(Pause, void());
-  MOCK_METHOD0(Unpause, void());
-  MOCK_METHOD1(ContextDestroyed, void(ExecutionContext*));
-};
-
-class PausableObjectTest : public testing::Test {
- protected:
-  PausableObjectTest();
-
-  Document& SrcDocument() const { return src_page_holder_->GetDocument(); }
-  Document& DestDocument() const { return dest_page_holder_->GetDocument(); }
-  MockPausableObject& PausableObject() { return *pausable_object_; }
-
- private:
-  std::unique_ptr<DummyPageHolder> src_page_holder_;
-  std::unique_ptr<DummyPageHolder> dest_page_holder_;
-  Persistent<MockPausableObject> pausable_object_;
-};
-
-PausableObjectTest::PausableObjectTest()
-    : src_page_holder_(DummyPageHolder::Create(IntSize(800, 600))),
-      dest_page_holder_(DummyPageHolder::Create(IntSize(800, 600))),
-      pausable_object_(MakeGarbageCollected<MockPausableObject>(
-          &src_page_holder_->GetDocument())) {
-  pausable_object_->PauseIfNeeded();
-}
-
-TEST_F(PausableObjectTest, NewContextObserved) {
-  unsigned initial_src_count = SrcDocument().PausableObjectCount();
-  unsigned initial_dest_count = DestDocument().PausableObjectCount();
-
-  EXPECT_CALL(PausableObject(), Unpause());
-  PausableObject().DidMoveToNewExecutionContext(&DestDocument());
-
-  EXPECT_EQ(initial_src_count - 1, SrcDocument().PausableObjectCount());
-  EXPECT_EQ(initial_dest_count + 1, DestDocument().PausableObjectCount());
-}
-
-TEST_F(PausableObjectTest, MoveToActiveDocument) {
-  EXPECT_CALL(PausableObject(), Unpause());
-  PausableObject().DidMoveToNewExecutionContext(&DestDocument());
-}
-
-TEST_F(PausableObjectTest, MoveToSuspendedDocument) {
-  DestDocument().PauseScheduledTasks(PauseState::kFrozen);
-
-  EXPECT_CALL(PausableObject(), Pause());
-  PausableObject().DidMoveToNewExecutionContext(&DestDocument());
-}
-
-TEST_F(PausableObjectTest, MoveToStoppedDocument) {
-  DestDocument().Shutdown();
-
-  EXPECT_CALL(PausableObject(), ContextDestroyed(&DestDocument()));
-  PausableObject().DidMoveToNewExecutionContext(&DestDocument());
-}
-
-}  // namespace blink
diff --git a/third_party/blink/renderer/core/execution_context/pause_state.h b/third_party/blink/renderer/core/execution_context/pause_state.h
deleted file mode 100644
index 938938f..0000000
--- a/third_party/blink/renderer/core/execution_context/pause_state.h
+++ /dev/null
@@ -1,23 +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 THIRD_PARTY_BLINK_RENDERER_CORE_EXECUTION_CONTEXT_PAUSE_STATE_H_
-#define THIRD_PARTY_BLINK_RENDERER_CORE_EXECUTION_CONTEXT_PAUSE_STATE_H_
-
-namespace blink {
-
-// This enum represents the pausing state of the ExecutionContext.
-
-// TODO(dtapuska): Remove this enum and use FrameLifecycleState instead.
-enum class PauseState {
-  // Pause tasks only. Used for nested event loops (alert, print).
-  kPaused,
-  // Freeze everything including media. Used for policies that
-  // have auto stopping of media that is hidden.
-  kFrozen
-};
-
-}  // namespace blink
-
-#endif  // THIRD_PARTY_BLINK_RENDERER_CORE_EXECUTION_CONTEXT_PAUSE_STATE_H_
diff --git a/third_party/blink/renderer/core/frame/local_frame.cc b/third_party/blink/renderer/core/frame/local_frame.cc
index c27cd18..8841d69e 100644
--- a/third_party/blink/renderer/core/frame/local_frame.cc
+++ b/third_party/blink/renderer/core/frame/local_frame.cc
@@ -1754,14 +1754,9 @@
 }
 
 void LocalFrame::PauseContext() {
-  // TODO(dtapuska): Eventually get rid of PauseState.
-  PauseState pause_state =
-      lifecycle_state_ == mojom::FrameLifecycleState::kFrozenAutoResumeMedia
-          ? PauseState::kFrozen
-          : PauseState::kPaused;
   if (Document* document = GetDocument()) {
     document->Fetcher()->SetDefersLoading(true);
-    document->PauseScheduledTasks(pause_state);
+    document->SetLifecycleState(lifecycle_state_);
   }
   Loader().SetDefersLoading(true);
   GetFrameScheduler()->SetPaused(true);
@@ -1770,7 +1765,7 @@
 void LocalFrame::UnpauseContext() {
   if (Document* document = GetDocument()) {
     document->Fetcher()->SetDefersLoading(false);
-    document->UnpauseScheduledTasks();
+    document->SetLifecycleState(mojom::FrameLifecycleState::kRunning);
   }
   Loader().SetDefersLoading(false);
   GetFrameScheduler()->SetPaused(false);
diff --git a/third_party/blink/renderer/core/frame/local_frame.h b/third_party/blink/renderer/core/frame/local_frame.h
index 44c3bfe7..0c22e2b 100644
--- a/third_party/blink/renderer/core/frame/local_frame.h
+++ b/third_party/blink/renderer/core/frame/local_frame.h
@@ -44,7 +44,6 @@
 #include "third_party/blink/renderer/core/dom/user_gesture_indicator.h"
 #include "third_party/blink/renderer/core/dom/weak_identifier_map.h"
 #include "third_party/blink/renderer/core/editing/forward.h"
-#include "third_party/blink/renderer/core/execution_context/pause_state.h"
 #include "third_party/blink/renderer/core/frame/frame.h"
 #include "third_party/blink/renderer/core/frame/frame_types.h"
 #include "third_party/blink/renderer/core/frame/local_frame_view.h"
diff --git a/third_party/blink/renderer/core/html/media/html_audio_element.cc b/third_party/blink/renderer/core/html/media/html_audio_element.cc
index c2b6157..c1fecb4 100644
--- a/third_party/blink/renderer/core/html/media/html_audio_element.cc
+++ b/third_party/blink/renderer/core/html/media/html_audio_element.cc
@@ -38,7 +38,7 @@
 HTMLAudioElement* HTMLAudioElement::Create(Document& document) {
   HTMLAudioElement* audio = MakeGarbageCollected<HTMLAudioElement>(document);
   audio->EnsureUserAgentShadowRoot();
-  audio->PauseIfNeeded();
+  audio->UpdateStateIfNeeded();
   return audio;
 }
 
@@ -50,7 +50,7 @@
   audio->setPreload(AtomicString("auto"));
   if (!src.IsNull())
     audio->SetSrc(src);
-  audio->PauseIfNeeded();
+  audio->UpdateStateIfNeeded();
   return audio;
 }
 
diff --git a/third_party/blink/renderer/core/html/media/html_media_element.cc b/third_party/blink/renderer/core/html/media/html_media_element.cc
index 735bb92d..942f087 100644
--- a/third_party/blink/renderer/core/html/media/html_media_element.cc
+++ b/third_party/blink/renderer/core/html/media/html_media_element.cc
@@ -448,7 +448,7 @@
 HTMLMediaElement::HTMLMediaElement(const QualifiedName& tag_name,
                                    Document& document)
     : HTMLElement(tag_name, document),
-      PausableObject(&document),
+      ContextLifecycleStateObserver(&document),
       load_timer_(document.GetTaskRunner(TaskType::kInternalMedia),
                   this,
                   &HTMLMediaElement::LoadTimerFired),
@@ -602,7 +602,7 @@
   // load event from within the destructor.
   old_document.DecrementLoadEventDelayCount();
 
-  PausableObject::DidMoveToNewExecutionContext(&GetDocument());
+  ContextLifecycleStateObserver::DidMoveToNewExecutionContext(&GetDocument());
   HTMLElement::DidMoveToNewDocument(old_document);
 }
 
@@ -3558,15 +3558,15 @@
     GetLayoutObject()->SetShouldDoFullPaintInvalidation();
 }
 
-void HTMLMediaElement::ContextPaused(PauseState pause_state) {
-  if (pause_state == PauseState::kFrozen && playing_) {
+void HTMLMediaElement::ContextLifecycleStateChanged(
+    mojom::FrameLifecycleState state) {
+  if (state == mojom::FrameLifecycleState::kFrozenAutoResumeMedia && playing_) {
     paused_by_context_paused_ = true;
     pause();
-  }
-}
-
-void HTMLMediaElement::ContextUnpaused() {
-  if (paused_by_context_paused_) {
+  } else if (state == mojom::FrameLifecycleState::kFrozen && playing_) {
+    pause();
+  } else if (state == mojom::FrameLifecycleState::kRunning &&
+             paused_by_context_paused_) {
     paused_by_context_paused_ = false;
     Play();
   }
@@ -3989,7 +3989,7 @@
       this);
   Supplementable<HTMLMediaElement>::Trace(visitor);
   HTMLElement::Trace(visitor);
-  PausableObject::Trace(visitor);
+  ContextLifecycleStateObserver::Trace(visitor);
 }
 
 void HTMLMediaElement::CreatePlaceholderTracksIfNecessary() {
diff --git a/third_party/blink/renderer/core/html/media/html_media_element.h b/third_party/blink/renderer/core/html/media/html_media_element.h
index e0ee8d2..674f448 100644
--- a/third_party/blink/renderer/core/html/media/html_media_element.h
+++ b/third_party/blink/renderer/core/html/media/html_media_element.h
@@ -35,7 +35,7 @@
 #include "third_party/blink/renderer/bindings/core/v8/active_script_wrappable.h"
 #include "third_party/blink/renderer/bindings/core/v8/script_promise.h"
 #include "third_party/blink/renderer/core/core_export.h"
-#include "third_party/blink/renderer/core/execution_context/pausable_object.h"
+#include "third_party/blink/renderer/core/execution_context/context_lifecycle_state_observer.h"
 #include "third_party/blink/renderer/core/html/html_element.h"
 #include "third_party/blink/renderer/core/html/media/media_controls.h"
 #include "third_party/blink/renderer/core/intersection_observer/intersection_observer.h"
@@ -87,7 +87,7 @@
     : public HTMLElement,
       public Supplementable<HTMLMediaElement>,
       public ActiveScriptWrappable<HTMLMediaElement>,
-      public PausableObject,
+      public ContextLifecycleStateObserver,
       private WebMediaPlayerClient {
   DEFINE_WRAPPERTYPEINFO();
   USING_GARBAGE_COLLECTED_MIXIN(HTMLMediaElement);
@@ -262,10 +262,10 @@
   void DisableAutomaticTextTrackSelection();
 
   // EventTarget function.
-  // Both Node (via HTMLElement) and PausableObject define this method, which
-  // causes an ambiguity error at compile time. This class's constructor
-  // ensures that both implementations return document, so return the result
-  // of one of them here.
+  // Both Node (via HTMLElement) and ContextLifecycleStateObserver define this
+  // method, which causes an ambiguity error at compile time. This class's
+  // constructor ensures that both implementations return document, so return
+  // the result of one of them here.
   using HTMLElement::GetExecutionContext;
 
   bool IsFullscreen() const;
@@ -386,9 +386,8 @@
 
   bool IsInteractiveContent() const final;
 
-  // PausableObject functions.
-  void ContextPaused(PauseState) override;
-  void ContextUnpaused() override;
+  // ContextLifecycleStateObserver functions.
+  void ContextLifecycleStateChanged(mojom::FrameLifecycleState) override;
   void ContextDestroyed(ExecutionContext*) override;
 
   virtual void UpdateDisplayState() {}
diff --git a/third_party/blink/renderer/core/html/media/html_media_element_test.cc b/third_party/blink/renderer/core/html/media/html_media_element_test.cc
index 2463e4e2..3faa20224 100644
--- a/third_party/blink/renderer/core/html/media/html_media_element_test.cc
+++ b/third_party/blink/renderer/core/html/media/html_media_element_test.cc
@@ -476,10 +476,17 @@
   SetReadyState(HTMLMediaElement::kHaveFutureData);
 
   EXPECT_FALSE(Media()->paused());
-  GetExecutionContext()->PausePausableObjects(PauseState::kFrozen);
+  GetExecutionContext()->SetLifecycleState(
+      mojom::FrameLifecycleState::kFrozenAutoResumeMedia);
   EXPECT_TRUE(Media()->paused());
-  GetExecutionContext()->UnpausePausableObjects();
+  GetExecutionContext()->SetLifecycleState(
+      mojom::FrameLifecycleState::kRunning);
   EXPECT_FALSE(Media()->paused());
+  GetExecutionContext()->SetLifecycleState(mojom::FrameLifecycleState::kFrozen);
+  EXPECT_TRUE(Media()->paused());
+  GetExecutionContext()->SetLifecycleState(
+      mojom::FrameLifecycleState::kRunning);
+  EXPECT_TRUE(Media()->paused());
 }
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/html/media/html_video_element.cc b/third_party/blink/renderer/core/html/media/html_video_element.cc
index 642053f..dad6245 100644
--- a/third_party/blink/renderer/core/html/media/html_video_element.cc
+++ b/third_party/blink/renderer/core/html/media/html_video_element.cc
@@ -105,7 +105,7 @@
 HTMLVideoElement* HTMLVideoElement::Create(Document& document) {
   HTMLVideoElement* video = MakeGarbageCollected<HTMLVideoElement>(document);
   video->EnsureUserAgentShadowRoot();
-  video->PauseIfNeeded();
+  video->UpdateStateIfNeeded();
   return video;
 }
 
diff --git a/third_party/blink/renderer/core/html/media/html_video_element.h b/third_party/blink/renderer/core/html/media/html_video_element.h
index 9e6a0a1..61759f9b 100644
--- a/third_party/blink/renderer/core/html/media/html_video_element.h
+++ b/third_party/blink/renderer/core/html/media/html_video_element.h
@@ -214,7 +214,7 @@
   friend class HTMLMediaElementEventListenersTest;
   friend class HTMLVideoElementPersistentTest;
 
-  // PausableObject functions.
+  // ContextLifecycleStateObserver functions.
   void ContextDestroyed(ExecutionContext*) final;
 
   bool LayoutObjectIsNeeded(const ComputedStyle&) const override;
diff --git a/third_party/blink/renderer/core/html/parser/html_document_parser.cc b/third_party/blink/renderer/core/html/parser/html_document_parser.cc
index caa8623..b955f8c 100644
--- a/third_party/blink/renderer/core/html/parser/html_document_parser.cc
+++ b/third_party/blink/renderer/core/html/parser/html_document_parser.cc
@@ -1238,6 +1238,13 @@
         base::TimeDelta::FromMilliseconds(1000), 50);
   }
   DCHECK(document->documentElement());
+  Element* documentElement = GetDocument()->documentElement();
+  if (documentElement->hasAttribute(u"\u26A1") ||
+      documentElement->hasAttribute("amp") ||
+      documentElement->hasAttribute("i-amphtml-layout")) {
+    GetDocument()->Loader()->DidObserveLoadingBehavior(
+        kWebLoadingBehaviorAmpDocumentLoaded);
+  }
   FetchQueuedPreloads();
 }
 
diff --git a/third_party/blink/renderer/core/inspector/devtools_session.cc b/third_party/blink/renderer/core/inspector/devtools_session.cc
index 347b9a74..57e06d0 100644
--- a/third_party/blink/renderer/core/inspector/devtools_session.cc
+++ b/third_party/blink/renderer/core/inspector/devtools_session.cc
@@ -18,6 +18,7 @@
 #include "third_party/blink/renderer/platform/cross_thread_functional.h"
 #include "third_party/blink/renderer/platform/heap/persistent.h"
 #include "third_party/blink/renderer/platform/web_test_support.h"
+#include "third_party/blink/renderer/platform/wtf/text/string_utf8_adaptor.h"
 
 namespace blink {
 
@@ -34,6 +35,24 @@
          method == "Runtime.terminateExecution" ||
          method == "Emulation.setScriptExecutionDisabled";
 }
+
+String ParseMessage(const mojom::blink::DevToolsMessagePtr& message) {
+  size_t size = message->data.size();
+  if (!size)
+    return g_empty_string;
+  return WTF::String::FromUTF8(
+      reinterpret_cast<const char*>(message->data.data()), size);
+}
+
+mojom::blink::DevToolsMessagePtr SerializeMessage(const String& message) {
+  WTF::StringUTF8Adaptor adaptor(message);
+  auto result = mojom::blink::DevToolsMessage::New();
+  result->data = mojo_base::BigBuffer(base::make_span(
+      reinterpret_cast<const uint8_t*>(adaptor.Data()), adaptor.length()));
+
+  return result;
+}
+
 }  // namespace
 
 // Created and stored in unique_ptr on UI.
@@ -63,16 +82,17 @@
   void DeleteSoon() { io_task_runner_->DeleteSoon(FROM_HERE, this); }
 
   // mojom::blink::DevToolsSession implementation.
-  void DispatchProtocolCommand(int call_id,
-                               const String& method,
-                               const String& message) override {
+  void DispatchProtocolCommand(
+      int call_id,
+      const String& method,
+      mojom::blink::DevToolsMessagePtr message) override {
     DCHECK(ShouldInterruptForMethod(method));
     // Crash renderer.
     if (method == "Page.crash")
       CHECK(false);
-    inspector_task_runner_->AppendTask(
-        CrossThreadBind(&DevToolsSession::DispatchProtocolCommand, session_,
-                        call_id, method, message));
+    inspector_task_runner_->AppendTask(CrossThreadBind(
+        &::blink::DevToolsSession::DispatchProtocolCommandMessage, session_,
+        call_id, method, ParseMessage(message)));
   }
 
  private:
@@ -156,9 +176,17 @@
   flushProtocolNotifications();
 }
 
-void DevToolsSession::DispatchProtocolCommand(int call_id,
-                                              const String& method,
-                                              const String& message) {
+void DevToolsSession::DispatchProtocolCommand(
+    int call_id,
+    const String& method,
+    blink::mojom::blink::DevToolsMessagePtr message_ptr) {
+  return DispatchProtocolCommandMessage(call_id, method,
+                                        ParseMessage(message_ptr));
+}
+
+void DevToolsSession::DispatchProtocolCommandMessage(int call_id,
+                                                     const String& method,
+                                                     const String& message) {
   // IOSession does not provide ordering guarantees relative to
   // Session, so a command may come to IOSession after Session is detached,
   // and get posted to main thread to this method.
@@ -233,7 +261,7 @@
   // protocol response in any of them.
   if (WebTestSupport::IsRunningWebTest())
     agent_->FlushProtocolNotifications();
-  host_ptr_->DispatchProtocolResponse(message, call_id,
+  host_ptr_->DispatchProtocolResponse(SerializeMessage(message), call_id,
                                       session_state_.TakeUpdates());
 }
 
@@ -258,21 +286,21 @@
       std::unique_ptr<v8_inspector::StringBuffer> notification)
       : v8_notification_(std::move(notification)) {}
 
-  String Serialize() {
+  mojom::blink::DevToolsMessagePtr Serialize() {
+    String serialized;
     if (blink_notification_) {
-      serialized_ = blink_notification_->serialize();
+      serialized = blink_notification_->serialize();
       blink_notification_.reset();
     } else if (v8_notification_) {
-      serialized_ = ToCoreString(v8_notification_->string());
+      serialized = ToCoreString(v8_notification_->string());
       v8_notification_.reset();
     }
-    return serialized_;
+    return SerializeMessage(serialized);
   }
 
  private:
   std::unique_ptr<protocol::Serializable> blink_notification_;
   std::unique_ptr<v8_inspector::StringBuffer> v8_notification_;
-  String serialized_;
 };
 
 void DevToolsSession::sendProtocolNotification(
diff --git a/third_party/blink/renderer/core/inspector/devtools_session.h b/third_party/blink/renderer/core/inspector/devtools_session.h
index 78f42b6..ec01239 100644
--- a/third_party/blink/renderer/core/inspector/devtools_session.h
+++ b/third_party/blink/renderer/core/inspector/devtools_session.h
@@ -55,9 +55,13 @@
   class IOSession;
 
   // mojom::blink::DevToolsSession implementation.
-  void DispatchProtocolCommand(int call_id,
-                               const String& method,
-                               const String& message) override;
+  void DispatchProtocolCommand(
+      int call_id,
+      const String& method,
+      mojom::blink::DevToolsMessagePtr message) override;
+  void DispatchProtocolCommandMessage(int call_id,
+                                      const String& method,
+                                      const String& message);
 
   // protocol::FrontendChannel implementation.
   void sendProtocolResponse(
diff --git a/third_party/blink/renderer/core/inspector/worker_thread_debugger.cc b/third_party/blink/renderer/core/inspector/worker_thread_debugger.cc
index 7462f7f..57b4ef4 100644
--- a/third_party/blink/renderer/core/inspector/worker_thread_debugger.cc
+++ b/third_party/blink/renderer/core/inspector/worker_thread_debugger.cc
@@ -171,7 +171,7 @@
   WorkerThread* thread = worker_threads_.at(context_group_id);
   DCHECK(!thread->GlobalScope()->IsClosing());
   thread->GetWorkerInspectorController()->FlushProtocolNotifications();
-  thread->GlobalScope()->PauseScheduledTasks(PauseState::kPaused);
+  thread->GlobalScope()->SetLifecycleState(mojom::FrameLifecycleState::kPaused);
   auto pause_handle = thread->GetScheduler()->Pause();
   if (!nested_runner_)
     nested_runner_ = Platform::Current()->CreateNestedMessageLoopRunner();
@@ -187,7 +187,8 @@
   DCHECK(!thread->GlobalScope()->IsClosing());
 
   nested_runner_->QuitNow();
-  thread->GlobalScope()->UnpauseScheduledTasks();
+  thread->GlobalScope()->SetLifecycleState(
+      mojom::FrameLifecycleState::kRunning);
 }
 
 void WorkerThreadDebugger::muteMetrics(int context_group_id) {
diff --git a/third_party/blink/renderer/core/paint/applied_decoration_painter.h b/third_party/blink/renderer/core/paint/applied_decoration_painter.h
index dd81e56..9f4ad5173 100644
--- a/third_party/blink/renderer/core/paint/applied_decoration_painter.h
+++ b/third_party/blink/renderer/core/paint/applied_decoration_painter.h
@@ -36,7 +36,7 @@
         decoration_info_(decoration_info),
         decoration_(decoration),
         double_offset_(double_offset),
-        wavy_offset_factor_(wavy_offset_factor){};
+        wavy_offset_factor_(wavy_offset_factor) {}
 
   void Paint();
   FloatRect Bounds();
diff --git a/third_party/blink/renderer/core/paint/image_paint_timing_detector_test.cc b/third_party/blink/renderer/core/paint/image_paint_timing_detector_test.cc
index ac793404..cbf8e77 100644
--- a/third_party/blink/renderer/core/paint/image_paint_timing_detector_test.cc
+++ b/third_party/blink/renderer/core/paint/image_paint_timing_detector_test.cc
@@ -31,7 +31,7 @@
  public:
   ImagePaintTimingDetectorTest()
       : ScopedFirstContentfulPaintPlusPlusForTest(true),
-        base_url_("http://www.test.com/"){};
+        base_url_("http://www.test.com/") {}
 
   ~ImagePaintTimingDetectorTest() override {
     Platform::Current()
diff --git a/third_party/blink/renderer/core/paint/ng/ng_paint_fragment_traversal.cc b/third_party/blink/renderer/core/paint/ng/ng_paint_fragment_traversal.cc
index c7473b2..6aac400 100644
--- a/third_party/blink/renderer/core/paint/ng/ng_paint_fragment_traversal.cc
+++ b/third_party/blink/renderer/core/paint/ng/ng_paint_fragment_traversal.cc
@@ -66,7 +66,7 @@
   explicit LayoutObjectFilter(const LayoutObject* layout_object)
       : layout_object_(layout_object) {
     DCHECK(layout_object);
-  };
+  }
   bool IsCollectible(const NGPaintFragment* fragment) const {
     return fragment->GetLayoutObject() == layout_object_;
   }
diff --git a/third_party/blink/renderer/core/paint/paint_and_raster_invalidation_test.cc b/third_party/blink/renderer/core/paint/paint_and_raster_invalidation_test.cc
index 187d292..4307a7a9 100644
--- a/third_party/blink/renderer/core/paint/paint_and_raster_invalidation_test.cc
+++ b/third_party/blink/renderer/core/paint/paint_and_raster_invalidation_test.cc
@@ -794,7 +794,7 @@
             &child_layout_view->ContainerForPaintInvalidation());
   EXPECT_EQ(LayoutRect(0, 0, 100, 100),
             child_layout_view->FirstFragment().VisualRect());
-};
+}
 
 TEST_P(PaintAndRasterInvalidationTest, DelayedFullPaintInvalidation) {
   EnableCompositing();
@@ -844,7 +844,7 @@
   EXPECT_FALSE(target->Parent()->ShouldCheckForPaintInvalidation());
   EXPECT_FALSE(target->NeedsPaintOffsetAndVisualRectUpdate());
   GetDocument().View()->SetTracksPaintInvalidations(false);
-};
+}
 
 TEST_P(PaintAndRasterInvalidationTest, SVGHiddenContainer) {
   EnableCompositing();
@@ -945,7 +945,7 @@
   EXPECT_EQ(LayoutRect(0, 0, 150, 20), a->FirstFragment().VisualRect());
   EXPECT_EQ(LayoutRect(150, 0, 150, 20), b->FirstFragment().VisualRect());
   EXPECT_EQ(LayoutRect(300, 0, 150, 20), c->FirstFragment().VisualRect());
-};
+}
 
 TEST_P(PaintAndRasterInvalidationTest, PaintPropertyChange) {
   SetUpHTML(*this);
diff --git a/third_party/blink/renderer/core/paint/paint_timing_detector.cc b/third_party/blink/renderer/core/paint/paint_timing_detector.cc
index 23f4830..6c168a6 100644
--- a/third_party/blink/renderer/core/paint/paint_timing_detector.cc
+++ b/third_party/blink/renderer/core/paint/paint_timing_detector.cc
@@ -21,7 +21,7 @@
       text_paint_timing_detector_(
           MakeGarbageCollected<TextPaintTimingDetector>(frame_view)),
       image_paint_timing_detector_(
-          MakeGarbageCollected<ImagePaintTimingDetector>(frame_view)){};
+          MakeGarbageCollected<ImagePaintTimingDetector>(frame_view)) {}
 
 void PaintTimingDetector::NotifyPrePaintFinished() {
   text_paint_timing_detector_->OnPrePaintFinished();
diff --git a/third_party/blink/renderer/core/testing/internals.cc b/third_party/blink/renderer/core/testing/internals.cc
index 8f71b974..13a57666 100644
--- a/third_party/blink/renderer/core/testing/internals.cc
+++ b/third_party/blink/renderer/core/testing/internals.cc
@@ -1675,9 +1675,10 @@
       InstanceCounters::kMediaKeySessionCounter);
 }
 
-unsigned Internals::pausableObjectCount(Document* document) {
+unsigned Internals::contextLifecycleStateObserverObjectCount(
+    Document* document) {
   DCHECK(document);
-  return document->PausableObjectCount();
+  return document->ContextLifecycleStateObserverCount();
 }
 
 static unsigned EventHandlerCount(
diff --git a/third_party/blink/renderer/core/testing/internals.h b/third_party/blink/renderer/core/testing/internals.h
index dd463b8..5d0b826 100644
--- a/third_party/blink/renderer/core/testing/internals.h
+++ b/third_party/blink/renderer/core/testing/internals.h
@@ -281,7 +281,7 @@
 
   unsigned mediaKeysCount();
   unsigned mediaKeySessionCount();
-  unsigned pausableObjectCount(Document*);
+  unsigned contextLifecycleStateObserverObjectCount(Document*);
   unsigned wheelEventHandlerCount(Document*) const;
   unsigned scrollEventHandlerCount(Document*) const;
   unsigned touchStartOrMoveEventHandlerCount(Document*) const;
diff --git a/third_party/blink/renderer/core/testing/internals.idl b/third_party/blink/renderer/core/testing/internals.idl
index 7099cd9..20f0c67 100644
--- a/third_party/blink/renderer/core/testing/internals.idl
+++ b/third_party/blink/renderer/core/testing/internals.idl
@@ -155,7 +155,7 @@
 
     unsigned long mediaKeysCount();
     unsigned long mediaKeySessionCount();
-    unsigned long pausableObjectCount(Document document);
+    unsigned long contextLifecycleStateObserverObjectCount(Document document);
     unsigned long wheelEventHandlerCount(Document document);
     unsigned long scrollEventHandlerCount(Document document);
     unsigned long touchStartOrMoveEventHandlerCount(Document document);
diff --git a/third_party/blink/renderer/modules/accessibility/ax_object_cache_impl.cc b/third_party/blink/renderer/modules/accessibility/ax_object_cache_impl.cc
index 33717e11..92cb9423 100644
--- a/third_party/blink/renderer/modules/accessibility/ax_object_cache_impl.cc
+++ b/third_party/blink/renderer/modules/accessibility/ax_object_cache_impl.cc
@@ -237,12 +237,30 @@
   AXID node_id = node_object_mapping_.at(node);
   DCHECK(!HashTraits<AXID>::IsDeletedValue(node_id));
 
-  if (layout_object && node_id && !layout_id) {
-    // This can happen if an AXNodeObject is created for a node that's not
-    // laid out, but later something changes and it gets a layoutObject (like if
-    // it's reparented).
+  if (layout_object && node_id && !layout_id && !IsMenuListOption(node) &&
+      !IsHTMLAreaElement(node)) {
+    // This can happen if an AXNodeObject is created for a node that's not laid
+    // out, but later something changes and it gets a layoutObject (like if it's
+    // reparented). It's also possible the layout object changed.
+    // In any case, reuse the ax_id since the node didn't change.
     Remove(node_id);
-    return nullptr;
+
+    // Note that this codepath can be reached when |layout_object| is about to
+    // be destroyed.
+
+    // This potentially misses root LayoutObject re-creation, but we have no way
+    // of knowing whether the |layout_object| in those cases is still valid.
+    if (!layout_object->Parent())
+      return nullptr;
+
+    layout_object_mapping_.Set(layout_object, node_id);
+    AXObject* new_obj = CreateFromRenderer(layout_object);
+    ids_in_use_.insert(node_id);
+    new_obj->SetAXObjectID(node_id);
+    objects_.Set(node_id, new_obj);
+    new_obj->Init();
+    new_obj->SetLastKnownIsIgnoredValue(new_obj->AccessibilityIsIgnored());
+    return new_obj;
   }
 
   if (layout_id)
@@ -427,6 +445,12 @@
   if (AXObject* obj = Get(layout_object))
     return obj;
 
+  // Area elements are never created based on layout objects (see |Get|), so we
+  // really should never get here.
+  Node* node = layout_object->GetNode();
+  if (node && (IsMenuListOption(node) || IsHTMLAreaElement(node)))
+    return nullptr;
+
   AXObject* new_obj = CreateFromRenderer(layout_object);
 
   // Will crash later if we have two objects for the same layoutObject.
@@ -437,8 +461,10 @@
   layout_object_mapping_.Set(layout_object, axid);
   new_obj->Init();
   new_obj->SetLastKnownIsIgnoredValue(new_obj->AccessibilityIsIgnored());
-  if (layout_object->GetNode())
-    MaybeNewRelationTarget(layout_object->GetNode(), new_obj);
+  if (node) {
+    node_object_mapping_.Set(node, axid);
+    MaybeNewRelationTarget(node, new_obj);
+  }
 
   return new_obj;
 }
@@ -573,10 +599,8 @@
   Remove(ax_id);
   node_object_mapping_.erase(node);
 
-  if (node->GetLayoutObject()) {
+  if (node->GetLayoutObject())
     Remove(node->GetLayoutObject());
-    return;
-  }
 }
 
 void AXObjectCacheImpl::Remove(AbstractInlineTextBox* inline_text_box) {
diff --git a/third_party/blink/renderer/modules/animationworklet/animation_worklet_global_scope_test.cc b/third_party/blink/renderer/modules/animationworklet/animation_worklet_global_scope_test.cc
index 4c36697a..9ff3e94 100644
--- a/third_party/blink/renderer/modules/animationworklet/animation_worklet_global_scope_test.cc
+++ b/third_party/blink/renderer/modules/animationworklet/animation_worklet_global_scope_test.cc
@@ -41,7 +41,7 @@
   void AddGlobalScope(WorkletGlobalScope*) override {
     did_add_global_scope_ = true;
   }
-  void SynchronizeAnimatorName(const String&) override{};
+  void SynchronizeAnimatorName(const String&) override {}
   bool did_add_global_scope() { return did_add_global_scope_; }
 
  private:
diff --git a/third_party/blink/renderer/modules/animationworklet/worklet_animation_options.h b/third_party/blink/renderer/modules/animationworklet/worklet_animation_options.h
index 900405f..4868ad2b 100644
--- a/third_party/blink/renderer/modules/animationworklet/worklet_animation_options.h
+++ b/third_party/blink/renderer/modules/animationworklet/worklet_animation_options.h
@@ -18,7 +18,7 @@
   explicit WorkletAnimationOptions(scoped_refptr<SerializedScriptValue>);
   std::unique_ptr<cc::AnimationOptions> Clone() const override;
 
-  scoped_refptr<SerializedScriptValue> GetData() { return data_; };
+  scoped_refptr<SerializedScriptValue> GetData() { return data_; }
   ~WorkletAnimationOptions() override;
 
  private:
diff --git a/third_party/blink/renderer/modules/battery/battery_manager.cc b/third_party/blink/renderer/modules/battery/battery_manager.cc
index e216d890ee..c22afe1 100644
--- a/third_party/blink/renderer/modules/battery/battery_manager.cc
+++ b/third_party/blink/renderer/modules/battery/battery_manager.cc
@@ -16,14 +16,15 @@
 BatteryManager* BatteryManager::Create(ExecutionContext* context) {
   BatteryManager* battery_manager =
       MakeGarbageCollected<BatteryManager>(context);
-  battery_manager->PauseIfNeeded();
+  battery_manager->UpdateStateIfNeeded();
   return battery_manager;
 }
 
 BatteryManager::~BatteryManager() = default;
 
 BatteryManager::BatteryManager(ExecutionContext* context)
-    : PausableObject(context), PlatformEventController(To<Document>(context)) {}
+    : ContextLifecycleStateObserver(context),
+      PlatformEventController(To<Document>(context)) {}
 
 ScriptPromise BatteryManager::StartRequest(ScriptState* script_state) {
   if (!battery_property_) {
@@ -96,14 +97,15 @@
   return BatteryDispatcher::Instance().LatestData();
 }
 
-void BatteryManager::ContextPaused(PauseState) {
-  has_event_listener_ = false;
-  StopUpdating();
-}
-
-void BatteryManager::ContextUnpaused() {
-  has_event_listener_ = true;
-  StartUpdating();
+void BatteryManager::ContextLifecycleStateChanged(
+    mojom::FrameLifecycleState state) {
+  if (state == mojom::FrameLifecycleState::kRunning) {
+    has_event_listener_ = true;
+    StartUpdating();
+  } else {
+    has_event_listener_ = false;
+    StopUpdating();
+  }
 }
 
 void BatteryManager::ContextDestroyed(ExecutionContext*) {
@@ -124,7 +126,7 @@
   visitor->Trace(battery_property_);
   PlatformEventController::Trace(visitor);
   EventTargetWithInlineData::Trace(visitor);
-  PausableObject::Trace(visitor);
+  ContextLifecycleStateObserver::Trace(visitor);
 }
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/modules/battery/battery_manager.h b/third_party/blink/renderer/modules/battery/battery_manager.h
index 98edcdf..fbed854 100644
--- a/third_party/blink/renderer/modules/battery/battery_manager.h
+++ b/third_party/blink/renderer/modules/battery/battery_manager.h
@@ -8,7 +8,7 @@
 #include "third_party/blink/renderer/bindings/core/v8/active_script_wrappable.h"
 #include "third_party/blink/renderer/bindings/core/v8/script_promise.h"
 #include "third_party/blink/renderer/bindings/core/v8/script_promise_property.h"
-#include "third_party/blink/renderer/core/execution_context/pausable_object.h"
+#include "third_party/blink/renderer/core/execution_context/context_lifecycle_state_observer.h"
 #include "third_party/blink/renderer/core/frame/platform_event_controller.h"
 #include "third_party/blink/renderer/modules/battery/battery_status.h"
 #include "third_party/blink/renderer/modules/event_target_modules.h"
@@ -18,7 +18,7 @@
 
 class BatteryManager final : public EventTargetWithInlineData,
                              public ActiveScriptWrappable<BatteryManager>,
-                             public PausableObject,
+                             public ContextLifecycleStateObserver,
                              public PlatformEventController {
   DEFINE_WRAPPERTYPEINFO();
   USING_GARBAGE_COLLECTED_MIXIN(BatteryManager);
@@ -57,9 +57,8 @@
   void UnregisterWithDispatcher() override;
   bool HasLastData() override;
 
-  // PausableObject implementation.
-  void ContextPaused(PauseState) override;
-  void ContextUnpaused() override;
+  // ContextLifecycleState implementation.
+  void ContextLifecycleStateChanged(mojom::FrameLifecycleState) override;
   void ContextDestroyed(ExecutionContext*) override;
 
   // ScriptWrappable implementation.
diff --git a/third_party/blink/renderer/modules/canvas/canvas2d/base_rendering_context_2d.h b/third_party/blink/renderer/modules/canvas/canvas2d/base_rendering_context_2d.h
index 3004f06..68ef5fd 100644
--- a/third_party/blink/renderer/modules/canvas/canvas2d/base_rendering_context_2d.h
+++ b/third_party/blink/renderer/modules/canvas/canvas2d/base_rendering_context_2d.h
@@ -334,7 +334,7 @@
 
   void UnwindStateStack();
 
-  virtual CanvasColorParams ColorParams() const { return CanvasColorParams(); };
+  virtual CanvasColorParams ColorParams() const { return CanvasColorParams(); }
   virtual bool WritePixels(const SkImageInfo& orig_info,
                            const void* pixels,
                            size_t row_bytes,
diff --git a/third_party/blink/renderer/modules/canvas/canvas2d/canvas_rendering_context_2d.h b/third_party/blink/renderer/modules/canvas/canvas2d/canvas_rendering_context_2d.h
index 6c8d41a1..900cda2 100644
--- a/third_party/blink/renderer/modules/canvas/canvas2d/canvas_rendering_context_2d.h
+++ b/third_party/blink/renderer/modules/canvas/canvas2d/canvas_rendering_context_2d.h
@@ -196,7 +196,7 @@
 
   void Trace(blink::Visitor*) override;
 
-  CanvasColorParams ColorParamsForTest() const { return ColorParams(); };
+  CanvasColorParams ColorParamsForTest() const { return ColorParams(); }
 
  protected:
   void NeedsFinalizeFrame() override {
diff --git a/third_party/blink/renderer/modules/idle/idle_manager.cc b/third_party/blink/renderer/modules/idle/idle_manager.cc
index 28ad7dd..f5d236e 100644
--- a/third_party/blink/renderer/modules/idle/idle_manager.cc
+++ b/third_party/blink/renderer/modules/idle/idle_manager.cc
@@ -48,9 +48,9 @@
   ScriptPromise promise = resolver->Promise();
 
   mojom::blink::IdleMonitorPtr monitor_ptr;
-  IdleStatus* status = MakeGarbageCollected<IdleStatus>(
-      ExecutionContext::From(script_state), threshold_seconds,
-      mojo::MakeRequest(&monitor_ptr));
+  IdleStatus* status =
+      IdleStatus::Create(ExecutionContext::From(script_state),
+                         threshold_seconds, mojo::MakeRequest(&monitor_ptr));
 
   requests_.insert(resolver);
   service_->AddMonitor(
diff --git a/third_party/blink/renderer/modules/idle/idle_status.cc b/third_party/blink/renderer/modules/idle/idle_status.cc
index edac0d88..98c6970 100644
--- a/third_party/blink/renderer/modules/idle/idle_status.cc
+++ b/third_party/blink/renderer/modules/idle/idle_status.cc
@@ -13,14 +13,21 @@
 
 namespace blink {
 
+IdleStatus* IdleStatus::Create(ExecutionContext* context,
+                               uint32_t threshold,
+                               mojom::blink::IdleMonitorRequest request) {
+  auto* status =
+      MakeGarbageCollected<IdleStatus>(context, threshold, std::move(request));
+  status->UpdateStateIfNeeded();
+  return status;
+}
+
 IdleStatus::IdleStatus(ExecutionContext* context,
                        uint32_t threshold,
                        mojom::blink::IdleMonitorRequest request)
-    : PausableObject(context),
+    : ContextLifecycleStateObserver(context),
       threshold_(threshold),
-      binding_(this, std::move(request)) {
-  PauseIfNeeded();
-}
+      binding_(this, std::move(request)) {}
 
 void IdleStatus::Init(IdleState state) {
   state_ = state;
@@ -44,12 +51,12 @@
   return binding_.is_bound();
 }
 
-void IdleStatus::ContextUnpaused() {
-  StartMonitoring();
-}
-
-void IdleStatus::ContextPaused(PauseState) {
-  StopMonitoring();
+void IdleStatus::ContextLifecycleStateChanged(
+    mojom::FrameLifecycleState state) {
+  if (state == mojom::FrameLifecycleState::kRunning)
+    StartMonitoring();
+  else
+    StopMonitoring();
 }
 
 void IdleStatus::ContextDestroyed(ExecutionContext*) {
@@ -101,7 +108,7 @@
 
 void IdleStatus::Trace(blink::Visitor* visitor) {
   EventTargetWithInlineData::Trace(visitor);
-  PausableObject::Trace(visitor);
+  ContextLifecycleStateObserver::Trace(visitor);
 }
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/modules/idle/idle_status.h b/third_party/blink/renderer/modules/idle/idle_status.h
index a8724416..c8f491f6 100644
--- a/third_party/blink/renderer/modules/idle/idle_status.h
+++ b/third_party/blink/renderer/modules/idle/idle_status.h
@@ -9,7 +9,7 @@
 #include "third_party/blink/public/platform/modules/idle/idle_manager.mojom-blink.h"
 #include "third_party/blink/renderer/bindings/core/v8/active_script_wrappable.h"
 #include "third_party/blink/renderer/core/dom/events/event_target.h"
-#include "third_party/blink/renderer/core/execution_context/pausable_object.h"
+#include "third_party/blink/renderer/core/execution_context/context_lifecycle_state_observer.h"
 #include "third_party/blink/renderer/modules/event_modules.h"
 #include "third_party/blink/renderer/modules/event_target_modules.h"
 #include "third_party/blink/renderer/platform/heap/heap_allocator.h"
@@ -19,7 +19,7 @@
 
 class IdleStatus final : public EventTargetWithInlineData,
                          public ActiveScriptWrappable<IdleStatus>,
-                         public PausableObject,
+                         public ContextLifecycleStateObserver,
                          public mojom::blink::IdleMonitor {
   USING_GARBAGE_COLLECTED_MIXIN(IdleStatus);
   DEFINE_WRAPPERTYPEINFO();
@@ -32,10 +32,13 @@
   // Constructed by the IdleManager when queried by script, but not returned
   // to script until the monitor has been registered by the service and
   // returned an initial state.
+  static IdleStatus* Create(ExecutionContext* context,
+                            uint32_t threshold,
+                            mojom::blink::IdleMonitorRequest request);
+
   IdleStatus(ExecutionContext*,
              uint32_t threshold,
              mojom::blink::IdleMonitorRequest);
-
   ~IdleStatus() override;
   void Dispose();
 
@@ -49,9 +52,8 @@
   // ActiveScriptWrappable implementation.
   bool HasPendingActivity() const final;
 
-  // PausableObject implementation.
-  void ContextPaused(PauseState) override;
-  void ContextUnpaused() override;
+  // ContextLifecycleStateObserver implementation.
+  void ContextLifecycleStateChanged(mojom::FrameLifecycleState) override;
   void ContextDestroyed(ExecutionContext*) override;
 
   // IdleStatus IDL interface.
diff --git a/third_party/blink/renderer/modules/media_controls/elements/media_control_animated_arrow_container_element.h b/third_party/blink/renderer/modules/media_controls/elements/media_control_animated_arrow_container_element.h
index ea60c72e..b4dd216 100644
--- a/third_party/blink/renderer/modules/media_controls/elements/media_control_animated_arrow_container_element.h
+++ b/third_party/blink/renderer/modules/media_controls/elements/media_control_animated_arrow_container_element.h
@@ -44,7 +44,7 @@
 
     // MediaControlAnimationEventListener::Observer overrides
     void OnAnimationIteration() override;
-    void OnAnimationEnd() override{};
+    void OnAnimationEnd() override {}
     Element& WatchedAnimationElement() const override;
 
     // Shows the animated arrows for a single animation iteration. If the
diff --git a/third_party/blink/renderer/modules/media_controls/elements/media_control_slider_element.h b/third_party/blink/renderer/modules/media_controls/elements/media_control_slider_element.h
index 0e1c05cd..30cad666 100644
--- a/third_party/blink/renderer/modules/media_controls/elements/media_control_slider_element.h
+++ b/third_party/blink/renderer/modules/media_controls/elements/media_control_slider_element.h
@@ -24,7 +24,7 @@
 
   // Stores the position of the segment in proportion from 0.0 to 1.0.
   struct Position {
-    Position(double left, double width) : left(left), width(width){};
+    Position(double left, double width) : left(left), width(width) {}
     double left;
     double width;
   };
diff --git a/third_party/blink/renderer/modules/media_controls/media_controls_resource_loader.cc b/third_party/blink/renderer/modules/media_controls/media_controls_resource_loader.cc
index 7248e6fc..1c263b2 100644
--- a/third_party/blink/renderer/modules/media_controls/media_controls_resource_loader.cc
+++ b/third_party/blink/renderer/modules/media_controls/media_controls_resource_loader.cc
@@ -35,58 +35,58 @@
       RuntimeEnabledFeatures::ModernMediaControlsEnabled()
           ? IDR_UASTYLE_MODERN_MEDIA_CONTROLS_CSS
           : IDR_UASTYLE_LEGACY_MEDIA_CONTROLS_CSS);
-};
+}
 
 String MediaControlsResourceLoader::GetMediaControlsAndroidCSS() const {
   if (RuntimeEnabledFeatures::ModernMediaControlsEnabled())
     return String();
   return UncompressResourceAsString(
       IDR_UASTYLE_LEGACY_MEDIA_CONTROLS_ANDROID_CSS);
-};
+}
 
 // static
 String MediaControlsResourceLoader::GetShadowTimelineStyleSheet() {
   return UncompressResourceAsString(
       IDR_SHADOWSTYLE_MODERN_MEDIA_CONTROLS_TIMELINE_CSS);
-};
+}
 
 // static
 String MediaControlsResourceLoader::GetShadowLoadingStyleSheet() {
   return UncompressResourceAsString(
       IDR_SHADOWSTYLE_MODERN_MEDIA_CONTROLS_LOADING_CSS);
-};
+}
 
 // static
 String MediaControlsResourceLoader::GetJumpSVGImage() {
   return UncompressResourceAsString(IDR_MODERN_MEDIA_CONTROLS_JUMP_SVG);
-};
+}
 
 // static
 String MediaControlsResourceLoader::GetArrowRightSVGImage() {
   return UncompressResourceAsString(IDR_MODERN_MEDIA_CONTROLS_ARROW_RIGHT_SVG);
-};
+}
 
 // static
 String MediaControlsResourceLoader::GetArrowLeftSVGImage() {
   return UncompressResourceAsString(IDR_MODERN_MEDIA_CONTROLS_ARROW_LEFT_SVG);
-};
+}
 
 // static
 String MediaControlsResourceLoader::GetScrubbingMessageStyleSheet() {
   return UncompressResourceAsString(
       IDR_SHADOWSTYLE_MODERN_MEDIA_CONTROLS_SCRUBBING_MESSAGE_CSS);
-};
+}
 
 // static
 String MediaControlsResourceLoader::GetAnimatedArrowStyleSheet() {
   return UncompressResourceAsString(
       IDR_SHADOWSTYLE_MODERN_MEDIA_CONTROLS_ANIMATED_ARROW_CSS);
-};
+}
 
 // static
 String MediaControlsResourceLoader::GetMediaInterstitialsStyleSheet() {
   return UncompressResourceAsString(IDR_UASTYLE_MEDIA_INTERSTITIALS_CSS);
-};
+}
 
 String MediaControlsResourceLoader::GetUAStyleSheet() {
   if (ShouldLoadAndroidCSS()) {
diff --git a/third_party/blink/renderer/modules/netinfo/network_information.cc b/third_party/blink/renderer/modules/netinfo/network_information.cc
index fe217c7..a7f95a2 100644
--- a/third_party/blink/renderer/modules/netinfo/network_information.cc
+++ b/third_party/blink/renderer/modules/netinfo/network_information.cc
@@ -83,7 +83,7 @@
 
 bool NetworkInformation::IsObserving() const {
   return !!connection_observer_handle_;
-};
+}
 
 String NetworkInformation::type() const {
   // type_ is only updated when listening for events, so ask
diff --git a/third_party/blink/renderer/modules/permissions/permission_status.cc b/third_party/blink/renderer/modules/permissions/permission_status.cc
index 8fbd71d..bced508 100644
--- a/third_party/blink/renderer/modules/permissions/permission_status.cc
+++ b/third_party/blink/renderer/modules/permissions/permission_status.cc
@@ -28,7 +28,7 @@
     MojoPermissionDescriptor descriptor) {
   PermissionStatus* permission_status = MakeGarbageCollected<PermissionStatus>(
       execution_context, status, std::move(descriptor));
-  permission_status->PauseIfNeeded();
+  permission_status->UpdateStateIfNeeded();
   permission_status->StartListening();
   return permission_status;
 }
@@ -36,7 +36,7 @@
 PermissionStatus::PermissionStatus(ExecutionContext* execution_context,
                                    MojoPermissionStatus status,
                                    MojoPermissionDescriptor descriptor)
-    : PausableObject(execution_context),
+    : ContextLifecycleStateObserver(execution_context),
       status_(status),
       descriptor_(std::move(descriptor)),
       binding_(this) {}
@@ -52,19 +52,19 @@
 }
 
 ExecutionContext* PermissionStatus::GetExecutionContext() const {
-  return PausableObject::GetExecutionContext();
+  return ContextLifecycleStateObserver::GetExecutionContext();
 }
 
 bool PermissionStatus::HasPendingActivity() const {
   return binding_.is_bound();
 }
 
-void PermissionStatus::ContextUnpaused() {
-  StartListening();
-}
-
-void PermissionStatus::ContextPaused(PauseState) {
-  StopListening();
+void PermissionStatus::ContextLifecycleStateChanged(
+    mojom::FrameLifecycleState state) {
+  if (state == mojom::FrameLifecycleState::kRunning)
+    StartListening();
+  else
+    StopListening();
 }
 
 void PermissionStatus::ContextDestroyed(ExecutionContext*) {
@@ -113,7 +113,7 @@
 
 void PermissionStatus::Trace(blink::Visitor* visitor) {
   EventTargetWithInlineData::Trace(visitor);
-  PausableObject::Trace(visitor);
+  ContextLifecycleStateObserver::Trace(visitor);
 }
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/modules/permissions/permission_status.h b/third_party/blink/renderer/modules/permissions/permission_status.h
index 0e4d8ad226..55b5074 100644
--- a/third_party/blink/renderer/modules/permissions/permission_status.h
+++ b/third_party/blink/renderer/modules/permissions/permission_status.h
@@ -9,7 +9,7 @@
 #include "third_party/blink/public/platform/modules/permissions/permission.mojom-blink.h"
 #include "third_party/blink/renderer/bindings/core/v8/active_script_wrappable.h"
 #include "third_party/blink/renderer/core/dom/events/event_target.h"
-#include "third_party/blink/renderer/core/execution_context/pausable_object.h"
+#include "third_party/blink/renderer/core/execution_context/context_lifecycle_state_observer.h"
 #include "third_party/blink/renderer/platform/heap/handle.h"
 #include "third_party/blink/renderer/platform/wtf/text/atomic_string.h"
 #include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
@@ -23,7 +23,7 @@
 // ExecutionContext.
 class PermissionStatus final : public EventTargetWithInlineData,
                                public ActiveScriptWrappable<PermissionStatus>,
-                               public PausableObject,
+                               public ContextLifecycleStateObserver,
                                public mojom::blink::PermissionObserver {
   USING_GARBAGE_COLLECTED_MIXIN(PermissionStatus);
   DEFINE_WRAPPERTYPEINFO();
@@ -54,9 +54,8 @@
   // ScriptWrappable implementation.
   bool HasPendingActivity() const final;
 
-  // PausableObject implementation.
-  void ContextPaused(PauseState) override;
-  void ContextUnpaused() override;
+  // ContextLifecycleStateObserver implementation.
+  void ContextLifecycleStateChanged(mojom::FrameLifecycleState) override;
   void ContextDestroyed(ExecutionContext*) override;
 
   String state() const;
diff --git a/third_party/blink/renderer/modules/presentation/presentation_availability.cc b/third_party/blink/renderer/modules/presentation/presentation_availability.cc
index eec6565..5828fe2 100644
--- a/third_party/blink/renderer/modules/presentation/presentation_availability.cc
+++ b/third_party/blink/renderer/modules/presentation/presentation_availability.cc
@@ -24,7 +24,7 @@
   PresentationAvailability* presentation_availability =
       MakeGarbageCollected<PresentationAvailability>(
           resolver->GetExecutionContext(), urls, value);
-  presentation_availability->PauseIfNeeded();
+  presentation_availability->UpdateStateIfNeeded();
   presentation_availability->UpdateListening();
   return presentation_availability;
 }
@@ -33,7 +33,7 @@
     ExecutionContext* execution_context,
     const WTF::Vector<KURL>& urls,
     bool value)
-    : PausableObject(execution_context),
+    : ContextLifecycleStateObserver(execution_context),
       PageVisibilityObserver(To<Document>(execution_context)->GetPage()),
       urls_(urls),
       value_(value),
@@ -48,7 +48,7 @@
 }
 
 ExecutionContext* PresentationAvailability::GetExecutionContext() const {
-  return PausableObject::GetExecutionContext();
+  return ContextLifecycleStateObserver::GetExecutionContext();
 }
 
 void PresentationAvailability::AddedEventListener(
@@ -76,12 +76,12 @@
   return state_ != State::kInactive;
 }
 
-void PresentationAvailability::ContextUnpaused() {
-  SetState(State::kActive);
-}
-
-void PresentationAvailability::ContextPaused(PauseState) {
-  SetState(State::kSuspended);
+void PresentationAvailability::ContextLifecycleStateChanged(
+    mojom::FrameLifecycleState state) {
+  if (state == mojom::FrameLifecycleState::kRunning)
+    SetState(State::kActive);
+  else
+    SetState(State::kSuspended);
 }
 
 void PresentationAvailability::ContextDestroyed(ExecutionContext*) {
@@ -123,7 +123,7 @@
 void PresentationAvailability::Trace(blink::Visitor* visitor) {
   EventTargetWithInlineData::Trace(visitor);
   PageVisibilityObserver::Trace(visitor);
-  PausableObject::Trace(visitor);
+  ContextLifecycleStateObserver::Trace(visitor);
 }
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/modules/presentation/presentation_availability.h b/third_party/blink/renderer/modules/presentation/presentation_availability.h
index c311012..b2e24824 100644
--- a/third_party/blink/renderer/modules/presentation/presentation_availability.h
+++ b/third_party/blink/renderer/modules/presentation/presentation_availability.h
@@ -9,7 +9,7 @@
 #include "third_party/blink/public/platform/web_vector.h"
 #include "third_party/blink/renderer/bindings/core/v8/active_script_wrappable.h"
 #include "third_party/blink/renderer/core/dom/events/event_target.h"
-#include "third_party/blink/renderer/core/execution_context/pausable_object.h"
+#include "third_party/blink/renderer/core/execution_context/context_lifecycle_state_observer.h"
 #include "third_party/blink/renderer/core/page/page_visibility_observer.h"
 #include "third_party/blink/renderer/modules/modules_export.h"
 #include "third_party/blink/renderer/modules/presentation/presentation_availability_observer.h"
@@ -28,7 +28,7 @@
 class MODULES_EXPORT PresentationAvailability final
     : public EventTargetWithInlineData,
       public ActiveScriptWrappable<PresentationAvailability>,
-      public PausableObject,
+      public ContextLifecycleStateObserver,
       public PageVisibilityObserver,
       public PresentationAvailabilityObserver {
   USING_GARBAGE_COLLECTED_MIXIN(PresentationAvailability);
@@ -53,9 +53,8 @@
   // ScriptWrappable implementation.
   bool HasPendingActivity() const final;
 
-  // PausableObject implementation.
-  void ContextPaused(PauseState) override;
-  void ContextUnpaused() override;
+  // ContextLifecycleStateObserver implementation.
+  void ContextLifecycleStateChanged(mojom::FrameLifecycleState) override;
   void ContextDestroyed(ExecutionContext*) override;
 
   // PageVisibilityObserver implementation.
@@ -73,10 +72,10 @@
                           RegisteredEventListener&) override;
 
  private:
-  // Current state of the PausableObject. It is Active when created. It
-  // becomes Suspended when suspend() is called and moves back to Active if
-  // resume() is called. It becomes Inactive when stop() is called or at
-  // destruction time.
+  // Current state of the ContextLifecycleStateObserver. It is Active when
+  // created. It becomes Suspended when suspend() is called and moves back to
+  // Active if resume() is called. It becomes Inactive when stop() is called or
+  // at destruction time.
   enum class State : char {
     kActive,
     kSuspended,
diff --git a/third_party/blink/renderer/modules/vr/vr_controller.cc b/third_party/blink/renderer/modules/vr/vr_controller.cc
index 45bcb147b..14abe1d8 100644
--- a/third_party/blink/renderer/modules/vr/vr_controller.cc
+++ b/third_party/blink/renderer/modules/vr/vr_controller.cc
@@ -90,7 +90,7 @@
   device->GetImmersiveVRDisplayInfo(WTF::Bind(
       &VRController::OnImmersiveDisplayInfoReturned, WrapPersistent(this)));
 
-  display_ = MakeGarbageCollected<VRDisplay>(navigator_vr_, std::move(device));
+  display_ = VRDisplay::Create(navigator_vr_, std::move(device));
 
   if (pending_listening_for_activate_) {
     SetListeningForActivate(pending_listening_for_activate_);
diff --git a/third_party/blink/renderer/modules/vr/vr_display.cc b/third_party/blink/renderer/modules/vr/vr_display.cc
index c9e0b79..06ff7ad 100644
--- a/third_party/blink/renderer/modules/vr/vr_display.cc
+++ b/third_party/blink/renderer/modules/vr/vr_display.cc
@@ -127,13 +127,11 @@
 
 VRDisplay::VRDisplay(NavigatorVR* navigator_vr,
                      device::mojom::blink::XRDevicePtr device)
-    : PausableObject(navigator_vr->GetDocument()),
+    : ContextLifecycleStateObserver(navigator_vr->GetDocument()),
       navigator_vr_(navigator_vr),
       capabilities_(MakeGarbageCollected<VRDisplayCapabilities>()),
       device_ptr_(std::move(device)),
       display_client_binding_(this) {
-  PauseIfNeeded();  // Initialize SuspendabaleObject.
-
   // Request a non-immersive session immediately as WebVR 1.1 expects to be able
   // to get non-immersive poses as soon as the display is returned.
   device::mojom::blink::XRSessionOptionsPtr options =
@@ -151,8 +149,9 @@
 
 VRDisplay::~VRDisplay() = default;
 
-void VRDisplay::ContextUnpaused() {
-  RequestVSync();
+void VRDisplay::ContextLifecycleStateChanged(mojom::FrameLifecycleState state) {
+  if (state == mojom::FrameLifecycleState::kRunning)
+    RequestVSync();
 }
 
 VRController* VRDisplay::Controller() {
@@ -1160,7 +1159,7 @@
 }
 
 void VRDisplay::ContextDestroyed(ExecutionContext* context) {
-  PausableObject::ContextDestroyed(context);
+  ContextLifecycleStateObserver::ContextDestroyed(context);
   ForceExitPresent();
   scripted_animation_controller_.Clear();
 }
diff --git a/third_party/blink/renderer/modules/vr/vr_display.h b/third_party/blink/renderer/modules/vr/vr_display.h
index 998343f..8c19d5d 100644
--- a/third_party/blink/renderer/modules/vr/vr_display.h
+++ b/third_party/blink/renderer/modules/vr/vr_display.h
@@ -11,7 +11,7 @@
 #include "third_party/blink/renderer/bindings/core/v8/v8_frame_request_callback.h"
 #include "third_party/blink/renderer/core/dom/document.h"
 #include "third_party/blink/renderer/core/dom/events/event_target.h"
-#include "third_party/blink/renderer/core/execution_context/pausable_object.h"
+#include "third_party/blink/renderer/core/execution_context/context_lifecycle_state_observer.h"
 #include "third_party/blink/renderer/modules/vr/vr_display_capabilities.h"
 #include "third_party/blink/renderer/modules/vr/vr_layer_init.h"
 #include "third_party/blink/renderer/platform/graphics/gpu/xr_frame_transport.h"
@@ -75,13 +75,21 @@
 
 class VRDisplay final : public EventTargetWithInlineData,
                         public ActiveScriptWrappable<VRDisplay>,
-                        public PausableObject,
+                        public ContextLifecycleStateObserver,
                         public device::mojom::blink::VRDisplayClient {
   DEFINE_WRAPPERTYPEINFO();
   USING_GARBAGE_COLLECTED_MIXIN(VRDisplay);
   USING_PRE_FINALIZER(VRDisplay, Dispose);
 
  public:
+  static VRDisplay* Create(NavigatorVR* navigator,
+                           device::mojom::blink::XRDevicePtr device) {
+    VRDisplay* display =
+        MakeGarbageCollected<VRDisplay>(navigator, std::move(device));
+    display->UpdateStateIfNeeded();
+    return display;
+  }
+
   VRDisplay(NavigatorVR*, device::mojom::blink::XRDevicePtr);
   ~VRDisplay() override;
 
@@ -130,8 +138,8 @@
   // ScriptWrappable implementation.
   bool HasPendingActivity() const final;
 
-  // PausableObject:
-  void ContextUnpaused() override;
+  // ContextLifecycleStateObserver:
+  void ContextLifecycleStateChanged(mojom::FrameLifecycleState) override;
 
   void OnChanged(device::mojom::blink::VRDisplayInfoPtr, bool is_immersive);
   void OnExitPresent(bool is_immersive);
diff --git a/third_party/blink/renderer/modules/webaudio/audio_context.cc b/third_party/blink/renderer/modules/webaudio/audio_context.cc
index afc0e9a..adb0eef 100644
--- a/third_party/blink/renderer/modules/webaudio/audio_context.cc
+++ b/third_party/blink/renderer/modules/webaudio/audio_context.cc
@@ -66,7 +66,7 @@
 
   AudioContext* audio_context =
       MakeGarbageCollected<AudioContext>(document, latency_hint);
-  audio_context->PauseIfNeeded();
+  audio_context->UpdateStateIfNeeded();
 
   if (!audio_utilities::IsValidAudioBufferSampleRate(
           audio_context->sampleRate())) {
diff --git a/third_party/blink/renderer/modules/webaudio/audio_context_test.cc b/third_party/blink/renderer/modules/webaudio/audio_context_test.cc
index e164c124..b867671a 100644
--- a/third_party/blink/renderer/modules/webaudio/audio_context_test.cc
+++ b/third_party/blink/renderer/modules/webaudio/audio_context_test.cc
@@ -179,9 +179,9 @@
 
   audio_context->set_was_audible_for_testing(true);
   EXPECT_FALSE(web_audio_device_paused_);
-  GetDocument().PausePausableObjects(PauseState::kFrozen);
+  GetDocument().SetLifecycleState(mojom::FrameLifecycleState::kFrozen);
   EXPECT_TRUE(web_audio_device_paused_);
-  GetDocument().UnpausePausableObjects();
+  GetDocument().SetLifecycleState(mojom::FrameLifecycleState::kRunning);
   EXPECT_FALSE(web_audio_device_paused_);
 }
 
diff --git a/third_party/blink/renderer/modules/webaudio/audio_listener.h b/third_party/blink/renderer/modules/webaudio/audio_listener.h
index ffe857b..062e013 100644
--- a/third_party/blink/renderer/modules/webaudio/audio_listener.h
+++ b/third_party/blink/renderer/modules/webaudio/audio_listener.h
@@ -54,19 +54,19 @@
   ~AudioListener() override;
 
   // Location of the listener
-  AudioParam* positionX() const { return position_x_; };
-  AudioParam* positionY() const { return position_y_; };
-  AudioParam* positionZ() const { return position_z_; };
+  AudioParam* positionX() const { return position_x_; }
+  AudioParam* positionY() const { return position_y_; }
+  AudioParam* positionZ() const { return position_z_; }
 
   // Forward direction vector of the listener
-  AudioParam* forwardX() const { return forward_x_; };
-  AudioParam* forwardY() const { return forward_y_; };
-  AudioParam* forwardZ() const { return forward_z_; };
+  AudioParam* forwardX() const { return forward_x_; }
+  AudioParam* forwardY() const { return forward_y_; }
+  AudioParam* forwardZ() const { return forward_z_; }
 
   // Up direction vector for the listener
-  AudioParam* upX() const { return up_x_; };
-  AudioParam* upY() const { return up_y_; };
-  AudioParam* upZ() const { return up_z_; };
+  AudioParam* upX() const { return up_x_; }
+  AudioParam* upY() const { return up_y_; }
+  AudioParam* upZ() const { return up_z_; }
 
   // True if any of AudioParams have automations.
   bool HasSampleAccurateValues() const;
diff --git a/third_party/blink/renderer/modules/webaudio/audio_node.h b/third_party/blink/renderer/modules/webaudio/audio_node.h
index 49ea5db..58301704 100644
--- a/third_party/blink/renderer/modules/webaudio/audio_node.h
+++ b/third_party/blink/renderer/modules/webaudio/audio_node.h
@@ -152,7 +152,7 @@
   // Like process(), but only causes the automations to process; the
   // normal processing of the node is bypassed.  By default, we assume
   // no AudioParams need to be updated.
-  virtual void ProcessOnlyAudioParams(uint32_t frames_to_process){};
+  virtual void ProcessOnlyAudioParams(uint32_t frames_to_process) {}
 
   // No significant resources should be allocated until initialize() is called.
   // Processing may not occur until a node is initialized.
diff --git a/third_party/blink/renderer/modules/webaudio/audio_param.h b/third_party/blink/renderer/modules/webaudio/audio_param.h
index b9cbdeb..efc3ebd 100644
--- a/third_party/blink/renderer/modules/webaudio/audio_param.h
+++ b/third_party/blink/renderer/modules/webaudio/audio_param.h
@@ -150,7 +150,7 @@
   AutomationRate GetAutomationRate() const { return automation_rate_; }
   void SetAutomationRate(AutomationRate automation_rate) {
     automation_rate_ = automation_rate;
-  };
+  }
 
   bool IsAutomationRateFixed() const {
     return rate_mode_ == AutomationRateMode::kFixed;
diff --git a/third_party/blink/renderer/modules/webaudio/audio_worklet_processor_definition.h b/third_party/blink/renderer/modules/webaudio/audio_worklet_processor_definition.h
index 7e1fa73..d4ad25e 100644
--- a/third_party/blink/renderer/modules/webaudio/audio_worklet_processor_definition.h
+++ b/third_party/blink/renderer/modules/webaudio/audio_worklet_processor_definition.h
@@ -55,7 +55,7 @@
     visitor->Trace(constructor_);
     visitor->Trace(process_);
     visitor->Trace(audio_param_descriptors_);
-  };
+  }
   const char* NameInHeapSnapshot() const override {
     return "AudioWorkletProcessorDefinition";
   }
diff --git a/third_party/blink/renderer/modules/webaudio/base_audio_context.cc b/third_party/blink/renderer/modules/webaudio/base_audio_context.cc
index cd03b1d..774c8a3 100644
--- a/third_party/blink/renderer/modules/webaudio/base_audio_context.cc
+++ b/third_party/blink/renderer/modules/webaudio/base_audio_context.cc
@@ -87,7 +87,7 @@
 // Constructor for rendering to the audio hardware.
 BaseAudioContext::BaseAudioContext(Document* document,
                                    enum ContextType context_type)
-    : PausableObject(document),
+    : ContextLifecycleStateObserver(document),
       destination_node_(nullptr),
       uuid_(CreateCanonicalUUIDString()),
       is_cleared_(false),
@@ -176,15 +176,15 @@
   DCHECK_EQ(active_source_nodes_.size(), 0u);
 }
 
-void BaseAudioContext::ContextPaused(PauseState pause_state) {
-  if (pause_state == PauseState::kFrozen)
+void BaseAudioContext::ContextLifecycleStateChanged(
+    mojom::FrameLifecycleState state) {
+  if (state == mojom::FrameLifecycleState::kRunning)
+    destination()->GetAudioDestinationHandler().Resume();
+  else if (state == mojom::FrameLifecycleState::kFrozen ||
+           state == mojom::FrameLifecycleState::kFrozenAutoResumeMedia)
     destination()->GetAudioDestinationHandler().Pause();
 }
 
-void BaseAudioContext::ContextUnpaused() {
-  destination()->GetAudioDestinationHandler().Resume();
-}
-
 void BaseAudioContext::ContextDestroyed(ExecutionContext*) {
   destination()->GetAudioDestinationHandler().ContextDestroyed();
   Uninitialize();
@@ -908,7 +908,7 @@
 }
 
 ExecutionContext* BaseAudioContext::GetExecutionContext() const {
-  return PausableObject::GetExecutionContext();
+  return ContextLifecycleStateObserver::GetExecutionContext();
 }
 
 void BaseAudioContext::StartRendering() {
@@ -936,7 +936,7 @@
   visitor->Trace(periodic_wave_triangle_);
   visitor->Trace(audio_worklet_);
   EventTargetWithInlineData::Trace(visitor);
-  PausableObject::Trace(visitor);
+  ContextLifecycleStateObserver::Trace(visitor);
 }
 
 const SecurityOrigin* BaseAudioContext::GetSecurityOrigin() const {
diff --git a/third_party/blink/renderer/modules/webaudio/base_audio_context.h b/third_party/blink/renderer/modules/webaudio/base_audio_context.h
index 3b7e5e9ed..28cc56c 100644
--- a/third_party/blink/renderer/modules/webaudio/base_audio_context.h
+++ b/third_party/blink/renderer/modules/webaudio/base_audio_context.h
@@ -33,7 +33,7 @@
 #include "third_party/blink/renderer/bindings/modules/v8/v8_decode_error_callback.h"
 #include "third_party/blink/renderer/bindings/modules/v8/v8_decode_success_callback.h"
 #include "third_party/blink/renderer/core/dom/events/event_listener.h"
-#include "third_party/blink/renderer/core/execution_context/pausable_object.h"
+#include "third_party/blink/renderer/core/execution_context/context_lifecycle_state_observer.h"
 #include "third_party/blink/renderer/core/typed_arrays/array_buffer_view_helpers.h"
 #include "third_party/blink/renderer/core/typed_arrays/dom_typed_array.h"
 #include "third_party/blink/renderer/modules/event_target_modules.h"
@@ -91,7 +91,7 @@
 class MODULES_EXPORT BaseAudioContext
     : public EventTargetWithInlineData,
       public ActiveScriptWrappable<BaseAudioContext>,
-      public PausableObject {
+      public ContextLifecycleStateObserver {
   USING_GARBAGE_COLLECTED_MIXIN(BaseAudioContext);
   DEFINE_WRAPPERTYPEINFO();
 
@@ -119,8 +119,7 @@
   }
 
   // Document notification
-  void ContextPaused(PauseState) override;
-  void ContextUnpaused() override;
+  void ContextLifecycleStateChanged(mojom::FrameLifecycleState) override;
   void ContextDestroyed(ExecutionContext*) override;
   bool HasPendingActivity() const override;
 
diff --git a/third_party/blink/renderer/modules/webaudio/offline_audio_context.cc b/third_party/blink/renderer/modules/webaudio/offline_audio_context.cc
index a06711f..19db10f 100644
--- a/third_party/blink/renderer/modules/webaudio/offline_audio_context.cc
+++ b/third_party/blink/renderer/modules/webaudio/offline_audio_context.cc
@@ -93,7 +93,7 @@
       MakeGarbageCollected<OfflineAudioContext>(document, number_of_channels,
                                                 number_of_frames, sample_rate,
                                                 exception_state);
-  audio_context->PauseIfNeeded();
+  audio_context->UpdateStateIfNeeded();
 
 #if DEBUG_AUDIONODE_REFERENCES
   fprintf(stderr, "[%16p]: OfflineAudioContext::OfflineAudioContext()\n",
diff --git a/third_party/blink/renderer/modules/webaudio/offline_audio_destination_node.cc b/third_party/blink/renderer/modules/webaudio/offline_audio_destination_node.cc
index 306368f..026b3e9 100644
--- a/third_party/blink/renderer/modules/webaudio/offline_audio_destination_node.cc
+++ b/third_party/blink/renderer/modules/webaudio/offline_audio_destination_node.cc
@@ -394,7 +394,7 @@
   // The rendering thread might have been changed, so we need to set up the
   // task runner again.
   PrepareTaskRunnerForRendering();
-};
+}
 
 // ----------------------------------------------------------------
 
diff --git a/third_party/blink/renderer/modules/webaudio/panner_node.h b/third_party/blink/renderer/modules/webaudio/panner_node.h
index 775241fb..1e4c623 100644
--- a/third_party/blink/renderer/modules/webaudio/panner_node.h
+++ b/third_party/blink/renderer/modules/webaudio/panner_node.h
@@ -219,13 +219,13 @@
   void Trace(blink::Visitor*) override;
 
   // Uses a 3D cartesian coordinate system
-  AudioParam* positionX() const { return position_x_; };
-  AudioParam* positionY() const { return position_y_; };
-  AudioParam* positionZ() const { return position_z_; };
+  AudioParam* positionX() const { return position_x_; }
+  AudioParam* positionY() const { return position_y_; }
+  AudioParam* positionZ() const { return position_z_; }
 
-  AudioParam* orientationX() const { return orientation_x_; };
-  AudioParam* orientationY() const { return orientation_y_; };
-  AudioParam* orientationZ() const { return orientation_z_; };
+  AudioParam* orientationX() const { return orientation_x_; }
+  AudioParam* orientationY() const { return orientation_y_; }
+  AudioParam* orientationZ() const { return orientation_z_; }
 
   String panningModel() const;
   void setPanningModel(const String&);
diff --git a/third_party/blink/renderer/modules/webaudio/wave_shaper_processor.h b/third_party/blink/renderer/modules/webaudio/wave_shaper_processor.h
index b8390675..5e900ac 100644
--- a/third_party/blink/renderer/modules/webaudio/wave_shaper_processor.h
+++ b/third_party/blink/renderer/modules/webaudio/wave_shaper_processor.h
@@ -54,7 +54,7 @@
                uint32_t frames_to_process) override;
 
   void SetCurve(const float* curve_data, unsigned curve_length);
-  Vector<float>* Curve() const { return curve_.get(); };
+  Vector<float>* Curve() const { return curve_.get(); }
 
   void SetOversample(OverSampleType);
   OverSampleType Oversample() const { return oversample_; }
diff --git a/third_party/blink/renderer/modules/webgl/webgl2_rendering_context_base.h b/third_party/blink/renderer/modules/webgl/webgl2_rendering_context_base.h
index 730aa33..b5f58d7 100644
--- a/third_party/blink/renderer/modules/webgl/webgl2_rendering_context_base.h
+++ b/third_party/blink/renderer/modules/webgl/webgl2_rendering_context_base.h
@@ -1051,7 +1051,7 @@
                                 GLint drawbuffer);
 
   /* WebGLRenderingContextBase overrides */
-  unsigned GetMaxWebGLLocationLength() const override { return 1024; };
+  unsigned GetMaxWebGLLocationLength() const override { return 1024; }
   bool ValidateCapability(const char* function_name, GLenum) override;
   bool ValidateBufferTarget(const char* function_name, GLenum target) override;
   bool ValidateAndUpdateBufferBindTarget(const char* function_name,
diff --git a/third_party/blink/renderer/modules/websockets/dom_websocket.cc b/third_party/blink/renderer/modules/websockets/dom_websocket.cc
index b75ba88..021d001 100644
--- a/third_party/blink/renderer/modules/websockets/dom_websocket.cc
+++ b/third_party/blink/renderer/modules/websockets/dom_websocket.cc
@@ -236,7 +236,7 @@
 }
 
 DOMWebSocket::DOMWebSocket(ExecutionContext* context)
-    : PausableObject(context),
+    : ContextLifecycleStateObserver(context),
       state_(kConnecting),
       buffered_amount_(0),
       consumed_buffered_amount_(0),
@@ -278,7 +278,7 @@
   }
 
   DOMWebSocket* websocket = MakeGarbageCollected<DOMWebSocket>(context);
-  websocket->PauseIfNeeded();
+  websocket->UpdateStateIfNeeded();
 
   if (protocols.IsNull()) {
     Vector<String> protocols_vector;
@@ -672,7 +672,7 @@
 }
 
 ExecutionContext* DOMWebSocket::GetExecutionContext() const {
-  return PausableObject::GetExecutionContext();
+  return ContextLifecycleStateObserver::GetExecutionContext();
 }
 
 void DOMWebSocket::ContextDestroyed(ExecutionContext*) {
@@ -690,17 +690,18 @@
   return channel_ || !event_queue_->IsEmpty();
 }
 
-void DOMWebSocket::ContextPaused(PauseState) {
-  event_queue_->Pause();
-}
+void DOMWebSocket::ContextLifecycleStateChanged(
+    mojom::FrameLifecycleState state) {
+  if (state == mojom::FrameLifecycleState::kRunning) {
+    event_queue_->Unpause();
 
-void DOMWebSocket::ContextUnpaused() {
-  event_queue_->Unpause();
-
-  // If |consumed_buffered_amount_| was updated while the object was paused then
-  // the changes to |buffered_amount_| will not yet have been applied. Post
-  // another task to update it.
-  PostBufferedAmountUpdateTask();
+    // If |consumed_buffered_amount_| was updated while the object was paused
+    // then the changes to |buffered_amount_| will not yet have been applied.
+    // Post another task to update it.
+    PostBufferedAmountUpdateTask();
+  } else {
+    event_queue_->Pause();
+  }
 }
 
 void DOMWebSocket::DidConnect(const String& subprotocol,
@@ -896,7 +897,7 @@
   visitor->Trace(event_queue_);
   WebSocketChannelClient::Trace(visitor);
   EventTargetWithInlineData::Trace(visitor);
-  PausableObject::Trace(visitor);
+  ContextLifecycleStateObserver::Trace(visitor);
 }
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/modules/websockets/dom_websocket.h b/third_party/blink/renderer/modules/websockets/dom_websocket.h
index e4481bc..cdd772b 100644
--- a/third_party/blink/renderer/modules/websockets/dom_websocket.h
+++ b/third_party/blink/renderer/modules/websockets/dom_websocket.h
@@ -37,7 +37,7 @@
 #include "third_party/blink/renderer/bindings/core/v8/active_script_wrappable.h"
 #include "third_party/blink/renderer/core/dom/events/event_listener.h"
 #include "third_party/blink/renderer/core/dom/events/event_target.h"
-#include "third_party/blink/renderer/core/execution_context/pausable_object.h"
+#include "third_party/blink/renderer/core/execution_context/context_lifecycle_state_observer.h"
 #include "third_party/blink/renderer/core/typed_arrays/array_buffer_view_helpers.h"
 #include "third_party/blink/renderer/modules/event_target_modules.h"
 #include "third_party/blink/renderer/modules/modules_export.h"
@@ -63,7 +63,7 @@
 
 class MODULES_EXPORT DOMWebSocket : public EventTargetWithInlineData,
                                     public ActiveScriptWrappable<DOMWebSocket>,
-                                    public PausableObject,
+                                    public ContextLifecycleStateObserver,
                                     public WebSocketChannelClient {
   DEFINE_WRAPPERTYPEINFO();
   USING_GARBAGE_COLLECTED_MIXIN(DOMWebSocket);
@@ -122,10 +122,9 @@
   const AtomicString& InterfaceName() const override;
   ExecutionContext* GetExecutionContext() const override;
 
-  // PausableObject functions.
+  // ContextLifecycleStateObserver functions.
   void ContextDestroyed(ExecutionContext*) override;
-  void ContextPaused(PauseState) override;
-  void ContextUnpaused() override;
+  void ContextLifecycleStateChanged(mojom::FrameLifecycleState) override;
 
   // ScriptWrappable functions.
   // Prevent this instance from being collected while it's not in CLOSED
diff --git a/third_party/blink/renderer/modules/websockets/dom_websocket_test.cc b/third_party/blink/renderer/modules/websockets/dom_websocket_test.cc
index d46b134..8238d50 100644
--- a/third_party/blink/renderer/modules/websockets/dom_websocket_test.cc
+++ b/third_party/blink/renderer/modules/websockets/dom_websocket_test.cc
@@ -82,7 +82,7 @@
   static DOMWebSocketWithMockChannel* Create(ExecutionContext* context) {
     DOMWebSocketWithMockChannel* websocket =
         MakeGarbageCollected<DOMWebSocketWithMockChannel>(context);
-    websocket->PauseIfNeeded();
+    websocket->UpdateStateIfNeeded();
     return websocket;
   }
 
diff --git a/third_party/blink/renderer/modules/xr/xr.cc b/third_party/blink/renderer/modules/xr/xr.cc
index a13967d..5e7c5535 100644
--- a/third_party/blink/renderer/modules/xr/xr.cc
+++ b/third_party/blink/renderer/modules/xr/xr.cc
@@ -462,7 +462,7 @@
     // Make sure we have an active device to listen for changes with.
     EnsureDevice();
   }
-};
+}
 
 void XR::ContextDestroyed(ExecutionContext*) {
   Dispose();
diff --git a/third_party/blink/renderer/platform/audio/audio_processor.h b/third_party/blink/renderer/platform/audio/audio_processor.h
index 1fdd140..87e61c66 100644
--- a/third_party/blink/renderer/platform/audio/audio_processor.h
+++ b/third_party/blink/renderer/platform/audio/audio_processor.h
@@ -68,7 +68,7 @@
   // Forces all AudioParams in the processor to run the timeline,
   // bypassing any other processing the processor would do in
   // process().
-  virtual void ProcessOnlyAudioParams(uint32_t frames_to_process){};
+  virtual void ProcessOnlyAudioParams(uint32_t frames_to_process) {}
 
   // Resets filter state
   virtual void Reset() = 0;
diff --git a/third_party/blink/renderer/platform/audio/audio_source_provider.h b/third_party/blink/renderer/platform/audio/audio_source_provider.h
index d673dd9..0f5cfb4 100644
--- a/third_party/blink/renderer/platform/audio/audio_source_provider.h
+++ b/third_party/blink/renderer/platform/audio/audio_source_provider.h
@@ -53,7 +53,7 @@
 
   // If a client is set, we call it back when the audio format is available or
   // changes.
-  virtual void SetClient(AudioSourceProviderClient*){};
+  virtual void SetClient(AudioSourceProviderClient*) {}
 
   virtual ~AudioSourceProvider() = default;
 };
diff --git a/third_party/blink/renderer/platform/audio/panner.h b/third_party/blink/renderer/platform/audio/panner.h
index dd4f0ab..93a0eb9 100644
--- a/third_party/blink/renderer/platform/audio/panner.h
+++ b/third_party/blink/renderer/platform/audio/panner.h
@@ -56,7 +56,6 @@
                                         HRTFDatabaseLoader*);
 
   virtual ~Panner() = default;
-  ;
 
   virtual void Pan(double azimuth,
                    double elevation,
diff --git a/third_party/blink/renderer/platform/audio/stereo_panner.h b/third_party/blink/renderer/platform/audio/stereo_panner.h
index e06094e..91f8d0c 100644
--- a/third_party/blink/renderer/platform/audio/stereo_panner.h
+++ b/third_party/blink/renderer/platform/audio/stereo_panner.h
@@ -23,7 +23,6 @@
  public:
   static std::unique_ptr<StereoPanner> Create(float sample_rate);
   ~StereoPanner() = default;
-  ;
 
   void PanWithSampleAccurateValues(const AudioBus* input_bus,
                                    AudioBus* output_bus,
diff --git a/third_party/blink/renderer/platform/graphics/static_bitmap_image.cc b/third_party/blink/renderer/platform/graphics/static_bitmap_image.cc
index 8550cb7b..7b6ef7e 100644
--- a/third_party/blink/renderer/platform/graphics/static_bitmap_image.cc
+++ b/third_party/blink/renderer/platform/graphics/static_bitmap_image.cc
@@ -88,34 +88,14 @@
   // If we don't need to change the color type, use SkImage::makeColorSpace()
   if (skia_image->colorType() == color_type) {
     skia_image = skia_image->makeColorSpace(color_space);
-    return StaticBitmapImage::Create(skia_image, skia_image->isTextureBacked()
-                                                     ? ContextProviderWrapper()
-                                                     : nullptr);
-  }
-
-  // Otherwise we need to create a surface and redraw the image as it is a
-  // different size in memory
-  SkImageInfo info =
-      SkImageInfo::Make(skia_image->width(), skia_image->height(), color_type,
-                        skia_image->alphaType(), color_space);
-  sk_sp<SkSurface> surface = nullptr;
-  if (skia_image->isTextureBacked()) {
-    GrContext* gr = ContextProviderWrapper()->ContextProvider()->GetGrContext();
-    surface = SkSurface::MakeRenderTarget(gr, SkBudgeted::kNo, info);
   } else {
-    surface = SkSurface::MakeRaster(info);
+    skia_image =
+        skia_image->makeColorTypeAndColorSpace(color_type, color_space);
   }
-  SkPaint paint;
-  surface->getCanvas()->drawImage(skia_image, 0, 0, &paint);
-  sk_sp<SkImage> converted_skia_image = surface->makeImageSnapshot();
 
-  DCHECK(converted_skia_image.get());
-  DCHECK(skia_image.get() != converted_skia_image.get());
-
-  return StaticBitmapImage::Create(converted_skia_image,
-                                   converted_skia_image->isTextureBacked()
-                                       ? ContextProviderWrapper()
-                                       : nullptr);
+  return StaticBitmapImage::Create(skia_image, skia_image->isTextureBacked()
+                                                   ? ContextProviderWrapper()
+                                                   : nullptr);
 }
 
 bool StaticBitmapImage::ConvertToArrayBufferContents(
diff --git a/third_party/blink/renderer/platform/heap/name_trait_test.cc b/third_party/blink/renderer/platform/heap/name_trait_test.cc
index fac0052b..08203bd 100644
--- a/third_party/blink/renderer/platform/heap/name_trait_test.cc
+++ b/third_party/blink/renderer/platform/heap/name_trait_test.cc
@@ -21,7 +21,7 @@
  public:
   ClassWithName(const char* name) : name_(name) {}
 
-  const char* NameInHeapSnapshot() const final { return name_; };
+  const char* NameInHeapSnapshot() const final { return name_; }
 
  private:
   const char* name_;
diff --git a/third_party/blink/renderer/platform/instance_counters.h b/third_party/blink/renderer/platform/instance_counters.h
index f0dc08fa..60296b80 100644
--- a/third_party/blink/renderer/platform/instance_counters.h
+++ b/third_party/blink/renderer/platform/instance_counters.h
@@ -38,24 +38,24 @@
 
 namespace blink {
 
-#define INSTANCE_COUNTERS_LIST(V) \
-  V(AudioHandler)                 \
-  V(Document)                     \
-  V(Frame)                        \
-  V(JSEventListener)              \
-  V(LayoutObject)                 \
-  V(MediaKeySession)              \
-  V(MediaKeys)                    \
-  V(Node)                         \
-  V(Resource)                     \
-  V(ScriptPromise)                \
-  V(PausableObject)               \
-  V(V8PerContextData)             \
-  V(WorkerGlobalScope)            \
-  V(UACSSResource)                \
-  V(RTCPeerConnection)            \
-  V(ResourceFetcher)              \
-  V(AdSubframe)                   \
+#define INSTANCE_COUNTERS_LIST(V)  \
+  V(AudioHandler)                  \
+  V(Document)                      \
+  V(Frame)                         \
+  V(JSEventListener)               \
+  V(LayoutObject)                  \
+  V(MediaKeySession)               \
+  V(MediaKeys)                     \
+  V(Node)                          \
+  V(Resource)                      \
+  V(ScriptPromise)                 \
+  V(ContextLifecycleStateObserver) \
+  V(V8PerContextData)              \
+  V(WorkerGlobalScope)             \
+  V(UACSSResource)                 \
+  V(RTCPeerConnection)             \
+  V(ResourceFetcher)               \
+  V(AdSubframe)                    \
   V(DetachedScriptState)
 
 // Atomic counters of the number of instances of objects that exist.
diff --git a/third_party/blink/renderer/platform/runtime_enabled_features.json5 b/third_party/blink/renderer/platform/runtime_enabled_features.json5
index ac4d82e..7cf1d63b 100644
--- a/third_party/blink/renderer/platform/runtime_enabled_features.json5
+++ b/third_party/blink/renderer/platform/runtime_enabled_features.json5
@@ -5,7 +5,15 @@
   // a class that stores static enablers for all experimental features.
 
   parameters: {
-    // Each feature can be assigned a "status":
+    // Each feature can be assigned a "status". The "status" can be either
+    // one of the values in the |valid_values| list or a dictionary of
+    // the platforms listed in |valid_keys| to |valid_values|.
+    // Use "default" as the key if you want to specify the status of
+    // the platforms other than the ones declared in the dictionary.
+    // ** Omitting "default" means the feature is not enabled on
+    // the platforms not listed in the status dictionary
+    //
+    // Definition of each status:
     // * status=stable: Enable this in all Blink configurations. We are
     //   committed to these APIs indefinitely.
     // * status=experimental: In-progress features, Web Developers might play
@@ -13,10 +21,19 @@
     // * status=test: Enabled in ContentShell for testing, otherwise off.
     // Features without a status are not enabled anywhere by default.
     //
+    // Example of the dictionary value use:
+    // {
+    //   name: "ExampleFeature",
+    //   status: {"Android": "stable", "ChromeOS": "experimental"},
+    // }
+    // "ExampleFeature" will be stable on Android, experimental on ChromeOS
+    // and not enabled on any other platform
+    //
     // "stable" features listed here should be rare, as anything which we've
     // shipped stable can have its runtime flag removed soon after.
     status: {
       valid_values: ["stable", "experimental", "test"],
+      valid_keys: ["Android", "Win", "ChromeOS", "MacOSX"]
     },
 
     // "implied_by" or "depends_on" specifies relationship to other features:
diff --git a/third_party/blink/renderer/platform/scheduler/common/scheduler_helper_unittest.cc b/third_party/blink/renderer/platform/scheduler/common/scheduler_helper_unittest.cc
index 160845cf..b260c0c 100644
--- a/third_party/blink/renderer/platform/scheduler/common/scheduler_helper_unittest.cc
+++ b/third_party/blink/renderer/platform/scheduler/common/scheduler_helper_unittest.cc
@@ -45,7 +45,7 @@
   }
 }
 
-};  // namespace
+}  // namespace
 
 class SchedulerHelperTest : public testing::Test {
  public:
diff --git a/third_party/blink/renderer/platform/scheduler/common/unprioritized_resource_loading_task_runner_handle.cc b/third_party/blink/renderer/platform/scheduler/common/unprioritized_resource_loading_task_runner_handle.cc
index ba2f87a..7565562 100644
--- a/third_party/blink/renderer/platform/scheduler/common/unprioritized_resource_loading_task_runner_handle.cc
+++ b/third_party/blink/renderer/platform/scheduler/common/unprioritized_resource_loading_task_runner_handle.cc
@@ -16,7 +16,7 @@
 UnprioritizedResourceLoadingTaskRunnerHandle::
     UnprioritizedResourceLoadingTaskRunnerHandle(
         scoped_refptr<base::SingleThreadTaskRunner> task_runner)
-    : task_runner_(std::move(task_runner)){};
+    : task_runner_(std::move(task_runner)) {}
 
 scoped_refptr<base::SingleThreadTaskRunner>
 UnprioritizedResourceLoadingTaskRunnerHandle::GetTaskRunner() const {
diff --git a/third_party/blink/renderer/platform/scheduler/main_thread/deadline_task_runner_unittest.cc b/third_party/blink/renderer/platform/scheduler/main_thread/deadline_task_runner_unittest.cc
index ecd64de..06b77b1e 100644
--- a/third_party/blink/renderer/platform/scheduler/main_thread/deadline_task_runner_unittest.cc
+++ b/third_party/blink/renderer/platform/scheduler/main_thread/deadline_task_runner_unittest.cc
@@ -52,7 +52,7 @@
   task_environment_.FastForwardUntilNoTasksRemain();
 
   EXPECT_THAT(run_times_, testing::ElementsAre(start_time + delay));
-};
+}
 
 TEST_F(DeadlineTaskRunnerTest, RunTwice) {
   base::TimeDelta delay1 = base::TimeDelta::FromMilliseconds(10);
@@ -66,7 +66,7 @@
   task_environment_.FastForwardUntilNoTasksRemain();
 
   EXPECT_THAT(run_times_, testing::ElementsAre(deadline1, deadline2));
-};
+}
 
 TEST_F(DeadlineTaskRunnerTest, EarlierDeadlinesTakePrecidence) {
   base::TimeTicks start_time = Now();
@@ -79,7 +79,7 @@
   task_environment_.FastForwardUntilNoTasksRemain();
 
   EXPECT_THAT(run_times_, testing::ElementsAre(start_time + delay1));
-};
+}
 
 TEST_F(DeadlineTaskRunnerTest, LaterDeadlinesIgnored) {
   base::TimeTicks start_time = Now();
@@ -90,7 +90,7 @@
   task_environment_.FastForwardUntilNoTasksRemain();
 
   EXPECT_THAT(run_times_, testing::ElementsAre(start_time + delay100));
-};
+}
 
 TEST_F(DeadlineTaskRunnerTest, DeleteDeadlineTaskRunnerAfterPosting) {
   deadline_task_runner_->SetDeadline(
@@ -101,7 +101,7 @@
   task_environment_.FastForwardUntilNoTasksRemain();
 
   EXPECT_TRUE(run_times_.empty());
-};
+}
 
 }  // namespace scheduler
 }  // namespace blink
diff --git a/third_party/blink/renderer/platform/scheduler/main_thread/main_thread.h b/third_party/blink/renderer/platform/scheduler/main_thread/main_thread.h
index 8bca7f0..794259a7 100644
--- a/third_party/blink/renderer/platform/scheduler/main_thread/main_thread.h
+++ b/third_party/blink/renderer/platform/scheduler/main_thread/main_thread.h
@@ -13,7 +13,7 @@
 
 namespace blink {
 class ThreadScheduler;
-};
+}
 
 namespace blink {
 namespace scheduler {
diff --git a/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_metrics_helper_unittest.cc b/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_metrics_helper_unittest.cc
index 435fd1a..4e4a9f2 100644
--- a/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_metrics_helper_unittest.cc
+++ b/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_metrics_helper_unittest.cc
@@ -33,7 +33,7 @@
       std::unique_ptr<base::sequence_manager::SequenceManager> sequence_manager,
       base::Optional<base::Time> initial_virtual_time)
       : MainThreadSchedulerImpl(std::move(sequence_manager),
-                                initial_virtual_time){};
+                                initial_virtual_time) {}
 
   using MainThreadSchedulerImpl::SetCurrentUseCaseForTest;
 };
diff --git a/third_party/blink/renderer/platform/scheduler/main_thread/resource_loading_task_runner_handle_impl.cc b/third_party/blink/renderer/platform/scheduler/main_thread/resource_loading_task_runner_handle_impl.cc
index 6e0ef04..cf410ff 100644
--- a/third_party/blink/renderer/platform/scheduler/main_thread/resource_loading_task_runner_handle_impl.cc
+++ b/third_party/blink/renderer/platform/scheduler/main_thread/resource_loading_task_runner_handle_impl.cc
@@ -24,7 +24,7 @@
     scoped_refptr<MainThreadTaskQueue> task_queue)
     : task_queue_(std::move(task_queue)),
       task_runner_(task_queue_->CreateTaskRunner(
-          TaskType::kNetworkingWithURLLoaderAnnotation)){};
+          TaskType::kNetworkingWithURLLoaderAnnotation)) {}
 
 ResourceLoadingTaskRunnerHandleImpl::~ResourceLoadingTaskRunnerHandleImpl() {
   if (task_queue_->GetFrameScheduler()) {
diff --git a/third_party/blink/renderer/platform/scheduler/public/thread_cpu_throttler.h b/third_party/blink/renderer/platform/scheduler/public/thread_cpu_throttler.h
index 6f02b7a..03b1105e 100644
--- a/third_party/blink/renderer/platform/scheduler/public/thread_cpu_throttler.h
+++ b/third_party/blink/renderer/platform/scheduler/public/thread_cpu_throttler.h
@@ -13,7 +13,7 @@
 namespace base {
 template <typename T>
 struct DefaultSingletonTraits;
-};
+}
 
 namespace blink {
 namespace scheduler {
diff --git a/third_party/blink/renderer/platform/scheduler/test/fuzzer/task_queue_with_voters.h b/third_party/blink/renderer/platform/scheduler/test/fuzzer/task_queue_with_voters.h
index 20036c9..641055bf 100644
--- a/third_party/blink/renderer/platform/scheduler/test/fuzzer/task_queue_with_voters.h
+++ b/third_party/blink/renderer/platform/scheduler/test/fuzzer/task_queue_with_voters.h
@@ -16,7 +16,7 @@
 
 struct PLATFORM_EXPORT TaskQueueWithVoters {
   explicit TaskQueueWithVoters(scoped_refptr<TestTaskQueue> task_queue)
-      : queue(std::move(task_queue)){};
+      : queue(std::move(task_queue)) {}
 
   scoped_refptr<TestTaskQueue> queue;
   std::vector<std::unique_ptr<TaskQueue::QueueEnabledVoter>> voters;
diff --git a/third_party/blink/renderer/platform/scheduler/test/fuzzer/thread_pool_manager.cc b/third_party/blink/renderer/platform/scheduler/test/fuzzer/thread_pool_manager.cc
index bd01bd1..a9dae64 100644
--- a/third_party/blink/renderer/platform/scheduler/test/fuzzer/thread_pool_manager.cc
+++ b/third_party/blink/renderer/platform/scheduler/test/fuzzer/thread_pool_manager.cc
@@ -25,7 +25,7 @@
       all_threads_ready_(true),
       initial_threads_created_(false) {
   DCHECK(processor_);
-};
+}
 
 ThreadPoolManager::~ThreadPoolManager() = default;
 
diff --git a/third_party/blink/web_tests/FlagExpectations/enable-blink-features=LayoutNG b/third_party/blink/web_tests/FlagExpectations/enable-blink-features=LayoutNG
index fcaa534..ce2b242 100644
--- a/third_party/blink/web_tests/FlagExpectations/enable-blink-features=LayoutNG
+++ b/third_party/blink/web_tests/FlagExpectations/enable-blink-features=LayoutNG
@@ -89,9 +89,23 @@
 
 # New failures are appended below by the script.
 crbug.com/591099 bluetooth/characteristic/notifications/notification-after-disconnection.html [ Pass ]
+crbug.com/591099 bluetooth/server/getPrimaryService/gen-reconnect-during-error.html [ Crash Pass ]
+crbug.com/591099 compositing/animation/busy-indicator.html [ Pass ]
+crbug.com/591099 compositing/scrollbars/nested-overlay-scrollbars.html [ Failure ]
 crbug.com/591099 css3/filters/composited-layer-child-bounds-after-composited-to-sw-shadow-change.html [ Failure ]
+crbug.com/591099 css3/filters/effect-drop-shadow-hw.html [ Pass ]
+crbug.com/591099 css3/filters/effect-reference-colorspace-hw.html [ Failure ]
+crbug.com/591099 css3/filters/effect-reference.html [ Failure ]
+crbug.com/591099 css3/filters/filter-repaint-composited-fallback-crash.html [ Pass ]
+crbug.com/591099 css3/filters/filter-repaint-composited-fallback.html [ Pass ]
 crbug.com/591099 css3/flexbox/intrinsic-width-orthogonal-writing-mode.html [ Failure ]
 crbug.com/591099 editing/selection/paint-hyphen.html [ Pass ]
+crbug.com/591099 external/wpt/WebCryptoAPI/derive_bits_keys/pbkdf2.https.any.html?1001-2000 [ Pass ]
+crbug.com/591099 external/wpt/WebCryptoAPI/derive_bits_keys/pbkdf2.https.any.html?2001-3000 [ Pass ]
+crbug.com/591099 external/wpt/WebCryptoAPI/derive_bits_keys/pbkdf2.https.any.html?3001-4000 [ Pass ]
+crbug.com/591099 external/wpt/WebCryptoAPI/derive_bits_keys/pbkdf2.https.any.html?6001-7000 [ Pass ]
+crbug.com/591099 external/wpt/WebCryptoAPI/derive_bits_keys/pbkdf2.https.any.html?7001-8000 [ Pass ]
+crbug.com/591099 external/wpt/WebCryptoAPI/generateKey/successes_RSA-OAEP.https.any.worker.html?121-130 [ Pass ]
 crbug.com/591099 external/wpt/bluetooth/requestDevice/request-from-iframe.https.html [ Pass ]
 crbug.com/591099 external/wpt/bluetooth/server/disconnect/detach-gc.https.html [ Pass ]
 crbug.com/591099 external/wpt/bluetooth/server/disconnect/gc-detach.https.html [ Pass ]
@@ -103,8 +117,12 @@
 crbug.com/591099 external/wpt/bluetooth/service/getCharacteristic/gen-reconnect-during.https.html [ Pass ]
 crbug.com/591099 external/wpt/bluetooth/service/getCharacteristics/gen-reconnect-during-with-uuid.https.html [ Pass ]
 crbug.com/591099 external/wpt/bluetooth/service/getCharacteristics/gen-reconnect-during.https.html [ Pass ]
+crbug.com/591099 external/wpt/content-security-policy/securitypolicyviolation/img-src-redirect-upgrade-reporting.https.html [ Timeout ]
+crbug.com/591099 external/wpt/cookies/http-state/domain-tests.html [ Pass ]
+crbug.com/591099 external/wpt/cookies/samesite/window-open-reload.html [ Failure ]
 crbug.com/591099 external/wpt/css/CSS2/floats/float-nowrap-3.html [ Pass ]
 crbug.com/591099 external/wpt/css/CSS2/floats/floats-line-wrap-shifted-001.html [ Pass ]
+crbug.com/591099 external/wpt/css/CSS2/floats/floats-wrap-bfc-006.xht [ Failure ]
 crbug.com/591099 external/wpt/css/CSS2/normal-flow/block-in-inline-empty-001.xht [ Pass ]
 crbug.com/591099 external/wpt/css/CSS2/normal-flow/block-in-inline-empty-004.xht [ Pass ]
 crbug.com/591099 external/wpt/css/CSS2/normal-flow/block-in-inline-insert-001e.xht [ Pass ]
@@ -113,9 +131,25 @@
 crbug.com/591099 external/wpt/css/CSS2/normal-flow/block-in-inline-nested-002.xht [ Pass ]
 crbug.com/591099 external/wpt/css/CSS2/normal-flow/block-in-inline-remove-006.xht [ Pass ]
 crbug.com/591099 external/wpt/css/CSS2/text/white-space-mixed-003.xht [ Pass ]
+crbug.com/591099 external/wpt/css/css-animations/Element-getAnimations-dynamic-changes.tentative.html [ Failure ]
+crbug.com/591099 external/wpt/css/css-animations/Element-getAnimations.tentative.html [ Pass ]
+crbug.com/591099 external/wpt/css/css-contain/contain-size-grid-002.html [ Failure ]
+crbug.com/591099 external/wpt/css/css-contain/contain-size-multicol-001.html [ Failure ]
+crbug.com/591099 external/wpt/css/css-contain/contain-style-counters-004.html [ Failure ]
 crbug.com/714962 external/wpt/css/css-fonts/font-features-across-space-1.html [ Pass ]
 crbug.com/714962 external/wpt/css/css-fonts/font-features-across-space-3.html [ Pass ]
+crbug.com/591099 external/wpt/css/css-fonts/font-synthesis-05.html [ Failure ]
+crbug.com/591099 external/wpt/css/css-fonts/font-variant-alternates-03.html [ Failure ]
+crbug.com/591099 external/wpt/css/css-fonts/font-variant-position-01.html [ Failure ]
+crbug.com/591099 external/wpt/css/css-grid/grid-model/grid-container-ignores-first-letter-002.html [ Failure ]
 crbug.com/919818 external/wpt/css/css-lists/list-and-block-textarea-001.html [ Failure ]
+crbug.com/591099 external/wpt/css/css-masking/clip-path-svg-content/mask-userspaceonuse-content-clip.svg [ Failure ]
+crbug.com/591099 external/wpt/css/css-masking/clip-path/clip-path-circle-008.html [ Failure ]
+crbug.com/591099 external/wpt/css/css-masking/clip-path/clip-path-ellipse-007.html [ Failure ]
+crbug.com/591099 external/wpt/css/css-masking/clip-path/clip-path-polygon-010.html [ Failure ]
+crbug.com/591099 external/wpt/css/css-multicol/multicol-span-all-005.html [ Failure ]
+crbug.com/591099 external/wpt/css/css-position/position-relative-table-tbody-top-absolute-child.html [ Failure ]
+crbug.com/591099 external/wpt/css/css-position/position-relative-table-tr-left-absolute-child.html [ Failure ]
 crbug.com/591099 external/wpt/css/css-position/static-position/htb-ltr-rtl.tentative.html [ Pass ]
 crbug.com/591099 external/wpt/css/css-position/static-position/htb-rtl-ltr.tentative.html [ Pass ]
 crbug.com/591099 external/wpt/css/css-position/static-position/htb-rtl-rtl.html [ Pass ]
@@ -126,8 +160,15 @@
 crbug.com/591099 external/wpt/css/css-position/static-position/vrl-rtl-ltr.tentative.html [ Pass ]
 crbug.com/591099 external/wpt/css/css-position/static-position/vrl-rtl-rtl.html [ Pass ]
 crbug.com/591099 external/wpt/css/css-rhythm/ [ Skip ]
+crbug.com/591099 external/wpt/css/css-shapes/shape-outside/shape-image/gradients/shape-outside-linear-gradient-006.html [ Failure ]
 crbug.com/591099 external/wpt/css/css-shapes/shape-outside/supported-shapes/polygon/shape-outside-polygon-017.html [ Pass ]
 crbug.com/845902 external/wpt/css/css-sizing/whitespace-and-break.html [ Pass ]
+crbug.com/591099 external/wpt/css/css-tables/table-has-box-sizing-border-box-002.html [ Failure ]
+crbug.com/591099 external/wpt/css/css-tables/visibility-collapse-col-002.html [ Failure ]
+crbug.com/591099 external/wpt/css/css-tables/visibility-collapse-colspan-002.html [ Failure ]
+crbug.com/591099 external/wpt/css/css-text-decor/text-emphasis-position-above-left-001.xht [ Failure ]
+crbug.com/591099 external/wpt/css/css-text-decor/text-emphasis-position-above-right-001.xht [ Failure ]
+crbug.com/591099 external/wpt/css/css-text-decor/text-emphasis-style-filled-001.xht [ Failure ]
 crbug.com/591099 external/wpt/css/css-text/boundary-shaping/boundary-shaping-001.html [ Pass ]
 crbug.com/591099 external/wpt/css/css-text/boundary-shaping/boundary-shaping-002.html [ Failure ]
 crbug.com/591099 external/wpt/css/css-text/boundary-shaping/boundary-shaping-006.html [ Failure ]
@@ -138,12 +179,23 @@
 crbug.com/591099 external/wpt/css/css-text/line-breaking/line-breaking-011.html [ Pass ]
 crbug.com/591099 external/wpt/css/css-text/line-breaking/line-breaking-ic-002.html [ Pass ]
 crbug.com/591099 external/wpt/css/css-text/line-breaking/line-breaking-ic-003.html [ Pass ]
+crbug.com/591099 external/wpt/css/css-text/overflow-wrap/overflow-wrap-anywhere-001.html [ Failure ]
 crbug.com/591099 external/wpt/css/css-text/overflow-wrap/overflow-wrap-break-word-005.html [ Failure ]
+crbug.com/591099 external/wpt/css/css-text/text-indent/text-indent-percentage-004.html [ Failure ]
+crbug.com/591099 external/wpt/css/css-text/text-transform/text-transform-capitalize-028.html [ Failure ]
 crbug.com/591099 external/wpt/css/css-text/white-space/line-edge-white-space-collapse-001.html [ Pass ]
 crbug.com/591099 external/wpt/css/css-text/white-space/line-edge-white-space-collapse-002.html [ Pass ]
+crbug.com/591099 external/wpt/css/css-text/white-space/pre-wrap-012.html [ Failure ]
 crbug.com/40634 external/wpt/css/css-text/white-space/trailing-space-before-br-001.html [ Pass ]
 crbug.com/591099 external/wpt/css/css-text/word-break/word-break-break-all-004.html [ Pass ]
+crbug.com/591099 external/wpt/css/css-transforms/transform-box/view-box-mutation.html [ Failure ]
+crbug.com/591099 external/wpt/css/css-transitions/properties-value-003.html [ Pass ]
 crbug.com/591099 external/wpt/css/css-ui/text-overflow-010.html [ Pass ]
+crbug.com/591099 external/wpt/css/css-ui/text-overflow-026.html [ Failure ]
+crbug.com/591099 external/wpt/css/css-values/attr-invalid-type-008.html [ Failure ]
+crbug.com/591099 external/wpt/css/css-values/calc-positive-fraction-001.html [ Failure ]
+crbug.com/591099 external/wpt/css/css-values/ic-unit-009.html [ Failure ]
+crbug.com/591099 external/wpt/css/css-values/ic-unit-012.html [ Failure ]
 crbug.com/591099 external/wpt/css/css-writing-modes/abs-pos-non-replaced-icb-vlr-003.xht [ Pass ]
 crbug.com/591099 external/wpt/css/css-writing-modes/abs-pos-non-replaced-icb-vlr-005.xht [ Pass ]
 crbug.com/591099 external/wpt/css/css-writing-modes/abs-pos-non-replaced-icb-vlr-011.xht [ Pass ]
@@ -219,8 +271,11 @@
 crbug.com/591099 external/wpt/css/css-writing-modes/abs-pos-non-replaced-vrl-224.xht [ Pass ]
 crbug.com/591099 external/wpt/css/css-writing-modes/available-size-002.html [ Pass ]
 crbug.com/591099 external/wpt/css/css-writing-modes/available-size-010.html [ Pass ]
+crbug.com/591099 external/wpt/css/css-writing-modes/available-size-013.html [ Failure ]
 crbug.com/591099 external/wpt/css/css-writing-modes/available-size-017.html [ Pass ]
+crbug.com/591099 external/wpt/css/css-writing-modes/baseline-with-orthogonal-flow-001.html [ Pass ]
 crbug.com/591099 external/wpt/css/css-writing-modes/block-flow-direction-vrl-009.xht [ Pass ]
+crbug.com/591099 external/wpt/css/css-writing-modes/clip-rect-vrl-006.xht [ Failure ]
 crbug.com/591099 external/wpt/css/css-writing-modes/inline-box-border-vlr-001.html [ Pass ]
 crbug.com/591099 external/wpt/css/css-writing-modes/line-box-direction-vrl-009.xht [ Pass ]
 crbug.com/591099 external/wpt/css/css-writing-modes/line-box-height-vlr-021.xht [ Pass ]
@@ -231,18 +286,36 @@
 crbug.com/591099 external/wpt/css/css-writing-modes/sizing-orthog-prct-vrl-in-htb-001.xht [ Pass ]
 crbug.com/591099 external/wpt/css/css-writing-modes/sizing-orthog-vrl-in-htb-001.xht [ Pass ]
 crbug.com/591099 external/wpt/css/css-writing-modes/sizing-orthog-vrl-in-htb-004.xht [ Pass ]
+crbug.com/591099 external/wpt/css/css-writing-modes/text-orientation-script-001f.html [ Pass ]
+crbug.com/591099 external/wpt/css/css-writing-modes/text-orientation-script-001j.html [ Pass ]
+crbug.com/591099 external/wpt/css/css-writing-modes/text-orientation-script-001n.html [ Pass ]
 crbug.com/591099 external/wpt/css/css-writing-modes/vertical-alignment-003.xht [ Pass ]
 crbug.com/591099 external/wpt/css/css-writing-modes/vertical-alignment-009.xht [ Pass ]
 crbug.com/591099 external/wpt/css/cssom-view/elementsFromPoint-inline-vrl-ltr.html [ Pass ]
 crbug.com/591099 external/wpt/css/cssom-view/elementsFromPoint-inline-vrl-rtl.html [ Pass ]
 crbug.com/591099 external/wpt/css/cssom-view/offsetTopLeftInline.html [ Pass ]
+crbug.com/591099 external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/align3/flex-abspos-staticpos-align-self-004.html [ Failure ]
+crbug.com/591099 external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/align3/flex-abspos-staticpos-align-self-vertWM-003.html [ Failure ]
+crbug.com/591099 external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/align3/flex-abspos-staticpos-justify-content-003.html [ Failure ]
+crbug.com/591099 external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/align3/flex-abspos-staticpos-justify-content-007.html [ Failure ]
+crbug.com/591099 external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/align3/flex-abspos-staticpos-justify-content-vertWM-002.html [ Failure ]
+crbug.com/591099 external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/align3/grid-abspos-staticpos-align-self-001.html [ Failure ]
+crbug.com/591099 external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/align3/grid-abspos-staticpos-align-self-vertWM-004.html [ Failure ]
+crbug.com/591099 external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/align3/grid-abspos-staticpos-justify-self-vertWM-001.html [ Failure ]
+crbug.com/591099 external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/counter-styles-3/descriptor-suffix.html [ Failure ]
+crbug.com/591099 external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/counter-styles-3/redefine-builtin.html [ Failure ]
 crbug.com/591099 external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/flexbox/flexbox-align-self-horiz-002.xhtml [ Pass ]
+crbug.com/591099 external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/flexbox/flexbox-align-self-vert-002.xhtml [ Failure ]
+crbug.com/591099 external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/flexbox/flexbox-collapsed-item-horiz-002.html [ Failure ]
+crbug.com/591099 external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/flexbox/flexbox-justify-content-horiz-003.xhtml [ Failure ]
+crbug.com/591099 external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/flexbox/flexbox-writing-mode-011.html [ Pass ]
 crbug.com/591099 external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/ib-split/emptyspan-1.html [ Pass ]
 crbug.com/591099 external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/ib-split/emptyspan-4.html [ Pass ]
 crbug.com/591099 external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/ib-split/remove-from-split-inline-6.html [ Pass ]
 crbug.com/591099 external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/ib-split/split-inner-inline-2.html [ Pass ]
 crbug.com/591099 external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/shapes1/shape-outside-border-box-border-radius-003.html [ Pass ]
 crbug.com/591099 external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/shapes1/shape-outside-border-box-border-radius-004.html [ Pass ]
+crbug.com/591099 external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/shapes1/shape-outside-border-box-border-radius-011.html [ Failure ]
 crbug.com/591099 external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/shapes1/shape-outside-circle-042.html [ Pass ]
 crbug.com/591099 external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/shapes1/shape-outside-circle-044.html [ Pass ]
 crbug.com/591099 external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/shapes1/shape-outside-circle-050.html [ Pass ]
@@ -255,68 +328,195 @@
 crbug.com/591099 external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/shapes1/shape-outside-margin-box-border-radius-004.html [ Pass ]
 crbug.com/591099 external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/shapes1/shape-outside-margin-box-border-radius-008.html [ Pass ]
 crbug.com/591099 external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/shapes1/shape-outside-padding-box-border-radius-002.html [ Pass ]
+crbug.com/591099 external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/writing-modes-3/text-combine-upright-compression-002.html [ Failure ]
 crbug.com/591099 external/wpt/dom/events/EventListener-addEventListener.sub.window.html [ Pass ]
+crbug.com/591099 external/wpt/dom/ranges/Range-insertNode.html [ Pass ]
 crbug.com/591099 external/wpt/encoding/legacy-mb-korean/euc-kr/euckr-decode-ksc_5601.html [ Pass ]
+crbug.com/591099 external/wpt/event-timing/event-timing-bufferbeforeonload.html [ Pass ]
+crbug.com/591099 external/wpt/fetch/api/abort/general.any.html [ Pass ]
+crbug.com/591099 external/wpt/fetch/api/cors/cors-redirect-preflight.any.html [ Pass ]
 crbug.com/591099 external/wpt/fetch/api/redirect/redirect-count.any.html [ Pass ]
 crbug.com/591099 external/wpt/fetch/api/redirect/redirect-count.any.worker.html [ Pass ]
+crbug.com/591099 external/wpt/fetch/api/request/request-keepalive-quota.html?include=slow-1 [ Pass ]
 crbug.com/591099 external/wpt/fetch/api/request/request-keepalive-quota.html?include=slow-2 [ Pass ]
+crbug.com/591099 external/wpt/fetch/api/response/response-clone.html [ Pass ]
+crbug.com/591099 external/wpt/fetch/http-cache/cc-request.html [ Pass ]
 crbug.com/591099 external/wpt/fullscreen/api/element-ready-check-containing-iframe-manual.html [ Pass ]
-crbug.com/591099 external/wpt/geolocation-API/PositionOptions.https.html [ Failure Pass ]
-crbug.com/591099 external/wpt/html/browsers/origin/cross-origin-objects/cross-origin-objects.html [ Crash Pass ]
+crbug.com/591099 external/wpt/fullscreen/api/element-request-fullscreen-and-remove-manual.html [ Failure Pass ]
+crbug.com/591099 external/wpt/geolocation-API/PositionOptions.https.html [ Failure ]
+crbug.com/591099 external/wpt/html/browsers/origin/cross-origin-objects/cross-origin-objects.html [ Pass ]
 crbug.com/591099 external/wpt/html/browsers/the-window-object/window-open-noopener.html?_parent [ Pass ]
 crbug.com/591099 external/wpt/html/browsers/the-window-object/window-open-noopener.html?_top [ Pass ]
 crbug.com/591099 external/wpt/html/dom/interfaces.worker.html [ Pass ]
+crbug.com/591099 external/wpt/html/rendering/non-replaced-elements/the-hr-element-0/width.html [ Failure ]
+crbug.com/591099 external/wpt/html/rendering/non-replaced-elements/the-page/body-margin-1i.html [ Failure ]
+crbug.com/591099 external/wpt/html/semantics/embedded-content/media-elements/track/track-element/track-cues-cuechange.html [ Pass ]
 crbug.com/591099 external/wpt/html/semantics/embedded-content/the-embed-element/embed-represent-nothing-02.html [ Pass ]
+crbug.com/591099 external/wpt/html/semantics/links/links-created-by-a-and-area-elements/target_blank_implicit_noopener.tentative.html [ Pass Timeout ]
+crbug.com/591099 external/wpt/html/semantics/scripting-1/the-script-element/execution-timing/111.html [ Pass ]
+crbug.com/591099 external/wpt/html/semantics/scripting-1/the-script-element/module/dynamic-import/no-active-script-manual-module.html [ Timeout ]
+crbug.com/591099 external/wpt/html/semantics/tabular-data/processing-model-1/span-limits.html [ Pass ]
+crbug.com/591099 external/wpt/longtask-timing/longtask-in-sibling-iframe.html [ Pass ]
+crbug.com/591099 external/wpt/mediacapture-fromelement/ended.html [ Pass ]
+crbug.com/591099 external/wpt/offscreen-canvas/drawing-images-to-the-canvas/2d.drawImage.9arg.destsize.worker.html [ Pass ]
+crbug.com/591099 external/wpt/offscreen-canvas/drawing-images-to-the-canvas/2d.drawImage.self.1.worker.html [ Pass ]
+crbug.com/591099 external/wpt/offscreen-canvas/drawing-images-to-the-canvas/2d.drawImage.transform.worker.html [ Pass ]
+crbug.com/591099 external/wpt/offscreen-canvas/drawing-images-to-the-canvas/2d.drawImage.zerosource.worker.html [ Pass ]
+crbug.com/591099 external/wpt/offscreen-canvas/pixel-manipulation/2d.imageData.get.nonfinite.worker.html [ Failure ]
+crbug.com/591099 external/wpt/preload/delaying-onload-link-preload-after-discovery.html [ Pass ]
+crbug.com/591099 external/wpt/preload/modulepreload.html [ Failure Pass ]
+crbug.com/591099 external/wpt/preload/onload-event.html [ Pass ]
+crbug.com/591099 external/wpt/preload/single-download-preload.html [ Pass ]
+crbug.com/591099 external/wpt/presentation-api/controlling-ua/getAvailability.https.html [ Timeout ]
 crbug.com/845902 external/wpt/quirks/line-height-trailing-collapsable-whitespace.html [ Pass ]
+crbug.com/591099 external/wpt/referrer-policy/no-referrer-when-downgrade/http-rp/same-origin/http-http/shared-worker/no-redirect/insecure-protocol.http.html [ Failure ]
+crbug.com/591099 external/wpt/referrer-policy/same-origin/http-rp/same-origin/http-http/shared-worker/keep-origin-redirect/same-origin-insecure.http.html [ Failure ]
+crbug.com/591099 external/wpt/service-workers/service-worker/fetch-frame-resource.https.html [ Pass ]
+crbug.com/591099 external/wpt/svg/text/reftests/text-inline-size-101.svg [ Failure ]
 crbug.com/591099 external/wpt/wasm/jsapi/constructor/instantiate.any.html [ Failure ]
 crbug.com/591099 external/wpt/wasm/jsapi/constructor/instantiate.any.worker.html [ Failure ]
+crbug.com/591099 external/wpt/wasm/jsapi/module/customSections.any.worker.html [ Failure ]
 crbug.com/591099 external/wpt/wasm/webapi/instantiateStreaming.any.html [ Failure ]
 crbug.com/591099 external/wpt/wasm/webapi/instantiateStreaming.any.serviceworker.html [ Failure ]
 crbug.com/591099 external/wpt/wasm/webapi/instantiateStreaming.any.sharedworker.html [ Failure ]
 crbug.com/591099 external/wpt/wasm/webapi/instantiateStreaming.any.worker.html [ Failure ]
+crbug.com/591099 external/wpt/wasm/webapi/rejected-arg.any.serviceworker.html [ Timeout ]
+crbug.com/591099 external/wpt/webauthn/createcredential-extensions.https.html [ Pass ]
 crbug.com/591099 external/wpt/webmessaging/with-ports/018.html [ Pass ]
+crbug.com/591099 external/wpt/webmessaging/without-ports/001.html [ Failure ]
 crbug.com/591099 external/wpt/webmessaging/without-ports/018.html [ Pass ]
+crbug.com/591099 external/wpt/webrtc/RTCIceConnectionState-candidate-pair.https.html [ Timeout ]
+crbug.com/591099 external/wpt/websockets/constructor/013.html [ Pass ]
+crbug.com/591099 external/wpt/websockets/constructor/013.html?wss [ Pass ]
+crbug.com/591099 external/wpt/websockets/interfaces/WebSocket/send/010.html [ Pass ]
+crbug.com/591099 external/wpt/webvtt/rendering/cues-with-video/processing-model/2_cues_overlapping_partially_move_up.html [ Failure ]
+crbug.com/591099 external/wpt/webvtt/rendering/cues-with-video/processing-model/bidi/u002E_u2028_u05D0.html [ Failure ]
+crbug.com/591099 external/wpt/webvtt/rendering/cues-with-video/processing-model/bidi/u06E9_no_strong_dir.html [ Failure ]
+crbug.com/591099 external/wpt/webvtt/rendering/cues-with-video/processing-model/evil/size_90.html [ Failure ]
+crbug.com/591099 external/wpt/webvtt/rendering/cues-with-video/processing-model/regions/regionanchor_y_50_percent.html [ Failure ]
+crbug.com/591099 external/wpt/webvtt/rendering/cues-with-video/processing-model/selectors/cue/background_properties.html [ Failure ]
+crbug.com/591099 external/wpt/webvtt/rendering/cues-with-video/processing-model/selectors/cue/font_shorthand.html [ Failure ]
+crbug.com/591099 external/wpt/webvtt/rendering/cues-with-video/processing-model/selectors/cue/text-shadow.html [ Failure ]
+crbug.com/591099 external/wpt/webvtt/rendering/cues-with-video/processing-model/selectors/cue_function/bold_object/bold_namespace.html [ Failure ]
+crbug.com/591099 external/wpt/webvtt/rendering/cues-with-video/processing-model/selectors/cue_function/bold_object/bold_timestamp_future.html [ Failure ]
+crbug.com/591099 external/wpt/webvtt/rendering/cues-with-video/processing-model/selectors/cue_function/bold_object/bold_transition_with_timestamp.html [ Failure ]
+crbug.com/591099 external/wpt/webvtt/rendering/cues-with-video/processing-model/selectors/cue_function/class_object/class_namespace.html [ Failure ]
+crbug.com/591099 external/wpt/webvtt/rendering/cues-with-video/processing-model/selectors/cue_function/id_color.html [ Failure ]
+crbug.com/591099 external/wpt/webvtt/rendering/cues-with-video/processing-model/selectors/cue_function/italic_object/italic_color.html [ Failure ]
+crbug.com/591099 external/wpt/webvtt/rendering/cues-with-video/processing-model/selectors/cue_function/italic_object/italic_timestamp_future.html [ Failure ]
+crbug.com/591099 external/wpt/webvtt/rendering/cues-with-video/processing-model/selectors/cue_function/not_root_selector.html [ Failure ]
+crbug.com/591099 external/wpt/webvtt/rendering/cues-with-video/processing-model/selectors/cue_function/text-decoration_overline.html [ Failure ]
+crbug.com/591099 external/wpt/webvtt/rendering/cues-with-video/processing-model/selectors/cue_function/voice_object/voice_timestamp_future.html [ Failure ]
+crbug.com/591099 external/wpt/webvtt/rendering/cues-with-video/processing-model/selectors/cue_function/voice_object/voice_transition_with_timestamp.html [ Failure ]
+crbug.com/591099 external/wpt/webvtt/rendering/cues-with-video/processing-model/selectors/cue_function/voice_object/voice_voice_attribute.html [ Failure ]
+crbug.com/591099 external/wpt/webvtt/rendering/cues-with-video/processing-model/selectors/cue_function/white-space_pre.html [ Failure ]
+crbug.com/591099 external/wpt/xhr/event-progress.htm [ Pass ]
+crbug.com/591099 external/wpt/xhr/setrequestheader-header-allowed.htm [ Failure ]
 crbug.com/591099 fast/backgrounds/quirks-mode-line-box-backgrounds.html [ Failure ]
+crbug.com/591099 fast/block/float/4145535Crash.html [ Pass ]
 crbug.com/591099 fast/borders/inline-mask-overlay-image-outset-vertical-rl.html [ Failure ]
 crbug.com/591099 fast/canvas/OffscreenCanvas-copyImage.html [ Pass ]
+crbug.com/591099 fast/css-grid-layout/grid-baseline.html [ Failure ]
 crbug.com/591099 fast/css-intrinsic-dimensions/height-css-tables-collapsed.html [ Failure Pass ]
 crbug.com/591099 fast/css-intrinsic-dimensions/height-positioned.html [ Pass ]
+crbug.com/591099 fast/css-intrinsic-dimensions/height-tables.html [ Pass ]
 crbug.com/591099 fast/css/absolute-inline-alignment-2.html [ Pass ]
 crbug.com/835484 fast/css/outline-narrowLine.html [ Failure ]
 crbug.com/855279 fast/css/text-overflow-ellipsis-vertical-hittest.html [ Pass ]
 crbug.com/591099 fast/css3-text/css3-text-decoration/text-underline-position/text-underline-position-under.html [ Failure ]
+crbug.com/591099 fast/dom/HTMLImageElement/image-srcset-w-onerror.html [ Failure Pass ]
+crbug.com/591099 fast/dom/SelectorAPI/resig-SelectorsAPI-test.xhtml [ Pass ]
+crbug.com/591099 fast/dom/shadow/focus-controller-recursion-crash.html [ Pass ]
+crbug.com/591099 fast/dom/shadow/svg-style-in-shadow-tree-crash.html [ Pass ]
+crbug.com/591099 fast/events/before-unload-return-value-from-listener.html [ Pass ]
+crbug.com/591099 fast/events/keyboard-scroll-use-count.html [ Crash Pass ]
 crbug.com/591099 fast/events/touch/compositor-touch-hit-rects-continuation.html [ Failure ]
 crbug.com/591099 fast/events/touch/compositor-touch-hit-rects-list-translate.html [ Failure ]
 crbug.com/591099 fast/events/touch/compositor-touch-hit-rects.html [ Failure ]
+crbug.com/591099 fast/filesystem/file-writer-abort-depth.html [ Crash Pass ]
+crbug.com/591099 fast/filesystem/file-writer-events.html [ Failure Pass ]
 crbug.com/889721 fast/inline/outline-continuations.html [ Failure ]
-crbug.com/591099 fast/replaced/replaced-breaking.html [ Failure Pass ]
+crbug.com/591099 fast/multicol/border-radius-clipped-layer.html [ Pass ]
+crbug.com/591099 fast/peerconnection/RTCPeerConnection-many.html [ Pass ]
+crbug.com/591099 fast/replaced/replaced-breaking.html [ Failure ]
 crbug.com/591099 fast/text/descent-clip-in-scaled-page.html [ Failure ]
 crbug.com/899902 fast/text/ellipsis-with-self-painting-layer.html [ Pass ]
 crbug.com/591099 fast/text/font-format-support-color-cff2-vertical.html [ Failure ]
 crbug.com/796943 fast/text/international/shape-across-elements-simple.html [ Pass ]
 crbug.com/591099 fast/text/whitespace/018.html [ Failure ]
+crbug.com/591099 fast/webgl/texImage-imageBitmap-from-canvas-resize.html [ Pass ]
 crbug.com/591099 fast/writing-mode/auto-sizing-orthogonal-flows.html [ Failure ]
 crbug.com/591099 fast/writing-mode/percentage-height-orthogonal-writing-modes.html [ Failure ]
 crbug.com/591099 fast/writing-mode/table-percent-width-quirk.html [ Pass ]
+crbug.com/591099 html/marquee/marquee-destroyed-without-removed-from-crash.html [ Pass ]
+crbug.com/591099 http/tests/activedomobject/media.html [ Crash Pass ]
+crbug.com/591099 http/tests/appcache/abort-cache-ondownloading.html [ Crash Pass ]
+crbug.com/591099 http/tests/appcache/manifest-containing-itself.html [ Crash Pass ]
+crbug.com/591099 http/tests/appcache/progress-counter.html [ Crash Pass ]
+crbug.com/591099 http/tests/appcache/update-cache.html [ Crash Pass ]
+crbug.com/591099 http/tests/appcache/video.html [ Crash Pass ]
+crbug.com/591099 http/tests/appcache/xhr-foreign-resource.html [ Crash Pass ]
+crbug.com/591099 http/tests/cache/content-type-ignored-during-revalidation.html [ Crash Pass ]
+crbug.com/591099 http/tests/cache/history-only-cached-subresource-loads.html [ Crash Pass ]
+crbug.com/591099 http/tests/cache/image-with-dpr-header-cached.html [ Crash Pass ]
+crbug.com/591099 http/tests/cache/preload-cleared-after-parsing-canceled-by-js.html [ Crash Pass ]
+crbug.com/591099 http/tests/cache/subresource-revalidation-referrer.html [ Crash Pass ]
+crbug.com/591099 http/tests/cookies/js-get-and-set-http-only-cookie.html [ Crash Pass ]
+crbug.com/591099 http/tests/cookies/meta.html [ Crash Pass ]
+crbug.com/591099 http/tests/css/object-fit-delayed-img-svg.html [ Crash Pass ]
+crbug.com/591099 http/tests/csspaint/invalidation-border-image.html [ Pass ]
 crbug.com/591099 http/tests/devtools/elements/highlight/highlight-css-grid.js [ Failure ]
-crbug.com/927467 http/tests/devtools/elements/navigate-styles-sidebar-with-arrow-keys.js [ Crash ]
-crbug.com/927467 http/tests/devtools/elements/styles-1/commit-selector.js [ Crash ]
-crbug.com/927467 http/tests/devtools/elements/styles-3/styles-disable-property-after-selector-edit.js [ Crash ]
-crbug.com/927467 http/tests/devtools/elements/styles-4/styles-do-not-detach-sourcemap-on-edits.js [ Crash ]
-crbug.com/927467 http/tests/devtools/elements/styles-4/styles-update-links-2.js [ Crash ]
-crbug.com/927467 http/tests/devtools/elements/styles/undo-set-selector-text.js [ Crash ]
+crbug.com/591099 http/tests/devtools/elements/shadow/shadow-distribution.js [ Failure ]
+crbug.com/591099 http/tests/devtools/elements/styles-1/edit-value-url-with-color.js [ Pass ]
+crbug.com/591099 http/tests/devtools/elements/user-properties.js [ Pass ]
+crbug.com/591099 http/tests/devtools/service-workers/service-worker-v8-cache.js [ Pass ]
+crbug.com/591099 http/tests/devtools/sources/debugger/debugger-proto-property.js [ Pass ]
 crbug.com/591099 http/tests/devtools/tracing-session-id.js [ Pass ]
 crbug.com/591099 http/tests/devtools/tracing/console-timeline.js [ Pass ]
+crbug.com/591099 http/tests/fetch/chromium/response-blob-gc-crash.html [ Pass ]
+crbug.com/591099 http/tests/fetch/serviceworker-proxied/thorough/cookie-nocors-base-https-other-https.html [ Pass ]
+crbug.com/591099 http/tests/fetch/serviceworker-proxied/thorough/redirect-nocors-base-https-other-https.html [ Pass ]
+crbug.com/591099 http/tests/fetch/serviceworker/thorough/cookie-nocors-base-https-other-https.html [ Pass ]
+crbug.com/591099 http/tests/fetch/serviceworker/thorough/redirect-nocors-base-https-other-https.html [ Pass ]
+crbug.com/591099 http/tests/fetch/serviceworker/thorough/scheme-blob-base-https-other-https.html [ Pass ]
+crbug.com/591099 http/tests/fetch/window/thorough/cors-preflight2-base-https-other-https.html [ Pass ]
+crbug.com/591099 http/tests/fetch/workers/thorough/auth-base-https-other-https.html [ Pass ]
+crbug.com/591099 http/tests/fetch/workers/thorough/cookie-nocors-base-https-other-https.html [ Pass ]
 crbug.com/591099 http/tests/html/validation-bubble-oopif-clip.html [ Pass ]
 crbug.com/591099 http/tests/images/feature-policy-unoptimized-images-cached-image.html [ Failure Pass ]
 crbug.com/591099 http/tests/images/image-decode-in-frame.html [ Pass ]
 crbug.com/591099 http/tests/images/restyle-decode-error.html [ Failure ]
+crbug.com/591099 http/tests/inspector-protocol/fetch/fetch-renderer.js [ Timeout ]
+crbug.com/591099 http/tests/inspector-protocol/network/navigation-blocking-xorigin-iframe.js [ Failure Pass ]
 crbug.com/591099 http/tests/media/autoplay/document-user-activation-cross-origin-feature-policy-disabled.html [ Failure Pass ]
+crbug.com/591099 http/tests/media/video-load-metadata-decode-error.html [ Pass ]
+crbug.com/591099 http/tests/multipart/multipart-main-resource.html [ Pass ]
+crbug.com/591099 http/tests/permissions/chromium/test-change-event-sharedworker.html [ Failure Pass ]
+crbug.com/591099 http/tests/plugins/cross-frame-object-access.html [ Failure Pass ]
+crbug.com/591099 http/tests/security/isolatedWorld/all-window-prototypes.html [ Crash Pass ]
+crbug.com/591099 http/tests/security/isolatedWorld/body-prototype.html [ Crash Pass ]
+crbug.com/591099 http/tests/security/isolatedWorld/context-destroy.html [ Crash Pass ]
+crbug.com/591099 http/tests/security/isolatedWorld/didClearWindowObject.html [ Crash Pass ]
+crbug.com/591099 http/tests/security/isolatedWorld/dispatchEvent.html [ Crash Pass ]
+crbug.com/591099 http/tests/security/isolatedWorld/media-query-wrapper-leaks.html [ Crash Failure ]
+crbug.com/591099 http/tests/security/isolatedWorld/sandboxed-iframe.html [ Crash Pass ]
+crbug.com/591099 http/tests/security/isolatedWorld/top-properties.html [ Crash Pass ]
+crbug.com/591099 http/tests/security/isolatedWorld/window-setTimeout-function.html [ Crash Pass ]
+crbug.com/591099 http/tests/security/javascriptURL/javascriptURL-execution-context-frame-src-setAttributeNS.html [ Crash Pass ]
+crbug.com/591099 http/tests/security/mixedContent/about-blank-iframe-in-main-frame.html [ Crash Pass ]
+crbug.com/591099 http/tests/security/mixedContent/insecure-formSubmission-in-main-frame-allowed.html [ Crash Pass ]
+crbug.com/591099 http/tests/security/mixedContent/insecure-formSubmission-in-main-frame-blocked.html [ Crash Pass ]
+crbug.com/591099 http/tests/security/mixedContent/insecure-script-in-data-iframe-in-main-frame-blocked.html [ Crash Pass ]
 crbug.com/591099 http/tests/security/upgrade-insecure-requests/iframe-upgrade.https.html [ Crash Pass ]
+crbug.com/591099 http/tests/security/video-poster-cross-origin-crash2.html [ Pass ]
+crbug.com/591099 http/tests/webfont/crbug-655076.html [ Pass ]
 crbug.com/591099 images/feature-policy-oversized-images-resize.html [ Pass ]
+crbug.com/591099 inspector-protocol/dom-snapshot/dom-snapshot-getSnapshot-origin-url.js [ Crash Pass ]
 crbug.com/591099 inspector-protocol/dom-snapshot/dom-snapshot-getSnapshot-pseudo-element.js [ Failure ]
 crbug.com/591099 inspector-protocol/input/dispatchTouchEvent.js [ Failure Pass ]
+crbug.com/591099 jquery/offset.html [ Pass ]
 crbug.com/591099 media/autoplay/webaudio-audio-context-resume.html [ Failure Pass ]
+crbug.com/591099 media_capabilities/encodingInfo-avc1.html [ Failure ]
 crbug.com/591099 paint/invalidation/flexbox/scrollbars-changed.html [ Failure ]
 crbug.com/835484 paint/invalidation/outline/inline-focus.html [ Failure ]
 crbug.com/591099 paint/invalidation/overflow/opacity-change-on-overflow-float.html [ Failure ]
@@ -325,28 +525,120 @@
 crbug.com/591099 paint/invalidation/svg/svg-background-partial-redraw.html [ Failure ]
 crbug.com/591099 paint/invalidation/svg/text-selection-update.svg [ Failure ]
 crbug.com/591099 paint/invalidation/svg/transform-focus-ring-repaint.html [ Failure ]
+crbug.com/591099 payments/payment-request-in-iframe.html [ Failure ]
 crbug.com/591099 printing/iframe-svg-in-object-print.html [ Failure ]
 crbug.com/591099 scrollbars/auto-scrollbar-fit-content.html [ Failure ]
+crbug.com/591099 storage/indexeddb/objectstore-cursor.html [ Pass ]
+crbug.com/591099 storage/indexeddb/structured-clone.html [ Pass ]
+crbug.com/591099 storage/websql/open-database-creation-callback-isolated-world.html [ Pass ]
+crbug.com/591099 storage/websql/transaction-error-callback.html [ Pass ]
+crbug.com/591099 svg/animations/svg-animation-policy-once.html [ Pass ]
 crbug.com/927467 svg/dom/parent-view-layout-crash.html [ Crash Pass ]
 crbug.com/591099 svg/zoom/page/zoom-svg-float-border-padding.xml [ Pass ]
 crbug.com/591099 tables/mozilla/bugs/bug14159-1.html [ Pass ]
-crbug.com/591099 virtual/android/rootscroller/set-root-scroller.html [ Pass ]
+crbug.com/591099 virtual/android/frame-size/intersection-observer-root-uses-frame-size.html [ Crash Pass ]
+crbug.com/591099 virtual/android/fullscreen/compositor-touch-hit-rects-fullscreen-video-controls.html [ Crash Failure ]
+crbug.com/591099 virtual/android/fullscreen/full-screen-detached-document.html [ Crash Pass ]
+crbug.com/591099 virtual/android/fullscreen/full-screen-orientation-change.html [ Crash Pass ]
+crbug.com/591099 virtual/android/fullscreen/full-screen-prefixed-and-unprefixed.html [ Crash Pass ]
+crbug.com/591099 virtual/android/fullscreen/full-screen-twice.html [ Crash Pass ]
+crbug.com/591099 virtual/android/fullscreen/notify-paint-crash.html [ Crash Pass ]
+crbug.com/591099 virtual/android/fullscreen/video-overlay-scroll.html [ Crash Pass ]
+crbug.com/591099 virtual/android/rootscroller/nested-rootscroller-browser-controls-bounds-shown.html [ Crash Failure ]
+crbug.com/591099 virtual/android/rootscroller/scroll-non-descendant-of-root-scroller.html [ Crash Pass ]
+crbug.com/591099 virtual/android/rootscroller/set-root-scroller.html [ Crash Pass ]
 crbug.com/591099 virtual/android/rootscroller/set-rootscroller-before-load.html [ Pass ]
+crbug.com/591099 virtual/bidi-caret-affinity/editing/selection/modify_move/move-by-character-005.html [ Crash Pass ]
+crbug.com/591099 virtual/bidi-caret-affinity/editing/selection/modify_move/move-forward-after-line-break.html [ Crash Failure ]
+crbug.com/591099 virtual/bidi-caret-affinity/editing/selection/modify_move/move_forward_line_mixed_editability.html [ Crash Pass ]
+crbug.com/591099 virtual/bidi-caret-affinity/editing/selection/modify_move/move_left_character_01_ltr.html [ Crash Pass ]
+crbug.com/591099 virtual/bidi-caret-affinity/editing/selection/modify_move/move_left_character_01_rtl.html [ Crash Pass ]
+crbug.com/591099 virtual/bidi-caret-affinity/editing/selection/modify_move/move_left_character_23_ltr.html [ Crash Failure ]
+crbug.com/591099 virtual/bidi-caret-affinity/editing/selection/modify_move/move_left_character_30_rtl.html [ Crash Pass ]
+crbug.com/591099 virtual/bidi-caret-affinity/editing/selection/modify_move/move_left_right_character_in_mixed_bidi.html [ Crash Pass ]
+crbug.com/591099 virtual/bidi-caret-affinity/editing/selection/modify_move/move_left_word_05_ltr_multi_line.html [ Crash Failure ]
+crbug.com/591099 virtual/bidi-caret-affinity/editing/selection/modify_move/move_left_word_09_ltr_multi_line.html [ Crash Failure ]
+crbug.com/591099 virtual/bidi-caret-affinity/editing/selection/modify_move/move_left_word_09_rtl_multi_line.html [ Crash Failure ]
+crbug.com/591099 virtual/bidi-caret-affinity/editing/selection/modify_move/move_right_character_09_rtl.html [ Crash Pass ]
+crbug.com/591099 virtual/bidi-caret-affinity/editing/selection/modify_move/move_right_character_16_ltr.html [ Crash Pass ]
+crbug.com/591099 virtual/bidi-caret-affinity/editing/selection/modify_move/move_right_character_16_rtl.html [ Crash Pass ]
+crbug.com/591099 virtual/bidi-caret-affinity/editing/selection/modify_move/move_right_word_01_rtl_multi_line.html [ Crash Failure ]
+crbug.com/591099 virtual/bidi-caret-affinity/editing/selection/modify_move/move_right_word_05_rtl_multi_line.html [ Failure ]
+crbug.com/591099 virtual/composite-after-paint/compositing/backface-visibility/backface-visibility-webgl.html [ Crash Pass ]
 crbug.com/916511 virtual/composite-after-paint/paint/background/scrolling-background-with-negative-z-child.html [ Crash ]
+crbug.com/591099 virtual/composite-after-paint/paint/frames/frameset-with-stacking-context-and-not-stacking-context-children.html [ Crash Pass ]
 crbug.com/591099 virtual/composite-after-paint/paint/invalidation/box/margin.html [ Failure Pass ]
+crbug.com/591099 virtual/disabled-service-worker-servicification/external/wpt/service-workers/service-worker/ServiceWorkerGlobalScope/postmessage.https.html [ Crash Pass ]
+crbug.com/591099 virtual/disabled-service-worker-servicification/external/wpt/service-workers/service-worker/client-id.https.html [ Crash Pass ]
+crbug.com/591099 virtual/disabled-service-worker-servicification/external/wpt/service-workers/service-worker/controller-on-reload.https.html [ Crash Pass ]
+crbug.com/591099 virtual/disabled-service-worker-servicification/external/wpt/service-workers/service-worker/fetch-event-redirect.https.html [ Crash Pass ]
+crbug.com/591099 virtual/disabled-service-worker-servicification/external/wpt/service-workers/service-worker/fetch-event.https.html [ Crash Pass ]
+crbug.com/591099 virtual/disabled-service-worker-servicification/external/wpt/service-workers/service-worker/fetch-request-xhr.https.html [ Crash Pass ]
+crbug.com/591099 virtual/disabled-service-worker-servicification/external/wpt/service-workers/service-worker/getregistration.https.html [ Crash Pass ]
+crbug.com/591099 virtual/disabled-service-worker-servicification/external/wpt/service-workers/service-worker/multi-globals/url-parsing.https.html [ Crash Pass ]
+crbug.com/591099 virtual/disabled-service-worker-servicification/external/wpt/service-workers/service-worker/navigation-preload/chunked-encoding.https.html [ Crash Pass ]
+crbug.com/591099 virtual/disabled-service-worker-servicification/external/wpt/service-workers/service-worker/referer.https.html [ Crash Pass ]
+crbug.com/591099 virtual/disabled-service-worker-servicification/external/wpt/service-workers/service-worker/serviceworkerobject-scripturl.https.html [ Crash Pass ]
+crbug.com/591099 virtual/disabled-service-worker-servicification/external/wpt/service-workers/service-worker/skip-waiting-without-using-registration.https.html [ Pass Timeout ]
+crbug.com/591099 virtual/disabled-service-worker-servicification/external/wpt/service-workers/service-worker/uncontrolled-page.https.html [ Crash Pass ]
+crbug.com/591099 virtual/disabled-service-worker-servicification/external/wpt/service-workers/service-worker/worker-client-id.https.html [ Crash Failure ]
+crbug.com/591099 virtual/display-lock/display-lock/lock-after-append/acquire-immediate-update-and-commit.html [ Crash Pass ]
+crbug.com/591099 virtual/display-lock/display-lock/lock-after-append/locked-element-prevents-anchor-links.html [ Crash Pass ]
 crbug.com/591099 virtual/display-lock/display-lock/lock-after-append/measure-forced-layout-after-commit.html [ Failure ]
 crbug.com/591099 virtual/display-lock/display-lock/lock-after-append/measure-forced-layout.html [ Failure ]
-crbug.com/591099 virtual/display-lock/display-lock/lock-after-append/measure-updated-layout.html [ Failure ]
+crbug.com/591099 virtual/display-lock/display-lock/lock-after-append/measure-updated-layout.html [ Crash Failure ]
 crbug.com/926276 virtual/display-lock/display-lock/lock-after-append/nested-update-and-commit.html [ Timeout ]
 crbug.com/926276 virtual/display-lock/display-lock/lock-after-append/nested-update.html [ Timeout ]
+crbug.com/591099 virtual/display-lock/display-lock/lock-before-append/acquire-timeout.html [ Crash Pass ]
 crbug.com/591099 virtual/display-lock/display-lock/lock-before-append/acquire-update-measure-remove.html [ Failure ]
+crbug.com/591099 virtual/display-lock/display-lock/lock-before-append/commit-without-acquire.html [ Crash Pass ]
 crbug.com/591099 virtual/display-lock/display-lock/lock-before-append/measure-forced-layout.html [ Failure ]
 crbug.com/591099 virtual/display-lock/display-lock/lock-before-append/measure-updated-layout.html [ Failure ]
 crbug.com/591099 virtual/exotic-color-space/ [ Skip ]
+crbug.com/591099 virtual/feature-policy-for-sandbox/http/tests/security/contentSecurityPolicy/sandbox-in-http-header-control.html [ Failure ]
+crbug.com/591099 virtual/feature-policy-for-sandbox/http/tests/security/mixedContent/insecure-plugin-in-iframe.html [ Failure Pass ]
+crbug.com/591099 virtual/feature-policy-for-sandbox/http/tests/security/sandbox-iframe-blocks-modals.php [ Failure ]
+crbug.com/591099 virtual/feature-policy-for-sandbox/mhtml/page_with_image_unmht.mht [ Crash Pass ]
+crbug.com/591099 virtual/feature-policy-for-sandbox/mhtml/transfer_encoding_7bit.mht [ Crash Pass ]
+crbug.com/591099 virtual/feature-policy-permissions/external/wpt/mediacapture-streams/MediaStream-finished-add.https.html [ Crash Pass ]
+crbug.com/591099 virtual/feature-policy-permissions/external/wpt/mediacapture-streams/MediaStreamTrack-applyConstraints.https.html [ Crash Pass ]
+crbug.com/591099 virtual/feature-policy-permissions/external/wpt/mediacapture-streams/MediaStreamTrack-getSettings.https.html [ Crash Pass ]
+crbug.com/591099 virtual/feature-policy-permissions/external/wpt/mediacapture-streams/historical.html [ Crash Pass ]
+crbug.com/591099 virtual/fractional_scrolling/fast/scrolling/background-paint-composited-scrolled.html [ Crash Pass ]
+crbug.com/591099 virtual/fractional_scrolling/fast/scrolling/fractional-scroll-offset-fixed-position-non-composited.html [ Failure ]
+crbug.com/591099 virtual/fractional_scrolling/fast/scrolling/overflow-scrollability.html [ Failure Pass ]
+crbug.com/591099 virtual/fractional_scrolling/fast/scrolling/scroll-clears-fragment-anchor.html [ Crash Pass ]
+crbug.com/591099 virtual/fractional_scrolling/fast/scrolling/scroll-into-view-collapsed-div.html [ Crash Pass ]
+crbug.com/591099 virtual/fractional_scrolling/fast/scrolling/scroll-to-origin-with-options-no-layout.html [ Crash Pass ]
+crbug.com/591099 virtual/fractional_scrolling/fast/scrolling/scrollbar-mousedown-mouseup.html [ Crash Pass ]
+crbug.com/591099 virtual/fractional_scrolling/fast/scrolling/scrollbar-prevent-default.html [ Crash Pass ]
+crbug.com/591099 virtual/fractional_scrolling/fast/scrolling/unscrollable-layer-subpixel-size-with-negative-overflow.html [ Crash Pass ]
+crbug.com/591099 virtual/fractional_scrolling_threaded/fast/scrolling/content-box-smaller-than-scrollbar.html [ Crash Pass ]
+crbug.com/591099 virtual/fractional_scrolling_threaded/fast/scrolling/empty-anchor.html [ Crash Pass ]
+crbug.com/591099 virtual/fractional_scrolling_threaded/fast/scrolling/events/overscroll-event-fired-to-element-with-overscroll-behavior.html [ Crash Pass ]
+crbug.com/591099 virtual/fractional_scrolling_threaded/fast/scrolling/hide-scrollbars.html [ Crash Pass ]
+crbug.com/591099 virtual/fractional_scrolling_threaded/fast/scrolling/horizontal-overflow-quirks.html [ Crash Pass ]
+crbug.com/591099 virtual/fractional_scrolling_threaded/fast/scrolling/scrollbar-mousedown-move-mouseup.html [ Crash Pass ]
 crbug.com/591099 virtual/gpu-rasterization/images/color-profile-image-filter-all.html [ Pass ]
+crbug.com/591099 virtual/gpu-rasterization/images/cross-fade-tiled.html [ Crash Pass ]
+crbug.com/591099 virtual/gpu-rasterization/images/feature-policy-oversized-images-edge-cases.html [ Crash Pass ]
+crbug.com/591099 virtual/gpu-rasterization/images/icon-decoding.html [ Crash Pass ]
+crbug.com/591099 virtual/gpu-rasterization/images/image-page-injected-script-crash.html [ Pass ]
+crbug.com/591099 virtual/gpu-rasterization/images/img-dimensions-styled.html [ Crash Pass ]
+crbug.com/591099 virtual/gpu-rasterization/images/rgb-jpeg-endian-pixels.html [ Crash Pass ]
+crbug.com/591099 virtual/gpu/fast/canvas/2d.fillText.gradient.html [ Crash Pass ]
 crbug.com/591099 virtual/gpu/fast/canvas/OffscreenCanvas-copyImage.html [ Pass ]
+crbug.com/591099 virtual/gpu/fast/canvas/OffscreenCanvas-filter.html [ Pass ]
+crbug.com/591099 virtual/gpu/fast/canvas/canvas-arc-circumference-fill.html [ Failure ]
+crbug.com/591099 virtual/gpu/fast/canvas/canvas-blend-image.html [ Pass ]
+crbug.com/591099 virtual/gpu/fast/canvas/canvas-blending-color-over-pattern.html [ Crash Pass ]
+crbug.com/591099 virtual/gpu/fast/canvas/canvas-blending-pattern-over-gradient.html [ Pass ]
+crbug.com/591099 virtual/gpu/fast/canvas/canvas-blending-pattern-over-image.html [ Pass ]
+crbug.com/591099 virtual/gpu/fast/canvas/canvas-filter-stroke-paint-pattern.html [ Pass ]
 crbug.com/591099 virtual/layout_ng/ [ Skip ]
 crbug.com/824918 virtual/layout_ng_experimental/ [ Skip ]
+crbug.com/591099 virtual/mojo-blob-urls/external/wpt/FileAPI/url/sandboxed-iframe.html [ Pass ]
+crbug.com/591099 virtual/mojo-blob-urls/external/wpt/FileAPI/url/url-format.any.html [ Pass ]
 crbug.com/591099 virtual/mouseevent_fractional/fast/events/touch/compositor-touch-hit-rects-continuation.html [ Failure ]
 crbug.com/591099 virtual/new-remote-playback-pipeline/ [ Skip ]
 crbug.com/591099 virtual/not-site-per-process/http/tests/devtools/isolated-code-cache/same-origin-test.js [ Failure Pass ]
@@ -354,13 +646,60 @@
 crbug.com/591099 virtual/omt-worker-fetch/external/wpt/referrer-policy/no-referrer/http-rp/same-origin/http-http/shared-worker/no-redirect/generic.http.html [ Pass ]
 crbug.com/591099 virtual/omt-worker-fetch/external/wpt/referrer-policy/no-referrer/meta-referrer/same-origin/http-http/shared-worker/keep-origin-redirect/generic.http.html [ Pass ]
 crbug.com/591099 virtual/omt-worker-fetch/external/wpt/referrer-policy/no-referrer/meta-referrer/same-origin/http-http/shared-worker/no-redirect/generic.http.html [ Pass ]
+crbug.com/591099 virtual/omt-worker-fetch/external/wpt/referrer-policy/origin/http-rp/same-origin/http-http/shared-worker/keep-origin-redirect/generic.http.html [ Failure ]
+crbug.com/591099 virtual/omt-worker-fetch/external/wpt/referrer-policy/origin/http-rp/same-origin/http-http/shared-worker/no-redirect/generic.http.html [ Failure ]
+crbug.com/591099 virtual/omt-worker-fetch/external/wpt/referrer-policy/origin/meta-referrer/same-origin/http-http/shared-worker/no-redirect/generic.http.html [ Failure ]
+crbug.com/591099 virtual/omt-worker-fetch/external/wpt/referrer-policy/strict-origin-when-cross-origin/http-rp/same-origin/http-http/shared-worker/keep-origin-redirect/same-insecure.http.html [ Failure ]
+crbug.com/591099 virtual/omt-worker-fetch/external/wpt/workers/semantics/multiple-workers/003.html [ Timeout ]
 crbug.com/591099 virtual/outofblink-cors-ns/external/wpt/fetch/api/redirect/redirect-count.any.html [ Pass ]
 crbug.com/591099 virtual/outofblink-cors-ns/external/wpt/fetch/api/redirect/redirect-count.any.worker.html [ Pass ]
 crbug.com/591099 virtual/outofblink-cors-ns/external/wpt/fetch/api/request/request-keepalive-quota.html?include=slow-2 [ Pass ]
+crbug.com/591099 virtual/outofblink-cors-ns/external/wpt/referrer-policy/generic/sandboxed-iframe-with-opaque-origin.html [ Timeout ]
+crbug.com/591099 virtual/outofblink-cors-ns/external/wpt/referrer-policy/origin-when-cross-origin/http-rp/same-origin/http-http/shared-worker/keep-origin-redirect/same-origin-insecure.http.html [ Failure ]
+crbug.com/591099 virtual/outofblink-cors-ns/external/wpt/referrer-policy/origin-when-cross-origin/http-rp/same-origin/http-http/shared-worker/no-redirect/same-origin-insecure.http.html [ Failure ]
+crbug.com/591099 virtual/outofblink-cors-ns/external/wpt/referrer-policy/strict-origin/meta-referrer/same-origin/http-http/shared-worker/keep-origin-redirect/insecure-protocol.http.html [ Failure ]
+crbug.com/591099 virtual/outofblink-cors-ns/external/wpt/service-workers/service-worker/fetch-event-respond-with-body-loaded-in-chunk.https.html [ Pass ]
+crbug.com/591099 virtual/outofblink-cors-ns/external/wpt/service-workers/service-worker/registration-updateviacache.https.html [ Pass ]
+crbug.com/591099 virtual/outofblink-cors-ns/external/wpt/service-workers/service-worker/update-after-navigation-redirect.https.html [ Pass ]
+crbug.com/591099 virtual/outofblink-cors-ns/external/wpt/service-workers/service-worker/update-bytecheck.https.html [ Timeout ]
+crbug.com/591099 virtual/outofblink-cors-ns/external/wpt/service-workers/service-worker/update-not-allowed.https.html [ Timeout ]
+crbug.com/591099 virtual/outofblink-cors-ns/external/wpt/xhr/progress-events-response-data-gzip.htm [ Pass ]
+crbug.com/591099 virtual/outofblink-cors-ns/external/wpt/xhr/sync-no-progress.any.worker.html [ Pass ]
+crbug.com/591099 virtual/outofblink-cors-ns/http/tests/fetch/serviceworker-proxied/thorough/redirect-credentials-base-https-other-https.html [ Pass ]
+crbug.com/591099 virtual/outofblink-cors-ns/http/tests/fetch/serviceworker/stream-reader-base-https-other-https.html [ Pass ]
+crbug.com/591099 virtual/outofblink-cors-ns/http/tests/fetch/serviceworker/thorough/redirect-credentials-base-https-other-https.html [ Pass ]
+crbug.com/591099 virtual/outofblink-cors-ns/http/tests/fetch/serviceworker/thorough/scheme-data-base-https-other-https.html [ Pass ]
+crbug.com/591099 virtual/outofblink-cors-ns/http/tests/fetch/workers/stream-reader-base-https-other-https.html [ Pass ]
+crbug.com/591099 virtual/outofblink-cors-ns/http/tests/security/contentSecurityPolicy/require-sri-for/require-sri-for-script-reportonly-blocked.php [ Pass ]
+crbug.com/591099 virtual/outofblink-cors-ns/http/tests/security/frameNavigation/xss-DENIED-top-navigation-without-user-gesture.html [ Failure ]
+crbug.com/591099 virtual/outofblink-cors-ns/http/tests/xmlhttprequest/timeout/xmlhttprequest-timeout-worker-simple.html [ Pass ]
+crbug.com/591099 virtual/outofblink-cors-ns/http/tests/xmlhttprequest/timeout/xmlhttprequest-timeout-worker-synconworker.html [ Pass ]
+crbug.com/591099 virtual/outofblink-cors-ns/http/tests/xmlhttprequest/web-apps/013.html [ Pass ]
 crbug.com/591099 virtual/outofblink-cors/ [ Skip ]
+crbug.com/591099 virtual/paint-timing/external/wpt/paint-timing/idlharness.window.html [ Pass ]
 crbug.com/591099 virtual/paint-timing/external/wpt/paint-timing/sibling-painting-first-image.html [ Failure ]
 crbug.com/591099 virtual/prefer_compositing_to_lcd_text/ [ Skip ]
 crbug.com/591099 virtual/scroll_customization/ [ Skip ]
+crbug.com/591099 virtual/speech-with-unified-autoplay/external/wpt/speech-api/SpeechSynthesis-speak-events.html [ Timeout ]
+crbug.com/591099 virtual/speech-with-unified-autoplay/external/wpt/speech-api/SpeechSynthesis-speak-twice.html [ Timeout ]
 crbug.com/591099 virtual/stable/ [ Skip ]
+crbug.com/591099 virtual/streaming-preload/http/tests/fetch/chromium/response-json-gc-crash.html [ Pass ]
+crbug.com/591099 virtual/streaming-preload/http/tests/fetch/serviceworker/thorough/cors-base-https-other-https.html [ Pass ]
+crbug.com/591099 virtual/streaming-preload/http/tests/fetch/workers/thorough/cors-preflight-base-https-other-https.html [ Pass ]
 crbug.com/591099 virtual/threaded/ [ Skip ]
+crbug.com/591099 virtual/user-activation-v2/fast/events/autoscroll-iframe-no-scrolling.html [ Crash Pass ]
+crbug.com/591099 virtual/user-activation-v2/fast/events/click-count.html [ Crash Pass ]
+crbug.com/591099 virtual/user-activation-v2/fast/events/message-channel-gc-4.html [ Crash Pass ]
+crbug.com/591099 virtual/user-activation-v2/fast/events/mouse-relative-position.html [ Crash Pass ]
+crbug.com/591099 virtual/user-activation-v2/fast/events/pointerevents/mouse-pointer-haspointercapture.html [ Failure Pass ]
 crbug.com/591099 virtual/user-activation-v2/fast/events/touch/compositor-touch-hit-rects-continuation.html [ Failure ]
+crbug.com/591099 virtual/user-activation-v2/fullscreen/model/fully-exit-fullscreen-nested-iframe.html [ Pass ]
+crbug.com/591099 virtual/video-surface-layer/media/W3C/video/networkState/networkState_during_progress.html [ Pass ]
+crbug.com/591099 virtual/video-surface-layer/media/autoplay-when-visible.html [ Pass ]
+crbug.com/591099 virtual/video-surface-layer/media/color-profile-video-seek-filter.html [ Pass ]
+crbug.com/591099 virtual/video-surface-layer/media/media-ended.html [ Pass ]
+crbug.com/591099 virtual/video-surface-layer/media/video-canvas-draw.html [ Failure ]
+crbug.com/591099 virtual/video-surface-layer/media/video-controls-hide-on-move-outside-controls.html [ Pass ]
+crbug.com/591099 virtual/webrtc-wpt-plan-b/external/wpt/webrtc/RTCIceTransport-extension.https.html [ Failure Pass ]
+crbug.com/591099 vr/getFrameData_oneframeupdate.html [ Pass ]
+crbug.com/591099 webexposed/global-interface-listing-shared-worker.html [ Pass ]
diff --git a/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_5.json b/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_5.json
index 47d34e3..9883b58 100644
--- a/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_5.json
+++ b/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_5.json
@@ -403614,11 +403614,11 @@
    "testharness"
   ],
   "html/browsers/the-window-object/window-open-noopener.html": [
-   "5256053753747a99c68dd9c6a89aa4e33bd22c57",
+   "cdda6335861eb46f94a77f6ed5b17fb85878a37a",
    "testharness"
   ],
   "html/browsers/the-window-object/window-open-noopener_indexed-expected.txt": [
-   "191f49c4868c30cc2dc4098a6ce7f46ea7ad64f1",
+   "23fd0069af3c0df508400e67c522baa11dc3e54c",
    "support"
   ],
   "html/browsers/the-window-object/window-properties.https-expected.txt": [
diff --git a/third_party/blink/web_tests/external/wpt/html/browsers/the-window-object/window-open-noopener.html b/third_party/blink/web_tests/external/wpt/html/browsers/the-window-object/window-open-noopener.html
index 52560537..cdda633 100644
--- a/third_party/blink/web_tests/external/wpt/html/browsers/the-window-object/window-open-noopener.html
+++ b/third_party/blink/web_tests/external/wpt/html/browsers/the-window-object/window-open-noopener.html
@@ -15,13 +15,13 @@
   { testDescription: "window.open() with 'noopener' should not reuse existing target",
     secondWindowFeatureString: "noopener",
     shouldReuse: false },
-  { testDescription: "noopener needs to be present as a token on its own",
+  { testDescription: "noopener=1 means the same as noopener",
     secondWindowFeatureString: "noopener=1",
-    shouldReuse: true },
-  { testDescription: "noopener needs to be present as a token on its own again",
+    shouldReuse: false },
+  { testDescription: "noopener=0 means lack of noopener",
     secondWindowFeatureString: "noopener=0",
     shouldReuse: true },
-  { testDescription: "noopener needs to be present as a token on its own yet again",
+  { testDescription: "noopener needs to be present as a token on its own",
     secondWindowFeatureString: "make me noopener",
     shouldReuse: true },
   { testDescription: "Trailing noopener should work",
diff --git a/third_party/blink/web_tests/external/wpt/html/browsers/the-window-object/window-open-noopener_indexed-expected.txt b/third_party/blink/web_tests/external/wpt/html/browsers/the-window-object/window-open-noopener_indexed-expected.txt
index 191f49c4..23fd006 100644
--- a/third_party/blink/web_tests/external/wpt/html/browsers/the-window-object/window-open-noopener_indexed-expected.txt
+++ b/third_party/blink/web_tests/external/wpt/html/browsers/the-window-object/window-open-noopener_indexed-expected.txt
@@ -1,8 +1,8 @@
 This is a testharness.js-based test.
 PASS window.open() with 'noopener' should not reuse existing target
+PASS noopener=1 means the same as noopener
+FAIL noopener=0 means lack of noopener assert_equals: expected object "[object Window]" but got null
 FAIL noopener needs to be present as a token on its own assert_equals: expected object "[object Window]" but got null
-FAIL noopener needs to be present as a token on its own again assert_equals: expected object "[object Window]" but got null
-FAIL noopener needs to be present as a token on its own yet again assert_equals: expected object "[object Window]" but got null
 PASS Trailing noopener should work
 PASS Leading noopener should work
 PASS Interior noopener should work
diff --git a/third_party/blink/web_tests/http/tests/activedomobject/media-expected.txt b/third_party/blink/web_tests/http/tests/activedomobject/media-expected.txt
index 2da7ff20..c82e438 100644
--- a/third_party/blink/web_tests/http/tests/activedomobject/media-expected.txt
+++ b/third_party/blink/web_tests/http/tests/activedomobject/media-expected.txt
@@ -1,8 +1,8 @@
 Tests that reparenting media elements also reparents ActiveDOMObject.
 
 Before Reparenting
-PASS: internals.pausableObjectCount(document) should be '0' and is.
-PASS: internals.pausableObjectCount(iframe) should be '1' and is.
+PASS: internals.contextLifecycleStateObserverObjectCount(document) should be '0' and is.
+PASS: internals.contextLifecycleStateObserverObjectCount(iframe) should be '1' and is.
 After Reparenting
-PASS: internals.pausableObjectCount(document) should be '1' and is.
-PASS: internals.pausableObjectCount(iframe) should be '0' and is.
+PASS: internals.contextLifecycleStateObserverObjectCount(document) should be '1' and is.
+PASS: internals.contextLifecycleStateObserverObjectCount(iframe) should be '0' and is.
diff --git a/third_party/blink/web_tests/http/tests/activedomobject/media.html b/third_party/blink/web_tests/http/tests/activedomobject/media.html
index 2e19e3f..d8ad43c 100644
--- a/third_party/blink/web_tests/http/tests/activedomobject/media.html
+++ b/third_party/blink/web_tests/http/tests/activedomobject/media.html
@@ -10,14 +10,14 @@
         window.iframe = document.querySelector('iframe').contentDocument;
 
         log('Before Reparenting');
-        shouldBe('internals.pausableObjectCount(document)', 0);
-        shouldBe('internals.pausableObjectCount(iframe)', 1);
+        shouldBe('internals.contextLifecycleStateObserverObjectCount(document)', 0);
+        shouldBe('internals.contextLifecycleStateObserverObjectCount(iframe)', 1);
 
         document.body.appendChild(window.iframe.querySelector('video'));
 
         log('After Reparenting');
-        shouldBe('internals.pausableObjectCount(document)', 1);
-        shouldBe('internals.pausableObjectCount(iframe)', 0);
+        shouldBe('internals.contextLifecycleStateObserverObjectCount(document)', 1);
+        shouldBe('internals.contextLifecycleStateObserverObjectCount(iframe)', 0);
     }
 </script>
 </body>
diff --git a/third_party/blink/web_tests/http/tests/devtools/oopif/oopif-performance-monitor-expected.txt b/third_party/blink/web_tests/http/tests/devtools/oopif/oopif-performance-monitor-expected.txt
index 9c36bb51..8de8cd8 100644
--- a/third_party/blink/web_tests/http/tests/devtools/oopif/oopif-performance-monitor-expected.txt
+++ b/third_party/blink/web_tests/http/tests/devtools/oopif/oopif-performance-monitor-expected.txt
@@ -4,6 +4,7 @@
 Metrics reported:
 AdSubframes
 AudioHandlers
+ContextLifecycleStateObservers
 DetachedScriptStates
 Documents
 DomContentLoaded
@@ -19,7 +20,6 @@
 MediaKeys
 NavigationStart
 Nodes
-PausableObjects
 RTCPeerConnections
 RecalcStyleCount
 RecalcStyleDuration
diff --git a/third_party/blink/web_tests/inspector-protocol/performance/perf-push-metrics-expected.txt b/third_party/blink/web_tests/inspector-protocol/performance/perf-push-metrics-expected.txt
index 7b8592a..46961bf 100644
--- a/third_party/blink/web_tests/inspector-protocol/performance/perf-push-metrics-expected.txt
+++ b/third_party/blink/web_tests/inspector-protocol/performance/perf-push-metrics-expected.txt
@@ -11,7 +11,7 @@
 	Nodes
 	Resources
 	ScriptPromises
-	PausableObjects
+	ContextLifecycleStateObservers
 	V8PerContextDatas
 	WorkerGlobalScopes
 	UACSSResources
@@ -44,7 +44,7 @@
 	Nodes
 	Resources
 	ScriptPromises
-	PausableObjects
+	ContextLifecycleStateObservers
 	V8PerContextDatas
 	WorkerGlobalScopes
 	UACSSResources
@@ -77,7 +77,7 @@
 	Nodes
 	Resources
 	ScriptPromises
-	PausableObjects
+	ContextLifecycleStateObservers
 	V8PerContextDatas
 	WorkerGlobalScopes
 	UACSSResources
diff --git a/third_party/closure_compiler/externs/arc_apps_private.js b/third_party/closure_compiler/externs/arc_apps_private.js
deleted file mode 100644
index e32f62b7..0000000
--- a/third_party/closure_compiler/externs/arc_apps_private.js
+++ /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.
-
-// This file was generated by:
-//   tools/json_schema_compiler/compiler.py.
-// NOTE: The format of types has changed. 'FooType' is now
-//   'chrome.arcAppsPrivate.FooType'.
-// Please run the closure compiler before committing changes.
-// See https://chromium.googlesource.com/chromium/src/+/master/docs/closure_compilation.md
-
-/** @fileoverview Externs generated from namespace: arcAppsPrivate */
-
-/**
- * @const
- */
-chrome.arcAppsPrivate = {};
-
-/**
- * @typedef {{
- *   packageName: string
- * }}
- */
-chrome.arcAppsPrivate.AppInfo;
-
-/**
- * Returns info of the installed ARC apps that are launchable, including ready
- * and non-ready apps.
- * @param {function(!Array<!chrome.arcAppsPrivate.AppInfo>):void} callback
- */
-chrome.arcAppsPrivate.getLaunchableApps = function(callback) {};
-
-/**
- * Launches the ARC app with its package name. The app is launched immediately
- * if it's ready, otherwise it will be launched when it becomes ready. The
- * callback is called as soon as the launch is scheduled.
- * @param {string} packageName
- * @param {function():void=} callback
- */
-chrome.arcAppsPrivate.launchApp = function(packageName, callback) {};
-
-/**
- * Fires when a new app can be launched via $(ref:launchApp).
- * @type {!ChromeEvent}
- */
-chrome.arcAppsPrivate.onInstalled;
diff --git a/third_party/crashpad/README.chromium b/third_party/crashpad/README.chromium
index 4f80aec..37877073 100644
--- a/third_party/crashpad/README.chromium
+++ b/third_party/crashpad/README.chromium
@@ -2,7 +2,7 @@
 Short Name: crashpad
 URL: https://crashpad.chromium.org/
 Version: unknown
-Revision: fe05eb7c99a42d0c1c437061fb5470f6fd844854
+Revision: bba9d0819c12a4bf39bebafb6233e000aa8a446c
 License: Apache 2.0
 License File: crashpad/LICENSE
 Security Critical: yes
diff --git a/third_party/crashpad/crashpad/DEPS b/third_party/crashpad/crashpad/DEPS
index 10c37bc..0c8edf20 100644
--- a/third_party/crashpad/crashpad/DEPS
+++ b/third_party/crashpad/crashpad/DEPS
@@ -24,7 +24,7 @@
       '6fe4a3251488f7af86d64fc25cf442e817cf6133',
   'crashpad/third_party/gtest/gtest':
       Var('chromium_git') + '/external/github.com/google/googletest@' +
-      'b18d39bd2ea2d2b508228a9a1d8ae9f7fba32f78',
+      '9518a57428ae0a7ed450c1361768e84a2a38af5a',
   'crashpad/third_party/gyp/gyp':
       Var('chromium_git') + '/external/gyp@' +
       '5e2b3ddde7cda5eb6bc09a5546a76b00e49d888f',
diff --git a/third_party/crashpad/crashpad/handler/BUILD.gn b/third_party/crashpad/crashpad/handler/BUILD.gn
index 7a91b1c..32d4d6c 100644
--- a/third_party/crashpad/crashpad/handler/BUILD.gn
+++ b/third_party/crashpad/crashpad/handler/BUILD.gn
@@ -135,29 +135,6 @@
     "../third_party/mini_chromium:base",
   ]
 
-  if (crashpad_is_mac && crashpad_is_in_chromium) {
-    if (is_component_build) {
-      ldflags = [
-        # The handler is in
-        # Chromium.app/Contents/Versions/X/Chromium Framework.framework/Versions/A/Helpers/
-        # so set rpath up to the base.
-        "-rpath",
-        "@loader_path/../../../../../../../..",
-
-        # The handler is also in
-        # Content Shell.app/Contents/Frameworks/Content Shell Framework.framework/Versions/C/Helpers/
-        # so set the rpath for that too.
-        "-rpath",
-        "@loader_path/../../../../../../..",
-
-        # The handler can also be executed in an unbundled framework at
-        # Chromium Framework.framework/Versions/A/Helpers/
-        "-rpath",
-        "@loader_path/../../../..",
-      ]
-    }
-  }
-
   if (crashpad_is_win) {
     if (crashpad_is_in_chromium || crashpad_is_in_dart) {
       remove_configs = [ "//build/config/win:console" ]
diff --git a/third_party/crashpad/crashpad/handler/win/crashy_test_program.cc b/third_party/crashpad/crashpad/handler/win/crashy_test_program.cc
index 990929b..9c8adbb 100644
--- a/third_party/crashpad/crashpad/handler/win/crashy_test_program.cc
+++ b/third_party/crashpad/crashpad/handler/win/crashy_test_program.cc
@@ -101,7 +101,7 @@
   return 0;
 }
 
-// Creates a suspended background thread, and sets EDI/RDI to point at
+// Creates a suspended background thread, and sets EDI/RDI/X17 to point at
 // g_test_memory so we can confirm it's available in the minidump.
 bool CreateThreadWithRegisterPointingToTestMemory() {
   HANDLE thread = CreateThread(
@@ -121,6 +121,8 @@
   context.Rdi = reinterpret_cast<DWORD64>(g_test_memory);
 #elif defined(ARCH_CPU_X86)
   context.Edi = reinterpret_cast<DWORD>(g_test_memory);
+#elif defined(ARCH_CPU_ARM64)
+  context.X17 = reinterpret_cast<DWORD64>(g_test_memory);
 #endif
   if (!SetThreadContext(thread, &context)) {
     PLOG(ERROR) << "SetThreadContext";
diff --git a/third_party/crashpad/crashpad/minidump/minidump_user_stream_writer.cc b/third_party/crashpad/crashpad/minidump/minidump_user_stream_writer.cc
index 139e827..8401b28 100644
--- a/third_party/crashpad/crashpad/minidump/minidump_user_stream_writer.cc
+++ b/third_party/crashpad/crashpad/minidump/minidump_user_stream_writer.cc
@@ -42,7 +42,7 @@
     return snapshot_->Read(this);
   }
 
-  size_t GetSize() const override { return snapshot_ ? snapshot_->Size() : 0; };
+  size_t GetSize() const override { return snapshot_ ? snapshot_->Size() : 0; }
 
   bool MemorySnapshotDelegateRead(void* data, size_t size) override {
     return writer_->Write(data, size);
diff --git a/third_party/crashpad/crashpad/snapshot/crashpad_info_client_options_test.cc b/third_party/crashpad/crashpad/snapshot/crashpad_info_client_options_test.cc
index d1c5f9d..1c5759e 100644
--- a/third_party/crashpad/crashpad/snapshot/crashpad_info_client_options_test.cc
+++ b/third_party/crashpad/crashpad/snapshot/crashpad_info_client_options_test.cc
@@ -326,10 +326,10 @@
   }
 }
 
-INSTANTIATE_TEST_CASE_P(CrashpadInfoSizes_ClientOptions,
-                        CrashpadInfoSizes_ClientOptions,
-                        testing::Values(FILE_PATH_LITERAL("small"),
-                                        FILE_PATH_LITERAL("large")));
+INSTANTIATE_TEST_SUITE_P(CrashpadInfoSizes_ClientOptions,
+                         CrashpadInfoSizes_ClientOptions,
+                         testing::Values(FILE_PATH_LITERAL("small"),
+                                         FILE_PATH_LITERAL("large")));
 
 }  // namespace
 }  // namespace test
diff --git a/third_party/crashpad/crashpad/snapshot/crashpad_types/crashpad_info_reader.cc b/third_party/crashpad/crashpad/snapshot/crashpad_types/crashpad_info_reader.cc
index 527d372..07a9b48 100644
--- a/third_party/crashpad/crashpad/snapshot/crashpad_types/crashpad_info_reader.cc
+++ b/third_party/crashpad/crashpad/snapshot/crashpad_types/crashpad_info_reader.cc
@@ -160,29 +160,29 @@
     return GET_MEMBER(member);                       \
   }
 
-DEFINE_GETTER(TriState, CrashpadHandlerBehavior, crashpad_handler_behavior);
+DEFINE_GETTER(TriState, CrashpadHandlerBehavior, crashpad_handler_behavior)
 
 DEFINE_GETTER(TriState,
               SystemCrashReporterForwarding,
-              system_crash_reporter_forwarding);
+              system_crash_reporter_forwarding)
 
 DEFINE_GETTER(TriState,
               GatherIndirectlyReferencedMemory,
-              gather_indirectly_referenced_memory);
+              gather_indirectly_referenced_memory)
 
 DEFINE_GETTER(uint32_t,
               IndirectlyReferencedMemoryCap,
-              indirectly_referenced_memory_cap);
+              indirectly_referenced_memory_cap)
 
-DEFINE_GETTER(VMAddress, ExtraMemoryRanges, extra_memory_ranges);
+DEFINE_GETTER(VMAddress, ExtraMemoryRanges, extra_memory_ranges)
 
-DEFINE_GETTER(VMAddress, SimpleAnnotations, simple_annotations);
+DEFINE_GETTER(VMAddress, SimpleAnnotations, simple_annotations)
 
-DEFINE_GETTER(VMAddress, AnnotationsList, annotations_list);
+DEFINE_GETTER(VMAddress, AnnotationsList, annotations_list)
 
 DEFINE_GETTER(VMAddress,
               UserDataMinidumpStreamHead,
-              user_data_minidump_stream_head);
+              user_data_minidump_stream_head)
 
 #undef DEFINE_GETTER
 #undef GET_MEMBER
diff --git a/third_party/crashpad/crashpad/snapshot/elf/elf_image_reader_test.cc b/third_party/crashpad/crashpad/snapshot/elf/elf_image_reader_test.cc
index 0846ada..971ed22 100644
--- a/third_party/crashpad/crashpad/snapshot/elf/elf_image_reader_test.cc
+++ b/third_party/crashpad/crashpad/snapshot/elf/elf_image_reader_test.cc
@@ -49,8 +49,8 @@
 #endif  // OS_FUCHSIA
 
 extern "C" {
-__attribute__((visibility("default"))) void
-ElfImageReaderTestExportedSymbol(){};
+__attribute__((visibility("default"))) void ElfImageReaderTestExportedSymbol() {
+}
 }  // extern "C"
 
 namespace crashpad {
diff --git a/third_party/crashpad/crashpad/snapshot/fuchsia/process_snapshot_fuchsia_test.cc b/third_party/crashpad/crashpad/snapshot/fuchsia/process_snapshot_fuchsia_test.cc
index a96d37c..52215a7 100644
--- a/third_party/crashpad/crashpad/snapshot/fuchsia/process_snapshot_fuchsia_test.cc
+++ b/third_party/crashpad/crashpad/snapshot/fuchsia/process_snapshot_fuchsia_test.cc
@@ -58,6 +58,8 @@
     const size_t size = t.pages * PAGE_SIZE;
     zx_status_t status = zx_vmo_create(size, 0, &vmo);
     ZX_CHECK(status == ZX_OK, status) << "zx_vmo_create";
+    status = zx_vmo_replace_as_executable(vmo, ZX_HANDLE_INVALID, &vmo);
+    ZX_CHECK(status == ZX_OK, status) << "zx_vmo_replace_as_executable";
     uintptr_t mapping_addr = 0;
     status = zx_vmar_map(
         zx_vmar_root_self(), t.zircon_perm, 0, vmo, 0, size, &mapping_addr);
diff --git a/third_party/crashpad/crashpad/snapshot/linux/cpu_context_linux.cc b/third_party/crashpad/crashpad/snapshot/linux/cpu_context_linux.cc
index 6ba52a8..8464a5a 100644
--- a/third_party/crashpad/crashpad/snapshot/linux/cpu_context_linux.cc
+++ b/third_party/crashpad/crashpad/snapshot/linux/cpu_context_linux.cc
@@ -17,6 +17,8 @@
 #include <stddef.h>
 #include <string.h>
 
+#include <limits>
+
 #include "base/logging.h"
 
 namespace crashpad {
diff --git a/third_party/crashpad/crashpad/snapshot/minidump/minidump_stream.h b/third_party/crashpad/crashpad/snapshot/minidump/minidump_stream.h
index 1c75cb6..4356b2c 100644
--- a/third_party/crashpad/crashpad/snapshot/minidump/minidump_stream.h
+++ b/third_party/crashpad/crashpad/snapshot/minidump/minidump_stream.h
@@ -25,7 +25,7 @@
 class MinidumpStream {
  public:
   MinidumpStream(uint32_t stream_type, std::vector<uint8_t> data)
-      : stream_type_(stream_type), data_(data){};
+      : stream_type_(stream_type), data_(data) {}
 
   uint32_t stream_type() const { return stream_type_; }
   const std::vector<uint8_t>& data() const { return data_; }
diff --git a/third_party/crashpad/crashpad/test/multiprocess.h b/third_party/crashpad/crashpad/test/multiprocess.h
index d027502..9a221bb3 100644
--- a/third_party/crashpad/crashpad/test/multiprocess.h
+++ b/third_party/crashpad/crashpad/test/multiprocess.h
@@ -26,7 +26,7 @@
 
 namespace internal {
 struct MultiprocessInfo;
-};
+}  // namespace internal
 
 //! \brief Manages a multiprocess test.
 //!
diff --git a/third_party/crashpad/crashpad/test/multiprocess_exec_test.cc b/third_party/crashpad/crashpad/test/multiprocess_exec_test.cc
index 99a1b01f..d290efa 100644
--- a/third_party/crashpad/crashpad/test/multiprocess_exec_test.cc
+++ b/third_party/crashpad/crashpad/test/multiprocess_exec_test.cc
@@ -72,8 +72,7 @@
   TestMultiprocessExec exec;
   exec.SetChildTestMainFunction("SimpleMultiprocess");
   exec.Run();
-};
-
+}
 
 CRASHPAD_CHILD_TEST_MAIN(SimpleMultiprocessReturnsNonZero) {
   return 123;
@@ -96,7 +95,7 @@
   exec.SetExpectedChildTermination(
       Multiprocess::TerminationReason::kTerminationNormal, 123);
   exec.Run();
-};
+}
 
 #if !defined(OS_WIN)
 
diff --git a/third_party/crashpad/crashpad/third_party/gtest/BUILD.gn b/third_party/crashpad/crashpad/third_party/gtest/BUILD.gn
index 541f6402..e124b9e 100644
--- a/third_party/crashpad/crashpad/third_party/gtest/BUILD.gn
+++ b/third_party/crashpad/crashpad/third_party/gtest/BUILD.gn
@@ -56,6 +56,7 @@
     testonly = true
     sources = [
       "gtest/googletest/include/gtest/gtest-death-test.h",
+      "gtest/googletest/include/gtest/gtest-matchers.h",
       "gtest/googletest/include/gtest/gtest-message.h",
       "gtest/googletest/include/gtest/gtest-param-test.h",
       "gtest/googletest/include/gtest/gtest-printers.h",
@@ -71,18 +72,17 @@
       "gtest/googletest/include/gtest/internal/gtest-death-test-internal.h",
       "gtest/googletest/include/gtest/internal/gtest-filepath.h",
       "gtest/googletest/include/gtest/internal/gtest-internal.h",
-      "gtest/googletest/include/gtest/internal/gtest-linked_ptr.h",
       "gtest/googletest/include/gtest/internal/gtest-param-util-generated.h",
       "gtest/googletest/include/gtest/internal/gtest-param-util.h",
       "gtest/googletest/include/gtest/internal/gtest-port-arch.h",
       "gtest/googletest/include/gtest/internal/gtest-port.h",
       "gtest/googletest/include/gtest/internal/gtest-string.h",
-      "gtest/googletest/include/gtest/internal/gtest-tuple.h",
       "gtest/googletest/include/gtest/internal/gtest-type-util.h",
       "gtest/googletest/src/gtest-all.cc",
       "gtest/googletest/src/gtest-death-test.cc",
       "gtest/googletest/src/gtest-filepath.cc",
       "gtest/googletest/src/gtest-internal-inl.h",
+      "gtest/googletest/src/gtest-matchers.cc",
       "gtest/googletest/src/gtest-port.cc",
       "gtest/googletest/src/gtest-printers.cc",
       "gtest/googletest/src/gtest-test-part.cc",
@@ -130,6 +130,7 @@
       "gtest/googletest/test/gtest_main_unittest.cc",
       "gtest/googletest/test/gtest_pred_impl_unittest.cc",
       "gtest/googletest/test/gtest_prod_test.cc",
+      "gtest/googletest/test/gtest_skip_test.cc",
       "gtest/googletest/test/gtest_unittest.cc",
       "gtest/googletest/test/production.cc",
       "gtest/googletest/test/production.h",
@@ -288,13 +289,14 @@
     sources = [
       "gtest/googlemock/include/gmock/gmock-actions.h",
       "gtest/googlemock/include/gmock/gmock-cardinalities.h",
+      "gtest/googlemock/include/gmock/gmock-function-mocker.h",
       "gtest/googlemock/include/gmock/gmock-generated-actions.h",
       "gtest/googlemock/include/gmock/gmock-generated-function-mockers.h",
       "gtest/googlemock/include/gmock/gmock-generated-matchers.h",
-      "gtest/googlemock/include/gmock/gmock-generated-nice-strict.h",
       "gtest/googlemock/include/gmock/gmock-matchers.h",
       "gtest/googlemock/include/gmock/gmock-more-actions.h",
       "gtest/googlemock/include/gmock/gmock-more-matchers.h",
+      "gtest/googlemock/include/gmock/gmock-nice-strict.h",
       "gtest/googlemock/include/gmock/gmock-spec-builders.h",
       "gtest/googlemock/include/gmock/gmock.h",
       "gtest/googlemock/include/gmock/internal/custom/gmock-generated-actions.h",
@@ -303,6 +305,7 @@
       "gtest/googlemock/include/gmock/internal/gmock-generated-internal-utils.h",
       "gtest/googlemock/include/gmock/internal/gmock-internal-utils.h",
       "gtest/googlemock/include/gmock/internal/gmock-port.h",
+      "gtest/googlemock/include/gmock/internal/gmock-pp.h",
       "gtest/googlemock/src/gmock-all.cc",
       "gtest/googlemock/src/gmock-cardinalities.cc",
       "gtest/googlemock/src/gmock-internal-utils.cc",
@@ -338,15 +341,17 @@
     sources = [
       "gtest/googlemock/test/gmock-actions_test.cc",
       "gtest/googlemock/test/gmock-cardinalities_test.cc",
+      "gtest/googlemock/test/gmock-function-mocker_test.cc",
       "gtest/googlemock/test/gmock-generated-actions_test.cc",
       "gtest/googlemock/test/gmock-generated-function-mockers_test.cc",
-      "gtest/googlemock/test/gmock-generated-internal-utils_test.cc",
       "gtest/googlemock/test/gmock-generated-matchers_test.cc",
       "gtest/googlemock/test/gmock-internal-utils_test.cc",
       "gtest/googlemock/test/gmock-matchers_test.cc",
       "gtest/googlemock/test/gmock-more-actions_test.cc",
       "gtest/googlemock/test/gmock-nice-strict_test.cc",
       "gtest/googlemock/test/gmock-port_test.cc",
+      "gtest/googlemock/test/gmock-pp-string_test.cc",
+      "gtest/googlemock/test/gmock-pp_test.cc",
       "gtest/googlemock/test/gmock-spec-builders_test.cc",
       "gtest/googlemock/test/gmock_test.cc",
     ]
diff --git a/third_party/crashpad/crashpad/third_party/gtest/gmock.gyp b/third_party/crashpad/crashpad/third_party/gtest/gmock.gyp
index d53c925..499792f 100644
--- a/third_party/crashpad/crashpad/third_party/gtest/gmock.gyp
+++ b/third_party/crashpad/crashpad/third_party/gtest/gmock.gyp
@@ -56,18 +56,20 @@
       'sources': [
         '<(gmock_dir)/include/gmock/gmock-actions.h',
         '<(gmock_dir)/include/gmock/gmock-cardinalities.h',
+        '<(gmock_dir)/include/gmock/gmock-function-mocker.h',
         '<(gmock_dir)/include/gmock/gmock-generated-actions.h',
         '<(gmock_dir)/include/gmock/gmock-generated-function-mockers.h',
         '<(gmock_dir)/include/gmock/gmock-generated-matchers.h',
-        '<(gmock_dir)/include/gmock/gmock-generated-nice-strict.h',
         '<(gmock_dir)/include/gmock/gmock-matchers.h',
         '<(gmock_dir)/include/gmock/gmock-more-actions.h',
         '<(gmock_dir)/include/gmock/gmock-more-matchers.h',
+        '<(gmock_dir)/include/gmock/gmock-nice-strict.h',
         '<(gmock_dir)/include/gmock/gmock-spec-builders.h',
         '<(gmock_dir)/include/gmock/gmock.h',
         '<(gmock_dir)/include/gmock/internal/custom/gmock-generated-actions.h',
         '<(gmock_dir)/include/gmock/internal/custom/gmock-matchers.h',
         '<(gmock_dir)/include/gmock/internal/custom/gmock-port.h',
+        '<(gmock_dir)/include/gmock/internal/custom/gmock-pp.h',
         '<(gmock_dir)/include/gmock/internal/gmock-generated-internal-utils.h',
         '<(gmock_dir)/include/gmock/internal/gmock-internal-utils.h',
         '<(gmock_dir)/include/gmock/internal/gmock-port.h',
@@ -156,15 +158,17 @@
       'sources': [
         '<(gmock_dir)/test/gmock-actions_test.cc',
         '<(gmock_dir)/test/gmock-cardinalities_test.cc',
+        '<(gmock_dir)/test/gmock-function-mocker_test.cc',
         '<(gmock_dir)/test/gmock-generated-actions_test.cc',
         '<(gmock_dir)/test/gmock-generated-function-mockers_test.cc',
-        '<(gmock_dir)/test/gmock-generated-internal-utils_test.cc',
         '<(gmock_dir)/test/gmock-generated-matchers_test.cc',
         '<(gmock_dir)/test/gmock-internal-utils_test.cc',
         '<(gmock_dir)/test/gmock-matchers_test.cc',
         '<(gmock_dir)/test/gmock-more-actions_test.cc',
         '<(gmock_dir)/test/gmock-nice-strict_test.cc',
         '<(gmock_dir)/test/gmock-port_test.cc',
+        '<(gmock_dir)/test/gmock-pp-string_test.cc',
+        '<(gmock_dir)/test/gmock-pp_test.cc',
         '<(gmock_dir)/test/gmock-spec-builders_test.cc',
         '<(gmock_dir)/test/gmock_test.cc',
       ],
diff --git a/third_party/crashpad/crashpad/third_party/gtest/gtest.gyp b/third_party/crashpad/crashpad/third_party/gtest/gtest.gyp
index 5d93feb..aa6399b 100644
--- a/third_party/crashpad/crashpad/third_party/gtest/gtest.gyp
+++ b/third_party/crashpad/crashpad/third_party/gtest/gtest.gyp
@@ -67,6 +67,7 @@
       ],
       'sources': [
         '<(gtest_dir)/include/gtest/gtest-death-test.h',
+        '<(gtest_dir)/include/gtest/gtest-matchers.h',
         '<(gtest_dir)/include/gtest/gtest-message.h',
         '<(gtest_dir)/include/gtest/gtest-param-test.h',
         '<(gtest_dir)/include/gtest/gtest-printers.h',
@@ -82,18 +83,17 @@
         '<(gtest_dir)/include/gtest/internal/gtest-death-test-internal.h',
         '<(gtest_dir)/include/gtest/internal/gtest-filepath.h',
         '<(gtest_dir)/include/gtest/internal/gtest-internal.h',
-        '<(gtest_dir)/include/gtest/internal/gtest-linked_ptr.h',
         '<(gtest_dir)/include/gtest/internal/gtest-param-util-generated.h',
         '<(gtest_dir)/include/gtest/internal/gtest-param-util.h',
         '<(gtest_dir)/include/gtest/internal/gtest-port-arch.h',
         '<(gtest_dir)/include/gtest/internal/gtest-port.h',
         '<(gtest_dir)/include/gtest/internal/gtest-string.h',
-        '<(gtest_dir)/include/gtest/internal/gtest-tuple.h',
         '<(gtest_dir)/include/gtest/internal/gtest-type-util.h',
         '<(gtest_dir)/src/gtest-all.cc',
         '<(gtest_dir)/src/gtest-death-test.cc',
         '<(gtest_dir)/src/gtest-filepath.cc',
         '<(gtest_dir)/src/gtest-internal-inl.h',
+        '<(gtest_dir)/src/gtest-matchers.cc',
         '<(gtest_dir)/src/gtest-port.cc',
         '<(gtest_dir)/src/gtest-printers.cc',
         '<(gtest_dir)/src/gtest-test-part.cc',
@@ -174,6 +174,7 @@
         '<(gtest_dir)/test/gtest_main_unittest.cc',
         '<(gtest_dir)/test/gtest_pred_impl_unittest.cc',
         '<(gtest_dir)/test/gtest_prod_test.cc',
+        '<(gtest_dir)/test/gtest_skip_test.cc',
         '<(gtest_dir)/test/gtest_unittest.cc',
         '<(gtest_dir)/test/production.cc',
         '<(gtest_dir)/test/production.h',
diff --git a/third_party/crashpad/crashpad/tools/generate_dump.cc b/third_party/crashpad/crashpad/tools/generate_dump.cc
index 9fb5a96109..35a4e05 100644
--- a/third_party/crashpad/crashpad/tools/generate_dump.cc
+++ b/third_party/crashpad/crashpad/tools/generate_dump.cc
@@ -26,11 +26,12 @@
 #include "minidump/minidump_file_writer.h"
 #include "tools/tool_support.h"
 #include "util/file/file_writer.h"
-#include "util/posix/drop_privileges.h"
 #include "util/stdlib/string_number_conversion.h"
 
 #if defined(OS_POSIX)
 #include <unistd.h>
+
+#include "util/posix/drop_privileges.h"
 #endif
 
 #if defined(OS_MACOSX)
diff --git a/third_party/crashpad/crashpad/util/linux/memory_map.cc b/third_party/crashpad/crashpad/util/linux/memory_map.cc
index 4f02ce8..17fd7a3 100644
--- a/third_party/crashpad/crashpad/util/linux/memory_map.cc
+++ b/third_party/crashpad/crashpad/util/linux/memory_map.cc
@@ -210,7 +210,7 @@
 class SparseReverseIterator : public MemoryMap::Iterator {
  public:
   SparseReverseIterator(const std::vector<const MemoryMap::Mapping*>& mappings)
-      : mappings_(mappings), riter_(mappings_.rbegin()){};
+      : mappings_(mappings), riter_(mappings_.rbegin()) {}
 
   SparseReverseIterator() : mappings_(), riter_(mappings_.rend()) {}
 
diff --git a/third_party/crashpad/crashpad/util/misc/from_pointer_cast_test.cc b/third_party/crashpad/crashpad/util/misc/from_pointer_cast_test.cc
index 1a6850f..ce53de5 100644
--- a/third_party/crashpad/crashpad/util/misc/from_pointer_cast_test.cc
+++ b/third_party/crashpad/crashpad/util/misc/from_pointer_cast_test.cc
@@ -41,7 +41,7 @@
                                                 volatile SomeType*,
                                                 const volatile SomeType*>;
 
-TYPED_TEST_CASE(FromPointerCastTest, FromPointerCastTestTypes);
+TYPED_TEST_SUITE(FromPointerCastTest, FromPointerCastTestTypes);
 
 TYPED_TEST(FromPointerCastTest, ToSigned) {
   EXPECT_EQ(FromPointerCast<int64_t>(nullptr), 0);
diff --git a/third_party/crashpad/crashpad/util/misc/lexing.cc b/third_party/crashpad/crashpad/util/misc/lexing.cc
index 6c31865..5e8fa30 100644
--- a/third_party/crashpad/crashpad/util/misc/lexing.cc
+++ b/third_party/crashpad/crashpad/util/misc/lexing.cc
@@ -32,10 +32,10 @@
   bool ConvertStringToNumber(const base::StringPiece& input, type* value) { \
     return function(input, value);                                          \
   }
-MAKE_ADAPTER(int, base::StringToInt);
-MAKE_ADAPTER(unsigned int, base::StringToUint);
-MAKE_ADAPTER(int64_t, base::StringToInt64);
-MAKE_ADAPTER(uint64_t, base::StringToUint64);
+MAKE_ADAPTER(int, base::StringToInt)
+MAKE_ADAPTER(unsigned int, base::StringToUint)
+MAKE_ADAPTER(int64_t, base::StringToInt64)
+MAKE_ADAPTER(uint64_t, base::StringToUint64)
 #undef MAKE_ADAPTER
 
 }  // namespace
diff --git a/third_party/crashpad/crashpad/util/net/http_body_test.cc b/third_party/crashpad/crashpad/util/net/http_body_test.cc
index e48cbf9..1e5a479 100644
--- a/third_party/crashpad/crashpad/util/net/http_body_test.cc
+++ b/third_party/crashpad/crashpad/util/net/http_body_test.cc
@@ -207,9 +207,9 @@
   EXPECT_EQ(actual_string, expected_string);
 }
 
-INSTANTIATE_TEST_CASE_P(VariableBufferSize,
-                        CompositeHTTPBodyStreamBufferSize,
-                        testing::Values(1, 2, 9, 16, 31, 128, 1024));
+INSTANTIATE_TEST_SUITE_P(VariableBufferSize,
+                         CompositeHTTPBodyStreamBufferSize,
+                         testing::Values(1, 2, 9, 16, 31, 128, 1024));
 
 }  // namespace
 }  // namespace test
diff --git a/third_party/crashpad/crashpad/util/net/http_transport_test.cc b/third_party/crashpad/crashpad/util/net/http_transport_test.cc
index 19422ec..f7888c0 100644
--- a/third_party/crashpad/crashpad/util/net/http_transport_test.cc
+++ b/third_party/crashpad/crashpad/util/net/http_transport_test.cc
@@ -371,14 +371,14 @@
 // lacking libcrypto.so.1.1, so disabled there for now. On Mac, they could also
 // likely be enabled relatively easily, if HTTPTransportMac learned to respect
 // the user-supplied cert.
-INSTANTIATE_TEST_CASE_P(HTTPTransport,
-                        HTTPTransport,
-                        testing::Values(FILE_PATH_LITERAL("http"),
-                                        FILE_PATH_LITERAL("https")));
+INSTANTIATE_TEST_SUITE_P(HTTPTransport,
+                         HTTPTransport,
+                         testing::Values(FILE_PATH_LITERAL("http"),
+                                         FILE_PATH_LITERAL("https")));
 #else
-INSTANTIATE_TEST_CASE_P(HTTPTransport,
-                        HTTPTransport,
-                        testing::Values(FILE_PATH_LITERAL("http")));
+INSTANTIATE_TEST_SUITE_P(HTTPTransport,
+                         HTTPTransport,
+                         testing::Values(FILE_PATH_LITERAL("http")));
 #endif
 
 }  // namespace
diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml
index 435bc8e..37e20c9 100644
--- a/tools/metrics/histograms/histograms.xml
+++ b/tools/metrics/histograms/histograms.xml
@@ -48703,8 +48703,8 @@
   </summary>
 </histogram>
 
-<histogram
-    name="Media.Learning.MediaCapabilities.DroppedFrameRatioTask.BaseTable"
+<histogram base="true"
+    name="Media.Learning.MediaCapabilities.DroppedFrameRatioTask"
     units="ConfusionMatrix" expires_after="2019-06-30">
   <owner>liberato@chromium.org</owner>
   <owner>chcunningham@chromium.org</owner>
@@ -48722,21 +48722,17 @@
 
     This is very similar to the existing MediaCapabilities implementation, but
     uses the same training set as other learners.
-  </summary>
-</histogram>
 
-<histogram
-    name="Media.Learning.MediaCapabilities.DroppedFrameRatioTask.BaseTree"
-    units="ConfusionMatrix" expires_after="2019-06-30">
-  <owner>liberato@chromium.org</owner>
-  <owner>chcunningham@chromium.org</owner>
-  <summary>
-    Confusion matrix for MediaCapabilities local learning experiment, using
-    ExtraTrees regression and the base MediaCapabilities features (resolution,
-    frame rate, video format). A positive outcome is smooth playback, while a
-    negative outcome is not smooth. For example, a False Negative indicates that
-    we predicted a negative result (not smooth playback), but we later observed
-    that the result was positive (smooth playback).
+    The &quot;BaseTable&quot; variant uses a lookup table as the model, and uses
+    the original MediaCapabilities features (resolution, frame rate, video
+    format).
+
+    The &quot;BaseTree&quot; variant uses ExtraTrees model and the same features
+    as the BaseTable variant.
+
+    The &quot;EnhancedTree&quot; variant uses ExtraTrees, plus additional
+    features such as NetworkType. The exact set of features is still in flux, so
+    be sure to restrict reporting to a particular Chromium version.
   </summary>
 </histogram>
 
@@ -140627,19 +140623,19 @@
   <affected-histogram
       name="PageLoad.Experimental.AbortTiming.ForwardBackNavigation.BeforeCommit">
     <obsolete>
-      Deprecated in favor of UserGesture/UserInputEvent/BrowserInitiated.
+      Deprecated in favor of UserGesture/BrowserInitiated.
     </obsolete>
   </affected-histogram>
   <affected-histogram
       name="PageLoad.Experimental.AbortTiming.NewNavigation.BeforeCommit">
     <obsolete>
-      Deprecated in favor of UserGesture/UserInputEvent/BrowserInitiated.
+      Deprecated in favor of UserGesture/BrowserInitiated.
     </obsolete>
   </affected-histogram>
   <affected-histogram
       name="PageLoad.Experimental.AbortTiming.Reload.BeforeCommit">
     <obsolete>
-      Deprecated in favor of UserGesture/UserInputEvent/BrowserInitiated.
+      Deprecated in favor of UserGesture/BrowserInitiated.
     </obsolete>
   </affected-histogram>
   <affected-histogram
@@ -140652,8 +140648,11 @@
              process"/>
   <suffix name="UserGesture"
       label="(experimental) Page load that has a user gesture"/>
-  <suffix name="UserInputEvent"
-      label="(experimental) Page load that has a user input event"/>
+  <suffix name="UserInputEvent">
+    <obsolete>
+      Deprecated in favor of UserGesture.
+    </obsolete>
+  </suffix>
   <affected-histogram
       name="PageLoad.Experimental.AbortTiming.ForwardBackNavigation.AfterCommit.BeforePaint"/>
   <affected-histogram
diff --git a/tools/metrics/ukm/ukm.xml b/tools/metrics/ukm/ukm.xml
index 0791751..8c02128 100644
--- a/tools/metrics/ukm/ukm.xml
+++ b/tools/metrics/ukm/ukm.xml
@@ -125,6 +125,27 @@
   </metric>
 </event>
 
+<event name="AmpPageLoad" singular="True">
+  <owner>sullivan@chromium.org</owner>
+  <metric name="MainFrameAmpPageLoad">
+    <summary>
+      True if the page loaded in the main frame is an AMP document (has an amp
+      attribute in the html element). Will not be recorded for non-AMP frames.
+      Note that most AMP documents are loaded in a subframe from a reader like
+      Google Search; this metric measures sites that are using AMP as a
+      site-wide framework and not a reader experience.
+    </summary>
+  </metric>
+  <metric name="SubFrameAmpPageLoad">
+    <summary>
+      True if the page loaded in any subframe is an AMP document (has an amp
+      attribute in the html element). Will not be recorded for non-AMP frames.
+      Note that most AMP documents are loaded in a subframe from a reader like
+      Google Search; this metric measures usage of such readers.
+    </summary>
+  </metric>
+</event>
+
 <event name="Autofill.CardUploadDecision">
   <owner>sebsg@chromium.org</owner>
   <metric name="UploadDecision">
diff --git a/tools/traffic_annotation/auditor/auditor_result.cc b/tools/traffic_annotation/auditor/auditor_result.cc
index 501b89d..5c030bf 100644
--- a/tools/traffic_annotation/auditor/auditor_result.cc
+++ b/tools/traffic_annotation/auditor/auditor_result.cc
@@ -34,7 +34,7 @@
          type == AuditorResult::Type::ERROR_INVALID_OS);
   if (!message.empty())
     details_.push_back(message);
-};
+}
 
 AuditorResult::AuditorResult(Type type, const std::string& message)
     : AuditorResult::AuditorResult(type,
@@ -49,7 +49,6 @@
                                    kNoCodeLineSpecified) {}
 
 AuditorResult::AuditorResult(const AuditorResult& other) = default;
-;
 
 AuditorResult::~AuditorResult() = default;
 
diff --git a/tools/traffic_annotation/auditor/auditor_result.h b/tools/traffic_annotation/auditor/auditor_result.h
index d65c7a7..a68d68c 100644
--- a/tools/traffic_annotation/auditor/auditor_result.h
+++ b/tools/traffic_annotation/auditor/auditor_result.h
@@ -67,7 +67,7 @@
 
   void AddDetail(const std::string& message);
 
-  Type type() const { return type_; };
+  Type type() const { return type_; }
 
   std::string file_path() const { return file_path_; }
   void set_file_path(const std::string& file_path) { file_path_ = file_path; }
diff --git a/tools/traffic_annotation/auditor/instance.cc b/tools/traffic_annotation/auditor/instance.cc
index 62ecb23..9ddac6d 100644
--- a/tools/traffic_annotation/auditor/instance.cc
+++ b/tools/traffic_annotation/auditor/instance.cc
@@ -124,7 +124,7 @@
       second_id_hash_code(other.second_id_hash_code),
       archive_content_hash_code(other.archive_content_hash_code),
       is_loaded_from_archive(other.is_loaded_from_archive),
-      is_merged(other.is_merged){};
+      is_merged(other.is_merged) {}
 
 AuditorResult AnnotationInstance::Deserialize(
     const std::vector<std::string>& serialized_lines,
@@ -652,7 +652,7 @@
       line_number(other.line_number),
       function_context(other.function_context),
       function_name(other.function_name),
-      is_annotated(other.is_annotated){};
+      is_annotated(other.is_annotated) {}
 
 AuditorResult CallInstance::Deserialize(
     const std::vector<std::string>& serialized_lines,
@@ -680,7 +680,7 @@
 AssignmentInstance::AssignmentInstance(const AssignmentInstance& other)
     : file_path(other.file_path),
       line_number(other.line_number),
-      function_context(other.function_context){};
+      function_context(other.function_context) {}
 
 AuditorResult AssignmentInstance::Deserialize(
     const std::vector<std::string>& serialized_lines,
@@ -696,4 +696,4 @@
   base::StringToInt(serialized_lines[start_line++], &line_number_int);
   line_number = static_cast<uint32_t>(line_number_int);
   return AuditorResult(AuditorResult::Type::RESULT_OK);
-}
\ No newline at end of file
+}
diff --git a/tools/traffic_annotation/auditor/traffic_annotation_auditor.h b/tools/traffic_annotation/auditor/traffic_annotation_auditor.h
index e6b2d32..c95e5f3a 100644
--- a/tools/traffic_annotation/auditor/traffic_annotation_auditor.h
+++ b/tools/traffic_annotation/auditor/traffic_annotation_auditor.h
@@ -117,11 +117,11 @@
   // net/traffic_annotation/network_traffic_annotation_test_helper.h
   static std::set<int> GetReservedIDsSet();
 
-  std::string clang_tool_raw_output() const { return clang_tool_raw_output_; };
+  std::string clang_tool_raw_output() const { return clang_tool_raw_output_; }
 
   void set_clang_tool_raw_output(const std::string& raw_output) {
     clang_tool_raw_output_ = raw_output;
-  };
+  }
 
   const std::vector<AnnotationInstance>& extracted_annotations() const {
     return extracted_annotations_;
diff --git a/tools/traffic_annotation/auditor/traffic_annotation_auditor_unittest.cc b/tools/traffic_annotation/auditor/traffic_annotation_auditor_unittest.cc
index e6191414..5b0322ae 100644
--- a/tools/traffic_annotation/auditor/traffic_annotation_auditor_unittest.cc
+++ b/tools/traffic_annotation/auditor/traffic_annotation_auditor_unittest.cc
@@ -88,7 +88,7 @@
   }
 
   const base::FilePath source_path() const { return source_path_; }
-  const base::FilePath tests_folder() const { return tests_folder_; };
+  const base::FilePath tests_folder() const { return tests_folder_; }
   TrafficAnnotationAuditor& auditor() { return *auditor_; }
   TrafficAnnotationIDChecker& id_checker() { return *id_checker_; }
   std::vector<AuditorResult>* errors() { return &errors_; }
diff --git a/ui/accessibility/platform/ax_platform_node_auralinux.cc b/ui/accessibility/platform/ax_platform_node_auralinux.cc
index 4e0cdb1..4bf4270 100644
--- a/ui/accessibility/platform/ax_platform_node_auralinux.cc
+++ b/ui/accessibility/platform/ax_platform_node_auralinux.cc
@@ -1313,22 +1313,30 @@
          role == ATK_ROLE_SPIN_BUTTON;
 }
 
-}  // namespace
+static void SetWeakGPtrToAtkObject(AtkObject** weak_pointer,
+                                   AtkObject* new_value) {
+  if (*weak_pointer == new_value)
+    return;
+
+  if (*weak_pointer) {
+    g_object_remove_weak_pointer(G_OBJECT(*weak_pointer),
+                                 reinterpret_cast<void**>(weak_pointer));
+  }
+
+  *weak_pointer = new_value;
+
+  if (new_value) {
+    g_object_add_weak_pointer(G_OBJECT(new_value),
+                              reinterpret_cast<void**>(weak_pointer));
+  }
+}
 
 static void SetActiveTopLevelFrame(AtkObject* new_top_level_frame) {
-  if (g_active_top_level_frame)
-    g_object_remove_weak_pointer(
-        G_OBJECT(g_active_top_level_frame),
-        reinterpret_cast<void**>(&g_active_top_level_frame));
-
-  g_active_top_level_frame = new_top_level_frame;
-
-  if (g_active_top_level_frame)
-    g_object_add_weak_pointer(
-        G_OBJECT(g_active_top_level_frame),
-        reinterpret_cast<void**>(&g_active_top_level_frame));
+  SetWeakGPtrToAtkObject(&g_active_top_level_frame, new_top_level_frame);
 }
 
+}  // namespace
+
 void AXPlatformNodeAuraLinux::EnsureGTypeInit() {
 #if !GLIB_CHECK_VERSION(2, 36, 0)
   static bool first_time = true;
@@ -2031,6 +2039,16 @@
 AtkRelationSet* AXPlatformNodeAuraLinux::GetAtkRelations() {
   AtkRelationSet* relation_set = atk_relation_set_new();
 
+  if (embedded_document_) {
+    atk_relation_set_add_relation_by_type(relation_set, ATK_RELATION_EMBEDS,
+                                          embedded_document_);
+  }
+
+  if (embedding_window_) {
+    atk_relation_set_add_relation_by_type(
+        relation_set, ATK_RELATION_EMBEDDED_BY, embedding_window_);
+  }
+
   // For each possible relation defined by an IntAttribute, we test that
   // attribute and then look for reverse relations. AddRelationToSet handles
   // discarding self-referential relations.
@@ -2081,6 +2099,9 @@
     g_current_selected = nullptr;
 
   DestroyAtkObjects();
+
+  SetWeakGPtrToAtkObject(&embedded_document_, nullptr);
+  SetWeakGPtrToAtkObject(&embedding_window_, nullptr);
 }
 
 void AXPlatformNodeAuraLinux::Destroy() {
@@ -2317,6 +2338,10 @@
     OnFocused();
 }
 
+void AXPlatformNodeAuraLinux::OnSelectedChildrenChanged() {
+  g_signal_emit_by_name(ATK_OBJECT(atk_object_), "selection-changed", true);
+}
+
 bool AXPlatformNodeAuraLinux::SelectionAndFocusAreTheSame() {
   if (AXPlatformNodeBase* container = GetSelectionContainer()) {
     ax::mojom::Role role = container->GetData().role;
@@ -2401,6 +2426,9 @@
     case ax::mojom::Event::kSelection:
       OnSelected();
       break;
+    case ax::mojom::Event::kSelectedChildrenChanged:
+      OnSelectedChildrenChanged();
+      break;
     case ax::mojom::Event::kValueChanged:
       OnValueChanged();
       break;
@@ -2617,4 +2645,14 @@
   return base::UTF16ToUTF8(hypertext_.hypertext);
 }
 
+void AXPlatformNodeAuraLinux::SetEmbeddedDocument(
+    AtkObject* new_embedded_document) {
+  SetWeakGPtrToAtkObject(&embedded_document_, new_embedded_document);
+}
+
+void AXPlatformNodeAuraLinux::SetEmbeddingWindow(
+    AtkObject* new_embedding_window) {
+  SetWeakGPtrToAtkObject(&embedding_window_, new_embedding_window);
+}
+
 }  // namespace ui
diff --git a/ui/accessibility/platform/ax_platform_node_auralinux.h b/ui/accessibility/platform/ax_platform_node_auralinux.h
index 749623b..25aebebf 100644
--- a/ui/accessibility/platform/ax_platform_node_auralinux.h
+++ b/ui/accessibility/platform/ax_platform_node_auralinux.h
@@ -85,6 +85,7 @@
   void OnMenuPopupHide();
   void OnMenuPopupEnd();
   void OnSelected();
+  void OnSelectedChildrenChanged();
   void OnValueChanged();
 
   bool SupportsSelectionWithAtkSelection();
@@ -103,6 +104,9 @@
   void UpdateHypertext();
   const AXHypertext& GetHypertext();
 
+  void SetEmbeddedDocument(AtkObject* new_document);
+  void SetEmbeddingWindow(AtkObject* new_embedding_window);
+
  protected:
   AXHypertext hypertext_;
 
@@ -145,6 +149,10 @@
   AtkObject* atk_object_ = nullptr;
   AtkHyperlink* atk_hyperlink_ = nullptr;
 
+  // Some weak pointers which help us track ATK embeds / embedded by relations.
+  AtkObject* embedded_document_ = nullptr;
+  AtkObject* embedding_window_ = nullptr;
+
   DISALLOW_COPY_AND_ASSIGN(AXPlatformNodeAuraLinux);
 };
 
diff --git a/ui/aura/gestures/gesture_recognizer_unittest.cc b/ui/aura/gestures/gesture_recognizer_unittest.cc
index 29df015..266037d 100644
--- a/ui/aura/gestures/gesture_recognizer_unittest.cc
+++ b/ui/aura/gestures/gesture_recognizer_unittest.cc
@@ -146,7 +146,7 @@
     flags_ = 0;
   }
 
-  const std::vector<ui::EventType>& events() const { return events_; };
+  const std::vector<ui::EventType>& events() const { return events_; }
 
   bool tap() const { return tap_; }
   bool tap_down() const { return tap_down_; }
diff --git a/ui/aura/window_event_dispatcher.cc b/ui/aura/window_event_dispatcher.cc
index f95080f..c3ba085 100644
--- a/ui/aura/window_event_dispatcher.cc
+++ b/ui/aura/window_event_dispatcher.cc
@@ -1080,9 +1080,10 @@
 
   host_->window()->env()->env_controller()->UpdateStateForTouchEvent(*event);
 
-  ui::TouchEvent orig_event(*event, target, window());
-  if (!env_->gesture_recognizer()->ProcessTouchEventPreDispatch(&orig_event,
-                                                                target)) {
+  ui::TouchEvent root_relative_event(*event);
+  root_relative_event.set_location_f(event->root_location_f());
+  if (!env_->gesture_recognizer()->ProcessTouchEventPreDispatch(
+          &root_relative_event, target)) {
     // The event is invalid - ignore it.
     event->StopPropagation();
     event->DisableSynchronousHandling();
@@ -1093,7 +1094,7 @@
 
   // This flag is set depending on the gestures recognized in the call above,
   // and needs to propagate with the forwarded event.
-  event->set_may_cause_scrolling(orig_event.may_cause_scrolling());
+  event->set_may_cause_scrolling(root_relative_event.may_cause_scrolling());
 
   return PreDispatchLocatedEvent(target, event);
 }
diff --git a/ui/base/models/simple_menu_model.cc b/ui/base/models/simple_menu_model.cc
index 8b546f8..f86a83e 100644
--- a/ui/base/models/simple_menu_model.cc
+++ b/ui/base/models/simple_menu_model.cc
@@ -21,6 +21,14 @@
 ////////////////////////////////////////////////////////////////////////////////
 // SimpleMenuModel::Delegate, public:
 
+bool SimpleMenuModel::Delegate::IsCommandIdChecked(int command_id) const {
+  return false;
+}
+
+bool SimpleMenuModel::Delegate::IsCommandIdEnabled(int command_id) const {
+  return true;
+}
+
 bool SimpleMenuModel::Delegate::IsCommandIdVisible(int command_id) const {
   return true;
 }
diff --git a/ui/base/models/simple_menu_model.h b/ui/base/models/simple_menu_model.h
index 0fe28e1..71dcec2 100644
--- a/ui/base/models/simple_menu_model.h
+++ b/ui/base/models/simple_menu_model.h
@@ -30,9 +30,14 @@
    public:
     ~Delegate() override {}
 
-    // Methods for determining the state of specific command ids.
-    virtual bool IsCommandIdChecked(int command_id) const = 0;
-    virtual bool IsCommandIdEnabled(int command_id) const = 0;
+    // Makes |command_id| appear toggled true if it's a "check" or "radio" type
+    // menu item. This has no effect for menu items with no boolean state.
+    virtual bool IsCommandIdChecked(int command_id) const;
+
+    // Delegate should return true if |command_id| should be enabled.
+    virtual bool IsCommandIdEnabled(int command_id) const;
+
+    // Delegate should return true if |command_id| should be visible.
     virtual bool IsCommandIdVisible(int command_id) const;
 
     // Some command ids have labels, sublabels, minor text and icons that change
diff --git a/ui/base/x/x11_util.cc b/ui/base/x/x11_util.cc
index 3bcb620..b5d9736 100644
--- a/ui/base/x/x11_util.cc
+++ b/ui/base/x/x11_util.cc
@@ -269,9 +269,7 @@
       return false;
     }
 
-    const XcursorImage* image() const {
-      return image_;
-    };
+    const XcursorImage* image() const { return image_; }
 
    private:
     XcursorImage* image_;
diff --git a/ui/display/mojo/display_mode_struct_traits.cc b/ui/display/mojo/display_mode_struct_traits.cc
index b076658f..7c65a2d 100644
--- a/ui/display/mojo/display_mode_struct_traits.cc
+++ b/ui/display/mojo/display_mode_struct_traits.cc
@@ -19,6 +19,6 @@
   *out = std::make_unique<display::DisplayMode>(size, data.is_interlaced(),
                                                 data.refresh_rate());
   return true;
-};
+}
 
 }  // namespace mojo
diff --git a/ui/events/ozone/layout/xkb/xkb_keyboard_layout_engine.cc b/ui/events/ozone/layout/xkb/xkb_keyboard_layout_engine.cc
index 19d0e00d..ca76e6f971 100644
--- a/ui/events/ozone/layout/xkb/xkb_keyboard_layout_engine.cc
+++ b/ui/events/ozone/layout/xkb/xkb_keyboard_layout_engine.cc
@@ -824,9 +824,11 @@
                {ui::EF_COMMAND_DOWN, XKB_MOD_NAME_LOGO},
                {ui::EF_ALTGR_DOWN, "Mod5"},
                {ui::EF_MOD3_DOWN, "Mod3"},
-               {ui::EF_CAPS_LOCK_ON, XKB_MOD_NAME_CAPS}};
+               {ui::EF_CAPS_LOCK_ON, XKB_MOD_NAME_CAPS},
+               {ui::EF_NUM_LOCK_ON, XKB_MOD_NAME_NUM}};
   xkb_flag_map_.clear();
   xkb_flag_map_.reserve(base::size(flags));
+  xkb_mod_mask_t num_lock_mask = 0;
   for (size_t i = 0; i < base::size(flags); ++i) {
     xkb_mod_index_t index = xkb_keymap_mod_get_index(keymap, flags[i].xkb_name);
     if (index == XKB_MOD_INVALID) {
@@ -835,16 +837,13 @@
       xkb_mod_mask_t flag = static_cast<xkb_mod_mask_t>(1) << index;
       XkbFlagMapEntry e = {flags[i].ui_flag, flag, index};
       xkb_flag_map_.push_back(e);
+      if (flags[i].ui_flag == EF_NUM_LOCK_ON)
+        num_lock_mask = flag;
     }
   }
-
 #if defined(OS_CHROMEOS)
   // Update num lock mask.
-  num_lock_mod_mask_ = 0;
-  xkb_mod_index_t num_mod_index =
-      xkb_keymap_mod_get_index(keymap, XKB_MOD_NAME_NUM);
-  if (num_mod_index != XKB_MOD_INVALID)
-    num_lock_mod_mask_ = static_cast<xkb_mod_mask_t>(1) << num_mod_index;
+  num_lock_mod_mask_ = num_lock_mask;
 #endif
 }
 
diff --git a/ui/file_manager/video_player/js/video_player_native_controls.js b/ui/file_manager/video_player/js/video_player_native_controls.js
index 71bb4b0..a6216a3 100644
--- a/ui/file_manager/video_player/js/video_player_native_controls.js
+++ b/ui/file_manager/video_player/js/video_player_native_controls.js
@@ -123,6 +123,16 @@
         break;
     }
   }.wrap(this));
+
+  getRequiredElement('video-container')
+      .addEventListener('click', (/** MouseEvent */ event) => {
+        // Turn on loop mode when ctrl+click while the video is playing.
+        // If the video is paused, ignore ctrl and play the video.
+        if (event.ctrlKey && !this.videoElement_.paused) {
+          this.setLoopedModeWithFeedback_(true);
+          event.preventDefault();
+        }
+      });
 };
 
 /**
@@ -159,6 +169,30 @@
 };
 
 /**
+ * Set the looped mode with feedback.
+ *
+ * @param {boolean} on Whether enabled or not.
+ * @private
+ */
+NativeControlsVideoPlayer.prototype.setLoopedModeWithFeedback_ = function(on) {
+  this.videoElement_.loop = on;
+  if (on) {
+    this.showNotification_('VIDEO_PLAYER_LOOPED_MODE');
+  }
+};
+
+/**
+ * Briefly show a text notification at top left corner.
+ *
+ * @param {string} identifier String identifier.
+ * @private
+ */
+NativeControlsVideoPlayer.prototype.showNotification_ = function(identifier) {
+  getRequiredElement('toast-content').textContent = str(identifier);
+  getRequiredElement('toast').show();
+};
+
+/**
  * Plays the first video.
  */
 NativeControlsVideoPlayer.prototype.playFirstVideo = function() {
@@ -224,6 +258,7 @@
  * @private
  */
 NativeControlsVideoPlayer.prototype.onPause_ = function() {
+  this.videoElement_.loop = false;
   if (this.videoElement_.currentTime == this.videoElement_.duration) {
     this.advance_(true);
   }
diff --git a/ui/file_manager/video_player/video_player.html b/ui/file_manager/video_player/video_player.html
index 1ad6f8e..35c157e 100644
--- a/ui/file_manager/video_player/video_player.html
+++ b/ui/file_manager/video_player/video_player.html
@@ -17,6 +17,7 @@
 
   <link rel="import" href="chrome-extension://hhaomjibdihmijegdhdafkllkbggdgoj/foreground/elements/files_icon_button.html">
   <link rel="import" href="chrome://resources/cr_elements/cr_slider/cr_slider.html">
+  <link rel="import" href="chrome://resources/cr_elements/cr_toast/cr_toast.html">
 
   <script src="js/video_player_scripts.js"></script>
 </head>
@@ -41,9 +42,24 @@
         --cr-slider-knob-color: rgb(64, 138, 241);
         --cr-slider-active-color: rgb(66, 133, 244);
       }
+
+      /* Let cr-toast appear at top left corner */
+      cr-toast {
+          bottom: auto;
+          top: 0;
+          transform: translateY(-100px);
+      }
+
+      cr-toast[open] {
+          transform: translateY(0);
+      }
+
     </style>
   </custom-style>
   <div id="video-player" tools>
+    <cr-toast id="toast" duration="3000">
+      <div id="toast-content"></div>
+    </cr-toast>
     <cr-menu id='cast-menu' class='cast-menu tool'
           i18n-values="playon-text:VIDEO_PLAYER_PLAY_ON"></cr-menu>
     <div id="cast-container">
diff --git a/ui/gfx/color_transform_unittest.cc b/ui/gfx/color_transform_unittest.cc
index 76a1d97..3c27ab8 100644
--- a/ui/gfx/color_transform_unittest.cc
+++ b/ui/gfx/color_transform_unittest.cc
@@ -365,7 +365,7 @@
   EXPECT_NEAR(tmp.x(), 0.735356983052449f, kEpsilon);
   EXPECT_NEAR(tmp.y(), 0.735356983052449f, kEpsilon);
   EXPECT_NEAR(tmp.z(), 0.735356983052449f, kEpsilon);
-};
+}
 
 TEST(SimpleColorSpace, ToUndefined) {
   ColorSpace null;
diff --git a/ui/gfx/ipc/skia/gfx_skia_param_traits_macros.h b/ui/gfx/ipc/skia/gfx_skia_param_traits_macros.h
index e48af3f..410d37bc 100644
--- a/ui/gfx/ipc/skia/gfx_skia_param_traits_macros.h
+++ b/ui/gfx/ipc/skia/gfx_skia_param_traits_macros.h
@@ -10,7 +10,7 @@
 #include "ipc/ipc_message_macros.h"
 #include "third_party/skia/include/core/SkImageInfo.h"
 
-IPC_ENUM_TRAITS_VALIDATE(SkColorType, kLastEnum_SkColorType);
-IPC_ENUM_TRAITS_VALIDATE(SkAlphaType, kLastEnum_SkAlphaType);
+IPC_ENUM_TRAITS_VALIDATE(SkColorType, kLastEnum_SkColorType)
+IPC_ENUM_TRAITS_VALIDATE(SkAlphaType, kLastEnum_SkAlphaType)
 
 #endif  // UI_GFX_IPC_SKIA_GFX_SKIA_PARAM_TRAITS_MACROS_H_
diff --git a/ui/gfx/render_text_unittest.cc b/ui/gfx/render_text_unittest.cc
index c8957cf..3fa4613 100644
--- a/ui/gfx/render_text_unittest.cc
+++ b/ui/gfx/render_text_unittest.cc
@@ -401,7 +401,7 @@
     test_api_.reset(new test::RenderTextTestApi(GetRenderText()));
   }
 
-  RenderTextHarfBuzz* GetRenderText() { return render_text_.get(); };
+  RenderTextHarfBuzz* GetRenderText() { return render_text_.get(); }
 
   Rect GetSubstringBoundsUnion(const Range& range) {
     const std::vector<Rect> bounds = render_text_->GetSubstringBounds(range);
@@ -485,7 +485,7 @@
 
   Canvas* canvas() { return &canvas_; }
   TestSkiaTextRenderer* renderer() { return &renderer_; }
-  test::RenderTextTestApi* test_api() { return test_api_.get(); };
+  test::RenderTextTestApi* test_api() { return test_api_.get(); }
 
  private:
   // Needed to bypass DCHECK in GetFallbackFont.
diff --git a/ui/message_center/views/notification_view_md.h b/ui/message_center/views/notification_view_md.h
index 9ec098ae..a36343d 100644
--- a/ui/message_center/views/notification_view_md.h
+++ b/ui/message_center/views/notification_view_md.h
@@ -139,8 +139,8 @@
   // Overridden from views::ButtonListener:
   void ButtonPressed(views::Button* sender, const ui::Event& event) override;
 
-  views::Textfield* textfield() const { return textfield_; };
-  views::ImageButton* button() const { return button_; };
+  views::Textfield* textfield() const { return textfield_; }
+  views::ImageButton* button() const { return button_; }
 
  private:
   NotificationInputDelegate* const delegate_;
diff --git a/ui/views/test/menu_test_utils.h b/ui/views/test/menu_test_utils.h
index 81e96b78..5de2d12 100644
--- a/ui/views/test/menu_test_utils.h
+++ b/ui/views/test/menu_test_utils.h
@@ -82,7 +82,7 @@
   MenuControllerTestApi();
   ~MenuControllerTestApi();
 
-  MenuController* controller() { return controller_.get(); };
+  MenuController* controller() { return controller_.get(); }
 
   // Clears out the current and pending states, without notifying the associated
   // menu items.
diff --git a/ui/views/widget/widget_unittest.cc b/ui/views/widget/widget_unittest.cc
index 2b8964b..6bc26ab 100644
--- a/ui/views/widget/widget_unittest.cc
+++ b/ui/views/widget/widget_unittest.cc
@@ -3684,7 +3684,7 @@
                                      new_device_scale_factor);
   }
 
-  float last_scale_factor() const { return last_scale_factor_; };
+  float last_scale_factor() const { return last_scale_factor_; }
 
  private:
   float last_scale_factor_ = 0.f;
diff --git a/ui/webui/resources/cr_elements/shared_vars_css.html b/ui/webui/resources/cr_elements/shared_vars_css.html
index 35aa3be4..461274f 100644
--- a/ui/webui/resources/cr_elements/shared_vars_css.html
+++ b/ui/webui/resources/cr_elements/shared_vars_css.html
@@ -181,6 +181,20 @@
       padding: 0 var(--cr-section-padding);
     }
 
+    --cr-centered-card-container-vertical-margin: 21px;
+
+    --cr-centered-card-max-width: 680px;
+    --cr-centered-card-container: {
+      box-sizing: border-box;
+      display: block;
+      height: inherit;
+      margin: 0 auto;
+      max-width: calc(var(--cr-centered-card-max-width) + 3 * 2px);
+      min-width: 550px;
+      position: relative;
+      width: 96%;
+    }
+
     --cr-text-elide: {
       overflow: hidden;
       text-overflow: ellipsis;