diff --git a/BUILD.gn b/BUILD.gn
index 50fdcb21..595c105 100644
--- a/BUILD.gn
+++ b/BUILD.gn
@@ -144,6 +144,7 @@
       "//third_party/dawn:dawn_end2end_tests_temp_group",
       "//third_party/dawn:dawn_unittests_temp_group",
       "//third_party/pdfium/samples:pdfium_test",
+      "//third_party/webrtc/rtc_tools:frame_analyzer",
       "//tools/perf/clear_system_cache",
       "//tools/polymer:polymer_tools_python_unittests",
       "//ui/accessibility:accessibility_perftests",
@@ -608,7 +609,7 @@
   if (is_win) {
     deps += [
       "//base:pe_image_test",
-      "//chrome/chrome_cleaner:chrome_cleaner_unittests",
+      "//chrome/chrome_cleaner",
       "//chrome/chrome_elf:chrome_elf_unittests",
       "//chrome/chrome_elf:dll_hash_main",
       "//chrome/elevation_service:elevation_service_unittests",
diff --git a/DEPS b/DEPS
index 5385587..49bc735 100644
--- a/DEPS
+++ b/DEPS
@@ -172,11 +172,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': '81a8d282d356667aab7bc8c0513da81bb1c5f3c4',
+  'skia_revision': '99b558b594a12ec1d09172f85a6586b17de75ccc',
   # 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': '29e8c96fb28537121f964b7b261c7dc286dfbf2c',
+  'v8_revision': '2af5f573918e2f46a0df5e9ceea380a52de7e45a',
   # 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.
@@ -184,7 +184,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': '652dbfc63e70f7af1b4d3d9beff5ae69b1699c14',
+  'angle_revision': '7f9c9a7fc00143cb5ad26a0bb5cb6950db4a1e58',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling SwiftShader
   # and whatever else without interference from each other.
@@ -235,7 +235,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling catapult
   # and whatever else without interference from each other.
-  'catapult_revision': 'f9004ee81c432e30474b6e87216b0fb038216ccf',
+  'catapult_revision': '5758cc96a5f3f0f9f3b6f64b83c4918fd2e523dd',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling libFuzzer
   # and whatever else without interference from each other.
@@ -303,11 +303,11 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling feed
   # and whatever else without interference from each other.
-  'shaderc_revision': '76ee91e12642e2be731aac3f0f21401b0e7d9d16',
+  'shaderc_revision': 'f7e05c734266528849e861da7bee3ac734df80e6',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling feed
   # and whatever else without interference from each other.
-  'dawn_revision': 'c3284fa40ec6b12731ed66c2f2a9256ae3fa692e',
+  'dawn_revision': 'ae1f25fee85ebf2773b24a0a4f39c160839b1dbb',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling feed
   # and whatever else without interference from each other.
@@ -871,7 +871,7 @@
 
   # Build tools for Chrome OS. Note: This depends on third_party/pyelftools.
   'src/third_party/chromite': {
-      'url': Var('chromium_git') + '/chromiumos/chromite.git' + '@' + 'a942a9f9a2358e11484e67c9169de0e698be2723',
+      'url': Var('chromium_git') + '/chromiumos/chromite.git' + '@' + '8c6f1f9af3f49004e3ba87220d69e17eabaf1b58',
       'condition': 'checkout_linux',
   },
 
@@ -896,7 +896,7 @@
   },
 
   'src/third_party/depot_tools':
-    Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + '72a245e4c678f478bf7e1961cae8b2ba5bfa93bf',
+    Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + '1917f7a099407369280b2cc74a33e44f4ed8c84c',
 
   'src/third_party/devtools-frontend/src':
     Var('chromium_git') + '/devtools/devtools-frontend' + '@' + Var('devtools_frontend_revision'),
@@ -978,7 +978,7 @@
   },
 
   'src/third_party/glslang/src':
-    Var('chromium_git') + '/external/github.com/KhronosGroup/glslang.git' + '@' + 'e471df3c9154afbf125838201d2cd36cd6bdc708',
+    Var('chromium_git') + '/external/github.com/KhronosGroup/glslang.git' + '@' + 'f34cdc70ca1b4e741a9ea5a906f86d3593623356',
 
   'src/third_party/google_toolbox_for_mac/src': {
       'url': Var('chromium_git') + '/external/github.com/google/google-toolbox-for-mac.git' + '@' + Var('google_toolbox_for_mac_revision'),
@@ -1579,7 +1579,7 @@
     Var('chromium_git') + '/v8/v8.git' + '@' +  Var('v8_revision'),
 
   'src-internal': {
-    'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@275467d3f177738333504b9d2ba68e6245494ae4',
+    'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@c2eeedf4626693915c496f99d25c3fe18529cba9',
     'condition': 'checkout_src_internal',
   },
 
diff --git a/android_webview/browser/network_service/aw_proxying_url_loader_factory.cc b/android_webview/browser/network_service/aw_proxying_url_loader_factory.cc
index c17fe640..ee38ecd9 100644
--- a/android_webview/browser/network_service/aw_proxying_url_loader_factory.cc
+++ b/android_webview/browser/network_service/aw_proxying_url_loader_factory.cc
@@ -149,7 +149,8 @@
   mojo::Receiver<network::mojom::URLLoader> proxied_loader_receiver_;
   network::mojom::URLLoaderClientPtr target_client_;
 
-  mojo::Binding<network::mojom::URLLoaderClient> proxied_client_binding_;
+  mojo::Receiver<network::mojom::URLLoaderClient> proxied_client_receiver_{
+      this};
   network::mojom::URLLoaderPtr target_loader_;
   mojo::Remote<network::mojom::URLLoaderFactory> target_factory_;
 
@@ -279,7 +280,6 @@
       traffic_annotation_(traffic_annotation),
       proxied_loader_receiver_(this, std::move(loader_receiver)),
       target_client_(std::move(client)),
-      proxied_client_binding_(this),
       target_factory_(std::move(target_factory)) {
   // If there is a client error, clean up the request.
   target_client_.set_connection_error_handler(base::BindOnce(
@@ -397,7 +397,7 @@
   }
 
   input_stream_previously_failed_ = true;
-  proxied_client_binding_.Unbind();
+  proxied_client_receiver_.reset();
   Restart();
   return true;  // request restarted
 }
@@ -417,7 +417,7 @@
       (request_.url.SchemeIs(url::kContentScheme) ||
        android_webview::IsAndroidSpecialFileUrl(request_.url))) {
     network::mojom::URLLoaderClientPtr proxied_client;
-    proxied_client_binding_.Bind(mojo::MakeRequest(&proxied_client));
+    proxied_client_receiver_.Bind(mojo::MakeRequest(&proxied_client));
     AndroidStreamReaderURLLoader* loader = new AndroidStreamReaderURLLoader(
         request_, std::move(proxied_client), traffic_annotation_,
         std::make_unique<ProtocolResponseDelegate>(request_.url,
@@ -428,7 +428,7 @@
 
   if (!target_loader_ && target_factory_) {
     network::mojom::URLLoaderClientPtr proxied_client;
-    proxied_client_binding_.Bind(mojo::MakeRequest(&proxied_client));
+    proxied_client_receiver_.Bind(mojo::MakeRequest(&proxied_client));
     target_factory_->CreateLoaderAndStart(
         mojo::MakeRequest(&target_loader_), routing_id_, request_id_, options_,
         request_, std::move(proxied_client), traffic_annotation_);
@@ -438,7 +438,7 @@
 void InterceptedRequest::ContinueAfterInterceptWithOverride(
     std::unique_ptr<AwWebResourceResponse> response) {
   network::mojom::URLLoaderClientPtr proxied_client;
-  proxied_client_binding_.Bind(mojo::MakeRequest(&proxied_client));
+  proxied_client_receiver_.Bind(mojo::MakeRequest(&proxied_client));
   AndroidStreamReaderURLLoader* loader = new AndroidStreamReaderURLLoader(
       request_, std::move(proxied_client), traffic_annotation_,
       std::make_unique<InterceptResponseDelegate>(std::move(response),
@@ -506,7 +506,7 @@
 void InterceptedRequest::OnReceiveResponse(
     network::mojom::URLResponseHeadPtr head) {
   // intercept response headers here
-  // pause/resume proxied_client_binding_ if necessary
+  // pause/resume |proxied_client_receiver_| if necessary
 
   if (head->headers && head->headers->response_code() >= 400) {
     // In Android WebView the WebViewClient.onReceivedHttpError callback
@@ -675,7 +675,7 @@
   if (proxied_loader_receiver_.is_bound() && wait_for_loader_error) {
     // Since the original client is gone no need to continue loading the
     // request.
-    proxied_client_binding_.Close();
+    proxied_client_receiver_.reset();
     target_loader_.reset();
 
     // Don't delete |this| yet, in case the |proxied_loader_receiver_|'s
diff --git a/ash/BUILD.gn b/ash/BUILD.gn
index 3b48226..809308e 100644
--- a/ash/BUILD.gn
+++ b/ash/BUILD.gn
@@ -1645,16 +1645,21 @@
   ]
 }
 
-copy("dbus_service_files") {
+action("dbus_service_files") {
   sources = [
     "dbus/org.chromium.DisplayService.conf",
     "dbus/org.chromium.GesturePropertiesService.conf",
     "dbus/org.chromium.LivenessService.conf",
     "dbus/org.chromium.UrlHandlerService.conf",
   ]
+  output_conf_file = "$root_out_dir/dbus/ash_dbus_services.conf"
   outputs = [
-    "$root_out_dir/dbus/{{source_file_part}}",
+    output_conf_file,
   ]
+
+  script = "//chromeos/tools/concat_dbus_conf_files.py"
+  args = [ rebase_path(output_conf_file, root_build_dir) ]
+  args += rebase_path(sources, root_build_dir)
 }
 
 test("ash_unittests") {
diff --git a/ash/assistant/ui/assistant_web_view.cc b/ash/assistant/ui/assistant_web_view.cc
index 1691cdf..13c4519 100644
--- a/ash/assistant/ui/assistant_web_view.cc
+++ b/ash/assistant/ui/assistant_web_view.cc
@@ -176,9 +176,11 @@
   SetFocusBehavior(FocusBehavior::ALWAYS);
 
   // We need to clip the corners of our web contents to match our container.
-  contents_->GetView()->native_view()->layer()->SetRoundedCornerRadius(
-      {/*top_left=*/0, /*top_right=*/0, /*bottom_right=*/kCornerRadiusDip,
-       /*bottom_left=*/kCornerRadiusDip});
+  if (!chromeos::assistant::features::IsAssistantWebContainerEnabled()) {
+    contents_->GetView()->native_view()->layer()->SetRoundedCornerRadius(
+        {/*top_left=*/0, /*top_right=*/0, /*bottom_right=*/kCornerRadiusDip,
+         /*bottom_left=*/kCornerRadiusDip});
+  }
 }
 
 void AssistantWebView::DidSuppressNavigation(const GURL& url,
diff --git a/ash/display/window_tree_host_manager.cc b/ash/display/window_tree_host_manager.cc
index 392a5bd..8d98252 100644
--- a/ash/display/window_tree_host_manager.cc
+++ b/ash/display/window_tree_host_manager.cc
@@ -500,7 +500,7 @@
         new_root_window_controller->GetStatusAreaWidget()
             ->unified_system_tray();
     if (old_tray->GetWidget()->IsVisible()) {
-      new_tray->SetVisible(true);
+      new_tray->SetVisiblePreferred(true);
       new_tray->GetWidget()->Show();
     }
 
diff --git a/ash/home_screen/drag_window_from_shelf_controller.cc b/ash/home_screen/drag_window_from_shelf_controller.cc
index f749301..eb31b8a4 100644
--- a/ash/home_screen/drag_window_from_shelf_controller.cc
+++ b/ash/home_screen/drag_window_from_shelf_controller.cc
@@ -46,6 +46,12 @@
 constexpr base::TimeDelta kShowOverviewTimeWhenDragSuspend =
     base::TimeDelta::FromMilliseconds(40);
 
+// The distance for the dragged window to pass over the bottom of the display
+// so that it can be dragged into home launcher or overview. If not pass this
+// value, the window will snap back to its original position.
+constexpr float kReturnToMaximizedDenseThreshold = 152.f;
+constexpr float kReturnToMaximizedStandardThreshold = 164.f;
+
 }  // namespace
 
 // Hide all visible windows expect the dragged windows or the window showing in
@@ -105,10 +111,20 @@
   DISALLOW_COPY_AND_ASSIGN(WindowsHider);
 };
 
+// static
+float DragWindowFromShelfController::GetReturnToMaximizedThreshold() {
+  return ShelfConfig::Get()->is_dense() ? kReturnToMaximizedDenseThreshold
+                                        : kReturnToMaximizedStandardThreshold;
+}
+
 DragWindowFromShelfController::DragWindowFromShelfController(
-    aura::Window* window)
-    : window_(window) {
+    aura::Window* window,
+    const gfx::Point& location_in_screen,
+    HotseatState hotseat_state)
+    : window_(window), hotseat_state_(hotseat_state) {
+  DCHECK_NE(hotseat_state, HotseatState::kShown);
   window_->AddObserver(this);
+  OnDragStarted(location_in_screen);
 }
 
 DragWindowFromShelfController::~DragWindowFromShelfController() {
@@ -124,17 +140,9 @@
   if (!window_)
     return;
 
-  if (!drag_started_) {
-    // Do not start drag until the drag goes above the hotseat.
-    const gfx::Rect work_area =
-        screen_util::GetDisplayWorkAreaBoundsInScreenForActiveDeskContainer(
-            window_);
-    if (location_in_screen.y() >
-        work_area.bottom() - ShelfConfig::Get()->hotseat_size()) {
-      return;
-    }
-    OnDragStarted(location_in_screen);
-  }
+  // TODO(xdai): clean up |drag_started_| variable.
+  if (!drag_started_)
+    return;
 
   UpdateDraggedWindow(location_in_screen);
 
@@ -206,7 +214,7 @@
   const bool in_overview = overview_controller->InOverviewSession();
   const bool in_splitview = split_view_controller->InSplitViewMode();
 
-  if (ShouldGoToHomeScreen(velocity_y)) {
+  if (ShouldGoToHomeScreen(location_in_screen, velocity_y)) {
     DCHECK(!in_splitview);
     if (in_overview) {
       overview_controller->EndOverview(
@@ -397,7 +405,7 @@
 DragWindowFromShelfController::GetSnapPosition(
     const gfx::Point& location_in_screen) const {
   // if |location_in_screen| is close to the bottom of the screen and is
-  // inside of kReturnToMaximizedThreshold threshold, we should not try to
+  // inside of GetReturnToMaximizedThreshold() threshold, we should not try to
   // snap the window.
   if (ShouldRestoreToOriginalBounds(location_in_screen))
     return SplitViewController::NONE;
@@ -423,15 +431,25 @@
 
 bool DragWindowFromShelfController::ShouldRestoreToOriginalBounds(
     const gfx::Point& location_in_screen) const {
-  const gfx::Rect work_area = display::Screen::GetScreen()
-                                  ->GetDisplayNearestPoint(location_in_screen)
-                                  .work_area();
+  const gfx::Rect display_bounds =
+      display::Screen::GetScreen()
+          ->GetDisplayNearestPoint(location_in_screen)
+          .bounds();
   return location_in_screen.y() >
-         work_area.bottom() - kReturnToMaximizedThreshold;
+         display_bounds.bottom() - GetReturnToMaximizedThreshold();
 }
 
 bool DragWindowFromShelfController::ShouldGoToHomeScreen(
+    const gfx::Point& location_in_screen,
     base::Optional<float> velocity_y) const {
+  // For a hidden hotseat, if the event end position does not exceed
+  // GetReturnToMaximizedThreshold(), it should restore back to the maximized
+  // bounds even though the velocity might be large.
+  if (hotseat_state_ == HotseatState::kHidden &&
+      ShouldRestoreToOriginalBounds(location_in_screen)) {
+    return false;
+  }
+
   return velocity_y.has_value() && *velocity_y < 0 &&
          std::abs(*velocity_y) >= kVelocityToHomeScreenThreshold &&
          !SplitViewController::Get(Shell::GetPrimaryRootWindow())
@@ -443,7 +461,7 @@
     const gfx::Point& location_in_screen,
     base::Optional<float> velocity_y) const {
   if (ShouldRestoreToOriginalBounds(location_in_screen) ||
-      ShouldGoToHomeScreen(velocity_y)) {
+      ShouldGoToHomeScreen(location_in_screen, velocity_y)) {
     return SplitViewController::NONE;
   }
 
@@ -456,7 +474,7 @@
   if (!Shell::Get()->overview_controller()->InOverviewSession())
     return false;
 
-  if (ShouldGoToHomeScreen(velocity_y))
+  if (ShouldGoToHomeScreen(location_in_screen, velocity_y))
     return false;
 
   const bool in_splitview =
diff --git a/ash/home_screen/drag_window_from_shelf_controller.h b/ash/home_screen/drag_window_from_shelf_controller.h
index 9d5b3ae3..280cebb 100644
--- a/ash/home_screen/drag_window_from_shelf_controller.h
+++ b/ash/home_screen/drag_window_from_shelf_controller.h
@@ -8,6 +8,7 @@
 #include <vector>
 
 #include "ash/ash_export.h"
+#include "ash/public/cpp/shelf_types.h"
 #include "ash/public/cpp/window_properties.h"
 #include "ash/wm/splitview/split_view_controller.h"
 #include "base/macros.h"
@@ -26,11 +27,6 @@
 // swiping up from the shelf to homescreen, overview or splitview.
 class ASH_EXPORT DragWindowFromShelfController : public aura::WindowObserver {
  public:
-  // The distance for the dragged window to pass over shelf so that it can be
-  // dragged into home launcher or overview. If not pass this value, the window
-  // will snap back to its original position.
-  static constexpr float kReturnToMaximizedThreshold = 116;
-
   // The deceleration threshold to open overview behind the dragged window
   // when swiping up from the shelf to drag the active window.
   static constexpr float kOpenOverviewThreshold = 10.f;
@@ -47,7 +43,15 @@
   // view is active during dragging.
   static constexpr float kVelocityToOverviewThreshold = 1000.f;
 
-  explicit DragWindowFromShelfController(aura::Window* window);
+  // The distance for the dragged window to pass over the bottom of the display
+  // so that it can be dragged into home launcher or overview. If not pass this
+  // value, the window will snap back to its original position. The value is
+  // different for standard or dense shelf.
+  static float GetReturnToMaximizedThreshold();
+
+  DragWindowFromShelfController(aura::Window* window,
+                                const gfx::Point& location_in_screen,
+                                HotseatState hotseat_state);
   ~DragWindowFromShelfController() override;
 
   // Called during swiping up on the shelf.
@@ -81,7 +85,7 @@
 
   // Returns true if the dragged window should restore to its original bounds
   // after drag ends. Happens when |location_in_screen| is within
-  // kReturnToMaximizedThreshold threshold.
+  // GetReturnToMaximizedThreshold() threshold.
   bool ShouldRestoreToOriginalBounds(
       const gfx::Point& location_in_screen) const;
 
@@ -89,7 +93,8 @@
   // the upward vertical velocity is larger than kVelocityToHomeScreenThreshold
   // and splitview is not active. Note when splitview is active, we do not allow
   // to go to home screen by fling.
-  bool ShouldGoToHomeScreen(base::Optional<float> velocity_y) const;
+  bool ShouldGoToHomeScreen(const gfx::Point& location_in_screen,
+                            base::Optional<float> velocity_y) const;
 
   // Returns the desired snap position on |location_in_screen| when drag ends.
   SplitViewController::SnapPosition GetSnapPositionOnDragEnd(
@@ -125,6 +130,9 @@
   // Timer to show and update overview.
   base::OneShotTimer show_overview_timer_;
 
+  // The hotseat state when drag starts.
+  const HotseatState hotseat_state_;
+
   DISALLOW_COPY_AND_ASSIGN(DragWindowFromShelfController);
 };
 
diff --git a/ash/home_screen/drag_window_from_shelf_controller_unittest.cc b/ash/home_screen/drag_window_from_shelf_controller_unittest.cc
index 57cf031..838a612 100644
--- a/ash/home_screen/drag_window_from_shelf_controller_unittest.cc
+++ b/ash/home_screen/drag_window_from_shelf_controller_unittest.cc
@@ -35,9 +35,11 @@
     base::RunLoop().RunUntilIdle();
   }
 
-  void StartDrag(aura::Window* window) {
-    window_drag_controller_ =
-        std::make_unique<DragWindowFromShelfController>(window);
+  void StartDrag(aura::Window* window,
+                 const gfx::Point& location_in_screen,
+                 HotseatState hotseat_state) {
+    window_drag_controller_ = std::make_unique<DragWindowFromShelfController>(
+        window, location_in_screen, hotseat_state);
   }
   void Drag(const gfx::Point& location_in_screen,
             float scroll_x,
@@ -77,7 +79,7 @@
   EXPECT_TRUE(window2->IsVisible());
   EXPECT_TRUE(window3->IsVisible());
 
-  StartDrag(window1.get());
+  StartDrag(window1.get(), shelf_bounds.CenterPoint(), HotseatState::kExtended);
   Drag(gfx::Point(200, 200), 1.f, 1.f);
   EXPECT_TRUE(window1->IsVisible());
   EXPECT_FALSE(window2->IsVisible());
@@ -91,7 +93,7 @@
   split_view_controller()->SnapWindow(window1.get(), SplitViewController::LEFT);
   split_view_controller()->SnapWindow(window2.get(),
                                       SplitViewController::RIGHT);
-  StartDrag(window1.get());
+  StartDrag(window1.get(), shelf_bounds.left_center(), HotseatState::kExtended);
   Drag(gfx::Point(0, 200), 1.f, 1.f);
   EXPECT_TRUE(window1->IsVisible());
   EXPECT_TRUE(window2->IsVisible());
@@ -101,7 +103,8 @@
   EXPECT_TRUE(window2->IsVisible());
   EXPECT_TRUE(window3->IsVisible());
 
-  StartDrag(window2.get());
+  StartDrag(window2.get(), shelf_bounds.right_center(),
+            HotseatState::kExtended);
   Drag(gfx::Point(400, 200), 1.f, 1.f);
   EXPECT_TRUE(window1->IsVisible());
   EXPECT_TRUE(window2->IsVisible());
@@ -118,7 +121,7 @@
   const gfx::Rect shelf_bounds =
       Shelf::ForWindow(Shell::GetPrimaryRootWindow())->GetIdealBounds();
   auto window = CreateTestWindow();
-  StartDrag(window.get());
+  StartDrag(window.get(), shelf_bounds.CenterPoint(), HotseatState::kExtended);
   Drag(gfx::Point(0, 200), 0.f, 1.f);
   aura::Window* home_screen_window =
       Shell::Get()->home_screen_controller()->delegate()->GetHomeScreenWindow();
@@ -141,14 +144,14 @@
 
   // If the dragged window restores to its original position, reshow the hidden
   // windows.
-  StartDrag(window1.get());
+  StartDrag(window1.get(), shelf_bounds.CenterPoint(), HotseatState::kExtended);
   Drag(gfx::Point(200, 200), 0.f, 1.f);
   EXPECT_FALSE(window2->IsVisible());
   EndDrag(shelf_bounds.CenterPoint(), base::nullopt);
   EXPECT_TRUE(window2->IsVisible());
 
   // If fling to homescreen, do not reshow the hidden windows.
-  StartDrag(window1.get());
+  StartDrag(window1.get(), shelf_bounds.CenterPoint(), HotseatState::kExtended);
   Drag(gfx::Point(200, 200), 0.f, 1.f);
   EXPECT_FALSE(window2->IsVisible());
   EndDrag(gfx::Point(200, 200),
@@ -160,7 +163,7 @@
   // windows.
   window2->Show();
   window1->Show();
-  StartDrag(window1.get());
+  StartDrag(window1.get(), shelf_bounds.CenterPoint(), HotseatState::kExtended);
   Drag(gfx::Point(200, 200), 0.f, 1.f);
   EXPECT_FALSE(window2->IsVisible());
   OverviewController* overview_controller = Shell::Get()->overview_controller();
@@ -176,7 +179,7 @@
   // showing in overview, do not reshow the hidden windows.
   window2->Show();
   window1->Show();
-  StartDrag(window1.get());
+  StartDrag(window1.get(), shelf_bounds.left_center(), HotseatState::kExtended);
   Drag(gfx::Point(0, 200), 0.f, 1.f);
   EXPECT_FALSE(window2->IsVisible());
   EXPECT_TRUE(overview_controller->InOverviewSession());
@@ -191,14 +194,13 @@
 // show correctly in overview.
 TEST_F(DragWindowFromShelfControllerTest, MinimizedWindowsShowInOverview) {
   UpdateDisplay("400x400");
+  const gfx::Rect shelf_bounds =
+      Shelf::ForWindow(Shell::GetPrimaryRootWindow())->GetIdealBounds();
   auto window3 = CreateTestWindow();
   auto window2 = CreateTestWindow();
   auto window1 = CreateTestWindow();
 
-  StartDrag(window1.get());
-  EXPECT_TRUE(window1->IsVisible());
-  EXPECT_TRUE(window2->IsVisible());
-  EXPECT_TRUE(window3->IsVisible());
+  StartDrag(window1.get(), shelf_bounds.CenterPoint(), HotseatState::kExtended);
   // Drag it far enough so overview should be open behind the dragged window.
   Drag(gfx::Point(200, 200), 0.f, 1.f);
   OverviewController* overview_controller = Shell::Get()->overview_controller();
@@ -224,9 +226,11 @@
 // delta (velocity) decrease to kOpenOverviewThreshold or less.
 TEST_F(DragWindowFromShelfControllerTest, OpenOverviewWhenHold) {
   UpdateDisplay("400x400");
+  const gfx::Rect shelf_bounds =
+      Shelf::ForWindow(Shell::GetPrimaryRootWindow())->GetIdealBounds();
   auto window = CreateTestWindow();
 
-  StartDrag(window.get());
+  StartDrag(window.get(), shelf_bounds.CenterPoint(), HotseatState::kExtended);
   Drag(gfx::Point(200, 200), 0.f,
        DragWindowFromShelfController::kOpenOverviewThreshold + 1);
   OverviewController* overview_controller = Shell::Get()->overview_controller();
@@ -241,13 +245,15 @@
 // kReturnToMaximizedThreshold, it will restore back to its original position.
 TEST_F(DragWindowFromShelfControllerTest, RestoreWindowToOriginalBounds) {
   UpdateDisplay("400x400");
+  const gfx::Rect shelf_bounds =
+      Shelf::ForWindow(Shell::GetPrimaryRootWindow())->GetIdealBounds();
   auto window = CreateTestWindow();
-  const gfx::Rect work_area = display::Screen::GetScreen()
-                                  ->GetDisplayNearestWindow(window.get())
-                                  .work_area();
+  const gfx::Rect display_bounds = display::Screen::GetScreen()
+                                       ->GetDisplayNearestWindow(window.get())
+                                       .bounds();
 
   // Drag it for a small distance and then release.
-  StartDrag(window.get());
+  StartDrag(window.get(), shelf_bounds.CenterPoint(), HotseatState::kExtended);
   Drag(gfx::Point(200, 200), 0.f,
        DragWindowFromShelfController::kShowOverviewThreshold + 1);
   EXPECT_FALSE(window->layer()->GetTargetTransform().IsIdentity());
@@ -258,15 +264,16 @@
   EXPECT_TRUE(WindowState::Get(window.get())->IsMaximized());
 
   // Drag it for a large distance and then drag back to release.
-  StartDrag(window.get());
+  StartDrag(window.get(), shelf_bounds.CenterPoint(), HotseatState::kExtended);
   Drag(gfx::Point(200, 200), 0.f, 1.f);
   EXPECT_FALSE(window->layer()->GetTargetTransform().IsIdentity());
   EXPECT_TRUE(overview_controller->InOverviewSession());
   EndDrag(
       gfx::Point(
-          200, work_area.bottom() -
-                   DragWindowFromShelfController::kReturnToMaximizedThreshold +
-                   1),
+          200,
+          display_bounds.bottom() -
+              DragWindowFromShelfController::GetReturnToMaximizedThreshold() +
+              1),
       base::nullopt);
   EXPECT_TRUE(window->layer()->GetTargetTransform().IsIdentity());
   EXPECT_FALSE(overview_controller->InOverviewSession());
@@ -277,7 +284,7 @@
   split_view_controller()->SnapWindow(window.get(), SplitViewController::LEFT);
   split_view_controller()->SnapWindow(window2.get(),
                                       SplitViewController::RIGHT);
-  StartDrag(window.get());
+  StartDrag(window.get(), shelf_bounds.left_center(), HotseatState::kExtended);
   Drag(gfx::Point(0, 200), 0.f, 1.f);
   EXPECT_FALSE(window->layer()->GetTargetTransform().IsIdentity());
   EXPECT_TRUE(overview_controller->InOverviewSession());
@@ -292,11 +299,13 @@
 // TODO(https://crbug.com/1019080) This test is flaky.
 TEST_F(DragWindowFromShelfControllerTest, DISABLED_FlingInOverview) {
   UpdateDisplay("400x400");
+  const gfx::Rect shelf_bounds =
+      Shelf::ForWindow(Shell::GetPrimaryRootWindow())->GetIdealBounds();
   auto window = CreateTestWindow();
 
   // If fling velocity is smaller than kVelocityToHomeScreenThreshold, decide
   // where the window should go based on the release position.
-  StartDrag(window.get());
+  StartDrag(window.get(), shelf_bounds.CenterPoint(), HotseatState::kExtended);
   Drag(gfx::Point(200, 200), 0.f, 1.f);
   OverviewController* overview_controller = Shell::Get()->overview_controller();
   EXPECT_TRUE(overview_controller->InOverviewSession());
@@ -309,7 +318,7 @@
   EXPECT_TRUE(WindowState::Get(window.get())->IsMaximized());
 
   // If fling velocity is equal or larger than kVelocityToHomeScreenThreshold
-  StartDrag(window.get());
+  StartDrag(window.get(), shelf_bounds.CenterPoint(), HotseatState::kExtended);
   Drag(gfx::Point(200, 200), 0.f, 1.f);
   EXPECT_TRUE(overview_controller->InOverviewSession());
   EndDrag(gfx::Point(0, 350),
@@ -323,6 +332,8 @@
 // overview.
 TEST_F(DragWindowFromShelfControllerTest, DragOrFlingInSplitView) {
   UpdateDisplay("400x400");
+  const gfx::Rect shelf_bounds =
+      Shelf::ForWindow(Shell::GetPrimaryRootWindow())->GetIdealBounds();
 
   auto window1 = CreateTestWindow();
   auto window2 = CreateTestWindow();
@@ -333,7 +344,7 @@
   EXPECT_TRUE(split_view_controller()->InSplitViewMode());
 
   // If the window is only dragged for a small distance:
-  StartDrag(window1.get());
+  StartDrag(window1.get(), shelf_bounds.left_center(), HotseatState::kExtended);
   Drag(gfx::Point(100, 200), 0.f, 1.f);
   EXPECT_TRUE(split_view_controller()->InSplitViewMode());
   EXPECT_TRUE(overview_controller->InOverviewSession());
@@ -344,7 +355,7 @@
   EXPECT_TRUE(split_view_controller()->IsWindowInSplitView(window2.get()));
 
   // If the window is dragged for a long distance:
-  StartDrag(window1.get());
+  StartDrag(window1.get(), shelf_bounds.left_center(), HotseatState::kExtended);
   Drag(gfx::Point(100, 200), 0.f, 1.f);
   EXPECT_TRUE(split_view_controller()->InSplitViewMode());
   EXPECT_TRUE(overview_controller->InOverviewSession());
@@ -358,7 +369,7 @@
   overview_controller->EndOverview();
 
   // If the window is flung with a small velocity:
-  StartDrag(window1.get());
+  StartDrag(window1.get(), shelf_bounds.left_center(), HotseatState::kExtended);
   Drag(gfx::Point(100, 200), 0.f, 1.f);
   EXPECT_TRUE(split_view_controller()->InSplitViewMode());
   EXPECT_TRUE(overview_controller->InOverviewSession());
@@ -372,7 +383,7 @@
   EXPECT_TRUE(split_view_controller()->IsWindowInSplitView(window2.get()));
 
   // If the window is flung with a large velocity:
-  StartDrag(window1.get());
+  StartDrag(window1.get(), shelf_bounds.left_center(), HotseatState::kExtended);
   Drag(gfx::Point(100, 200), 0.f, 1.f);
   EXPECT_TRUE(split_view_controller()->InSplitViewMode());
   EXPECT_TRUE(overview_controller->InOverviewSession());
@@ -396,7 +407,7 @@
       Shelf::ForWindow(Shell::GetPrimaryRootWindow())->GetIdealBounds();
   auto window = CreateTestWindow();
 
-  StartDrag(window.get());
+  StartDrag(window.get(), shelf_bounds.CenterPoint(), HotseatState::kExtended);
   Drag(gfx::Point(0, 200), 0.f,
        DragWindowFromShelfController::kShowOverviewThreshold + 1);
   OverviewController* overview_controller = Shell::Get()->overview_controller();
@@ -416,10 +427,12 @@
 // stops.
 TEST_F(DragWindowFromShelfControllerTest, HideOverviewDuringDragging) {
   UpdateDisplay("400x400");
+  const gfx::Rect shelf_bounds =
+      Shelf::ForWindow(Shell::GetPrimaryRootWindow())->GetIdealBounds();
   auto window2 = CreateTestWindow();
   auto window1 = CreateTestWindow();
 
-  StartDrag(window1.get());
+  StartDrag(window1.get(), shelf_bounds.CenterPoint(), HotseatState::kExtended);
   Drag(gfx::Point(200, 200), 0.5f, 0.5f);
   OverviewController* overview_controller = Shell::Get()->overview_controller();
   EXPECT_TRUE(overview_controller->InOverviewSession());
@@ -456,7 +469,7 @@
       Shelf::ForWindow(Shell::GetPrimaryRootWindow())->GetIdealBounds();
   auto window = CreateTestWindow();
 
-  StartDrag(window.get());
+  StartDrag(window.get(), shelf_bounds.CenterPoint(), HotseatState::kExtended);
   Drag(gfx::Point(200, 200), 0.5f, 0.5f);
   OverviewController* overview_controller = Shell::Get()->overview_controller();
   EXPECT_TRUE(overview_controller->InOverviewSession());
@@ -506,7 +519,7 @@
   EXPECT_NE(window->GetProperty(kBackdropWindowMode),
             BackdropWindowMode::kDisabled);
 
-  StartDrag(window.get());
+  StartDrag(window.get(), shelf_bounds.left_center(), HotseatState::kExtended);
   Drag(gfx::Point(0, 200), 0.f, 10.f);
   EndDrag(shelf_bounds.CenterPoint(),
           base::make_optional(
@@ -520,6 +533,8 @@
 // hidden windows should restore to its previous visibility state.
 // TODO(crbug.com/1022319): flaky.
 TEST_F(DragWindowFromShelfControllerTest, DISABLED_CancelDragDismissOverview) {
+  const gfx::Rect shelf_bounds =
+      Shelf::ForWindow(Shell::GetPrimaryRootWindow())->GetIdealBounds();
   auto window3 = CreateTestWindow();
   auto window2 = CreateTestWindow();
   auto window1 = CreateTestWindow();
@@ -527,7 +542,7 @@
   EXPECT_TRUE(window2->IsVisible());
   EXPECT_TRUE(window3->IsVisible());
 
-  StartDrag(window1.get());
+  StartDrag(window1.get(), shelf_bounds.CenterPoint(), HotseatState::kExtended);
   Drag(gfx::Point(200, 200), 0.5f, 0.5f);
   OverviewController* overview_controller = Shell::Get()->overview_controller();
   EXPECT_TRUE(overview_controller->InOverviewSession());
@@ -545,8 +560,10 @@
 // TODO(https://crbug.com/1018498) This test is flaky.
 TEST_F(DragWindowFromShelfControllerTest,
        DISABLED_CancelDragIfWindowDestroyed) {
+  const gfx::Rect shelf_bounds =
+      Shelf::ForWindow(Shell::GetPrimaryRootWindow())->GetIdealBounds();
   auto window = CreateTestWindow();
-  StartDrag(window.get());
+  StartDrag(window.get(), shelf_bounds.CenterPoint(), HotseatState::kExtended);
   Drag(gfx::Point(200, 200), 0.5f, 0.5f);
   EXPECT_EQ(window_drag_controller()->dragged_window(), window.get());
   EXPECT_TRUE(window_drag_controller()->drag_started());
@@ -558,4 +575,28 @@
   CancelDrag();
 }
 
+TEST_F(DragWindowFromShelfControllerTest, FlingWithHiddenHotseat) {
+  const gfx::Rect shelf_bounds =
+      Shelf::ForWindow(Shell::GetPrimaryRootWindow())->GetIdealBounds();
+  auto window = CreateTestWindow();
+  gfx::Point start = shelf_bounds.CenterPoint();
+  StartDrag(window.get(), start, HotseatState::kHidden);
+  // Only drag for a small distance and then fling.
+  Drag(gfx::Point(start.x(), start.y() - 10), 0.5f, 0.5f);
+  EndDrag(gfx::Point(start.x(), start.y() - 10),
+          base::make_optional(
+              -DragWindowFromShelfController::kVelocityToHomeScreenThreshold));
+  // The window should restore back to its original position.
+  EXPECT_TRUE(WindowState::Get(window.get())->IsMaximized());
+
+  // Now a bigger distance to fling.
+  StartDrag(window.get(), start, HotseatState::kHidden);
+  Drag(gfx::Point(start.x(), start.y() - 200), 0.5f, 0.5f);
+  EndDrag(gfx::Point(start.x(), start.y() - 200),
+          base::make_optional(
+              -DragWindowFromShelfController::kVelocityToHomeScreenThreshold));
+  // The window should be minimized.
+  EXPECT_TRUE(WindowState::Get(window.get())->IsMinimized());
+}
+
 }  // namespace ash
diff --git a/ash/public/cpp/shelf_config.h b/ash/public/cpp/shelf_config.h
index 02cdd8bf..6a19046 100644
--- a/ash/public/cpp/shelf_config.h
+++ b/ash/public/cpp/shelf_config.h
@@ -141,6 +141,8 @@
     return mousewheel_scroll_offset_threshold_;
   }
 
+  bool is_dense() const { return is_dense_; }
+
   // Gets the current color for the shelf control buttons.
   SkColor GetShelfControlButtonColor() const;
 
diff --git a/ash/rotator/screen_rotation_animator_unittest.cc b/ash/rotator/screen_rotation_animator_unittest.cc
index 6283148..88246f7 100644
--- a/ash/rotator/screen_rotation_animator_unittest.cc
+++ b/ash/rotator/screen_rotation_animator_unittest.cc
@@ -384,7 +384,7 @@
   // Long duration for hide animation, to allow it to be interrupted.
   ui::ScopedAnimationDurationScaleMode hide_duration(
       ui::ScopedAnimationDurationScaleMode::SLOW_DURATION);
-  GetTray()->SetVisible(false);
+  GetTray()->SetVisiblePreferred(false);
 
   // ScreenRotationAnimator copies the current layers, and deletes them upon
   // completion. Allow its animation to complete first.
@@ -615,7 +615,7 @@
   // Long duration for hide animation, to allow it to be interrupted.
   ui::ScopedAnimationDurationScaleMode hide_duration(
       ui::ScopedAnimationDurationScaleMode::SLOW_DURATION);
-  GetTray()->SetVisible(false);
+  GetTray()->SetVisiblePreferred(false);
 
   // Allow ScreenRotationAnimator animation to complete first.
   ui::ScopedAnimationDurationScaleMode rotate_duration(
diff --git a/ash/shelf/shelf_layout_manager.cc b/ash/shelf/shelf_layout_manager.cc
index 25ae94a..bf1a094 100644
--- a/ash/shelf/shelf_layout_manager.cc
+++ b/ash/shelf/shelf_layout_manager.cc
@@ -2456,8 +2456,8 @@
   if (!window)
     return false;
 
-  window_drag_controller_ =
-      std::make_unique<DragWindowFromShelfController>(window);
+  window_drag_controller_ = std::make_unique<DragWindowFromShelfController>(
+      window, event_in_screen.location(), hotseat_state());
   return true;
 }
 
diff --git a/ash/system/accessibility/dictation_button_tray.cc b/ash/system/accessibility/dictation_button_tray.cc
index f4f25ec7..bd131dbd 100644
--- a/ash/system/accessibility/dictation_button_tray.cc
+++ b/ash/system/accessibility/dictation_button_tray.cc
@@ -95,7 +95,7 @@
 void DictationButtonTray::UpdateVisibility() {
   bool is_visible =
       Shell::Get()->accessibility_controller()->dictation_enabled();
-  SetVisible(is_visible);
+  SetVisiblePreferred(is_visible);
 }
 
 void DictationButtonTray::CheckDictationStatusAndUpdateIcon() {
diff --git a/ash/system/accessibility/select_to_speak_tray.cc b/ash/system/accessibility/select_to_speak_tray.cc
index 5453e7b..ce87c5e 100644
--- a/ash/system/accessibility/select_to_speak_tray.cc
+++ b/ash/system/accessibility/select_to_speak_tray.cc
@@ -89,7 +89,7 @@
 
 void SelectToSpeakTray::CheckStatusAndUpdateIcon() {
   if (!Shell::Get()->accessibility_controller()->select_to_speak_enabled()) {
-    SetVisible(false);
+    SetVisiblePreferred(false);
     return;
   }
 
@@ -111,7 +111,7 @@
       break;
   }
 
-  SetVisible(true);
+  SetVisiblePreferred(true);
 }
 
 }  // namespace ash
diff --git a/ash/system/ime_menu/ime_menu_tray.cc b/ash/system/ime_menu/ime_menu_tray.cc
index cf7b2a3..fc6f2fa 100644
--- a/ash/system/ime_menu/ime_menu_tray.cc
+++ b/ash/system/ime_menu/ime_menu_tray.cc
@@ -489,7 +489,7 @@
 }
 
 void ImeMenuTray::OnIMEMenuActivationChanged(bool is_activated) {
-  SetVisible(is_activated);
+  SetVisiblePreferred(is_activated);
   if (is_activated)
     UpdateTrayLabel();
   else
diff --git a/ash/system/night_light/night_light_controller_impl.cc b/ash/system/night_light/night_light_controller_impl.cc
index b3a3cb37..20e1723 100644
--- a/ash/system/night_light/night_light_controller_impl.cc
+++ b/ash/system/night_light/night_light_controller_impl.cc
@@ -464,6 +464,21 @@
 
 void NightLightControllerImpl::OnActiveUserPrefServiceChanged(
     PrefService* pref_service) {
+  // TODO(afakhry|yjliu): Remove this VLOG when https://crbug.com/1015474 is
+  // fixed.
+  auto vlog_helper = [](const PrefService* pref_service) -> std::string {
+    if (!pref_service)
+      return "None";
+    return base::StringPrintf(
+        "{State %s, Schedule Type: %d}",
+        pref_service->GetBoolean(prefs::kNightLightEnabled) ? "enabled"
+                                                            : "disabled",
+        pref_service->GetInteger(prefs::kNightLightScheduleType));
+  };
+  VLOG(1) << "Switching user pref service from "
+          << vlog_helper(active_user_pref_service_) << " to "
+          << vlog_helper(pref_service) << ".";
+
   // Initial login and user switching in multi profiles.
   active_user_pref_service_ = pref_service;
   InitFromUserPrefs();
@@ -608,6 +623,7 @@
 }
 
 void NightLightControllerImpl::OnEnabledPrefChanged() {
+  VLOG(1) << "Enable state changed. New state: " << GetEnabled() << ".";
   DCHECK(active_user_pref_service_);
   Refresh(false /* did_schedule_change */);
   NotifyStatusChanged();
@@ -623,6 +639,7 @@
 }
 
 void NightLightControllerImpl::OnScheduleTypePrefChanged() {
+  VLOG(1) << "Schedule type changed. New type: " << GetScheduleType() << ".";
   DCHECK(active_user_pref_service_);
   NotifyClientWithScheduleChange();
   Refresh(true /* did_schedule_change */);
diff --git a/ash/system/overview/overview_button_tray.cc b/ash/system/overview/overview_button_tray.cc
index 72ce0cf..0a33119 100644
--- a/ash/system/overview/overview_button_tray.cc
+++ b/ash/system/overview/overview_button_tray.cc
@@ -195,7 +195,7 @@
   bool should_show =
       Shell::Get()->tablet_mode_controller()->ShouldShowOverviewButton();
 
-  SetVisible(should_show && active_session && !app_mode);
+  SetVisiblePreferred(should_show && active_session && !app_mode);
 }
 
 }  // namespace ash
diff --git a/ash/system/overview/overview_button_tray_unittest.cc b/ash/system/overview/overview_button_tray_unittest.cc
index 4c6593a..4555a85a2 100644
--- a/ash/system/overview/overview_button_tray_unittest.cc
+++ b/ash/system/overview/overview_button_tray_unittest.cc
@@ -317,7 +317,7 @@
 TEST_F(OverviewButtonTrayTest, HideAnimationAlwaysCompletes) {
   TabletModeControllerTestApi().EnterTabletMode();
   EXPECT_TRUE(GetTray()->GetVisible());
-  GetTray()->SetVisible(false);
+  GetTray()->SetVisiblePreferred(false);
   EXPECT_FALSE(GetTray()->GetVisible());
 }
 
@@ -330,7 +330,7 @@
   std::unique_ptr<ui::ScopedAnimationDurationScaleMode> hide_duration(
       new ui::ScopedAnimationDurationScaleMode(
           ui::ScopedAnimationDurationScaleMode::SLOW_DURATION));
-  GetTray()->SetVisible(false);
+  GetTray()->SetVisiblePreferred(false);
 
   aura::Window* root_window = Shell::GetRootWindowForDisplayId(
       display::Screen::GetScreen()->GetPrimaryDisplay().id());
diff --git a/ash/system/palette/palette_tray.cc b/ash/system/palette/palette_tray.cc
index 048b5e8d..6f86fac 100644
--- a/ash/system/palette/palette_tray.cc
+++ b/ash/system/palette/palette_tray.cc
@@ -558,7 +558,7 @@
       prefs::kEnableStylusTools);
 
   if (!is_palette_enabled_) {
-    SetVisible(false);
+    SetVisiblePreferred(false);
     palette_tool_manager_->DisableActiveTool(PaletteGroup::MODE);
   } else {
     UpdateIconVisibility();
@@ -591,9 +591,10 @@
 }
 
 void PaletteTray::UpdateIconVisibility() {
-  SetVisible(HasSeenStylus() && is_palette_enabled_ &&
-             stylus_utils::HasStylusInput() && ShouldShowOnDisplay(this) &&
-             palette_utils::IsInUserSession());
+  SetVisiblePreferred(HasSeenStylus() && is_palette_enabled_ &&
+                      stylus_utils::HasStylusInput() &&
+                      ShouldShowOnDisplay(this) &&
+                      palette_utils::IsInUserSession());
 }
 
 }  // namespace ash
diff --git a/ash/system/status_area_widget.cc b/ash/system/status_area_widget.cc
index 0f7e51e..c895dae 100644
--- a/ash/system/status_area_widget.cc
+++ b/ash/system/status_area_widget.cc
@@ -83,8 +83,7 @@
   virtual_keyboard_tray_->Initialize();
   ime_menu_tray_->Initialize();
   select_to_speak_tray_->Initialize();
-  if (dictation_button_tray_)
-    dictation_button_tray_->Initialize();
+  dictation_button_tray_->Initialize();
   overview_button_tray_->Initialize();
   UpdateAfterShelfAlignmentChange();
   UpdateAfterLoginStatusChange(
@@ -116,8 +115,7 @@
   virtual_keyboard_tray_->UpdateAfterShelfAlignmentChange();
   ime_menu_tray_->UpdateAfterShelfAlignmentChange();
   select_to_speak_tray_->UpdateAfterShelfAlignmentChange();
-  if (dictation_button_tray_)
-    dictation_button_tray_->UpdateAfterShelfAlignmentChange();
+  dictation_button_tray_->UpdateAfterShelfAlignmentChange();
   palette_tray_->UpdateAfterShelfAlignmentChange();
   overview_button_tray_->UpdateAfterShelfAlignmentChange();
   status_area_widget_delegate_->UpdateLayout();
@@ -135,7 +133,7 @@
 
 void StatusAreaWidget::SetSystemTrayVisibility(bool visible) {
   TrayBackgroundView* tray = unified_system_tray_.get();
-  tray->SetVisible(visible);
+  tray->SetVisiblePreferred(visible);
   // Opacity is set to prevent flakiness in kiosk browser tests. See
   // https://crbug.com/624584.
   SetOpacity(visible ? 1.f : 0.f);
@@ -182,8 +180,7 @@
   logout_button_tray_->SchedulePaint();
   ime_menu_tray_->SchedulePaint();
   select_to_speak_tray_->SchedulePaint();
-  if (dictation_button_tray_)
-    dictation_button_tray_->SchedulePaint();
+  dictation_button_tray_->SchedulePaint();
   palette_tray_->SchedulePaint();
   overview_button_tray_->SchedulePaint();
 }
diff --git a/ash/system/status_area_widget.h b/ash/system/status_area_widget.h
index a9664f3..5e0236d 100644
--- a/ash/system/status_area_widget.h
+++ b/ash/system/status_area_widget.h
@@ -35,6 +35,10 @@
 // on secondary monitors at the login screen).
 class ASH_EXPORT StatusAreaWidget : public views::Widget {
  public:
+  // Whether the status area is collapsed or expanded. Currently, this is only
+  // applicable in in-app tablet mode. Otherwise the state is NOT_COLLAPSIBLE.
+  enum class CollapseState { NOT_COLLAPSIBLE, COLLAPSED, EXPANDED };
+
   StatusAreaWidget(aura::Window* status_container, Shelf* shelf);
   ~StatusAreaWidget() override;
 
@@ -109,6 +113,8 @@
     return virtual_keyboard_tray_.get();
   }
 
+  CollapseState collapse_state() const { return collapse_state_; }
+
  private:
   friend class StatusAreaWidgetTestApi;
 
@@ -130,6 +136,8 @@
 
   LoginStatus login_status_ = LoginStatus::NOT_LOGGED_IN;
 
+  CollapseState collapse_state_ = CollapseState::NOT_COLLAPSIBLE;
+
   Shelf* shelf_;
 
   DISALLOW_COPY_AND_ASSIGN(StatusAreaWidget);
diff --git a/ash/system/status_area_widget_test_api.cc b/ash/system/status_area_widget_test_api.cc
index 5a0e8a7..55846ca0 100644
--- a/ash/system/status_area_widget_test_api.cc
+++ b/ash/system/status_area_widget_test_api.cc
@@ -43,4 +43,9 @@
   std::move(callback).Run();
 }
 
+void StatusAreaWidgetTestApi::SetCollapseState(
+    StatusAreaWidget::CollapseState collapse_state) {
+  widget_->collapse_state_ = collapse_state;
+}
+
 }  // namespace ash
diff --git a/ash/system/status_area_widget_test_api.h b/ash/system/status_area_widget_test_api.h
index f75896b..7fde252 100644
--- a/ash/system/status_area_widget_test_api.h
+++ b/ash/system/status_area_widget_test_api.h
@@ -24,6 +24,8 @@
   // mojom::StatusAreaWidgetTestApi:
   void TapSelectToSpeakTray(TapSelectToSpeakTrayCallback callback) override;
 
+  void SetCollapseState(StatusAreaWidget::CollapseState collapse_state);
+
  private:
   StatusAreaWidget* const widget_;
 
diff --git a/ash/system/status_area_widget_unittest.cc b/ash/system/status_area_widget_unittest.cc
index 035cdc2..3f5762f 100644
--- a/ash/system/status_area_widget_unittest.cc
+++ b/ash/system/status_area_widget_unittest.cc
@@ -14,10 +14,15 @@
 #include "ash/session/session_controller_impl.h"
 #include "ash/session/test_session_controller_client.h"
 #include "ash/shell.h"
+#include "ash/system/accessibility/dictation_button_tray.h"
+#include "ash/system/accessibility/select_to_speak_tray.h"
 #include "ash/system/ime_menu/ime_menu_tray.h"
+#include "ash/system/model/system_tray_model.h"
+#include "ash/system/model/virtual_keyboard_model.h"
 #include "ash/system/overview/overview_button_tray.h"
 #include "ash/system/palette/palette_tray.h"
 #include "ash/system/session/logout_button_tray.h"
+#include "ash/system/status_area_widget_test_api.h"
 #include "ash/system/status_area_widget_test_helper.h"
 #include "ash/system/tray/system_tray_notifier.h"
 #include "ash/system/unified/unified_system_tray.h"
@@ -273,8 +278,8 @@
        ClickingVirtualKeyboardTrayHidesShownKeyboard) {
   // Set up the virtual keyboard tray icon along with some other tray icons.
   StatusAreaWidget* status = StatusAreaWidgetTestHelper::GetStatusAreaWidget();
-  status->virtual_keyboard_tray_for_testing()->SetVisible(true);
-  status->ime_menu_tray()->SetVisible(true);
+  status->virtual_keyboard_tray_for_testing()->SetVisiblePreferred(true);
+  status->ime_menu_tray()->SetVisiblePreferred(true);
 
   keyboard_ui_controller()->ShowKeyboard(false /* locked */);
   ASSERT_TRUE(keyboard::WaitUntilShown());
@@ -294,8 +299,8 @@
        TappingVirtualKeyboardTrayHidesShownKeyboard) {
   // Set up the virtual keyboard tray icon along with some other tray icons.
   StatusAreaWidget* status = StatusAreaWidgetTestHelper::GetStatusAreaWidget();
-  status->virtual_keyboard_tray_for_testing()->SetVisible(true);
-  status->ime_menu_tray()->SetVisible(true);
+  status->virtual_keyboard_tray_for_testing()->SetVisiblePreferred(true);
+  status->ime_menu_tray()->SetVisiblePreferred(true);
 
   keyboard_ui_controller()->ShowKeyboard(false /* locked */);
   ASSERT_TRUE(keyboard::WaitUntilShown());
@@ -355,4 +360,88 @@
   EXPECT_FALSE(keyboard::IsKeyboardHiding());
 }
 
+class StatusAreaWidgetCollapseStateTest : public AshTestBase {
+ protected:
+  void SetUp() override {
+    AshTestBase::SetUp();
+
+    StatusAreaWidget* status_area =
+        StatusAreaWidgetTestHelper::GetStatusAreaWidget();
+    virtual_keyboard_ = status_area->virtual_keyboard_tray_for_testing();
+    ime_menu_ = status_area->ime_menu_tray();
+    palette_ = status_area->palette_tray();
+    dictation_button_ = status_area->dictation_button_tray();
+    select_to_speak_ = status_area->select_to_speak_tray();
+
+    virtual_keyboard_->SetVisiblePreferred(true);
+    ime_menu_->SetVisiblePreferred(true);
+    palette_->SetVisiblePreferred(true);
+    dictation_button_->SetVisiblePreferred(true);
+    select_to_speak_->SetVisiblePreferred(true);
+  }
+
+  void SetCollapseState(StatusAreaWidget::CollapseState collapse_state) {
+    StatusAreaWidgetTestApi test_api(
+        StatusAreaWidgetTestHelper::GetStatusAreaWidget());
+    test_api.SetCollapseState(collapse_state);
+
+    virtual_keyboard_->UpdateAfterStatusAreaCollapseChange();
+    ime_menu_->UpdateAfterStatusAreaCollapseChange();
+    palette_->UpdateAfterStatusAreaCollapseChange();
+    dictation_button_->UpdateAfterStatusAreaCollapseChange();
+    select_to_speak_->UpdateAfterStatusAreaCollapseChange();
+  }
+
+  TrayBackgroundView* virtual_keyboard_;
+  TrayBackgroundView* ime_menu_;
+  TrayBackgroundView* palette_;
+  TrayBackgroundView* dictation_button_;
+  TrayBackgroundView* select_to_speak_;
+};
+
+TEST_F(StatusAreaWidgetCollapseStateTest, TrayVisibility) {
+  // Initial visibility.
+  ime_menu_->SetVisiblePreferred(false);
+  virtual_keyboard_->set_show_when_collapsed(false);
+  palette_->set_show_when_collapsed(true);
+  EXPECT_FALSE(ime_menu_->GetVisible());
+  EXPECT_TRUE(virtual_keyboard_->GetVisible());
+  EXPECT_TRUE(palette_->GetVisible());
+
+  // Post-collapse visibility.
+  SetCollapseState(StatusAreaWidget::CollapseState::COLLAPSED);
+  EXPECT_FALSE(ime_menu_->GetVisible());
+  EXPECT_FALSE(virtual_keyboard_->GetVisible());
+  EXPECT_TRUE(palette_->GetVisible());
+
+  // Expanded visibility.
+  SetCollapseState(StatusAreaWidget::CollapseState::EXPANDED);
+  EXPECT_FALSE(ime_menu_->GetVisible());
+  EXPECT_TRUE(virtual_keyboard_->GetVisible());
+  EXPECT_TRUE(palette_->GetVisible());
+}
+
+TEST_F(StatusAreaWidgetCollapseStateTest, ImeMenuShownWithVirtualKeyboard) {
+  // Set up tray items.
+  ime_menu_->set_show_when_collapsed(false);
+  palette_->set_show_when_collapsed(true);
+
+  // Collapsing the status area should hide the IME menu tray item.
+  SetCollapseState(StatusAreaWidget::CollapseState::COLLAPSED);
+  EXPECT_FALSE(ime_menu_->GetVisible());
+  EXPECT_TRUE(palette_->GetVisible());
+
+  // But only the IME menu tray item should be shown after showing keyboard,
+  // simulated here by OnArcInputMethodSurfaceBoundsChanged().
+  Shell::Get()
+      ->system_tray_model()
+      ->virtual_keyboard()
+      ->OnArcInputMethodSurfaceBoundsChanged(gfx::Rect(0, 0, 100, 100));
+  EXPECT_TRUE(ime_menu_->GetVisible());
+  EXPECT_FALSE(palette_->GetVisible());
+  EXPECT_FALSE(virtual_keyboard_->GetVisible());
+  EXPECT_FALSE(dictation_button_->GetVisible());
+  EXPECT_FALSE(select_to_speak_->GetVisible());
+}
+
 }  // namespace ash
diff --git a/ash/system/tray/status_area_overflow_button_tray.cc b/ash/system/tray/status_area_overflow_button_tray.cc
index df3784be2..128e8c5 100644
--- a/ash/system/tray/status_area_overflow_button_tray.cc
+++ b/ash/system/tray/status_area_overflow_button_tray.cc
@@ -104,7 +104,7 @@
 
   // TODO(tengs): Make this tray button visible when the device is in tablet
   // mode and the status area width exceeds the maximum desirable width.
-  SetVisible(false);
+  SetVisiblePreferred(false);
 }
 
 bool StatusAreaOverflowButtonTray::PerformAction(const ui::Event& event) {
diff --git a/ash/system/tray/tray_background_view.cc b/ash/system/tray/tray_background_view.cc
index 8da2ecf..db272e2 100644
--- a/ash/system/tray/tray_background_view.cc
+++ b/ash/system/tray/tray_background_view.cc
@@ -149,6 +149,7 @@
       separator_visible_(true),
       visible_preferred_(false),
       show_with_virtual_keyboard_(false),
+      show_when_collapsed_(true),
       widget_observer_(new TrayWidgetObserver(this)) {
   DCHECK(shelf_);
   set_notify_enter_exit_on_child(true);
@@ -202,17 +203,12 @@
       window, base::TimeDelta::FromMilliseconds(kAnimationDurationForPopupMs));
 }
 
+void TrayBackgroundView::SetVisiblePreferred(bool visible_preferred) {
+  visible_preferred_ = visible_preferred;
+  SetVisible(GetEffectiveVisibility());
+}
+
 void TrayBackgroundView::SetVisible(bool visible) {
-  visible_preferred_ = visible;
-
-  // If virtual keyboard is visible and TrayBackgroundView is hidden because of
-  // that, ignore SetVisible() call. |visible_preferred_|  will be restored
-  // in OnVirtualKeyboardVisibilityChanged() when virtual keyboard is hidden.
-  if (!show_with_virtual_keyboard_ &&
-      Shell::Get()->system_tray_model()->virtual_keyboard()->visible()) {
-    return;
-  }
-
   if (visible == layer()->GetTargetVisibility())
     return;
 
@@ -328,21 +324,8 @@
 }
 
 void TrayBackgroundView::OnVirtualKeyboardVisibilityChanged() {
-  if (show_with_virtual_keyboard_) {
-    // The view always shows up when virtual keyboard is visible if
-    // |show_with_virtual_keyboard| is true.
-    views::View::SetVisible(
-        Shell::Get()->system_tray_model()->virtual_keyboard()->visible() ||
-        visible_preferred_);
-    return;
-  }
-
-  // If virtual keyboard is hidden and current preferred visibility is true,
-  // set the visibility to true. We call base class' SetVisible because we don't
-  // want |visible_preferred_| to be updated here.
-  views::View::SetVisible(
-      !Shell::Get()->system_tray_model()->virtual_keyboard()->visible() &&
-      visible_preferred_);
+  // We call the base class' SetVisible to skip animations.
+  views::View::SetVisible(GetEffectiveVisibility());
 }
 
 TrayBubbleView* TrayBackgroundView::GetBubbleView() {
@@ -363,6 +346,11 @@
   // Do nothing by default. Child class may do something.
 }
 
+void TrayBackgroundView::UpdateAfterStatusAreaCollapseChange() {
+  // We call the base class' SetVisible to skip animations.
+  views::View::SetVisible(GetEffectiveVisibility());
+}
+
 void TrayBackgroundView::BubbleResized(const TrayBubbleView* bubble_view) {}
 
 void TrayBackgroundView::OnImplicitAnimationsCompleted() {
@@ -490,4 +478,25 @@
   layer()->SetClipRect(GetBackgroundBounds());
 }
 
+bool TrayBackgroundView::GetEffectiveVisibility() {
+  // When the virtual keyboard is visible, the effective visibility of the view
+  // is solely determined by |show_with_virtual_keyboard_|.
+  if (Shell::Get()->system_tray_model()->virtual_keyboard()->visible())
+    return show_with_virtual_keyboard_;
+
+  if (!visible_preferred_)
+    return false;
+
+  // When the status area is collapsed, the effective visibility of the view is
+  // determined by |show_when_collapsed_|.
+  StatusAreaWidget::CollapseState collapse_state =
+      Shelf::ForWindow(GetWidget()->GetNativeWindow())
+          ->GetStatusAreaWidget()
+          ->collapse_state();
+  if (collapse_state == StatusAreaWidget::CollapseState::COLLAPSED)
+    return show_when_collapsed_;
+
+  return true;
+}
+
 }  // namespace ash
diff --git a/ash/system/tray/tray_background_view.h b/ash/system/tray/tray_background_view.h
index a46d5492..62d3287 100644
--- a/ash/system/tray/tray_background_view.h
+++ b/ash/system/tray/tray_background_view.h
@@ -42,13 +42,6 @@
   // Initializes animations for the bubble.
   static void InitializeBubbleAnimations(views::Widget* bubble_widget);
 
-  // views::View:
-  void SetVisible(bool visible) override;
-  const char* GetClassName() const override;
-  void AboutToRequestFocusFromTabTraversal(bool reverse) override;
-  void GetAccessibleNodeData(ui::AXNodeData* node_data) override;
-  void ChildPreferredSizeChanged(views::View* child) override;
-
   // ActionableView:
   std::unique_ptr<views::InkDropRipple> CreateInkDropRipple() const override;
   std::unique_ptr<views::InkDropHighlight> CreateInkDropHighlight()
@@ -76,6 +69,9 @@
   virtual void UpdateAfterRootWindowBoundsChange(const gfx::Rect& old_bounds,
                                                  const gfx::Rect& new_bounds);
 
+  // Called whenever the status area's collapse state changes.
+  virtual void UpdateAfterStatusAreaCollapseChange();
+
   // Called when the anchor (tray or bubble) may have moved or changed.
   virtual void AnchorUpdated() {}
 
@@ -106,6 +102,11 @@
   // Updates the visibility of this tray's separator.
   void set_separator_visibility(bool visible) { separator_visible_ = visible; }
 
+  // Sets whether to show the view when the status area is collapsed.
+  void set_show_when_collapsed(bool show_when_collapsed) {
+    show_when_collapsed_ = show_when_collapsed;
+  }
+
   // Gets the anchor for bubbles, which is tray_container().
   views::View* GetBubbleAnchor() const;
 
@@ -120,6 +121,12 @@
   // based on background insets returned from GetBackgroundInsets().
   gfx::Rect GetBackgroundBounds() const;
 
+  // Sets whether the tray item should be shown by default (e.g. it is
+  // activated). The effective visibility of the tray item is determined by the
+  // current state of the status tray (i.e. whether the virtual keyboard is
+  // showing or if it is collapsed).
+  void SetVisiblePreferred(bool visible_preferred);
+
  protected:
   // ActionableView:
   void OnBoundsChanged(const gfx::Rect& previous_bounds) override;
@@ -137,6 +144,13 @@
   class HighlightPathGenerator;
   class TrayWidgetObserver;
 
+  // views::View:
+  void SetVisible(bool visible) override;
+  const char* GetClassName() const override;
+  void AboutToRequestFocusFromTabTraversal(bool reverse) override;
+  void GetAccessibleNodeData(ui::AXNodeData* node_data) override;
+  void ChildPreferredSizeChanged(views::View* child) override;
+
   // ui::ImplicitAnimationObserver:
   void OnImplicitAnimationsCompleted() override;
   bool RequiresNotificationWhenAnimatorDestroyed() const override;
@@ -151,6 +165,10 @@
   // Updates the background layer.
   void UpdateBackground();
 
+  // Returns the effective visibility of the tray item based on the current
+  // state.
+  bool GetEffectiveVisibility();
+
   // The shelf containing the system tray for this view.
   Shelf* shelf_;
 
@@ -173,6 +191,9 @@
   // If true, the view always shows up when virtual keyboard is visible.
   bool show_with_virtual_keyboard_;
 
+  // If true, the view is visible when the status area is collapsed.
+  bool show_when_collapsed_;
+
   std::unique_ptr<TrayWidgetObserver> widget_observer_;
   std::unique_ptr<TrayEventFilter> tray_event_filter_;
 
diff --git a/ash/system/unified/unified_system_tray.cc b/ash/system/unified/unified_system_tray.cc
index 13e90d3..b44acd54 100644
--- a/ash/system/unified/unified_system_tray.cc
+++ b/ash/system/unified/unified_system_tray.cc
@@ -270,7 +270,7 @@
 }
 
 void UnifiedSystemTray::UpdateAfterLoginStatusChange() {
-  SetVisible(true);
+  SetVisiblePreferred(true);
   PreferredSizeChanged();
 }
 
diff --git a/ash/system/virtual_keyboard/virtual_keyboard_tray.cc b/ash/system/virtual_keyboard/virtual_keyboard_tray.cc
index ddcb0f2..69f42ff3 100644
--- a/ash/system/virtual_keyboard/virtual_keyboard_tray.cc
+++ b/ash/system/virtual_keyboard/virtual_keyboard_tray.cc
@@ -90,7 +90,7 @@
 void VirtualKeyboardTray::OnAccessibilityStatusChanged() {
   bool new_enabled =
       Shell::Get()->accessibility_controller()->virtual_keyboard_enabled();
-  SetVisible(new_enabled);
+  SetVisiblePreferred(new_enabled);
 }
 
 void VirtualKeyboardTray::OnKeyboardVisibilityChanged(const bool is_visible) {
diff --git a/ash/system/virtual_keyboard/virtual_keyboard_tray_unittest.cc b/ash/system/virtual_keyboard/virtual_keyboard_tray_unittest.cc
index 279bb18..b39f979c 100644
--- a/ash/system/virtual_keyboard/virtual_keyboard_tray_unittest.cc
+++ b/ash/system/virtual_keyboard/virtual_keyboard_tray_unittest.cc
@@ -40,7 +40,7 @@
 TEST_F(VirtualKeyboardTrayTest, PerformActionTogglesVirtualKeyboard) {
   StatusAreaWidget* status = StatusAreaWidgetTestHelper::GetStatusAreaWidget();
   VirtualKeyboardTray* tray = status->virtual_keyboard_tray_for_testing();
-  tray->SetVisible(true);
+  tray->SetVisiblePreferred(true);
   ASSERT_TRUE(tray->GetVisible());
 
   // First tap should show the virtual keyboard.
diff --git a/base/android/java/src/org/chromium/base/StrictModeContext.java b/base/android/java/src/org/chromium/base/StrictModeContext.java
index 49b2ad8..2c9aa80 100644
--- a/base/android/java/src/org/chromium/base/StrictModeContext.java
+++ b/base/android/java/src/org/chromium/base/StrictModeContext.java
@@ -50,6 +50,17 @@
     }
 
     /**
+     * Convenience method for disabling all thread-level StrictMode checks with try-with-resources.
+     * Includes everything listed here:
+     *     https://developer.android.com/reference/android/os/StrictMode.ThreadPolicy.Builder.html
+     */
+    public static StrictModeContext allowAllThreadPolicies() {
+        StrictMode.ThreadPolicy oldPolicy = StrictMode.getThreadPolicy();
+        StrictMode.setThreadPolicy(StrictMode.ThreadPolicy.LAX);
+        return new StrictModeContext(oldPolicy);
+    }
+
+    /**
      * Convenience method for disabling StrictMode for disk-writes with try-with-resources.
      */
     public static StrictModeContext allowDiskWrites() {
@@ -84,4 +95,4 @@
             StrictMode.setVmPolicy(mVmPolicy);
         }
     }
-}
\ No newline at end of file
+}
diff --git a/base/test/android/javatests/src/org/chromium/base/test/ScreenshotOnFailureStatement.java b/base/test/android/javatests/src/org/chromium/base/test/ScreenshotOnFailureStatement.java
index f982e14..3ad851a 100644
--- a/base/test/android/javatests/src/org/chromium/base/test/ScreenshotOnFailureStatement.java
+++ b/base/test/android/javatests/src/org/chromium/base/test/ScreenshotOnFailureStatement.java
@@ -14,6 +14,7 @@
 import org.junit.runners.model.Statement;
 
 import org.chromium.base.Log;
+import org.chromium.base.StrictModeContext;
 
 import java.io.File;
 
@@ -65,32 +66,34 @@
                             screenshotFile));
             return;
         }
-        if (!screenshotDir.exists()) {
-            if (!screenshotDir.mkdirs()) {
-                Log.d(TAG,
-                        String.format(
-                                "Failed to create %s. Can't save screenshot.", screenshotDir));
+        try (StrictModeContext ignored = StrictModeContext.allowAllThreadPolicies()) {
+            if (!screenshotDir.exists()) {
+                if (!screenshotDir.mkdirs()) {
+                    Log.d(TAG,
+                            String.format(
+                                    "Failed to create %s. Can't save screenshot.", screenshotDir));
+                    return;
+                }
+            }
+
+            // The Vega standalone VR headset can't take screenshots normally (they just show a
+            // black screen with the VR overlay), so instead, use VrCore's RecorderService.
+            if (Build.DEVICE.equals("vega")) {
+                takeScreenshotVega(screenshotFile);
                 return;
             }
-        }
 
-        // The Vega standalone VR headset can't take screenshots normally (they just show a black
-        // screen with the VR overlay), so instead, use VrCore's RecorderService.
-        if (Build.DEVICE.equals("vega")) {
-            takeScreenshotVega(screenshotFile);
-            return;
-        }
+            UiDevice uiDevice = null;
+            try {
+                uiDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation());
+            } catch (RuntimeException ex) {
+                Log.d(TAG, "Failed to initialize UiDevice", ex);
+                return;
+            }
 
-        UiDevice uiDevice = null;
-        try {
-            uiDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation());
-        } catch (RuntimeException ex) {
-            Log.d(TAG, "Failed to initialize UiDevice", ex);
-            return;
+            Log.d(TAG, String.format("Saving screenshot of test failure, %s", screenshotFile));
+            uiDevice.takeScreenshot(screenshotFile);
         }
-
-        Log.d(TAG, String.format("Saving screenshot of test failure, %s", screenshotFile));
-        uiDevice.takeScreenshot(screenshotFile);
     }
 
     private void takeScreenshotVega(final File screenshotFile) {
diff --git a/build/fuchsia/linux.sdk.sha1 b/build/fuchsia/linux.sdk.sha1
index 16110e5..1096166 100644
--- a/build/fuchsia/linux.sdk.sha1
+++ b/build/fuchsia/linux.sdk.sha1
@@ -1 +1 @@
-8897419927696300224
\ No newline at end of file
+8897393320560678400
\ No newline at end of file
diff --git a/build/fuchsia/mac.sdk.sha1 b/build/fuchsia/mac.sdk.sha1
index ee69debb..d9f85a3 100644
--- a/build/fuchsia/mac.sdk.sha1
+++ b/build/fuchsia/mac.sdk.sha1
@@ -1 +1 @@
-8897425289159983392
\ No newline at end of file
+8897398712024874704
\ No newline at end of file
diff --git a/cc/trees/layer_tree_host_impl.cc b/cc/trees/layer_tree_host_impl.cc
index 9e8db5bb..4cfa0b7 100644
--- a/cc/trees/layer_tree_host_impl.cc
+++ b/cc/trees/layer_tree_host_impl.cc
@@ -2074,6 +2074,10 @@
   // external viewport to be set otherwise.
   DCHECK(active_tree_->internal_device_viewport().origin().IsOrigin());
 
+#if DCHECK_IS_ON()
+  base::AutoReset<bool> reset_sync_draw(&doing_sync_draw_, true);
+#endif
+
   if (skip_draw) {
     client_->OnDrawForLayerTreeFrameSink(resourceless_software_draw_, true);
     return;
@@ -2297,6 +2301,21 @@
       std::move(compositor_frame),
       /*hit_test_data_changed=*/false, debug_state_.show_hit_test_borders);
 
+#if DCHECK_IS_ON()
+  if (!doing_sync_draw_) {
+    // The throughput computation (in |FrameSequenceTracker|) depends on the
+    // compositor-frame submission to happen while a BeginFrameArgs is 'active'
+    // (i.e. between calls to WillBeginImplFrame() and DidFinishImplFrame()).
+    // Verify that this is the case.
+    // No begin-frame is available when doing sync draws, so avoid doing this
+    // check in that case.
+    const auto& bfargs = current_begin_frame_tracker_.Current();
+    const auto& ack = compositor_frame.metadata.begin_frame_ack;
+    DCHECK_EQ(bfargs.source_id, ack.source_id);
+    DCHECK_EQ(bfargs.sequence_number, ack.sequence_number);
+  }
+#endif
+
   frame_trackers_.NotifySubmitFrame(
       compositor_frame.metadata.frame_token, frame->has_missing_content,
       frame->begin_frame_ack, frame->origin_begin_main_frame_args);
diff --git a/cc/trees/layer_tree_host_impl.h b/cc/trees/layer_tree_host_impl.h
index 2ae154e1..b6faedc 100644
--- a/cc/trees/layer_tree_host_impl.h
+++ b/cc/trees/layer_tree_host_impl.h
@@ -1293,6 +1293,11 @@
   // not we are in that state.
   bool pending_tree_fully_painted_ = false;
 
+#if DCHECK_IS_ON()
+  // Use to track when doing a synchronous draw.
+  bool doing_sync_draw_ = false;
+#endif
+
   // Provides support for PaintWorklets which depend on input properties that
   // are being animated by the compositor (aka 'animated' PaintWorklets).
   // Responsible for storing animated custom property values and for
diff --git a/cc/trees/layer_tree_host_impl_unittest.cc b/cc/trees/layer_tree_host_impl_unittest.cc
index 9784156e..fb8bf14f 100644
--- a/cc/trees/layer_tree_host_impl_unittest.cc
+++ b/cc/trees/layer_tree_host_impl_unittest.cc
@@ -600,9 +600,13 @@
   void DrawFrame() {
     PrepareForUpdateDrawProperties(host_impl_->active_tree());
     TestFrameData frame;
+    host_impl_->WillBeginImplFrame(viz::CreateBeginFrameArgsForTesting(
+        BEGINFRAME_FROM_HERE, viz::BeginFrameArgs::kManualSourceId, 1,
+        base::TimeTicks() + base::TimeDelta::FromMilliseconds(1)));
     EXPECT_EQ(DRAW_SUCCESS, host_impl_->PrepareToDraw(&frame));
     host_impl_->DrawLayers(&frame);
     host_impl_->DidDrawAllLayers(frame);
+    host_impl_->DidFinishImplFrame();
   }
 
   RenderFrameMetadata StartDrawAndProduceRenderFrameMetadata() {
@@ -4621,6 +4625,9 @@
 
   {
     TestFrameData frame;
+    host_impl_->WillBeginImplFrame(viz::CreateBeginFrameArgsForTesting(
+        BEGINFRAME_FROM_HERE, viz::BeginFrameArgs::kManualSourceId, 1,
+        base::TimeTicks() + base::TimeDelta::FromMilliseconds(1)));
     EXPECT_EQ(DRAW_SUCCESS, host_impl_->PrepareToDraw(&frame));
 
     EXPECT_FALSE(frame.has_no_damage);
@@ -4631,6 +4638,7 @@
     EXPECT_NE(total_quad_count, 0u);
     host_impl_->DrawLayers(&frame);
     host_impl_->DidDrawAllLayers(frame);
+    host_impl_->DidFinishImplFrame();
   }
 
   // Stops the child layer from drawing. We should have damage from this but
@@ -4646,6 +4654,9 @@
 
   {
     TestFrameData frame;
+    host_impl_->WillBeginImplFrame(viz::CreateBeginFrameArgsForTesting(
+        BEGINFRAME_FROM_HERE, viz::BeginFrameArgs::kManualSourceId, 1,
+        base::TimeTicks() + base::TimeDelta::FromMilliseconds(1)));
     EXPECT_EQ(DRAW_SUCCESS, host_impl_->PrepareToDraw(&frame));
 
     EXPECT_FALSE(frame.has_no_damage);
@@ -4656,12 +4667,16 @@
     EXPECT_EQ(total_quad_count, 0u);
     host_impl_->DrawLayers(&frame);
     host_impl_->DidDrawAllLayers(frame);
+    host_impl_->DidFinishImplFrame();
   }
 
   // Now tries to draw again. Nothing changes, so should have no damage, no
   // render pass, and no quad.
   {
     TestFrameData frame;
+    host_impl_->WillBeginImplFrame(viz::CreateBeginFrameArgsForTesting(
+        BEGINFRAME_FROM_HERE, viz::BeginFrameArgs::kManualSourceId, 1,
+        base::TimeTicks() + base::TimeDelta::FromMilliseconds(1)));
     EXPECT_EQ(DRAW_SUCCESS, host_impl_->PrepareToDraw(&frame));
 
     EXPECT_TRUE(frame.has_no_damage);
@@ -4672,6 +4687,7 @@
     EXPECT_EQ(total_quad_count, 0u);
     host_impl_->DrawLayers(&frame);
     host_impl_->DidDrawAllLayers(frame);
+    host_impl_->DidFinishImplFrame();
   }
 }
 
@@ -4965,9 +4981,13 @@
       host_impl_->SetRequiresHighResToDraw();
 
     TestFrameData frame;
+    host_impl_->WillBeginImplFrame(viz::CreateBeginFrameArgsForTesting(
+        BEGINFRAME_FROM_HERE, viz::BeginFrameArgs::kManualSourceId, 1,
+        base::TimeTicks() + base::TimeDelta::FromMilliseconds(1)));
     EXPECT_EQ(testcase.expected_result, host_impl_->PrepareToDraw(&frame));
     host_impl_->DrawLayers(&frame);
     host_impl_->DidDrawAllLayers(frame);
+    host_impl_->DidFinishImplFrame();
   }
 }
 
@@ -7111,9 +7131,13 @@
 
   // Check scroll delta reflected in layer.
   TestFrameData frame;
+  host_impl_->WillBeginImplFrame(viz::CreateBeginFrameArgsForTesting(
+      BEGINFRAME_FROM_HERE, viz::BeginFrameArgs::kManualSourceId, 1,
+      base::TimeTicks() + base::TimeDelta::FromMilliseconds(1)));
   EXPECT_EQ(DRAW_SUCCESS, host_impl_->PrepareToDraw(&frame));
   host_impl_->DrawLayers(&frame);
   host_impl_->DidDrawAllLayers(frame);
+  host_impl_->DidFinishImplFrame();
   EXPECT_FALSE(frame.has_no_damage);
   CheckLayerScrollDelta(scroll_layer,
                         gfx::ScrollOffsetToVector2dF(scroll_offset));
@@ -8306,9 +8330,13 @@
 static bool MayContainVideoBitSetOnFrameData(LayerTreeHostImpl* host_impl) {
   host_impl->active_tree()->set_needs_update_draw_properties();
   TestFrameData frame;
+  host_impl->WillBeginImplFrame(viz::CreateBeginFrameArgsForTesting(
+      BEGINFRAME_FROM_HERE, viz::BeginFrameArgs::kManualSourceId, 1,
+      base::TimeTicks() + base::TimeDelta::FromMilliseconds(1)));
   EXPECT_EQ(DRAW_SUCCESS, host_impl->PrepareToDraw(&frame));
   host_impl->DrawLayers(&frame);
   host_impl->DidDrawAllLayers(frame);
+  host_impl->DidFinishImplFrame();
   return frame.may_contain_video;
 }
 
@@ -8645,8 +8673,6 @@
           nullptr);
   layer_tree_host_impl->SetVisible(true);
   layer_tree_host_impl->InitializeFrameSink(layer_tree_frame_sink.get());
-  layer_tree_host_impl->WillBeginImplFrame(
-      viz::CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, 0, 2));
 
   LayerImpl* root = SetupRootLayer<LayerImpl>(
       layer_tree_host_impl->active_tree(), gfx::Size(500, 500));
@@ -8664,9 +8690,13 @@
   TestFrameData frame;
 
   // First frame, the entire screen should get swapped.
+  layer_tree_host_impl->WillBeginImplFrame(viz::CreateBeginFrameArgsForTesting(
+      BEGINFRAME_FROM_HERE, viz::BeginFrameArgs::kManualSourceId, 1,
+      base::TimeTicks() + base::TimeDelta::FromMilliseconds(1)));
   EXPECT_EQ(DRAW_SUCCESS, layer_tree_host_impl->PrepareToDraw(&frame));
   layer_tree_host_impl->DrawLayers(&frame);
   layer_tree_host_impl->DidDrawAllLayers(frame);
+  layer_tree_host_impl->DidFinishImplFrame();
   gfx::Rect expected_swap_rect(500, 500);
   EXPECT_EQ(expected_swap_rect.ToString(),
             fake_layer_tree_frame_sink->last_swap_rect().ToString());
@@ -8675,9 +8705,13 @@
   // the union of old and new child rects: gfx::Rect(26, 28).
   child->SetOffsetToTransformParent(gfx::Vector2dF());
   child->NoteLayerPropertyChanged();
+  layer_tree_host_impl->WillBeginImplFrame(viz::CreateBeginFrameArgsForTesting(
+      BEGINFRAME_FROM_HERE, viz::BeginFrameArgs::kManualSourceId, 1,
+      base::TimeTicks() + base::TimeDelta::FromMilliseconds(1)));
   EXPECT_EQ(DRAW_SUCCESS, layer_tree_host_impl->PrepareToDraw(&frame));
   layer_tree_host_impl->DrawLayers(&frame);
-  host_impl_->DidDrawAllLayers(frame);
+  layer_tree_host_impl->DidDrawAllLayers(frame);
+  layer_tree_host_impl->DidFinishImplFrame();
 
   expected_swap_rect = gfx::Rect(26, 28);
   EXPECT_EQ(expected_swap_rect.ToString(),
@@ -8686,9 +8720,13 @@
   layer_tree_host_impl->active_tree()->SetDeviceViewportRect(gfx::Rect(10, 10));
   // This will damage everything.
   root->SetBackgroundColor(SK_ColorBLACK);
+  layer_tree_host_impl->WillBeginImplFrame(viz::CreateBeginFrameArgsForTesting(
+      BEGINFRAME_FROM_HERE, viz::BeginFrameArgs::kManualSourceId, 1,
+      base::TimeTicks() + base::TimeDelta::FromMilliseconds(1)));
   EXPECT_EQ(DRAW_SUCCESS, layer_tree_host_impl->PrepareToDraw(&frame));
   layer_tree_host_impl->DrawLayers(&frame);
-  host_impl_->DidDrawAllLayers(frame);
+  layer_tree_host_impl->DidDrawAllLayers(frame);
+  layer_tree_host_impl->DidFinishImplFrame();
 
   expected_swap_rect = gfx::Rect(10, 10);
   EXPECT_EQ(expected_swap_rect.ToString(),
@@ -8783,6 +8821,9 @@
 
   // Verify one quad is drawn when transparent background set is not set.
   TestFrameData frame;
+  host_impl_->WillBeginImplFrame(viz::CreateBeginFrameArgsForTesting(
+      BEGINFRAME_FROM_HERE, viz::BeginFrameArgs::kManualSourceId, 1,
+      base::TimeTicks() + base::TimeDelta::FromMilliseconds(1)));
   EXPECT_EQ(DRAW_SUCCESS, host_impl_->PrepareToDraw(&frame));
   {
     const auto& root_pass = frame.render_passes.back();
@@ -8792,6 +8833,7 @@
   }
   host_impl_->DrawLayers(&frame);
   host_impl_->DidDrawAllLayers(frame);
+  host_impl_->DidFinishImplFrame();
 
   // Cause damage so we would draw something if possible.
   host_impl_->SetFullViewportDamage();
@@ -8799,6 +8841,9 @@
   // Verify no quads are drawn when transparent background is set.
   host_impl_->active_tree()->set_background_color(SK_ColorTRANSPARENT);
   host_impl_->SetFullViewportDamage();
+  host_impl_->WillBeginImplFrame(viz::CreateBeginFrameArgsForTesting(
+      BEGINFRAME_FROM_HERE, viz::BeginFrameArgs::kManualSourceId, 1,
+      base::TimeTicks() + base::TimeDelta::FromMilliseconds(1)));
   EXPECT_EQ(DRAW_SUCCESS, host_impl_->PrepareToDraw(&frame));
   {
     const auto& root_pass = frame.render_passes.back();
@@ -8806,6 +8851,7 @@
   }
   host_impl_->DrawLayers(&frame);
   host_impl_->DidDrawAllLayers(frame);
+  host_impl_->DidFinishImplFrame();
 
   // Cause damage so we would draw something if possible.
   host_impl_->SetFullViewportDamage();
@@ -8813,6 +8859,9 @@
   // Verify no quads are drawn when semi-transparent background is set.
   host_impl_->active_tree()->set_background_color(SkColorSetARGB(5, 255, 0, 0));
   host_impl_->SetFullViewportDamage();
+  host_impl_->WillBeginImplFrame(viz::CreateBeginFrameArgsForTesting(
+      BEGINFRAME_FROM_HERE, viz::BeginFrameArgs::kManualSourceId, 1,
+      base::TimeTicks() + base::TimeDelta::FromMilliseconds(1)));
   EXPECT_EQ(DRAW_SUCCESS, host_impl_->PrepareToDraw(&frame));
   {
     const auto& root_pass = frame.render_passes.back();
@@ -8820,6 +8869,7 @@
   }
   host_impl_->DrawLayers(&frame);
   host_impl_->DidDrawAllLayers(frame);
+  host_impl_->DidFinishImplFrame();
 }
 
 class LayerTreeHostImplTestDrawAndTestDamage : public LayerTreeHostImplTest {
@@ -8833,6 +8883,9 @@
     bool expect_to_draw = !expected_damage.IsEmpty();
 
     TestFrameData frame;
+    host_impl_->WillBeginImplFrame(viz::CreateBeginFrameArgsForTesting(
+        BEGINFRAME_FROM_HERE, viz::BeginFrameArgs::kManualSourceId, 1,
+        base::TimeTicks() + base::TimeDelta::FromMilliseconds(1)));
     EXPECT_EQ(DRAW_SUCCESS, host_impl_->PrepareToDraw(&frame));
 
     if (!expect_to_draw) {
@@ -8862,6 +8915,7 @@
 
     EXPECT_EQ(expect_to_draw, host_impl_->DrawLayers(&frame));
     host_impl_->DidDrawAllLayers(frame);
+    host_impl_->DidFinishImplFrame();
   }
 };
 
@@ -8943,6 +8997,9 @@
   ASSERT_EQ(1u, host_impl_->active_tree()->GetRenderSurfaceList().size());
 
   TestFrameData frame;
+  host_impl_->WillBeginImplFrame(viz::CreateBeginFrameArgsForTesting(
+      BEGINFRAME_FROM_HERE, viz::BeginFrameArgs::kManualSourceId, 1,
+      base::TimeTicks() + base::TimeDelta::FromMilliseconds(1)));
   EXPECT_EQ(DRAW_SUCCESS, host_impl_->PrepareToDraw(&frame));
 
   ASSERT_EQ(1u, frame.render_passes.size());
@@ -8962,6 +9019,7 @@
 
   host_impl_->DrawLayers(&frame);
   host_impl_->DidDrawAllLayers(frame);
+  host_impl_->DidFinishImplFrame();
 }
 
 class CompositorFrameMetadataTest : public LayerTreeHostImplTest {
@@ -9122,12 +9180,16 @@
   gfx::Rect full_frame_damage(
       host_impl->active_tree()->GetDeviceViewport().size());
   TestFrameData frame;
+  host_impl->WillBeginImplFrame(viz::CreateBeginFrameArgsForTesting(
+      BEGINFRAME_FROM_HERE, viz::BeginFrameArgs::kManualSourceId, 1,
+      base::TimeTicks() + base::TimeDelta::FromMilliseconds(1)));
   EXPECT_EQ(DRAW_SUCCESS, host_impl->PrepareToDraw(&frame));
   ASSERT_EQ(1u, frame.render_passes.size());
   const viz::RenderPass* root_render_pass = frame.render_passes.back().get();
   EXPECT_EQ(full_frame_damage, root_render_pass->damage_rect);
   EXPECT_TRUE(host_impl->DrawLayers(&frame));
   host_impl->DidDrawAllLayers(frame);
+  host_impl->DidFinishImplFrame();
 }
 }  // namespace
 
@@ -11477,8 +11539,6 @@
   scrolling_layer->SetBounds(new_content_size);
   GetScrollNode(scrolling_layer)->bounds = new_content_size;
 
-  DrawFrame();
-
   begin_frame_args.frame_time =
       start_time + base::TimeDelta::FromMilliseconds(200);
   begin_frame_args.sequence_number++;
diff --git a/chrome/VERSION b/chrome/VERSION
index e6e3473ed..bdd94ae 100644
--- a/chrome/VERSION
+++ b/chrome/VERSION
@@ -1,4 +1,4 @@
 MAJOR=80
 MINOR=0
-BUILD=3963
+BUILD=3964
 PATCH=0
diff --git a/chrome/android/BUILD.gn b/chrome/android/BUILD.gn
index 25b9be88..2acc3cb 100644
--- a/chrome/android/BUILD.gn
+++ b/chrome/android/BUILD.gn
@@ -1116,6 +1116,7 @@
     "java/res_template/xml/file_paths.xml",
     "java/res_template/xml/launchershortcuts.xml",
     "java/res_template/xml/searchable.xml",
+    "java/res_template/xml/syncadapter.xml",
   ]
   res_dir = "java/res_template"
   variables = [ "manifest_package=$chrome_public_manifest_package" ]
diff --git a/chrome/android/chrome_java_sources.gni b/chrome/android/chrome_java_sources.gni
index 9b7b8d70..dda43d25 100644
--- a/chrome/android/chrome_java_sources.gni
+++ b/chrome/android/chrome_java_sources.gni
@@ -854,6 +854,8 @@
   "java/src/org/chromium/chrome/browser/instantapps/InstantAppsBannerData.java",
   "java/src/org/chromium/chrome/browser/instantapps/InstantAppsHandler.java",
   "java/src/org/chromium/chrome/browser/instantapps/InstantAppsSettings.java",
+  "java/src/org/chromium/chrome/browser/invalidation/ChromeBrowserSyncAdapter.java",
+  "java/src/org/chromium/chrome/browser/invalidation/ChromeBrowserSyncAdapterService.java",
   "java/src/org/chromium/chrome/browser/invalidation/ResumableDelayedTaskRunner.java",
   "java/src/org/chromium/chrome/browser/invalidation/SessionsInvalidationManager.java",
   "java/src/org/chromium/chrome/browser/invalidation/UniqueIdInvalidationClientNameGenerator.java",
diff --git a/chrome/android/features/vr/java/src/org/chromium/chrome/browser/vr/VrShellDelegate.java b/chrome/android/features/vr/java/src/org/chromium/chrome/browser/vr/VrShellDelegate.java
index f536b0f..9a379a0 100644
--- a/chrome/android/features/vr/java/src/org/chromium/chrome/browser/vr/VrShellDelegate.java
+++ b/chrome/android/features/vr/java/src/org/chromium/chrome/browser/vr/VrShellDelegate.java
@@ -165,10 +165,6 @@
     private boolean mRestoreSystemUiVisibility;
     private Integer mRestoreOrientation;
     private boolean mRequestedWebVr;
-    private boolean mListeningForWebVrActivate;
-    private boolean mMaybeActivateAfterHeadsetInsertion;
-    private Handler mClearMaybeActivateHandler = new Handler();
-    private boolean mActivateFromHeadsetInsertion;
     private boolean mStartedFromVrIntent;
 
     private boolean mInternalIntentUsedToStartVr;
@@ -252,11 +248,6 @@
                 VrModuleProvider.getDelegate().addBlackOverlayViewForActivity(sInstance.mActivity);
             }
 
-            // For headset insertion handling it should be impossible in practice to receive this
-            // broadcast after being resumed. However, with VR entry flows skipped, these events
-            // can happen out of order. See https://crbug.com/762724.
-            sInstance.mActivateFromHeadsetInsertion = sInstance.mMaybeActivateAfterHeadsetInsertion;
-
             if (sInstance.mPaused) {
                 if (activity instanceof ChromeTabbedActivity) {
                     // We can special case singleInstance activities like CTA to avoid having to use
@@ -1067,19 +1058,7 @@
         if (mNativeVrShellDelegate == 0) return false;
         if (!canEnterVr()) return false;
 
-        // If headset insertion was performed while a page was listening for vrdisplayactivate,
-        // we assume it wants to request presentation. Go into WebVR mode tentatively. If the page
-        // doesn't request presentation in the vrdisplayactivate handler we will exit presentation
-        // later.
-        if (mActivateFromHeadsetInsertion) {
-            assert !mRequestedWebVr;
-            assert !mStartedFromVrIntent;
-        }
-        enterVr(mActivateFromHeadsetInsertion);
-        if (mActivateFromHeadsetInsertion && mListeningForWebVrActivate) {
-            VrShellDelegateJni.get().displayActivate(mNativeVrShellDelegate, VrShellDelegate.this);
-            mActivateFromHeadsetInsertion = false;
-        }
+        enterVr();
 
         // The user has successfully completed a DON flow.
         RecordUserAction.record("VR.DON");
@@ -1087,7 +1066,7 @@
         return true;
     }
 
-    private void enterVr(final boolean tentativeWebVrMode) {
+    private void enterVr() {
         // We should only enter VR when we're the resumed Activity or our changes to things like
         // system UI flags might get lost.
         assert !mPaused;
@@ -1116,12 +1095,11 @@
         if (!sRegisteredVrAssetsComponent) {
             registerVrAssetsComponentIfDaydreamUser(isDaydreamCurrentViewer());
         }
-        boolean webVrMode = mRequestedWebVr || tentativeWebVrMode;
-        mVrShell.initializeNative(webVrMode, VrModuleProvider.getDelegate().bootsToVr());
-        mVrShell.setWebVrModeEnabled(webVrMode);
+        mVrShell.initializeNative(mRequestedWebVr, VrModuleProvider.getDelegate().bootsToVr());
+        mVrShell.setWebVrModeEnabled(mRequestedWebVr);
 
         // We're entering VR, but not in WebVr mode.
-        mVrBrowserUsed = !webVrMode;
+        mVrBrowserUsed = !mRequestedWebVr;
 
         // resume needs to be called on GvrLayout after initialization to make sure DON flow works
         // properly.
@@ -1298,8 +1276,7 @@
         if (getVrSupportLevel() <= VrSupportLevel.VR_NEEDS_UPDATE) return false;
 
         // If VR browsing is not enabled and this is not a WebXR request, then return false.
-        boolean presenting = mRequestedWebVr || mActivateFromHeadsetInsertion;
-        if (!isVrBrowsingEnabled() && !presenting) return false;
+        if (!isVrBrowsingEnabled() && !mRequestedWebVr) return false;
         return true;
     }
 
@@ -1354,7 +1331,7 @@
             getVrDaydreamApi().launchInVr(getEnterVrPendingIntent(mActivity));
             mProbablyInDon = true;
         } else {
-            enterVr(false);
+            enterVr();
         }
         return EnterVRResult.REQUESTED;
     }
@@ -1430,9 +1407,6 @@
     @VisibleForTesting
     protected void onResume() {
         if (VrDelegate.DEBUG_LOGS) Log.i(TAG, "onResume");
-        if (!mTestWorkaroundDontCancelVrEntryOnResume) {
-            mMaybeActivateAfterHeadsetInsertion = false;
-        }
         if (mNeedsAnimationCancel) {
             // At least on some devices, like the Samsung S8+, a Window animation is run after our
             // Activity is shown that fades between a stale screenshot from before pausing to the
@@ -1520,7 +1494,6 @@
         if (mInVr) {
             maybeSetPresentResult(true);
             mDonSucceeded = false;
-            assert !mActivateFromHeadsetInsertion;
             return;
         }
         if (maybeExitVrToUpdateVrServices()) return;
@@ -1556,10 +1529,6 @@
         unregisterDaydreamIntent();
         if (getVrSupportLevel() <= VrSupportLevel.VR_NEEDS_UPDATE) return;
 
-        if (mMaybeActivateAfterHeadsetInsertion) {
-            mClearMaybeActivateHandler.removeCallbacksAndMessages(null);
-        }
-
         if (mInVr) mVrShell.pause();
         if (mNativeVrShellDelegate != 0) {
             VrShellDelegateJni.get().onPause(mNativeVrShellDelegate, VrShellDelegate.this);
@@ -1569,7 +1538,6 @@
     }
 
     private void onStart() {
-        mMaybeActivateAfterHeadsetInsertion = false;
         if (mDonSucceeded) setWindowModeForVr();
 
         // This handles the case where Chrome was paused in VR (ie the user navigated to DD home or
@@ -1658,47 +1626,10 @@
         return mIsDaydreamCurrentViewer;
     }
 
-    @CalledByNative
-    private void setListeningForWebVrActivate(boolean listening) {
-        if (VrDelegate.DEBUG_LOGS) {
-            Log.i(TAG, "WebVR page listening for vrdisplayactivate: " + listening);
-        }
-        // Non-Daydream devices do not have the concept of activation.
-        if (getVrSupportLevel() != VrSupportLevel.VR_DAYDREAM) return;
-        if (mListeningForWebVrActivate == listening) return;
-        mListeningForWebVrActivate = listening;
-        if (mListeningForWebVrActivate) {
-            registerDaydreamIntent(mActivity);
-            if (mNeedsAnimationCancel || mCancellingEntryAnimation) return;
-            if (mActivateFromHeadsetInsertion) {
-                // Dispatch vrdisplayactivate so that the WebVr page can call requestPresent
-                // to start presentation.
-                VrShellDelegateJni.get().displayActivate(
-                        mNativeVrShellDelegate, VrShellDelegate.this);
-                mActivateFromHeadsetInsertion = false;
-            }
-        } else {
-            if (!canEnterVr()) unregisterDaydreamIntent();
-            // When the active web page has a vrdisplayactivate event handler, and the phone is
-            // inserted into the headset, a vrdisplayactive event should be fired once DON flow
-            // is finished. However, the DON flow will pause our activity, which makes the active
-            // page lose focus and report that it can't handle displayActivate.
-            // Because of the order of onPause events running, we can't check for
-            // mListeningForWebVrActivate in onPause() as we may or may not already have lost focus.
-            // We need to remember that
-            mMaybeActivateAfterHeadsetInsertion = !mInVr && !mRequestedWebVr;
-            if (!mPaused) {
-                mClearMaybeActivateHandler.post(
-                        () -> { mMaybeActivateAfterHeadsetInsertion = false; });
-            }
-        }
-    }
-
     private void cancelPendingVrEntry() {
         if (VrDelegate.DEBUG_LOGS) Log.i(TAG, "cancelPendingVrEntry");
         VrModuleProvider.getDelegate().removeBlackOverlayView(mActivity, false /* animate */);
         mDonSucceeded = false;
-        mActivateFromHeadsetInsertion = false;
         maybeSetPresentResult(false);
         if (!mShowingDaydreamDoff) {
             setVrModeEnabled(mActivity, false);
@@ -1923,11 +1854,6 @@
     }
 
     @VisibleForTesting
-    protected boolean isListeningForWebVrActivate() {
-        return mListeningForWebVrActivate;
-    }
-
-    @VisibleForTesting
     protected boolean isVrEntryComplete() {
         return mInVr && !mProbablyInDon && getVrShell().hasUiFinishedLoading();
     }
@@ -1973,7 +1899,6 @@
         void onLibraryAvailable();
         void setPresentResult(long nativeVrShellDelegate, VrShellDelegate caller, boolean result);
         void recordVrStartAction(long nativeVrShellDelegate, int startAction);
-        void displayActivate(long nativeVrShellDelegate, VrShellDelegate caller);
         void onPause(long nativeVrShellDelegate, VrShellDelegate caller);
         void onResume(long nativeVrShellDelegate, VrShellDelegate caller);
         void destroy(long nativeVrShellDelegate, VrShellDelegate caller);
diff --git a/chrome/android/java/AndroidManifest.xml b/chrome/android/java/AndroidManifest.xml
index 3728cbf3..fd759c44 100644
--- a/chrome/android/java/AndroidManifest.xml
+++ b/chrome/android/java/AndroidManifest.xml
@@ -978,6 +978,16 @@
                 android:resource="@xml/file_paths" />
         </provider>
 
+        <!-- Sync adapter for browser invalidation. -->
+        <service android:name="org.chromium.chrome.browser.invalidation.ChromeBrowserSyncAdapterService"
+            android:exported="false">
+            <intent-filter>
+                <action android:name="android.content.SyncAdapter" />
+            </intent-filter>
+            <meta-data android:name="android.content.SyncAdapter"
+                       android:resource="@xml/syncadapter" />
+        </service>
+
         <!-- Broadcast receiver that will be notified of account changes -->
         <receiver android:name="org.chromium.chrome.browser.services.AccountsChangedReceiver">
             <intent-filter>
diff --git a/chrome/android/java/monochrome_public_bundle__base_bundle_module.AndroidManifest.expected b/chrome/android/java/monochrome_public_bundle__base_bundle_module.AndroidManifest.expected
index fc9c4544..a004f967 100644
--- a/chrome/android/java/monochrome_public_bundle__base_bundle_module.AndroidManifest.expected
+++ b/chrome/android/java/monochrome_public_bundle__base_bundle_module.AndroidManifest.expected
@@ -1554,6 +1554,14 @@
         android:name="org.chromium.chrome.browser.incognito.IncognitoNotificationService"/>
     <service
         android:exported="false"
+        android:name="org.chromium.chrome.browser.invalidation.ChromeBrowserSyncAdapterService">
+      <intent-filter>
+        <action android:name="android.content.SyncAdapter"/>
+      </intent-filter>
+      <meta-data android:name="android.content.SyncAdapter" android:resource="@xml/syncadapter"/>
+    </service>
+    <service
+        android:exported="false"
         android:name="org.chromium.chrome.browser.media.MediaCaptureNotificationService"/>
     <service
         android:exported="false"
diff --git a/chrome/android/java/res/layout/contacts_list_item_view.xml b/chrome/android/java/res/layout/contacts_list_item_view.xml
index c613b059..c65a178 100644
--- a/chrome/android/java/res/layout/contacts_list_item_view.xml
+++ b/chrome/android/java/res/layout/contacts_list_item_view.xml
@@ -14,6 +14,7 @@
         android:layout_width="0dp"
         android:layout_height="wrap_content"
         android:layout_weight="1"
+        android:layout_marginEnd="12dp"
         android:orientation="vertical"
         android:layout_gravity="center_vertical" >
 
@@ -26,14 +27,39 @@
             android:textAppearance="@style/TextAppearance.BlackTitle1" />
 
         <LinearLayout
-            android:layout_width="match_parent"
+            android:layout_width="wrap_content"
             android:layout_height="wrap_content"
-            android:orientation="horizontal" >
+            android:orientation="horizontal">
+
+            <TextView
+                android:id="@+id/address"
+                android:layout_width="0dp"
+                android:layout_height="wrap_content"
+                android:layout_weight="1"
+                android:maxLines="1"
+                android:ellipsize="end"
+                android:textAppearance="@style/TextAppearance.BlackBody" />
+
+            <TextView
+                android:id="@+id/address_overflow_count"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:paddingStart="4dp"
+                android:clickable="true"
+                android:maxLines="1"
+                android:textAppearance="@style/TextAppearance.BlueLink2" />
+        </LinearLayout>
+
+        <LinearLayout
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:orientation="horizontal">
 
             <TextView
                 android:id="@+id/email"
-                android:layout_width="wrap_content"
+                android:layout_width="0dp"
                 android:layout_height="wrap_content"
+                android:layout_weight="1"
                 android:maxLines="1"
                 android:ellipsize="end"
                 android:textAppearance="@style/TextAppearance.BlackBody" />
@@ -42,22 +68,22 @@
                 android:id="@+id/email_overflow_count"
                 android:layout_width="wrap_content"
                 android:layout_height="wrap_content"
+                android:paddingStart="4dp"
                 android:clickable="true"
                 android:maxLines="1"
-                android:paddingStart="4dp"
-                android:ellipsize="end"
-                android:textAppearance="@style/TextAppearance.ContactsPickerMoreDetails" />
+                android:textAppearance="@style/TextAppearance.BlueLink2" />
         </LinearLayout>
 
         <LinearLayout
-            android:layout_width="match_parent"
+            android:layout_width="wrap_content"
             android:layout_height="wrap_content"
             android:orientation="horizontal" >
 
             <TextView
                 android:id="@+id/telephone_number"
-                android:layout_width="wrap_content"
+                android:layout_width="0dp"
                 android:layout_height="wrap_content"
+                android:layout_weight="1"
                 android:maxLines="1"
                 android:ellipsize="end"
                 android:textAppearance="@style/TextAppearance.BlackBody" />
@@ -66,11 +92,10 @@
                 android:id="@+id/telephone_number_overflow_count"
                 android:layout_width="wrap_content"
                 android:layout_height="wrap_content"
+                android:paddingStart="4dp"
                 android:clickable="true"
                 android:maxLines="1"
-                android:paddingStart="4dp"
-                android:ellipsize="end"
-                android:textAppearance="@style/TextAppearance.ContactsPickerMoreDetails" />
+                android:textAppearance="@style/TextAppearance.BlueLink2" />
         </LinearLayout>
     </LinearLayout>
 
@@ -78,7 +103,7 @@
         android:id="@+id/star"
         android:layout_width="32dp"
         android:layout_height="32dp"
-        android:layout_marginEnd="20dp"
+        android:layout_marginEnd="10dp"
         android:src="@drawable/btn_star_filled"
         android:visibility="gone" />
 </merge>
diff --git a/chrome/android/java/res/layout/top_view.xml b/chrome/android/java/res/layout/top_view.xml
index ea425b3c..801176f 100644
--- a/chrome/android/java/res/layout/top_view.xml
+++ b/chrome/android/java/res/layout/top_view.xml
@@ -36,6 +36,13 @@
             style="@style/SuggestionChip" />
 
         <org.chromium.ui.widget.ChipView
+            android:id="@+id/address_filter"
+            android:gravity="center"
+            android:layout_height="wrap_content"
+            android:layout_width="wrap_content"
+            style="@style/SuggestionChip" />
+
+        <org.chromium.ui.widget.ChipView
             android:id="@+id/email_filter"
             android:gravity="center"
             android:layout_height="wrap_content"
diff --git a/chrome/android/java/res/values/styles.xml b/chrome/android/java/res/values/styles.xml
index 9a5624d..4b99217 100644
--- a/chrome/android/java/res/values/styles.xml
+++ b/chrome/android/java/res/values/styles.xml
@@ -758,9 +758,6 @@
         <item name="android:textColor">@color/default_text_color</item>
         <item name="android:textSize">@dimen/text_size_large</item>
     </style>
-    <style name="TextAppearance.ContactsPickerMoreDetails" parent="TextAppearance.BlackBody">
-        <item name="android:textColor">@color/default_text_color_link</item>
-    </style>
     <style name="TextAppearance.PageInfoPermissionSubtitle" parent="TextAppearance.BlackBody">
         <item name="android:textColor">@color/secondary_text_default_material_light</item>
     </style>
diff --git a/chrome/android/java/res_template/xml/syncadapter.xml b/chrome/android/java/res_template/xml/syncadapter.xml
new file mode 100644
index 0000000..e69dfa9
--- /dev/null
+++ b/chrome/android/java/res_template/xml/syncadapter.xml
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright 2015 The Chromium Authors. All rights reserved.
+     Use of this source code is governed by a BSD-style license that can be
+     found in the LICENSE file. -->
+
+<!-- The attributes in this XML file provide configuration information -->
+<!-- for the SyncAdapter. -->
+
+<sync-adapter xmlns:android="http://schemas.android.com/apk/res/android"
+    android:contentAuthority="{{manifest_package}}"
+    android:accountType="com.google" />
+
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/contacts_picker/ContactDetails.java b/chrome/android/java/src/org/chromium/chrome/browser/contacts_picker/ContactDetails.java
index edad68f..6068900b 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/contacts_picker/ContactDetails.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/contacts_picker/ContactDetails.java
@@ -34,6 +34,8 @@
         public String overflowEmailCount;
         public String primaryTelephoneNumber;
         public String overflowTelephoneNumberCount;
+        public String primaryAddress;
+        public String overflowAddressCount;
     }
 
     // The unique id for the contact.
@@ -151,16 +153,38 @@
         return displayChars;
     }
 
+    private String ensureSingleLine(String address) {
+        String returnValue = address.replaceAll("\n\n", "\n");
+        // The string might have multiple consecutive new-lines, which means \n\n\n -> \n\n, so
+        // we'll perform the conversion until we've caught them all.
+        while (returnValue.length() < address.length()) {
+            address = returnValue;
+            returnValue = address.replaceAll("\n\n", "\n");
+        }
+
+        return returnValue.replaceAll("\n", ", ");
+    }
+
     /**
      * Accessor for the list of contact details (emails and phone numbers). Returned as strings
      * separated by newline).
+     * @param includeAddresses Whether to include addresses in the returned results.
      * @param includeEmails Whether to include emails in the returned results.
      * @param includeTels Whether to include telephones in the returned results.
      * @return A string containing all the contact details registered for this contact.
      */
-    public String getContactDetailsAsString(boolean includeEmails, boolean includeTels) {
+    public String getContactDetailsAsString(
+            boolean includeAddresses, boolean includeEmails, boolean includeTels) {
         int count = 0;
         StringBuilder builder = new StringBuilder();
+        if (includeAddresses) {
+            for (PaymentAddress address : mAddresses) {
+                if (count++ > 0) {
+                    builder.append("\n");
+                }
+                builder.append(ensureSingleLine(address.addressLine[0]));
+            }
+        }
         if (includeEmails) {
             for (String email : mEmails) {
                 if (count++ > 0) {
@@ -183,15 +207,29 @@
 
     /**
      * Accessor for the list of contact details (emails and phone numbers).
+     * @param includeAddresses Whether to include addresses in the returned results.
      * @param includeEmails Whether to include emails in the returned results.
      * @param includeTels Whether to include telephones in the returned results.
      * @param resources The resources to use for fetching the string. Must be provided.
      * @return The contact details registered for this contact.
      */
-    public AbbreviatedContactDetails getAbbreviatedContactDetails(
+    public AbbreviatedContactDetails getAbbreviatedContactDetails(boolean includeAddresses,
             boolean includeEmails, boolean includeTels, @Nullable Resources resources) {
         AbbreviatedContactDetails results = new AbbreviatedContactDetails();
 
+        results.overflowAddressCount = "";
+        if (!includeAddresses || mAddresses.size() == 0) {
+            results.primaryAddress = "";
+        } else {
+            results.primaryAddress = ensureSingleLine(mAddresses.get(0).addressLine[0]);
+            int totalAddresses = mAddresses.size();
+            if (totalAddresses > 1) {
+                int hiddenAddresses = totalAddresses - 1;
+                results.overflowAddressCount = resources.getQuantityString(
+                        R.plurals.contacts_picker_more_details, hiddenAddresses, hiddenAddresses);
+            }
+        }
+
         results.overflowEmailCount = "";
         if (!includeEmails || mEmails.size() == 0) {
             results.primaryEmail = "";
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/contacts_picker/ContactView.java b/chrome/android/java/src/org/chromium/chrome/browser/contacts_picker/ContactView.java
index b901f393..0298678 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/contacts_picker/ContactView.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/contacts_picker/ContactView.java
@@ -45,6 +45,8 @@
     private TextView mDisplayName;
 
     // The contact details for the contact.
+    private TextView mAddress;
+    private TextView mAddressOverflowCount;
     private TextView mEmail;
     private TextView mEmailOverflowCount;
     private TextView mPhoneNumber;
@@ -74,12 +76,15 @@
         super.onFinishInflate();
 
         mDisplayName = findViewById(R.id.title);
+        mAddress = findViewById(R.id.address);
+        mAddressOverflowCount = findViewById(R.id.address_overflow_count);
         mEmail = findViewById(R.id.email);
         mEmailOverflowCount = findViewById(R.id.email_overflow_count);
         mPhoneNumber = findViewById(R.id.telephone_number);
         mPhoneNumberOverflowCount = findViewById(R.id.telephone_number_overflow_count);
         mStar = findViewById(R.id.star);
 
+        mAddressOverflowCount.setOnClickListener(this);
         mEmailOverflowCount.setOnClickListener(this);
         mPhoneNumberOverflowCount.setOnClickListener(this);
     }
@@ -87,7 +92,8 @@
     @Override
     public void onClick(View view) {
         int id = view.getId();
-        if (id == R.id.email_overflow_count || id == R.id.telephone_number_overflow_count) {
+        if (id == R.id.address_overflow_count || id == R.id.email_overflow_count
+                || id == R.id.telephone_number_overflow_count) {
             onLongClick(this);
         } else {
             super.onClick(view);
@@ -119,6 +125,7 @@
                          .with(ModalDialogProperties.TITLE, mContactDetails.getDisplayName())
                          .with(ModalDialogProperties.MESSAGE,
                                  mContactDetails.getContactDetailsAsString(
+                                         PickerAdapter.includesAddresses(),
                                          PickerAdapter.includesEmails(),
                                          PickerAdapter.includesTelephones()))
                          .with(ModalDialogProperties.POSITIVE_BUTTON_TEXT, mContext.getResources(),
@@ -176,10 +183,13 @@
 
         ContactDetails.AbbreviatedContactDetails details =
                 contactDetails.getAbbreviatedContactDetails(
+                        /*includeAddresses=*/PickerAdapter.includesAddresses(),
                         /*includeEmails=*/PickerAdapter.includesEmails(),
                         /*includeTels=*/PickerAdapter.includesTelephones(),
                         mContext.getResources());
 
+        updateTextViewVisibilityAndContent(mAddress, details.primaryAddress);
+        updateTextViewVisibilityAndContent(mAddressOverflowCount, details.overflowAddressCount);
         updateTextViewVisibilityAndContent(mEmail, details.primaryEmail);
         updateTextViewVisibilityAndContent(mEmailOverflowCount, details.overflowEmailCount);
         updateTextViewVisibilityAndContent(mPhoneNumber, details.primaryTelephoneNumber);
@@ -215,6 +225,8 @@
     private void resetTile() {
         setIconDrawable(null);
         mDisplayName.setText("");
+        mAddress.setText("");
+        mAddressOverflowCount.setText("");
         mEmail.setText("");
         mEmailOverflowCount.setText("");
         mPhoneNumber.setText("");
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/contacts_picker/PickerAdapter.java b/chrome/android/java/src/org/chromium/chrome/browser/contacts_picker/PickerAdapter.java
index fdfabbf..68eb2ef 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/contacts_picker/PickerAdapter.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/contacts_picker/PickerAdapter.java
@@ -65,11 +65,12 @@
      * The types of filters supported.
      */
     @Retention(RetentionPolicy.SOURCE)
-    @IntDef({FilterType.NAMES, FilterType.EMAILS, FilterType.TELEPHONES})
+    @IntDef({FilterType.NAMES, FilterType.EMAILS, FilterType.TELEPHONES, FilterType.ADDRESSES})
     public @interface FilterType {
         int NAMES = 0;
         int EMAILS = 1;
         int TELEPHONES = 2;
+        int ADDRESSES = 3;
     }
 
     /**
@@ -122,6 +123,9 @@
     // A list of search result indices into the larger data set.
     private ArrayList<Integer> mSearchResults;
 
+    // Whether to include addresses in the returned results.
+    private static boolean sIncludeAddresses;
+
     // Whether to include names in the returned results.
     private static boolean sIncludeNames;
 
@@ -148,6 +152,7 @@
         mCategoryView = categoryView;
         mContentResolver = context.getContentResolver();
         mFormattedOrigin = formattedOrigin;
+        sIncludeAddresses = true;
         sIncludeNames = true;
         sIncludeEmails = true;
         sIncludeTelephones = true;
@@ -188,7 +193,8 @@
             String query_lower = query.toLowerCase(Locale.getDefault());
             for (ContactDetails contact : mContactDetails) {
                 if (contact.getDisplayName().toLowerCase(Locale.getDefault()).contains(query_lower)
-                        || contact.getContactDetailsAsString(includesEmails(), includesTelephones())
+                        || contact.getContactDetailsAsString(includesAddresses(), includesEmails(),
+                                          includesTelephones())
                                    .toLowerCase(Locale.getDefault())
                                    .contains(query_lower)) {
                     mSearchResults.add(count);
@@ -277,7 +283,8 @@
                 mTopView.registerChipToggledCallback(this);
                 mTopView.updateCheckboxVisibility(mCategoryView.multiSelectionAllowed());
                 mTopView.updateChipVisibility(mCategoryView.includeNames,
-                        mCategoryView.includeEmails, mCategoryView.includeTel);
+                        mCategoryView.includeAddresses, mCategoryView.includeEmails,
+                        mCategoryView.includeTel);
                 mCategoryView.setTopView(mTopView);
                 if (mContactDetails != null) mTopView.updateContactCount(mContactDetails.size());
                 return new TopViewHolder(mTopView);
@@ -334,6 +341,9 @@
             case FilterType.NAMES:
                 sIncludeNames = !sIncludeNames;
                 break;
+            case FilterType.ADDRESSES:
+                sIncludeAddresses = !sIncludeAddresses;
+                break;
             case FilterType.EMAILS:
                 sIncludeEmails = !sIncludeEmails;
                 break;
@@ -348,6 +358,13 @@
     }
 
     /**
+     * Returns true unless the adapter is filtering out addresses.
+     */
+    public static boolean includesAddresses() {
+        return sIncludeAddresses;
+    }
+
+    /**
      * Returns true unless the adapter is filtering out names.
      */
     public static boolean includesNames() {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/contacts_picker/TopView.java b/chrome/android/java/src/org/chromium/chrome/browser/contacts_picker/TopView.java
index 291a284..b3979880 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/contacts_picker/TopView.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/contacts_picker/TopView.java
@@ -64,6 +64,9 @@
     // A Chip for filtering out names.
     private ChipView mNamesFilterChip;
 
+    // A Chip for filtering out addresses.
+    private ChipView mAddressFilterChip;
+
     // A Chip for filtering out emails.
     private ChipView mEmailFilterChip;
 
@@ -101,6 +104,12 @@
         mNamesFilterChip.setSelected(true);
         mNamesFilterChip.setOnClickListener(this);
 
+        mAddressFilterChip = findViewById(R.id.address_filter);
+        textView = mAddressFilterChip.getPrimaryTextView();
+        textView.setText(R.string.top_view_address_filter_label);
+        mAddressFilterChip.setSelected(true);
+        mAddressFilterChip.setOnClickListener(this);
+
         mEmailFilterChip = findViewById(R.id.email_filter);
         textView = mEmailFilterChip.getPrimaryTextView();
         textView.setText(R.string.top_view_email_filter_label);
@@ -119,6 +128,8 @@
         int id = view.getId();
         if (id == R.id.names_filter) {
             notifyChipToggled(PickerAdapter.FilterType.NAMES);
+        } else if (id == R.id.address_filter) {
+            notifyChipToggled(PickerAdapter.FilterType.ADDRESSES);
         } else if (id == R.id.email_filter) {
             notifyChipToggled(PickerAdapter.FilterType.EMAILS);
         } else if (id == R.id.tel_filter) {
@@ -137,6 +148,9 @@
             case PickerAdapter.FilterType.NAMES:
                 chipView = mNamesFilterChip;
                 break;
+            case PickerAdapter.FilterType.ADDRESSES:
+                chipView = mAddressFilterChip;
+                break;
             case PickerAdapter.FilterType.EMAILS:
                 chipView = mEmailFilterChip;
                 break;
@@ -194,12 +208,14 @@
     /**
      * Updates which chips should be displayed as part of the top view.
      * @param shouldDisplayNames Whether the names chip should be displayed.
+     * @param shouldDisplayAddresses Whether the addresses chip should be displayed.
      * @param shouldDisplayEmails Whether the emails chip should be displayed.
      * @param shouldDisplayTel Whether the telephone chip should be displayed.
      */
-    public void updateChipVisibility(
-            boolean shouldDisplayNames, boolean shouldDisplayEmails, boolean shouldDisplayTel) {
+    public void updateChipVisibility(boolean shouldDisplayNames, boolean shouldDisplayAddresses,
+            boolean shouldDisplayEmails, boolean shouldDisplayTel) {
         mNamesFilterChip.setVisibility(shouldDisplayNames ? View.VISIBLE : View.GONE);
+        mAddressFilterChip.setVisibility(shouldDisplayAddresses ? View.VISIBLE : View.GONE);
         mEmailFilterChip.setVisibility(shouldDisplayEmails ? View.VISIBLE : View.GONE);
         mTelephonesFilterChip.setVisibility(shouldDisplayTel ? View.VISIBLE : View.GONE);
     }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/invalidation/ChromeBrowserSyncAdapter.java b/chrome/android/java/src/org/chromium/chrome/browser/invalidation/ChromeBrowserSyncAdapter.java
new file mode 100644
index 0000000..1d40fcd
--- /dev/null
+++ b/chrome/android/java/src/org/chromium/chrome/browser/invalidation/ChromeBrowserSyncAdapter.java
@@ -0,0 +1,44 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.chrome.browser.invalidation;
+
+import android.accounts.Account;
+import android.content.AbstractThreadedSyncAdapter;
+import android.content.ContentProviderClient;
+import android.content.ContentResolver;
+import android.content.Context;
+import android.content.SyncResult;
+import android.os.Bundle;
+
+import org.chromium.components.signin.ChromeSigninController;
+
+/**
+ * A Sync adapter that integrates with Android's OS-level Sync settings.
+ */
+public class ChromeBrowserSyncAdapter extends AbstractThreadedSyncAdapter {
+    public ChromeBrowserSyncAdapter(Context context) {
+        super(context, false);
+    }
+
+    @Override
+    public void onPerformSync(Account account, Bundle extras, String authority,
+            ContentProviderClient provider, SyncResult syncResult) {
+        // Make sure to only report Chrome as "syncable" if the given account matches our
+        // signed-in account.
+        if (extras.getBoolean(ContentResolver.SYNC_EXTRAS_INITIALIZE)) {
+            Account signedInAccount = ChromeSigninController.get().getSignedInUser();
+            if (account.equals(signedInAccount)) {
+                ContentResolver.setIsSyncable(account, authority, 1);
+            } else {
+                ContentResolver.setIsSyncable(account, authority, 0);
+            }
+            return;
+        }
+
+        // Else: Nothing to do; we ignore explicit requests to perform a sync, since Chrome Sync
+        // knows when it should perform a sync. We could consider calling
+        // ProfileSyncService.triggerRefresh() to honor explicit requests.
+    }
+}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/invalidation/ChromeBrowserSyncAdapterService.java b/chrome/android/java/src/org/chromium/chrome/browser/invalidation/ChromeBrowserSyncAdapterService.java
new file mode 100644
index 0000000..1326932
--- /dev/null
+++ b/chrome/android/java/src/org/chromium/chrome/browser/invalidation/ChromeBrowserSyncAdapterService.java
@@ -0,0 +1,41 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.chrome.browser.invalidation;
+
+import android.annotation.SuppressLint;
+import android.app.Service;
+import android.content.Context;
+import android.content.Intent;
+import android.os.IBinder;
+
+import org.chromium.base.ContextUtils;
+import org.chromium.chrome.browser.init.ProcessInitializationHandler;
+
+/**
+ * A Service that provides access to {@link ChromeBrowserSyncAdapter}.
+ */
+public class ChromeBrowserSyncAdapterService extends Service {
+    @SuppressLint("StaticFieldLeak")
+    private static ChromeBrowserSyncAdapter sSyncAdapter;
+    private static final Object LOCK = new Object();
+
+    /**
+     * Get the sync adapter reference, creating an instance if necessary.
+     */
+    private ChromeBrowserSyncAdapter getOrCreateSyncAdapter(Context applicationContext) {
+        synchronized (LOCK) {
+            if (sSyncAdapter == null) {
+                ProcessInitializationHandler.getInstance().initializePreNative();
+                sSyncAdapter = new ChromeBrowserSyncAdapter(applicationContext);
+            }
+        }
+        return sSyncAdapter;
+    }
+
+    @Override
+    public IBinder onBind(Intent intent) {
+        return getOrCreateSyncAdapter(ContextUtils.getApplicationContext()).getSyncAdapterBinder();
+    }
+}
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/contacts_picker/ContactDetailsTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/contacts_picker/ContactDetailsTest.java
index 564c351..6219c8f 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/contacts_picker/ContactDetailsTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/contacts_picker/ContactDetailsTest.java
@@ -52,6 +52,8 @@
         Assert.assertEquals(expected.primaryTelephoneNumber, actual.primaryTelephoneNumber);
         Assert.assertEquals(
                 expected.overflowTelephoneNumberCount, actual.overflowTelephoneNumberCount);
+        Assert.assertEquals(expected.primaryAddress, actual.primaryAddress);
+        Assert.assertEquals(expected.overflowAddressCount, actual.overflowAddressCount);
     }
 
     @Test
@@ -117,11 +119,18 @@
         Assert.assertEquals(true, contact.isSelf());
         Assert.assertTrue(null != contact.getSelfIcon());
 
-        Assert.assertEquals("", contact.getContactDetailsAsString(false, false));
+        Assert.assertEquals("",
+                contact.getContactDetailsAsString(/*includeAddresses=*/false,
+                        /*includeEmails=*/false, /*includeTels=*/false));
         Assert.assertEquals("email@example.com\nemail2@example.com",
-                contact.getContactDetailsAsString(true, false));
-        Assert.assertEquals(
-                "555 123-4567\n555 765-4321", contact.getContactDetailsAsString(false, true));
+                contact.getContactDetailsAsString(
+                        /*includeAddresses=*/false, /*includeEmails=*/true, /*includeTels=*/false));
+        Assert.assertEquals("555 123-4567\n555 765-4321",
+                contact.getContactDetailsAsString(
+                        /*includeAddresses=*/false, /*includeEmails=*/false, /*includeTels=*/true));
+        Assert.assertEquals("formattedAddress1\nformattedAddress2",
+                contact.getContactDetailsAsString(
+                        /*includeAddresses=*/true, /*includeEmails=*/false, /*includeTels=*/false));
 
         Resources resources = mContext.getResources();
         ContactDetails.AbbreviatedContactDetails expected =
@@ -130,28 +139,98 @@
         expected.overflowEmailCount = "(+ 1 more)";
         expected.primaryTelephoneNumber = "555 123-4567";
         expected.overflowTelephoneNumberCount = "(+ 1 more)";
+        expected.primaryAddress = "formattedAddress1";
+        expected.overflowAddressCount = "(+ 1 more)";
 
         // Test with full details.
         ContactDetails.AbbreviatedContactDetails actual = contact.getAbbreviatedContactDetails(
-                /*includeEmails=*/true, /*includeTels=*/true, resources);
+                /*includeAddresses=*/true, /*includeEmails=*/true, /*includeTels=*/true, resources);
         compareAbbreviatedContactDetails(expected, actual);
+
         // Test with only email details.
         actual = contact.getAbbreviatedContactDetails(
-                /*includeEmails=*/true, /*includeTels=*/false, resources);
+                /*includeAddresses=*/false, /*includeEmails=*/true, /*includeTels=*/false,
+                resources);
         expected.primaryTelephoneNumber = "";
         expected.overflowTelephoneNumberCount = "";
+        expected.primaryAddress = "";
+        expected.overflowAddressCount = "";
         compareAbbreviatedContactDetails(expected, actual);
+
         // Test with no details.
         actual = contact.getAbbreviatedContactDetails(
-                /*includeEmails=*/false, /*includeTels=*/false, resources);
+                /*includeAddresses=*/false, /*includeEmails=*/false, /*includeTels=*/false,
+                resources);
         expected.primaryEmail = "";
         expected.overflowEmailCount = "";
         compareAbbreviatedContactDetails(expected, actual);
+
         // Test with only telephone details.
         actual = contact.getAbbreviatedContactDetails(
-                /*includeEmails=*/false, /*includeTels=*/true, resources);
+                /*includeAddresses=*/false, /*includeEmails=*/false, /*includeTels=*/true,
+                resources);
         expected.primaryTelephoneNumber = "555 123-4567";
         expected.overflowTelephoneNumberCount = "(+ 1 more)";
         compareAbbreviatedContactDetails(expected, actual);
+
+        // Test with only address details.
+        actual = contact.getAbbreviatedContactDetails(
+                /*includeAddresses=*/true, /*includeEmails=*/false, /*includeTels=*/false,
+                resources);
+        expected.primaryTelephoneNumber = "";
+        expected.overflowTelephoneNumberCount = "";
+        expected.primaryAddress = "formattedAddress1";
+        expected.overflowAddressCount = "(+ 1 more)";
+        compareAbbreviatedContactDetails(expected, actual);
+    }
+
+    @Test
+    @SmallTest
+    public void testEnsureSingleLine() {
+        PaymentAddress address = new PaymentAddress();
+        address.city = "city";
+        address.country = "country";
+        address.addressLine = new String[] {"Street\n\n\nCity\n\n\nCountry"};
+        address.postalCode = "postalCode";
+        address.region = "region";
+        address.dependentLocality = "";
+        address.sortingCode = "";
+        address.organization = "";
+        address.recipient = "";
+        address.phone = "";
+
+        Resources resources = mContext.getResources();
+
+        // Odd number of multiple consecutive new-lines.
+        ContactDetails contact =
+                new ContactDetails("id", "Display Name", null, null, Arrays.asList(address));
+        ContactDetails.AbbreviatedContactDetails abbreviated = contact.getAbbreviatedContactDetails(
+                /*includeAddresses=*/true, /*includeEmails=*/false, /*includeTels=*/false,
+                resources);
+        Assert.assertEquals("Street, City, Country", abbreviated.primaryAddress);
+
+        // Even number of multiple consecutive new-lines.
+        address.addressLine = new String[] {"Street\n\n\n\nCity\n\n\n\nCountry"};
+        contact = new ContactDetails("id", "Display Name", null, null, Arrays.asList(address));
+        abbreviated = contact.getAbbreviatedContactDetails(
+                /*includeAddresses=*/true, /*includeEmails=*/false, /*includeTels=*/false,
+                resources);
+        Assert.assertEquals("Street, City, Country", abbreviated.primaryAddress);
+
+        // New lines included, but none consecutive.
+        address.addressLine = new String[] {"Street\nCity\nCountry"};
+        contact = new ContactDetails("id", "Display Name", null, null, Arrays.asList(address));
+        abbreviated = contact.getAbbreviatedContactDetails(
+                /*includeAddresses=*/true, /*includeEmails=*/false, /*includeTels=*/false,
+                resources);
+        Assert.assertEquals("Street, City, Country", abbreviated.primaryAddress);
+
+        // No new-lines.
+        address.addressLine = new String[] {"Street City Country"};
+        contact = new ContactDetails("id", "Display Name", null, null, Arrays.asList(address));
+        abbreviated = contact.getAbbreviatedContactDetails(
+                /*includeAddresses=*/true, /*includeEmails=*/false, /*includeTels=*/false,
+                resources);
+        Assert.assertEquals("Street City Country", abbreviated.primaryAddress);
     }
 }
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/contacts_picker/ContactsPickerDialogTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/contacts_picker/ContactsPickerDialogTest.java
index 878eab79..7fc5bb78 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/contacts_picker/ContactsPickerDialogTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/contacts_picker/ContactsPickerDialogTest.java
@@ -361,13 +361,45 @@
         Assert.assertNotNull(emailFilter);
         View telFilter = topView.findViewById(R.id.tel_filter);
         Assert.assertNotNull(telFilter);
+        View addrFilter = topView.findViewById(R.id.address_filter);
+        Assert.assertNotNull(addrFilter);
 
         // Per configuration given in the createDialog() call, the names and telephone filters
-        // should be visible, but the e-mail filter should be gone.
+        // should be visible, but the e-mail and address filter should be gone.
         Assert.assertEquals(namesFilter.getVisibility(), View.VISIBLE);
         Assert.assertEquals(emailFilter.getVisibility(), View.GONE);
         Assert.assertEquals(telFilter.getVisibility(), View.VISIBLE);
-        // TODO(crbug.com/1016870): Add a false test for the filter chip, when added.
+        Assert.assertEquals(addrFilter.getVisibility(), View.GONE);
+    }
+
+    @Test
+    @LargeTest
+    public void testFilterVisibilityReverseForDataInclusion() throws Throwable {
+        setTestContacts(/*ownerEmail=*/null);
+        createDialog(/* multiselect = */ false, /* includeNames = */ false,
+                /* includeEmails = */ true,
+                /* includeTel = */ false,
+                /* includeAddresses = */ true);
+        Assert.assertTrue(mDialog.isShowing());
+
+        TopView topView = getTopView();
+        Assert.assertNotNull(topView);
+
+        View namesFilter = topView.findViewById(R.id.names_filter);
+        Assert.assertNotNull(namesFilter);
+        View emailFilter = topView.findViewById(R.id.email_filter);
+        Assert.assertNotNull(emailFilter);
+        View telFilter = topView.findViewById(R.id.tel_filter);
+        Assert.assertNotNull(telFilter);
+        View addrFilter = topView.findViewById(R.id.address_filter);
+        Assert.assertNotNull(addrFilter);
+
+        // Per configuration given in the createDialog() call, the names and telephone filters
+        // should be hidden, but the e-mail and address filter should be visible.
+        Assert.assertEquals(namesFilter.getVisibility(), View.GONE);
+        Assert.assertEquals(emailFilter.getVisibility(), View.VISIBLE);
+        Assert.assertEquals(telFilter.getVisibility(), View.GONE);
+        Assert.assertEquals(addrFilter.getVisibility(), View.VISIBLE);
     }
 
     @Test
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/vr/TestVrShellDelegate.java b/chrome/android/javatests/src/org/chromium/chrome/browser/vr/TestVrShellDelegate.java
index abdf035..db453ab7 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/vr/TestVrShellDelegate.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/vr/TestVrShellDelegate.java
@@ -83,11 +83,6 @@
     }
 
     @Override
-    public boolean isListeningForWebVrActivate() {
-        return super.isListeningForWebVrActivate();
-    }
-
-    @Override
     public boolean isVrEntryComplete() {
         return super.isVrEntryComplete();
     }
@@ -191,4 +186,4 @@
     public void setAllow2dIntents(boolean allow) {
         mAllow2dIntents = allow;
     }
-}
\ No newline at end of file
+}
diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc
index 69807cd..487508e 100644
--- a/chrome/browser/about_flags.cc
+++ b/chrome/browser/about_flags.cc
@@ -4134,6 +4134,11 @@
      flag_descriptions::kMediaSessionNotificationsDescription, kOsCrOS,
      FEATURE_VALUE_TYPE(ash::features::kMediaSessionNotification)},
 
+    {"enable-neural-stylus-palm-rejection",
+     flag_descriptions::kEnableNeuralStylusPalmRejectionName,
+     flag_descriptions::kEnableNeuralStylusPalmRejectionDescription, kOsCrOS,
+     FEATURE_VALUE_TYPE(ui::kEnableNeuralPalmDetectionFilter)},
+
     {"enable-heuristic-stylus-palm-rejection",
      flag_descriptions::kEnableHeuristicStylusPalmRejectionName,
      flag_descriptions::kEnableHeuristicStylusPalmRejectionDescription, kOsCrOS,
diff --git a/chrome/browser/android/vr/arcore_device/arcore_gl.cc b/chrome/browser/android/vr/arcore_device/arcore_gl.cc
index 7ee8cae..399a807 100644
--- a/chrome/browser/android/vr/arcore_device/arcore_gl.cc
+++ b/chrome/browser/android/vr/arcore_device/arcore_gl.cc
@@ -413,15 +413,14 @@
     frame_data->detected_planes_data = arcore_->GetDetectedPlanesData();
   }
 
-  frame_data->anchors_data = arcore_->GetAnchorsData();
-
   fps_meter_.AddFrame(base::TimeTicks::Now());
   TRACE_COUNTER1("gpu", "WebXR FPS", fps_meter_.GetFPS());
 
   // Post a task to finish processing the frame so any calls to
   // RequestHitTest() that were made during this function, which can block
   // on the arcore_->Update() call above, can be processed in this frame.
-  // Additionally, this gives a chance for OnScreenTouch() tasks to run.
+  // Additionally, this gives a chance for OnScreenTouch() tasks to run
+  // and added anchors to be registered.
   gl_thread_task_runner_->PostTask(
       FROM_HERE,
       base::BindOnce(&ArCoreGl::ProcessFrame, weak_ptr_factory_.GetWeakPtr(),
@@ -767,6 +766,9 @@
         arcore_->GetHitTestSubscriptionResults(frame_data->pose);
   }
 
+  // Get anchors data, including anchors created this frame.
+  frame_data->anchors_data = arcore_->GetAnchorsData();
+
   // The timing requirements for hit-test are documented here:
   // https://github.com/immersive-web/hit-test/blob/master/explainer.md#timing
   // The current implementation of frame generation on the renderer side is
diff --git a/chrome/browser/android/vr/vr_shell_delegate.cc b/chrome/browser/android/vr/vr_shell_delegate.cc
index 6f7824a..18a386f4 100644
--- a/chrome/browser/android/vr/vr_shell_delegate.cc
+++ b/chrome/browser/android/vr/vr_shell_delegate.cc
@@ -211,23 +211,6 @@
   std::move(request_present_response_callback_).Run(std::move(session));
 }
 
-void VrShellDelegate::DisplayActivate(JNIEnv* env,
-                                      const JavaParamRef<jobject>& obj) {
-  device::GvrDevice* gvr_device = GetGvrDevice();
-  if (gvr_device) {
-    // The only possible source for DisplayActivate is HeadsetActivation.
-    possible_presentation_start_action_ =
-        PresentationStartAction::kHeadsetActivation;
-
-    gvr_device->Activate(
-        device::mojom::VRDisplayEventReason::MOUNTED,
-        base::BindRepeating(&VrShellDelegate::OnActivateDisplayHandled,
-                            weak_ptr_factory_.GetWeakPtr()));
-  } else {
-    OnActivateDisplayHandled(true /* will_not_present */);
-  }
-}
-
 void VrShellDelegate::OnPause(JNIEnv* env, const JavaParamRef<jobject>& obj) {
   if (vr_shell_)
     return;
@@ -289,22 +272,6 @@
       Java_VrShellDelegate_getVrCoreInfo(env, j_vr_shell_delegate_)));
 }
 
-void VrShellDelegate::OnActivateDisplayHandled(bool will_not_present) {
-  if (will_not_present) {
-    // WebVR page didn't request presentation in the vrdisplayactivate handler.
-    // Tell VrShell that we are in VR Browsing Mode.
-    ExitWebVRPresent();
-    // Reset possible_presentation_start_action_ as it may have been set.
-    possible_presentation_start_action_ = base::nullopt;
-  }
-}
-
-void VrShellDelegate::OnListeningForActivateChanged(bool listening) {
-  JNIEnv* env = AttachCurrentThread();
-  Java_VrShellDelegate_setListeningForWebVrActivate(env, j_vr_shell_delegate_,
-                                                    listening);
-}
-
 void VrShellDelegate::OnRuntimeAdded(vr::BrowserXRRuntime* runtime) {
   if (vr_shell_) {
     // See comment in VrShellDelegate::SetDelegate. This handles the case where
diff --git a/chrome/browser/android/vr/vr_shell_delegate.h b/chrome/browser/android/vr/vr_shell_delegate.h
index 55b2e9a5f..23c26fa 100644
--- a/chrome/browser/android/vr/vr_shell_delegate.h
+++ b/chrome/browser/android/vr/vr_shell_delegate.h
@@ -59,8 +59,6 @@
                         jboolean success);
   void RecordVrStartAction(JNIEnv* env,
                            jint start_action);
-  void DisplayActivate(JNIEnv* env,
-                       const base::android::JavaParamRef<jobject>& obj);
   void OnPause(JNIEnv* env, const base::android::JavaParamRef<jobject>& obj);
   void OnResume(JNIEnv* env, const base::android::JavaParamRef<jobject>& obj);
   bool IsClearActivatePending(JNIEnv* env,
@@ -81,7 +79,6 @@
       device::mojom::VRDisplayInfoPtr display_info,
       device::mojom::XRRuntimeSessionOptionsPtr options,
       base::OnceCallback<void(device::mojom::XRSessionPtr)> callback) override;
-  void OnListeningForActivateChanged(bool listening) override;
 
   // vr::XRRuntimeManagerObserver implementation.
   // VrShellDelegate implements XRRuntimeManagerObserver to turn off poses (by
@@ -91,9 +88,6 @@
   // VrShell got created, their poses will be turned off too on its
   // creation.
   void OnRuntimeAdded(vr::BrowserXRRuntime* runtime) override;
-
-  void OnActivateDisplayHandled(bool will_not_present);
-  void SetListeningForActivate(bool listening);
   void OnPresentResult(
       device::mojom::VRDisplayInfoPtr display_info,
       device::mojom::XRRuntimeSessionOptionsPtr options,
diff --git a/chrome/browser/apps/guest_view/web_view_interactive_browsertest.cc b/chrome/browser/apps/guest_view/web_view_interactive_browsertest.cc
index cecdbeb..e0d7db6 100644
--- a/chrome/browser/apps/guest_view/web_view_interactive_browsertest.cc
+++ b/chrome/browser/apps/guest_view/web_view_interactive_browsertest.cc
@@ -1451,7 +1451,7 @@
     ui::CompositionText composition;
     composition.text = base::UTF8ToUTF16("InputTest456");
     text_input_client->SetCompositionText(composition);
-    text_input_client->ConfirmCompositionText();
+    text_input_client->ConfirmCompositionText(/* keep_selection */ false);
     EXPECT_TRUE(content::ExecuteScript(
                   embedder_web_contents,
                   "window.runCommand('testInputMethodRunNextStep', 2);"));
diff --git a/chrome/browser/apps/intent_helper/intent_picker_auto_display_pref.cc b/chrome/browser/apps/intent_helper/intent_picker_auto_display_pref.cc
index 4d4be30..91c47897 100644
--- a/chrome/browser/apps/intent_helper/intent_picker_auto_display_pref.cc
+++ b/chrome/browser/apps/intent_helper/intent_picker_auto_display_pref.cc
@@ -17,6 +17,7 @@
 constexpr int kDismissThreshold = 2;
 
 constexpr char kAutoDisplayKey[] = "picker_auto_display_key";
+constexpr char kPlatformKey[] = "picker_platform_key";
 
 // Retrieves or creates a new dictionary for the specific |origin|.
 std::unique_ptr<base::DictionaryValue> GetAutoDisplayDictForSettings(
@@ -60,11 +61,28 @@
   return ui_dismissed_counter_ < kDismissThreshold;
 }
 
+IntentPickerAutoDisplayPref::Platform
+IntentPickerAutoDisplayPref::GetPlatform() {
+  return platform_;
+}
+
+void IntentPickerAutoDisplayPref::UpdatePlatform(Platform platform) {
+  if (!pref_dict_)
+    return;
+
+  DCHECK_GE(static_cast<int>(platform), static_cast<int>(Platform::kNone));
+  DCHECK_LE(static_cast<int>(platform), static_cast<int>(Platform::kMaxValue));
+  platform_ = platform;
+  pref_dict_->SetInteger(kPlatformKey, static_cast<int>(platform_));
+  Commit();
+}
+
 IntentPickerAutoDisplayPref::IntentPickerAutoDisplayPref(
     const GURL& origin,
     std::unique_ptr<base::DictionaryValue> pref_dict)
     : origin_(origin), pref_dict_(pref_dict.release()) {
   ui_dismissed_counter_ = QueryDismissedCounter();
+  platform_ = QueryPlatform();
 }
 
 int IntentPickerAutoDisplayPref::QueryDismissedCounter() {
@@ -73,6 +91,8 @@
 
   int counter = 0;
   pref_dict_->GetInteger(kAutoDisplayKey, &counter);
+  DCHECK_GE(counter, static_cast<int>(Platform::kNone));
+  DCHECK_LE(counter, static_cast<int>(Platform::kMaxValue));
 
   return counter;
 }
@@ -87,6 +107,19 @@
   pref_dict_->SetInteger(kAutoDisplayKey, ui_dismissed_counter_);
 }
 
+IntentPickerAutoDisplayPref::Platform
+IntentPickerAutoDisplayPref::QueryPlatform() {
+  if (!pref_dict_)
+    return Platform::kNone;
+
+  int platform = 0;
+  pref_dict_->GetInteger(kPlatformKey, &platform);
+  DCHECK_GE(platform, static_cast<int>(Platform::kNone));
+  DCHECK_LT(platform, static_cast<int>(Platform::kMaxValue));
+
+  return static_cast<Platform>(platform);
+}
+
 void IntentPickerAutoDisplayPref::Commit() {
   settings_map_->SetWebsiteSettingDefaultScope(
       origin_, origin_, ContentSettingsType::INTENT_PICKER_DISPLAY,
diff --git a/chrome/browser/apps/intent_helper/intent_picker_auto_display_pref.h b/chrome/browser/apps/intent_helper/intent_picker_auto_display_pref.h
index bdebc09a..319c9df 100644
--- a/chrome/browser/apps/intent_helper/intent_picker_auto_display_pref.h
+++ b/chrome/browser/apps/intent_helper/intent_picker_auto_display_pref.h
@@ -17,6 +17,10 @@
 // UI for a given origin.
 class IntentPickerAutoDisplayPref final {
  public:
+  // The platform selected by the user to handle this URL for devices of tablet
+  // form factor.
+  enum class Platform { kNone = 0, kArc = 1, kChrome = 2, kMaxValue = kChrome };
+
   IntentPickerAutoDisplayPref(const GURL& origin,
                               HostContentSettingsMap* settings);
   ~IntentPickerAutoDisplayPref();
@@ -25,6 +29,10 @@
 
   bool HasExceededThreshold();
 
+  Platform GetPlatform();
+
+  void UpdatePlatform(Platform platform);
+
  private:
   // Creates and keep track of the dictionary for this specific origin.
   IntentPickerAutoDisplayPref(const GURL& origin,
@@ -34,6 +42,8 @@
 
   void SetDismissedCounter(int new_counter);
 
+  Platform QueryPlatform();
+
   void Commit();
 
   // Origin associated to this preference.
@@ -41,6 +51,10 @@
 
   int ui_dismissed_counter_;
 
+  // The platform selected by the user to handle link navigations with.
+  // This is only for devices of tablet form factor.
+  Platform platform_;
+
   // Dictionary for this particular preference.
   std::unique_ptr<base::DictionaryValue> pref_dict_;
 
diff --git a/chrome/browser/apps/intent_helper/intent_picker_auto_display_service.cc b/chrome/browser/apps/intent_helper/intent_picker_auto_display_service.cc
index 632806e..d57ade46 100644
--- a/chrome/browser/apps/intent_helper/intent_picker_auto_display_service.cc
+++ b/chrome/browser/apps/intent_helper/intent_picker_auto_display_service.cc
@@ -6,7 +6,6 @@
 
 #include <memory>
 
-#include "chrome/browser/apps/intent_helper/intent_picker_auto_display_pref.h"
 #include "chrome/browser/apps/intent_helper/intent_picker_auto_display_service_factory.h"
 #include "chrome/browser/content_settings/host_content_settings_map_factory.h"
 
@@ -41,3 +40,14 @@
 void IntentPickerAutoDisplayService::IncrementCounter(const GURL& url) {
   CreateLocalPreference(profile_, url)->IncrementCounter();
 }
+
+IntentPickerAutoDisplayPref::Platform
+IntentPickerAutoDisplayService::GetLastUsedPlatformForTablets(const GURL& url) {
+  return CreateLocalPreference(profile_, url)->GetPlatform();
+}
+
+void IntentPickerAutoDisplayService::UpdatePlatformForTablets(
+    const GURL& url,
+    IntentPickerAutoDisplayPref::Platform platform) {
+  CreateLocalPreference(profile_, url)->UpdatePlatform(platform);
+}
diff --git a/chrome/browser/apps/intent_helper/intent_picker_auto_display_service.h b/chrome/browser/apps/intent_helper/intent_picker_auto_display_service.h
index 4070c14..a198cc2 100644
--- a/chrome/browser/apps/intent_helper/intent_picker_auto_display_service.h
+++ b/chrome/browser/apps/intent_helper/intent_picker_auto_display_service.h
@@ -6,6 +6,7 @@
 #define CHROME_BROWSER_APPS_INTENT_HELPER_INTENT_PICKER_AUTO_DISPLAY_SERVICE_H_
 
 #include "base/macros.h"
+#include "chrome/browser/apps/intent_helper/intent_picker_auto_display_pref.h"
 #include "components/keyed_service/core/keyed_service.h"
 #include "url/gurl.h"
 
@@ -28,6 +29,17 @@
   // Keep track of the |url| repetitions.
   void IncrementCounter(const GURL& url);
 
+  // Returns the last platform selected by the user to handle |url|.
+  // If it has not been checked then it will return |Platform::kNone|
+  // for devices of tablet form factor.
+  IntentPickerAutoDisplayPref::Platform GetLastUsedPlatformForTablets(
+      const GURL& url);
+
+  // Updates the Platform to |platform| for |url| for devices of
+  // tablet form factor.
+  void UpdatePlatformForTablets(const GURL& url,
+                                IntentPickerAutoDisplayPref::Platform platform);
+
  private:
   Profile* profile_;
 
diff --git a/chrome/browser/browsing_data/chrome_browsing_data_remover_delegate.cc b/chrome/browser/browsing_data/chrome_browsing_data_remover_delegate.cc
index 74335c50..cd3a18c 100644
--- a/chrome/browser/browsing_data/chrome_browsing_data_remover_delegate.cc
+++ b/chrome/browser/browsing_data/chrome_browsing_data_remover_delegate.cc
@@ -865,6 +865,9 @@
       password_store->RemoveLeakedCredentialsByUrlAndTime(
           nullable_filter, delete_begin_, delete_end_,
           CreateTaskCompletionClosure(TracingDataType::kLeakedCredentials));
+      password_store->RemoveFieldInfoByTime(
+          delete_begin_, delete_end_,
+          CreateTaskCompletionClosure(TracingDataType::kFieldInfo));
     }
   }
 
diff --git a/chrome/browser/browsing_data/chrome_browsing_data_remover_delegate.h b/chrome/browser/browsing_data/chrome_browsing_data_remover_delegate.h
index 56a73802..ae53976 100644
--- a/chrome/browser/browsing_data/chrome_browsing_data_remover_delegate.h
+++ b/chrome/browser/browsing_data/chrome_browsing_data_remover_delegate.h
@@ -227,7 +227,8 @@
     kTpmAttestationKeys = 30,
     kStrikes = 31,
     kLeakedCredentials = 32,
-    kMaxValue = kLeakedCredentials,
+    kFieldInfo = 33,
+    kMaxValue = kFieldInfo,
   };
 
   // Called by CreateTaskCompletionClosure().
diff --git a/chrome/browser/chrome_content_browser_client.cc b/chrome/browser/chrome_content_browser_client.cc
index 737ae4e..8dc95a1 100644
--- a/chrome/browser/chrome_content_browser_client.cc
+++ b/chrome/browser/chrome_content_browser_client.cc
@@ -3655,6 +3655,23 @@
                                                      render_frame_host);
 }
 
+#if defined(OS_WIN) || defined(OS_MACOSX) || \
+    (defined(OS_LINUX) && !defined(OS_CHROMEOS))
+bool ShouldEnableAudioSandbox(const policy::PolicyMap& policies) {
+  const base::Value* audio_sandbox_enabled_policy_value =
+      policies.GetValue(policy::key::kAudioSandboxEnabled);
+  if (audio_sandbox_enabled_policy_value) {
+    bool force_enable_audio_sandbox;
+    audio_sandbox_enabled_policy_value->GetAsBoolean(
+        &force_enable_audio_sandbox);
+    return force_enable_audio_sandbox;
+  }
+
+  return base::FeatureList::IsEnabled(
+      service_manager::features::kAudioServiceSandbox);
+}
+#endif
+
 void ChromeContentBrowserClient::WillStartServiceManager() {
 #if defined(OS_WIN) || defined(OS_MACOSX) || \
     (defined(OS_LINUX) && !defined(OS_CHROMEOS))
@@ -3679,14 +3696,9 @@
 #endif
     bool enable_audio_process =
         base::FeatureList::IsEnabled(features::kAudioServiceOutOfProcess);
-    bool enable_audio_sandbox = base::FeatureList::IsEnabled(
-        service_manager::features::kAudioServiceSandbox);
-    const base::Value* audio_sandbox_enabled_policy_value =
-        policies.GetValue(policy::key::kAudioSandboxEnabled);
-    if (audio_sandbox_enabled_policy_value)
-      audio_sandbox_enabled_policy_value->GetAsBoolean(&enable_audio_sandbox);
-    service_manager::EnableAudioSandbox(enable_audio_sandbox);
-    if (!enable_audio_sandbox || !enable_audio_process) {
+
+    service_manager::EnableAudioSandbox(ShouldEnableAudioSandbox(policies));
+    if (!service_manager::IsAudioSandboxEnabled() || !enable_audio_process) {
       // Disabling the audio process or audio sandbox implies disabling APM in
       // the audio service for security reasons. Append a switch so that this
       // is communicated to the audio and renderer processes.
diff --git a/chrome/browser/chromeos/BUILD.gn b/chrome/browser/chromeos/BUILD.gn
index 7e6d1fb..8e200cf 100644
--- a/chrome/browser/chromeos/BUILD.gn
+++ b/chrome/browser/chromeos/BUILD.gn
@@ -2337,7 +2337,7 @@
   }
 }
 
-copy("dbus_service_files") {
+action("dbus_service_files") {
   sources = [
     "dbus/org.chromium.ChromeFeaturesService.conf",
     "dbus/org.chromium.ComponentUpdaterService.conf",
@@ -2353,9 +2353,14 @@
     "dbus/org.chromium.VirtualFileRequestService.conf",
     "dbus/org.chromium.VmApplicationsService.conf",
   ]
+  output_conf_file = "$root_out_dir/dbus/chrome_dbus_services.conf"
   outputs = [
-    "$root_out_dir/dbus/{{source_file_part}}",
+    output_conf_file,
   ]
+
+  script = "//chromeos/tools/concat_dbus_conf_files.py"
+  args = [ rebase_path(output_conf_file, root_build_dir) ]
+  args += rebase_path(sources, root_build_dir)
 }
 
 static_library("arc_test_support") {
@@ -2930,32 +2935,13 @@
     "../ui/webui/settings/chromeos/device_keyboard_handler_unittest.cc",
     "../ui/webui/settings/chromeos/internet_handler_unittest.cc",
     "../ui/webui/settings/chromeos/multidevice_handler_unittest.cc",
-    "//components/drive/about_resource_loader_unittest.cc",
-    "//components/drive/change_list_loader_unittest.cc",
     "//components/drive/change_list_processor_unittest.cc",
     "//components/drive/chromeos/file_cache_unittest.cc",
-    "//components/drive/directory_loader_unittest.cc",
     "//components/drive/drive_file_util_unittest.cc",
     "//components/drive/drive_notification_manager_unittest.cc",
     "//components/drive/drive_operation_queue_unittest.cc",
-    "//components/drive/fake_file_system_unittest.cc",
     "//components/drive/file_change_unittest.cc",
-    "//components/drive/file_system/copy_operation_unittest.cc",
-    "//components/drive/file_system/create_directory_operation_unittest.cc",
-    "//components/drive/file_system/create_file_operation_unittest.cc",
-    "//components/drive/file_system/download_operation_unittest.cc",
-    "//components/drive/file_system/get_file_for_saving_operation_unittest.cc",
-    "//components/drive/file_system/move_operation_unittest.cc",
-    "//components/drive/file_system/open_file_operation_unittest.cc",
-    "//components/drive/file_system/operation_test_base.cc",
-    "//components/drive/file_system/operation_test_base.h",
-    "//components/drive/file_system/remove_operation_unittest.cc",
-    "//components/drive/file_system/search_operation_unittest.cc",
-    "//components/drive/file_system/set_property_operation_unittest.cc",
-    "//components/drive/file_system/touch_operation_unittest.cc",
-    "//components/drive/file_system/truncate_operation_unittest.cc",
     "//components/drive/file_system_core_util_unittest.cc",
-    "//components/drive/file_system_unittest.cc",
     "//components/drive/file_write_watcher_unittest.cc",
     "//components/drive/job_queue_unittest.cc",
     "//components/drive/job_scheduler_unittest.cc",
@@ -2965,13 +2951,6 @@
     "//components/drive/resource_metadata_storage_unittest.cc",
     "//components/drive/resource_metadata_unittest.cc",
     "//components/drive/search_metadata_unittest.cc",
-    "//components/drive/start_page_token_loader_unittest.cc",
-    "//components/drive/sync/entry_revert_performer_unittest.cc",
-    "//components/drive/sync/entry_update_performer_unittest.cc",
-    "//components/drive/sync/remove_performer_unittest.cc",
-    "//components/drive/sync_client_unittest.cc",
-    "//components/drive/team_drive_change_list_loader_unittest.cc",
-    "//components/drive/team_drive_list_loader_unittest.cc",
   ]
 
   public_deps = [
diff --git a/chrome/browser/chromeos/apps/intent_helper/chromeos_apps_navigation_throttle.cc b/chrome/browser/chromeos/apps/intent_helper/chromeos_apps_navigation_throttle.cc
index be1516b..97bfc26 100644
--- a/chrome/browser/chromeos/apps/intent_helper/chromeos_apps_navigation_throttle.cc
+++ b/chrome/browser/chromeos/apps/intent_helper/chromeos_apps_navigation_throttle.cc
@@ -18,6 +18,7 @@
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/browser_finder.h"
 #include "chrome/browser/ui/browser_window.h"
+#include "chromeos/constants/chromeos_switches.h"
 #include "components/arc/intent_helper/arc_intent_helper_bridge.h"
 #include "components/arc/metrics/arc_metrics_constants.h"
 #include "content/public/browser/browser_context.h"
@@ -66,6 +67,21 @@
     apps::PickerEntryType entry_type,
     apps::IntentPickerCloseReason close_reason,
     bool should_persist) {
+  if (chromeos::switches::IsTabletFormFactor() && should_persist) {
+    // On devices of tablet form factor, until the user has decided to persist
+    // the setting, the browser-side intent picker should always be seen.
+    auto platform = IntentPickerAutoDisplayPref::Platform::kNone;
+    if (entry_type == apps::PickerEntryType::kArc) {
+      platform = IntentPickerAutoDisplayPref::Platform::kArc;
+    } else if (entry_type == apps::PickerEntryType::kUnknown &&
+               close_reason == apps::IntentPickerCloseReason::STAY_IN_CHROME) {
+      platform = IntentPickerAutoDisplayPref::Platform::kChrome;
+    }
+    IntentPickerAutoDisplayService::Get(
+        Profile::FromBrowserContext(web_contents->GetBrowserContext()))
+        ->UpdatePlatformForTablets(url, platform);
+  }
+
   const bool should_launch_app =
       close_reason == apps::IntentPickerCloseReason::OPEN_APP;
   switch (entry_type) {
@@ -217,14 +233,17 @@
 bool ChromeOsAppsNavigationThrottle::ShouldDeferNavigationForArc(
     content::NavigationHandle* handle) {
   // Query for ARC apps, and if we are handling a link navigation, allow the
-  // preferred app (if it exists) to be launched.
+  // preferred app (if it exists) to be launched unless we are on a device
+  // of tablet form factor, which will only launch the app if the user has
+  // explicitly set that app as preferred and persisted that setting via the
+  // intent picker previously.
   if (arc_enabled_ &&
       arc::ArcIntentPickerAppFetcher::WillGetArcAppsForNavigation(
           handle,
           base::BindOnce(
               &ChromeOsAppsNavigationThrottle::OnDeferredNavigationProcessed,
               weak_factory_.GetWeakPtr()),
-          /*should_launch_preferred_app=*/navigate_from_link())) {
+          ShouldLaunchPreferredApp(handle->GetURL()))) {
     return true;
   }
   return false;
@@ -260,6 +279,14 @@
     const std::vector<apps::IntentPickerAppInfo>& apps_for_picker,
     content::WebContents* web_contents,
     const GURL& url) {
+  // On devices with tablet form factor we should not pop out the intent
+  // picker if Chrome has been chosen by the user as the platform for this URL.
+  if (chromeos::switches::IsTabletFormFactor()) {
+    if (ui_auto_display_service_->GetLastUsedPlatformForTablets(url) ==
+        IntentPickerAutoDisplayPref::Platform::kChrome) {
+      return PickerShowState::kOmnibox;
+    }
+  }
   return ShouldAutoDisplayUi(apps_for_picker, web_contents, url) &&
                  navigate_from_link()
              ? PickerShowState::kPopOut
@@ -299,4 +326,18 @@
   DCHECK(ui_auto_display_service_);
   return ui_auto_display_service_->ShouldAutoDisplayUi(url);
 }
+
+bool ChromeOsAppsNavigationThrottle::ShouldLaunchPreferredApp(const GURL& url) {
+  DCHECK(ui_auto_display_service_);
+  // Devices of tablet form factor should only launch a preferred app
+  // from Chrome if it has been explicitly set and persisted by the user in the
+  // intent picker previously.
+  if (chromeos::switches::IsTabletFormFactor() &&
+      ui_auto_display_service_->GetLastUsedPlatformForTablets(url) !=
+          IntentPickerAutoDisplayPref::Platform::kArc) {
+    return false;
+  }
+  return navigate_from_link();
+}
+
 }  // namespace chromeos
diff --git a/chrome/browser/chromeos/apps/intent_helper/chromeos_apps_navigation_throttle.h b/chrome/browser/chromeos/apps/intent_helper/chromeos_apps_navigation_throttle.h
index ce344e4b..8d01621 100644
--- a/chrome/browser/chromeos/apps/intent_helper/chromeos_apps_navigation_throttle.h
+++ b/chrome/browser/chromeos/apps/intent_helper/chromeos_apps_navigation_throttle.h
@@ -122,6 +122,9 @@
       content::WebContents* web_contents,
       const GURL& url);
 
+  // Whether or not we should launch preferred ARC apps.
+  bool ShouldLaunchPreferredApp(const GURL& url);
+
   // True if ARC is enabled, false otherwise.
   const bool arc_enabled_;
 
diff --git a/chrome/browser/chromeos/login/lock/views_screen_locker.cc b/chrome/browser/chromeos/login/lock/views_screen_locker.cc
index 6907dd1..6f276365 100644
--- a/chrome/browser/chromeos/login/lock/views_screen_locker.cc
+++ b/chrome/browser/chromeos/login/lock/views_screen_locker.cc
@@ -227,25 +227,18 @@
 
   focused_pod_account_id_ = base::Optional<AccountId>(account_id);
 
-  const user_manager::User* user =
-      user_manager::UserManager::Get()->FindUser(account_id);
-  // |user| may be null in kiosk mode or unit tests.
-  if (user && user->is_logged_in() && !user->is_active()) {
-    SessionControllerClientImpl::DoSwitchActiveUser(account_id);
-  } else {
-    lock_screen_utils::SetUserInputMethod(account_id.GetUserEmail(),
-                                          ime_state_.get());
-    lock_screen_utils::SetKeyboardSettings(account_id);
-    WallpaperControllerClient::Get()->ShowUserWallpaper(account_id);
+  lock_screen_utils::SetUserInputMethod(account_id.GetUserEmail(),
+                                        ime_state_.get());
+  lock_screen_utils::SetKeyboardSettings(account_id);
+  WallpaperControllerClient::Get()->ShowUserWallpaper(account_id);
 
-    bool use_24hour_clock = false;
-    if (user_manager::known_user::GetBooleanPref(
-            account_id, prefs::kUse24HourClock, &use_24hour_clock)) {
-      g_browser_process->platform_part()
-          ->GetSystemClock()
-          ->SetLastFocusedPodHourClockType(
-              use_24hour_clock ? base::k24HourClock : base::k12HourClock);
-    }
+  bool use_24hour_clock = false;
+  if (user_manager::known_user::GetBooleanPref(
+          account_id, prefs::kUse24HourClock, &use_24hour_clock)) {
+    g_browser_process->platform_part()
+        ->GetSystemClock()
+        ->SetLastFocusedPodHourClockType(use_24hour_clock ? base::k24HourClock
+                                                          : base::k12HourClock);
   }
 }
 
diff --git a/chrome/browser/chromeos/login/ui/login_web_dialog.cc b/chrome/browser/chromeos/login/ui/login_web_dialog.cc
index 312ce17..7cc30bb 100644
--- a/chrome/browser/chromeos/login/ui/login_web_dialog.cc
+++ b/chrome/browser/chromeos/login/ui/login_web_dialog.cc
@@ -114,8 +114,7 @@
   return stack.empty() ? nullptr : stack.front();
 }
 
-void LoginWebDialog::OnDialogShown(content::WebUI* webui,
-                                   content::RenderViewHost* render_view_host) {
+void LoginWebDialog::OnDialogShown(content::WebUI* webui) {
   g_web_contents_stack.Pointer()->push_front(webui->GetWebContents());
 }
 
diff --git a/chrome/browser/chromeos/login/ui/login_web_dialog.h b/chrome/browser/chromeos/login/ui/login_web_dialog.h
index 10bfcb7..fb831ae 100644
--- a/chrome/browser/chromeos/login/ui/login_web_dialog.h
+++ b/chrome/browser/chromeos/login/ui/login_web_dialog.h
@@ -66,8 +66,7 @@
   void GetDialogSize(gfx::Size* size) const override;
   void GetMinimumDialogSize(gfx::Size* size) const override;
   std::string GetDialogArgs() const override;
-  void OnDialogShown(content::WebUI* webui,
-                     content::RenderViewHost* render_view_host) override;
+  void OnDialogShown(content::WebUI* webui) override;
   // NOTE: This function deletes this object at the end.
   void OnDialogClosed(const std::string& json_retval) override;
   void OnCloseContents(content::WebContents* source,
diff --git a/chrome/browser/chromeos/policy/system_log_uploader_unittest.cc b/chrome/browser/chromeos/policy/system_log_uploader_unittest.cc
index a3d8a82..49488980b 100644
--- a/chrome/browser/chromeos/policy/system_log_uploader_unittest.cc
+++ b/chrome/browser/chromeos/policy/system_log_uploader_unittest.cc
@@ -295,10 +295,11 @@
   base::HistogramTester histogram_tester_;
 };
 
+// TODO(crbug.com/1022591) Disabled because of flakiness.
 // Verify log throttling. Try successive kLogThrottleCount log uploads by
 // creating a new task. First kLogThrottleCount logs should have 0 delay.
 // Successive logs should have approx. kLogThrottleWindowDuration delay.
-TEST_P(SystemLogUploaderTest, LogThrottleTest) {
+TEST_P(SystemLogUploaderTest, DISABLED_LogThrottleTest) {
   for (int upload_num = 0;
        upload_num < SystemLogUploader::kLogThrottleCount + 3; upload_num++) {
     EXPECT_FALSE(task_runner_->HasPendingTask());
diff --git a/chrome/browser/extensions/api/identity/gaia_web_auth_flow.cc b/chrome/browser/extensions/api/identity/gaia_web_auth_flow.cc
index f8677cb1..94e82cb 100644
--- a/chrome/browser/extensions/api/identity/gaia_web_auth_flow.cc
+++ b/chrome/browser/extensions/api/identity/gaia_web_auth_flow.cc
@@ -90,8 +90,7 @@
       account_id_,
       base::BindOnce(&GaiaWebAuthFlow::OnUbertokenFetchComplete,
                      base::Unretained(this)),
-      gaia::GaiaSource::kChrome, profile_->GetURLLoaderFactory(),
-      /*bound_to_channel_id=*/false);
+      gaia::GaiaSource::kChrome, profile_->GetURLLoaderFactory());
 }
 
 void GaiaWebAuthFlow::OnUbertokenFetchComplete(GoogleServiceAuthError error,
diff --git a/chrome/browser/extensions/api/input_ime/input_ime_api_chromeos.cc b/chrome/browser/extensions/api/input_ime/input_ime_api_chromeos.cc
index c56489c..3941291f 100644
--- a/chrome/browser/extensions/api/input_ime/input_ime_api_chromeos.cc
+++ b/chrome/browser/extensions/api/input_ime/input_ime_api_chromeos.cc
@@ -712,6 +712,18 @@
 }
 
 ExtensionFunction::ResponseAction
+InputMethodPrivateFinishComposingTextFunction::Run() {
+  InputMethodEngine* engine = GetEngineIfActive(
+      Profile::FromBrowserContext(browser_context()), extension_id());
+  if (!engine)
+    return RespondNow(Error(kInputImeApiChromeOSErrorEngineNotAvailable));
+
+  engine->ConfirmCompositionText(/* reset_engine */ false,
+                                 /* keep_selection */ true);
+  return RespondNow(NoArguments());
+}
+
+ExtensionFunction::ResponseAction
 InputMethodPrivateNotifyImeMenuItemActivatedFunction::Run() {
   chromeos::input_method::InputMethodDescriptor current_input_method =
       chromeos::input_method::InputMethodManager::Get()
diff --git a/chrome/browser/extensions/api/input_ime/input_ime_api_chromeos.h b/chrome/browser/extensions/api/input_ime/input_ime_api_chromeos.h
index 12a8e009..e717357 100644
--- a/chrome/browser/extensions/api/input_ime/input_ime_api_chromeos.h
+++ b/chrome/browser/extensions/api/input_ime/input_ime_api_chromeos.h
@@ -114,6 +114,26 @@
   ResponseAction Run() override;
 };
 
+class InputMethodPrivateFinishComposingTextFunction : public ExtensionFunction {
+ public:
+  InputMethodPrivateFinishComposingTextFunction(
+      const InputMethodPrivateFinishComposingTextFunction&) = delete;
+  InputMethodPrivateFinishComposingTextFunction& operator=(
+      const InputMethodPrivateFinishComposingTextFunction&) = delete;
+
+  InputMethodPrivateFinishComposingTextFunction() = default;
+
+ protected:
+  ~InputMethodPrivateFinishComposingTextFunction() override = default;
+
+  // ExtensionFunction:
+  ResponseAction Run() override;
+
+ private:
+  DECLARE_EXTENSION_FUNCTION("inputMethodPrivate.finishComposingText",
+                             INPUTMETHODPRIVATE_FINISHCOMPOSINGTEXT)
+};
+
 class InputMethodPrivateNotifyImeMenuItemActivatedFunction
     : public ExtensionFunction {
  public:
diff --git a/chrome/browser/flag-metadata.json b/chrome/browser/flag-metadata.json
index 21ac126..8fbe1df 100644
--- a/chrome/browser/flag-metadata.json
+++ b/chrome/browser/flag-metadata.json
@@ -1549,6 +1549,13 @@
     "expiry_milestone": -1
   },
   {
+    "name": "enable-neural-stylus-palm-rejection",
+    "owners": ["robsc", "napper", "adlr"],
+    // We add a neural net to change how fingers are handled. We set a milestone
+    // deep into the future to allow for experiments.
+    "expiry_milestone": 90
+  },
+  {
     "name": "enable-new-download-backend",
     "owners": [ "shaktisahu", "dtrainor" ],
     "expiry_milestone": 80
diff --git a/chrome/browser/flag_descriptions.cc b/chrome/browser/flag_descriptions.cc
index f356d98..b36de73 100644
--- a/chrome/browser/flag_descriptions.cc
+++ b/chrome/browser/flag_descriptions.cc
@@ -3497,6 +3497,12 @@
 const char kEnableHomeLauncherDescription[] =
     "Enable home launcher in tablet mode.";
 
+const char kEnableNeuralStylusPalmRejectionName[] =
+    "Enable Neural Palm Detection";
+const char kEnableNeuralStylusPalmRejectionDescription[] =
+    "Experimental: Enable Neural Palm detection. Not compatible with all "
+    "devices.";
+
 const char kEnableParentalControlsSettingsName[] =
     "Enable Parental controls settings";
 const char kEnableParentalControlsSettingsDescription[] =
diff --git a/chrome/browser/flag_descriptions.h b/chrome/browser/flag_descriptions.h
index 99073a74..411e4a1 100644
--- a/chrome/browser/flag_descriptions.h
+++ b/chrome/browser/flag_descriptions.h
@@ -2068,6 +2068,9 @@
 extern const char kEnableHomeLauncherName[];
 extern const char kEnableHomeLauncherDescription[];
 
+extern const char kEnableNeuralStylusPalmRejectionName[];
+extern const char kEnableNeuralStylusPalmRejectionDescription[];
+
 extern const char kEnableParentalControlsSettingsName[];
 extern const char kEnableParentalControlsSettingsDescription[];
 
diff --git a/chrome/browser/offline_pages/offline_page_request_handler_unittest.cc b/chrome/browser/offline_pages/offline_page_request_handler_unittest.cc
index 69b55ac..53716127 100644
--- a/chrome/browser/offline_pages/offline_page_request_handler_unittest.cc
+++ b/chrome/browser/offline_pages/offline_page_request_handler_unittest.cc
@@ -43,6 +43,7 @@
 #include "content/public/common/previews_state.h"
 #include "content/public/common/resource_type.h"
 #include "content/public/test/browser_task_environment.h"
+#include "mojo/public/cpp/bindings/receiver.h"
 #include "mojo/public/cpp/system/wait.h"
 #include "net/base/filename_util.h"
 #include "net/http/http_request_headers.h"
@@ -154,8 +155,7 @@
     virtual ~Observer() {}
   };
 
-  explicit TestURLLoaderClient(Observer* observer)
-      : observer_(observer), binding_(this) {}
+  explicit TestURLLoaderClient(Observer* observer) : observer_(observer) {}
   ~TestURLLoaderClient() override {}
 
   void OnReceiveResponse(
@@ -190,9 +190,9 @@
 
   network::mojom::URLLoaderClientPtr CreateInterfacePtr() {
     network::mojom::URLLoaderClientPtr client_ptr;
-    binding_.Bind(mojo::MakeRequest(&client_ptr));
-    binding_.set_connection_error_handler(base::BindOnce(
-        &TestURLLoaderClient::OnConnectionError, base::Unretained(this)));
+    receiver_.Bind(mojo::MakeRequest(&client_ptr));
+    receiver_.set_disconnect_handler(base::BindOnce(
+        &TestURLLoaderClient::OnMojoDisconnect, base::Unretained(this)));
     return client_ptr;
   }
 
@@ -203,10 +203,10 @@
   }
 
  private:
-  void OnConnectionError() {}
+  void OnMojoDisconnect() {}
 
   Observer* observer_ = nullptr;
-  mojo::Binding<network::mojom::URLLoaderClient> binding_;
+  mojo::Receiver<network::mojom::URLLoaderClient> receiver_{this};
   mojo::ScopedDataPipeConsumerHandle response_body_;
   network::URLLoaderCompletionStatus completion_status_;
 
diff --git a/chrome/browser/optimization_guide/optimization_guide_hints_manager.cc b/chrome/browser/optimization_guide/optimization_guide_hints_manager.cc
index 541df95b..517b626 100644
--- a/chrome/browser/optimization_guide/optimization_guide_hints_manager.cc
+++ b/chrome/browser/optimization_guide/optimization_guide_hints_manager.cc
@@ -848,11 +848,16 @@
     // If we do not have a hint already loaded and we do not have one in the
     // cache, we do not know what to do with the URL so just return.
     // Otherwise, we do have information, but we just do not know it yet.
-    *optimization_type_decision =
-        has_hint_in_cache
-            ? optimization_guide::OptimizationTypeDecision::
-                  kHadHintButNotLoadedInTime
-            : optimization_guide::OptimizationTypeDecision::kNoHintAvailable;
+    if (has_hint_in_cache) {
+      *optimization_type_decision = optimization_guide::
+          OptimizationTypeDecision::kHadHintButNotLoadedInTime;
+    } else if (IsHintBeingFetched(url.host())) {
+      *optimization_type_decision = optimization_guide::
+          OptimizationTypeDecision::kHintFetchStartedButNotAvailableInTime;
+    } else {
+      *optimization_type_decision =
+          optimization_guide::OptimizationTypeDecision::kNoHintAvailable;
+    }
     return;
   }
   if (!matched_page_hint) {
@@ -930,7 +935,8 @@
     return;
   }
 
-  if (IsAllowedToFetchNavigationHints(navigation_handle->GetURL())) {
+  if (IsAllowedToFetchNavigationHints(navigation_handle->GetURL()) &&
+      !hint_cache_->HasHint(navigation_handle->GetURL().host())) {
     std::vector<std::string> hosts{navigation_handle->GetURL().host()};
     navigation_hosts_last_fetched_real_time_.clear();
     navigation_hosts_last_fetched_real_time_.push_back(
@@ -956,3 +962,10 @@
   optimization_guide::HintsFetcher::ClearHostsSuccessfullyFetched(
       pref_service_);
 }
+
+bool OptimizationGuideHintsManager::IsHintBeingFetched(
+    const std::string& host) const {
+  return std::find(navigation_hosts_last_fetched_real_time_.begin(),
+                   navigation_hosts_last_fetched_real_time_.end(),
+                   host) != navigation_hosts_last_fetched_real_time_.end();
+}
diff --git a/chrome/browser/optimization_guide/optimization_guide_hints_manager.h b/chrome/browser/optimization_guide/optimization_guide_hints_manager.h
index 118ac516..2855b73d 100644
--- a/chrome/browser/optimization_guide/optimization_guide_hints_manager.h
+++ b/chrome/browser/optimization_guide/optimization_guide_hints_manager.h
@@ -270,6 +270,10 @@
       const base::Optional<NavigationPredictorKeyedService::Prediction>&
           prediction) override;
 
+  // Returns whether a hint for |host| is currently being fetched from the
+  // remote Optimization Guide Service.
+  bool IsHintBeingFetched(const std::string& host) const;
+
   // The OptimizationGuideService that this guide is listening to. Not owned.
   optimization_guide::OptimizationGuideService* const
       optimization_guide_service_;
diff --git a/chrome/browser/optimization_guide/optimization_guide_hints_manager_unittest.cc b/chrome/browser/optimization_guide/optimization_guide_hints_manager_unittest.cc
index cd4c53d3..b0879e8 100644
--- a/chrome/browser/optimization_guide/optimization_guide_hints_manager_unittest.cc
+++ b/chrome/browser/optimization_guide/optimization_guide_hints_manager_unittest.cc
@@ -1942,6 +1942,30 @@
 }
 
 TEST_F(OptimizationGuideHintsManagerTest,
+       HintsFetchedAtNavigationTime_HasComponentHintButNotFetched) {
+  hints_manager()->RegisterOptimizationTypes(
+      {optimization_guide::proto::DEFER_ALL_SCRIPT});
+  base::test::ScopedFeatureList scoped_list;
+  scoped_list.InitAndEnableFeature(
+      optimization_guide::features::kOptimizationHintsFetching);
+  InitializeWithDefaultConfig("1.0.0.0");
+
+  // Set ECT estimate so hint is activated.
+  hints_manager()->OnEffectiveConnectionTypeChanged(
+      net::EffectiveConnectionType::EFFECTIVE_CONNECTION_TYPE_SLOW_2G);
+  std::unique_ptr<content::MockNavigationHandle> navigation_handle =
+      CreateMockNavigationHandleWithOptimizationGuideWebContentsObserver(
+          url_with_hints());
+  base::RunLoop run_loop;
+  base::HistogramTester histogram_tester;
+  hints_manager()->OnNavigationStartOrRedirect(navigation_handle.get(),
+                                               run_loop.QuitClosure());
+  run_loop.Run();
+  histogram_tester.ExpectTotalCount(
+      "OptimizationGuide.HintsFetcher.GetHintsRequest.HostCount", 0);
+}
+
+TEST_F(OptimizationGuideHintsManagerTest,
        HintsNotFetchedAtNavigationTime_ECT_4G) {
   hints_manager()->RegisterOptimizationTypes(
       {optimization_guide::proto::DEFER_ALL_SCRIPT});
@@ -1965,6 +1989,35 @@
       "OptimizationGuide.HintsFetcher.GetHintsRequest.HostCount", 0);
 }
 
+TEST_F(OptimizationGuideHintsManagerTest, CanApplyOptimizationCalledMidFetch) {
+  hints_manager()->RegisterOptimizationTypes(
+      {optimization_guide::proto::DEFER_ALL_SCRIPT});
+  base::test::ScopedFeatureList scoped_list;
+  scoped_list.InitAndEnableFeature(
+      optimization_guide::features::kOptimizationHintsFetching);
+  InitializeWithDefaultConfig("1.0.0.0");
+
+  // Set ECT estimate so hint will attempt to be fetched.
+  hints_manager()->OnEffectiveConnectionTypeChanged(
+      net::EffectiveConnectionType::EFFECTIVE_CONNECTION_TYPE_2G);
+  std::unique_ptr<content::MockNavigationHandle> navigation_handle =
+      CreateMockNavigationHandleWithOptimizationGuideWebContentsObserver(
+          url_without_hints());
+  hints_manager()->OnNavigationStartOrRedirect(navigation_handle.get(),
+                                               base::DoNothing());
+  optimization_guide::OptimizationTargetDecision unused_target_decision;
+  optimization_guide::OptimizationTypeDecision optimization_type_decision;
+  hints_manager()->CanApplyOptimization(
+      navigation_handle.get(),
+      optimization_guide::proto::OPTIMIZATION_TARGET_PAINFUL_PAGE_LOAD,
+      optimization_guide::proto::DEFER_ALL_SCRIPT, &unused_target_decision,
+      &optimization_type_decision, /*optimization_metadata=*/nullptr);
+
+  EXPECT_EQ(optimization_type_decision,
+            optimization_guide::OptimizationTypeDecision::
+                kHintFetchStartedButNotAvailableInTime);
+}
+
 TEST_F(OptimizationGuideHintsManagerTest,
        CanApplyOptimizationNoMatchingPageHint) {
   InitializeWithDefaultConfig("1.0.0.0");
diff --git a/chrome/browser/optimization_guide/optimization_guide_keyed_service.cc b/chrome/browser/optimization_guide/optimization_guide_keyed_service.cc
index f3cdee9..be6b6d7 100644
--- a/chrome/browser/optimization_guide/optimization_guide_keyed_service.cc
+++ b/chrome/browser/optimization_guide/optimization_guide_keyed_service.cc
@@ -90,22 +90,16 @@
   switch (optimization_target_decision) {
     case optimization_guide::OptimizationTargetDecision::kPageLoadDoesNotMatch:
     case optimization_guide::OptimizationTargetDecision::
-        kModelNotAvailableOnClient:
-    case optimization_guide::OptimizationTargetDecision::
         kModelPredictionHoldback:
       return optimization_guide::OptimizationGuideDecision::kFalse;
     case optimization_guide::OptimizationTargetDecision::kPageLoadMatches:
       return optimization_guide::OptimizationGuideDecision::kTrue;
+    case optimization_guide::OptimizationTargetDecision::
+        kModelNotAvailableOnClient:
+    case optimization_guide::OptimizationTargetDecision::kUnknown:
     case optimization_guide::OptimizationTargetDecision::kDeciderNotInitialized:
-    default:
       return optimization_guide::OptimizationGuideDecision::kUnknown;
   }
-  static_assert(
-      optimization_guide::OptimizationTargetDecision::kMaxValue ==
-          optimization_guide::OptimizationTargetDecision::
-              kDeciderNotInitialized,
-      "This function should be updated when a new OptimizationTargetDecision "
-      "is added");
 }
 
 // Returns the OptimizationGuideDecision from |optimization_type_decision|.
@@ -122,16 +116,17 @@
         kHadOptimizationFilterButNotLoadedInTime:
     case optimization_guide::OptimizationTypeDecision::
         kHadHintButNotLoadedInTime:
+    case optimization_guide::OptimizationTypeDecision::
+        kHintFetchStartedButNotAvailableInTime:
     case optimization_guide::OptimizationTypeDecision::kDeciderNotInitialized:
       return optimization_guide::OptimizationGuideDecision::kUnknown;
-    default:
+    case optimization_guide::OptimizationTypeDecision::kNotAllowedByHint:
+    case optimization_guide::OptimizationTypeDecision::kNoMatchingPageHint:
+    case optimization_guide::OptimizationTypeDecision::kNoHintAvailable:
+    case optimization_guide::OptimizationTypeDecision::
+        kNotAllowedByOptimizationFilter:
       return optimization_guide::OptimizationGuideDecision::kFalse;
   }
-  static_assert(
-      optimization_guide::OptimizationTypeDecision::kMaxValue ==
-          optimization_guide::OptimizationTypeDecision::kDeciderNotInitialized,
-      "This function should be updated when a new OptimizationTypeDecision is "
-      "added");
 }
 
 // Returns the OptimizationGuideDecision based on |decisions|
@@ -139,19 +134,26 @@
 // 2) If all decisions are true, return true.
 // 3) Otherwise, return unknown.
 optimization_guide::OptimizationGuideDecision ResolveOptimizationGuideDecisions(
-    std::vector<optimization_guide::OptimizationGuideDecision> decisions) {
-  bool has_unknown_decision = false;
+    const std::vector<optimization_guide::OptimizationGuideDecision>&
+        decisions) {
+  bool has_all_true_decisions = true;
   for (const auto decision : decisions) {
     if (decision == optimization_guide::OptimizationGuideDecision::kFalse)
       return optimization_guide::OptimizationGuideDecision::kFalse;
 
-    if (decision == optimization_guide::OptimizationGuideDecision::kUnknown)
-      has_unknown_decision = true;
+    if (decision != optimization_guide::OptimizationGuideDecision::kTrue) {
+      has_all_true_decisions = false;
+      break;
+    }
   }
 
-  return has_unknown_decision
-             ? optimization_guide::OptimizationGuideDecision::kUnknown
-             : optimization_guide::OptimizationGuideDecision::kTrue;
+  return has_all_true_decisions
+             ? optimization_guide::OptimizationGuideDecision::kTrue
+             : optimization_guide::OptimizationGuideDecision::kUnknown;
+  static_assert(optimization_guide::OptimizationGuideDecision::kMaxValue ==
+                    optimization_guide::OptimizationGuideDecision::kFalse,
+                "This function should be updated when a new "
+                "OptimizationGuideDecision is added");
 }
 
 }  // namespace
diff --git a/chrome/browser/optimization_guide/optimization_guide_keyed_service_browsertest.cc b/chrome/browser/optimization_guide/optimization_guide_keyed_service_browsertest.cc
index 24bd717..260da5f 100644
--- a/chrome/browser/optimization_guide/optimization_guide_keyed_service_browsertest.cc
+++ b/chrome/browser/optimization_guide/optimization_guide_keyed_service_browsertest.cc
@@ -666,6 +666,9 @@
     cmd->AppendSwitch("enable-spdy-proxy-auth");
     // Add switch to avoid having to see the infobar in the test.
     cmd->AppendSwitch(previews::switches::kDoNotRequireLitePageRedirectInfoBar);
+    // Add switch to avoid racing navigations in the test.
+    cmd->AppendSwitch(optimization_guide::switches::
+                          kDisableFetchingHintsAtNavigationStartForTesting);
   }
 
  private:
@@ -802,11 +805,11 @@
   // There should be a hint that matches this URL.
   histogram_tester.ExpectUniqueSample("OptimizationGuide.LoadedHint.Result",
                                       true, 1);
-  EXPECT_EQ(optimization_guide::OptimizationGuideDecision::kFalse,
+  EXPECT_EQ(optimization_guide::OptimizationGuideDecision::kUnknown,
             last_should_target_navigation_decision());
   EXPECT_EQ(optimization_guide::OptimizationGuideDecision::kTrue,
             last_can_apply_optimization_decision());
-  EXPECT_EQ(optimization_guide::OptimizationGuideDecision::kFalse,
+  EXPECT_EQ(optimization_guide::OptimizationGuideDecision::kUnknown,
             last_consumer_decision());
   histogram_tester.ExpectUniqueSample(
       "OptimizationGuide.TargetDecision.PainfulPageLoad",
diff --git a/chrome/browser/previews/previews_lite_page_redirect_serving_url_loader.cc b/chrome/browser/previews/previews_lite_page_redirect_serving_url_loader.cc
index c713caf..5619d32 100644
--- a/chrome/browser/previews/previews_lite_page_redirect_serving_url_loader.cc
+++ b/chrome/browser/previews/previews_lite_page_redirect_serving_url_loader.cc
@@ -205,9 +205,7 @@
 
 PreviewsLitePageRedirectServingURLLoader::
     PreviewsLitePageRedirectServingURLLoader(ResultCallback result_callback)
-    : url_loader_binding_(this),
-      result_callback_(std::move(result_callback)),
-      binding_(this) {}
+    : result_callback_(std::move(result_callback)), binding_(this) {}
 
 void PreviewsLitePageRedirectServingURLLoader::StartNetworkRequest(
     const network::ResourceRequest& request,
@@ -218,10 +216,10 @@
   previews_url_ = request.url;
   network::mojom::URLLoaderClientPtr client;
 
-  url_loader_binding_.Bind(mojo::MakeRequest(&client),
-                           base::ThreadTaskRunnerHandle::Get());
-  url_loader_binding_.set_connection_error_handler(base::BindOnce(
-      &PreviewsLitePageRedirectServingURLLoader::OnConnectionError,
+  url_loader_receiver_.Bind(mojo::MakeRequest(&client),
+                            base::ThreadTaskRunnerHandle::Get());
+  url_loader_receiver_.set_disconnect_handler(base::BindOnce(
+      &PreviewsLitePageRedirectServingURLLoader::OnMojoDisconnect,
       base::Unretained(this)));
 
   // Create a network service URL loader with passed in params.
@@ -274,7 +272,7 @@
   DCHECK(!binding_.is_bound());
   binding_.Bind(std::move(receiver));
   binding_.set_connection_error_handler(base::BindOnce(
-      &PreviewsLitePageRedirectServingURLLoader::OnConnectionError,
+      &PreviewsLitePageRedirectServingURLLoader::OnMojoDisconnect,
       weak_ptr_factory_.GetWeakPtr()));
   forwarding_client_ = std::move(forwarding_client);
 
@@ -290,7 +288,7 @@
   forwarding_client_->OnReceiveResponse(resource_response_->head);
 
   // Resume previously paused network service URLLoader.
-  url_loader_binding_.ResumeIncomingMethodCallProcessing();
+  url_loader_receiver_.Resume();
 }
 
 void PreviewsLitePageRedirectServingURLLoader::OnReceiveResponse(
@@ -359,7 +357,7 @@
                       GURL(original_url).host(), frame_tree_node_id_);
   }
 
-  url_loader_binding_.PauseIncomingMethodCallProcessing();
+  url_loader_receiver_.Pause();
   std::move(result_callback_)
       .Run(ServingLoaderResult::kSuccess, base::nullopt, nullptr);
 }
@@ -492,7 +490,7 @@
   network_url_loader_->ResumeReadingBodyFromNet();
 }
 
-void PreviewsLitePageRedirectServingURLLoader::OnConnectionError() {
+void PreviewsLitePageRedirectServingURLLoader::OnMojoDisconnect() {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   // When we are not yet bound to the navigation code, fallback, which will
   // destroy this object.
@@ -505,7 +503,7 @@
   }
 
   network_url_loader_.reset();
-  url_loader_binding_.Close();
+  url_loader_receiver_.reset();
 
   if (binding_.is_bound()) {
     binding_.Close();
diff --git a/chrome/browser/previews/previews_lite_page_redirect_serving_url_loader.h b/chrome/browser/previews/previews_lite_page_redirect_serving_url_loader.h
index aca4f58..adeac94 100644
--- a/chrome/browser/previews/previews_lite_page_redirect_serving_url_loader.h
+++ b/chrome/browser/previews/previews_lite_page_redirect_serving_url_loader.h
@@ -16,6 +16,7 @@
 #include "content/public/browser/url_loader_request_interceptor.h"
 #include "mojo/public/cpp/bindings/binding.h"
 #include "mojo/public/cpp/bindings/pending_receiver.h"
+#include "mojo/public/cpp/bindings/receiver.h"
 #include "mojo/public/cpp/system/data_pipe.h"
 #include "services/network/public/cpp/resource_response.h"
 #include "services/network/public/cpp/shared_url_loader_factory.h"
@@ -89,9 +90,9 @@
       mojo::ScopedDataPipeConsumerHandle body) override;
   void OnComplete(const network::URLLoaderCompletionStatus& status) override;
 
-  // When a connection error occurs in either mojo pipe, this objects lifetime
+  // When a disconnection occurs in either mojo pipe, this object's lifetime
   // needs to be managed and the connections need to be closed.
-  void OnConnectionError();
+  void OnMojoDisconnect();
 
   // Calls |result_callback_| with kFallback and cleans up.
   void Fallback();
@@ -110,9 +111,9 @@
       mojo::PendingReceiver<network::mojom::URLLoader> receiver,
       network::mojom::URLLoaderClientPtr forwarding_client);
 
-  // The network URLLoader that fetches the LitePage URL and its binding.
+  // The network URLLoader that fetches the LitePage URL and its receiver.
   network::mojom::URLLoaderPtr network_url_loader_;
-  mojo::Binding<network::mojom::URLLoaderClient> url_loader_binding_;
+  mojo::Receiver<network::mojom::URLLoaderClient> url_loader_receiver_{this};
 
   // When a result is determined, this callback should be run with the
   // appropriate ServingLoaderResult.
diff --git a/chrome/browser/resources/chromeos/camera/src/views/main.html b/chrome/browser/resources/chromeos/camera/src/views/main.html
index 81200bf..f5e88e6 100644
--- a/chrome/browser/resources/chromeos/camera/src/views/main.html
+++ b/chrome/browser/resources/chromeos/camera/src/views/main.html
@@ -201,7 +201,7 @@
           <button class="icon" tabindex="0" i18n-aria="back_button"></button>
           <div i18n-content="settings_button"></div>
         </div>
-        <button class="menu-item circle" id="settings-gridtype" tabindex="0"
+        <button class="menu-item" id="settings-gridtype" tabindex="0"
                 aria-describedby="gridtype-desc">
           <div class="icon"></div>
           <div>
@@ -214,7 +214,7 @@
           </div>
           <div class="icon end"></div>
         </button>
-        <button class="menu-item circle" id="settings-timerdur" tabindex="0"
+        <button class="menu-item" id="settings-timerdur" tabindex="0"
                 aria-describedby="timerdur-desc">
           <div class="icon"></div>
           <div>
@@ -226,23 +226,23 @@
           </div>
           <div class="icon end"></div>
         </button>
-        <button class="menu-item circle" id="settings-resolution" tabindex="0">
+        <button class="menu-item" id="settings-resolution" tabindex="0">
           <div class="icon"></div>
           <div i18n-content="camera_resolution_button">
           </div>
           <div class="icon end"></div>
         </button>
-        <button class="menu-item circle" id="settings-expert" tabindex="0">
+        <button class="menu-item" id="settings-expert" tabindex="0">
           <div class="icon"></div>
           <div i18n-content="expert_mode_button">
           </div>
           <div class="icon end"></div>
         </button>
-        <button class="menu-item circle" id="settings-feedback" tabindex="0">
+        <button class="menu-item" id="settings-feedback" tabindex="0">
           <div class="icon"></div>
           <div i18n-content="feedback_button"></div>
         </button>
-        <button class="menu-item circle" id="settings-help" tabindex="0">
+        <button class="menu-item" id="settings-help" tabindex="0">
           <div class="icon"></div>
           <div i18n-content="help_button"></div>
         </button>
@@ -298,7 +298,7 @@
         </div>
         <div id="builtin-photo-header" class="menu-item"
           i18n-content="label_switch_take_photo_button"></div>
-        <button class="menu-item resol-item circle"
+        <button class="menu-item resol-item"
                 id="settings-front-photores" tabindex="0"
                 aria-describedby="front-photores-desc">
           <div>
@@ -310,7 +310,7 @@
           </div>
           <div class="icon end"></div>
         </button>
-        <button class="menu-item resol-item circle"
+        <button class="menu-item resol-item"
                 id="settings-back-photores" tabindex="0"
                 aria-describedby="back-photores-desc">
           <div>
@@ -323,7 +323,7 @@
         </button>
         <div id="builtin-video-header" class="menu-item"
           i18n-content="label_switch_record_video_button"></div>
-        <button class="menu-item resol-item circle"
+        <button class="menu-item resol-item"
                 id="settings-front-videores" tabindex="0"
                 aria-describedby="front-videores-desc">
           <div>
@@ -334,7 +334,7 @@
           </div>
           <div class="icon end"></div>
         </button>
-        <button class="menu-item resol-item circle"
+        <button class="menu-item resol-item"
                 id="settings-back-videores" tabindex="0"
                 aria-describedby="back-videores-desc">
           <div>
@@ -369,13 +369,13 @@
           <button class="icon" tabindex="0" i18n-aria="back_button"></button>
           <div i18n-content="expert_mode_button"></div>
         </div>
-        <label class="menu-item circle" for="expert-show-metadata">
+        <label class="menu-item" for="expert-show-metadata">
           <input class="icon" id="expert-show-metadata" type="checkbox"
                  tabindex="0" data-state="show-metadata"
                  data-key="showMetadata">
           <span i18n-content="expert_preview_metadata"></span>
         </label>
-        <label class="menu-item circle" for="expert-save-metadata">
+        <label class="menu-item" for="expert-save-metadata">
           <input class="icon" id="expert-save-metadata" type="checkbox"
                  tabindex="0" data-state="save-metadata"
                  data-key="saveMetadata">
@@ -444,7 +444,7 @@
           </div>
           <div class="icon end"></div>
         </button>
-        <button class="menu-item resol-item circle external-camera"
+        <button class="menu-item resol-item external-camera"
               tabindex="0">
           <div>
             <div i18n-content="video_resolution_button"></div>
diff --git a/chrome/browser/resources/chromeos/switch_access/focus_ring_manager.js b/chrome/browser/resources/chromeos/switch_access/focus_ring_manager.js
index e8fc5cf..d2ea4aa4 100644
--- a/chrome/browser/resources/chromeos/switch_access/focus_ring_manager.js
+++ b/chrome/browser/resources/chromeos/switch_access/focus_ring_manager.js
@@ -87,6 +87,11 @@
     if (this.rings_.size === 0) {
       return;
     }
+    if (!primary.location || !group.location) {
+      throw SwitchAccess.error(
+          SAConstants.ErrorType.MISSING_LOCATION,
+          'Cannot set focus rings if node location is undefined');
+    }
 
     if (primary instanceof BackButtonNode) {
       // TODO(anastasi): Use standard focus rings.
diff --git a/chrome/browser/resources/chromeos/switch_access/navigation_manager.js b/chrome/browser/resources/chromeos/switch_access/navigation_manager.js
index f5a0c97..dca1625 100644
--- a/chrome/browser/resources/chromeos/switch_access/navigation_manager.js
+++ b/chrome/browser/resources/chromeos/switch_access/navigation_manager.js
@@ -355,11 +355,10 @@
       }
     }
 
-    const desktop = RootNodeWrapper.buildDesktopTree(this.desktop_);
-    const nextNode = desktop.firstChild.automationNode;
-    if (nextNode) {
-      this.moveTo_(nextNode);
-    }
+    // If there is no valid node in the group stack, go to the desktop.
+    this.group_ = RootNodeWrapper.buildDesktopTree(this.desktop_);
+    this.node_ = this.group_.firstChild;
+    this.groupStack_ = [];
   }
 
   /**
diff --git a/chrome/browser/resources/chromeos/switch_access/switch_access_constants.js b/chrome/browser/resources/chromeos/switch_access/switch_access_constants.js
index de67581..9470ffb 100644
--- a/chrome/browser/resources/chromeos/switch_access/switch_access_constants.js
+++ b/chrome/browser/resources/chromeos/switch_access/switch_access_constants.js
@@ -190,6 +190,7 @@
   NULL_CHILD: 6,
   NO_CHILDREN: 7,
   MALFORMED_DESKTOP: 8,
+  MISSING_LOCATION: 9,
 };
 
 /**
diff --git a/chrome/browser/resources/chromeos/switch_access/switch_access_predicate.js b/chrome/browser/resources/chromeos/switch_access/switch_access_predicate.js
index f6c0f9c..0866606 100644
--- a/chrome/browser/resources/chromeos/switch_access/switch_access_predicate.js
+++ b/chrome/browser/resources/chromeos/switch_access/switch_access_predicate.js
@@ -39,7 +39,7 @@
     const state = node.state;
 
     // Skip things that are offscreen or invisible.
-    if (state[StateType.OFFSCREEN] || loc.top < 0 || loc.left < 0 ||
+    if (state[StateType.OFFSCREEN] || !loc || loc.top < 0 || loc.left < 0 ||
         state[StateType.INVISIBLE]) {
       return false;
     }
diff --git a/chrome/browser/resources/extensions/activity_log/BUILD.gn b/chrome/browser/resources/extensions/activity_log/BUILD.gn
index 70ade218..d562aa8 100644
--- a/chrome/browser/resources/extensions/activity_log/BUILD.gn
+++ b/chrome/browser/resources/extensions/activity_log/BUILD.gn
@@ -1,6 +1,6 @@
-# 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.
+#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")
 import("//tools/polymer/polymer.gni")
diff --git a/chrome/browser/resources/extensions/activity_log/activity_log.js b/chrome/browser/resources/extensions/activity_log/activity_log.js
index c0cee3fd..6bf480f 100644
--- a/chrome/browser/resources/extensions/activity_log/activity_log.js
+++ b/chrome/browser/resources/extensions/activity_log/activity_log.js
@@ -37,140 +37,140 @@
   STREAM: 1
 };
 
+/**
+ * A struct used as a placeholder for chrome.developerPrivate.ExtensionInfo
+ * for this component if the extensionId from the URL does not correspond to
+ * installed extension.
+ * @typedef {{
+ *   id: string,
+ *   isPlaceholder: boolean,
+ * }}
+ */
+export let ActivityLogExtensionPlaceholder;
+
+Polymer({
+  is: 'extensions-activity-log',
+
+  _template: html`{__html_template__}`,
+
+  behaviors: [
+    CrContainerShadowBehavior,
+    I18nBehavior,
+    ItemBehavior,
+  ],
+
+  properties: {
+    /**
+     * The underlying ExtensionInfo for the details being displayed.
+     * @type {!chrome.developerPrivate.ExtensionInfo|
+     *        !ActivityLogExtensionPlaceholder}
+     */
+    extensionInfo: Object,
+
+    /** @type {!ActivityLogDelegate} */
+    delegate: Object,
+
+    /** @private {!ActivityLogSubpage} */
+    selectedSubpage_: {
+      type: Number,
+      value: ActivityLogSubpage.NONE,
+      observer: 'onSelectedSubpageChanged_',
+    },
+
+    /** @private {Array<string>} */
+    tabNames_: {
+      type: Array,
+      value: () => ([
+        loadTimeData.getString('activityLogHistoryTabHeading'),
+        loadTimeData.getString('activityLogStreamTabHeading'),
+      ]),
+    }
+  },
+
+  listeners: {
+    'view-enter-start': 'onViewEnterStart_',
+    'view-exit-finish': 'onViewExitFinish_',
+  },
+
   /**
-   * A struct used as a placeholder for chrome.developerPrivate.ExtensionInfo
-   * for this component if the extensionId from the URL does not correspond to
-   * installed extension.
-   * @typedef {{
-   *   id: string,
-   *   isPlaceholder: boolean,
-   * }}
+   * Focuses the back button when page is loaded and set the activie view to
+   * be HISTORY when we navigate to the page.
+   * @private
    */
-  export let ActivityLogExtensionPlaceholder;
+  onViewEnterStart_: function() {
+    this.selectedSubpage_ = ActivityLogSubpage.HISTORY;
+    afterNextRender(this, () => focusWithoutInk(this.$.closeButton));
+  },
 
-  Polymer({
-    is: 'extensions-activity-log',
+  /**
+   * Set |selectedSubpage_| to NONE to remove the active view from the DOM.
+   * @private
+   */
+  onViewExitFinish_: function() {
+    this.selectedSubpage_ = ActivityLogSubpage.NONE;
+    // clear the stream if the user is exiting the activity log page.
+    const activityLogStream = this.$$('activity-log-stream');
+    if (activityLogStream) {
+      activityLogStream.clearStream();
+    }
+  },
 
-    _template: html`{__html_template__}`,
+  /**
+   * @private
+   * @return {string}
+   */
+  getActivityLogHeading_: function() {
+    const headingName = this.extensionInfo.isPlaceholder ?
+        this.i18n('missingOrUninstalledExtension') :
+        this.extensionInfo.name;
+    return this.i18n('activityLogPageHeading', headingName);
+  },
 
-    behaviors: [
-      CrContainerShadowBehavior,
-      I18nBehavior,
-      ItemBehavior,
-    ],
+  /**
+   * @private
+   * @return {boolean}
+   */
+  isHistoryTabSelected_: function() {
+    return this.selectedSubpage_ === ActivityLogSubpage.HISTORY;
+  },
 
-    properties: {
-      /**
-       * The underlying ExtensionInfo for the details being displayed.
-       * @type {!chrome.developerPrivate.ExtensionInfo|
-       *        !ActivityLogExtensionPlaceholder}
-       */
-      extensionInfo: Object,
+  /**
+   * @private
+   * @return {boolean}
+   */
+  isStreamTabSelected_: function() {
+    return this.selectedSubpage_ === ActivityLogSubpage.STREAM;
+  },
 
-      /** @type {!ActivityLogDelegate} */
-      delegate: Object,
-
-      /** @private {!ActivityLogSubpage} */
-      selectedSubpage_: {
-        type: Number,
-        value: ActivityLogSubpage.NONE,
-        observer: 'onSelectedSubpageChanged_',
-      },
-
-      /** @private {Array<string>} */
-      tabNames_: {
-        type: Array,
-        value: () => ([
-          loadTimeData.getString('activityLogHistoryTabHeading'),
-          loadTimeData.getString('activityLogStreamTabHeading'),
-        ]),
+  /**
+   * @private
+   * @param {!ActivityLogSubpage} newTab
+   * @param {!ActivityLogSubpage} oldTab
+   */
+  onSelectedSubpageChanged_: function(newTab, oldTab) {
+    const activityLogStream = this.$$('activity-log-stream');
+    if (activityLogStream) {
+      if (newTab === ActivityLogSubpage.STREAM) {
+        // Start the stream if the user is switching to the real-time tab.
+        // This will not handle the first tab switch to the real-time tab as
+        // the stream has not been attached to the DOM yet, and is handled
+        // instead by the stream's |attached| method.
+        activityLogStream.startStream();
+      } else if (oldTab === ActivityLogSubpage.STREAM) {
+        // Pause the stream if the user is navigating away from the real-time
+        // tab.
+        activityLogStream.pauseStream();
       }
-    },
+    }
+  },
 
-    listeners: {
-      'view-enter-start': 'onViewEnterStart_',
-      'view-exit-finish': 'onViewExitFinish_',
-    },
-
-    /**
-     * Focuses the back button when page is loaded and set the activie view to
-     * be HISTORY when we navigate to the page.
-     * @private
-     */
-    onViewEnterStart_: function() {
-      this.selectedSubpage_ = ActivityLogSubpage.HISTORY;
-      afterNextRender(this, () => focusWithoutInk(this.$.closeButton));
-    },
-
-    /**
-     * Set |selectedSubpage_| to NONE to remove the active view from the DOM.
-     * @private
-     */
-    onViewExitFinish_: function() {
-      this.selectedSubpage_ = ActivityLogSubpage.NONE;
-      // clear the stream if the user is exiting the activity log page.
-      const activityLogStream = this.$$('activity-log-stream');
-      if (activityLogStream) {
-        activityLogStream.clearStream();
-      }
-    },
-
-    /**
-     * @private
-     * @return {string}
-     */
-    getActivityLogHeading_: function() {
-      const headingName = this.extensionInfo.isPlaceholder ?
-          this.i18n('missingOrUninstalledExtension') :
-          this.extensionInfo.name;
-      return this.i18n('activityLogPageHeading', headingName);
-    },
-
-    /**
-     * @private
-     * @return {boolean}
-     */
-    isHistoryTabSelected_: function() {
-      return this.selectedSubpage_ === ActivityLogSubpage.HISTORY;
-    },
-
-    /**
-     * @private
-     * @return {boolean}
-     */
-    isStreamTabSelected_: function() {
-      return this.selectedSubpage_ === ActivityLogSubpage.STREAM;
-    },
-
-    /**
-     * @private
-     * @param {!ActivityLogSubpage} newTab
-     * @param {!ActivityLogSubpage} oldTab
-     */
-    onSelectedSubpageChanged_: function(newTab, oldTab) {
-      const activityLogStream = this.$$('activity-log-stream');
-      if (activityLogStream) {
-        if (newTab === ActivityLogSubpage.STREAM) {
-          // Start the stream if the user is switching to the real-time tab.
-          // This will not handle the first tab switch to the real-time tab as
-          // the stream has not been attached to the DOM yet, and is handled
-          // instead by the stream's |attached| method.
-          activityLogStream.startStream();
-        } else if (oldTab === ActivityLogSubpage.STREAM) {
-          // Pause the stream if the user is navigating away from the real-time
-          // tab.
-          activityLogStream.pauseStream();
-        }
-      }
-    },
-
-    /** @private */
-    onCloseButtonTap_: function() {
-      if (this.extensionInfo.isPlaceholder) {
-        navigation.navigateTo({page: Page.LIST});
-      } else {
-        navigation.navigateTo(
-            {page: Page.DETAILS, extensionId: this.extensionInfo.id});
-      }
-    },
-  });
+  /** @private */
+  onCloseButtonTap_: function() {
+    if (this.extensionInfo.isPlaceholder) {
+      navigation.navigateTo({page: Page.LIST});
+    } else {
+      navigation.navigateTo(
+          {page: Page.DETAILS, extensionId: this.extensionInfo.id});
+    }
+  },
+});
diff --git a/chrome/browser/resources/extensions/activity_log/activity_log_history.js b/chrome/browser/resources/extensions/activity_log/activity_log_history.js
index 3be47fc..a28281e 100644
--- a/chrome/browser/resources/extensions/activity_log/activity_log_history.js
+++ b/chrome/browser/resources/extensions/activity_log/activity_log_history.js
@@ -14,410 +14,410 @@
 
 import {ActivityGroup} from './activity_log_history_item.js';
 
+/**
+ * The different states the activity log page can be in. Initial state is
+ * LOADING because we call the activity log API whenever a user navigates to
+ * the page. LOADED is the state where the API call has returned a successful
+ * result.
+ * @enum {string}
+ */
+export const ActivityLogPageState = {
+  LOADING: 'loading',
+  LOADED: 'loaded'
+};
+
+/** @interface */
+export class ActivityLogDelegate {
   /**
-   * The different states the activity log page can be in. Initial state is
-   * LOADING because we call the activity log API whenever a user navigates to
-   * the page. LOADED is the state where the API call has returned a successful
-   * result.
-   * @enum {string}
+   * @param {string} extensionId
+   * @return {!Promise<!chrome.activityLogPrivate.ActivityResultSet>}
    */
-  export const ActivityLogPageState = {
-    LOADING: 'loading',
-    LOADED: 'loaded'
-  };
+  getExtensionActivityLog(extensionId) {}
 
-  /** @interface */
-  export class ActivityLogDelegate {
-    /**
-     * @param {string} extensionId
-     * @return {!Promise<!chrome.activityLogPrivate.ActivityResultSet>}
-     */
-    getExtensionActivityLog(extensionId) {}
+  /**
+   * @param {string} extensionId
+   * @param {string} searchTerm
+   * @return {!Promise<!chrome.activityLogPrivate.ActivityResultSet>}
+   */
+  getFilteredExtensionActivityLog(extensionId, searchTerm) {}
 
-    /**
-     * @param {string} extensionId
-     * @param {string} searchTerm
-     * @return {!Promise<!chrome.activityLogPrivate.ActivityResultSet>}
-     */
-    getFilteredExtensionActivityLog(extensionId, searchTerm) {}
+  /**
+   * @param {!Array<string>} activityIds
+   * @return {!Promise<void>}
+   */
+  deleteActivitiesById(activityIds) {}
 
-    /**
-     * @param {!Array<string>} activityIds
-     * @return {!Promise<void>}
-     */
-    deleteActivitiesById(activityIds) {}
+  /**
+   * @param {string} extensionId
+   * @return {!Promise<void>}
+   */
+  deleteActivitiesFromExtension(extensionId) {}
 
-    /**
-     * @param {string} extensionId
-     * @return {!Promise<void>}
-     */
-    deleteActivitiesFromExtension(extensionId) {}
+  /**
+   * @param {string} rawActivityData
+   * @param {string} fileName
+   */
+  downloadActivities(rawActivityData, fileName) {}
+}
 
-    /**
-     * @param {string} rawActivityData
-     * @param {string} fileName
-     */
-    downloadActivities(rawActivityData, fileName) {}
+/**
+ * Content scripts activities do not have an API call, so we use the names of
+ * the scripts executed (specified as a stringified JSON array in the args
+ * field) as the keys for an activity group instead.
+ * @private
+ * @param {!chrome.activityLogPrivate.ExtensionActivity} activity
+ * @return {!Array<string>}
+ */
+function getActivityGroupKeysForContentScript_(activity) {
+  assert(
+      activity.activityType ===
+      chrome.activityLogPrivate.ExtensionActivityType.CONTENT_SCRIPT);
+
+  if (!activity.args) {
+    return [];
   }
 
-  /**
-   * Content scripts activities do not have an API call, so we use the names of
-   * the scripts executed (specified as a stringified JSON array in the args
-   * field) as the keys for an activity group instead.
-   * @private
-   * @param {!chrome.activityLogPrivate.ExtensionActivity} activity
-   * @return {!Array<string>}
-   */
-  function getActivityGroupKeysForContentScript_(activity) {
-    assert(
-        activity.activityType ===
-        chrome.activityLogPrivate.ExtensionActivityType.CONTENT_SCRIPT);
+  const parsedArgs = JSON.parse(activity.args);
+  assert(Array.isArray(parsedArgs), 'Invalid API data.');
+  return /** @type {!Array<string>} */ (parsedArgs);
+}
 
-    if (!activity.args) {
-      return [];
+/**
+ * Web request activities can have extra information which describes what the
+ * web request does in more detail than just the api_call. This information
+ * is in activity.other.webRequest and we use this to generate more activity
+ * group keys if possible.
+ * @private
+ * @param {!chrome.activityLogPrivate.ExtensionActivity} activity
+ * @return {!Array<string>}
+ */
+function getActivityGroupKeysForWebRequest_(activity) {
+  assert(
+      activity.activityType ===
+      chrome.activityLogPrivate.ExtensionActivityType.WEB_REQUEST);
+
+  const apiCall = activity.apiCall;
+  const other = activity.other;
+
+  if (!other || !other.webRequest) {
+    return [apiCall];
+  }
+
+  const webRequest = /** @type {!Object} */ (JSON.parse(other.webRequest));
+  assert(typeof webRequest === 'object', 'Invalid API data');
+
+  // If there is extra information in the other.webRequest object,
+  // construct a group for each consisting of the API call and each object key
+  // in other.webRequest. Otherwise we default to just the API call.
+  return Object.keys(webRequest).length === 0 ?
+      [apiCall] :
+      Object.keys(webRequest).map(field => `${apiCall} (${field})`);
+}
+
+/**
+ * Group activity log entries by a key determined from each entry. Usually
+ * this would be the activity's API call though content script and web
+ * requests have different keys. We currently assume that every API call
+ * matches to one activity type.
+ * @param {!Array<!chrome.activityLogPrivate.ExtensionActivity>}
+ *     activityData
+ * @return {!Map<string, !ActivityGroup>}
+ */
+function groupActivities(activityData) {
+  const groupedActivities = new Map();
+
+  for (const activity of activityData) {
+    const activityId = activity.activityId;
+    const activityType = activity.activityType;
+    const count = activity.count;
+    const pageUrl = activity.pageUrl;
+
+    const isContentScript = activityType ===
+        chrome.activityLogPrivate.ExtensionActivityType.CONTENT_SCRIPT;
+    const isWebRequest = activityType ===
+        chrome.activityLogPrivate.ExtensionActivityType.WEB_REQUEST;
+
+    let activityGroupKeys = [activity.apiCall];
+    if (isContentScript) {
+      activityGroupKeys = getActivityGroupKeysForContentScript_(activity);
+    } else if (isWebRequest) {
+      activityGroupKeys = getActivityGroupKeysForWebRequest_(activity);
     }
 
-    const parsedArgs = JSON.parse(activity.args);
-    assert(Array.isArray(parsedArgs), 'Invalid API data.');
-    return /** @type {!Array<string>} */ (parsedArgs);
-  }
+    for (const key of activityGroupKeys) {
+      if (!groupedActivities.has(key)) {
+        const activityGroup = {
+          activityIds: new Set([activityId]),
+          key,
+          count,
+          activityType,
+          countsByUrl: pageUrl ? new Map([[pageUrl, count]]) : new Map(),
+          expanded: false,
+        };
+        groupedActivities.set(key, activityGroup);
+      } else {
+        const activityGroup = groupedActivities.get(key);
+        activityGroup.activityIds.add(activityId);
+        activityGroup.count += count;
 
-  /**
-   * Web request activities can have extra information which describes what the
-   * web request does in more detail than just the api_call. This information
-   * is in activity.other.webRequest and we use this to generate more activity
-   * group keys if possible.
-   * @private
-   * @param {!chrome.activityLogPrivate.ExtensionActivity} activity
-   * @return {!Array<string>}
-   */
-  function getActivityGroupKeysForWebRequest_(activity) {
-    assert(
-        activity.activityType ===
-        chrome.activityLogPrivate.ExtensionActivityType.WEB_REQUEST);
-
-    const apiCall = activity.apiCall;
-    const other = activity.other;
-
-    if (!other || !other.webRequest) {
-      return [apiCall];
+        if (pageUrl) {
+          const currentCount = activityGroup.countsByUrl.get(pageUrl) || 0;
+          activityGroup.countsByUrl.set(pageUrl, currentCount + count);
+        }
+      }
     }
-
-    const webRequest = /** @type {!Object} */ (JSON.parse(other.webRequest));
-    assert(typeof webRequest === 'object', 'Invalid API data');
-
-    // If there is extra information in the other.webRequest object,
-    // construct a group for each consisting of the API call and each object key
-    // in other.webRequest. Otherwise we default to just the API call.
-    return Object.keys(webRequest).length === 0 ?
-        [apiCall] :
-        Object.keys(webRequest).map(field => `${apiCall} (${field})`);
   }
 
+  return groupedActivities;
+}
+
+/**
+ * Sort activities by the total count for each activity group key. Resolve
+ * ties by the alphabetical order of the key.
+ * @param {!Map<string, !ActivityGroup>} groupedActivities
+ * @return {!Array<!ActivityGroup>}
+ */
+function sortActivitiesByCallCount(groupedActivities) {
+  return Array.from(groupedActivities.values()).sort((a, b) => {
+    if (a.count != b.count) {
+      return b.count - a.count;
+    }
+    if (a.key < b.key) {
+      return -1;
+    }
+    if (a.key > b.key) {
+      return 1;
+    }
+    return 0;
+  });
+}
+
+Polymer({
+  is: 'activity-log-history',
+
+  _template: html`{__html_template__}`,
+
+  properties: {
+    /** @type {!string} */
+    extensionId: String,
+
+    /** @type {!ActivityLogDelegate} */
+    delegate: Object,
+
+    /**
+     * 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 {!Array<!ActivityGroup>}
+     */
+    activityData_: {
+      type: Array,
+      value: () => [],
+    },
+
+    /** @private {ActivityLogPageState} */
+    pageState_: {
+      type: String,
+      value: ActivityLogPageState.LOADING,
+    },
+
+    /** @private */
+    lastSearch_: {
+      type: String,
+      value: '',
+    },
+  },
+
+  listeners: {
+    'delete-activity-log-item': 'deleteItem_',
+  },
+
   /**
-   * Group activity log entries by a key determined from each entry. Usually
-   * this would be the activity's API call though content script and web
-   * requests have different keys. We currently assume that every API call
-   * matches to one activity type.
+   * 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,
+
+  /**
+   * The stringified API response from the activityLogPrivate API with
+   * individual activities sorted in ascending order by timestamp; used for
+   * exporting the activity log.
+   * @private {string}
+   */
+  rawActivities_: '',
+
+  /**
+   * Expose only the promise of dataFetchedResolver_.
+   * @return {!Promise<void>}
+   */
+  whenDataFetched: function() {
+    return this.dataFetchedResolver_.promise;
+  },
+
+  /** @override */
+  attached: function() {
+    this.dataFetchedResolver_ = new PromiseResolver();
+    this.refreshActivities_();
+  },
+
+  /**
+   * @private
+   * @return {boolean}
+   */
+  shouldShowEmptyActivityLogMessage_: function() {
+    return this.pageState_ === ActivityLogPageState.LOADED &&
+        this.activityData_.length === 0;
+  },
+
+  /**
+   * @private
+   * @return {boolean}
+   */
+  shouldShowLoadingMessage_: function() {
+    return this.pageState_ === ActivityLogPageState.LOADING;
+  },
+
+  /**
+   * @private
+   * @return {boolean}
+   */
+  shouldShowActivities_: function() {
+    return this.pageState_ === ActivityLogPageState.LOADED &&
+        this.activityData_.length > 0;
+  },
+
+  /** @private */
+  onClearActivitiesClick_: function() {
+    this.delegate.deleteActivitiesFromExtension(this.extensionId).then(() => {
+      this.processActivities_([]);
+    });
+  },
+
+  /** @private */
+  onMoreActionsClick_: function() {
+    this.$$('cr-action-menu').showAt(assert(this.$$('cr-icon-button')));
+  },
+
+  /**
+   * @private
+   * @param {boolean} expanded
+   */
+  expandItems_: function(expanded) {
+    // Do not use .filter here as we need the original index of the item
+    // in |activityData_|.
+    this.activityData_.forEach((item, index) => {
+      if (item.countsByUrl.size > 0) {
+        this.set(`activityData_.${index}.expanded`, expanded);
+      }
+    });
+    this.$$('cr-action-menu').close();
+  },
+
+  /** @private */
+  onExpandAllClick_: function() {
+    this.expandItems_(true);
+  },
+
+  /** @private */
+  onCollapseAllClick_: function() {
+    this.expandItems_(false);
+  },
+
+  /** @private */
+  onExportClick_: function() {
+    const fileName = `exported_activity_log_${this.extensionId}.json`;
+    this.delegate.downloadActivities(this.rawActivities_, fileName);
+  },
+
+  /**
+   * @private
+   * @param {!CustomEvent<!Array<string>>} e
+   */
+  deleteItem_: function(e) {
+    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_();
+    });
+  },
+
+  /**
+   * @private
    * @param {!Array<!chrome.activityLogPrivate.ExtensionActivity>}
    *     activityData
-   * @return {!Map<string, !ActivityGroup>}
    */
-  function groupActivities(activityData) {
-    const groupedActivities = new Map();
+  processActivities_: function(activityData) {
+    this.pageState_ = ActivityLogPageState.LOADED;
 
-    for (const activity of activityData) {
-      const activityId = activity.activityId;
-      const activityType = activity.activityType;
-      const count = activity.count;
-      const pageUrl = activity.pageUrl;
+    // Sort |activityData| in ascending order based on the activity's
+    // timestamp; Used for |this.encodedRawActivities|.
+    activityData.sort((a, b) => a.time - b.time);
+    this.rawActivities_ = JSON.stringify(activityData);
 
-      const isContentScript = activityType ===
-          chrome.activityLogPrivate.ExtensionActivityType.CONTENT_SCRIPT;
-      const isWebRequest = activityType ===
-          chrome.activityLogPrivate.ExtensionActivityType.WEB_REQUEST;
-
-      let activityGroupKeys = [activity.apiCall];
-      if (isContentScript) {
-        activityGroupKeys = getActivityGroupKeysForContentScript_(activity);
-      } else if (isWebRequest) {
-        activityGroupKeys = getActivityGroupKeysForWebRequest_(activity);
-      }
-
-      for (const key of activityGroupKeys) {
-        if (!groupedActivities.has(key)) {
-          const activityGroup = {
-            activityIds: new Set([activityId]),
-            key,
-            count,
-            activityType,
-            countsByUrl: pageUrl ? new Map([[pageUrl, count]]) : new Map(),
-            expanded: false,
-          };
-          groupedActivities.set(key, activityGroup);
-        } else {
-          const activityGroup = groupedActivities.get(key);
-          activityGroup.activityIds.add(activityId);
-          activityGroup.count += count;
-
-          if (pageUrl) {
-            const currentCount = activityGroup.countsByUrl.get(pageUrl) || 0;
-            activityGroup.countsByUrl.set(pageUrl, currentCount + count);
-          }
-        }
-      }
+    this.activityData_ =
+        sortActivitiesByCallCount(groupActivities(activityData));
+    if (!this.dataFetchedResolver_.isFulfilled) {
+      this.dataFetchedResolver_.resolve();
     }
-
-    return groupedActivities;
-  }
+  },
 
   /**
-   * Sort activities by the total count for each activity group key. Resolve
-   * ties by the alphabetical order of the key.
-   * @param {!Map<string, !ActivityGroup>} groupedActivities
-   * @return {!Array<!ActivityGroup>}
+   * @private
+   * @return {!Promise<void>}
    */
-  function sortActivitiesByCallCount(groupedActivities) {
-    return Array.from(groupedActivities.values()).sort((a, b) => {
-      if (a.count != b.count) {
-        return b.count - a.count;
-      }
-      if (a.key < b.key) {
-        return -1;
-      }
-      if (a.key > b.key) {
-        return 1;
-      }
-      return 0;
-    });
-  }
+  refreshActivities_: function() {
+    if (this.lastSearch_ === '') {
+      return this.getActivityLog_();
+    }
 
-  Polymer({
-    is: 'activity-log-history',
+    return this.getFilteredActivityLog_(this.lastSearch_);
+  },
 
-    _template: html`{__html_template__}`,
+  /**
+   * @private
+   * @return {!Promise<void>}
+   */
+  getActivityLog_: function() {
+    this.pageState_ = ActivityLogPageState.LOADING;
+    return this.delegate.getExtensionActivityLog(this.extensionId)
+        .then(result => {
+          this.processActivities_(result.activities);
+        });
+  },
 
-    properties: {
-      /** @type {!string} */
-      extensionId: String,
+  /**
+   * @private
+   * @param {string} searchTerm
+   * @return {!Promise<void>}
+   */
+  getFilteredActivityLog_: function(searchTerm) {
+    this.pageState_ = ActivityLogPageState.LOADING;
+    return this.delegate
+        .getFilteredExtensionActivityLog(this.extensionId, searchTerm)
+        .then(result => {
+          this.processActivities_(result.activities);
+        });
+  },
 
-      /** @type {!ActivityLogDelegate} */
-      delegate: Object,
+  /**
+   * @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;
+    }
 
-      /**
-       * 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 {!Array<!ActivityGroup>}
-       */
-      activityData_: {
-        type: Array,
-        value: () => [],
-      },
-
-      /** @private {ActivityLogPageState} */
-      pageState_: {
-        type: String,
-        value: ActivityLogPageState.LOADING,
-      },
-
-      /** @private */
-      lastSearch_: {
-        type: String,
-        value: '',
-      },
-    },
-
-    listeners: {
-      'delete-activity-log-item': 'deleteItem_',
-    },
-
-    /**
-     * 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,
-
-    /**
-     * The stringified API response from the activityLogPrivate API with
-     * individual activities sorted in ascending order by timestamp; used for
-     * exporting the activity log.
-     * @private {string}
-     */
-    rawActivities_: '',
-
-    /**
-     * Expose only the promise of dataFetchedResolver_.
-     * @return {!Promise<void>}
-     */
-    whenDataFetched: function() {
-      return this.dataFetchedResolver_.promise;
-    },
-
-    /** @override */
-    attached: function() {
-      this.dataFetchedResolver_ = new PromiseResolver();
-      this.refreshActivities_();
-    },
-
-    /**
-     * @private
-     * @return {boolean}
-     */
-    shouldShowEmptyActivityLogMessage_: function() {
-      return this.pageState_ === ActivityLogPageState.LOADED &&
-          this.activityData_.length === 0;
-    },
-
-    /**
-     * @private
-     * @return {boolean}
-     */
-    shouldShowLoadingMessage_: function() {
-      return this.pageState_ === ActivityLogPageState.LOADING;
-    },
-
-    /**
-     * @private
-     * @return {boolean}
-     */
-    shouldShowActivities_: function() {
-      return this.pageState_ === ActivityLogPageState.LOADED &&
-          this.activityData_.length > 0;
-    },
-
-    /** @private */
-    onClearActivitiesClick_: function() {
-      this.delegate.deleteActivitiesFromExtension(this.extensionId).then(() => {
-        this.processActivities_([]);
-      });
-    },
-
-    /** @private */
-    onMoreActionsClick_: function() {
-      this.$$('cr-action-menu').showAt(assert(this.$$('cr-icon-button')));
-    },
-
-    /**
-     * @private
-     * @param {boolean} expanded
-     */
-    expandItems_: function(expanded) {
-      // Do not use .filter here as we need the original index of the item
-      // in |activityData_|.
-      this.activityData_.forEach((item, index) => {
-        if (item.countsByUrl.size > 0) {
-          this.set(`activityData_.${index}.expanded`, expanded);
-        }
-      });
-      this.$$('cr-action-menu').close();
-    },
-
-    /** @private */
-    onExpandAllClick_: function() {
-      this.expandItems_(true);
-    },
-
-    /** @private */
-    onCollapseAllClick_: function() {
-      this.expandItems_(false);
-    },
-
-    /** @private */
-    onExportClick_: function() {
-      const fileName = `exported_activity_log_${this.extensionId}.json`;
-      this.delegate.downloadActivities(this.rawActivities_, fileName);
-    },
-
-    /**
-     * @private
-     * @param {!CustomEvent<!Array<string>>} e
-     */
-    deleteItem_: function(e) {
-      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_();
-      });
-    },
-
-    /**
-     * @private
-     * @param {!Array<!chrome.activityLogPrivate.ExtensionActivity>}
-     *     activityData
-     */
-    processActivities_: function(activityData) {
-      this.pageState_ = ActivityLogPageState.LOADED;
-
-      // Sort |activityData| in ascending order based on the activity's
-      // timestamp; Used for |this.encodedRawActivities|.
-      activityData.sort((a, b) => a.time - b.time);
-      this.rawActivities_ = JSON.stringify(activityData);
-
-      this.activityData_ =
-          sortActivitiesByCallCount(groupActivities(activityData));
-      if (!this.dataFetchedResolver_.isFulfilled) {
-        this.dataFetchedResolver_.resolve();
-      }
-    },
-
-    /**
-     * @private
-     * @return {!Promise<void>}
-     */
-    refreshActivities_: function() {
-      if (this.lastSearch_ === '') {
-        return this.getActivityLog_();
-      }
-
-      return this.getFilteredActivityLog_(this.lastSearch_);
-    },
-
-    /**
-     * @private
-     * @return {!Promise<void>}
-     */
-    getActivityLog_: function() {
-      this.pageState_ = ActivityLogPageState.LOADING;
-      return this.delegate.getExtensionActivityLog(this.extensionId)
-          .then(result => {
-            this.processActivities_(result.activities);
-          });
-    },
-
-    /**
-     * @private
-     * @param {string} searchTerm
-     * @return {!Promise<void>}
-     */
-    getFilteredActivityLog_: function(searchTerm) {
-      this.pageState_ = ActivityLogPageState.LOADING;
-      return this.delegate
-          .getFilteredExtensionActivityLog(this.extensionId, searchTerm)
-          .then(result => {
-            this.processActivities_(result.activities);
-          });
-    },
-
-    /**
-     * @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;
-      this.refreshActivities_();
-    },
-  });
+    this.lastSearch_ = searchTerm;
+    this.refreshActivities_();
+  },
+});
diff --git a/chrome/browser/resources/extensions/activity_log/activity_log_history_item.js b/chrome/browser/resources/extensions/activity_log/activity_log_history_item.js
index 1c172fba..1ed2d728 100644
--- a/chrome/browser/resources/extensions/activity_log/activity_log_history_item.js
+++ b/chrome/browser/resources/extensions/activity_log/activity_log_history_item.js
@@ -11,96 +11,95 @@
 
 import {html, Polymer} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
 
-  /**
-   * @typedef {{
-   *   activityIds: !Set<string>,
-   *   key: string,
-   *   count: number,
-   *   activityType: !chrome.activityLogPrivate.ExtensionActivityFilter,
-   *   countsByUrl: !Map<string, number>,
-   *   expanded: boolean
-   * }}
-   */
-  export let ActivityGroup;
+/**
+ * @typedef {{
+ *   activityIds: !Set<string>,
+ *   key: string,
+ *   count: number,
+ *   activityType: !chrome.activityLogPrivate.ExtensionActivityFilter,
+ *   countsByUrl: !Map<string, number>,
+ *   expanded: boolean
+ * }}
+ */
+export let ActivityGroup;
 
-  /**
-   * A struct used to describe each url and its associated counts. The id is
-   * unique for each item in the list of URLs and is used for the tooltip.
-   * @typedef {{
-   *   page: string,
-   *   count: number
-   * }}
-   */
-  let PageUrlItem;
+/**
+ * A struct used to describe each url and its associated counts. The id is
+ * unique for each item in the list of URLs and is used for the tooltip.
+ * @typedef {{
+ *   page: string,
+ *   count: number
+ * }}
+ */
+let PageUrlItem;
 
-  Polymer({
-    is: 'activity-log-history-item',
+Polymer({
+  is: 'activity-log-history-item',
 
-    _template: html`{__html_template__}`,
+  _template: html`{__html_template__}`,
 
-    properties: {
-      /**
-       * The underlying ActivityGroup that provides data for the
-       * ActivityLogItem displayed.
-       * @type {!ActivityGroup}
-       */
-      data: Object,
-
-      /** @private */
-      isExpandable_: {
-        type: Boolean,
-        computed: 'computeIsExpandable_(data.countsByUrl)',
-      },
-    },
-
+  properties: {
     /**
-     * @private
-     * @return {boolean}
+     * The underlying ActivityGroup that provides data for the
+     * ActivityLogItem displayed.
+     * @type {!ActivityGroup}
      */
-    computeIsExpandable_: function() {
-      return this.data.countsByUrl.size > 0;
-    },
-
-    /**
-     * Sort the page URLs by the number of times it was associated with the key
-     * for this ActivityGroup (API call or content script invocation.) Resolve
-     * ties by the alphabetical order of the page URL.
-     * @private
-     * @return {!Array<PageUrlItem>}
-     */
-    getPageUrls_: function() {
-      return Array.from(this.data.countsByUrl.entries())
-          .map(e => ({page: e[0], count: e[1]}))
-          .sort(function(a, b) {
-            if (a.count != b.count) {
-              return b.count - a.count;
-            }
-            return a.page < b.page ? -1 : (a.page > b.page ? 1 : 0);
-          });
-    },
+    data: Object,
 
     /** @private */
-    onDeleteTap_: function(e) {
-      e.stopPropagation();
-      this.fire(
-          'delete-activity-log-item',
-          Array.from(this.data.activityIds.values()));
+    isExpandable_: {
+      type: Boolean,
+      computed: 'computeIsExpandable_(data.countsByUrl)',
     },
+  },
 
-    /** @private */
-    onExpandTap_: function() {
-      if (this.isExpandable_) {
-        this.set('data.expanded', !this.data.expanded);
-      }
-    },
+  /**
+   * @private
+   * @return {boolean}
+   */
+  computeIsExpandable_: function() {
+    return this.data.countsByUrl.size > 0;
+  },
 
-    /**
-     * Show the call count for a particular page URL if more than one page
-     * URL is associated with the key for this ActivityGroup.
-     * @private
-     * @return {boolean}
-     */
-    shouldShowPageUrlCount_: function() {
-      return this.data.countsByUrl.size > 1;
-    },
-  });
+  /**
+   * Sort the page URLs by the number of times it was associated with the key
+   * for this ActivityGroup (API call or content script invocation.) Resolve
+   * ties by the alphabetical order of the page URL.
+   * @private
+   * @return {!Array<PageUrlItem>}
+   */
+  getPageUrls_: function() {
+    return Array.from(this.data.countsByUrl.entries())
+        .map(e => ({page: e[0], count: e[1]}))
+        .sort(function(a, b) {
+          if (a.count != b.count) {
+            return b.count - a.count;
+          }
+          return a.page < b.page ? -1 : (a.page > b.page ? 1 : 0);
+        });
+  },
+
+  /** @private */
+  onDeleteTap_: function(e) {
+    e.stopPropagation();
+    this.fire(
+        'delete-activity-log-item', Array.from(this.data.activityIds.values()));
+  },
+
+  /** @private */
+  onExpandTap_: function() {
+    if (this.isExpandable_) {
+      this.set('data.expanded', !this.data.expanded);
+    }
+  },
+
+  /**
+   * Show the call count for a particular page URL if more than one page
+   * URL is associated with the key for this ActivityGroup.
+   * @private
+   * @return {boolean}
+   */
+  shouldShowPageUrlCount_: function() {
+    return this.data.countsByUrl.size > 1;
+  },
+});
diff --git a/chrome/browser/resources/extensions/activity_log/activity_log_stream.js b/chrome/browser/resources/extensions/activity_log/activity_log_stream.js
index 1a62539..7b74faf 100644
--- a/chrome/browser/resources/extensions/activity_log/activity_log_stream.js
+++ b/chrome/browser/resources/extensions/activity_log/activity_log_stream.js
@@ -13,223 +13,221 @@
 import {StreamArgItem, StreamItem} from './activity_log_stream_item.js';
 
 
-  /** @interface */
-  export class ActivityLogEventDelegate {
-    /** @return {!ChromeEvent} */
-    getOnExtensionActivity() {}
+/** @interface */
+export class ActivityLogEventDelegate {
+  /** @return {!ChromeEvent} */
+  getOnExtensionActivity() {}
+}
+
+/**
+ * Process activity for the stream. In the case of content scripts, we split
+ * the activity for every script invoked.
+ * @param {!chrome.activityLogPrivate.ExtensionActivity}
+ *     activity
+ * @return {!Array<!StreamItem>}
+ */
+function processActivityForStream(activity) {
+  const activityType = activity.activityType;
+  const timestamp = activity.time;
+  const isContentScript = activityType ===
+      chrome.activityLogPrivate.ExtensionActivityType.CONTENT_SCRIPT;
+
+  const args = isContentScript ? JSON.stringify([]) : activity.args;
+
+  let streamItemNames = [activity.apiCall];
+
+  // TODO(kelvinjiang): Reuse logic from activity_log_history and refactor
+  // some of the processing code into a separate file in a follow up CL.
+  if (isContentScript) {
+    streamItemNames = activity.args ? JSON.parse(activity.args) : [];
+    assert(Array.isArray(streamItemNames), 'Invalid data for script names.');
   }
 
+  const other = activity.other;
+  const webRequestInfo = other && other.webRequest;
+
+  return streamItemNames.map(name => ({
+                               args,
+                               argUrl: activity.argUrl,
+                               activityType,
+                               name,
+                               pageUrl: activity.pageUrl,
+                               timestamp,
+                               webRequestInfo,
+                               expanded: false,
+                             }));
+}
+
+Polymer({
+  is: 'activity-log-stream',
+
+  _template: html`{__html_template__}`,
+
+  properties: {
+    /** @type {string} */
+    extensionId: String,
+
+    /** @type {!ActivityLogEventDelegate} */
+    delegate: Object,
+
+    /** @private */
+    isStreamOn_: {
+      type: Boolean,
+      value: false,
+    },
+
+    /** @private {!Array<!StreamItem>} */
+    activityStream_: {
+      type: Array,
+      value: () => [],
+    },
+
+    /** @private {!Array<!StreamItem>} */
+    filteredActivityStream_: {
+      type: Array,
+      computed:
+          'computeFilteredActivityStream_(activityStream_.*, lastSearch_)',
+    },
+
+    /** @private */
+    lastSearch_: {
+      type: String,
+      value: '',
+    },
+  },
+
+  listeners: {
+    'resize-stream': 'onResizeStream_',
+  },
+
   /**
-   * Process activity for the stream. In the case of content scripts, we split
-   * the activity for every script invoked.
-   * @param {!chrome.activityLogPrivate.ExtensionActivity}
-   *     activity
-   * @return {!Array<!StreamItem>}
+   * Instance of |extensionActivityListener_| bound to |this|.
+   * @private {!Function}
    */
-  function processActivityForStream(activity) {
-    const activityType = activity.activityType;
-    const timestamp = activity.time;
-    const isContentScript = activityType ===
-        chrome.activityLogPrivate.ExtensionActivityType.CONTENT_SCRIPT;
+  listenerInstance_: () => {},
 
-    const args = isContentScript ? JSON.stringify([]) : activity.args;
+  /** @override */
+  attached: function() {
+    // Since this component is not restamped, this will only be called once
+    // in its lifecycle.
+    this.listenerInstance_ = this.extensionActivityListener_.bind(this);
+    this.startStream();
+  },
 
-    let streamItemNames = [activity.apiCall];
+  /** @private */
+  onResizeStream_: function(e) {
+    this.$$('iron-list').notifyResize();
+  },
 
-    // TODO(kelvinjiang): Reuse logic from activity_log_history and refactor
-    // some of the processing code into a separate file in a follow up CL.
-    if (isContentScript) {
-      streamItemNames = activity.args ? JSON.parse(activity.args) : [];
-      assert(Array.isArray(streamItemNames), 'Invalid data for script names.');
+  clearStream: function() {
+    this.splice('activityStream_', 0, this.activityStream_.length);
+  },
+
+  startStream: function() {
+    if (this.isStreamOn_) {
+      return;
     }
 
-    const other = activity.other;
-    const webRequestInfo = other && other.webRequest;
+    this.isStreamOn_ = true;
+    this.delegate.getOnExtensionActivity().addListener(this.listenerInstance_);
+  },
 
-    return streamItemNames.map(name => ({
-                                 args,
-                                 argUrl: activity.argUrl,
-                                 activityType,
-                                 name,
-                                 pageUrl: activity.pageUrl,
-                                 timestamp,
-                                 webRequestInfo,
-                                 expanded: false,
-                               }));
-  }
+  pauseStream: function() {
+    if (!this.isStreamOn_) {
+      return;
+    }
 
-  Polymer({
-    is: 'activity-log-stream',
+    this.delegate.getOnExtensionActivity().removeListener(
+        this.listenerInstance_);
+    this.isStreamOn_ = false;
+  },
 
-    _template: html`{__html_template__}`,
-
-    properties: {
-      /** @type {string} */
-      extensionId: String,
-
-      /** @type {!ActivityLogEventDelegate} */
-      delegate: Object,
-
-      /** @private */
-      isStreamOn_: {
-        type: Boolean,
-        value: false,
-      },
-
-      /** @private {!Array<!StreamItem>} */
-      activityStream_: {
-        type: Array,
-        value: () => [],
-      },
-
-      /** @private {!Array<!StreamItem>} */
-      filteredActivityStream_: {
-        type: Array,
-        computed:
-            'computeFilteredActivityStream_(activityStream_.*, lastSearch_)',
-      },
-
-      /** @private */
-      lastSearch_: {
-        type: String,
-        value: '',
-      },
-    },
-
-    listeners: {
-      'resize-stream': 'onResizeStream_',
-    },
-
-    /**
-     * Instance of |extensionActivityListener_| bound to |this|.
-     * @private {!Function}
-     */
-    listenerInstance_: () => {},
-
-    /** @override */
-    attached: function() {
-      // Since this component is not restamped, this will only be called once
-      // in its lifecycle.
-      this.listenerInstance_ = this.extensionActivityListener_.bind(this);
+  /** @private */
+  onToggleButtonClick_: function() {
+    if (this.isStreamOn_) {
+      this.pauseStream();
+    } else {
       this.startStream();
-    },
+    }
+  },
 
-    /** @private */
-    onResizeStream_: function(e) {
-      this.$$('iron-list').notifyResize();
-    },
+  /**
+   * @private
+   * @return {boolean}
+   */
+  isStreamEmpty_: function() {
+    return this.activityStream_.length == 0;
+  },
 
-    clearStream: function() {
-      this.splice('activityStream_', 0, this.activityStream_.length);
-    },
+  /**
+   * @private
+   * @return {boolean}
+   */
+  isFilteredStreamEmpty_: function() {
+    return this.filteredActivityStream_.length == 0;
+  },
 
-    startStream: function() {
-      if (this.isStreamOn_) {
-        return;
-      }
+  /**
+   * @private
+   * @return {boolean}
+   */
+  shouldShowEmptySearchMessage_: function() {
+    return !this.isStreamEmpty_() && this.isFilteredStreamEmpty_();
+  },
 
-      this.isStreamOn_ = true;
-      this.delegate.getOnExtensionActivity().addListener(
-          this.listenerInstance_);
-    },
+  /**
+   * @private
+   * @param {!chrome.activityLogPrivate.ExtensionActivity} activity
+   */
+  extensionActivityListener_: function(activity) {
+    if (activity.extensionId != this.extensionId) {
+      return;
+    }
 
-    pauseStream: function() {
-      if (!this.isStreamOn_) {
-        return;
-      }
+    this.splice(
+        'activityStream_', this.activityStream_.length, 0,
+        ...processActivityForStream(activity));
 
-      this.delegate.getOnExtensionActivity().removeListener(
-          this.listenerInstance_);
-      this.isStreamOn_ = false;
-    },
+    // Used to update the scrollbar.
+    this.$$('iron-list').notifyResize();
+  },
 
-    /** @private */
-    onToggleButtonClick_: function() {
-      if (this.isStreamOn_) {
-        this.pauseStream();
-      } else {
-        this.startStream();
-      }
-    },
+  /**
+   * @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, '').toLowerCase();
+    if (searchTerm === this.lastSearch_) {
+      return;
+    }
 
-    /**
-     * @private
-     * @return {boolean}
-     */
-    isStreamEmpty_: function() {
-      return this.activityStream_.length == 0;
-    },
+    this.lastSearch_ = searchTerm;
+  },
 
-    /**
-     * @private
-     * @return {boolean}
-     */
-    isFilteredStreamEmpty_: function() {
-      return this.filteredActivityStream_.length == 0;
-    },
+  /**
+   * @private
+   * @return {!Array<!StreamItem>}
+   */
+  computeFilteredActivityStream_: function() {
+    if (!this.lastSearch_) {
+      return this.activityStream_.slice();
+    }
 
-    /**
-     * @private
-     * @return {boolean}
-     */
-    shouldShowEmptySearchMessage_: function() {
-      return !this.isStreamEmpty_() && this.isFilteredStreamEmpty_();
-    },
+    // Match on these properties for each activity.
+    const propNames = [
+      'name',
+      'pageUrl',
+      'activityType',
+    ];
 
-    /**
-     * @private
-     * @param {!chrome.activityLogPrivate.ExtensionActivity} activity
-     */
-    extensionActivityListener_: function(activity) {
-      if (activity.extensionId != this.extensionId) {
-        return;
-      }
-
-      this.splice(
-          'activityStream_', this.activityStream_.length, 0,
-          ...processActivityForStream(activity));
-
-      // Used to update the scrollbar.
-      this.$$('iron-list').notifyResize();
-    },
-
-    /**
-     * @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, '').toLowerCase();
-      if (searchTerm === this.lastSearch_) {
-        return;
-      }
-
-      this.lastSearch_ = searchTerm;
-    },
-
-    /**
-     * @private
-     * @return {!Array<!StreamItem>}
-     */
-    computeFilteredActivityStream_: function() {
-      if (!this.lastSearch_) {
-        return this.activityStream_.slice();
-      }
-
-      // Match on these properties for each activity.
-      const propNames = [
-        'name',
-        'pageUrl',
-        'activityType',
-      ];
-
-      return this.activityStream_.filter(act => {
-        return propNames.some(prop => {
-          return act[prop] &&
-              act[prop].toLowerCase().includes(this.lastSearch_);
-        });
+    return this.activityStream_.filter(act => {
+      return propNames.some(prop => {
+        return act[prop] && act[prop].toLowerCase().includes(this.lastSearch_);
       });
-    },
-  });
+    });
+  },
+});
diff --git a/chrome/browser/resources/extensions/activity_log/activity_log_stream_item.js b/chrome/browser/resources/extensions/activity_log/activity_log_stream_item.js
index daf175a..e702507 100644
--- a/chrome/browser/resources/extensions/activity_log/activity_log_stream_item.js
+++ b/chrome/browser/resources/extensions/activity_log/activity_log_stream_item.js
@@ -10,152 +10,152 @@
 
 import {html, Polymer} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
 
-  /**
-   * @typedef {{
-   *   name: string,
-   *   timestamp: number,
-   *   activityType: !chrome.activityLogPrivate.ExtensionActivityFilter,
-   *   pageUrl: string,
-   *   argUrl: string,
-   *   args: string,
-   *   webRequestInfo: (string|undefined),
-   *   expanded: boolean
-   * }}
-   */
-  export let StreamItem;
+/**
+ * @typedef {{
+ *   name: string,
+ *   timestamp: number,
+ *   activityType: !chrome.activityLogPrivate.ExtensionActivityFilter,
+ *   pageUrl: string,
+ *   argUrl: string,
+ *   args: string,
+ *   webRequestInfo: (string|undefined),
+ *   expanded: boolean
+ * }}
+ */
+export let StreamItem;
 
-  /**
-   * A struct used to describe each argument for an activity (each item in
-   * the parsed version of |data.args|). Contains the argument's value itself
-   * and its index.
-   * @typedef {{
-   *   arg: string,
-   *   index: number
-   * }}
-   */
-  export let StreamArgItem;
+/**
+ * A struct used to describe each argument for an activity (each item in
+ * the parsed version of |data.args|). Contains the argument's value itself
+ * and its index.
+ * @typedef {{
+ *   arg: string,
+ *   index: number
+ * }}
+ */
+export let StreamArgItem;
 
-  /**
-   * Placeholder for arg_url that can occur in |StreamItem.args|. Sometimes we
-   * see this as '\u003Carg_url>' (opening arrow is unicode converted) but
-   * string comparison with the non-unicode value still returns true so we
-   * don't need to convert.
-   * @type {string}
-   */
-  export const ARG_URL_PLACEHOLDER = '<arg_url>';
+/**
+ * Placeholder for arg_url that can occur in |StreamItem.args|. Sometimes we
+ * see this as '\u003Carg_url>' (opening arrow is unicode converted) but
+ * string comparison with the non-unicode value still returns true so we
+ * don't need to convert.
+ * @type {string}
+ */
+export const ARG_URL_PLACEHOLDER = '<arg_url>';
 
-  /**
-   * Regex pattern for |ARG_URL_PLACEHOLDER| for String.replace. A regex of the
-   * exact string with a global search flag is needed to replace all
-   * occurrences.
-   * @type {!RegExp}
-   */
-  const ARG_URL_PLACEHOLDER_REGEX = /"<arg_url>"/g;
+/**
+ * Regex pattern for |ARG_URL_PLACEHOLDER| for String.replace. A regex of the
+ * exact string with a global search flag is needed to replace all
+ * occurrences.
+ * @type {!RegExp}
+ */
+const ARG_URL_PLACEHOLDER_REGEX = /"<arg_url>"/g;
 
-  Polymer({
-    is: 'activity-log-stream-item',
+Polymer({
+  is: 'activity-log-stream-item',
 
-    _template: html`{__html_template__}`,
+  _template: html`{__html_template__}`,
 
-    properties: {
-      /**
-       * The underlying ActivityGroup that provides data for the
-       * ActivityLogItem displayed.
-       * @type {!StreamItem}
-       */
-      data: Object,
-
-      /** @private {!Array<!StreamArgItem>} */
-      argsList_: {
-        type: Array,
-        computed: 'computeArgsList_(data.args)',
-      },
-
-      /** @private */
-      isExpandable_: {
-        type: Boolean,
-        computed: 'computeIsExpandable_(data)',
-      },
-    },
-
+  properties: {
     /**
-     * @private
-     * @return {boolean}
+     * The underlying ActivityGroup that provides data for the
+     * ActivityLogItem displayed.
+     * @type {!StreamItem}
      */
-    computeIsExpandable_: function() {
-      return this.hasPageUrl_() || this.hasArgs_() || this.hasWebRequestInfo_();
-    },
+    data: Object,
 
-    /**
-     * @private
-     * @return {string}
-     */
-    getFormattedTime_: function() {
-      // Format the activity's time to HH:MM:SS.mmm format. Use ToLocaleString
-      // for HH:MM:SS and padLeft for milliseconds.
-      const activityDate = new Date(this.data.timestamp);
-      const timeString = activityDate.toLocaleTimeString(undefined, {
-        hour12: false,
-        hour: '2-digit',
-        minute: '2-digit',
-        second: '2-digit',
-      });
-
-      const ms = activityDate.getMilliseconds().toString().padStart(3, '0');
-      return `${timeString}.${ms}`;
-    },
-
-    /**
-     * @private
-     * @return {boolean}
-     */
-    hasPageUrl_: function() {
-      return !!this.data.pageUrl;
-    },
-
-    /**
-     * @private
-     * @return {boolean}
-     */
-    hasArgs_: function() {
-      return this.argsList_.length > 0;
-    },
-
-    /**
-     * @private
-     * @return {boolean}
-     */
-    hasWebRequestInfo_: function() {
-      return !!this.data.webRequestInfo && this.data.webRequestInfo != '{}';
-    },
-
-    /**
-     * @private
-     * @return {!Array<!StreamArgItem>}
-     */
-    computeArgsList_: function() {
-      const parsedArgs = JSON.parse(this.data.args);
-      if (!Array.isArray(parsedArgs)) {
-        return [];
-      }
-
-      // Replace occurrences AFTER parsing then stringifying as the JSON
-      // serializer on the C++ side escapes certain characters such as '<' and
-      // parsing un-escapes these characters.
-      // See EscapeSpecialCodePoint in base/json/string_escape.cc.
-      return parsedArgs.map(
-          (arg, i) => ({
-            arg: JSON.stringify(arg).replace(
-                ARG_URL_PLACEHOLDER_REGEX, `"${this.data.argUrl}"`),
-            index: i + 1,
-          }));
+    /** @private {!Array<!StreamArgItem>} */
+    argsList_: {
+      type: Array,
+      computed: 'computeArgsList_(data.args)',
     },
 
     /** @private */
-    onExpandClick_: function() {
-      if (this.isExpandable_) {
-        this.set('data.expanded', !this.data.expanded);
-        this.fire('resize-stream');
-      }
+    isExpandable_: {
+      type: Boolean,
+      computed: 'computeIsExpandable_(data)',
     },
-  });
+  },
+
+  /**
+   * @private
+   * @return {boolean}
+   */
+  computeIsExpandable_: function() {
+    return this.hasPageUrl_() || this.hasArgs_() || this.hasWebRequestInfo_();
+  },
+
+  /**
+   * @private
+   * @return {string}
+   */
+  getFormattedTime_: function() {
+    // Format the activity's time to HH:MM:SS.mmm format. Use ToLocaleString
+    // for HH:MM:SS and padLeft for milliseconds.
+    const activityDate = new Date(this.data.timestamp);
+    const timeString = activityDate.toLocaleTimeString(undefined, {
+      hour12: false,
+      hour: '2-digit',
+      minute: '2-digit',
+      second: '2-digit',
+    });
+
+    const ms = activityDate.getMilliseconds().toString().padStart(3, '0');
+    return `${timeString}.${ms}`;
+  },
+
+  /**
+   * @private
+   * @return {boolean}
+   */
+  hasPageUrl_: function() {
+    return !!this.data.pageUrl;
+  },
+
+  /**
+   * @private
+   * @return {boolean}
+   */
+  hasArgs_: function() {
+    return this.argsList_.length > 0;
+  },
+
+  /**
+   * @private
+   * @return {boolean}
+   */
+  hasWebRequestInfo_: function() {
+    return !!this.data.webRequestInfo && this.data.webRequestInfo != '{}';
+  },
+
+  /**
+   * @private
+   * @return {!Array<!StreamArgItem>}
+   */
+  computeArgsList_: function() {
+    const parsedArgs = JSON.parse(this.data.args);
+    if (!Array.isArray(parsedArgs)) {
+      return [];
+    }
+
+    // Replace occurrences AFTER parsing then stringifying as the JSON
+    // serializer on the C++ side escapes certain characters such as '<' and
+    // parsing un-escapes these characters.
+    // See EscapeSpecialCodePoint in base/json/string_escape.cc.
+    return parsedArgs.map(
+        (arg, i) => ({
+          arg: JSON.stringify(arg).replace(
+              ARG_URL_PLACEHOLDER_REGEX, `"${this.data.argUrl}"`),
+          index: i + 1,
+        }));
+  },
+
+  /** @private */
+  onExpandClick_: function() {
+    if (this.isExpandable_) {
+      this.set('data.expanded', !this.data.expanded);
+      this.fire('resize-stream');
+    }
+  },
+});
diff --git a/chrome/browser/resources/extensions/code_section.js b/chrome/browser/resources/extensions/code_section.js
index c8406113..9a24dd3 100644
--- a/chrome/browser/resources/extensions/code_section.js
+++ b/chrome/browser/resources/extensions/code_section.js
@@ -12,192 +12,192 @@
 import {html, Polymer} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
 
 
+/**
+ * @param {number} totalCount
+ * @param {number} oppositeCount
+ * @return {number}
+ */
+function visibleLineCount(totalCount, oppositeCount) {
+  // We limit the number of lines shown for DOM performance.
+  const MAX_VISIBLE_LINES = 1000;
+  const max =
+      Math.max(MAX_VISIBLE_LINES / 2, MAX_VISIBLE_LINES - oppositeCount);
+  return Math.min(max, totalCount);
+}
+
+Polymer({
+  is: 'extensions-code-section',
+
+  _template: html`{__html_template__}`,
+
+  behaviors: [I18nBehavior],
+
+  properties: {
+    /**
+     * The code this object is displaying.
+     * @type {?chrome.developerPrivate.RequestFileSourceResponse}
+     */
+    code: {
+      type: Object,
+      value: null,
+    },
+
+    isActive: Boolean,
+
+    /** @private Highlighted code. */
+    highlighted_: String,
+
+    /** @private Code before the highlighted section. */
+    before_: String,
+
+    /** @private Code after the highlighted section. */
+    after_: String,
+
+    /** @private */
+    showNoCode_: {
+      type: Boolean,
+      computed: 'computeShowNoCode_(isActive, highlighted_)',
+    },
+
+    /** @private Description for the highlighted section. */
+    highlightDescription_: String,
+
+    /** @private */
+    lineNumbers_: String,
+
+    /** @private */
+    truncatedBefore_: Number,
+
+    /** @private */
+    truncatedAfter_: Number,
+
+    /**
+     * The string to display if no |code| is set (e.g. because we couldn't
+     * load the relevant source file).
+     * @type {string}
+     */
+    couldNotDisplayCode: String,
+  },
+
+  observers: [
+    'onCodeChanged_(code.*)',
+  ],
+
   /**
-   * @param {number} totalCount
-   * @param {number} oppositeCount
-   * @return {number}
+   * @private
    */
-  function visibleLineCount(totalCount, oppositeCount) {
-    // We limit the number of lines shown for DOM performance.
-    const MAX_VISIBLE_LINES = 1000;
-    const max =
-        Math.max(MAX_VISIBLE_LINES / 2, MAX_VISIBLE_LINES - oppositeCount);
-    return Math.min(max, totalCount);
-  }
+  onCodeChanged_: function() {
+    if (!this.code ||
+        (!this.code.beforeHighlight && !this.code.highlight &&
+         !this.code.afterHighlight)) {
+      this.highlighted_ = '';
+      this.highlightDescription_ = '';
+      this.before_ = '';
+      this.after_ = '';
+      this.lineNumbers_ = '';
+      return;
+    }
 
-  Polymer({
-    is: 'extensions-code-section',
+    const before = this.code.beforeHighlight;
+    const highlight = this.code.highlight;
+    const after = this.code.afterHighlight;
 
-    _template: html`{__html_template__}`,
+    const linesBefore = before ? before.split('\n') : [];
+    const linesAfter = after ? after.split('\n') : [];
+    const visibleLineCountBefore =
+        visibleLineCount(linesBefore.length, linesAfter.length);
+    const visibleLineCountAfter =
+        visibleLineCount(linesAfter.length, linesBefore.length);
 
-    behaviors: [I18nBehavior],
+    const visibleBefore =
+        linesBefore.slice(linesBefore.length - visibleLineCountBefore)
+            .join('\n');
+    let visibleAfter = linesAfter.slice(0, visibleLineCountAfter).join('\n');
+    // If the last character is a \n, force it to be rendered.
+    if (visibleAfter.charAt(visibleAfter.length - 1) == '\n') {
+      visibleAfter += ' ';
+    }
 
-    properties: {
-      /**
-       * The code this object is displaying.
-       * @type {?chrome.developerPrivate.RequestFileSourceResponse}
-       */
-      code: {
-        type: Object,
-        value: null,
-      },
+    this.highlighted_ = highlight;
+    this.highlightDescription_ = this.getAccessibilityHighlightDescription_(
+        linesBefore.length, highlight.split('\n').length);
+    this.before_ = visibleBefore;
+    this.after_ = visibleAfter;
+    this.truncatedBefore_ = linesBefore.length - visibleLineCountBefore;
+    this.truncatedAfter_ = linesAfter.length - visibleLineCountAfter;
 
-      isActive: Boolean,
+    const visibleCode = visibleBefore + highlight + visibleAfter;
 
-      /** @private Highlighted code. */
-      highlighted_: String,
+    this.setLineNumbers_(
+        this.truncatedBefore_ + 1,
+        this.truncatedBefore_ + visibleCode.split('\n').length);
+    this.scrollToHighlight_(visibleLineCountBefore);
+  },
 
-      /** @private Code before the highlighted section. */
-      before_: String,
+  /**
+   * @param {number} lineCount
+   * @param {string} stringSingular
+   * @param {string} stringPluralTemplate
+   * @return {string}
+   * @private
+   */
+  getLinesNotShownLabel_(lineCount, stringSingular, stringPluralTemplate) {
+    return lineCount == 1 ?
+        stringSingular :
+        loadTimeData.substituteString(stringPluralTemplate, lineCount);
+  },
 
-      /** @private Code after the highlighted section. */
-      after_: String,
+  /**
+   * @param {number} start
+   * @param {number} end
+   * @private
+   */
+  setLineNumbers_: function(start, end) {
+    let lineNumbers = '';
+    for (let i = start; i <= end; ++i) {
+      lineNumbers += i + '\n';
+    }
 
-      /** @private */
-      showNoCode_: {
-        type: Boolean,
-        computed: 'computeShowNoCode_(isActive, highlighted_)',
-      },
+    this.lineNumbers_ = lineNumbers;
+  },
 
-      /** @private Description for the highlighted section. */
-      highlightDescription_: String,
+  /**
+   * @param {number} linesBeforeHighlight
+   * @private
+   */
+  scrollToHighlight_: function(linesBeforeHighlight) {
+    const CSS_LINE_HEIGHT = 20;
 
-      /** @private */
-      lineNumbers_: String,
+    // Count how many pixels is above the highlighted code.
+    const highlightTop = linesBeforeHighlight * CSS_LINE_HEIGHT;
 
-      /** @private */
-      truncatedBefore_: Number,
+    // Find the position to show the highlight roughly in the middle.
+    const targetTop = highlightTop - this.clientHeight * 0.5;
 
-      /** @private */
-      truncatedAfter_: Number,
+    this.$['scroll-container'].scrollTo({top: targetTop});
+  },
 
-      /**
-       * The string to display if no |code| is set (e.g. because we couldn't
-       * load the relevant source file).
-       * @type {string}
-       */
-      couldNotDisplayCode: String,
-    },
+  /**
+   * @param {number} lineStart
+   * @param {number} numLines
+   * @return {string}
+   * @private
+   */
+  getAccessibilityHighlightDescription_: function(lineStart, numLines) {
+    if (numLines > 1) {
+      return this.i18n(
+          'accessibilityErrorMultiLine', lineStart.toString(),
+          (lineStart + numLines - 1).toString());
+    } else {
+      return this.i18n('accessibilityErrorLine', lineStart.toString());
+    }
+  },
 
-    observers: [
-      'onCodeChanged_(code.*)',
-    ],
-
-    /**
-     * @private
-     */
-    onCodeChanged_: function() {
-      if (!this.code ||
-          (!this.code.beforeHighlight && !this.code.highlight &&
-           !this.code.afterHighlight)) {
-        this.highlighted_ = '';
-        this.highlightDescription_ = '';
-        this.before_ = '';
-        this.after_ = '';
-        this.lineNumbers_ = '';
-        return;
-      }
-
-      const before = this.code.beforeHighlight;
-      const highlight = this.code.highlight;
-      const after = this.code.afterHighlight;
-
-      const linesBefore = before ? before.split('\n') : [];
-      const linesAfter = after ? after.split('\n') : [];
-      const visibleLineCountBefore =
-          visibleLineCount(linesBefore.length, linesAfter.length);
-      const visibleLineCountAfter =
-          visibleLineCount(linesAfter.length, linesBefore.length);
-
-      const visibleBefore =
-          linesBefore.slice(linesBefore.length - visibleLineCountBefore)
-              .join('\n');
-      let visibleAfter = linesAfter.slice(0, visibleLineCountAfter).join('\n');
-      // If the last character is a \n, force it to be rendered.
-      if (visibleAfter.charAt(visibleAfter.length - 1) == '\n') {
-        visibleAfter += ' ';
-      }
-
-      this.highlighted_ = highlight;
-      this.highlightDescription_ = this.getAccessibilityHighlightDescription_(
-          linesBefore.length, highlight.split('\n').length);
-      this.before_ = visibleBefore;
-      this.after_ = visibleAfter;
-      this.truncatedBefore_ = linesBefore.length - visibleLineCountBefore;
-      this.truncatedAfter_ = linesAfter.length - visibleLineCountAfter;
-
-      const visibleCode = visibleBefore + highlight + visibleAfter;
-
-      this.setLineNumbers_(
-          this.truncatedBefore_ + 1,
-          this.truncatedBefore_ + visibleCode.split('\n').length);
-      this.scrollToHighlight_(visibleLineCountBefore);
-    },
-
-    /**
-     * @param {number} lineCount
-     * @param {string} stringSingular
-     * @param {string} stringPluralTemplate
-     * @return {string}
-     * @private
-     */
-    getLinesNotShownLabel_(lineCount, stringSingular, stringPluralTemplate) {
-      return lineCount == 1 ?
-          stringSingular :
-          loadTimeData.substituteString(stringPluralTemplate, lineCount);
-    },
-
-    /**
-     * @param {number} start
-     * @param {number} end
-     * @private
-     */
-    setLineNumbers_: function(start, end) {
-      let lineNumbers = '';
-      for (let i = start; i <= end; ++i) {
-        lineNumbers += i + '\n';
-      }
-
-      this.lineNumbers_ = lineNumbers;
-    },
-
-    /**
-     * @param {number} linesBeforeHighlight
-     * @private
-     */
-    scrollToHighlight_: function(linesBeforeHighlight) {
-      const CSS_LINE_HEIGHT = 20;
-
-      // Count how many pixels is above the highlighted code.
-      const highlightTop = linesBeforeHighlight * CSS_LINE_HEIGHT;
-
-      // Find the position to show the highlight roughly in the middle.
-      const targetTop = highlightTop - this.clientHeight * 0.5;
-
-      this.$['scroll-container'].scrollTo({top: targetTop});
-    },
-
-    /**
-     * @param {number} lineStart
-     * @param {number} numLines
-     * @return {string}
-     * @private
-     */
-    getAccessibilityHighlightDescription_: function(lineStart, numLines) {
-      if (numLines > 1) {
-        return this.i18n(
-            'accessibilityErrorMultiLine', lineStart.toString(),
-            (lineStart + numLines - 1).toString());
-      } else {
-        return this.i18n('accessibilityErrorLine', lineStart.toString());
-      }
-    },
-
-    /**
-     * @private
-     * @return {boolean}
-     */
-    computeShowNoCode_: function() {
-      return this.isActive && !this.highlighted_;
-    },
-  });
+  /**
+   * @private
+   * @return {boolean}
+   */
+  computeShowNoCode_: function() {
+    return this.isActive && !this.highlighted_;
+  },
+});
diff --git a/chrome/browser/resources/extensions/detail_view.js b/chrome/browser/resources/extensions/detail_view.js
index 1c33c0e..65dfba4 100644
--- a/chrome/browser/resources/extensions/detail_view.js
+++ b/chrome/browser/resources/extensions/detail_view.js
@@ -34,354 +34,351 @@
 import {computeInspectableViewLabel, getItemSource, getItemSourceString, isControlled, isEnabled, userCanChangeEnablement} from './item_util.js';
 import {navigation, Page} from './navigation_helper.js';
 
-  Polymer({
-    is: 'extensions-detail-view',
+Polymer({
+  is: 'extensions-detail-view',
 
-    _template: html`{__html_template__}`,
+  _template: html`{__html_template__}`,
 
-    behaviors: [
-      CrContainerShadowBehavior,
-      ItemBehavior,
-    ],
+  behaviors: [
+    CrContainerShadowBehavior,
+    ItemBehavior,
+  ],
 
-    properties: {
-      /**
-       * The underlying ExtensionInfo for the details being displayed.
-       * @type {!chrome.developerPrivate.ExtensionInfo}
-       */
-      data: Object,
-
-      /** @private */
-      size_: String,
-
-      /** @type {!ItemDelegate} */
-      delegate: Object,
-
-      /** Whether the user has enabled the UI's developer mode. */
-      inDevMode: Boolean,
-
-      /** Whether "allow in incognito" option should be shown. */
-      incognitoAvailable: Boolean,
-
-      /** Whether "View Activity Log" link should be shown. */
-      showActivityLog: Boolean,
-
-      /** Whether the user navigated to this page from the activity log page. */
-      fromActivityLog: Boolean,
-    },
-
-    observers: [
-      'onItemIdChanged_(data.id, delegate)',
-    ],
-
-    listeners: {
-      'view-enter-start': 'onViewEnterStart_',
-    },
-
+  properties: {
     /**
-     * Focuses the extensions options button. This should be used after the
-     * dialog closes.
+     * The underlying ExtensionInfo for the details being displayed.
+     * @type {!chrome.developerPrivate.ExtensionInfo}
      */
-    focusOptionsButton: function() {
-      this.$$('#extensions-options').focus();
-    },
-
-    /**
-     * Focuses the back button when page is loaded.
-     * @private
-     */
-    onViewEnterStart_: function() {
-      const elementToFocus = this.fromActivityLog ?
-          this.$.extensionsActivityLogLink :
-          this.$.closeButton;
-
-      afterNextRender(this, () => focusWithoutInk(elementToFocus));
-    },
+    data: Object,
 
     /** @private */
-    onItemIdChanged_: function() {
-      // Clear the size, since this view is reused, such that no obsolete size
-      // is displayed.:
-      this.size_ = '';
-      this.delegate.getExtensionSize(this.data.id).then(size => {
-        this.size_ = size;
-      });
-    },
+    size_: String,
 
-    /** @private */
-    onActivityLogTap_: function() {
-      navigation.navigateTo(
-          {page: Page.ACTIVITY_LOG, extensionId: this.data.id});
-    },
+    /** @type {!ItemDelegate} */
+    delegate: Object,
 
-    /**
-     * @param {string} description
-     * @param {string} fallback
-     * @return {string}
-     * @private
-     */
-    getDescription_: function(description, fallback) {
-      return description || fallback;
-    },
+    /** Whether the user has enabled the UI's developer mode. */
+    inDevMode: Boolean,
 
-    /** @private */
-    onCloseButtonTap_: function() {
-      navigation.navigateTo({page: Page.LIST});
-    },
+    /** Whether "allow in incognito" option should be shown. */
+    incognitoAvailable: Boolean,
 
-    /**
-     * @return {boolean}
-     * @private
-     */
-    isControlled_: function() {
-      return isControlled(this.data);
-    },
+    /** Whether "View Activity Log" link should be shown. */
+    showActivityLog: Boolean,
 
-    /**
-     * @return {boolean}
-     * @private
-     */
-    isEnabled_: function() {
-      return isEnabled(this.data.state);
-    },
+    /** Whether the user navigated to this page from the activity log page. */
+    fromActivityLog: Boolean,
+  },
 
-    /**
-     * @return {boolean}
-     * @private
-     */
-    isEnableToggleEnabled_: function() {
-      return userCanChangeEnablement(this.data);
-    },
+  observers: [
+    'onItemIdChanged_(data.id, delegate)',
+  ],
 
-    /**
-     * Returns true if the extension is in the terminated state.
-     * @return {boolean}
-     * @private
-     */
-    isTerminated_: function() {
-      return this.data.state ==
-          chrome.developerPrivate.ExtensionState.TERMINATED;
-    },
+  listeners: {
+    'view-enter-start': 'onViewEnterStart_',
+  },
 
-    /**
-     * @return {boolean}
-     * @private
-     */
-    hasDependentExtensions_: function() {
-      return this.data.dependentExtensions.length > 0;
-    },
+  /**
+   * Focuses the extensions options button. This should be used after the
+   * dialog closes.
+   */
+  focusOptionsButton: function() {
+    this.$$('#extensions-options').focus();
+  },
 
-    /**
-     * @return {boolean}
-     * @private
-     */
-    hasWarnings_: function() {
-      return this.data.disableReasons.corruptInstall ||
-          this.data.disableReasons.suspiciousInstall ||
-          this.data.disableReasons.updateRequired ||
-          !!this.data.blacklistText || this.data.runtimeWarnings.length > 0;
-    },
+  /**
+   * Focuses the back button when page is loaded.
+   * @private
+   */
+  onViewEnterStart_: function() {
+    const elementToFocus = this.fromActivityLog ?
+        this.$.extensionsActivityLogLink :
+        this.$.closeButton;
 
-    /**
-     * @return {string}
-     * @private
-     */
-    computeEnabledStyle_: function() {
-      return this.isEnabled_() ? 'enabled-text' : '';
-    },
+    afterNextRender(this, () => focusWithoutInk(elementToFocus));
+  },
 
-    /**
-     * @param {!chrome.developerPrivate.ExtensionState} state
-     * @param {string} onText
-     * @param {string} offText
-     * @return {string}
-     * @private
-     */
-    computeEnabledText_: function(state, onText, offText) {
-      // TODO(devlin): Get the full spectrum of these strings from bettes.
-      return isEnabled(state) ? onText : offText;
-    },
+  /** @private */
+  onItemIdChanged_: function() {
+    // Clear the size, since this view is reused, such that no obsolete size
+    // is displayed.:
+    this.size_ = '';
+    this.delegate.getExtensionSize(this.data.id).then(size => {
+      this.size_ = size;
+    });
+  },
 
-    /**
-     * @param {!chrome.developerPrivate.ExtensionView} view
-     * @return {string}
-     * @private
-     */
-    computeInspectLabel_: function(view) {
-      return computeInspectableViewLabel(view);
-    },
+  /** @private */
+  onActivityLogTap_: function() {
+    navigation.navigateTo({page: Page.ACTIVITY_LOG, extensionId: this.data.id});
+  },
 
-    /**
-     * @return {boolean}
-     * @private
-     */
-    shouldShowOptionsLink_: function() {
-      return !!this.data.optionsPage;
-    },
+  /**
+   * @param {string} description
+   * @param {string} fallback
+   * @return {string}
+   * @private
+   */
+  getDescription_: function(description, fallback) {
+    return description || fallback;
+  },
 
-    /**
-     * @return {boolean}
-     * @private
-     */
-    shouldShowOptionsSection_: function() {
-      return this.data.incognitoAccess.isEnabled ||
-          this.data.fileAccess.isEnabled || this.data.errorCollection.isEnabled;
-    },
+  /** @private */
+  onCloseButtonTap_: function() {
+    navigation.navigateTo({page: Page.LIST});
+  },
 
-    /**
-     * @return {boolean}
-     * @private
-     */
-    shouldShowIncognitoOption_: function() {
-      return this.data.incognitoAccess.isEnabled && this.incognitoAvailable;
-    },
+  /**
+   * @return {boolean}
+   * @private
+   */
+  isControlled_: function() {
+    return isControlled(this.data);
+  },
 
-    /** @private */
-    onEnableChange_: function() {
-      this.delegate.setItemEnabled(
-          this.data.id, this.$['enable-toggle'].checked);
-    },
+  /**
+   * @return {boolean}
+   * @private
+   */
+  isEnabled_: function() {
+    return isEnabled(this.data.state);
+  },
 
-    /**
-     * @param {!{model: !{item: !chrome.developerPrivate.ExtensionView}}} e
-     * @private
-     */
-    onInspectTap_: function(e) {
-      this.delegate.inspectItemView(this.data.id, e.model.item);
-    },
+  /**
+   * @return {boolean}
+   * @private
+   */
+  isEnableToggleEnabled_: function() {
+    return userCanChangeEnablement(this.data);
+  },
 
-    /** @private */
-    onExtensionOptionsTap_: function() {
-      this.delegate.showItemOptionsPage(this.data);
-    },
+  /**
+   * Returns true if the extension is in the terminated state.
+   * @return {boolean}
+   * @private
+   */
+  isTerminated_: function() {
+    return this.data.state == chrome.developerPrivate.ExtensionState.TERMINATED;
+  },
 
-    /** @private */
-    onReloadTap_: function() {
-      this.delegate.reloadItem(this.data.id).catch(loadError => {
-        this.fire('load-error', loadError);
-      });
-    },
+  /**
+   * @return {boolean}
+   * @private
+   */
+  hasDependentExtensions_: function() {
+    return this.data.dependentExtensions.length > 0;
+  },
 
-    /** @private */
-    onRemoveTap_: function() {
-      this.delegate.deleteItem(this.data.id);
-    },
+  /**
+   * @return {boolean}
+   * @private
+   */
+  hasWarnings_: function() {
+    return this.data.disableReasons.corruptInstall ||
+        this.data.disableReasons.suspiciousInstall ||
+        this.data.disableReasons.updateRequired || !!this.data.blacklistText ||
+        this.data.runtimeWarnings.length > 0;
+  },
 
-    /** @private */
-    onRepairTap_: function() {
-      this.delegate.repairItem(this.data.id);
-    },
+  /**
+   * @return {string}
+   * @private
+   */
+  computeEnabledStyle_: function() {
+    return this.isEnabled_() ? 'enabled-text' : '';
+  },
 
-    /** @private */
-    onLoadPathTap_: function() {
-      this.delegate.showInFolder(this.data.id);
-    },
+  /**
+   * @param {!chrome.developerPrivate.ExtensionState} state
+   * @param {string} onText
+   * @param {string} offText
+   * @return {string}
+   * @private
+   */
+  computeEnabledText_: function(state, onText, offText) {
+    // TODO(devlin): Get the full spectrum of these strings from bettes.
+    return isEnabled(state) ? onText : offText;
+  },
 
-    /** @private */
-    onAllowIncognitoChange_: function() {
-      this.delegate.setItemAllowedIncognito(
-          this.data.id, this.$$('#allow-incognito').checked);
-    },
+  /**
+   * @param {!chrome.developerPrivate.ExtensionView} view
+   * @return {string}
+   * @private
+   */
+  computeInspectLabel_: function(view) {
+    return computeInspectableViewLabel(view);
+  },
 
-    /** @private */
-    onAllowOnFileUrlsChange_: function() {
-      this.delegate.setItemAllowedOnFileUrls(
-          this.data.id, this.$$('#allow-on-file-urls').checked);
-    },
+  /**
+   * @return {boolean}
+   * @private
+   */
+  shouldShowOptionsLink_: function() {
+    return !!this.data.optionsPage;
+  },
 
-    /** @private */
-    onCollectErrorsChange_: function() {
-      this.delegate.setItemCollectsErrors(
-          this.data.id, this.$$('#collect-errors').checked);
-    },
+  /**
+   * @return {boolean}
+   * @private
+   */
+  shouldShowOptionsSection_: function() {
+    return this.data.incognitoAccess.isEnabled ||
+        this.data.fileAccess.isEnabled || this.data.errorCollection.isEnabled;
+  },
 
-    /** @private */
-    onExtensionWebSiteTap_: function() {
-      this.delegate.openUrl(this.data.manifestHomePageUrl);
-    },
+  /**
+   * @return {boolean}
+   * @private
+   */
+  shouldShowIncognitoOption_: function() {
+    return this.data.incognitoAccess.isEnabled && this.incognitoAvailable;
+  },
 
-    /** @private */
-    onViewInStoreTap_: function() {
-      this.delegate.openUrl(this.data.webStoreUrl);
-    },
+  /** @private */
+  onEnableChange_: function() {
+    this.delegate.setItemEnabled(this.data.id, this.$['enable-toggle'].checked);
+  },
 
-    /**
-     * @param {!chrome.developerPrivate.DependentExtension} item
-     * @return {string}
-     * @private
-     */
-    computeDependentEntry_: function(item) {
-      return loadTimeData.getStringF('itemDependentEntry', item.name, item.id);
-    },
+  /**
+   * @param {!{model: !{item: !chrome.developerPrivate.ExtensionView}}} e
+   * @private
+   */
+  onInspectTap_: function(e) {
+    this.delegate.inspectItemView(this.data.id, e.model.item);
+  },
 
-    /**
-     * @return {string}
-     * @private
-     */
-    computeSourceString_: function() {
-      return this.data.locationText ||
-          getItemSourceString(getItemSource(this.data));
-    },
+  /** @private */
+  onExtensionOptionsTap_: function() {
+    this.delegate.showItemOptionsPage(this.data);
+  },
 
-    /**
-     * @param {chrome.developerPrivate.ControllerType} type
-     * @return {string}
-     * @private
-     */
-    getIndicatorIcon_: function(type) {
-      switch (type) {
-        case 'POLICY':
-          return 'cr20:domain';
-        case 'CHILD_CUSTODIAN':
-          return 'cr:account-child-invert';
-        case 'SUPERVISED_USER_CUSTODIAN':
-          return 'cr:supervisor-account';
-        default:
-          return '';
-      }
-    },
+  /** @private */
+  onReloadTap_: function() {
+    this.delegate.reloadItem(this.data.id).catch(loadError => {
+      this.fire('load-error', loadError);
+    });
+  },
 
-    /**
-     * @return {boolean}
-     * @private
-     */
-    hasPermissions_: function() {
-      return this.data.permissions.simplePermissions.length > 0 ||
-          this.hasRuntimeHostPermissions_();
-    },
+  /** @private */
+  onRemoveTap_: function() {
+    this.delegate.deleteItem(this.data.id);
+  },
 
-    /**
-     * @return {boolean}
-     * @private
-     */
-    hasRuntimeHostPermissions_: function() {
-      return !!this.data.permissions.runtimeHostPermissions;
-    },
+  /** @private */
+  onRepairTap_: function() {
+    this.delegate.repairItem(this.data.id);
+  },
 
-    /**
-     * @return {boolean}
-     * @private
-     */
-    showSiteAccessContent_: function() {
-      return this.showFreeformRuntimeHostPermissions_() ||
-          this.showHostPermissionsToggleList_();
-    },
+  /** @private */
+  onLoadPathTap_: function() {
+    this.delegate.showInFolder(this.data.id);
+  },
 
-    /**
-     * @return {boolean}
-     * @private
-     */
-    showFreeformRuntimeHostPermissions_: function() {
-      return this.hasRuntimeHostPermissions_() &&
-          this.data.permissions.runtimeHostPermissions.hasAllHosts;
-    },
+  /** @private */
+  onAllowIncognitoChange_: function() {
+    this.delegate.setItemAllowedIncognito(
+        this.data.id, this.$$('#allow-incognito').checked);
+  },
 
-    /**
-     * @return {boolean}
-     * @private
-     */
-    showHostPermissionsToggleList_: function() {
-      return this.hasRuntimeHostPermissions_() &&
-          !this.data.permissions.runtimeHostPermissions.hasAllHosts;
-    },
-  });
+  /** @private */
+  onAllowOnFileUrlsChange_: function() {
+    this.delegate.setItemAllowedOnFileUrls(
+        this.data.id, this.$$('#allow-on-file-urls').checked);
+  },
+
+  /** @private */
+  onCollectErrorsChange_: function() {
+    this.delegate.setItemCollectsErrors(
+        this.data.id, this.$$('#collect-errors').checked);
+  },
+
+  /** @private */
+  onExtensionWebSiteTap_: function() {
+    this.delegate.openUrl(this.data.manifestHomePageUrl);
+  },
+
+  /** @private */
+  onViewInStoreTap_: function() {
+    this.delegate.openUrl(this.data.webStoreUrl);
+  },
+
+  /**
+   * @param {!chrome.developerPrivate.DependentExtension} item
+   * @return {string}
+   * @private
+   */
+  computeDependentEntry_: function(item) {
+    return loadTimeData.getStringF('itemDependentEntry', item.name, item.id);
+  },
+
+  /**
+   * @return {string}
+   * @private
+   */
+  computeSourceString_: function() {
+    return this.data.locationText ||
+        getItemSourceString(getItemSource(this.data));
+  },
+
+  /**
+   * @param {chrome.developerPrivate.ControllerType} type
+   * @return {string}
+   * @private
+   */
+  getIndicatorIcon_: function(type) {
+    switch (type) {
+      case 'POLICY':
+        return 'cr20:domain';
+      case 'CHILD_CUSTODIAN':
+        return 'cr:account-child-invert';
+      case 'SUPERVISED_USER_CUSTODIAN':
+        return 'cr:supervisor-account';
+      default:
+        return '';
+    }
+  },
+
+  /**
+   * @return {boolean}
+   * @private
+   */
+  hasPermissions_: function() {
+    return this.data.permissions.simplePermissions.length > 0 ||
+        this.hasRuntimeHostPermissions_();
+  },
+
+  /**
+   * @return {boolean}
+   * @private
+   */
+  hasRuntimeHostPermissions_: function() {
+    return !!this.data.permissions.runtimeHostPermissions;
+  },
+
+  /**
+   * @return {boolean}
+   * @private
+   */
+  showSiteAccessContent_: function() {
+    return this.showFreeformRuntimeHostPermissions_() ||
+        this.showHostPermissionsToggleList_();
+  },
+
+  /**
+   * @return {boolean}
+   * @private
+   */
+  showFreeformRuntimeHostPermissions_: function() {
+    return this.hasRuntimeHostPermissions_() &&
+        this.data.permissions.runtimeHostPermissions.hasAllHosts;
+  },
+
+  /**
+   * @return {boolean}
+   * @private
+   */
+  showHostPermissionsToggleList_: function() {
+    return this.hasRuntimeHostPermissions_() &&
+        !this.data.permissions.runtimeHostPermissions.hasAllHosts;
+  },
+});
diff --git a/chrome/browser/resources/extensions/drag_and_drop_handler.js b/chrome/browser/resources/extensions/drag_and_drop_handler.js
index b05bbbf9..a6bfab3 100644
--- a/chrome/browser/resources/extensions/drag_and_drop_handler.js
+++ b/chrome/browser/resources/extensions/drag_and_drop_handler.js
@@ -7,100 +7,98 @@
 import {Service} from './service.js';
 
 
-  /** @implements DragWrapperDelegate */
-  export class DragAndDropHandler {
-    /**
-     * @param {boolean} dragEnabled
-     * @param {!EventTarget} target
-     */
-    constructor(dragEnabled, target) {
-      this.dragEnabled = dragEnabled;
+/** @implements DragWrapperDelegate */
+export class DragAndDropHandler {
+  /**
+   * @param {boolean} dragEnabled
+   * @param {!EventTarget} target
+   */
+  constructor(dragEnabled, target) {
+    this.dragEnabled = dragEnabled;
 
-      /** @private {!EventTarget} */
-      this.eventTarget_ = target;
+    /** @private {!EventTarget} */
+    this.eventTarget_ = target;
+  }
+
+  /** @override */
+  shouldAcceptDrag(e) {
+    // External Extension installation can be disabled globally, e.g. while a
+    // different overlay is already showing.
+    if (!this.dragEnabled) {
+      return false;
     }
 
-    /** @override */
-    shouldAcceptDrag(e) {
-      // External Extension installation can be disabled globally, e.g. while a
-      // different overlay is already showing.
-      if (!this.dragEnabled) {
-        return false;
-      }
+    // We can't access filenames during the 'dragenter' event, so we have to
+    // wait until 'drop' to decide whether to do something with the file or
+    // not.
+    // See: http://www.w3.org/TR/2011/WD-html5-20110113/dnd.html#concept-dnd-p
+    return !!e.dataTransfer.types && e.dataTransfer.types.indexOf('Files') > -1;
+  }
 
-      // We can't access filenames during the 'dragenter' event, so we have to
-      // wait until 'drop' to decide whether to do something with the file or
-      // not.
-      // See: http://www.w3.org/TR/2011/WD-html5-20110113/dnd.html#concept-dnd-p
-      return !!e.dataTransfer.types &&
-          e.dataTransfer.types.indexOf('Files') > -1;
+  /** @override */
+  doDragEnter() {
+    Service.getInstance().notifyDragInstallInProgress();
+    this.eventTarget_.dispatchEvent(new CustomEvent('extension-drag-started'));
+  }
+
+  /** @override */
+  doDragLeave() {
+    this.fireDragEnded_();
+  }
+
+  /** @override */
+  doDragOver(e) {
+    e.preventDefault();
+  }
+
+  /** @override */
+  doDrop(e) {
+    this.fireDragEnded_();
+    if (e.dataTransfer.files.length != 1) {
+      return;
     }
 
-    /** @override */
-    doDragEnter() {
-      Service.getInstance().notifyDragInstallInProgress();
-      this.eventTarget_.dispatchEvent(
-          new CustomEvent('extension-drag-started'));
+    let handled = false;
+
+    // Files lack a check if they're a directory, but we can find out through
+    // its item entry.
+    const item = e.dataTransfer.items[0];
+    if (item.kind === 'file' && item.webkitGetAsEntry().isDirectory) {
+      handled = true;
+      this.handleDirectoryDrop_();
+    } else if (/\.(crx|user\.js|zip)$/i.test(e.dataTransfer.files[0].name)) {
+      // Only process files that look like extensions. Other files should
+      // navigate the browser normally.
+      handled = true;
+      this.handleFileDrop_();
     }
 
-    /** @override */
-    doDragLeave() {
-      this.fireDragEnded_();
-    }
-
-    /** @override */
-    doDragOver(e) {
+    if (handled) {
       e.preventDefault();
     }
-
-    /** @override */
-    doDrop(e) {
-      this.fireDragEnded_();
-      if (e.dataTransfer.files.length != 1) {
-        return;
-      }
-
-      let handled = false;
-
-      // Files lack a check if they're a directory, but we can find out through
-      // its item entry.
-      const item = e.dataTransfer.items[0];
-      if (item.kind === 'file' && item.webkitGetAsEntry().isDirectory) {
-        handled = true;
-        this.handleDirectoryDrop_();
-      } else if (/\.(crx|user\.js|zip)$/i.test(e.dataTransfer.files[0].name)) {
-        // Only process files that look like extensions. Other files should
-        // navigate the browser normally.
-        handled = true;
-        this.handleFileDrop_();
-      }
-
-      if (handled) {
-        e.preventDefault();
-      }
-    }
-
-    /**
-     * Handles a dropped file.
-     * @private
-     */
-    handleFileDrop_() {
-      Service.getInstance().installDroppedFile();
-    }
-
-    /**
-     * Handles a dropped directory.
-     * @private
-     */
-    handleDirectoryDrop_() {
-      Service.getInstance().loadUnpackedFromDrag().catch(loadError => {
-        this.eventTarget_.dispatchEvent(new CustomEvent(
-            'drag-and-drop-load-error', {detail: loadError}));
-      });
-    }
-
-    /** @private */
-    fireDragEnded_() {
-      this.eventTarget_.dispatchEvent(new CustomEvent('extension-drag-ended'));
-    }
   }
+
+  /**
+   * Handles a dropped file.
+   * @private
+   */
+  handleFileDrop_() {
+    Service.getInstance().installDroppedFile();
+  }
+
+  /**
+   * Handles a dropped directory.
+   * @private
+   */
+  handleDirectoryDrop_() {
+    Service.getInstance().loadUnpackedFromDrag().catch(loadError => {
+      this.eventTarget_.dispatchEvent(
+          new CustomEvent('drag-and-drop-load-error', {detail: loadError}));
+    });
+  }
+
+  /** @private */
+  fireDragEnded_() {
+    this.eventTarget_.dispatchEvent(new CustomEvent('extension-drag-ended'));
+  }
+}
diff --git a/chrome/browser/resources/extensions/error_page.js b/chrome/browser/resources/extensions/error_page.js
index a1d876b..1da980e 100644
--- a/chrome/browser/resources/extensions/error_page.js
+++ b/chrome/browser/resources/extensions/error_page.js
@@ -28,415 +28,414 @@
 /** @typedef {chrome.developerPrivate.RuntimeError} */
 let RuntimeError;
 
-  /** @interface */
-  export class ErrorPageDelegate {
-    /**
-     * @param {string} extensionId
-     * @param {!Array<number>=} errorIds
-     * @param {chrome.developerPrivate.ErrorType=} type
-     */
-    deleteErrors(extensionId, errorIds, type) {}
-
-    /**
-     * @param {chrome.developerPrivate.RequestFileSourceProperties} args
-     * @return {!Promise<!chrome.developerPrivate.RequestFileSourceResponse>}
-     */
-    requestFileSource(args) {}
-  }
-
+/** @interface */
+export class ErrorPageDelegate {
   /**
-   * Get the URL relative to the main extension url. If the url is
-   * unassociated with the extension, this will be the full url.
-   * @param {string} url
-   * @param {?(ManifestError|RuntimeError)} error
-   * @return {string}
+   * @param {string} extensionId
+   * @param {!Array<number>=} errorIds
+   * @param {chrome.developerPrivate.ErrorType=} type
    */
-  function getRelativeUrl(url, error) {
-    const fullUrl = 'chrome-extension://' + error.extensionId + '/';
-    return url.startsWith(fullUrl) ? url.substring(fullUrl.length) : url;
-  }
+  deleteErrors(extensionId, errorIds, type) {}
 
   /**
-   * Given 3 strings, this function returns the correct one for the type of
-   * error that |item| is.
-   * @param {!ManifestError|!RuntimeError} item
-   * @param {string} log
-   * @param {string} warn
-   * @param {string} error
+   * @param {chrome.developerPrivate.RequestFileSourceProperties} args
+   * @return {!Promise<!chrome.developerPrivate.RequestFileSourceResponse>}
+   */
+  requestFileSource(args) {}
+}
+
+/**
+ * Get the URL relative to the main extension url. If the url is
+ * unassociated with the extension, this will be the full url.
+ * @param {string} url
+ * @param {?(ManifestError|RuntimeError)} error
+ * @return {string}
+ */
+function getRelativeUrl(url, error) {
+  const fullUrl = 'chrome-extension://' + error.extensionId + '/';
+  return url.startsWith(fullUrl) ? url.substring(fullUrl.length) : url;
+}
+
+/**
+ * Given 3 strings, this function returns the correct one for the type of
+ * error that |item| is.
+ * @param {!ManifestError|!RuntimeError} item
+ * @param {string} log
+ * @param {string} warn
+ * @param {string} error
+ * @return {string}
+ * @private
+ */
+function getErrorSeverityText_(item, log, warn, error) {
+  if (item.type == chrome.developerPrivate.ErrorType.RUNTIME) {
+    switch (item.severity) {
+      case chrome.developerPrivate.ErrorLevel.LOG:
+        return log;
+      case chrome.developerPrivate.ErrorLevel.WARN:
+        return warn;
+      case chrome.developerPrivate.ErrorLevel.ERROR:
+        return error;
+    }
+    assertNotReached();
+  }
+  assert(item.type == chrome.developerPrivate.ErrorType.MANIFEST);
+  return warn;
+}
+
+Polymer({
+  is: 'extensions-error-page',
+
+  _template: html`{__html_template__}`,
+
+  behaviors: [CrContainerShadowBehavior],
+
+  properties: {
+    /** @type {!chrome.developerPrivate.ExtensionInfo|undefined} */
+    data: Object,
+
+    /** @type {!ErrorPageDelegate|undefined} */
+    delegate: Object,
+
+    // Whether or not dev mode is enabled.
+    inDevMode: {
+      type: Boolean,
+      value: false,
+      observer: 'onInDevModeChanged_',
+    },
+
+    /** @private {!Array<!(ManifestError|RuntimeError)>} */
+    entries_: Array,
+
+    /** @private {?chrome.developerPrivate.RequestFileSourceResponse} */
+    code_: Object,
+
+    /**
+     * Index into |entries_|.
+     * @private
+     */
+    selectedEntry_: {
+      type: Number,
+      observer: 'onSelectedErrorChanged_',
+    },
+
+    /** @private {?chrome.developerPrivate.StackFrame}*/
+    selectedStackFrame_: {
+      type: Object,
+      value: function() {
+        return null;
+      },
+    },
+  },
+
+  observers: [
+    'observeDataChanges_(data.*)',
+  ],
+
+  listeners: {
+    'view-enter-start': 'onViewEnterStart_',
+  },
+
+  /** @override */
+  ready: function() {
+    FocusOutlineManager.forDocument(document);
+  },
+
+  /** @return {!ManifestError|!RuntimeError} */
+  getSelectedError: function() {
+    return this.entries_[this.selectedEntry_];
+  },
+
+  /**
+   * Focuses the back button when page is loaded.
+   * @private
+   */
+  onViewEnterStart_: function() {
+    afterNextRender(this, () => focusWithoutInk(this.$.closeButton));
+    chrome.metricsPrivate.recordUserAction('Options_ViewExtensionErrors');
+  },
+
+  /**
+   * @param {!ManifestError|!RuntimeError} error
+   * @param {string} unknown
    * @return {string}
    * @private
    */
-  function getErrorSeverityText_(item, log, warn, error) {
-    if (item.type == chrome.developerPrivate.ErrorType.RUNTIME) {
-      switch (item.severity) {
-        case chrome.developerPrivate.ErrorLevel.LOG:
-          return log;
-        case chrome.developerPrivate.ErrorLevel.WARN:
-          return warn;
-        case chrome.developerPrivate.ErrorLevel.ERROR:
-          return error;
-      }
-      assertNotReached();
+  getContextUrl_: function(error, unknown) {
+    return error.contextUrl ? getRelativeUrl(error.contextUrl, error) : unknown;
+  },
+
+  /**
+   * Watches for changes to |data| in order to fetch the corresponding
+   * file source.
+   * @private
+   */
+  observeDataChanges_: function() {
+    const errors = this.data.manifestErrors.concat(this.data.runtimeErrors);
+    this.entries_ = errors;
+    this.selectedEntry_ = -1;  // This also help reset code-section content.
+    if (this.entries_.length) {
+      this.selectedEntry_ = 0;
     }
-    assert(item.type == chrome.developerPrivate.ErrorType.MANIFEST);
-    return warn;
-  }
+  },
 
-  Polymer({
-    is: 'extensions-error-page',
+  /** @private */
+  onCloseButtonTap_: function() {
+    navigation.navigateTo({page: Page.LIST});
+  },
 
-    _template: html`{__html_template__}`,
+  /** @private */
+  onClearAllTap_: function() {
+    const ids = this.entries_.map(entry => entry.id);
+    this.delegate.deleteErrors(this.data.id, ids);
+  },
 
-    behaviors: [CrContainerShadowBehavior],
+  /**
+   * @param {!ManifestError|!RuntimeError} error
+   * @return {string}
+   * @private
+   */
+  computeErrorIcon_: function(error) {
+    // Do not i18n these strings, they're CSS classes.
+    return getErrorSeverityText_(error, 'info', 'warning', 'error');
+  },
 
-    properties: {
-      /** @type {!chrome.developerPrivate.ExtensionInfo|undefined} */
-      data: Object,
+  /**
+   * @param {!ManifestError|!RuntimeError} error
+   * @return {string}
+   * @private
+   */
+  computeErrorTypeLabel_: function(error) {
+    return getErrorSeverityText_(
+        error, loadTimeData.getString('logLevel'),
+        loadTimeData.getString('warnLevel'),
+        loadTimeData.getString('errorLevel'));
+  },
 
-      /** @type {!ErrorPageDelegate|undefined} */
-      delegate: Object,
+  /**
+   * @param {!Event} e
+   * @private
+   */
+  onDeleteErrorAction_: function(e) {
+    this.delegate.deleteErrors(
+        this.data.id, [(/** @type {!{model:Object}} */ (e)).model.item.id]);
+    e.stopPropagation();
+  },
 
-      // Whether or not dev mode is enabled.
-      inDevMode: {
-        type: Boolean,
-        value: false,
-        observer: 'onInDevModeChanged_',
-      },
+  /** private */
+  onInDevModeChanged_: function() {
+    if (!this.inDevMode) {
+      // Wait until next render cycle in case error page is loading.
+      this.async(() => {
+        this.onCloseButtonTap_();
+      });
+    }
+  },
 
-      /** @private {!Array<!(ManifestError|RuntimeError)>} */
-      entries_: Array,
+  /**
+   * Fetches the source for the selected error and populates the code section.
+   * @private
+   */
+  onSelectedErrorChanged_: function() {
+    this.code_ = null;
 
-      /** @private {?chrome.developerPrivate.RequestFileSourceResponse} */
-      code_: Object,
+    if (this.selectedEntry_ < 0) {
+      return;
+    }
 
-      /**
-       * Index into |entries_|.
-       * @private
-       */
-      selectedEntry_: {
-        type: Number,
-        observer: 'onSelectedErrorChanged_',
-      },
+    const error = this.getSelectedError();
+    const args = {
+      extensionId: error.extensionId,
+      message: error.message,
+    };
+    switch (error.type) {
+      case chrome.developerPrivate.ErrorType.MANIFEST:
+        args.pathSuffix = error.source;
+        args.manifestKey = error.manifestKey;
+        args.manifestSpecific = error.manifestSpecific;
+        break;
+      case chrome.developerPrivate.ErrorType.RUNTIME:
+        // slice(1) because pathname starts with a /.
+        args.pathSuffix = new URL(error.source).pathname.slice(1);
+        args.lineNumber = error.stackTrace && error.stackTrace[0] ?
+            error.stackTrace[0].lineNumber :
+            0;
+        this.selectedStackFrame_ = error.stackTrace && error.stackTrace[0] ?
+            error.stackTrace[0] :
+            null;
+        break;
+    }
+    this.delegate.requestFileSource(args).then(code => this.code_ = code);
+  },
 
-      /** @private {?chrome.developerPrivate.StackFrame}*/
-      selectedStackFrame_: {
-        type: Object,
-        value: function() {
-          return null;
-        },
-      },
-    },
+  /**
+   * @return {boolean}
+   * @private
+   */
+  computeIsRuntimeError_: function(item) {
+    return item.type == chrome.developerPrivate.ErrorType.RUNTIME;
+  },
 
-    observers: [
-      'observeDataChanges_(data.*)',
-    ],
+  /**
+   * The description is a human-readable summation of the frame, in the
+   * form "<relative_url>:<line_number> (function)", e.g.
+   * "myfile.js:25 (myFunction)".
+   * @param {!chrome.developerPrivate.StackFrame} frame
+   * @return {string}
+   * @private
+   */
+  getStackTraceLabel_: function(frame) {
+    let description = getRelativeUrl(frame.url, this.getSelectedError()) + ':' +
+        frame.lineNumber;
 
-    listeners: {
-      'view-enter-start': 'onViewEnterStart_',
-    },
+    if (frame.functionName) {
+      const functionName = frame.functionName == '(anonymous function)' ?
+          loadTimeData.getString('anonymousFunction') :
+          frame.functionName;
+      description += ' (' + functionName + ')';
+    }
 
-    /** @override */
-    ready: function() {
-      FocusOutlineManager.forDocument(document);
-    },
+    return description;
+  },
 
-    /** @return {!ManifestError|!RuntimeError} */
-    getSelectedError: function() {
-      return this.entries_[this.selectedEntry_];
-    },
+  /**
+   * @param {chrome.developerPrivate.StackFrame} frame
+   * @return {string}
+   * @private
+   */
+  getStackFrameClass_: function(frame) {
+    return frame == this.selectedStackFrame_ ? 'selected' : '';
+  },
 
-    /**
-     * Focuses the back button when page is loaded.
-     * @private
-     */
-    onViewEnterStart_: function() {
-      afterNextRender(this, () => focusWithoutInk(this.$.closeButton));
-      chrome.metricsPrivate.recordUserAction('Options_ViewExtensionErrors');
-    },
+  /**
+   * @param {!chrome.developerPrivate.StackFrame} frame
+   * @return {number}
+   * @private
+   */
+  getStackFrameTabIndex_: function(frame) {
+    return frame == this.selectedStackFrame_ ? 0 : -1;
+  },
 
-    /**
-     * @param {!ManifestError|!RuntimeError} error
-     * @param {string} unknown
-     * @return {string}
-     * @private
-     */
-    getContextUrl_: function(error, unknown) {
-      return error.contextUrl ? getRelativeUrl(error.contextUrl, error) :
-                                unknown;
-    },
+  /**
+   * This function is used to determine whether or not we want to show a
+   * stack frame. We don't want to show code from internal scripts.
+   * @param {string} url
+   * @return {boolean}
+   * @private
+   */
+  shouldDisplayFrame_: function(url) {
+    // All our internal scripts are in the 'extensions::' namespace.
+    return !/^extensions::/.test(url);
+  },
 
-    /**
-     * Watches for changes to |data| in order to fetch the corresponding
-     * file source.
-     * @private
-     */
-    observeDataChanges_: function() {
-      const errors = this.data.manifestErrors.concat(this.data.runtimeErrors);
-      this.entries_ = errors;
-      this.selectedEntry_ = -1;  // This also help reset code-section content.
-      if (this.entries_.length) {
-        this.selectedEntry_ = 0;
-      }
-    },
+  /**
+   * @param {!chrome.developerPrivate.StackFrame} frame
+   * @private
+   */
+  updateSelected_: function(frame) {
+    this.selectedStackFrame_ = assert(frame);
 
-    /** @private */
-    onCloseButtonTap_: function() {
-      navigation.navigateTo({page: Page.LIST});
-    },
+    const selectedError = this.getSelectedError();
+    this.delegate
+        .requestFileSource({
+          extensionId: selectedError.extensionId,
+          message: selectedError.message,
+          pathSuffix: getRelativeUrl(frame.url, selectedError),
+          lineNumber: frame.lineNumber,
+        })
+        .then(code => this.code_ = code);
+  },
 
-    /** @private */
-    onClearAllTap_: function() {
-      const ids = this.entries_.map(entry => entry.id);
-      this.delegate.deleteErrors(this.data.id, ids);
-    },
+  /**
+   * @param {!Event} e
+   * @private
+   */
+  onStackFrameTap_: function(e) {
+    const frame = /** @type {!{model:Object}} */ (e).model.item;
+    this.updateSelected_(frame);
+  },
 
-    /**
-     * @param {!ManifestError|!RuntimeError} error
-     * @return {string}
-     * @private
-     */
-    computeErrorIcon_: function(error) {
-      // Do not i18n these strings, they're CSS classes.
-      return getErrorSeverityText_(error, 'info', 'warning', 'error');
-    },
+  /**
+   * @param {!Event} e
+   * @private
+   */
+  onStackKeydown_: function(e) {
+    let direction = 0;
 
-    /**
-     * @param {!ManifestError|!RuntimeError} error
-     * @return {string}
-     * @private
-     */
-    computeErrorTypeLabel_: function(error) {
-      return getErrorSeverityText_(
-          error, loadTimeData.getString('logLevel'),
-          loadTimeData.getString('warnLevel'),
-          loadTimeData.getString('errorLevel'));
-    },
+    if (e.key == 'ArrowDown') {
+      direction = 1;
+    } else if (e.key == 'ArrowUp') {
+      direction = -1;
+    } else {
+      return;
+    }
 
-    /**
-     * @param {!Event} e
-     * @private
-     */
-    onDeleteErrorAction_: function(e) {
-      this.delegate.deleteErrors(
-          this.data.id, [(/** @type {!{model:Object}} */ (e)).model.item.id]);
-      e.stopPropagation();
-    },
+    e.preventDefault();
 
-    /** private */
-    onInDevModeChanged_: function() {
-      if (!this.inDevMode) {
-        // Wait until next render cycle in case error page is loading.
-        this.async(() => {
-          this.onCloseButtonTap_();
-        });
-      }
-    },
+    const list = e.target.parentElement.querySelectorAll('li');
 
-    /**
-     * Fetches the source for the selected error and populates the code section.
-     * @private
-     */
-    onSelectedErrorChanged_: function() {
-      this.code_ = null;
-
-      if (this.selectedEntry_ < 0) {
-        return;
-      }
-
-      const error = this.getSelectedError();
-      const args = {
-        extensionId: error.extensionId,
-        message: error.message,
-      };
-      switch (error.type) {
-        case chrome.developerPrivate.ErrorType.MANIFEST:
-          args.pathSuffix = error.source;
-          args.manifestKey = error.manifestKey;
-          args.manifestSpecific = error.manifestSpecific;
-          break;
-        case chrome.developerPrivate.ErrorType.RUNTIME:
-          // slice(1) because pathname starts with a /.
-          args.pathSuffix = new URL(error.source).pathname.slice(1);
-          args.lineNumber = error.stackTrace && error.stackTrace[0] ?
-              error.stackTrace[0].lineNumber :
-              0;
-          this.selectedStackFrame_ = error.stackTrace && error.stackTrace[0] ?
-              error.stackTrace[0] :
-              null;
-          break;
-      }
-      this.delegate.requestFileSource(args).then(code => this.code_ = code);
-    },
-
-    /**
-     * @return {boolean}
-     * @private
-     */
-    computeIsRuntimeError_: function(item) {
-      return item.type == chrome.developerPrivate.ErrorType.RUNTIME;
-    },
-
-    /**
-     * The description is a human-readable summation of the frame, in the
-     * form "<relative_url>:<line_number> (function)", e.g.
-     * "myfile.js:25 (myFunction)".
-     * @param {!chrome.developerPrivate.StackFrame} frame
-     * @return {string}
-     * @private
-     */
-    getStackTraceLabel_: function(frame) {
-      let description = getRelativeUrl(frame.url, this.getSelectedError()) +
-          ':' + frame.lineNumber;
-
-      if (frame.functionName) {
-        const functionName = frame.functionName == '(anonymous function)' ?
-            loadTimeData.getString('anonymousFunction') :
-            frame.functionName;
-        description += ' (' + functionName + ')';
-      }
-
-      return description;
-    },
-
-    /**
-     * @param {chrome.developerPrivate.StackFrame} frame
-     * @return {string}
-     * @private
-     */
-    getStackFrameClass_: function(frame) {
-      return frame == this.selectedStackFrame_ ? 'selected' : '';
-    },
-
-    /**
-     * @param {!chrome.developerPrivate.StackFrame} frame
-     * @return {number}
-     * @private
-     */
-    getStackFrameTabIndex_: function(frame) {
-      return frame == this.selectedStackFrame_ ? 0 : -1;
-    },
-
-    /**
-     * This function is used to determine whether or not we want to show a
-     * stack frame. We don't want to show code from internal scripts.
-     * @param {string} url
-     * @return {boolean}
-     * @private
-     */
-    shouldDisplayFrame_: function(url) {
-      // All our internal scripts are in the 'extensions::' namespace.
-      return !/^extensions::/.test(url);
-    },
-
-    /**
-     * @param {!chrome.developerPrivate.StackFrame} frame
-     * @private
-     */
-    updateSelected_: function(frame) {
-      this.selectedStackFrame_ = assert(frame);
-
-      const selectedError = this.getSelectedError();
-      this.delegate
-          .requestFileSource({
-            extensionId: selectedError.extensionId,
-            message: selectedError.message,
-            pathSuffix: getRelativeUrl(frame.url, selectedError),
-            lineNumber: frame.lineNumber,
-          })
-          .then(code => this.code_ = code);
-    },
-
-    /**
-     * @param {!Event} e
-     * @private
-     */
-    onStackFrameTap_: function(e) {
-      const frame = /** @type {!{model:Object}} */ (e).model.item;
-      this.updateSelected_(frame);
-    },
-
-    /**
-     * @param {!Event} e
-     * @private
-     */
-    onStackKeydown_: function(e) {
-      let direction = 0;
-
-      if (e.key == 'ArrowDown') {
-        direction = 1;
-      } else if (e.key == 'ArrowUp') {
-        direction = -1;
-      } else {
-        return;
-      }
-
-      e.preventDefault();
-
-      const list = e.target.parentElement.querySelectorAll('li');
-
-      for (let i = 0; i < list.length; ++i) {
-        if (list[i].classList.contains('selected')) {
-          const polymerEvent = /** @type {!{model: !Object}} */ (e);
-          const frame = polymerEvent.model.item.stackTrace[i + direction];
-          if (frame) {
-            this.updateSelected_(frame);
-            list[i + direction].focus();  // Preserve focus.
-          }
-          return;
+    for (let i = 0; i < list.length; ++i) {
+      if (list[i].classList.contains('selected')) {
+        const polymerEvent = /** @type {!{model: !Object}} */ (e);
+        const frame = polymerEvent.model.item.stackTrace[i + direction];
+        if (frame) {
+          this.updateSelected_(frame);
+          list[i + direction].focus();  // Preserve focus.
         }
-      }
-    },
-
-    /**
-     * Computes the class name for the error item depending on whether its
-     * the currently selected error.
-     * @param {number} index
-     * @return {string}
-     * @private
-     */
-    computeErrorClass_: function(index) {
-      return index == this.selectedEntry_ ? 'selected' : '';
-    },
-
-    /** @private */
-    iconName_: function(index) {
-      return index == this.selectedEntry_ ? 'icon-expand-less' :
-                                            'icon-expand-more';
-    },
-
-    /**
-     * Determine if the iron-collapse should be opened (expanded).
-     * @param {number} index
-     * @return {boolean}
-     * @private
-     */
-    isOpened_: function(index) {
-      return index == this.selectedEntry_;
-    },
-
-
-    /**
-     * @param {number} index
-     * @return {string} The aria-expanded value as a string.
-     * @private
-     */
-    isAriaExpanded_: function(index) {
-      return this.isOpened_(index).toString();
-    },
-
-    /**
-     * @param {!{type: string, code: string, model: !{index: number}}} e
-     * @private
-     */
-    onErrorItemAction_: function(e) {
-      if (e.type == 'keydown' && !((e.code == 'Space' || e.code == 'Enter'))) {
         return;
       }
+    }
+  },
 
-      // Call preventDefault() to avoid the browser scrolling when the space key
-      // is pressed.
-      e.preventDefault();
-      this.selectedEntry_ =
-          this.selectedEntry_ == e.model.index ? -1 : e.model.index;
-    },
-  });
+  /**
+   * Computes the class name for the error item depending on whether its
+   * the currently selected error.
+   * @param {number} index
+   * @return {string}
+   * @private
+   */
+  computeErrorClass_: function(index) {
+    return index == this.selectedEntry_ ? 'selected' : '';
+  },
+
+  /** @private */
+  iconName_: function(index) {
+    return index == this.selectedEntry_ ? 'icon-expand-less' :
+                                          'icon-expand-more';
+  },
+
+  /**
+   * Determine if the iron-collapse should be opened (expanded).
+   * @param {number} index
+   * @return {boolean}
+   * @private
+   */
+  isOpened_: function(index) {
+    return index == this.selectedEntry_;
+  },
+
+
+  /**
+   * @param {number} index
+   * @return {string} The aria-expanded value as a string.
+   * @private
+   */
+  isAriaExpanded_: function(index) {
+    return this.isOpened_(index).toString();
+  },
+
+  /**
+   * @param {!{type: string, code: string, model: !{index: number}}} e
+   * @private
+   */
+  onErrorItemAction_: function(e) {
+    if (e.type == 'keydown' && !((e.code == 'Space' || e.code == 'Enter'))) {
+      return;
+    }
+
+    // Call preventDefault() to avoid the browser scrolling when the space key
+    // is pressed.
+    e.preventDefault();
+    this.selectedEntry_ =
+        this.selectedEntry_ == e.model.index ? -1 : e.model.index;
+  },
+});
diff --git a/chrome/browser/resources/extensions/host_permissions_toggle_list.js b/chrome/browser/resources/extensions/host_permissions_toggle_list.js
index 44594ebc..b8a3e49 100644
--- a/chrome/browser/resources/extensions/host_permissions_toggle_list.js
+++ b/chrome/browser/resources/extensions/host_permissions_toggle_list.js
@@ -14,78 +14,78 @@
 
 import {ItemDelegate} from './item.js';
 
-  Polymer({
-    is: 'extensions-host-permissions-toggle-list',
+Polymer({
+  is: 'extensions-host-permissions-toggle-list',
 
-    _template: html`{__html_template__}`,
+  _template: html`{__html_template__}`,
 
-    properties: {
-      /**
-       * The underlying permissions data.
-       * @type {chrome.developerPrivate.RuntimeHostPermissions}
-       */
-      permissions: Object,
-
-      /** @private */
-      itemId: String,
-
-      /** @type {!ItemDelegate} */
-      delegate: Object,
-    },
-
+  properties: {
     /**
-     * @return {boolean} Whether the item is allowed to execute on all of its
-     *     requested sites.
-     * @private
+     * The underlying permissions data.
+     * @type {chrome.developerPrivate.RuntimeHostPermissions}
      */
-    allowedOnAllHosts_: function() {
-      return this.permissions.hostAccess ==
-          chrome.developerPrivate.HostAccess.ON_ALL_SITES;
-    },
-
-    /**
-     * Returns a lexicographically-sorted list of the hosts associated with this
-     * item.
-     * @return {!Array<!chrome.developerPrivate.SiteControl>}
-     * @private
-     */
-    getSortedHosts_: function() {
-      return this.permissions.hosts.sort((a, b) => {
-        if (a.host < b.host) {
-          return -1;
-        }
-        if (a.host > b.host) {
-          return 1;
-        }
-        return 0;
-      });
-    },
+    permissions: Object,
 
     /** @private */
-    onAllHostsToggleChanged_: function() {
-      // TODO(devlin): In the case of going from all sites to specific sites,
-      // we'll withhold all sites (i.e., all specific site toggles will move to
-      // unchecked, and the user can check them individually). This is slightly
-      // different than the sync page, where disabling the "sync everything"
-      // switch leaves everything synced, and user can uncheck them
-      // individually. It could be nice to align on behavior, but probably not
-      // super high priority.
-      this.delegate.setItemHostAccess(
-          this.itemId,
-          this.$.allHostsToggle.checked ?
-              chrome.developerPrivate.HostAccess.ON_ALL_SITES :
-              chrome.developerPrivate.HostAccess.ON_SPECIFIC_SITES);
-    },
+    itemId: String,
 
-    /** @private */
-    onHostAccessChanged_: function(e) {
-      const host = e.target.host;
-      const checked = e.target.checked;
+    /** @type {!ItemDelegate} */
+    delegate: Object,
+  },
 
-      if (checked) {
-        this.delegate.addRuntimeHostPermission(this.itemId, host);
-      } else {
-        this.delegate.removeRuntimeHostPermission(this.itemId, host);
+  /**
+   * @return {boolean} Whether the item is allowed to execute on all of its
+   *     requested sites.
+   * @private
+   */
+  allowedOnAllHosts_: function() {
+    return this.permissions.hostAccess ==
+        chrome.developerPrivate.HostAccess.ON_ALL_SITES;
+  },
+
+  /**
+   * Returns a lexicographically-sorted list of the hosts associated with this
+   * item.
+   * @return {!Array<!chrome.developerPrivate.SiteControl>}
+   * @private
+   */
+  getSortedHosts_: function() {
+    return this.permissions.hosts.sort((a, b) => {
+      if (a.host < b.host) {
+        return -1;
       }
-    },
-  });
+      if (a.host > b.host) {
+        return 1;
+      }
+      return 0;
+    });
+  },
+
+  /** @private */
+  onAllHostsToggleChanged_: function() {
+    // TODO(devlin): In the case of going from all sites to specific sites,
+    // we'll withhold all sites (i.e., all specific site toggles will move to
+    // unchecked, and the user can check them individually). This is slightly
+    // different than the sync page, where disabling the "sync everything"
+    // switch leaves everything synced, and user can uncheck them
+    // individually. It could be nice to align on behavior, but probably not
+    // super high priority.
+    this.delegate.setItemHostAccess(
+        this.itemId,
+        this.$.allHostsToggle.checked ?
+            chrome.developerPrivate.HostAccess.ON_ALL_SITES :
+            chrome.developerPrivate.HostAccess.ON_SPECIFIC_SITES);
+  },
+
+  /** @private */
+  onHostAccessChanged_: function(e) {
+    const host = e.target.host;
+    const checked = e.target.checked;
+
+    if (checked) {
+      this.delegate.addRuntimeHostPermission(this.itemId, host);
+    } else {
+      this.delegate.removeRuntimeHostPermission(this.itemId, host);
+    }
+  },
+});
diff --git a/chrome/browser/resources/extensions/install_warnings_dialog.js b/chrome/browser/resources/extensions/install_warnings_dialog.js
index a882800..b333dca 100644
--- a/chrome/browser/resources/extensions/install_warnings_dialog.js
+++ b/chrome/browser/resources/extensions/install_warnings_dialog.js
@@ -10,23 +10,23 @@
 
 import {html, Polymer} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
 
-  Polymer({
-    is: 'extensions-install-warnings-dialog',
+Polymer({
+  is: 'extensions-install-warnings-dialog',
 
-    _template: html`{__html_template__}`,
+  _template: html`{__html_template__}`,
 
-    properties: {
-      /** @type {!Array<string>} */
-      installWarnings: Array,
-    },
+  properties: {
+    /** @type {!Array<string>} */
+    installWarnings: Array,
+  },
 
-    /** @override */
-    attached: function() {
-      this.$.dialog.showModal();
-    },
+  /** @override */
+  attached: function() {
+    this.$.dialog.showModal();
+  },
 
-    /** @private */
-    onOkTap_: function() {
-      this.$.dialog.close();
-    },
-  });
+  /** @private */
+  onOkTap_: function() {
+    this.$.dialog.close();
+  },
+});
diff --git a/chrome/browser/resources/extensions/item.js b/chrome/browser/resources/extensions/item.js
index 0cea8365..4abc178 100644
--- a/chrome/browser/resources/extensions/item.js
+++ b/chrome/browser/resources/extensions/item.js
@@ -29,418 +29,414 @@
 import {computeInspectableViewLabel, getItemSource, getItemSourceString, isControlled, isEnabled, SourceType, userCanChangeEnablement} from './item_util.js';
 import {navigation, Page} from './navigation_helper.js';
 
-  /** @interface */
-  export class ItemDelegate {
-    /** @param {string} id */
-    deleteItem(id) {}
+/** @interface */
+export class ItemDelegate {
+  /** @param {string} id */
+  deleteItem(id) {}
 
-    /**
-     * @param {string} id
-     * @param {boolean} isEnabled
-     */
-    setItemEnabled(id, isEnabled) {}
+  /**
+   * @param {string} id
+   * @param {boolean} isEnabled
+   */
+  setItemEnabled(id, isEnabled) {}
 
-    /**
-     * @param {string} id
-     * @param {boolean} isAllowedIncognito
-     */
-    setItemAllowedIncognito(id, isAllowedIncognito) {}
+  /**
+   * @param {string} id
+   * @param {boolean} isAllowedIncognito
+   */
+  setItemAllowedIncognito(id, isAllowedIncognito) {}
 
-    /**
-     * @param {string} id
-     * @param {boolean} isAllowedOnFileUrls
-     */
-    setItemAllowedOnFileUrls(id, isAllowedOnFileUrls) {}
+  /**
+   * @param {string} id
+   * @param {boolean} isAllowedOnFileUrls
+   */
+  setItemAllowedOnFileUrls(id, isAllowedOnFileUrls) {}
 
-    /**
-     * @param {string} id
-     * @param {!chrome.developerPrivate.HostAccess} hostAccess
-     */
-    setItemHostAccess(id, hostAccess) {}
+  /**
+   * @param {string} id
+   * @param {!chrome.developerPrivate.HostAccess} hostAccess
+   */
+  setItemHostAccess(id, hostAccess) {}
 
-    /**
-     * @param {string} id
-     * @param {boolean} collectsErrors
-     */
-    setItemCollectsErrors(id, collectsErrors) {}
+  /**
+   * @param {string} id
+   * @param {boolean} collectsErrors
+   */
+  setItemCollectsErrors(id, collectsErrors) {}
 
-    /**
-     * @param {string} id
-     * @param {chrome.developerPrivate.ExtensionView} view
-     */
-    inspectItemView(id, view) {}
+  /**
+   * @param {string} id
+   * @param {chrome.developerPrivate.ExtensionView} view
+   */
+  inspectItemView(id, view) {}
 
-    /**
-     * @param {string} url
-     */
-    openUrl(url) {}
+  /**
+   * @param {string} url
+   */
+  openUrl(url) {}
 
-    /**
-     * @param {string} id
-     * @return {!Promise}
-     */
-    reloadItem(id) {}
+  /**
+   * @param {string} id
+   * @return {!Promise}
+   */
+  reloadItem(id) {}
 
-    /** @param {string} id */
-    repairItem(id) {}
+  /** @param {string} id */
+  repairItem(id) {}
 
-    /** @param {!chrome.developerPrivate.ExtensionInfo} extension */
-    showItemOptionsPage(extension) {}
+  /** @param {!chrome.developerPrivate.ExtensionInfo} extension */
+  showItemOptionsPage(extension) {}
 
-    /** @param {string} id */
-    showInFolder(id) {}
+  /** @param {string} id */
+  showInFolder(id) {}
 
-    /**
-     * @param {string} id
-     * @return {!Promise<string>}
-     */
-    getExtensionSize(id) {}
+  /**
+   * @param {string} id
+   * @return {!Promise<string>}
+   */
+  getExtensionSize(id) {}
 
-    /**
-     * @param {string} id
-     * @param {string} host
-     * @return {!Promise<void>}
-     */
-    addRuntimeHostPermission(id, host) {}
+  /**
+   * @param {string} id
+   * @param {string} host
+   * @return {!Promise<void>}
+   */
+  addRuntimeHostPermission(id, host) {}
 
-    /**
-     * @param {string} id
-     * @param {string} host
-     * @return {!Promise<void>}
-     */
-    removeRuntimeHostPermission(id, host) {}
-  }
+  /**
+   * @param {string} id
+   * @param {string} host
+   * @return {!Promise<void>}
+   */
+  removeRuntimeHostPermission(id, host) {}
+}
 
-  Polymer({
-    is: 'extensions-item',
+Polymer({
+  is: 'extensions-item',
 
-    _template: html`{__html_template__}`,
+  _template: html`{__html_template__}`,
 
-    behaviors: [I18nBehavior, ItemBehavior],
+  behaviors: [I18nBehavior, ItemBehavior],
 
-    properties: {
-      // The item's delegate, or null.
-      delegate: {
-        type: Object,
-      },
-
-      // Whether or not dev mode is enabled.
-      inDevMode: {
-        type: Boolean,
-        value: false,
-      },
-
-      // The underlying ExtensionInfo itself. Public for use in declarative
-      // bindings.
-      /** @type {chrome.developerPrivate.ExtensionInfo} */
-      data: {
-        type: Object,
-      },
-
-      // Whether or not the expanded view of the item is shown.
-      /** @private */
-      showingDetails_: {
-        type: Boolean,
-        value: false,
-      },
+  properties: {
+    // The item's delegate, or null.
+    delegate: {
+      type: Object,
     },
 
-    /** Prevents reloading the same item while it's already being reloaded. */
-    isReloading_: false,
-
-    observers: [
-      'observeIdVisibility_(inDevMode, showingDetails_, data.id)',
-    ],
-
-    /** @return {!HTMLElement} The "Details" button. */
-    getDetailsButton: function() {
-      return /** @type {!HTMLElement} */ (this.$.detailsButton);
+    // Whether or not dev mode is enabled.
+    inDevMode: {
+      type: Boolean,
+      value: false,
     },
 
-    /** @return {?HTMLElement} The "Errors" button, if it exists. */
-    getErrorsButton: function() {
-      return /** @type {?HTMLElement} */ (this.$$('#errors-button'));
+    // The underlying ExtensionInfo itself. Public for use in declarative
+    // bindings.
+    /** @type {chrome.developerPrivate.ExtensionInfo} */
+    data: {
+      type: Object,
     },
 
-    /** @private string */
-    a11yAssociation_: function() {
-      // Don't use I18nBehavior.i18n because of additional checks it performs.
-      // Polymer ensures that this string is not stamped into arbitrary HTML.
-      // |this.data.name| can contain any data including html tags.
-      // ex: "My <video> download extension!"
-      return loadTimeData.getStringF(
-          'extensionA11yAssociation', this.data.name);
-    },
-
+    // Whether or not the expanded view of the item is shown.
     /** @private */
-    observeIdVisibility_: function(inDevMode, showingDetails, id) {
-      flush();
-      const idElement = this.$$('#extension-id');
-      if (idElement) {
-        assert(this.data);
-        idElement.innerHTML = this.i18n('itemId', this.data.id);
-      }
+    showingDetails_: {
+      type: Boolean,
+      value: false,
     },
+  },
 
-    /**
-     * @return {boolean}
-     * @private
-     */
-    shouldShowErrorsButton_: function() {
-      // When the error console is disabled (happens when
-      // --disable-error-console command line flag is used or when in the
-      // Stable/Beta channel), |installWarnings| is populated.
-      if (this.data.installWarnings && this.data.installWarnings.length > 0) {
-        return true;
-      }
+  /** Prevents reloading the same item while it's already being reloaded. */
+  isReloading_: false,
 
-      // When error console is enabled |installedWarnings| is not populated.
-      // Instead |manifestErrors| and |runtimeErrors| are used.
-      return this.data.manifestErrors.length > 0 ||
-          this.data.runtimeErrors.length > 0;
-    },
+  observers: [
+    'observeIdVisibility_(inDevMode, showingDetails_, data.id)',
+  ],
 
-    /** @private */
-    onRemoveTap_: function() {
-      this.delegate.deleteItem(this.data.id);
-    },
+  /** @return {!HTMLElement} The "Details" button. */
+  getDetailsButton: function() {
+    return /** @type {!HTMLElement} */ (this.$.detailsButton);
+  },
 
-    /** @private */
-    onEnableChange_: function() {
-      this.delegate.setItemEnabled(
-          this.data.id, this.$['enable-toggle'].checked);
-    },
+  /** @return {?HTMLElement} The "Errors" button, if it exists. */
+  getErrorsButton: function() {
+    return /** @type {?HTMLElement} */ (this.$$('#errors-button'));
+  },
 
-    /** @private */
-    onErrorsTap_: function() {
-      if (this.data.installWarnings && this.data.installWarnings.length > 0) {
-        this.fire('show-install-warnings', this.data.installWarnings);
-        return;
-      }
+  /** @private string */
+  a11yAssociation_: function() {
+    // Don't use I18nBehavior.i18n because of additional checks it performs.
+    // Polymer ensures that this string is not stamped into arbitrary HTML.
+    // |this.data.name| can contain any data including html tags.
+    // ex: "My <video> download extension!"
+    return loadTimeData.getStringF('extensionA11yAssociation', this.data.name);
+  },
 
-      navigation.navigateTo({page: Page.ERRORS, extensionId: this.data.id});
-    },
+  /** @private */
+  observeIdVisibility_: function(inDevMode, showingDetails, id) {
+    flush();
+    const idElement = this.$$('#extension-id');
+    if (idElement) {
+      assert(this.data);
+      idElement.innerHTML = this.i18n('itemId', this.data.id);
+    }
+  },
 
-    /** @private */
-    onDetailsTap_: function() {
-      navigation.navigateTo({page: Page.DETAILS, extensionId: this.data.id});
-    },
+  /**
+   * @return {boolean}
+   * @private
+   */
+  shouldShowErrorsButton_: function() {
+    // When the error console is disabled (happens when
+    // --disable-error-console command line flag is used or when in the
+    // Stable/Beta channel), |installWarnings| is populated.
+    if (this.data.installWarnings && this.data.installWarnings.length > 0) {
+      return true;
+    }
 
-    /**
-     * @param {!{model: !{item: !chrome.developerPrivate.ExtensionView}}} e
-     * @private
-     */
-    onInspectTap_: function(e) {
-      this.delegate.inspectItemView(this.data.id, this.data.views[0]);
-    },
+    // When error console is enabled |installedWarnings| is not populated.
+    // Instead |manifestErrors| and |runtimeErrors| are used.
+    return this.data.manifestErrors.length > 0 ||
+        this.data.runtimeErrors.length > 0;
+  },
 
-    /** @private */
-    onExtraInspectTap_: function() {
-      navigation.navigateTo({page: Page.DETAILS, extensionId: this.data.id});
-    },
+  /** @private */
+  onRemoveTap_: function() {
+    this.delegate.deleteItem(this.data.id);
+  },
 
-    /** @private */
-    onReloadTap_: function() {
-      // Don't reload if in the middle of an update.
-      if (this.isReloading_) {
-        return;
-      }
+  /** @private */
+  onEnableChange_: function() {
+    this.delegate.setItemEnabled(this.data.id, this.$['enable-toggle'].checked);
+  },
 
-      this.isReloading_ = true;
+  /** @private */
+  onErrorsTap_: function() {
+    if (this.data.installWarnings && this.data.installWarnings.length > 0) {
+      this.fire('show-install-warnings', this.data.installWarnings);
+      return;
+    }
 
-      const toastManager = getInstance();
-      // Keep the toast open indefinitely.
-      toastManager.duration = 0;
-      toastManager.show(this.i18n('itemReloading'), false);
-      this.delegate.reloadItem(this.data.id)
-          .then(
-              () => {
-                toastManager.hide();
-                toastManager.duration = 3000;
-                toastManager.show(this.i18n('itemReloaded'), false);
-                this.isReloading_ = false;
-              },
-              loadError => {
-                this.fire('load-error', loadError);
-                toastManager.hide();
-                this.isReloading_ = false;
-              });
-    },
+    navigation.navigateTo({page: Page.ERRORS, extensionId: this.data.id});
+  },
 
-    /** @private */
-    onRepairTap_: function() {
-      this.delegate.repairItem(this.data.id);
-    },
+  /** @private */
+  onDetailsTap_: function() {
+    navigation.navigateTo({page: Page.DETAILS, extensionId: this.data.id});
+  },
 
-    /**
-     * @return {boolean}
-     * @private
-     */
-    isControlled_: function() {
-      return isControlled(this.data);
-    },
+  /**
+   * @param {!{model: !{item: !chrome.developerPrivate.ExtensionView}}} e
+   * @private
+   */
+  onInspectTap_: function(e) {
+    this.delegate.inspectItemView(this.data.id, this.data.views[0]);
+  },
 
-    /**
-     * @return {boolean}
-     * @private
-     */
-    isEnabled_: function() {
-      return isEnabled(this.data.state);
-    },
+  /** @private */
+  onExtraInspectTap_: function() {
+    navigation.navigateTo({page: Page.DETAILS, extensionId: this.data.id});
+  },
 
-    /**
-     * @return {boolean}
-     * @private
-     */
-    isEnableToggleEnabled_: function() {
-      return userCanChangeEnablement(this.data);
-    },
+  /** @private */
+  onReloadTap_: function() {
+    // Don't reload if in the middle of an update.
+    if (this.isReloading_) {
+      return;
+    }
 
-    /**
-     * Returns true if the enable toggle should be shown.
-     * @return {boolean}
-     * @private
-     */
-    showEnableToggle_: function() {
-      return !this.isTerminated_() && !this.data.disableReasons.corruptInstall;
-    },
+    this.isReloading_ = true;
 
-    /**
-     * Returns true if the extension is in the terminated state.
-     * @return {boolean}
-     * @private
-     */
-    isTerminated_: function() {
-      return this.data.state ==
-          chrome.developerPrivate.ExtensionState.TERMINATED;
-    },
+    const toastManager = getInstance();
+    // Keep the toast open indefinitely.
+    toastManager.duration = 0;
+    toastManager.show(this.i18n('itemReloading'), false);
+    this.delegate.reloadItem(this.data.id)
+        .then(
+            () => {
+              toastManager.hide();
+              toastManager.duration = 3000;
+              toastManager.show(this.i18n('itemReloaded'), false);
+              this.isReloading_ = false;
+            },
+            loadError => {
+              this.fire('load-error', loadError);
+              toastManager.hide();
+              this.isReloading_ = false;
+            });
+  },
 
-    /**
-     * return {string}
-     * @private
-     */
-    computeClasses_: function() {
-      let classes = this.isEnabled_() ? 'enabled' : 'disabled';
-      if (this.inDevMode) {
-        classes += ' dev-mode';
-      }
-      return classes;
-    },
+  /** @private */
+  onRepairTap_: function() {
+    this.delegate.repairItem(this.data.id);
+  },
 
-    /**
-     * @return {string}
-     * @private
-     */
-    computeSourceIndicatorIcon_: function() {
-      switch (getItemSource(this.data)) {
-        case SourceType.POLICY:
-          return 'extensions-icons:business';
-        case SourceType.SIDELOADED:
-          return 'extensions-icons:input';
-        case SourceType.UNKNOWN:
-          // TODO(dpapad): Ask UX for a better icon for this case.
-          return 'extensions-icons:input';
-        case SourceType.UNPACKED:
-          return 'extensions-icons:unpacked';
-        case SourceType.WEBSTORE:
-          return '';
-      }
-      assertNotReached();
-    },
+  /**
+   * @return {boolean}
+   * @private
+   */
+  isControlled_: function() {
+    return isControlled(this.data);
+  },
 
-    /**
-     * @return {string}
-     * @private
-     */
-    computeSourceIndicatorText_: function() {
-      if (this.data.locationText) {
-        return this.data.locationText;
-      }
+  /**
+   * @return {boolean}
+   * @private
+   */
+  isEnabled_: function() {
+    return isEnabled(this.data.state);
+  },
 
-      const sourceType = getItemSource(this.data);
-      return sourceType == SourceType.WEBSTORE ?
-          '' :
-          getItemSourceString(sourceType);
-    },
+  /**
+   * @return {boolean}
+   * @private
+   */
+  isEnableToggleEnabled_: function() {
+    return userCanChangeEnablement(this.data);
+  },
 
-    /**
-     * @return {boolean}
-     * @private
-     */
-    computeInspectViewsHidden_: function() {
-      return !this.data.views || this.data.views.length == 0;
-    },
+  /**
+   * Returns true if the enable toggle should be shown.
+   * @return {boolean}
+   * @private
+   */
+  showEnableToggle_: function() {
+    return !this.isTerminated_() && !this.data.disableReasons.corruptInstall;
+  },
 
-    /**
-     * @return {string}
-     * @private
-     */
-    computeFirstInspectTitle_: function() {
-      // Note: theoretically, this wouldn't be called without any inspectable
-      // views (because it's in a dom-if="!computeInspectViewsHidden_()").
-      // However, due to the recycling behavior of iron list, it seems that
-      // sometimes it can. Even when it is, the UI behaves properly, but we
-      // need to handle the case gracefully.
-      return this.data.views.length > 0 ?
-          computeInspectableViewLabel(this.data.views[0]) :
-          '';
-    },
+  /**
+   * Returns true if the extension is in the terminated state.
+   * @return {boolean}
+   * @private
+   */
+  isTerminated_: function() {
+    return this.data.state == chrome.developerPrivate.ExtensionState.TERMINATED;
+  },
 
-    /**
-     * @return {string}
-     * @private
-     */
-    computeFirstInspectLabel_: function() {
-      const label = this.computeFirstInspectTitle_();
-      return label && this.data.views.length > 1 ? label + ',' : label;
-    },
+  /**
+   * return {string}
+   * @private
+   */
+  computeClasses_: function() {
+    let classes = this.isEnabled_() ? 'enabled' : 'disabled';
+    if (this.inDevMode) {
+      classes += ' dev-mode';
+    }
+    return classes;
+  },
 
-    /**
-     * @return {boolean}
-     * @private
-     */
-    computeExtraViewsHidden_: function() {
-      return this.data.views.length <= 1;
-    },
+  /**
+   * @return {string}
+   * @private
+   */
+  computeSourceIndicatorIcon_: function() {
+    switch (getItemSource(this.data)) {
+      case SourceType.POLICY:
+        return 'extensions-icons:business';
+      case SourceType.SIDELOADED:
+        return 'extensions-icons:input';
+      case SourceType.UNKNOWN:
+        // TODO(dpapad): Ask UX for a better icon for this case.
+        return 'extensions-icons:input';
+      case SourceType.UNPACKED:
+        return 'extensions-icons:unpacked';
+      case SourceType.WEBSTORE:
+        return '';
+    }
+    assertNotReached();
+  },
 
-    /**
-     * @return {boolean}
-     * @private
-     */
-    computeDevReloadButtonHidden_: function() {
-      // Only display the reload spinner if the extension is unpacked and
-      // enabled. There's no point in reloading a disabled extension, and we'll
-      // show a crashed reload button if it's terminated.
-      const showIcon =
-          this.data.location == chrome.developerPrivate.Location.UNPACKED &&
-          this.data.state == chrome.developerPrivate.ExtensionState.ENABLED;
-      return !showIcon;
-    },
+  /**
+   * @return {string}
+   * @private
+   */
+  computeSourceIndicatorText_: function() {
+    if (this.data.locationText) {
+      return this.data.locationText;
+    }
 
-    /**
-     * @return {string}
-     * @private
-     */
-    computeExtraInspectLabel_: function() {
-      return this.i18n(
-          'itemInspectViewsExtra', (this.data.views.length - 1).toString());
-    },
+    const sourceType = getItemSource(this.data);
+    return sourceType == SourceType.WEBSTORE ? '' :
+                                               getItemSourceString(sourceType);
+  },
 
-    /**
-     * @return {boolean}
-     * @private
-     */
-    hasWarnings_: function() {
-      return this.data.disableReasons.corruptInstall ||
-          this.data.disableReasons.suspiciousInstall ||
-          this.data.runtimeWarnings.length > 0 || !!this.data.blacklistText;
-    },
+  /**
+   * @return {boolean}
+   * @private
+   */
+  computeInspectViewsHidden_: function() {
+    return !this.data.views || this.data.views.length == 0;
+  },
 
-    /**
-     * @return {string}
-     * @private
-     */
-    computeWarningsClasses_: function() {
-      return this.data.blacklistText ? 'severe' : 'mild';
-    },
-  });
+  /**
+   * @return {string}
+   * @private
+   */
+  computeFirstInspectTitle_: function() {
+    // Note: theoretically, this wouldn't be called without any inspectable
+    // views (because it's in a dom-if="!computeInspectViewsHidden_()").
+    // However, due to the recycling behavior of iron list, it seems that
+    // sometimes it can. Even when it is, the UI behaves properly, but we
+    // need to handle the case gracefully.
+    return this.data.views.length > 0 ?
+        computeInspectableViewLabel(this.data.views[0]) :
+        '';
+  },
+
+  /**
+   * @return {string}
+   * @private
+   */
+  computeFirstInspectLabel_: function() {
+    const label = this.computeFirstInspectTitle_();
+    return label && this.data.views.length > 1 ? label + ',' : label;
+  },
+
+  /**
+   * @return {boolean}
+   * @private
+   */
+  computeExtraViewsHidden_: function() {
+    return this.data.views.length <= 1;
+  },
+
+  /**
+   * @return {boolean}
+   * @private
+   */
+  computeDevReloadButtonHidden_: function() {
+    // Only display the reload spinner if the extension is unpacked and
+    // enabled. There's no point in reloading a disabled extension, and we'll
+    // show a crashed reload button if it's terminated.
+    const showIcon =
+        this.data.location == chrome.developerPrivate.Location.UNPACKED &&
+        this.data.state == chrome.developerPrivate.ExtensionState.ENABLED;
+    return !showIcon;
+  },
+
+  /**
+   * @return {string}
+   * @private
+   */
+  computeExtraInspectLabel_: function() {
+    return this.i18n(
+        'itemInspectViewsExtra', (this.data.views.length - 1).toString());
+  },
+
+  /**
+   * @return {boolean}
+   * @private
+   */
+  hasWarnings_: function() {
+    return this.data.disableReasons.corruptInstall ||
+        this.data.disableReasons.suspiciousInstall ||
+        this.data.runtimeWarnings.length > 0 || !!this.data.blacklistText;
+  },
+
+  /**
+   * @return {string}
+   * @private
+   */
+  computeWarningsClasses_: function() {
+    return this.data.blacklistText ? 'severe' : 'mild';
+  },
+});
diff --git a/chrome/browser/resources/extensions/item_behavior.js b/chrome/browser/resources/extensions/item_behavior.js
index 07c7794..c1e368a 100644
--- a/chrome/browser/resources/extensions/item_behavior.js
+++ b/chrome/browser/resources/extensions/item_behavior.js
@@ -4,25 +4,25 @@
 
 import {assertNotReached} from 'chrome://resources/js/assert.m.js';
 
-  /** @polymerBehavior */
-  export const ItemBehavior = {
-    /**
-     * @param {chrome.developerPrivate.ExtensionType} type
-     * @param {string} appLabel
-     * @param {string} extensionLabel
-     * @return {string} The app or extension label depending on |type|.
-     */
-    appOrExtension: function(type, appLabel, extensionLabel) {
-      const ExtensionType = chrome.developerPrivate.ExtensionType;
-      switch (type) {
-        case ExtensionType.HOSTED_APP:
-        case ExtensionType.LEGACY_PACKAGED_APP:
-        case ExtensionType.PLATFORM_APP:
-          return appLabel;
-        case ExtensionType.EXTENSION:
-        case ExtensionType.SHARED_MODULE:
-          return extensionLabel;
-      }
-      assertNotReached('Item type is not App or Extension.');
-    },
-  };
+/** @polymerBehavior */
+export const ItemBehavior = {
+  /**
+   * @param {chrome.developerPrivate.ExtensionType} type
+   * @param {string} appLabel
+   * @param {string} extensionLabel
+   * @return {string} The app or extension label depending on |type|.
+   */
+  appOrExtension: function(type, appLabel, extensionLabel) {
+    const ExtensionType = chrome.developerPrivate.ExtensionType;
+    switch (type) {
+      case ExtensionType.HOSTED_APP:
+      case ExtensionType.LEGACY_PACKAGED_APP:
+      case ExtensionType.PLATFORM_APP:
+        return appLabel;
+      case ExtensionType.EXTENSION:
+      case ExtensionType.SHARED_MODULE:
+        return extensionLabel;
+    }
+    assertNotReached('Item type is not App or Extension.');
+  },
+};
diff --git a/chrome/browser/resources/extensions/item_list.js b/chrome/browser/resources/extensions/item_list.js
index b11d8be2..f24ce18 100644
--- a/chrome/browser/resources/extensions/item_list.js
+++ b/chrome/browser/resources/extensions/item_list.js
@@ -12,121 +12,121 @@
 
 import {ItemDelegate} from './item.js';
 
-  Polymer({
-    is: 'extensions-item-list',
+Polymer({
+  is: 'extensions-item-list',
 
-    _template: html`{__html_template__}`,
+  _template: html`{__html_template__}`,
 
-    behaviors: [CrContainerShadowBehavior, I18nBehavior],
+  behaviors: [CrContainerShadowBehavior, I18nBehavior],
 
-    properties: {
-      /** @type {!Array<!chrome.developerPrivate.ExtensionInfo>} */
-      apps: Array,
+  properties: {
+    /** @type {!Array<!chrome.developerPrivate.ExtensionInfo>} */
+    apps: Array,
 
-      /** @type {!Array<!chrome.developerPrivate.ExtensionInfo>} */
-      extensions: Array,
+    /** @type {!Array<!chrome.developerPrivate.ExtensionInfo>} */
+    extensions: Array,
 
-      /** @type {ItemDelegate} */
-      delegate: Object,
+    /** @type {ItemDelegate} */
+    delegate: Object,
 
-      inDevMode: {
-        type: Boolean,
-        value: false,
-      },
-
-      filter: {
-        type: String,
-      },
-
-      /** @private */
-      computedFilter_: {
-        type: String,
-        computed: 'computeFilter_(filter)',
-        observer: 'announceSearchResults_',
-      },
-
-      /** @private */
-      shownExtensionsCount_: {
-        type: Number,
-        value: 0,
-      },
-
-      /** @private */
-      shownAppsCount_: {
-        type: Number,
-        value: 0,
-      },
+    inDevMode: {
+      type: Boolean,
+      value: false,
     },
 
-    /**
-     * @param {string} id
-     * @return {?Element}
-     */
-    getDetailsButton: function(id) {
-      const item = this.$$(`#${id}`);
-      return item && item.getDetailsButton();
-    },
-
-    /**
-     * @param {string} id
-     * @return {?Element}
-     */
-    getErrorsButton: function(id) {
-      const item = this.$$(`#${id}`);
-      return item && item.getErrorsButton();
-    },
-
-    /**
-     * Computes the filter function to be used for determining which items
-     * should be shown. A |null| value indicates that everything should be
-     * shown.
-     * return {?Function}
-     * @private
-     */
-    computeFilter_: function() {
-      const formattedFilter = this.filter.trim().toLowerCase();
-      return formattedFilter ?
-          i => i.name.toLowerCase().includes(formattedFilter) :
-          null;
+    filter: {
+      type: String,
     },
 
     /** @private */
-    shouldShowEmptyItemsMessage_: function() {
-      if (!this.apps || !this.extensions) {
-        return;
-      }
-
-      return this.apps.length === 0 && this.extensions.length === 0;
+    computedFilter_: {
+      type: String,
+      computed: 'computeFilter_(filter)',
+      observer: 'announceSearchResults_',
     },
 
     /** @private */
-    shouldShowEmptySearchMessage_: function() {
-      return !this.shouldShowEmptyItemsMessage_() &&
-          this.shownAppsCount_ === 0 && this.shownExtensionsCount_ === 0;
+    shownExtensionsCount_: {
+      type: Number,
+      value: 0,
     },
 
     /** @private */
-    onNoExtensionsTap_: function(e) {
-      if (e.target.tagName == 'A') {
-        chrome.metricsPrivate.recordUserAction('Options_GetMoreExtensions');
-      }
+    shownAppsCount_: {
+      type: Number,
+      value: 0,
     },
+  },
 
-    /** @private */
-    announceSearchResults_: function() {
-      if (this.computedFilter_) {
-        IronA11yAnnouncer.requestAvailability();
-        this.async(() => {  // Async to allow list to update.
-          const total = this.shownAppsCount_ + this.shownExtensionsCount_;
-          this.fire('iron-announce', {
-            text: this.shouldShowEmptySearchMessage_() ?
-                this.i18n('noSearchResults') :
-                (total == 1 ?
-                     this.i18n('searchResultsSingular', this.filter) :
-                     this.i18n(
-                         'searchResultsPlural', total.toString(), this.filter)),
-          });
+  /**
+   * @param {string} id
+   * @return {?Element}
+   */
+  getDetailsButton: function(id) {
+    const item = this.$$(`#${id}`);
+    return item && item.getDetailsButton();
+  },
+
+  /**
+   * @param {string} id
+   * @return {?Element}
+   */
+  getErrorsButton: function(id) {
+    const item = this.$$(`#${id}`);
+    return item && item.getErrorsButton();
+  },
+
+  /**
+   * Computes the filter function to be used for determining which items
+   * should be shown. A |null| value indicates that everything should be
+   * shown.
+   * return {?Function}
+   * @private
+   */
+  computeFilter_: function() {
+    const formattedFilter = this.filter.trim().toLowerCase();
+    return formattedFilter ?
+        i => i.name.toLowerCase().includes(formattedFilter) :
+        null;
+  },
+
+  /** @private */
+  shouldShowEmptyItemsMessage_: function() {
+    if (!this.apps || !this.extensions) {
+      return;
+    }
+
+    return this.apps.length === 0 && this.extensions.length === 0;
+  },
+
+  /** @private */
+  shouldShowEmptySearchMessage_: function() {
+    return !this.shouldShowEmptyItemsMessage_() && this.shownAppsCount_ === 0 &&
+        this.shownExtensionsCount_ === 0;
+  },
+
+  /** @private */
+  onNoExtensionsTap_: function(e) {
+    if (e.target.tagName == 'A') {
+      chrome.metricsPrivate.recordUserAction('Options_GetMoreExtensions');
+    }
+  },
+
+  /** @private */
+  announceSearchResults_: function() {
+    if (this.computedFilter_) {
+      IronA11yAnnouncer.requestAvailability();
+      this.async(() => {  // Async to allow list to update.
+        const total = this.shownAppsCount_ + this.shownExtensionsCount_;
+        this.fire('iron-announce', {
+          text: this.shouldShowEmptySearchMessage_() ?
+              this.i18n('noSearchResults') :
+              (total == 1 ?
+                   this.i18n('searchResultsSingular', this.filter) :
+                   this.i18n(
+                       'searchResultsPlural', total.toString(), this.filter)),
         });
-      }
-    },
-  });
+      });
+    }
+  },
+});
diff --git a/chrome/browser/resources/extensions/item_util.js b/chrome/browser/resources/extensions/item_util.js
index dccf05dba..b137f5d8 100644
--- a/chrome/browser/resources/extensions/item_util.js
+++ b/chrome/browser/resources/extensions/item_util.js
@@ -8,144 +8,144 @@
 import {loadTimeData} from 'chrome://resources/js/load_time_data.m.js';
 
 
-  // Closure compiler won't let this be declared inside cr.define().
-  /** @enum {string} */
-  export const SourceType = {
-    WEBSTORE: 'webstore',
-    POLICY: 'policy',
-    SIDELOADED: 'sideloaded',
-    UNPACKED: 'unpacked',
-    UNKNOWN: 'unknown',
-  };
+// Closure compiler won't let this be declared inside cr.define().
+/** @enum {string} */
+export const SourceType = {
+  WEBSTORE: 'webstore',
+  POLICY: 'policy',
+  SIDELOADED: 'sideloaded',
+  UNPACKED: 'unpacked',
+  UNKNOWN: 'unknown',
+};
 
-  /**
-   * Returns true if the extension is enabled, including terminated
-   * extensions.
-   * @param {!chrome.developerPrivate.ExtensionState} state
-   * @return {boolean}
-   */
-  export function isEnabled(state) {
-    switch (state) {
-      case chrome.developerPrivate.ExtensionState.ENABLED:
-      case chrome.developerPrivate.ExtensionState.TERMINATED:
-        return true;
-      case chrome.developerPrivate.ExtensionState.BLACKLISTED:
-      case chrome.developerPrivate.ExtensionState.DISABLED:
-        return false;
-    }
-    assertNotReached();
-  }
-
-    /**
-     * @param {!chrome.developerPrivate.ExtensionInfo} extensionInfo
-     * @return {boolean} Whether the extension is controlled.
-     */
-  export function isControlled(extensionInfo) {
-    return !!extensionInfo.controlledInfo;
-  }
-
-    /**
-     * Returns true if the user can change whether or not the extension is
-     * enabled.
-     * @param {!chrome.developerPrivate.ExtensionInfo} item
-     * @return {boolean}
-     */
-  export function userCanChangeEnablement(item) {
-    // User doesn't have permission.
-    if (!item.userMayModify) {
+/**
+ * Returns true if the extension is enabled, including terminated
+ * extensions.
+ * @param {!chrome.developerPrivate.ExtensionState} state
+ * @return {boolean}
+ */
+export function isEnabled(state) {
+  switch (state) {
+    case chrome.developerPrivate.ExtensionState.ENABLED:
+    case chrome.developerPrivate.ExtensionState.TERMINATED:
+      return true;
+    case chrome.developerPrivate.ExtensionState.BLACKLISTED:
+    case chrome.developerPrivate.ExtensionState.DISABLED:
       return false;
-    }
-    // Item is forcefully disabled.
-    if (item.disableReasons.corruptInstall ||
-        item.disableReasons.suspiciousInstall ||
-        item.disableReasons.updateRequired) {
-      return false;
-    }
-    // An item with dependent extensions can't be disabled (it would bork the
-    // dependents).
-    if (item.dependentExtensions.length > 0) {
-      return false;
-    }
-    // Blacklisted can't be enabled, either.
-    if (item.state == chrome.developerPrivate.ExtensionState.BLACKLISTED) {
-      return false;
-    }
+  }
+  assertNotReached();
+}
 
-    return true;
+/**
+ * @param {!chrome.developerPrivate.ExtensionInfo} extensionInfo
+ * @return {boolean} Whether the extension is controlled.
+ */
+export function isControlled(extensionInfo) {
+  return !!extensionInfo.controlledInfo;
+}
+
+/**
+ * Returns true if the user can change whether or not the extension is
+ * enabled.
+ * @param {!chrome.developerPrivate.ExtensionInfo} item
+ * @return {boolean}
+ */
+export function userCanChangeEnablement(item) {
+  // User doesn't have permission.
+  if (!item.userMayModify) {
+    return false;
+  }
+  // Item is forcefully disabled.
+  if (item.disableReasons.corruptInstall ||
+      item.disableReasons.suspiciousInstall ||
+      item.disableReasons.updateRequired) {
+    return false;
+  }
+  // An item with dependent extensions can't be disabled (it would bork the
+  // dependents).
+  if (item.dependentExtensions.length > 0) {
+    return false;
+  }
+  // Blacklisted can't be enabled, either.
+  if (item.state == chrome.developerPrivate.ExtensionState.BLACKLISTED) {
+    return false;
   }
 
-    /**
-     * @param {!chrome.developerPrivate.ExtensionInfo} item
-     * @return {SourceType}
-     */
-  export function getItemSource(item) {
-    if (item.controlledInfo &&
-        item.controlledInfo.type ==
-            chrome.developerPrivate.ControllerType.POLICY) {
-      return SourceType.POLICY;
-    }
+  return true;
+}
 
-    switch (item.location) {
-      case chrome.developerPrivate.Location.THIRD_PARTY:
-        return SourceType.SIDELOADED;
-      case chrome.developerPrivate.Location.UNPACKED:
-        return SourceType.UNPACKED;
-      case chrome.developerPrivate.Location.UNKNOWN:
-        return SourceType.UNKNOWN;
-      case chrome.developerPrivate.Location.FROM_STORE:
-        return SourceType.WEBSTORE;
-    }
-
-    assertNotReached(item.location);
+/**
+ * @param {!chrome.developerPrivate.ExtensionInfo} item
+ * @return {SourceType}
+ */
+export function getItemSource(item) {
+  if (item.controlledInfo &&
+      item.controlledInfo.type ==
+          chrome.developerPrivate.ControllerType.POLICY) {
+    return SourceType.POLICY;
   }
 
-    /**
-     * @param {SourceType} source
-     * @return {string}
-     */
-  export function getItemSourceString(source) {
-    switch (source) {
-      case SourceType.POLICY:
-        return loadTimeData.getString('itemSourcePolicy');
-      case SourceType.SIDELOADED:
-        return loadTimeData.getString('itemSourceSideloaded');
-      case SourceType.UNPACKED:
-        return loadTimeData.getString('itemSourceUnpacked');
-      case SourceType.WEBSTORE:
-        return loadTimeData.getString('itemSourceWebstore');
-      case SourceType.UNKNOWN:
-        // Nothing to return. Calling code should use
-        // chrome.developerPrivate.ExtensionInfo's |locationText| instead.
-        return '';
-    }
-    assertNotReached();
+  switch (item.location) {
+    case chrome.developerPrivate.Location.THIRD_PARTY:
+      return SourceType.SIDELOADED;
+    case chrome.developerPrivate.Location.UNPACKED:
+      return SourceType.UNPACKED;
+    case chrome.developerPrivate.Location.UNKNOWN:
+      return SourceType.UNKNOWN;
+    case chrome.developerPrivate.Location.FROM_STORE:
+      return SourceType.WEBSTORE;
   }
 
-    /**
-     * Computes the human-facing label for the given inspectable view.
-     * @param {!chrome.developerPrivate.ExtensionView} view
-     * @return {string}
-     */
-  export function computeInspectableViewLabel(view) {
-    // Trim the "chrome-extension://<id>/".
-    const url = new URL(view.url);
-    let label = view.url;
-    if (url.protocol == 'chrome-extension:') {
-      label = url.pathname.substring(1);
-    }
-    if (label == '_generated_background_page.html') {
-      label = loadTimeData.getString('viewBackgroundPage');
-    }
-    // Add any qualifiers.
-    if (view.incognito) {
-      label += ' ' + loadTimeData.getString('viewIncognito');
-    }
-    if (view.renderProcessId == -1) {
-      label += ' ' + loadTimeData.getString('viewInactive');
-    }
-    if (view.isIframe) {
-      label += ' ' + loadTimeData.getString('viewIframe');
-    }
+  assertNotReached(item.location);
+}
 
-    return label;
+/**
+ * @param {SourceType} source
+ * @return {string}
+ */
+export function getItemSourceString(source) {
+  switch (source) {
+    case SourceType.POLICY:
+      return loadTimeData.getString('itemSourcePolicy');
+    case SourceType.SIDELOADED:
+      return loadTimeData.getString('itemSourceSideloaded');
+    case SourceType.UNPACKED:
+      return loadTimeData.getString('itemSourceUnpacked');
+    case SourceType.WEBSTORE:
+      return loadTimeData.getString('itemSourceWebstore');
+    case SourceType.UNKNOWN:
+      // Nothing to return. Calling code should use
+      // chrome.developerPrivate.ExtensionInfo's |locationText| instead.
+      return '';
   }
+  assertNotReached();
+}
+
+/**
+ * Computes the human-facing label for the given inspectable view.
+ * @param {!chrome.developerPrivate.ExtensionView} view
+ * @return {string}
+ */
+export function computeInspectableViewLabel(view) {
+  // Trim the "chrome-extension://<id>/".
+  const url = new URL(view.url);
+  let label = view.url;
+  if (url.protocol == 'chrome-extension:') {
+    label = url.pathname.substring(1);
+  }
+  if (label == '_generated_background_page.html') {
+    label = loadTimeData.getString('viewBackgroundPage');
+  }
+  // Add any qualifiers.
+  if (view.incognito) {
+    label += ' ' + loadTimeData.getString('viewIncognito');
+  }
+  if (view.renderProcessId == -1) {
+    label += ' ' + loadTimeData.getString('viewInactive');
+  }
+  if (view.isIframe) {
+    label += ' ' + loadTimeData.getString('viewIframe');
+  }
+
+  return label;
+}
diff --git a/chrome/browser/resources/extensions/keyboard_shortcut_delegate.js b/chrome/browser/resources/extensions/keyboard_shortcut_delegate.js
index 4c4a293..4281304e 100644
--- a/chrome/browser/resources/extensions/keyboard_shortcut_delegate.js
+++ b/chrome/browser/resources/extensions/keyboard_shortcut_delegate.js
@@ -4,32 +4,32 @@
 
 'use strict';
 
-  /** @interface */
-  export class KeyboardShortcutDelegate {
-    /**
-     * Called when shortcut capturing changes in order to suspend or re-enable
-     * global shortcut handling. This is important so that the shortcuts aren't
-     * processed normally as the user types them.
-     * TODO(devlin): From very brief experimentation, it looks like preventing
-     * the default handling on the event also does this. Investigate more in the
-     * future.
-     * @param {boolean} isCapturing
-     */
-    setShortcutHandlingSuspended(isCapturing) {}
+/** @interface */
+export class KeyboardShortcutDelegate {
+  /**
+   * Called when shortcut capturing changes in order to suspend or re-enable
+   * global shortcut handling. This is important so that the shortcuts aren't
+   * processed normally as the user types them.
+   * TODO(devlin): From very brief experimentation, it looks like preventing
+   * the default handling on the event also does this. Investigate more in the
+   * future.
+   * @param {boolean} isCapturing
+   */
+  setShortcutHandlingSuspended(isCapturing) {}
 
-    /**
-     * Updates an extension command's keybinding.
-     * @param {string} extensionId
-     * @param {string} commandName
-     * @param {string} keybinding
-     */
-    updateExtensionCommandKeybinding(extensionId, commandName, keybinding) {}
+  /**
+   * Updates an extension command's keybinding.
+   * @param {string} extensionId
+   * @param {string} commandName
+   * @param {string} keybinding
+   */
+  updateExtensionCommandKeybinding(extensionId, commandName, keybinding) {}
 
-    /**
-     * Updates an extension command's scope.
-     * @param {string} extensionId
-     * @param {string} commandName
-     * @param {chrome.developerPrivate.CommandScope} scope
-     */
-    updateExtensionCommandScope(extensionId, commandName, scope) {}
-  }
+  /**
+   * Updates an extension command's scope.
+   * @param {string} extensionId
+   * @param {string} commandName
+   * @param {chrome.developerPrivate.CommandScope} scope
+   */
+  updateExtensionCommandScope(extensionId, commandName, scope) {}
+}
diff --git a/chrome/browser/resources/extensions/keyboard_shortcuts.js b/chrome/browser/resources/extensions/keyboard_shortcuts.js
index 6a92974d..92d8663 100644
--- a/chrome/browser/resources/extensions/keyboard_shortcuts.js
+++ b/chrome/browser/resources/extensions/keyboard_shortcuts.js
@@ -14,95 +14,95 @@
 import {ItemBehavior} from './item_behavior.js';
 import {KeyboardShortcutDelegate} from './keyboard_shortcut_delegate.js';
 
-  // The UI to display and manage keyboard shortcuts set for extension commands.
-  Polymer({
-    is: 'extensions-keyboard-shortcuts',
+// The UI to display and manage keyboard shortcuts set for extension commands.
+Polymer({
+  is: 'extensions-keyboard-shortcuts',
 
-    _template: html`{__html_template__}`,
+  _template: html`{__html_template__}`,
 
-    behaviors: [CrContainerShadowBehavior, ItemBehavior],
+  behaviors: [CrContainerShadowBehavior, ItemBehavior],
 
-    properties: {
-      /** @type {!KeyboardShortcutDelegate} */
-      delegate: Object,
+  properties: {
+    /** @type {!KeyboardShortcutDelegate} */
+    delegate: Object,
 
-      /** @type {Array<!chrome.developerPrivate.ExtensionInfo>} */
-      items: Array,
-
-      /**
-       * Proxying the enum to be used easily by the html template.
-       * @private
-       */
-      CommandScope_: {
-        type: Object,
-        value: chrome.developerPrivate.CommandScope,
-      },
-    },
-
-    listeners: {
-      'view-enter-start': 'onViewEnter_',
-    },
-
-    /** @private */
-    onViewEnter_: function() {
-      chrome.metricsPrivate.recordUserAction('Options_ExtensionCommands');
-    },
+    /** @type {Array<!chrome.developerPrivate.ExtensionInfo>} */
+    items: Array,
 
     /**
-     * @return {!Array<!chrome.developerPrivate.ExtensionInfo>}
+     * Proxying the enum to be used easily by the html template.
      * @private
      */
-    calculateShownItems_: function() {
-      return this.items.filter(function(item) {
-        return item.commands.length > 0;
-      });
+    CommandScope_: {
+      type: Object,
+      value: chrome.developerPrivate.CommandScope,
     },
+  },
 
-    /**
-     * A polymer bug doesn't allow for databinding of a string property as a
-     * boolean, but it is correctly interpreted from a function.
-     * Bug: https://github.com/Polymer/polymer/issues/3669
-     * @param {string} keybinding
-     * @return {boolean}
-     * @private
-     */
-    hasKeybinding_: function(keybinding) {
-      return !!keybinding;
-    },
+  listeners: {
+    'view-enter-start': 'onViewEnter_',
+  },
 
-    /**
-     * Determines whether to disable the dropdown menu for the command's scope.
-     * @param {!chrome.developerPrivate.Command} command
-     * @return {boolean}
-     * @private
-     */
-    computeScopeDisabled_: function(command) {
-      return command.isExtensionAction || !command.isActive;
-    },
+  /** @private */
+  onViewEnter_: function() {
+    chrome.metricsPrivate.recordUserAction('Options_ExtensionCommands');
+  },
 
-    /**
-     * This function exists to force trigger an update when CommandScope_
-     * becomes available.
-     * @param {string} scope
-     * @return {string}
-     */
-    triggerScopeChange_: function(scope) {
-      return scope;
-    },
+  /**
+   * @return {!Array<!chrome.developerPrivate.ExtensionInfo>}
+   * @private
+   */
+  calculateShownItems_: function() {
+    return this.items.filter(function(item) {
+      return item.commands.length > 0;
+    });
+  },
 
-    /** @private */
-    onCloseButtonClick_: function() {
-      this.fire('close');
-    },
+  /**
+   * A polymer bug doesn't allow for databinding of a string property as a
+   * boolean, but it is correctly interpreted from a function.
+   * Bug: https://github.com/Polymer/polymer/issues/3669
+   * @param {string} keybinding
+   * @return {boolean}
+   * @private
+   */
+  hasKeybinding_: function(keybinding) {
+    return !!keybinding;
+  },
 
-    /**
-     * @param {!{target: HTMLSelectElement, model: Object}} event
-     * @private
-     */
-    onScopeChanged_: function(event) {
-      this.delegate.updateExtensionCommandScope(
-          event.model.get('item.id'), event.model.get('command.name'),
-          /** @type {chrome.developerPrivate.CommandScope} */
-          (event.target.value));
-    },
-  });
+  /**
+   * Determines whether to disable the dropdown menu for the command's scope.
+   * @param {!chrome.developerPrivate.Command} command
+   * @return {boolean}
+   * @private
+   */
+  computeScopeDisabled_: function(command) {
+    return command.isExtensionAction || !command.isActive;
+  },
+
+  /**
+   * This function exists to force trigger an update when CommandScope_
+   * becomes available.
+   * @param {string} scope
+   * @return {string}
+   */
+  triggerScopeChange_: function(scope) {
+    return scope;
+  },
+
+  /** @private */
+  onCloseButtonClick_: function() {
+    this.fire('close');
+  },
+
+  /**
+   * @param {!{target: HTMLSelectElement, model: Object}} event
+   * @private
+   */
+  onScopeChanged_: function(event) {
+    this.delegate.updateExtensionCommandScope(
+        event.model.get('item.id'), event.model.get('command.name'),
+        /** @type {chrome.developerPrivate.CommandScope} */
+        (event.target.value));
+  },
+});
diff --git a/chrome/browser/resources/extensions/kiosk_browser_proxy.js b/chrome/browser/resources/extensions/kiosk_browser_proxy.js
index 1316bb6..2a00b9e 100644
--- a/chrome/browser/resources/extensions/kiosk_browser_proxy.js
+++ b/chrome/browser/resources/extensions/kiosk_browser_proxy.js
@@ -37,66 +37,66 @@
  */
 export let KioskAppSettings;
 
-  /** @interface */
-  export class KioskBrowserProxy {
-    /** @param {string} appId */
-    addKioskApp(appId) {}
+/** @interface */
+export class KioskBrowserProxy {
+  /** @param {string} appId */
+  addKioskApp(appId) {}
 
-    /** @param {string} appId */
-    disableKioskAutoLaunch(appId) {}
+  /** @param {string} appId */
+  disableKioskAutoLaunch(appId) {}
 
-    /** @param {string} appId */
-    enableKioskAutoLaunch(appId) {}
+  /** @param {string} appId */
+  enableKioskAutoLaunch(appId) {}
 
-    /** @return {!Promise<!KioskAppSettings>} */
-    getKioskAppSettings() {}
+  /** @return {!Promise<!KioskAppSettings>} */
+  getKioskAppSettings() {}
 
-    /** @return {!Promise<!KioskSettings>} */
-    initializeKioskAppSettings() {}
+  /** @return {!Promise<!KioskSettings>} */
+  initializeKioskAppSettings() {}
 
-    /** @param {string} appId */
-    removeKioskApp(appId) {}
+  /** @param {string} appId */
+  removeKioskApp(appId) {}
 
-    /** @param {boolean} disableBailout */
-    setDisableBailoutShortcut(disableBailout) {}
+  /** @param {boolean} disableBailout */
+  setDisableBailoutShortcut(disableBailout) {}
+}
+
+/** @implements {KioskBrowserProxy} */
+export class KioskBrowserProxyImpl {
+  /** @override */
+  initializeKioskAppSettings() {
+    return sendWithPromise('initializeKioskAppSettings');
   }
 
-  /** @implements {KioskBrowserProxy} */
-  export class KioskBrowserProxyImpl {
-    /** @override */
-    initializeKioskAppSettings() {
-      return sendWithPromise('initializeKioskAppSettings');
-    }
-
-    /** @override */
-    getKioskAppSettings() {
-      return sendWithPromise('getKioskAppSettings');
-    }
-
-    /** @override */
-    addKioskApp(appId) {
-      chrome.send('addKioskApp', [appId]);
-    }
-
-    /** @override */
-    disableKioskAutoLaunch(appId) {
-      chrome.send('disableKioskAutoLaunch', [appId]);
-    }
-
-    /** @override */
-    enableKioskAutoLaunch(appId) {
-      chrome.send('enableKioskAutoLaunch', [appId]);
-    }
-
-    /** @override */
-    removeKioskApp(appId) {
-      chrome.send('removeKioskApp', [appId]);
-    }
-
-    /** @override */
-    setDisableBailoutShortcut(disableBailout) {
-      chrome.send('setDisableBailoutShortcut', [disableBailout]);
-    }
+  /** @override */
+  getKioskAppSettings() {
+    return sendWithPromise('getKioskAppSettings');
   }
 
-  addSingletonGetter(KioskBrowserProxyImpl);
+  /** @override */
+  addKioskApp(appId) {
+    chrome.send('addKioskApp', [appId]);
+  }
+
+  /** @override */
+  disableKioskAutoLaunch(appId) {
+    chrome.send('disableKioskAutoLaunch', [appId]);
+  }
+
+  /** @override */
+  enableKioskAutoLaunch(appId) {
+    chrome.send('enableKioskAutoLaunch', [appId]);
+  }
+
+  /** @override */
+  removeKioskApp(appId) {
+    chrome.send('removeKioskApp', [appId]);
+  }
+
+  /** @override */
+  setDisableBailoutShortcut(disableBailout) {
+    chrome.send('setDisableBailoutShortcut', [disableBailout]);
+  }
+}
+
+addSingletonGetter(KioskBrowserProxyImpl);
diff --git a/chrome/browser/resources/extensions/kiosk_dialog.js b/chrome/browser/resources/extensions/kiosk_dialog.js
index bfae0a1..04bc4cb 100644
--- a/chrome/browser/resources/extensions/kiosk_dialog.js
+++ b/chrome/browser/resources/extensions/kiosk_dialog.js
@@ -18,179 +18,179 @@
 import {KioskApp, KioskAppSettings, KioskBrowserProxy, KioskBrowserProxyImpl} from './kiosk_browser_proxy.js';
 
 
-  Polymer({
-    is: 'extensions-kiosk-dialog',
+Polymer({
+  is: 'extensions-kiosk-dialog',
 
-    _template: html`{__html_template__}`,
+  _template: html`{__html_template__}`,
 
-    behaviors: [WebUIListenerBehavior, ItemBehavior],
+  behaviors: [WebUIListenerBehavior, ItemBehavior],
 
-    properties: {
-      /** @private {?string} */
-      addAppInput_: {
-        type: String,
-        value: null,
-      },
-
-      /** @private {!Array<!KioskApp>} */
-      apps_: Array,
-
-      /** @private */
-      bailoutDisabled_: Boolean,
-
-      /** @private */
-      canEditAutoLaunch_: Boolean,
-
-      /** @private */
-      canEditBailout_: Boolean,
-
-      /** @private {?string} */
-      errorAppId_: String,
+  properties: {
+    /** @private {?string} */
+    addAppInput_: {
+      type: String,
+      value: null,
     },
 
-    /** @private {?KioskBrowserProxy} */
-    kioskBrowserProxy_: null,
-
-    /** @override */
-    ready: function() {
-      this.kioskBrowserProxy_ = KioskBrowserProxyImpl.getInstance();
-    },
-
-    /** @override */
-    attached: function() {
-      this.kioskBrowserProxy_.initializeKioskAppSettings()
-          .then(params => {
-            this.canEditAutoLaunch_ = params.autoLaunchEnabled;
-            return this.kioskBrowserProxy_.getKioskAppSettings();
-          })
-          .then(this.setSettings_.bind(this));
-
-      this.addWebUIListener(
-          'kiosk-app-settings-changed', this.setSettings_.bind(this));
-      this.addWebUIListener('kiosk-app-updated', this.updateApp_.bind(this));
-      this.addWebUIListener('kiosk-app-error', this.showError_.bind(this));
-
-      this.$.dialog.showModal();
-    },
-
-    /**
-     * @param {!KioskAppSettings} settings
-     * @private
-     */
-    setSettings_: function(settings) {
-      this.apps_ = settings.apps;
-      this.bailoutDisabled_ = settings.disableBailout;
-      this.canEditBailout_ = settings.hasAutoLaunchApp;
-    },
-
-    /**
-     * @param {!KioskApp} app
-     * @private
-     */
-    updateApp_: function(app) {
-      const index = this.apps_.findIndex(a => a.id == app.id);
-      assert(index < this.apps_.length);
-      this.set('apps_.' + index, app);
-    },
-
-    /**
-     * @param {string} appId
-     * @private
-     */
-    showError_: function(appId) {
-      this.errorAppId_ = appId;
-    },
-
-    /**
-     * @param {string} errorMessage
-     * @return {string}
-     * @private
-     */
-    getErrorMessage_: function(errorMessage) {
-      return this.errorAppId_ + ' ' + errorMessage;
-    },
+    /** @private {!Array<!KioskApp>} */
+    apps_: Array,
 
     /** @private */
-    onAddAppTap_: function() {
-      assert(this.addAppInput_);
-      this.kioskBrowserProxy_.addKioskApp(this.addAppInput_);
-      this.addAppInput_ = null;
-    },
+    bailoutDisabled_: Boolean,
 
     /** @private */
-    clearInputInvalid_: function() {
-      this.errorAppId_ = null;
-    },
-
-    /**
-     * @param {{model: {item: !KioskApp}}} event
-     * @private
-     */
-    onAutoLaunchButtonTap_: function(event) {
-      const app = event.model.item;
-      if (app.autoLaunch) {  // If the app is originally set to
-                             // auto-launch.
-        this.kioskBrowserProxy_.disableKioskAutoLaunch(app.id);
-      } else {
-        this.kioskBrowserProxy_.enableKioskAutoLaunch(app.id);
-      }
-    },
-
-    /**
-     * @param {!Event} event
-     * @private
-     */
-    onBailoutChanged_: function(event) {
-      event.preventDefault();
-      if (this.$.bailout.checked) {
-        this.$['confirm-dialog'].showModal();
-      } else {
-        this.kioskBrowserProxy_.setDisableBailoutShortcut(false);
-        this.$['confirm-dialog'].close();
-      }
-    },
+    canEditAutoLaunch_: Boolean,
 
     /** @private */
-    onBailoutDialogCancelTap_: function() {
-      this.$.bailout.checked = false;
-      this.$['confirm-dialog'].cancel();
-    },
+    canEditBailout_: Boolean,
 
-    /** @private */
-    onBailoutDialogConfirmTap_: function() {
-      this.kioskBrowserProxy_.setDisableBailoutShortcut(true);
+    /** @private {?string} */
+    errorAppId_: String,
+  },
+
+  /** @private {?KioskBrowserProxy} */
+  kioskBrowserProxy_: null,
+
+  /** @override */
+  ready: function() {
+    this.kioskBrowserProxy_ = KioskBrowserProxyImpl.getInstance();
+  },
+
+  /** @override */
+  attached: function() {
+    this.kioskBrowserProxy_.initializeKioskAppSettings()
+        .then(params => {
+          this.canEditAutoLaunch_ = params.autoLaunchEnabled;
+          return this.kioskBrowserProxy_.getKioskAppSettings();
+        })
+        .then(this.setSettings_.bind(this));
+
+    this.addWebUIListener(
+        'kiosk-app-settings-changed', this.setSettings_.bind(this));
+    this.addWebUIListener('kiosk-app-updated', this.updateApp_.bind(this));
+    this.addWebUIListener('kiosk-app-error', this.showError_.bind(this));
+
+    this.$.dialog.showModal();
+  },
+
+  /**
+   * @param {!KioskAppSettings} settings
+   * @private
+   */
+  setSettings_: function(settings) {
+    this.apps_ = settings.apps;
+    this.bailoutDisabled_ = settings.disableBailout;
+    this.canEditBailout_ = settings.hasAutoLaunchApp;
+  },
+
+  /**
+   * @param {!KioskApp} app
+   * @private
+   */
+  updateApp_: function(app) {
+    const index = this.apps_.findIndex(a => a.id == app.id);
+    assert(index < this.apps_.length);
+    this.set('apps_.' + index, app);
+  },
+
+  /**
+   * @param {string} appId
+   * @private
+   */
+  showError_: function(appId) {
+    this.errorAppId_ = appId;
+  },
+
+  /**
+   * @param {string} errorMessage
+   * @return {string}
+   * @private
+   */
+  getErrorMessage_: function(errorMessage) {
+    return this.errorAppId_ + ' ' + errorMessage;
+  },
+
+  /** @private */
+  onAddAppTap_: function() {
+    assert(this.addAppInput_);
+    this.kioskBrowserProxy_.addKioskApp(this.addAppInput_);
+    this.addAppInput_ = null;
+  },
+
+  /** @private */
+  clearInputInvalid_: function() {
+    this.errorAppId_ = null;
+  },
+
+  /**
+   * @param {{model: {item: !KioskApp}}} event
+   * @private
+   */
+  onAutoLaunchButtonTap_: function(event) {
+    const app = event.model.item;
+    if (app.autoLaunch) {  // If the app is originally set to
+                           // auto-launch.
+      this.kioskBrowserProxy_.disableKioskAutoLaunch(app.id);
+    } else {
+      this.kioskBrowserProxy_.enableKioskAutoLaunch(app.id);
+    }
+  },
+
+  /**
+   * @param {!Event} event
+   * @private
+   */
+  onBailoutChanged_: function(event) {
+    event.preventDefault();
+    if (this.$.bailout.checked) {
+      this.$['confirm-dialog'].showModal();
+    } else {
+      this.kioskBrowserProxy_.setDisableBailoutShortcut(false);
       this.$['confirm-dialog'].close();
-    },
+    }
+  },
 
-    /** @private */
-    onDoneTap_: function() {
-      this.$.dialog.close();
-    },
+  /** @private */
+  onBailoutDialogCancelTap_: function() {
+    this.$.bailout.checked = false;
+    this.$['confirm-dialog'].cancel();
+  },
 
-    /**
-     * @param {{model: {item: !KioskApp}}} event
-     * @private
-     */
-    onDeleteAppTap_: function(event) {
-      this.kioskBrowserProxy_.removeKioskApp(event.model.item.id);
-    },
+  /** @private */
+  onBailoutDialogConfirmTap_: function() {
+    this.kioskBrowserProxy_.setDisableBailoutShortcut(true);
+    this.$['confirm-dialog'].close();
+  },
 
-    /**
-     * @param {boolean} autoLaunched
-     * @param {string} disableStr
-     * @param {string} enableStr
-     * @return {string}
-     * @private
-     */
-    getAutoLaunchButtonLabel_: function(autoLaunched, disableStr, enableStr) {
-      return autoLaunched ? disableStr : enableStr;
-    },
+  /** @private */
+  onDoneTap_: function() {
+    this.$.dialog.close();
+  },
 
-    /**
-     * @param {!Event} e
-     * @private
-     */
-    stopPropagation_: function(e) {
-      e.stopPropagation();
-    },
-  });
+  /**
+   * @param {{model: {item: !KioskApp}}} event
+   * @private
+   */
+  onDeleteAppTap_: function(event) {
+    this.kioskBrowserProxy_.removeKioskApp(event.model.item.id);
+  },
+
+  /**
+   * @param {boolean} autoLaunched
+   * @param {string} disableStr
+   * @param {string} enableStr
+   * @return {string}
+   * @private
+   */
+  getAutoLaunchButtonLabel_: function(autoLaunched, disableStr, enableStr) {
+    return autoLaunched ? disableStr : enableStr;
+  },
+
+  /**
+   * @param {!Event} e
+   * @private
+   */
+  stopPropagation_: function(e) {
+    e.stopPropagation();
+  },
+});
diff --git a/chrome/browser/resources/extensions/load_error.js b/chrome/browser/resources/extensions/load_error.js
index c8c6588..ff678ac 100644
--- a/chrome/browser/resources/extensions/load_error.js
+++ b/chrome/browser/resources/extensions/load_error.js
@@ -12,76 +12,75 @@
 import {assert} from 'chrome://resources/js/assert.m.js';
 import {html, Polymer} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
 
-  /** @interface */
-  export class LoadErrorDelegate {
-    /**
-     * Attempts to load the previously-attempted unpacked extension.
-     * @param {string} retryId
-     * @return {!Promise}
-     */
-    retryLoadUnpacked(retryId) {}
-  }
+/** @interface */
+export class LoadErrorDelegate {
+  /**
+   * Attempts to load the previously-attempted unpacked extension.
+   * @param {string} retryId
+   * @return {!Promise}
+   */
+  retryLoadUnpacked(retryId) {}
+}
 
-  Polymer({
-    is: 'extensions-load-error',
+Polymer({
+  is: 'extensions-load-error',
 
-    _template: html`{__html_template__}`,
+  _template: html`{__html_template__}`,
 
-    properties: {
-      /** @type {LoadErrorDelegate} */
-      delegate: Object,
+  properties: {
+    /** @type {LoadErrorDelegate} */
+    delegate: Object,
 
-      /** @type {chrome.developerPrivate.LoadError} */
-      loadError: Object,
-
-      /** @private */
-      retrying_: Boolean,
-    },
-
-    observers: [
-      'observeLoadErrorChanges_(loadError)',
-    ],
-
-    show: function() {
-      /** @type {!CrDialogElement} */ (this.$.dialog).showModal();
-    },
-
-    close: function() {
-      /** @type {!CrDialogElement} */ (this.$.dialog).close();
-    },
+    /** @type {chrome.developerPrivate.LoadError} */
+    loadError: Object,
 
     /** @private */
-    onRetryTap_: function() {
-      this.retrying_ = true;
-      this.delegate.retryLoadUnpacked(this.loadError.retryGuid)
-          .then(
-              () => {
-                this.close();
-              },
-              loadError => {
-                this.loadError =
-                    /** @type {chrome.developerPrivate.LoadError} */ (
-                        loadError);
-                this.retrying_ = false;
-              });
-    },
+    retrying_: Boolean,
+  },
 
-    /** @private */
-    observeLoadErrorChanges_: function() {
-      assert(this.loadError);
-      const source = this.loadError.source;
-      // CodeSection expects a RequestFileSourceResponse, rather than an
-      // ErrorFileSource. Massage into place.
-      // TODO(devlin): Make RequestFileSourceResponse use ErrorFileSource.
-      /** @type {!chrome.developerPrivate.RequestFileSourceResponse} */
-      const codeSectionProperties = {
-        beforeHighlight: source ? source.beforeHighlight : '',
-        highlight: source ? source.highlight : '',
-        afterHighlight: source ? source.afterHighlight : '',
-        title: '',
-        message: this.loadError.error,
-      };
+  observers: [
+    'observeLoadErrorChanges_(loadError)',
+  ],
 
-      this.$.code.code = codeSectionProperties;
-    },
-  });
+  show: function() {
+    /** @type {!CrDialogElement} */ (this.$.dialog).showModal();
+  },
+
+  close: function() {
+    /** @type {!CrDialogElement} */ (this.$.dialog).close();
+  },
+
+  /** @private */
+  onRetryTap_: function() {
+    this.retrying_ = true;
+    this.delegate.retryLoadUnpacked(this.loadError.retryGuid)
+        .then(
+            () => {
+              this.close();
+            },
+            loadError => {
+              this.loadError =
+                  /** @type {chrome.developerPrivate.LoadError} */ (loadError);
+              this.retrying_ = false;
+            });
+  },
+
+  /** @private */
+  observeLoadErrorChanges_: function() {
+    assert(this.loadError);
+    const source = this.loadError.source;
+    // CodeSection expects a RequestFileSourceResponse, rather than an
+    // ErrorFileSource. Massage into place.
+    // TODO(devlin): Make RequestFileSourceResponse use ErrorFileSource.
+    /** @type {!chrome.developerPrivate.RequestFileSourceResponse} */
+    const codeSectionProperties = {
+      beforeHighlight: source ? source.beforeHighlight : '',
+      highlight: source ? source.highlight : '',
+      afterHighlight: source ? source.afterHighlight : '',
+      title: '',
+      message: this.loadError.error,
+    };
+
+    this.$.code.code = codeSectionProperties;
+  },
+});
diff --git a/chrome/browser/resources/extensions/manager.js b/chrome/browser/resources/extensions/manager.js
index e73a0f2..b1df5c6 100644
--- a/chrome/browser/resources/extensions/manager.js
+++ b/chrome/browser/resources/extensions/manager.js
@@ -35,626 +35,625 @@
 import {Dialog, navigation, Page, PageState} from './navigation_helper.js';
 import {Service} from './service.js';
 
-  /**
-   * Compares two extensions to determine which should come first in the list.
-   * @param {chrome.developerPrivate.ExtensionInfo} a
-   * @param {chrome.developerPrivate.ExtensionInfo} b
-   * @return {number}
-   */
-  const compareExtensions = function(a, b) {
-    function compare(x, y) {
-      return x < y ? -1 : (x > y ? 1 : 0);
-    }
-    function compareLocation(x, y) {
-      if (x.location == y.location) {
-        return 0;
-      }
-      if (x.location == chrome.developerPrivate.Location.UNPACKED) {
-        return -1;
-      }
-      if (y.location == chrome.developerPrivate.Location.UNPACKED) {
-        return 1;
-      }
+/**
+ * Compares two extensions to determine which should come first in the list.
+ * @param {chrome.developerPrivate.ExtensionInfo} a
+ * @param {chrome.developerPrivate.ExtensionInfo} b
+ * @return {number}
+ */
+const compareExtensions = function(a, b) {
+  function compare(x, y) {
+    return x < y ? -1 : (x > y ? 1 : 0);
+  }
+  function compareLocation(x, y) {
+    if (x.location == y.location) {
       return 0;
     }
-    return compareLocation(a, b) ||
-        compare(a.name.toLowerCase(), b.name.toLowerCase()) ||
-        compare(a.id, b.id);
-  };
+    if (x.location == chrome.developerPrivate.Location.UNPACKED) {
+      return -1;
+    }
+    if (y.location == chrome.developerPrivate.Location.UNPACKED) {
+      return 1;
+    }
+    return 0;
+  }
+  return compareLocation(a, b) ||
+      compare(a.name.toLowerCase(), b.name.toLowerCase()) ||
+      compare(a.id, b.id);
+};
 
-  Polymer({
-    is: 'extensions-manager',
+Polymer({
+  is: 'extensions-manager',
 
-    _template: html`{__html_template__}`,
+  _template: html`{__html_template__}`,
 
-    properties: {
-      canLoadUnpacked: {
-        type: Boolean,
-        value: false,
-      },
-
-      /** @type {!Service} */
-      delegate: {
-        type: Object,
-        value: function() {
-          return Service.getInstance();
-        },
-      },
-
-      inDevMode: {
-        type: Boolean,
-        value: () => loadTimeData.getBoolean('inDevMode'),
-      },
-
-      showActivityLog: {
-        type: Boolean,
-        value: () => loadTimeData.getBoolean('showActivityLog'),
-      },
-
-      devModeControlledByPolicy: {
-        type: Boolean,
-        value: false,
-      },
-
-      /** @private */
-      isSupervised_: {
-        type: Boolean,
-        value: false,
-      },
-
-      incognitoAvailable_: {
-        type: Boolean,
-        value: false,
-      },
-
-      filter: {
-        type: String,
-        value: '',
-      },
-
-      /**
-       * The item currently displayed in the error subpage. We use a separate
-       * item for different pages (rather than a single subpageItem_ property)
-       * so that hidden subpages don't update when an item updates. That is, we
-       * don't want the details view subpage to update when the item shown in
-       * the errors page updates, and vice versa.
-       * @private {!chrome.developerPrivate.ExtensionInfo|undefined}
-       */
-      errorPageItem_: Object,
-
-      /**
-       * The item currently displayed in the details view subpage. See also
-       * errorPageItem_.
-       * @private {!chrome.developerPrivate.ExtensionInfo|undefined}
-       */
-      detailViewItem_: Object,
-
-      /**
-       * The item that provides some information about the current extension
-       * for the activity log view subpage. See also errorPageItem_.
-       * @private {!chrome.developerPrivate.ExtensionInfo|undefined|
-       *           !ActivityLogExtensionPlaceholder}
-       */
-      activityLogItem_: Object,
-
-      /** @private {!Array<!chrome.developerPrivate.ExtensionInfo>} */
-      extensions_: Array,
-
-      /** @private {!Array<!chrome.developerPrivate.ExtensionInfo>} */
-      apps_: Array,
-
-      /**
-       * Prevents page content from showing before data is first loaded.
-       * @private
-       */
-      didInitPage_: {
-        type: Boolean,
-        value: false,
-      },
-
-      /** @private */
-      showDrawer_: Boolean,
-
-      /** @private */
-      showLoadErrorDialog_: Boolean,
-
-      /** @private */
-      showInstallWarningsDialog_: Boolean,
-
-      /** @private {?Array<string>} */
-      installWarnings_: Array,
-
-      /** @private */
-      showOptionsDialog_: Boolean,
-
-      /**
-       * Whether the last page the user navigated from was the activity log
-       * page.
-       * @private
-       */
-      fromActivityLog_: Boolean,
-
-      // <if expr="chromeos">
-      /** @private */
-      kioskEnabled_: {
-        type: Boolean,
-        value: false,
-      },
-
-      /** @private */
-      showKioskDialog_: {
-        type: Boolean,
-        value: false,
-      },
-      // </if>
+  properties: {
+    canLoadUnpacked: {
+      type: Boolean,
+      value: false,
     },
 
-    listeners: {
-      'load-error': 'onLoadError_',
-      'view-enter-start': 'onViewEnterStart_',
-      'view-exit-start': 'onViewExitStart_',
-      'view-exit-finish': 'onViewExitFinish_',
+    /** @type {!Service} */
+    delegate: {
+      type: Object,
+      value: function() {
+        return Service.getInstance();
+      },
     },
 
-    /**
-     * The current page being shown. Default to null, and initPage_ will figure
-     * out the initial page based on url.
-     * @private {?PageState}
-     */
-    currentPage_: null,
-
-    /**
-     * The ID of the listener on |navigation|. Stored so that the
-     * listener can be removed when this element is detached (happens in tests).
-     * @private {?number}
-     */
-    navigationListener_: null,
-
-    /** @override */
-    ready: function() {
-      const service = Service.getInstance();
-
-      const onProfileStateChanged = profileInfo => {
-        this.isSupervised_ = profileInfo.isSupervised;
-        this.incognitoAvailable_ = profileInfo.isIncognitoAvailable;
-        this.devModeControlledByPolicy =
-            profileInfo.isDeveloperModeControlledByPolicy;
-        this.inDevMode = profileInfo.inDeveloperMode;
-        this.canLoadUnpacked = profileInfo.canLoadUnpacked;
-      };
-      service.getProfileStateChangedTarget().addListener(onProfileStateChanged);
-      service.getProfileConfiguration().then(onProfileStateChanged);
-
-      service.getExtensionsInfo().then(extensionsAndApps => {
-        this.initExtensionsAndApps_(extensionsAndApps);
-        this.initPage_();
-
-        service.getItemStateChangedTarget().addListener(
-            this.onItemStateChanged_.bind(this));
-      });
-
-      // <if expr="chromeos">
-      KioskBrowserProxyImpl.getInstance()
-          .initializeKioskAppSettings()
-          .then(params => {
-            this.kioskEnabled_ = params.kioskEnabled;
-          });
-      // </if>
+    inDevMode: {
+      type: Boolean,
+      value: () => loadTimeData.getBoolean('inDevMode'),
     },
 
-    /** @override */
-    attached: function() {
-      document.documentElement.classList.remove('loading');
-      document.fonts.load('bold 12px Roboto');
-
-      this.navigationListener_ = navigation.addListener(newPage => {
-        this.changePage_(newPage);
-      });
+    showActivityLog: {
+      type: Boolean,
+      value: () => loadTimeData.getBoolean('showActivityLog'),
     },
 
-    /** @override */
-    detached: function() {
-      assert(navigation.removeListener(
-          /** @type {number} */ (this.navigationListener_)));
-      this.navigationListener_ = null;
-    },
-
-    /**
-     * Initializes the page to reflect what's specified in the url so that if
-     * the user visits chrome://extensions/?id=..., we land on the proper page.
-     * @private
-     */
-    initPage_: function() {
-      this.didInitPage_ = true;
-      this.changePage_(navigation.getCurrentPage());
-    },
-
-    /**
-     * @param {!chrome.developerPrivate.EventData} eventData
-     * @private
-     */
-    onItemStateChanged_: function(eventData) {
-      const EventType = chrome.developerPrivate.EventType;
-      switch (eventData.event_type) {
-        case EventType.VIEW_REGISTERED:
-        case EventType.VIEW_UNREGISTERED:
-        case EventType.INSTALLED:
-        case EventType.LOADED:
-        case EventType.UNLOADED:
-        case EventType.ERROR_ADDED:
-        case EventType.ERRORS_REMOVED:
-        case EventType.PREFS_CHANGED:
-        case EventType.WARNINGS_CHANGED:
-        case EventType.COMMAND_ADDED:
-        case EventType.COMMAND_REMOVED:
-        case EventType.PERMISSIONS_CHANGED:
-          // |extensionInfo| can be undefined in the case of an extension
-          // being unloaded right before uninstallation. There's nothing to do
-          // here.
-          if (!eventData.extensionInfo) {
-            break;
-          }
-
-          if (this.delegate.shouldIgnoreUpdate(
-                  eventData.extensionInfo.id, eventData.event_type)) {
-            break;
-          }
-
-          const listId = this.getListId_(eventData.extensionInfo);
-          const currentIndex = this[listId].findIndex(
-              item => item.id == eventData.extensionInfo.id);
-
-          if (currentIndex >= 0) {
-            this.updateItem_(listId, currentIndex, eventData.extensionInfo);
-          } else {
-            this.addItem_(listId, eventData.extensionInfo);
-          }
-          break;
-        case EventType.UNINSTALLED:
-          this.removeItem_(eventData.item_id);
-          break;
-        default:
-          assertNotReached();
-      }
-    },
-
-    /**
-     * @param {!CustomEvent<string>} event
-     * @private
-     */
-    onFilterChanged_: function(event) {
-      if (this.currentPage_.page !== Page.LIST) {
-        navigation.navigateTo({page: Page.LIST});
-      }
-      this.filter = event.detail;
+    devModeControlledByPolicy: {
+      type: Boolean,
+      value: false,
     },
 
     /** @private */
-    onMenuButtonTap_: function() {
-      this.showDrawer_ = true;
-      this.async(() => {
-        this.$$('#drawer').openDrawer();
-      });
+    isSupervised_: {
+      type: Boolean,
+      value: false,
+    },
+
+    incognitoAvailable_: {
+      type: Boolean,
+      value: false,
+    },
+
+    filter: {
+      type: String,
+      value: '',
     },
 
     /**
-     * @param {!chrome.developerPrivate.ExtensionInfo} item
-     * @return {string} The ID of the list that the item belongs in.
-     * @private
+     * The item currently displayed in the error subpage. We use a separate
+     * item for different pages (rather than a single subpageItem_ property)
+     * so that hidden subpages don't update when an item updates. That is, we
+     * don't want the details view subpage to update when the item shown in
+     * the errors page updates, and vice versa.
+     * @private {!chrome.developerPrivate.ExtensionInfo|undefined}
      */
-    getListId_: function(item) {
-      const ExtensionType = chrome.developerPrivate.ExtensionType;
-      switch (item.type) {
-        case ExtensionType.HOSTED_APP:
-        case ExtensionType.LEGACY_PACKAGED_APP:
-        case ExtensionType.PLATFORM_APP:
-          return 'apps_';
-        case ExtensionType.EXTENSION:
-        case ExtensionType.SHARED_MODULE:
-          return 'extensions_';
-        case ExtensionType.THEME:
-          assertNotReached('Don\'t send themes to the chrome://extensions page');
-          break;
-      }
-      assertNotReached();
-    },
+    errorPageItem_: Object,
 
     /**
-     * @param {string} listId The list to look for the item in.
-     * @param {string} itemId The id of the item to look for.
-     * @return {number} The index of the item in the list, or -1 if not found.
-     * @private
+     * The item currently displayed in the details view subpage. See also
+     * errorPageItem_.
+     * @private {!chrome.developerPrivate.ExtensionInfo|undefined}
      */
-    getIndexInList_: function(listId, itemId) {
-      return this[listId].findIndex(function(item) {
-        return item.id == itemId;
-      });
-    },
+    detailViewItem_: Object,
 
     /**
-     * @return {?chrome.developerPrivate.ExtensionInfo}
-     * @private
+     * The item that provides some information about the current extension
+     * for the activity log view subpage. See also errorPageItem_.
+     * @private {!chrome.developerPrivate.ExtensionInfo|undefined|
+     *           !ActivityLogExtensionPlaceholder}
      */
-    getData_: function(id) {
-      return this.extensions_[this.getIndexInList_('extensions_', id)] ||
-          this.apps_[this.getIndexInList_('apps_', id)];
-    },
+    activityLogItem_: Object,
+
+    /** @private {!Array<!chrome.developerPrivate.ExtensionInfo>} */
+    extensions_: Array,
+
+    /** @private {!Array<!chrome.developerPrivate.ExtensionInfo>} */
+    apps_: Array,
 
     /**
-     * Categorizes |extensionsAndApps| to apps and extensions and initializes
-     * those lists.
-     * @param {!Array<!chrome.developerPrivate.ExtensionInfo>} extensionsAndApps
+     * Prevents page content from showing before data is first loaded.
      * @private
      */
-    initExtensionsAndApps_: function(extensionsAndApps) {
-      extensionsAndApps.sort(compareExtensions);
-      const apps = [];
-      const extensions = [];
-      for (const i of extensionsAndApps) {
-        const list = this.getListId_(i) === 'apps_' ? apps : extensions;
-        list.push(i);
-      }
-
-      this.apps_ = apps;
-      this.extensions_ = extensions;
-    },
-
-    /**
-     * Creates and adds a new extensions-item element to the list, inserting it
-     * into its sorted position in the relevant section.
-     * @param {!chrome.developerPrivate.ExtensionInfo} item The extension
-     *     the new element is representing.
-     * @private
-     */
-    addItem_: function(listId, item) {
-      // We should never try and add an existing item.
-      assert(this.getIndexInList_(listId, item.id) == -1);
-      let insertBeforeChild = this[listId].findIndex(function(listEl) {
-        return compareExtensions(listEl, item) > 0;
-      });
-      if (insertBeforeChild == -1) {
-        insertBeforeChild = this[listId].length;
-      }
-      this.splice(listId, insertBeforeChild, 0, item);
-    },
-
-    /**
-     * @param {!chrome.developerPrivate.ExtensionInfo} item The data for the
-     *     item to update.
-     * @private
-     */
-    updateItem_: function(listId, index, item) {
-      // We should never try and update a non-existent item.
-      assert(index >= 0);
-      this.set([listId, index], item);
-
-      // Update the subpage if it is open and displaying the item. If it's not
-      // open, we don't update the data even if it's displaying that item. We'll
-      // set the item correctly before opening the page. It's a little weird
-      // that the DOM will have stale data, but there's no point in causing the
-      // extra work.
-      if (this.detailViewItem_ && this.detailViewItem_.id == item.id &&
-          this.currentPage_.page == Page.DETAILS) {
-        this.detailViewItem_ = item;
-      } else if (
-          this.errorPageItem_ && this.errorPageItem_.id == item.id &&
-          this.currentPage_.page == Page.ERRORS) {
-        this.errorPageItem_ = item;
-      } else if (
-          this.activityLogItem_ && this.activityLogItem_.id == item.id &&
-          this.currentPage_.page == Page.ACTIVITY_LOG) {
-        this.activityLogItem_ = item;
-      }
-    },
-
-    /**
-     * @param {string} itemId The id of item to remove.
-     * @private
-     */
-    removeItem_: function(itemId) {
-      // Search for the item to be deleted in |extensions_|.
-      let listId = 'extensions_';
-      let index = this.getIndexInList_(listId, itemId);
-      if (index == -1) {
-        // If not in |extensions_| it must be in |apps_|.
-        listId = 'apps_';
-        index = this.getIndexInList_(listId, itemId);
-      }
-
-      // We should never try and remove a non-existent item.
-      assert(index >= 0);
-      this.splice(listId, index, 1);
-      if ((this.currentPage_.page == Page.ACTIVITY_LOG ||
-           this.currentPage_.page == Page.DETAILS ||
-           this.currentPage_.page == Page.ERRORS) &&
-          this.currentPage_.extensionId == itemId) {
-        // Leave the details page (the 'list' page is a fine choice).
-        navigation.replaceWith({page: Page.LIST});
-      }
-    },
-
-    /**
-     * @param {!CustomEvent<!chrome.developerPrivate.LoadError>} e
-     * @private
-     */
-    onLoadError_: function(e) {
-      this.showLoadErrorDialog_ = true;
-      this.async(() => {
-        const dialog = this.$$('#load-error');
-        dialog.loadError = e.detail;
-        dialog.show();
-      });
-    },
-
-    /**
-     * Changes the active page selection.
-     * @param {PageState} newPage
-     * @private
-     */
-    changePage_: function(newPage) {
-      this.onCloseDrawer_();
-
-      const optionsDialog = this.$$('#options-dialog');
-      if (optionsDialog && optionsDialog.open) {
-        this.showOptionsDialog_ = false;
-      }
-
-      const fromPage = this.currentPage_ ? this.currentPage_.page : null;
-      const toPage = newPage.page;
-      let data;
-      let activityLogPlaceholder;
-      if (newPage.extensionId) {
-        data = this.getData_(newPage.extensionId);
-        if (!data) {
-          // Allow the user to navigate to the activity log page even if the
-          // extension ID is not valid. This enables the use case of seeing an
-          // extension's install-time activities by navigating to an extension's
-          // activity log page, then installing the extension.
-          if (this.showActivityLog && toPage == Page.ACTIVITY_LOG) {
-            activityLogPlaceholder = {
-              id: newPage.extensionId,
-              isPlaceholder: true,
-            };
-          } else {
-            // Attempting to view an invalid (removed?) app or extension ID.
-            navigation.replaceWith({page: Page.LIST});
-            return;
-          }
-        }
-      }
-
-      if (toPage == Page.DETAILS) {
-        this.detailViewItem_ = assert(data);
-      } else if (toPage == Page.ERRORS) {
-        this.errorPageItem_ = assert(data);
-      } else if (toPage == Page.ACTIVITY_LOG) {
-        if (!this.showActivityLog) {
-          // Redirect back to the details page if we try to view the
-          // activity log of an extension but the flag is not set.
-          navigation.replaceWith(
-              {page: Page.DETAILS, extensionId: newPage.extensionId});
-          return;
-        }
-
-        this.activityLogItem_ = data ? assert(data) : activityLogPlaceholder;
-      }
-
-      if (fromPage != toPage) {
-        /** @type {CrViewManagerElement} */ (this.$.viewManager)
-            .switchView(/** @type {string} */ (toPage));
-      }
-
-      if (newPage.subpage) {
-        assert(newPage.subpage == Dialog.OPTIONS);
-        assert(newPage.extensionId);
-        this.showOptionsDialog_ = true;
-        this.async(() => {
-          this.$$('#options-dialog').show(data);
-        });
-      }
-
-      document.title = toPage == Page.DETAILS ?
-          `${loadTimeData.getString('title')} - ${this.detailViewItem_.name}` :
-          loadTimeData.getString('title');
-      this.currentPage_ = newPage;
-    },
-
-    /**
-     * This method detaches the drawer dialog completely. Should only be
-     * triggered by the dialog's 'close' event.
-     * @private
-     */
-    onDrawerClose_: function() {
-      this.showDrawer_ = false;
-    },
-
-    /**
-     * This method animates the closing of the drawer.
-     * @private
-     */
-    onCloseDrawer_: function() {
-      const drawer = this.$$('#drawer');
-      if (drawer && drawer.open) {
-        drawer.close();
-      }
+    didInitPage_: {
+      type: Boolean,
+      value: false,
     },
 
     /** @private */
-    onLoadErrorDialogClose_: function() {
-      this.showLoadErrorDialog_ = false;
-    },
+    showDrawer_: Boolean,
 
     /** @private */
-    onOptionsDialogClose_: function() {
-      this.showOptionsDialog_ = false;
-      this.$$('extensions-detail-view').focusOptionsButton();
-    },
+    showLoadErrorDialog_: Boolean,
 
     /** @private */
-    onViewEnterStart_: function() {
-      this.fromActivityLog_ = false;
-    },
+    showInstallWarningsDialog_: Boolean,
 
-    /**
-     * @param {!Event} e
-     * @private
-     */
-    onViewExitStart_: function(e) {
-      const viewType = e.composedPath()[0].tagName;
-      this.fromActivityLog_ = viewType == 'EXTENSIONS-ACTIVITY-LOG';
-    },
-
-    /**
-     * @param {!Event} e
-     * @private
-     */
-    onViewExitFinish_: function(e) {
-      const viewType = e.composedPath()[0].tagName;
-      if (viewType == 'EXTENSIONS-ITEM-LIST' ||
-          viewType == 'EXTENSIONS-KEYBOARD-SHORTCUTS' ||
-          viewType == 'EXTENSIONS-ACTIVITY-LOG') {
-        return;
-      }
-
-      const extensionId = e.composedPath()[0].data.id;
-      const list = this.$$('extensions-item-list');
-      const button = viewType == 'EXTENSIONS-DETAIL-VIEW' ?
-          list.getDetailsButton(extensionId) :
-          list.getErrorsButton(extensionId);
-
-      // The button will not exist, when returning from a details page
-      // because the corresponding extension/app was deleted.
-      if (button) {
-        button.focus();
-      }
-    },
-
-    /**
-     * @param {!CustomEvent<!Array<string>>} e
-     * @private
-     */
-    onShowInstallWarnings_: function(e) {
-      // Leverage Polymer data bindings instead of just assigning the
-      // installWarnings on the dialog since the dialog hasn't been stamped
-      // in the DOM yet.
-      this.installWarnings_ = e.detail;
-      this.showInstallWarningsDialog_ = true;
-    },
+    /** @private {?Array<string>} */
+    installWarnings_: Array,
 
     /** @private */
-    onInstallWarningsDialogClose_: function() {
-      this.installWarnings_ = null;
-      this.showInstallWarningsDialog_ = false;
-    },
+    showOptionsDialog_: Boolean,
+
+    /**
+     * Whether the last page the user navigated from was the activity log
+     * page.
+     * @private
+     */
+    fromActivityLog_: Boolean,
 
     // <if expr="chromeos">
     /** @private */
-    onKioskTap_: function() {
-      this.showKioskDialog_ = true;
+    kioskEnabled_: {
+      type: Boolean,
+      value: false,
     },
 
-    onKioskDialogClose_: function() {
-      this.showKioskDialog_ = false;
+    /** @private */
+    showKioskDialog_: {
+      type: Boolean,
+      value: false,
     },
     // </if>
-  });
+  },
+
+  listeners: {
+    'load-error': 'onLoadError_',
+    'view-enter-start': 'onViewEnterStart_',
+    'view-exit-start': 'onViewExitStart_',
+    'view-exit-finish': 'onViewExitFinish_',
+  },
+
+  /**
+   * The current page being shown. Default to null, and initPage_ will figure
+   * out the initial page based on url.
+   * @private {?PageState}
+   */
+  currentPage_: null,
+
+  /**
+   * The ID of the listener on |navigation|. Stored so that the
+   * listener can be removed when this element is detached (happens in tests).
+   * @private {?number}
+   */
+  navigationListener_: null,
+
+  /** @override */
+  ready: function() {
+    const service = Service.getInstance();
+
+    const onProfileStateChanged = profileInfo => {
+      this.isSupervised_ = profileInfo.isSupervised;
+      this.incognitoAvailable_ = profileInfo.isIncognitoAvailable;
+      this.devModeControlledByPolicy =
+          profileInfo.isDeveloperModeControlledByPolicy;
+      this.inDevMode = profileInfo.inDeveloperMode;
+      this.canLoadUnpacked = profileInfo.canLoadUnpacked;
+    };
+    service.getProfileStateChangedTarget().addListener(onProfileStateChanged);
+    service.getProfileConfiguration().then(onProfileStateChanged);
+
+    service.getExtensionsInfo().then(extensionsAndApps => {
+      this.initExtensionsAndApps_(extensionsAndApps);
+      this.initPage_();
+
+      service.getItemStateChangedTarget().addListener(
+          this.onItemStateChanged_.bind(this));
+    });
+
+    // <if expr="chromeos">
+    KioskBrowserProxyImpl.getInstance().initializeKioskAppSettings().then(
+        params => {
+          this.kioskEnabled_ = params.kioskEnabled;
+        });
+    // </if>
+  },
+
+  /** @override */
+  attached: function() {
+    document.documentElement.classList.remove('loading');
+    document.fonts.load('bold 12px Roboto');
+
+    this.navigationListener_ = navigation.addListener(newPage => {
+      this.changePage_(newPage);
+    });
+  },
+
+  /** @override */
+  detached: function() {
+    assert(navigation.removeListener(
+        /** @type {number} */ (this.navigationListener_)));
+    this.navigationListener_ = null;
+  },
+
+  /**
+   * Initializes the page to reflect what's specified in the url so that if
+   * the user visits chrome://extensions/?id=..., we land on the proper page.
+   * @private
+   */
+  initPage_: function() {
+    this.didInitPage_ = true;
+    this.changePage_(navigation.getCurrentPage());
+  },
+
+  /**
+   * @param {!chrome.developerPrivate.EventData} eventData
+   * @private
+   */
+  onItemStateChanged_: function(eventData) {
+    const EventType = chrome.developerPrivate.EventType;
+    switch (eventData.event_type) {
+      case EventType.VIEW_REGISTERED:
+      case EventType.VIEW_UNREGISTERED:
+      case EventType.INSTALLED:
+      case EventType.LOADED:
+      case EventType.UNLOADED:
+      case EventType.ERROR_ADDED:
+      case EventType.ERRORS_REMOVED:
+      case EventType.PREFS_CHANGED:
+      case EventType.WARNINGS_CHANGED:
+      case EventType.COMMAND_ADDED:
+      case EventType.COMMAND_REMOVED:
+      case EventType.PERMISSIONS_CHANGED:
+        // |extensionInfo| can be undefined in the case of an extension
+        // being unloaded right before uninstallation. There's nothing to do
+        // here.
+        if (!eventData.extensionInfo) {
+          break;
+        }
+
+        if (this.delegate.shouldIgnoreUpdate(
+                eventData.extensionInfo.id, eventData.event_type)) {
+          break;
+        }
+
+        const listId = this.getListId_(eventData.extensionInfo);
+        const currentIndex = this[listId].findIndex(
+            item => item.id == eventData.extensionInfo.id);
+
+        if (currentIndex >= 0) {
+          this.updateItem_(listId, currentIndex, eventData.extensionInfo);
+        } else {
+          this.addItem_(listId, eventData.extensionInfo);
+        }
+        break;
+      case EventType.UNINSTALLED:
+        this.removeItem_(eventData.item_id);
+        break;
+      default:
+        assertNotReached();
+    }
+  },
+
+  /**
+   * @param {!CustomEvent<string>} event
+   * @private
+   */
+  onFilterChanged_: function(event) {
+    if (this.currentPage_.page !== Page.LIST) {
+      navigation.navigateTo({page: Page.LIST});
+    }
+    this.filter = event.detail;
+  },
+
+  /** @private */
+  onMenuButtonTap_: function() {
+    this.showDrawer_ = true;
+    this.async(() => {
+      this.$$('#drawer').openDrawer();
+    });
+  },
+
+  /**
+   * @param {!chrome.developerPrivate.ExtensionInfo} item
+   * @return {string} The ID of the list that the item belongs in.
+   * @private
+   */
+  getListId_: function(item) {
+    const ExtensionType = chrome.developerPrivate.ExtensionType;
+    switch (item.type) {
+      case ExtensionType.HOSTED_APP:
+      case ExtensionType.LEGACY_PACKAGED_APP:
+      case ExtensionType.PLATFORM_APP:
+        return 'apps_';
+      case ExtensionType.EXTENSION:
+      case ExtensionType.SHARED_MODULE:
+        return 'extensions_';
+      case ExtensionType.THEME:
+        assertNotReached('Don\'t send themes to the chrome://extensions page');
+        break;
+    }
+    assertNotReached();
+  },
+
+  /**
+   * @param {string} listId The list to look for the item in.
+   * @param {string} itemId The id of the item to look for.
+   * @return {number} The index of the item in the list, or -1 if not found.
+   * @private
+   */
+  getIndexInList_: function(listId, itemId) {
+    return this[listId].findIndex(function(item) {
+      return item.id == itemId;
+    });
+  },
+
+  /**
+   * @return {?chrome.developerPrivate.ExtensionInfo}
+   * @private
+   */
+  getData_: function(id) {
+    return this.extensions_[this.getIndexInList_('extensions_', id)] ||
+        this.apps_[this.getIndexInList_('apps_', id)];
+  },
+
+  /**
+   * Categorizes |extensionsAndApps| to apps and extensions and initializes
+   * those lists.
+   * @param {!Array<!chrome.developerPrivate.ExtensionInfo>} extensionsAndApps
+   * @private
+   */
+  initExtensionsAndApps_: function(extensionsAndApps) {
+    extensionsAndApps.sort(compareExtensions);
+    const apps = [];
+    const extensions = [];
+    for (const i of extensionsAndApps) {
+      const list = this.getListId_(i) === 'apps_' ? apps : extensions;
+      list.push(i);
+    }
+
+    this.apps_ = apps;
+    this.extensions_ = extensions;
+  },
+
+  /**
+   * Creates and adds a new extensions-item element to the list, inserting it
+   * into its sorted position in the relevant section.
+   * @param {!chrome.developerPrivate.ExtensionInfo} item The extension
+   *     the new element is representing.
+   * @private
+   */
+  addItem_: function(listId, item) {
+    // We should never try and add an existing item.
+    assert(this.getIndexInList_(listId, item.id) == -1);
+    let insertBeforeChild = this[listId].findIndex(function(listEl) {
+      return compareExtensions(listEl, item) > 0;
+    });
+    if (insertBeforeChild == -1) {
+      insertBeforeChild = this[listId].length;
+    }
+    this.splice(listId, insertBeforeChild, 0, item);
+  },
+
+  /**
+   * @param {!chrome.developerPrivate.ExtensionInfo} item The data for the
+   *     item to update.
+   * @private
+   */
+  updateItem_: function(listId, index, item) {
+    // We should never try and update a non-existent item.
+    assert(index >= 0);
+    this.set([listId, index], item);
+
+    // Update the subpage if it is open and displaying the item. If it's not
+    // open, we don't update the data even if it's displaying that item. We'll
+    // set the item correctly before opening the page. It's a little weird
+    // that the DOM will have stale data, but there's no point in causing the
+    // extra work.
+    if (this.detailViewItem_ && this.detailViewItem_.id == item.id &&
+        this.currentPage_.page == Page.DETAILS) {
+      this.detailViewItem_ = item;
+    } else if (
+        this.errorPageItem_ && this.errorPageItem_.id == item.id &&
+        this.currentPage_.page == Page.ERRORS) {
+      this.errorPageItem_ = item;
+    } else if (
+        this.activityLogItem_ && this.activityLogItem_.id == item.id &&
+        this.currentPage_.page == Page.ACTIVITY_LOG) {
+      this.activityLogItem_ = item;
+    }
+  },
+
+  /**
+   * @param {string} itemId The id of item to remove.
+   * @private
+   */
+  removeItem_: function(itemId) {
+    // Search for the item to be deleted in |extensions_|.
+    let listId = 'extensions_';
+    let index = this.getIndexInList_(listId, itemId);
+    if (index == -1) {
+      // If not in |extensions_| it must be in |apps_|.
+      listId = 'apps_';
+      index = this.getIndexInList_(listId, itemId);
+    }
+
+    // We should never try and remove a non-existent item.
+    assert(index >= 0);
+    this.splice(listId, index, 1);
+    if ((this.currentPage_.page == Page.ACTIVITY_LOG ||
+         this.currentPage_.page == Page.DETAILS ||
+         this.currentPage_.page == Page.ERRORS) &&
+        this.currentPage_.extensionId == itemId) {
+      // Leave the details page (the 'list' page is a fine choice).
+      navigation.replaceWith({page: Page.LIST});
+    }
+  },
+
+  /**
+   * @param {!CustomEvent<!chrome.developerPrivate.LoadError>} e
+   * @private
+   */
+  onLoadError_: function(e) {
+    this.showLoadErrorDialog_ = true;
+    this.async(() => {
+      const dialog = this.$$('#load-error');
+      dialog.loadError = e.detail;
+      dialog.show();
+    });
+  },
+
+  /**
+   * Changes the active page selection.
+   * @param {PageState} newPage
+   * @private
+   */
+  changePage_: function(newPage) {
+    this.onCloseDrawer_();
+
+    const optionsDialog = this.$$('#options-dialog');
+    if (optionsDialog && optionsDialog.open) {
+      this.showOptionsDialog_ = false;
+    }
+
+    const fromPage = this.currentPage_ ? this.currentPage_.page : null;
+    const toPage = newPage.page;
+    let data;
+    let activityLogPlaceholder;
+    if (newPage.extensionId) {
+      data = this.getData_(newPage.extensionId);
+      if (!data) {
+        // Allow the user to navigate to the activity log page even if the
+        // extension ID is not valid. This enables the use case of seeing an
+        // extension's install-time activities by navigating to an extension's
+        // activity log page, then installing the extension.
+        if (this.showActivityLog && toPage == Page.ACTIVITY_LOG) {
+          activityLogPlaceholder = {
+            id: newPage.extensionId,
+            isPlaceholder: true,
+          };
+        } else {
+          // Attempting to view an invalid (removed?) app or extension ID.
+          navigation.replaceWith({page: Page.LIST});
+          return;
+        }
+      }
+    }
+
+    if (toPage == Page.DETAILS) {
+      this.detailViewItem_ = assert(data);
+    } else if (toPage == Page.ERRORS) {
+      this.errorPageItem_ = assert(data);
+    } else if (toPage == Page.ACTIVITY_LOG) {
+      if (!this.showActivityLog) {
+        // Redirect back to the details page if we try to view the
+        // activity log of an extension but the flag is not set.
+        navigation.replaceWith(
+            {page: Page.DETAILS, extensionId: newPage.extensionId});
+        return;
+      }
+
+      this.activityLogItem_ = data ? assert(data) : activityLogPlaceholder;
+    }
+
+    if (fromPage != toPage) {
+      /** @type {CrViewManagerElement} */ (this.$.viewManager)
+          .switchView(/** @type {string} */ (toPage));
+    }
+
+    if (newPage.subpage) {
+      assert(newPage.subpage == Dialog.OPTIONS);
+      assert(newPage.extensionId);
+      this.showOptionsDialog_ = true;
+      this.async(() => {
+        this.$$('#options-dialog').show(data);
+      });
+    }
+
+    document.title = toPage == Page.DETAILS ?
+        `${loadTimeData.getString('title')} - ${this.detailViewItem_.name}` :
+        loadTimeData.getString('title');
+    this.currentPage_ = newPage;
+  },
+
+  /**
+   * This method detaches the drawer dialog completely. Should only be
+   * triggered by the dialog's 'close' event.
+   * @private
+   */
+  onDrawerClose_: function() {
+    this.showDrawer_ = false;
+  },
+
+  /**
+   * This method animates the closing of the drawer.
+   * @private
+   */
+  onCloseDrawer_: function() {
+    const drawer = this.$$('#drawer');
+    if (drawer && drawer.open) {
+      drawer.close();
+    }
+  },
+
+  /** @private */
+  onLoadErrorDialogClose_: function() {
+    this.showLoadErrorDialog_ = false;
+  },
+
+  /** @private */
+  onOptionsDialogClose_: function() {
+    this.showOptionsDialog_ = false;
+    this.$$('extensions-detail-view').focusOptionsButton();
+  },
+
+  /** @private */
+  onViewEnterStart_: function() {
+    this.fromActivityLog_ = false;
+  },
+
+  /**
+   * @param {!Event} e
+   * @private
+   */
+  onViewExitStart_: function(e) {
+    const viewType = e.composedPath()[0].tagName;
+    this.fromActivityLog_ = viewType == 'EXTENSIONS-ACTIVITY-LOG';
+  },
+
+  /**
+   * @param {!Event} e
+   * @private
+   */
+  onViewExitFinish_: function(e) {
+    const viewType = e.composedPath()[0].tagName;
+    if (viewType == 'EXTENSIONS-ITEM-LIST' ||
+        viewType == 'EXTENSIONS-KEYBOARD-SHORTCUTS' ||
+        viewType == 'EXTENSIONS-ACTIVITY-LOG') {
+      return;
+    }
+
+    const extensionId = e.composedPath()[0].data.id;
+    const list = this.$$('extensions-item-list');
+    const button = viewType == 'EXTENSIONS-DETAIL-VIEW' ?
+        list.getDetailsButton(extensionId) :
+        list.getErrorsButton(extensionId);
+
+    // The button will not exist, when returning from a details page
+    // because the corresponding extension/app was deleted.
+    if (button) {
+      button.focus();
+    }
+  },
+
+  /**
+   * @param {!CustomEvent<!Array<string>>} e
+   * @private
+   */
+  onShowInstallWarnings_: function(e) {
+    // Leverage Polymer data bindings instead of just assigning the
+    // installWarnings on the dialog since the dialog hasn't been stamped
+    // in the DOM yet.
+    this.installWarnings_ = e.detail;
+    this.showInstallWarningsDialog_ = true;
+  },
+
+  /** @private */
+  onInstallWarningsDialogClose_: function() {
+    this.installWarnings_ = null;
+    this.showInstallWarningsDialog_ = false;
+  },
+
+  // <if expr="chromeos">
+  /** @private */
+  onKioskTap_: function() {
+    this.showKioskDialog_ = true;
+  },
+
+  onKioskDialogClose_: function() {
+    this.showKioskDialog_ = false;
+  },
+  // </if>
+});
diff --git a/chrome/browser/resources/extensions/navigation_helper.js b/chrome/browser/resources/extensions/navigation_helper.js
index f062024..b4bc143d 100644
--- a/chrome/browser/resources/extensions/navigation_helper.js
+++ b/chrome/browser/resources/extensions/navigation_helper.js
@@ -5,225 +5,225 @@
 import {assert} from 'chrome://resources/js/assert.m.js';
 
 
-  /**
-   * The different pages that can be shown at a time.
-   * Note: This must remain in sync with the page ids in manager.html!
-   * @enum {string}
-   */
-  export const Page = {
-    LIST: 'items-list',
-    DETAILS: 'details-view',
-    ACTIVITY_LOG: 'activity-log',
-    SHORTCUTS: 'keyboard-shortcuts',
-    ERRORS: 'error-page',
-  };
+/**
+ * The different pages that can be shown at a time.
+ * Note: This must remain in sync with the page ids in manager.html!
+ * @enum {string}
+ */
+export const Page = {
+  LIST: 'items-list',
+  DETAILS: 'details-view',
+  ACTIVITY_LOG: 'activity-log',
+  SHORTCUTS: 'keyboard-shortcuts',
+  ERRORS: 'error-page',
+};
 
-  /** @enum {string} */
-  export const Dialog = {
-    OPTIONS: 'options',
-  };
+/** @enum {string} */
+export const Dialog = {
+  OPTIONS: 'options',
+};
 
-  /**
-   * @typedef {{page: Page,
-   *            extensionId: (string|undefined),
-   *            subpage: (!Dialog|undefined)}}
-   */
-  export let PageState;
+/**
+ * @typedef {{page: Page,
+ *            extensionId: (string|undefined),
+ *            subpage: (!Dialog|undefined)}}
+ */
+export let PageState;
 
-  /**
-   * @param {!PageState} a
-   * @param {!PageState} b
-   * @return {boolean} Whether a and b are equal.
-   */
-  function isPageStateEqual(a, b) {
-    return a.page == b.page && a.subpage == b.subpage &&
-        a.extensionId == b.extensionId;
+/**
+ * @param {!PageState} a
+ * @param {!PageState} b
+ * @return {boolean} Whether a and b are equal.
+ */
+function isPageStateEqual(a, b) {
+  return a.page == b.page && a.subpage == b.subpage &&
+      a.extensionId == b.extensionId;
+}
+
+/**
+ * Regular expression that captures the leading slash, the content and the
+ * trailing slash in three different groups.
+ * @const {!RegExp}
+ */
+const CANONICAL_PATH_REGEX = /(^\/)([\/-\w]+)(\/$)/;
+
+/**
+ * A helper object to manage in-page navigations. Since the extensions page
+ * needs to support different urls for different subpages (like the details
+ * page), we use this object to manage the history and url conversions.
+ */
+export class NavigationHelper {
+  constructor() {
+    this.processRoute_();
+
+    /** @private {number} */
+    this.nextListenerId_ = 1;
+
+    /** @private {!Map<number, function(!PageState)>} */
+    this.listeners_ = new Map();
+
+    /** @private {!PageState} */
+    this.previousPage_;
+
+    window.addEventListener('popstate', () => {
+      this.notifyRouteChanged_(this.getCurrentPage());
+    });
+  }
+
+  /** @private */
+  get currentPath_() {
+    return location.pathname.replace(CANONICAL_PATH_REGEX, '$1$2');
   }
 
   /**
-   * Regular expression that captures the leading slash, the content and the
-   * trailing slash in three different groups.
-   * @const {!RegExp}
+   * Going to /configureCommands and /shortcuts should land you on /shortcuts.
+   * These are the only two supported routes, so all other cases will redirect
+   * you to root path if not already on it.
+   * @private
    */
-  const CANONICAL_PATH_REGEX = /(^\/)([\/-\w]+)(\/$)/;
-
-  /**
-   * A helper object to manage in-page navigations. Since the extensions page
-   * needs to support different urls for different subpages (like the details
-   * page), we use this object to manage the history and url conversions.
-   */
-  export class NavigationHelper {
-    constructor() {
-      this.processRoute_();
-
-      /** @private {number} */
-      this.nextListenerId_ = 1;
-
-      /** @private {!Map<number, function(!PageState)>} */
-      this.listeners_ = new Map();
-
-      /** @private {!PageState} */
-      this.previousPage_;
-
-      window.addEventListener('popstate', () => {
-        this.notifyRouteChanged_(this.getCurrentPage());
-      });
-    }
-
-    /** @private */
-    get currentPath_() {
-      return location.pathname.replace(CANONICAL_PATH_REGEX, '$1$2');
-    }
-
-    /**
-     * Going to /configureCommands and /shortcuts should land you on /shortcuts.
-     * These are the only two supported routes, so all other cases will redirect
-     * you to root path if not already on it.
-     * @private
-     */
-    processRoute_() {
-      if (this.currentPath_ == '/configureCommands' ||
-          this.currentPath_ == '/shortcuts') {
-        window.history.replaceState(
-            undefined /* stateObject */, '', '/shortcuts');
-      } else if (this.currentPath_ !== '/') {
-        window.history.replaceState(undefined /* stateObject */, '', '/');
-      }
-    }
-
-    /**
-     * @return {!PageState} The page that should be displayed for the
-     *     current URL.
-     */
-    getCurrentPage() {
-      const search = new URLSearchParams(location.search);
-      let id = search.get('id');
-      if (id) {
-        return {page: Page.DETAILS, extensionId: id};
-      }
-      id = search.get('activity');
-      if (id) {
-        return {page: Page.ACTIVITY_LOG, extensionId: id};
-      }
-      id = search.get('options');
-      if (id) {
-        return {page: Page.DETAILS, extensionId: id, subpage: Dialog.OPTIONS};
-      }
-      id = search.get('errors');
-      if (id) {
-        return {page: Page.ERRORS, extensionId: id};
-      }
-
-      if (this.currentPath_ == '/shortcuts') {
-        return {page: Page.SHORTCUTS};
-      }
-
-      return {page: Page.LIST};
-    }
-
-    /**
-     * Function to add subscribers.
-     * @param {!function(!PageState)} listener
-     * @return {number} A numerical ID to be used for removing the listener.
-     */
-    addListener(listener) {
-      const nextListenerId = this.nextListenerId_++;
-      this.listeners_.set(nextListenerId, listener);
-      return nextListenerId;
-    }
-
-    /**
-     * Remove a previously registered listener.
-     * @param {number} id
-     * @return {boolean} Whether a listener with the given ID was actually found
-     *     and removed.
-     */
-    removeListener(id) {
-      return this.listeners_.delete(id);
-    }
-
-    /**
-     * Function to notify subscribers.
-     * @private
-     */
-    notifyRouteChanged_(newPage) {
-      this.listeners_.forEach((listener, id) => {
-        listener(newPage);
-      });
-    }
-
-    /**
-     * @param {!PageState} newPage the page to navigate to.
-     */
-    navigateTo(newPage) {
-      const currentPage = this.getCurrentPage();
-      if (currentPage && isPageStateEqual(currentPage, newPage)) {
-        return;
-      }
-
-      this.updateHistory(newPage, false /* replaceState */);
-      this.notifyRouteChanged_(newPage);
-    }
-
-    /**
-     * @param {!PageState} newPage the page to replace the current
-     *     page with.
-     */
-    replaceWith(newPage) {
-      this.updateHistory(newPage, true /* replaceState */);
-      if (this.previousPage_ && isPageStateEqual(this.previousPage_, newPage)) {
-        // Skip the duplicate history entry.
-        history.back();
-        return;
-      }
-      this.notifyRouteChanged_(newPage);
-    }
-
-    /**
-     * Called when a page changes, and pushes state to history to reflect it.
-     * @param {!PageState} entry
-     * @param {boolean} replaceState
-     */
-    updateHistory(entry, replaceState) {
-      let path;
-      switch (entry.page) {
-        case Page.LIST:
-          path = '/';
-          break;
-        case Page.ACTIVITY_LOG:
-          path = '/?activity=' + entry.extensionId;
-          break;
-        case Page.DETAILS:
-          if (entry.subpage) {
-            assert(entry.subpage == Dialog.OPTIONS);
-            path = '/?options=' + entry.extensionId;
-          } else {
-            path = '/?id=' + entry.extensionId;
-          }
-          break;
-        case Page.SHORTCUTS:
-          path = '/shortcuts';
-          break;
-        case Page.ERRORS:
-          path = '/?errors=' + entry.extensionId;
-          break;
-      }
-      assert(path);
-      const state = {url: path};
-      const currentPage = this.getCurrentPage();
-      const isDialogNavigation = currentPage.page == entry.page &&
-          currentPage.extensionId == entry.extensionId;
-      // Navigating to a dialog doesn't visually change pages; it just opens
-      // a dialog. As such, we replace state rather than pushing a new state
-      // on the stack so that hitting the back button doesn't just toggle the
-      // dialog.
-      if (replaceState || isDialogNavigation) {
-        history.replaceState(state, '', path);
-      } else {
-        this.previousPage_ = currentPage;
-        history.pushState(state, '', path);
-      }
+  processRoute_() {
+    if (this.currentPath_ == '/configureCommands' ||
+        this.currentPath_ == '/shortcuts') {
+      window.history.replaceState(
+          undefined /* stateObject */, '', '/shortcuts');
+    } else if (this.currentPath_ !== '/') {
+      window.history.replaceState(undefined /* stateObject */, '', '/');
     }
   }
 
-  export const navigation = new NavigationHelper();
+  /**
+   * @return {!PageState} The page that should be displayed for the
+   *     current URL.
+   */
+  getCurrentPage() {
+    const search = new URLSearchParams(location.search);
+    let id = search.get('id');
+    if (id) {
+      return {page: Page.DETAILS, extensionId: id};
+    }
+    id = search.get('activity');
+    if (id) {
+      return {page: Page.ACTIVITY_LOG, extensionId: id};
+    }
+    id = search.get('options');
+    if (id) {
+      return {page: Page.DETAILS, extensionId: id, subpage: Dialog.OPTIONS};
+    }
+    id = search.get('errors');
+    if (id) {
+      return {page: Page.ERRORS, extensionId: id};
+    }
+
+    if (this.currentPath_ == '/shortcuts') {
+      return {page: Page.SHORTCUTS};
+    }
+
+    return {page: Page.LIST};
+  }
+
+  /**
+   * Function to add subscribers.
+   * @param {!function(!PageState)} listener
+   * @return {number} A numerical ID to be used for removing the listener.
+   */
+  addListener(listener) {
+    const nextListenerId = this.nextListenerId_++;
+    this.listeners_.set(nextListenerId, listener);
+    return nextListenerId;
+  }
+
+  /**
+   * Remove a previously registered listener.
+   * @param {number} id
+   * @return {boolean} Whether a listener with the given ID was actually found
+   *     and removed.
+   */
+  removeListener(id) {
+    return this.listeners_.delete(id);
+  }
+
+  /**
+   * Function to notify subscribers.
+   * @private
+   */
+  notifyRouteChanged_(newPage) {
+    this.listeners_.forEach((listener, id) => {
+      listener(newPage);
+    });
+  }
+
+  /**
+   * @param {!PageState} newPage the page to navigate to.
+   */
+  navigateTo(newPage) {
+    const currentPage = this.getCurrentPage();
+    if (currentPage && isPageStateEqual(currentPage, newPage)) {
+      return;
+    }
+
+    this.updateHistory(newPage, false /* replaceState */);
+    this.notifyRouteChanged_(newPage);
+  }
+
+  /**
+   * @param {!PageState} newPage the page to replace the current
+   *     page with.
+   */
+  replaceWith(newPage) {
+    this.updateHistory(newPage, true /* replaceState */);
+    if (this.previousPage_ && isPageStateEqual(this.previousPage_, newPage)) {
+      // Skip the duplicate history entry.
+      history.back();
+      return;
+    }
+    this.notifyRouteChanged_(newPage);
+  }
+
+  /**
+   * Called when a page changes, and pushes state to history to reflect it.
+   * @param {!PageState} entry
+   * @param {boolean} replaceState
+   */
+  updateHistory(entry, replaceState) {
+    let path;
+    switch (entry.page) {
+      case Page.LIST:
+        path = '/';
+        break;
+      case Page.ACTIVITY_LOG:
+        path = '/?activity=' + entry.extensionId;
+        break;
+      case Page.DETAILS:
+        if (entry.subpage) {
+          assert(entry.subpage == Dialog.OPTIONS);
+          path = '/?options=' + entry.extensionId;
+        } else {
+          path = '/?id=' + entry.extensionId;
+        }
+        break;
+      case Page.SHORTCUTS:
+        path = '/shortcuts';
+        break;
+      case Page.ERRORS:
+        path = '/?errors=' + entry.extensionId;
+        break;
+    }
+    assert(path);
+    const state = {url: path};
+    const currentPage = this.getCurrentPage();
+    const isDialogNavigation = currentPage.page == entry.page &&
+        currentPage.extensionId == entry.extensionId;
+    // Navigating to a dialog doesn't visually change pages; it just opens
+    // a dialog. As such, we replace state rather than pushing a new state
+    // on the stack so that hitting the back button doesn't just toggle the
+    // dialog.
+    if (replaceState || isDialogNavigation) {
+      history.replaceState(state, '', path);
+    } else {
+      this.previousPage_ = currentPage;
+      history.pushState(state, '', path);
+    }
+  }
+}
+
+export const navigation = new NavigationHelper();
diff --git a/chrome/browser/resources/extensions/options_dialog.js b/chrome/browser/resources/extensions/options_dialog.js
index dfa0fba0..ce9aa267 100644
--- a/chrome/browser/resources/extensions/options_dialog.js
+++ b/chrome/browser/resources/extensions/options_dialog.js
@@ -9,124 +9,123 @@
 import {ItemBehavior} from './item_behavior.js';
 import {navigation, Page} from './navigation_helper.js';
 
-  /**
-   * @return {!Promise} A signal that the document is ready. Need to wait for
-   *     this, otherwise the custom ExtensionOptions element might not have been
-   *     registered yet.
-   */
-  function whenDocumentReady() {
-    if (document.readyState == 'complete') {
-      return Promise.resolve();
-    }
-
-    return new Promise(function(resolve) {
-      document.addEventListener('readystatechange', function f() {
-        if (document.readyState == 'complete') {
-          document.removeEventListener('readystatechange', f);
-          resolve();
-        }
-      });
-    });
+/**
+ * @return {!Promise} A signal that the document is ready. Need to wait for
+ *     this, otherwise the custom ExtensionOptions element might not have been
+ *     registered yet.
+ */
+function whenDocumentReady() {
+  if (document.readyState == 'complete') {
+    return Promise.resolve();
   }
 
-  // The minimum width in pixels for the options dialog.
-  export const OptionsDialogMinWidth = 400;
-
-  // The maximum height in pixels for the options dialog.
-  export const OptionsDialogMaxHeight = 640;
-
-  Polymer({
-    is: 'extensions-options-dialog',
-
-    _template: html`{__html_template__}`,
-
-    behaviors: [ItemBehavior],
-
-    properties: {
-      /** @private {Object} */
-      extensionOptions_: Object,
-
-      /** @private {chrome.developerPrivate.ExtensionInfo} */
-      data_: Object,
-    },
-
-    /** @private {?Function} */
-    boundUpdateDialogSize_: null,
-
-    /** @private {?{height: number, width: number}} */
-    preferredSize_: null,
-
-    get open() {
-      return this.$.dialog.open;
-    },
-
-    /**
-     * Resizes the dialog to the width/height stored in |preferredSize_|, taking
-     * into account the window width/height.
-     * @private
-     */
-    updateDialogSize_: function() {
-      const headerHeight = this.$.body.offsetTop;
-      const maxHeight =
-          Math.min(0.9 * window.innerHeight, OptionsDialogMaxHeight);
-      const effectiveHeight =
-          Math.min(maxHeight, headerHeight + this.preferredSize_.height);
-      const effectiveWidth =
-          Math.max(OptionsDialogMinWidth, this.preferredSize_.width);
-
-      this.$.dialog.style.setProperty(
-          '--dialog-height', `${effectiveHeight}px`);
-      this.$.dialog.style.setProperty('--dialog-width', `${effectiveWidth}px`);
-      this.$.dialog.style.setProperty('--dialog-opacity', '1');
-    },
-
-    /** @param {chrome.developerPrivate.ExtensionInfo} data */
-    show: function(data) {
-      this.data_ = data;
-      whenDocumentReady().then(() => {
-        if (!this.extensionOptions_) {
-          this.extensionOptions_ = document.createElement('ExtensionOptions');
-        }
-        this.extensionOptions_.extension = this.data_.id;
-        this.extensionOptions_.onclose = () => this.$.dialog.close();
-
-        const boundUpdateDialogSize = this.updateDialogSize_.bind(this);
-        this.boundUpdateDialogSize_ = boundUpdateDialogSize;
-        this.extensionOptions_.onpreferredsizechanged = e => {
-          if (!this.$.dialog.open) {
-            this.$.dialog.showModal();
-          }
-          this.preferredSize_ = e;
-          this.debounce('updateDialogSize_', boundUpdateDialogSize, 50);
-        };
-
-        // Add a 'resize' such that the dialog is resized when window size
-        // changes.
-        window.addEventListener('resize', this.boundUpdateDialogSize_);
-        this.$.body.appendChild(/** @type {Node} */ (this.extensionOptions_));
-      });
-    },
-
-    /** @private */
-    onClose_: function() {
-      this.extensionOptions_.onpreferredsizechanged = null;
-
-      if (this.boundUpdateDialogSize_) {
-        window.removeEventListener('resize', this.boundUpdateDialogSize_);
-        this.boundUpdateDialogSize_ = null;
+  return new Promise(function(resolve) {
+    document.addEventListener('readystatechange', function f() {
+      if (document.readyState == 'complete') {
+        document.removeEventListener('readystatechange', f);
+        resolve();
       }
-
-      const currentPage = navigation.getCurrentPage();
-      // We update the page when the options dialog closes, but only if we're
-      // still on the details page. We could be on a different page if the
-      // user hit back while the options dialog was visible; in that case, the
-      // new page is already correct.
-      if (currentPage && currentPage.page == Page.DETAILS) {
-        // This will update the currentPage_ and the NavigationHelper; since
-        // the active page is already the details page, no main page
-        // transition occurs.
-        navigation.navigateTo(
-            {page: Page.DETAILS, extensionId: currentPage.extensionId});
-      }
-    },
+    });
   });
+}
+
+// The minimum width in pixels for the options dialog.
+export const OptionsDialogMinWidth = 400;
+
+// The maximum height in pixels for the options dialog.
+export const OptionsDialogMaxHeight = 640;
+
+Polymer({
+  is: 'extensions-options-dialog',
+
+  _template: html`{__html_template__}`,
+
+  behaviors: [ItemBehavior],
+
+  properties: {
+    /** @private {Object} */
+    extensionOptions_: Object,
+
+    /** @private {chrome.developerPrivate.ExtensionInfo} */
+    data_: Object,
+  },
+
+  /** @private {?Function} */
+  boundUpdateDialogSize_: null,
+
+  /** @private {?{height: number, width: number}} */
+  preferredSize_: null,
+
+  get open() {
+    return this.$.dialog.open;
+  },
+
+  /**
+   * Resizes the dialog to the width/height stored in |preferredSize_|, taking
+   * into account the window width/height.
+   * @private
+   */
+  updateDialogSize_: function() {
+    const headerHeight = this.$.body.offsetTop;
+    const maxHeight =
+        Math.min(0.9 * window.innerHeight, OptionsDialogMaxHeight);
+    const effectiveHeight =
+        Math.min(maxHeight, headerHeight + this.preferredSize_.height);
+    const effectiveWidth =
+        Math.max(OptionsDialogMinWidth, this.preferredSize_.width);
+
+    this.$.dialog.style.setProperty('--dialog-height', `${effectiveHeight}px`);
+    this.$.dialog.style.setProperty('--dialog-width', `${effectiveWidth}px`);
+    this.$.dialog.style.setProperty('--dialog-opacity', '1');
+  },
+
+  /** @param {chrome.developerPrivate.ExtensionInfo} data */
+  show: function(data) {
+    this.data_ = data;
+    whenDocumentReady().then(() => {
+      if (!this.extensionOptions_) {
+        this.extensionOptions_ = document.createElement('ExtensionOptions');
+      }
+      this.extensionOptions_.extension = this.data_.id;
+      this.extensionOptions_.onclose = () => this.$.dialog.close();
+
+      const boundUpdateDialogSize = this.updateDialogSize_.bind(this);
+      this.boundUpdateDialogSize_ = boundUpdateDialogSize;
+      this.extensionOptions_.onpreferredsizechanged = e => {
+        if (!this.$.dialog.open) {
+          this.$.dialog.showModal();
+        }
+        this.preferredSize_ = e;
+        this.debounce('updateDialogSize_', boundUpdateDialogSize, 50);
+      };
+
+      // Add a 'resize' such that the dialog is resized when window size
+      // changes.
+      window.addEventListener('resize', this.boundUpdateDialogSize_);
+      this.$.body.appendChild(/** @type {Node} */ (this.extensionOptions_));
+    });
+  },
+
+  /** @private */
+  onClose_: function() {
+    this.extensionOptions_.onpreferredsizechanged = null;
+
+    if (this.boundUpdateDialogSize_) {
+      window.removeEventListener('resize', this.boundUpdateDialogSize_);
+      this.boundUpdateDialogSize_ = null;
+    }
+
+    const currentPage = navigation.getCurrentPage();
+    // We update the page when the options dialog closes, but only if we're
+    // still on the details page. We could be on a different page if the
+    // user hit back while the options dialog was visible; in that case, the
+    // new page is already correct.
+    if (currentPage && currentPage.page == Page.DETAILS) {
+      // This will update the currentPage_ and the NavigationHelper; since
+      // the active page is already the details page, no main page
+      // transition occurs.
+      navigation.navigateTo(
+          {page: Page.DETAILS, extensionId: currentPage.extensionId});
+    }
+  },
+});
diff --git a/chrome/browser/resources/extensions/pack_dialog.js b/chrome/browser/resources/extensions/pack_dialog.js
index 6ccfe322..4791d6b 100644
--- a/chrome/browser/resources/extensions/pack_dialog.js
+++ b/chrome/browser/resources/extensions/pack_dialog.js
@@ -12,123 +12,122 @@
 
 import {html, Polymer} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
 
-  /** @interface */
-  export class PackDialogDelegate {
-    /**
-     * Opens a file browser for the user to select the root directory.
-     * @return {Promise<string>} A promise that is resolved with the path the
-     *     user selected.
-     */
-    choosePackRootDirectory() {}
+/** @interface */
+export class PackDialogDelegate {
+  /**
+   * Opens a file browser for the user to select the root directory.
+   * @return {Promise<string>} A promise that is resolved with the path the
+   *     user selected.
+   */
+  choosePackRootDirectory() {}
 
-    /**
-     * Opens a file browser for the user to select the private key file.
-     * @return {Promise<string>} A promise that is resolved with the path the
-     *     user selected.
-     */
-    choosePrivateKeyPath() {}
+  /**
+   * Opens a file browser for the user to select the private key file.
+   * @return {Promise<string>} A promise that is resolved with the path the
+   *     user selected.
+   */
+  choosePrivateKeyPath() {}
 
-    /**
-     * Packs the extension into a .crx.
-     * @param {string} rootPath
-     * @param {string} keyPath
-     * @param {number=} flag
-     * @param {function(chrome.developerPrivate.PackDirectoryResponse)=}
-     *     callback
-     */
-    packExtension(rootPath, keyPath, flag, callback) {}
-  }
+  /**
+   * Packs the extension into a .crx.
+   * @param {string} rootPath
+   * @param {string} keyPath
+   * @param {number=} flag
+   * @param {function(chrome.developerPrivate.PackDirectoryResponse)=}
+   *     callback
+   */
+  packExtension(rootPath, keyPath, flag, callback) {}
+}
 
-  Polymer({
-    is: 'extensions-pack-dialog',
+Polymer({
+  is: 'extensions-pack-dialog',
 
-    _template: html`{__html_template__}`,
+  _template: html`{__html_template__}`,
 
-    properties: {
-      /** @type {PackDialogDelegate} */
-      delegate: Object,
+  properties: {
+    /** @type {PackDialogDelegate} */
+    delegate: Object,
 
-      /** @private */
-      packDirectory_: {
-        type: String,
-        value: '',  // Initialized to trigger binding when attached.
-      },
-
-      /** @private */
-      keyFile_: String,
-
-      /** @private {?chrome.developerPrivate.PackDirectoryResponse} */
-      lastResponse_: Object,
-    },
-
-    /** @override */
-    attached: function() {
-      this.$.dialog.showModal();
+    /** @private */
+    packDirectory_: {
+      type: String,
+      value: '',  // Initialized to trigger binding when attached.
     },
 
     /** @private */
-    onRootBrowse_: function() {
-      this.delegate.choosePackRootDirectory().then(path => {
-        if (path) {
-          this.set('packDirectory_', path);
-        }
-      });
-    },
+    keyFile_: String,
 
-    /** @private */
-    onKeyBrowse_: function() {
-      this.delegate.choosePrivateKeyPath().then(path => {
-        if (path) {
-          this.set('keyFile_', path);
-        }
-      });
-    },
+    /** @private {?chrome.developerPrivate.PackDirectoryResponse} */
+    lastResponse_: Object,
+  },
 
-    /** @private */
-    onCancelTap_: function() {
-      this.$.dialog.cancel();
-    },
+  /** @override */
+  attached: function() {
+    this.$.dialog.showModal();
+  },
 
-    /** @private */
-    onConfirmTap_: function() {
+  /** @private */
+  onRootBrowse_: function() {
+    this.delegate.choosePackRootDirectory().then(path => {
+      if (path) {
+        this.set('packDirectory_', path);
+      }
+    });
+  },
+
+  /** @private */
+  onKeyBrowse_: function() {
+    this.delegate.choosePrivateKeyPath().then(path => {
+      if (path) {
+        this.set('keyFile_', path);
+      }
+    });
+  },
+
+  /** @private */
+  onCancelTap_: function() {
+    this.$.dialog.cancel();
+  },
+
+  /** @private */
+  onConfirmTap_: function() {
+    this.delegate.packExtension(
+        this.packDirectory_, this.keyFile_, 0, this.onPackResponse_.bind(this));
+  },
+
+  /**
+   * @param {chrome.developerPrivate.PackDirectoryResponse} response the
+   *    response from request to pack an extension.
+   * @private
+   */
+  onPackResponse_: function(response) {
+    this.lastResponse_ = response;
+  },
+
+  /**
+   * In the case that the alert dialog was a success message, the entire
+   * pack-dialog should close. Otherwise, we detach the alert by setting
+   * lastResponse_ null. Additionally, if the user selected "proceed anyway"
+   * in the dialog, we pack the extension again with override flags.
+   * @param {!Event} e
+   * @private
+   */
+  onAlertClose_: function(e) {
+    e.stopPropagation();
+
+    if (this.lastResponse_.status ==
+        chrome.developerPrivate.PackStatus.SUCCESS) {
+      this.$.dialog.close();
+      return;
+    }
+
+    // This is only possible for a warning dialog.
+    if (this.$$('extensions-pack-dialog-alert').returnValue == 'success') {
       this.delegate.packExtension(
-          this.packDirectory_, this.keyFile_, 0,
-          this.onPackResponse_.bind(this));
-    },
+          this.lastResponse_.item_path, this.lastResponse_.pem_path,
+          this.lastResponse_.override_flags, this.onPackResponse_.bind(this));
+    }
 
-    /**
-     * @param {chrome.developerPrivate.PackDirectoryResponse} response the
-     *    response from request to pack an extension.
-     * @private
-     */
-    onPackResponse_: function(response) {
-      this.lastResponse_ = response;
-    },
-
-    /**
-     * In the case that the alert dialog was a success message, the entire
-     * pack-dialog should close. Otherwise, we detach the alert by setting
-     * lastResponse_ null. Additionally, if the user selected "proceed anyway"
-     * in the dialog, we pack the extension again with override flags.
-     * @param {!Event} e
-     * @private
-     */
-    onAlertClose_: function(e) {
-      e.stopPropagation();
-
-      if (this.lastResponse_.status ==
-          chrome.developerPrivate.PackStatus.SUCCESS) {
-        this.$.dialog.close();
-        return;
-      }
-
-      // This is only possible for a warning dialog.
-      if (this.$$('extensions-pack-dialog-alert').returnValue == 'success') {
-        this.delegate.packExtension(
-            this.lastResponse_.item_path, this.lastResponse_.pem_path,
-            this.lastResponse_.override_flags, this.onPackResponse_.bind(this));
-      }
-
-      this.lastResponse_ = null;
-    },
-  });
+    this.lastResponse_ = null;
+  },
+});
diff --git a/chrome/browser/resources/extensions/pack_dialog_alert.js b/chrome/browser/resources/extensions/pack_dialog_alert.js
index 913dafb..a39869e 100644
--- a/chrome/browser/resources/extensions/pack_dialog_alert.js
+++ b/chrome/browser/resources/extensions/pack_dialog_alert.js
@@ -9,90 +9,89 @@
 import {loadTimeData} from 'chrome://resources/js/load_time_data.m.js';
 import {html, Polymer} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
 
-  Polymer({
-    is: 'extensions-pack-dialog-alert',
+Polymer({
+  is: 'extensions-pack-dialog-alert',
 
-    _template: html`{__html_template__}`,
+  _template: html`{__html_template__}`,
 
-    properties: {
-      /** @private {chrome.developerPrivate.PackDirectoryResponse} */
-      model: Object,
+  properties: {
+    /** @private {chrome.developerPrivate.PackDirectoryResponse} */
+    model: Object,
 
-      /** @private */
-      title_: String,
+    /** @private */
+    title_: String,
 
-      /** @private */
-      message_: String,
+    /** @private */
+    message_: String,
 
-      /** @private {?string} */
-      cancelLabel_: String,
-
-      /**
-       * This needs to be initialized to trigger data-binding.
-       * @private {?string}
-       */
-      confirmLabel_: {
-        type: String,
-        value: '',
-      }
-    },
-
-    /** @return {string} */
-    get returnValue() {
-      return /** @type {!CrDialogElement} */ (this.$.dialog)
-          .getNative()
-          .returnValue;
-    },
-
-    /** @override */
-    ready: function() {
-      // Initialize button label values for initial html binding.
-      this.cancelLabel_ = null;
-      this.confirmLabel_ = null;
-
-      switch (this.model.status) {
-        case chrome.developerPrivate.PackStatus.WARNING:
-          this.title_ = loadTimeData.getString('packDialogWarningTitle');
-          this.cancelLabel_ = loadTimeData.getString('cancel');
-          this.confirmLabel_ =
-              loadTimeData.getString('packDialogProceedAnyway');
-          break;
-        case chrome.developerPrivate.PackStatus.ERROR:
-          this.title_ = loadTimeData.getString('packDialogErrorTitle');
-          this.cancelLabel_ = loadTimeData.getString('ok');
-          break;
-        case chrome.developerPrivate.PackStatus.SUCCESS:
-          this.title_ = loadTimeData.getString('packDialogTitle');
-          this.cancelLabel_ = loadTimeData.getString('ok');
-          break;
-        default:
-          assertNotReached();
-          return;
-      }
-    },
-
-    /** @override */
-    attached: function() {
-      this.$.dialog.showModal();
-    },
+    /** @private {?string} */
+    cancelLabel_: String,
 
     /**
-     * @return {string}
-     * @private
+     * This needs to be initialized to trigger data-binding.
+     * @private {?string}
      */
-    getCancelButtonClass_: function() {
-      return this.confirmLabel_ ? 'cancel-button' : 'action-button';
-    },
-
-    /** @private */
-    onCancelTap_: function() {
-      this.$.dialog.cancel();
-    },
-
-    /** @private */
-    onConfirmTap_: function() {
-      // The confirm button should only be available in WARNING state.
-      assert(this.model.status === chrome.developerPrivate.PackStatus.WARNING);
-      this.$.dialog.close();
+    confirmLabel_: {
+      type: String,
+      value: '',
     }
-  });
+  },
+
+  /** @return {string} */
+  get returnValue() {
+    return /** @type {!CrDialogElement} */ (this.$.dialog)
+        .getNative()
+        .returnValue;
+  },
+
+  /** @override */
+  ready: function() {
+    // Initialize button label values for initial html binding.
+    this.cancelLabel_ = null;
+    this.confirmLabel_ = null;
+
+    switch (this.model.status) {
+      case chrome.developerPrivate.PackStatus.WARNING:
+        this.title_ = loadTimeData.getString('packDialogWarningTitle');
+        this.cancelLabel_ = loadTimeData.getString('cancel');
+        this.confirmLabel_ = loadTimeData.getString('packDialogProceedAnyway');
+        break;
+      case chrome.developerPrivate.PackStatus.ERROR:
+        this.title_ = loadTimeData.getString('packDialogErrorTitle');
+        this.cancelLabel_ = loadTimeData.getString('ok');
+        break;
+      case chrome.developerPrivate.PackStatus.SUCCESS:
+        this.title_ = loadTimeData.getString('packDialogTitle');
+        this.cancelLabel_ = loadTimeData.getString('ok');
+        break;
+      default:
+        assertNotReached();
+        return;
+    }
+  },
+
+  /** @override */
+  attached: function() {
+    this.$.dialog.showModal();
+  },
+
+  /**
+   * @return {string}
+   * @private
+   */
+  getCancelButtonClass_: function() {
+    return this.confirmLabel_ ? 'cancel-button' : 'action-button';
+  },
+
+  /** @private */
+  onCancelTap_: function() {
+    this.$.dialog.cancel();
+  },
+
+  /** @private */
+  onConfirmTap_: function() {
+    // The confirm button should only be available in WARNING state.
+    assert(this.model.status === chrome.developerPrivate.PackStatus.WARNING);
+    this.$.dialog.close();
+  }
+});
diff --git a/chrome/browser/resources/extensions/runtime_host_permissions.js b/chrome/browser/resources/extensions/runtime_host_permissions.js
index 33624e4..1814e42 100644
--- a/chrome/browser/resources/extensions/runtime_host_permissions.js
+++ b/chrome/browser/resources/extensions/runtime_host_permissions.js
@@ -23,245 +23,244 @@
 
 import {ItemDelegate} from './item.js';
 
-  Polymer({
-    is: 'extensions-runtime-host-permissions',
+Polymer({
+  is: 'extensions-runtime-host-permissions',
 
-    _template: html`{__html_template__}`,
+  _template: html`{__html_template__}`,
 
-    properties: {
-      /**
-       * The underlying permissions data.
-       * @type {chrome.developerPrivate.RuntimeHostPermissions}
-       */
-      permissions: Object,
-
-      /** @private */
-      itemId: String,
-
-      /** @type {!ItemDelegate} */
-      delegate: Object,
-
-      /**
-       * Whether the dialog to add a new host permission is shown.
-       * @private
-       */
-      showHostDialog_: Boolean,
-
-      /**
-       * The current site of the entry that the host dialog is editing, if the
-       * dialog is open for editing.
-       * @type {?string}
-       * @private
-       */
-      hostDialogModel_: {
-        type: String,
-        value: null,
-      },
-
-      /**
-       * The element to return focus to once the host dialog closes.
-       * @type {?HTMLElement}
-       * @private
-       */
-      hostDialogAnchorElement_: {
-        type: Object,
-        value: null,
-      },
-
-      /**
-       * If the action menu is open, the site of the entry it is open for.
-       * Otherwise null.
-       * @type {?string}
-       * @private
-       */
-      actionMenuModel_: {
-        type: String,
-        value: null,
-      },
-
-      /**
-       * The element that triggered the action menu, so that the page will
-       * return focus once the action menu (or dialog) closes.
-       * @type {?HTMLElement}
-       * @private
-       */
-      actionMenuAnchorElement_: {
-        type: Object,
-        value: null,
-      },
-
-      /**
-       * The old host access setting; used when we don't immediately commit the
-       * change to host access so that we can reset it if the user cancels.
-       * @type {?string}
-       * @private
-       */
-      oldHostAccess_: {
-        type: String,
-        value: null,
-      },
-
-      /**
-       * Proxying the enum to be used easily by the html template.
-       * @private
-       */
-      HostAccess_: {
-        type: Object,
-        value: chrome.developerPrivate.HostAccess,
-      },
-    },
-
+  properties: {
     /**
-     * @param {!Event} event
-     * @private
+     * The underlying permissions data.
+     * @type {chrome.developerPrivate.RuntimeHostPermissions}
      */
-    onHostAccessChange_: function(event) {
-      const group = /** @type {!HTMLElement} */ (this.$['host-access']);
-      const access = group.selected;
-
-      if (access == chrome.developerPrivate.HostAccess.ON_SPECIFIC_SITES &&
-          this.permissions.hostAccess !=
-              chrome.developerPrivate.HostAccess.ON_SPECIFIC_SITES) {
-        // If the user is transitioning to the "on specific sites" option, show
-        // the "add host" dialog. This serves two purposes:
-        // - The user is prompted to add a host immediately, since otherwise
-        //   "on specific sites" is meaningless, and
-        // - The way the C++ code differentiates between "on click" and "on
-        //   specific sites" is by checking if there are any specific sites.
-        //   This ensures there will be at least one, so that the host access
-        //   is properly calculated.
-        this.oldHostAccess_ = this.permissions.hostAccess;
-        this.doShowHostDialog_(group, null);
-      } else {
-        this.delegate.setItemHostAccess(this.itemId, access);
-      }
-    },
-
-    /**
-     * @return {boolean}
-     * @private
-     */
-    showSpecificSites_: function() {
-      return this.permissions.hostAccess ==
-          chrome.developerPrivate.HostAccess.ON_SPECIFIC_SITES;
-    },
-
-    /**
-     * Returns the granted host permissions as a sorted set of strings.
-     * @return {!Array<string>}
-     * @private
-     */
-    getRuntimeHosts_: function() {
-      if (!this.permissions.hosts) {
-        return [];
-      }
-
-      // Only show granted hosts in the list.
-      // TODO(devlin): For extensions that request a finite set of hosts,
-      // display them in a toggle list. https://crbug.com/891803.
-      return this.permissions.hosts.filter(control => control.granted)
-          .map(control => control.host)
-          .sort();
-    },
-
-    /**
-     * @param {Event} e
-     * @private
-     */
-    onAddHostClick_: function(e) {
-      const target = /** @type {!HTMLElement} */ (e.target);
-      this.doShowHostDialog_(target, null);
-    },
-
-    /**
-     * @param {!HTMLElement} anchorElement The element to return focus to once
-     *     the dialog closes.
-     * @param {?string} currentSite The site entry currently being
-     *     edited, or null if this is to add a new entry.
-     * @private
-     */
-    doShowHostDialog_: function(anchorElement, currentSite) {
-      this.hostDialogAnchorElement_ = anchorElement;
-      this.hostDialogModel_ = currentSite;
-      this.showHostDialog_ = true;
-    },
+    permissions: Object,
 
     /** @private */
-    onHostDialogClose_: function() {
-      this.hostDialogModel_ = null;
-      this.showHostDialog_ = false;
-      focusWithoutInk(assert(this.hostDialogAnchorElement_, 'Host Anchor'));
-      this.hostDialogAnchorElement_ = null;
+    itemId: String,
+
+    /** @type {!ItemDelegate} */
+    delegate: Object,
+
+    /**
+     * Whether the dialog to add a new host permission is shown.
+     * @private
+     */
+    showHostDialog_: Boolean,
+
+    /**
+     * The current site of the entry that the host dialog is editing, if the
+     * dialog is open for editing.
+     * @type {?string}
+     * @private
+     */
+    hostDialogModel_: {
+      type: String,
+      value: null,
+    },
+
+    /**
+     * The element to return focus to once the host dialog closes.
+     * @type {?HTMLElement}
+     * @private
+     */
+    hostDialogAnchorElement_: {
+      type: Object,
+      value: null,
+    },
+
+    /**
+     * If the action menu is open, the site of the entry it is open for.
+     * Otherwise null.
+     * @type {?string}
+     * @private
+     */
+    actionMenuModel_: {
+      type: String,
+      value: null,
+    },
+
+    /**
+     * The element that triggered the action menu, so that the page will
+     * return focus once the action menu (or dialog) closes.
+     * @type {?HTMLElement}
+     * @private
+     */
+    actionMenuAnchorElement_: {
+      type: Object,
+      value: null,
+    },
+
+    /**
+     * The old host access setting; used when we don't immediately commit the
+     * change to host access so that we can reset it if the user cancels.
+     * @type {?string}
+     * @private
+     */
+    oldHostAccess_: {
+      type: String,
+      value: null,
+    },
+
+    /**
+     * Proxying the enum to be used easily by the html template.
+     * @private
+     */
+    HostAccess_: {
+      type: Object,
+      value: chrome.developerPrivate.HostAccess,
+    },
+  },
+
+  /**
+   * @param {!Event} event
+   * @private
+   */
+  onHostAccessChange_: function(event) {
+    const group = /** @type {!HTMLElement} */ (this.$['host-access']);
+    const access = group.selected;
+
+    if (access == chrome.developerPrivate.HostAccess.ON_SPECIFIC_SITES &&
+        this.permissions.hostAccess !=
+            chrome.developerPrivate.HostAccess.ON_SPECIFIC_SITES) {
+      // If the user is transitioning to the "on specific sites" option, show
+      // the "add host" dialog. This serves two purposes:
+      // - The user is prompted to add a host immediately, since otherwise
+      //   "on specific sites" is meaningless, and
+      // - The way the C++ code differentiates between "on click" and "on
+      //   specific sites" is by checking if there are any specific sites.
+      //   This ensures there will be at least one, so that the host access
+      //   is properly calculated.
+      this.oldHostAccess_ = this.permissions.hostAccess;
+      this.doShowHostDialog_(group, null);
+    } else {
+      this.delegate.setItemHostAccess(this.itemId, access);
+    }
+  },
+
+  /**
+   * @return {boolean}
+   * @private
+   */
+  showSpecificSites_: function() {
+    return this.permissions.hostAccess ==
+        chrome.developerPrivate.HostAccess.ON_SPECIFIC_SITES;
+  },
+
+  /**
+   * Returns the granted host permissions as a sorted set of strings.
+   * @return {!Array<string>}
+   * @private
+   */
+  getRuntimeHosts_: function() {
+    if (!this.permissions.hosts) {
+      return [];
+    }
+
+    // Only show granted hosts in the list.
+    // TODO(devlin): For extensions that request a finite set of hosts,
+    // display them in a toggle list. https://crbug.com/891803.
+    return this.permissions.hosts.filter(control => control.granted)
+        .map(control => control.host)
+        .sort();
+  },
+
+  /**
+   * @param {Event} e
+   * @private
+   */
+  onAddHostClick_: function(e) {
+    const target = /** @type {!HTMLElement} */ (e.target);
+    this.doShowHostDialog_(target, null);
+  },
+
+  /**
+   * @param {!HTMLElement} anchorElement The element to return focus to once
+   *     the dialog closes.
+   * @param {?string} currentSite The site entry currently being
+   *     edited, or null if this is to add a new entry.
+   * @private
+   */
+  doShowHostDialog_: function(anchorElement, currentSite) {
+    this.hostDialogAnchorElement_ = anchorElement;
+    this.hostDialogModel_ = currentSite;
+    this.showHostDialog_ = true;
+  },
+
+  /** @private */
+  onHostDialogClose_: function() {
+    this.hostDialogModel_ = null;
+    this.showHostDialog_ = false;
+    focusWithoutInk(assert(this.hostDialogAnchorElement_, 'Host Anchor'));
+    this.hostDialogAnchorElement_ = null;
+    this.oldHostAccess_ = null;
+  },
+
+  /** @private */
+  onHostDialogCancel_: function() {
+    // The user canceled the dialog. Set host-access back to the old value,
+    // if the dialog was shown when just transitioning to a new state.
+    if (this.oldHostAccess_) {
+      assert(this.permissions.hostAccess == this.oldHostAccess_);
+      this.$['host-access'].selected = this.oldHostAccess_;
       this.oldHostAccess_ = null;
-    },
+    }
+  },
 
-    /** @private */
-    onHostDialogCancel_: function() {
-      // The user canceled the dialog. Set host-access back to the old value,
-      // if the dialog was shown when just transitioning to a new state.
-      if (this.oldHostAccess_) {
-        assert(this.permissions.hostAccess == this.oldHostAccess_);
-        this.$['host-access'].selected = this.oldHostAccess_;
-        this.oldHostAccess_ = null;
-      }
-    },
+  /**
+   * @return {boolean}
+   * @private
+   */
+  dialogShouldUpdateHostAccess_: function() {
+    return !!this.oldHostAccess_;
+  },
 
-    /**
-     * @return {boolean}
-     * @private
-     */
-    dialogShouldUpdateHostAccess_: function() {
-      return !!this.oldHostAccess_;
-    },
+  /**
+   * @param {!{
+   *   model: !{item: string},
+   *   target: !HTMLElement,
+   * }} e
+   * @private
+   */
+  onEditHostClick_: function(e) {
+    this.actionMenuModel_ = e.model.item;
+    this.actionMenuAnchorElement_ = e.target;
+    const actionMenu =
+        /** @type {CrActionMenuElement} */ (this.$.hostActionMenu);
+    actionMenu.showAt(e.target);
+  },
 
-    /**
-     * @param {!{
-     *   model: !{item: string},
-     *   target: !HTMLElement,
-     * }} e
-     * @private
-     */
-    onEditHostClick_: function(e) {
-      this.actionMenuModel_ = e.model.item;
-      this.actionMenuAnchorElement_ = e.target;
-      const actionMenu =
-          /** @type {CrActionMenuElement} */ (this.$.hostActionMenu);
-      actionMenu.showAt(e.target);
-    },
+  /** @private */
+  onActionMenuEditClick_: function() {
+    // Cache the site before closing the action menu, since it's cleared.
+    const site = this.actionMenuModel_;
 
-    /** @private */
-    onActionMenuEditClick_: function() {
-      // Cache the site before closing the action menu, since it's cleared.
-      const site = this.actionMenuModel_;
+    // Cache and reset actionMenuAnchorElement_ so focus is not returned
+    // to the action menu's trigger (since the dialog will be shown next).
+    // Instead, curry the element to the dialog, so once it closes, focus
+    // will be returned.
+    const anchorElement = assert(this.actionMenuAnchorElement_, 'Menu Anchor');
+    this.actionMenuAnchorElement_ = null;
+    this.closeActionMenu_();
+    this.doShowHostDialog_(anchorElement, site);
+  },
 
-      // Cache and reset actionMenuAnchorElement_ so focus is not returned
-      // to the action menu's trigger (since the dialog will be shown next).
-      // Instead, curry the element to the dialog, so once it closes, focus
-      // will be returned.
-      const anchorElement =
-          assert(this.actionMenuAnchorElement_, 'Menu Anchor');
-      this.actionMenuAnchorElement_ = null;
-      this.closeActionMenu_();
-      this.doShowHostDialog_(anchorElement, site);
-    },
+  /** @private */
+  onActionMenuRemoveClick_: function() {
+    this.delegate.removeRuntimeHostPermission(
+        this.itemId, assert(this.actionMenuModel_, 'Action Menu Model'));
+    this.closeActionMenu_();
+  },
 
-    /** @private */
-    onActionMenuRemoveClick_: function() {
-      this.delegate.removeRuntimeHostPermission(
-          this.itemId, assert(this.actionMenuModel_, 'Action Menu Model'));
-      this.closeActionMenu_();
-    },
+  /** @private */
+  closeActionMenu_: function() {
+    const menu = this.$.hostActionMenu;
+    assert(menu.open);
+    menu.close();
+  },
 
-    /** @private */
-    closeActionMenu_: function() {
-      const menu = this.$.hostActionMenu;
-      assert(menu.open);
-      menu.close();
-    },
-
-    /** @private */
-    onActionMenuClose_: function() {
-      this.actionMenuModel_ = null;
-      this.actionMenuAnchorElement_ = null;
-    },
-  });
+  /** @private */
+  onActionMenuClose_: function() {
+    this.actionMenuModel_ = null;
+    this.actionMenuAnchorElement_ = null;
+  },
+});
diff --git a/chrome/browser/resources/extensions/runtime_hosts_dialog.js b/chrome/browser/resources/extensions/runtime_hosts_dialog.js
index b37c1ae9..bbe15ac 100644
--- a/chrome/browser/resources/extensions/runtime_hosts_dialog.js
+++ b/chrome/browser/resources/extensions/runtime_hosts_dialog.js
@@ -14,216 +14,216 @@
 
 import {ItemDelegate} from './item.js';
 
-  // A RegExp to roughly match acceptable patterns entered by the user.
-  // exec'ing() this RegExp will match the following groups:
-  // 0: Full matched string.
-  // 1: Scheme + scheme separator (e.g., 'https://').
-  // 2: Scheme only (e.g., 'https').
-  // 3: Match subdomains ('*.').
-  // 4: Hostname (e.g., 'example.com').
-  // 5: Port, including ':' separator (e.g., ':80').
-  // 6: Path, include '/' separator (e.g., '/*').
-  const patternRegExp = new RegExp(
-      '^' +
-      // Scheme; optional.
-      '((http|https|\\*)://)?' +
-      // Include subdomains specifier; optional.
-      '(\\*\\.)?' +
-      // Hostname, required.
-      '([a-z0-9\\.-]+\\.[a-z0-9]+)' +
-      // Port, optional.
-      '(:[0-9]+)?' +
-      // Path, optional but if present must be '/' or '/*'.
-      '(\\/\\*|\\/)?' +
-      '$');
+// A RegExp to roughly match acceptable patterns entered by the user.
+// exec'ing() this RegExp will match the following groups:
+// 0: Full matched string.
+// 1: Scheme + scheme separator (e.g., 'https://').
+// 2: Scheme only (e.g., 'https').
+// 3: Match subdomains ('*.').
+// 4: Hostname (e.g., 'example.com').
+// 5: Port, including ':' separator (e.g., ':80').
+// 6: Path, include '/' separator (e.g., '/*').
+const patternRegExp = new RegExp(
+    '^' +
+    // Scheme; optional.
+    '((http|https|\\*)://)?' +
+    // Include subdomains specifier; optional.
+    '(\\*\\.)?' +
+    // Hostname, required.
+    '([a-z0-9\\.-]+\\.[a-z0-9]+)' +
+    // Port, optional.
+    '(:[0-9]+)?' +
+    // Path, optional but if present must be '/' or '/*'.
+    '(\\/\\*|\\/)?' +
+    '$');
 
-  export function getPatternFromSite(site) {
-    const res = patternRegExp.exec(site);
-    assert(res);
-    const scheme = res[1] || '*://';
-    const host = (res[3] || '') + res[4];
-    const port = res[5] || '';
-    const path = '/*';
-    return scheme + host + port + path;
-  }
+export function getPatternFromSite(site) {
+  const res = patternRegExp.exec(site);
+  assert(res);
+  const scheme = res[1] || '*://';
+  const host = (res[3] || '') + res[4];
+  const port = res[5] || '';
+  const path = '/*';
+  return scheme + host + port + path;
+}
 
-  Polymer({
-    is: 'extensions-runtime-hosts-dialog',
+Polymer({
+  is: 'extensions-runtime-hosts-dialog',
 
-    _template: html`{__html_template__}`,
+  _template: html`{__html_template__}`,
 
-    properties: {
-      /** @type {!ItemDelegate} */
-      delegate: Object,
+  properties: {
+    /** @type {!ItemDelegate} */
+    delegate: Object,
 
-      /** @type {string} */
-      itemId: String,
+    /** @type {string} */
+    itemId: String,
 
-      /**
-       * The site that this entry is currently managing. Only non-empty if this
-       * is for editing an existing entry.
-       * @type {?string}
-       */
-      currentSite: {
-        type: String,
-        value: null,
-      },
-
-      /**
-       * Whether the dialog should update the host access to be "on specific
-       * sites" before adding a new host permission.
-       */
-      updateHostAccess: {
-        type: Boolean,
-        value: false,
-      },
-
-      /**
-       * The site to add an exception for.
-       * @private
-       */
-      site_: String,
-
-      /**
-       * Whether the currently-entered input is valid.
-       * @private
-       */
-      inputInvalid_: {
-        type: Boolean,
-        value: false,
-      },
-    },
-
-    /** @override */
-    attached: function() {
-      if (this.currentSite !== null && this.currentSite !== undefined) {
-        this.site_ = this.currentSite;
-        this.validate_();
-      }
-      this.$.dialog.showModal();
-    },
-
-    /** @return {boolean} */
-    isOpen: function() {
-      return this.$.dialog.open;
+    /**
+     * The site that this entry is currently managing. Only non-empty if this
+     * is for editing an existing entry.
+     * @type {?string}
+     */
+    currentSite: {
+      type: String,
+      value: null,
     },
 
     /**
-     * Validates that the pattern entered is valid.
-     * @private
+     * Whether the dialog should update the host access to be "on specific
+     * sites" before adding a new host permission.
      */
-    validate_: function() {
-      // If input is empty, disable the action button, but don't show the red
-      // invalid message.
-      if (this.site_.trim().length == 0) {
-        this.inputInvalid_ = false;
-        return;
-      }
-
-      const valid = patternRegExp.test(this.site_);
-      this.inputInvalid_ = !valid;
+    updateHostAccess: {
+      type: Boolean,
+      value: false,
     },
 
     /**
-     * @return {string}
+     * The site to add an exception for.
      * @private
      */
-    computeDialogTitle_: function() {
-      const stringId = this.currentSite === null ? 'runtimeHostsDialogTitle' :
-                                                   'hostPermissionsEdit';
-      return loadTimeData.getString(stringId);
-    },
+    site_: String,
 
     /**
-     * @return {boolean}
+     * Whether the currently-entered input is valid.
      * @private
      */
-    computeSubmitButtonDisabled_: function() {
-      return this.inputInvalid_ || this.site_ === undefined ||
-          this.site_.trim().length == 0;
+    inputInvalid_: {
+      type: Boolean,
+      value: false,
     },
+  },
 
-    /**
-     * @return {string}
-     * @private
-     */
-    computeSubmitButtonLabel_: function() {
-      const stringId = this.currentSite === null ? 'add' : 'save';
-      return loadTimeData.getString(stringId);
-    },
+  /** @override */
+  attached: function() {
+    if (this.currentSite !== null && this.currentSite !== undefined) {
+      this.site_ = this.currentSite;
+      this.validate_();
+    }
+    this.$.dialog.showModal();
+  },
 
-    /** @private */
-    onCancelTap_: function() {
-      this.$.dialog.cancel();
-    },
+  /** @return {boolean} */
+  isOpen: function() {
+    return this.$.dialog.open;
+  },
 
-    /**
-     * The tap handler for the submit button (adds the pattern and closes
-     * the dialog).
-     * @private
-     */
-    onSubmitTap_: function() {
-      if (this.currentSite !== null) {
-        this.handleEdit_();
-      } else {
-        this.handleAdd_();
-      }
-    },
+  /**
+   * Validates that the pattern entered is valid.
+   * @private
+   */
+  validate_: function() {
+    // If input is empty, disable the action button, but don't show the red
+    // invalid message.
+    if (this.site_.trim().length == 0) {
+      this.inputInvalid_ = false;
+      return;
+    }
 
-    /**
-     * Handles adding a new site entry.
-     * @private
-     */
-    handleAdd_: function() {
-      assert(!this.currentSite);
+    const valid = patternRegExp.test(this.site_);
+    this.inputInvalid_ = !valid;
+  },
 
-      if (this.updateHostAccess) {
-        this.delegate.setItemHostAccess(
-            this.itemId, chrome.developerPrivate.HostAccess.ON_SPECIFIC_SITES);
-      }
+  /**
+   * @return {string}
+   * @private
+   */
+  computeDialogTitle_: function() {
+    const stringId = this.currentSite === null ? 'runtimeHostsDialogTitle' :
+                                                 'hostPermissionsEdit';
+    return loadTimeData.getString(stringId);
+  },
 
-      this.addPermission_();
-    },
+  /**
+   * @return {boolean}
+   * @private
+   */
+  computeSubmitButtonDisabled_: function() {
+    return this.inputInvalid_ || this.site_ === undefined ||
+        this.site_.trim().length == 0;
+  },
 
-    /**
-     * Handles editing an existing site entry.
-     * @private
-     */
-    handleEdit_: function() {
-      assert(this.currentSite);
-      assert(
-          !this.updateHostAccess,
-          'Editing host permissions should only be possible if the host ' +
-              'access is already set to specific sites.');
+  /**
+   * @return {string}
+   * @private
+   */
+  computeSubmitButtonLabel_: function() {
+    const stringId = this.currentSite === null ? 'add' : 'save';
+    return loadTimeData.getString(stringId);
+  },
 
-      if (this.currentSite == this.site_) {
-        // No change in values, so no need to update anything.
-        this.$.dialog.close();
-        return;
-      }
+  /** @private */
+  onCancelTap_: function() {
+    this.$.dialog.cancel();
+  },
 
-      // Editing an existing entry is done by removing the current site entry,
-      // and then adding the new one.
-      this.delegate.removeRuntimeHostPermission(this.itemId, this.currentSite)
-          .then(() => {
-            this.addPermission_();
-          });
-    },
+  /**
+   * The tap handler for the submit button (adds the pattern and closes
+   * the dialog).
+   * @private
+   */
+  onSubmitTap_: function() {
+    if (this.currentSite !== null) {
+      this.handleEdit_();
+    } else {
+      this.handleAdd_();
+    }
+  },
 
-    /**
-     * Adds the runtime host permission through the delegate. If successful,
-     * closes the dialog; otherwise displays the invalid input message.
-     * @private
-     */
-    addPermission_: function() {
-      const pattern = getPatternFromSite(this.site_);
-      this.delegate.addRuntimeHostPermission(this.itemId, pattern)
-          .then(
-              () => {
-                this.$.dialog.close();
-              },
-              () => {
-                this.inputInvalid_ = true;
-              });
-    },
-  });
+  /**
+   * Handles adding a new site entry.
+   * @private
+   */
+  handleAdd_: function() {
+    assert(!this.currentSite);
+
+    if (this.updateHostAccess) {
+      this.delegate.setItemHostAccess(
+          this.itemId, chrome.developerPrivate.HostAccess.ON_SPECIFIC_SITES);
+    }
+
+    this.addPermission_();
+  },
+
+  /**
+   * Handles editing an existing site entry.
+   * @private
+   */
+  handleEdit_: function() {
+    assert(this.currentSite);
+    assert(
+        !this.updateHostAccess,
+        'Editing host permissions should only be possible if the host ' +
+            'access is already set to specific sites.');
+
+    if (this.currentSite == this.site_) {
+      // No change in values, so no need to update anything.
+      this.$.dialog.close();
+      return;
+    }
+
+    // Editing an existing entry is done by removing the current site entry,
+    // and then adding the new one.
+    this.delegate.removeRuntimeHostPermission(this.itemId, this.currentSite)
+        .then(() => {
+          this.addPermission_();
+        });
+  },
+
+  /**
+   * Adds the runtime host permission through the delegate. If successful,
+   * closes the dialog; otherwise displays the invalid input message.
+   * @private
+   */
+  addPermission_: function() {
+    const pattern = getPatternFromSite(this.site_);
+    this.delegate.addRuntimeHostPermission(this.itemId, pattern)
+        .then(
+            () => {
+              this.$.dialog.close();
+            },
+            () => {
+              this.inputInvalid_ = true;
+            });
+  },
+});
diff --git a/chrome/browser/resources/extensions/service.js b/chrome/browser/resources/extensions/service.js
index 1c9967b..0e1e52c 100644
--- a/chrome/browser/resources/extensions/service.js
+++ b/chrome/browser/resources/extensions/service.js
@@ -11,455 +11,453 @@
 import {ItemDelegate} from './item.js';
 import {KeyboardShortcutDelegate} from './keyboard_shortcut_delegate.js';
 import {LoadErrorDelegate} from './load_error.js';
-import {Dialog,navigation,Page} from './navigation_helper.js';
+import {Dialog, navigation, Page} from './navigation_helper.js';
 import {PackDialogDelegate} from './pack_dialog.js';
 import {ToolbarDelegate} from './toolbar.js';
 
 
+/**
+ * @implements {ActivityLogDelegate}
+ * @implements {ActivityLogEventDelegate}
+ * @implements {ErrorPageDelegate}
+ * @implements {ItemDelegate}
+ * @implements {KeyboardShortcutDelegate}
+ * @implements {LoadErrorDelegate}
+ * @implements {PackDialogDelegate}
+ * @implements {ToolbarDelegate}
+ */
+export class Service {
+  constructor() {
+    /** @private {boolean} */
+    this.isDeleting_ = false;
+
+    /** @private {!Set<string>} */
+    this.eventsToIgnoreOnce_ = new Set();
+  }
+
+  getProfileConfiguration() {
+    return new Promise(function(resolve, reject) {
+      chrome.developerPrivate.getProfileConfiguration(resolve);
+    });
+  }
+
+  getItemStateChangedTarget() {
+    return chrome.developerPrivate.onItemStateChanged;
+  }
+
   /**
-   * @implements {ActivityLogDelegate}
-   * @implements {ActivityLogEventDelegate}
-   * @implements {ErrorPageDelegate}
-   * @implements {ItemDelegate}
-   * @implements {KeyboardShortcutDelegate}
-   * @implements {LoadErrorDelegate}
-   * @implements {PackDialogDelegate}
-   * @implements {ToolbarDelegate}
+   * @param {string} extensionId
+   * @param {!chrome.developerPrivate.EventType} eventType
+   * @return {boolean}
    */
-  export class Service {
-    constructor() {
-      /** @private {boolean} */
+  shouldIgnoreUpdate(extensionId, eventType) {
+    return this.eventsToIgnoreOnce_.delete(`${extensionId}_${eventType}`);
+  }
+
+  /**
+   * @param {string} extensionId
+   * @param {!chrome.developerPrivate.EventType} eventType
+   */
+  ignoreNextEvent(extensionId, eventType) {
+    this.eventsToIgnoreOnce_.add(`${extensionId}_${eventType}`);
+  }
+
+  getProfileStateChangedTarget() {
+    return chrome.developerPrivate.onProfileStateChanged;
+  }
+
+  getExtensionsInfo() {
+    return new Promise(function(resolve, reject) {
+      chrome.developerPrivate.getExtensionsInfo(
+          {includeDisabled: true, includeTerminated: true}, resolve);
+    });
+  }
+
+  /** @override */
+  getExtensionSize(id) {
+    return new Promise(function(resolve, reject) {
+      chrome.developerPrivate.getExtensionSize(id, resolve);
+    });
+  }
+
+  /** @override */
+  addRuntimeHostPermission(id, host) {
+    return new Promise((resolve, reject) => {
+      chrome.developerPrivate.addHostPermission(id, host, () => {
+        if (chrome.runtime.lastError) {
+          reject(chrome.runtime.lastError.message);
+          return;
+        }
+        resolve();
+      });
+    });
+  }
+
+  /** @override */
+  removeRuntimeHostPermission(id, host) {
+    return new Promise((resolve, reject) => {
+      chrome.developerPrivate.removeHostPermission(id, host, () => {
+        if (chrome.runtime.lastError) {
+          reject(chrome.runtime.lastError.message);
+          return;
+        }
+        resolve();
+      });
+    });
+  }
+
+  /**
+   * Opens a file browser dialog for the user to select a file (or directory).
+   * @param {chrome.developerPrivate.SelectType} selectType
+   * @param {chrome.developerPrivate.FileType} fileType
+   * @return {Promise<string>} The promise to be resolved with the selected
+   *     path.
+   */
+  chooseFilePath_(selectType, fileType) {
+    return new Promise(function(resolve, reject) {
+      chrome.developerPrivate.choosePath(selectType, fileType, function(path) {
+        if (chrome.runtime.lastError &&
+            chrome.runtime.lastError != 'File selection was canceled.') {
+          reject(chrome.runtime.lastError);
+        } else {
+          resolve(path || '');
+        }
+      });
+    });
+  }
+
+  /** @override */
+  updateExtensionCommandKeybinding(extensionId, commandName, keybinding) {
+    chrome.developerPrivate.updateExtensionCommand({
+      extensionId: extensionId,
+      commandName: commandName,
+      keybinding: keybinding,
+    });
+  }
+
+  /** @override */
+  updateExtensionCommandScope(extensionId, commandName, scope) {
+    // The COMMAND_REMOVED event needs to be ignored since it is sent before
+    // the command is added back with the updated scope but can be handled
+    // after the COMMAND_ADDED event.
+    this.ignoreNextEvent(
+        extensionId, chrome.developerPrivate.EventType.COMMAND_REMOVED);
+    chrome.developerPrivate.updateExtensionCommand({
+      extensionId: extensionId,
+      commandName: commandName,
+      scope: scope,
+    });
+  }
+
+
+  /** @override */
+  setShortcutHandlingSuspended(isCapturing) {
+    chrome.developerPrivate.setShortcutHandlingSuspended(isCapturing);
+  }
+
+  /**
+   * @param {chrome.developerPrivate.LoadUnpackedOptions=} opt_options
+   * @return {!Promise} A signal that loading finished, rejected if any error
+   *     occurred.
+   * @private
+   */
+  loadUnpackedHelper_(opt_options) {
+    return new Promise(function(resolve, reject) {
+      const options = Object.assign(
+          {
+            failQuietly: true,
+            populateError: true,
+          },
+          opt_options);
+
+      chrome.developerPrivate.loadUnpacked(options, (loadError) => {
+        if (chrome.runtime.lastError &&
+            chrome.runtime.lastError.message !=
+                'File selection was canceled.') {
+          throw new Error(chrome.runtime.lastError.message);
+        }
+        if (loadError) {
+          return reject(loadError);
+        }
+
+        resolve();
+      });
+    });
+  }
+
+  /** @override */
+  deleteItem(id) {
+    if (this.isDeleting_) {
+      return;
+    }
+    this.isDeleting_ = true;
+    chrome.management.uninstall(id, {showConfirmDialog: true}, () => {
+      // The "last error" was almost certainly the user canceling the dialog.
+      // Do nothing. We only check it so we don't get noisy logs.
+      /** @suppress {suspiciousCode} */
+      chrome.runtime.lastError;
       this.isDeleting_ = false;
+    });
+  }
 
-      /** @private {!Set<string>} */
-      this.eventsToIgnoreOnce_ = new Set();
-    }
+  /** @override */
+  setItemEnabled(id, isEnabled) {
+    chrome.management.setEnabled(id, isEnabled);
+  }
 
-    getProfileConfiguration() {
-      return new Promise(function(resolve, reject) {
-        chrome.developerPrivate.getProfileConfiguration(resolve);
+  /** @override */
+  setItemAllowedIncognito(id, isAllowedIncognito) {
+    chrome.developerPrivate.updateExtensionConfiguration({
+      extensionId: id,
+      incognitoAccess: isAllowedIncognito,
+    });
+  }
+
+  /** @override */
+  setItemAllowedOnFileUrls(id, isAllowedOnFileUrls) {
+    chrome.developerPrivate.updateExtensionConfiguration({
+      extensionId: id,
+      fileAccess: isAllowedOnFileUrls,
+    });
+  }
+
+  /** @override */
+  setItemHostAccess(id, hostAccess) {
+    chrome.developerPrivate.updateExtensionConfiguration({
+      extensionId: id,
+      hostAccess: hostAccess,
+    });
+  }
+
+  /** @override */
+  setItemCollectsErrors(id, collectsErrors) {
+    chrome.developerPrivate.updateExtensionConfiguration({
+      extensionId: id,
+      errorCollection: collectsErrors,
+    });
+  }
+
+  /** @override */
+  inspectItemView(id, view) {
+    chrome.developerPrivate.openDevTools({
+      extensionId: id,
+      renderProcessId: view.renderProcessId,
+      renderViewId: view.renderViewId,
+      incognito: view.incognito,
+    });
+  }
+
+  /**
+   * @param {string} url
+   * @override
+   */
+  openUrl(url) {
+    window.open(url);
+  }
+
+  /** @override */
+  reloadItem(id) {
+    return new Promise(function(resolve, reject) {
+      chrome.developerPrivate.reload(
+          id, {failQuietly: true, populateErrorForUnpacked: true},
+          (loadError) => {
+            if (loadError) {
+              reject(loadError);
+              return;
+            }
+
+            resolve();
+          });
+    });
+  }
+
+  /** @override */
+  repairItem(id) {
+    chrome.developerPrivate.repairExtension(id);
+  }
+
+  /** @override */
+  showItemOptionsPage(extension) {
+    assert(extension && extension.optionsPage);
+    if (extension.optionsPage.openInTab) {
+      chrome.developerPrivate.showOptions(extension.id);
+    } else {
+      navigation.navigateTo({
+        page: Page.DETAILS,
+        subpage: Dialog.OPTIONS,
+        extensionId: extension.id,
       });
     }
-
-    getItemStateChangedTarget() {
-      return chrome.developerPrivate.onItemStateChanged;
-    }
-
-    /**
-     * @param {string} extensionId
-     * @param {!chrome.developerPrivate.EventType} eventType
-     * @return {boolean}
-     */
-    shouldIgnoreUpdate(extensionId, eventType) {
-      return this.eventsToIgnoreOnce_.delete(`${extensionId}_${eventType}`);
-    }
-
-    /**
-     * @param {string} extensionId
-     * @param {!chrome.developerPrivate.EventType} eventType
-     */
-    ignoreNextEvent(extensionId, eventType) {
-      this.eventsToIgnoreOnce_.add(`${extensionId}_${eventType}`);
-    }
-
-    getProfileStateChangedTarget() {
-      return chrome.developerPrivate.onProfileStateChanged;
-    }
-
-    getExtensionsInfo() {
-      return new Promise(function(resolve, reject) {
-        chrome.developerPrivate.getExtensionsInfo(
-            {includeDisabled: true, includeTerminated: true}, resolve);
-      });
-    }
-
-    /** @override */
-    getExtensionSize(id) {
-      return new Promise(function(resolve, reject) {
-        chrome.developerPrivate.getExtensionSize(id, resolve);
-      });
-    }
-
-    /** @override */
-    addRuntimeHostPermission(id, host) {
-      return new Promise((resolve, reject) => {
-        chrome.developerPrivate.addHostPermission(id, host, () => {
-          if (chrome.runtime.lastError) {
-            reject(chrome.runtime.lastError.message);
-            return;
-          }
-          resolve();
-        });
-      });
-    }
-
-    /** @override */
-    removeRuntimeHostPermission(id, host) {
-      return new Promise((resolve, reject) => {
-        chrome.developerPrivate.removeHostPermission(id, host, () => {
-          if (chrome.runtime.lastError) {
-            reject(chrome.runtime.lastError.message);
-            return;
-          }
-          resolve();
-        });
-      });
-    }
-
-    /**
-     * Opens a file browser dialog for the user to select a file (or directory).
-     * @param {chrome.developerPrivate.SelectType} selectType
-     * @param {chrome.developerPrivate.FileType} fileType
-     * @return {Promise<string>} The promise to be resolved with the selected
-     *     path.
-     */
-    chooseFilePath_(selectType, fileType) {
-      return new Promise(function(resolve, reject) {
-        chrome.developerPrivate.choosePath(
-            selectType, fileType, function(path) {
-              if (chrome.runtime.lastError &&
-                  chrome.runtime.lastError != 'File selection was canceled.') {
-                reject(chrome.runtime.lastError);
-              } else {
-                resolve(path || '');
-              }
-            });
-      });
-    }
-
-    /** @override */
-    updateExtensionCommandKeybinding(extensionId, commandName, keybinding) {
-      chrome.developerPrivate.updateExtensionCommand({
-        extensionId: extensionId,
-        commandName: commandName,
-        keybinding: keybinding,
-      });
-    }
-
-    /** @override */
-    updateExtensionCommandScope(extensionId, commandName, scope) {
-      // The COMMAND_REMOVED event needs to be ignored since it is sent before
-      // the command is added back with the updated scope but can be handled
-      // after the COMMAND_ADDED event.
-      this.ignoreNextEvent(
-          extensionId, chrome.developerPrivate.EventType.COMMAND_REMOVED);
-      chrome.developerPrivate.updateExtensionCommand({
-        extensionId: extensionId,
-        commandName: commandName,
-        scope: scope,
-      });
-    }
-
-
-    /** @override */
-    setShortcutHandlingSuspended(isCapturing) {
-      chrome.developerPrivate.setShortcutHandlingSuspended(isCapturing);
-    }
-
-    /**
-     * @param {chrome.developerPrivate.LoadUnpackedOptions=} opt_options
-     * @return {!Promise} A signal that loading finished, rejected if any error
-     *     occurred.
-     * @private
-     */
-    loadUnpackedHelper_(opt_options) {
-      return new Promise(function(resolve, reject) {
-        const options = Object.assign(
-            {
-              failQuietly: true,
-              populateError: true,
-            },
-            opt_options);
-
-        chrome.developerPrivate.loadUnpacked(
-            options, (loadError) => {
-              if (chrome.runtime.lastError &&
-                  chrome.runtime.lastError.message !=
-                      'File selection was canceled.') {
-                throw new Error(chrome.runtime.lastError.message);
-              }
-              if (loadError) {
-                return reject(loadError);
-              }
-
-              resolve();
-            });
-      });
-    }
-
-    /** @override */
-    deleteItem(id) {
-      if (this.isDeleting_) {
-        return;
-      }
-      this.isDeleting_ = true;
-      chrome.management.uninstall(id, {showConfirmDialog: true}, () => {
-        // The "last error" was almost certainly the user canceling the dialog.
-        // Do nothing. We only check it so we don't get noisy logs.
-        /** @suppress {suspiciousCode} */
-        chrome.runtime.lastError;
-        this.isDeleting_ = false;
-      });
-    }
-
-    /** @override */
-    setItemEnabled(id, isEnabled) {
-      chrome.management.setEnabled(id, isEnabled);
-    }
-
-    /** @override */
-    setItemAllowedIncognito(id, isAllowedIncognito) {
-      chrome.developerPrivate.updateExtensionConfiguration({
-        extensionId: id,
-        incognitoAccess: isAllowedIncognito,
-      });
-    }
-
-    /** @override */
-    setItemAllowedOnFileUrls(id, isAllowedOnFileUrls) {
-      chrome.developerPrivate.updateExtensionConfiguration({
-        extensionId: id,
-        fileAccess: isAllowedOnFileUrls,
-      });
-    }
-
-    /** @override */
-    setItemHostAccess(id, hostAccess) {
-      chrome.developerPrivate.updateExtensionConfiguration({
-        extensionId: id,
-        hostAccess: hostAccess,
-      });
-    }
-
-    /** @override */
-    setItemCollectsErrors(id, collectsErrors) {
-      chrome.developerPrivate.updateExtensionConfiguration({
-        extensionId: id,
-        errorCollection: collectsErrors,
-      });
-    }
-
-    /** @override */
-    inspectItemView(id, view) {
-      chrome.developerPrivate.openDevTools({
-        extensionId: id,
-        renderProcessId: view.renderProcessId,
-        renderViewId: view.renderViewId,
-        incognito: view.incognito,
-      });
-    }
-
-    /**
-     * @param {string} url
-     * @override
-     */
-    openUrl(url) {
-      window.open(url);
-    }
-
-    /** @override */
-    reloadItem(id) {
-      return new Promise(function(resolve, reject) {
-        chrome.developerPrivate.reload(
-            id, {failQuietly: true, populateErrorForUnpacked: true},
-            (loadError) => {
-              if (loadError) {
-                reject(loadError);
-                return;
-              }
-
-              resolve();
-            });
-      });
-    }
-
-    /** @override */
-    repairItem(id) {
-      chrome.developerPrivate.repairExtension(id);
-    }
-
-    /** @override */
-    showItemOptionsPage(extension) {
-      assert(extension && extension.optionsPage);
-      if (extension.optionsPage.openInTab) {
-        chrome.developerPrivate.showOptions(extension.id);
-      } else {
-        navigation.navigateTo({
-          page: Page.DETAILS,
-          subpage: Dialog.OPTIONS,
-          extensionId: extension.id,
-        });
-      }
-    }
-
-    /** @override */
-    setProfileInDevMode(inDevMode) {
-      chrome.developerPrivate.updateProfileConfiguration(
-          {inDeveloperMode: inDevMode});
-    }
-
-    /** @override */
-    loadUnpacked() {
-      return this.loadUnpackedHelper_();
-    }
-
-    /** @override */
-    retryLoadUnpacked(retryGuid) {
-      // Attempt to load an unpacked extension, optionally as another attempt at
-      // a previously-specified load.
-      return this.loadUnpackedHelper_({retryGuid: retryGuid});
-    }
-
-    /** @override */
-    choosePackRootDirectory() {
-      return this.chooseFilePath_(
-          chrome.developerPrivate.SelectType.FOLDER,
-          chrome.developerPrivate.FileType.LOAD);
-    }
-
-    /** @override */
-    choosePrivateKeyPath() {
-      return this.chooseFilePath_(
-          chrome.developerPrivate.SelectType.FILE,
-          chrome.developerPrivate.FileType.PEM);
-    }
-
-    /** @override */
-    packExtension(rootPath, keyPath, flag, callback) {
-      chrome.developerPrivate.packDirectory(rootPath, keyPath, flag, callback);
-    }
-
-    /** @override */
-    updateAllExtensions() {
-      return new Promise((resolve) => {
-        chrome.developerPrivate.autoUpdate(resolve);
-        chrome.metricsPrivate.recordUserAction('Options_UpdateExtensions');
-      });
-    }
-
-    /** @override */
-    deleteErrors(extensionId, errorIds, type) {
-      chrome.developerPrivate.deleteExtensionErrors({
-        extensionId: extensionId,
-        errorIds: errorIds,
-        type: type,
-      });
-    }
-
-    /** @override */
-    requestFileSource(args) {
-      return new Promise(function(resolve, reject) {
-        chrome.developerPrivate.requestFileSource(args, resolve);
-      });
-    }
-
-    /** @override */
-    showInFolder(id) {
-      chrome.developerPrivate.showPath(id);
-    }
-
-    /** @override */
-    getExtensionActivityLog(extensionId) {
-      return new Promise(function(resolve, reject) {
-        chrome.activityLogPrivate.getExtensionActivities(
-            {
-              activityType: chrome.activityLogPrivate.ExtensionActivityFilter.ANY,
-              extensionId: extensionId
-            },
-            resolve);
-      });
-    }
-
-    /** @override */
-    getFilteredExtensionActivityLog(extensionId, searchTerm) {
-      const anyType = chrome.activityLogPrivate.ExtensionActivityFilter.ANY;
-
-      // Construct one filter for each API call we will make: one for substring
-      // search by api call, one for substring search by page URL, and one for
-      // substring search by argument URL. % acts as a wildcard.
-      const activityLogFilters = [
-        {
-          activityType: anyType,
-          extensionId: extensionId,
-          apiCall: `%${searchTerm}%`,
-        },
-        {
-          activityType: anyType,
-          extensionId: extensionId,
-          pageUrl: `%${searchTerm}%`,
-        },
-        {
-          activityType: anyType,
-          extensionId: extensionId,
-          argUrl: `%${searchTerm}%`
-        }
-      ];
-
-      const promises = activityLogFilters.map(
-          filter => new Promise(function(resolve, reject) {
-            chrome.activityLogPrivate.getExtensionActivities(filter, resolve);
-          }));
-
-      return Promise.all(promises).then(results => {
-        // We may have results that are present in one or more searches, so
-        // we merge them here. We also assume that every distinct activity
-        // id corresponds to exactly one activity.
-        const activitiesById = new Map();
-        for (const result of results) {
-          for (const activity of result.activities) {
-            activitiesById.set(activity.activityId, activity);
-          }
-        }
-
-        return {activities: Array.from(activitiesById.values())};
-      });
-    }
-
-    /** @override */
-    deleteActivitiesById(activityIds) {
-      return new Promise(function(resolve, reject) {
-        chrome.activityLogPrivate.deleteActivities(activityIds, resolve);
-      });
-    }
-
-    /** @override */
-    deleteActivitiesFromExtension(extensionId) {
-      return new Promise(function(resolve, reject) {
-        chrome.activityLogPrivate.deleteActivitiesByExtension(
-            extensionId, resolve);
-      });
-    }
-
-    /** @override */
-    getOnExtensionActivity() {
-      return chrome.activityLogPrivate.onExtensionActivity;
-    }
-
-    /** @override */
-    downloadActivities(rawActivityData, fileName) {
-      const blob = new Blob([rawActivityData], {type: 'application/json'});
-      const url = URL.createObjectURL(blob);
-      const a = document.createElement('a');
-      a.href = url;
-      a.download = fileName;
-      a.click();
-    }
-
-    /**
-     * Attempts to load an unpacked extension via a drag-n-drop gesture.
-     * @return {!Promise}
-     */
-    loadUnpackedFromDrag() {
-      return this.loadUnpackedHelper_({useDraggedPath: true});
-    }
-
-    installDroppedFile() {
-      chrome.developerPrivate.installDroppedFile();
-    }
-
-    notifyDragInstallInProgress() {
-      chrome.developerPrivate.notifyDragInstallInProgress();
-    }
   }
 
-  addSingletonGetter(Service);
+  /** @override */
+  setProfileInDevMode(inDevMode) {
+    chrome.developerPrivate.updateProfileConfiguration(
+        {inDeveloperMode: inDevMode});
+  }
+
+  /** @override */
+  loadUnpacked() {
+    return this.loadUnpackedHelper_();
+  }
+
+  /** @override */
+  retryLoadUnpacked(retryGuid) {
+    // Attempt to load an unpacked extension, optionally as another attempt at
+    // a previously-specified load.
+    return this.loadUnpackedHelper_({retryGuid: retryGuid});
+  }
+
+  /** @override */
+  choosePackRootDirectory() {
+    return this.chooseFilePath_(
+        chrome.developerPrivate.SelectType.FOLDER,
+        chrome.developerPrivate.FileType.LOAD);
+  }
+
+  /** @override */
+  choosePrivateKeyPath() {
+    return this.chooseFilePath_(
+        chrome.developerPrivate.SelectType.FILE,
+        chrome.developerPrivate.FileType.PEM);
+  }
+
+  /** @override */
+  packExtension(rootPath, keyPath, flag, callback) {
+    chrome.developerPrivate.packDirectory(rootPath, keyPath, flag, callback);
+  }
+
+  /** @override */
+  updateAllExtensions() {
+    return new Promise((resolve) => {
+      chrome.developerPrivate.autoUpdate(resolve);
+      chrome.metricsPrivate.recordUserAction('Options_UpdateExtensions');
+    });
+  }
+
+  /** @override */
+  deleteErrors(extensionId, errorIds, type) {
+    chrome.developerPrivate.deleteExtensionErrors({
+      extensionId: extensionId,
+      errorIds: errorIds,
+      type: type,
+    });
+  }
+
+  /** @override */
+  requestFileSource(args) {
+    return new Promise(function(resolve, reject) {
+      chrome.developerPrivate.requestFileSource(args, resolve);
+    });
+  }
+
+  /** @override */
+  showInFolder(id) {
+    chrome.developerPrivate.showPath(id);
+  }
+
+  /** @override */
+  getExtensionActivityLog(extensionId) {
+    return new Promise(function(resolve, reject) {
+      chrome.activityLogPrivate.getExtensionActivities(
+          {
+            activityType: chrome.activityLogPrivate.ExtensionActivityFilter.ANY,
+            extensionId: extensionId
+          },
+          resolve);
+    });
+  }
+
+  /** @override */
+  getFilteredExtensionActivityLog(extensionId, searchTerm) {
+    const anyType = chrome.activityLogPrivate.ExtensionActivityFilter.ANY;
+
+    // Construct one filter for each API call we will make: one for substring
+    // search by api call, one for substring search by page URL, and one for
+    // substring search by argument URL. % acts as a wildcard.
+    const activityLogFilters = [
+      {
+        activityType: anyType,
+        extensionId: extensionId,
+        apiCall: `%${searchTerm}%`,
+      },
+      {
+        activityType: anyType,
+        extensionId: extensionId,
+        pageUrl: `%${searchTerm}%`,
+      },
+      {
+        activityType: anyType,
+        extensionId: extensionId,
+        argUrl: `%${searchTerm}%`
+      }
+    ];
+
+    const promises = activityLogFilters.map(
+        filter => new Promise(function(resolve, reject) {
+          chrome.activityLogPrivate.getExtensionActivities(filter, resolve);
+        }));
+
+    return Promise.all(promises).then(results => {
+      // We may have results that are present in one or more searches, so
+      // we merge them here. We also assume that every distinct activity
+      // id corresponds to exactly one activity.
+      const activitiesById = new Map();
+      for (const result of results) {
+        for (const activity of result.activities) {
+          activitiesById.set(activity.activityId, activity);
+        }
+      }
+
+      return {activities: Array.from(activitiesById.values())};
+    });
+  }
+
+  /** @override */
+  deleteActivitiesById(activityIds) {
+    return new Promise(function(resolve, reject) {
+      chrome.activityLogPrivate.deleteActivities(activityIds, resolve);
+    });
+  }
+
+  /** @override */
+  deleteActivitiesFromExtension(extensionId) {
+    return new Promise(function(resolve, reject) {
+      chrome.activityLogPrivate.deleteActivitiesByExtension(
+          extensionId, resolve);
+    });
+  }
+
+  /** @override */
+  getOnExtensionActivity() {
+    return chrome.activityLogPrivate.onExtensionActivity;
+  }
+
+  /** @override */
+  downloadActivities(rawActivityData, fileName) {
+    const blob = new Blob([rawActivityData], {type: 'application/json'});
+    const url = URL.createObjectURL(blob);
+    const a = document.createElement('a');
+    a.href = url;
+    a.download = fileName;
+    a.click();
+  }
+
+  /**
+   * Attempts to load an unpacked extension via a drag-n-drop gesture.
+   * @return {!Promise}
+   */
+  loadUnpackedFromDrag() {
+    return this.loadUnpackedHelper_({useDraggedPath: true});
+  }
+
+  installDroppedFile() {
+    chrome.developerPrivate.installDroppedFile();
+  }
+
+  notifyDragInstallInProgress() {
+    chrome.developerPrivate.notifyDragInstallInProgress();
+  }
+}
+
+addSingletonGetter(Service);
diff --git a/chrome/browser/resources/extensions/shortcut_input.js b/chrome/browser/resources/extensions/shortcut_input.js
index 67a9261..eace4ad 100644
--- a/chrome/browser/resources/extensions/shortcut_input.js
+++ b/chrome/browser/resources/extensions/shortcut_input.js
@@ -22,223 +22,223 @@
   NEED_CHARACTER: 3,
 };
 
-  // The UI to display and manage keyboard shortcuts set for extension commands.
-  Polymer({
-    is: 'extensions-shortcut-input',
+// The UI to display and manage keyboard shortcuts set for extension commands.
+Polymer({
+  is: 'extensions-shortcut-input',
 
-    _template: html`{__html_template__}`,
+  _template: html`{__html_template__}`,
 
-    properties: {
-      /** @type {!KeyboardShortcutDelegate} */
-      delegate: Object,
+  properties: {
+    /** @type {!KeyboardShortcutDelegate} */
+    delegate: Object,
 
-      item: {
-        type: String,
-        value: '',
-      },
-
-      commandName: {
-        type: String,
-        value: '',
-      },
-
-      shortcut: {
-        type: String,
-        value: '',
-      },
-
-      /** @private */
-      capturing_: {
-        type: Boolean,
-        value: false,
-      },
-
-      /** @private {!ShortcutError} */
-      error_: {
-        type: Number,
-        value: 0,
-      },
-
-      /** @private */
-      pendingShortcut_: {
-        type: String,
-        value: '',
-      },
+    item: {
+      type: String,
+      value: '',
     },
 
-    /** @override */
-    ready: function() {
-      const node = this.$.input;
-      node.addEventListener('mouseup', this.startCapture_.bind(this));
-      node.addEventListener('blur', this.endCapture_.bind(this));
-      node.addEventListener('focus', this.startCapture_.bind(this));
-      node.addEventListener('keydown', this.onKeyDown_.bind(this));
-      node.addEventListener('keyup', this.onKeyUp_.bind(this));
+    commandName: {
+      type: String,
+      value: '',
+    },
+
+    shortcut: {
+      type: String,
+      value: '',
     },
 
     /** @private */
-    startCapture_: function() {
-      if (this.capturing_) {
-        return;
-      }
-      this.capturing_ = true;
-      this.delegate.setShortcutHandlingSuspended(true);
+    capturing_: {
+      type: Boolean,
+      value: false,
+    },
+
+    /** @private {!ShortcutError} */
+    error_: {
+      type: Number,
+      value: 0,
     },
 
     /** @private */
-    endCapture_: function() {
+    pendingShortcut_: {
+      type: String,
+      value: '',
+    },
+  },
+
+  /** @override */
+  ready: function() {
+    const node = this.$.input;
+    node.addEventListener('mouseup', this.startCapture_.bind(this));
+    node.addEventListener('blur', this.endCapture_.bind(this));
+    node.addEventListener('focus', this.startCapture_.bind(this));
+    node.addEventListener('keydown', this.onKeyDown_.bind(this));
+    node.addEventListener('keyup', this.onKeyUp_.bind(this));
+  },
+
+  /** @private */
+  startCapture_: function() {
+    if (this.capturing_) {
+      return;
+    }
+    this.capturing_ = true;
+    this.delegate.setShortcutHandlingSuspended(true);
+  },
+
+  /** @private */
+  endCapture_: function() {
+    if (!this.capturing_) {
+      return;
+    }
+    this.pendingShortcut_ = '';
+    this.capturing_ = false;
+    const input = this.$.input;
+    input.blur();
+    input.invalid = false;
+    this.delegate.setShortcutHandlingSuspended(false);
+  },
+
+  /**
+   * @param {!Event} e
+   * @private
+   */
+  onKeyDown_: function(e) {
+    if (e.target == this.$.clear) {
+      return;
+    }
+
+    if (e.keyCode == Key.Escape) {
       if (!this.capturing_) {
+        // If we're not currently capturing, allow escape to propagate.
         return;
       }
-      this.pendingShortcut_ = '';
-      this.capturing_ = false;
-      const input = this.$.input;
-      input.blur();
-      input.invalid = false;
-      this.delegate.setShortcutHandlingSuspended(false);
-    },
-
-    /**
-     * @param {!Event} e
-     * @private
-     */
-    onKeyDown_: function(e) {
-      if (e.target == this.$.clear) {
-        return;
-      }
-
-      if (e.keyCode == Key.Escape) {
-        if (!this.capturing_) {
-          // If we're not currently capturing, allow escape to propagate.
-          return;
-        }
-        // Otherwise, escape cancels capturing.
-        this.endCapture_();
-        e.preventDefault();
-        e.stopPropagation();
-        return;
-      }
-      if (e.keyCode == Key.Tab) {
-        // Allow tab propagation for keyboard navigation.
-        return;
-      }
-
-      if (!this.capturing_) {
-        this.startCapture_();
-      }
-
-      this.handleKey_(/** @type {!KeyboardEvent} */ (e));
-    },
-
-    /**
-     * @param {!Event} e
-     * @private
-     */
-    onKeyUp_: function(e) {
-      // Ignores pressing 'Space' or 'Enter' on the clear button. In 'Enter's
-      // case, the clear button disappears before key-up, so 'Enter's key-up
-      // target becomes the input field, not the clear button, and needs to
-      // be caught explicitly.
-      if (e.target == this.$.clear || e.key == 'Enter') {
-        return;
-      }
-
-      if (e.keyCode == Key.Escape || e.keyCode == Key.Tab) {
-        return;
-      }
-
-      this.handleKey_(/** @type {!KeyboardEvent} */ (e));
-    },
-
-    /**
-     * @param {!ShortcutError} error
-     * @param {string} includeStartModifier
-     * @param {string} tooManyModifiers
-     * @param {string} needCharacter
-     * @return {string} UI string.
-     * @private
-     */
-    getErrorString_: function(
-        error, includeStartModifier, tooManyModifiers, needCharacter) {
-      if (error == ShortcutError.TOO_MANY_MODIFIERS) {
-        return tooManyModifiers;
-      }
-      if (error == ShortcutError.NEED_CHARACTER) {
-        return needCharacter;
-      }
-      return includeStartModifier;
-    },
-
-    /**
-     * @param {!KeyboardEvent} e
-     * @private
-     */
-    handleKey_: function(e) {
-      // While capturing, we prevent all events from bubbling, to prevent
-      // shortcuts lacking the right modifier (F3 for example) from activating
-      // and ending capture prematurely.
+      // Otherwise, escape cancels capturing.
+      this.endCapture_();
       e.preventDefault();
       e.stopPropagation();
+      return;
+    }
+    if (e.keyCode == Key.Tab) {
+      // Allow tab propagation for keyboard navigation.
+      return;
+    }
 
-      // We don't allow both Ctrl and Alt in the same keybinding.
-      // TODO(devlin): This really should go in hasValidModifiers,
-      // but that requires updating the existing page as well.
-      if (e.ctrlKey && e.altKey) {
-        this.error_ = ShortcutError.TOO_MANY_MODIFIERS;
-        this.$.input.invalid = true;
-        return;
-      }
-      if (!hasValidModifiers(e)) {
-        this.pendingShortcut_ = '';
-        this.error_ = ShortcutError.INCLUDE_START_MODIFIER;
-        this.$.input.invalid = true;
-        return;
-      }
-      this.pendingShortcut_ = keystrokeToString(e);
-      if (!isValidKeyCode(e.keyCode)) {
-        this.error_ = ShortcutError.NEED_CHARACTER;
-        this.$.input.invalid = true;
-        return;
-      }
-      this.$.input.invalid = false;
+    if (!this.capturing_) {
+      this.startCapture_();
+    }
 
-      this.commitPending_();
-      this.endCapture_();
-    },
+    this.handleKey_(/** @type {!KeyboardEvent} */ (e));
+  },
 
-    /** @private */
-    commitPending_: function() {
-      this.shortcut = this.pendingShortcut_;
-      this.delegate.updateExtensionCommandKeybinding(
-          this.item, this.commandName, this.shortcut);
-    },
+  /**
+   * @param {!Event} e
+   * @private
+   */
+  onKeyUp_: function(e) {
+    // Ignores pressing 'Space' or 'Enter' on the clear button. In 'Enter's
+    // case, the clear button disappears before key-up, so 'Enter's key-up
+    // target becomes the input field, not the clear button, and needs to
+    // be caught explicitly.
+    if (e.target == this.$.clear || e.key == 'Enter') {
+      return;
+    }
 
-    /**
-     * @return {string} The text to be displayed in the shortcut field.
-     * @private
-     */
-    computeText_: function() {
-      const shortcutString =
-          this.capturing_ ? this.pendingShortcut_ : this.shortcut;
-      return shortcutString.split('+').join(' + ');
-    },
+    if (e.keyCode == Key.Escape || e.keyCode == Key.Tab) {
+      return;
+    }
 
-    /**
-     * @return {boolean} Whether the clear button is hidden.
-     * @private
-     */
-    computeClearHidden_: function() {
-      // We don't want to show the clear button if the input is currently
-      // capturing a new shortcut or if there is no shortcut to clear.
-      return this.capturing_ || !this.shortcut;
-    },
+    this.handleKey_(/** @type {!KeyboardEvent} */ (e));
+  },
 
-    /** @private */
-    onClearTap_: function() {
-      assert(this.shortcut);
+  /**
+   * @param {!ShortcutError} error
+   * @param {string} includeStartModifier
+   * @param {string} tooManyModifiers
+   * @param {string} needCharacter
+   * @return {string} UI string.
+   * @private
+   */
+  getErrorString_: function(
+      error, includeStartModifier, tooManyModifiers, needCharacter) {
+    if (error == ShortcutError.TOO_MANY_MODIFIERS) {
+      return tooManyModifiers;
+    }
+    if (error == ShortcutError.NEED_CHARACTER) {
+      return needCharacter;
+    }
+    return includeStartModifier;
+  },
 
+  /**
+   * @param {!KeyboardEvent} e
+   * @private
+   */
+  handleKey_: function(e) {
+    // While capturing, we prevent all events from bubbling, to prevent
+    // shortcuts lacking the right modifier (F3 for example) from activating
+    // and ending capture prematurely.
+    e.preventDefault();
+    e.stopPropagation();
+
+    // We don't allow both Ctrl and Alt in the same keybinding.
+    // TODO(devlin): This really should go in hasValidModifiers,
+    // but that requires updating the existing page as well.
+    if (e.ctrlKey && e.altKey) {
+      this.error_ = ShortcutError.TOO_MANY_MODIFIERS;
+      this.$.input.invalid = true;
+      return;
+    }
+    if (!hasValidModifiers(e)) {
       this.pendingShortcut_ = '';
-      this.commitPending_();
-      this.endCapture_();
-    },
-  });
+      this.error_ = ShortcutError.INCLUDE_START_MODIFIER;
+      this.$.input.invalid = true;
+      return;
+    }
+    this.pendingShortcut_ = keystrokeToString(e);
+    if (!isValidKeyCode(e.keyCode)) {
+      this.error_ = ShortcutError.NEED_CHARACTER;
+      this.$.input.invalid = true;
+      return;
+    }
+    this.$.input.invalid = false;
+
+    this.commitPending_();
+    this.endCapture_();
+  },
+
+  /** @private */
+  commitPending_: function() {
+    this.shortcut = this.pendingShortcut_;
+    this.delegate.updateExtensionCommandKeybinding(
+        this.item, this.commandName, this.shortcut);
+  },
+
+  /**
+   * @return {string} The text to be displayed in the shortcut field.
+   * @private
+   */
+  computeText_: function() {
+    const shortcutString =
+        this.capturing_ ? this.pendingShortcut_ : this.shortcut;
+    return shortcutString.split('+').join(' + ');
+  },
+
+  /**
+   * @return {boolean} Whether the clear button is hidden.
+   * @private
+   */
+  computeClearHidden_: function() {
+    // We don't want to show the clear button if the input is currently
+    // capturing a new shortcut or if there is no shortcut to clear.
+    return this.capturing_ || !this.shortcut;
+  },
+
+  /** @private */
+  onClearTap_: function() {
+    assert(this.shortcut);
+
+    this.pendingShortcut_ = '';
+    this.commitPending_();
+    this.endCapture_();
+  },
+});
diff --git a/chrome/browser/resources/extensions/shortcut_util.js b/chrome/browser/resources/extensions/shortcut_util.js
index ed09384f..0f61a402 100644
--- a/chrome/browser/resources/extensions/shortcut_util.js
+++ b/chrome/browser/resources/extensions/shortcut_util.js
@@ -6,191 +6,194 @@
 import {isChromeOS, isMac} from 'chrome://resources/js/cr.m.js';
 
 
-  /** @enum {number} */
-  export const Key = {
-    Comma: 188,
-    Del: 46,
-    Down: 40,
-    End: 35,
-    Escape: 27,
-    Home: 36,
-    Ins: 45,
-    Left: 37,
-    MediaNextTrack: 176,
-    MediaPlayPause: 179,
-    MediaPrevTrack: 177,
-    MediaStop: 178,
-    PageDown: 34,
-    PageUp: 33,
-    Period: 190,
-    Right: 39,
-    Space: 32,
-    Tab: 9,
-    Up: 38,
-  };
+/** @enum {number} */
+export const Key = {
+  Comma: 188,
+  Del: 46,
+  Down: 40,
+  End: 35,
+  Escape: 27,
+  Home: 36,
+  Ins: 45,
+  Left: 37,
+  MediaNextTrack: 176,
+  MediaPlayPause: 179,
+  MediaPrevTrack: 177,
+  MediaStop: 178,
+  PageDown: 34,
+  PageUp: 33,
+  Period: 190,
+  Right: 39,
+  Space: 32,
+  Tab: 9,
+  Up: 38,
+};
 
-  /**
-   * Enum for whether we require modifiers of a keycode.
-   * @enum {number}
-   */
-  const ModifierPolicy = {NOT_ALLOWED: 0, REQUIRED: 1};
+/**
+ * Enum for whether we require modifiers of a keycode.
+ * @enum {number}
+ */
+const ModifierPolicy = {
+  NOT_ALLOWED: 0,
+  REQUIRED: 1
+};
 
-  /**
-   * Gets the ModifierPolicy. Currently only "MediaNextTrack", "MediaPrevTrack",
-   * "MediaStop", "MediaPlayPause" are required to be used without any modifier.
-   * @param {number} keyCode
-   * @return {ModifierPolicy}
-   */
-  function getModifierPolicy(keyCode) {
-    switch (keyCode) {
-      case Key.MediaNextTrack:
-      case Key.MediaPlayPause:
-      case Key.MediaPrevTrack:
-      case Key.MediaStop:
-        return ModifierPolicy.NOT_ALLOWED;
-      default:
-        return ModifierPolicy.REQUIRED;
+/**
+ * Gets the ModifierPolicy. Currently only "MediaNextTrack", "MediaPrevTrack",
+ * "MediaStop", "MediaPlayPause" are required to be used without any modifier.
+ * @param {number} keyCode
+ * @return {ModifierPolicy}
+ */
+function getModifierPolicy(keyCode) {
+  switch (keyCode) {
+    case Key.MediaNextTrack:
+    case Key.MediaPlayPause:
+    case Key.MediaPrevTrack:
+    case Key.MediaStop:
+      return ModifierPolicy.NOT_ALLOWED;
+    default:
+      return ModifierPolicy.REQUIRED;
+  }
+}
+
+/**
+ * Returns whether the keyboard event has a key modifier, which could affect
+ * how it's handled.
+ * @param {!KeyboardEvent} e
+ * @param {boolean} countShiftAsModifier Whether the 'Shift' key should be
+ *     counted as modifier.
+ * @return {boolean} True if the event has any modifiers.
+ */
+function hasModifier(e, countShiftAsModifier) {
+  return e.ctrlKey || e.altKey ||
+      // Meta key is only relevant on Mac and CrOS, where we treat Command
+      // and Search (respectively) as modifiers.
+      (isMac && e.metaKey) || (isChromeOS && e.metaKey) ||
+      (countShiftAsModifier && e.shiftKey);
+}
+
+/**
+ * Checks whether the passed in |keyCode| is a valid extension command key.
+ * @param {number} keyCode
+ * @return {boolean} Whether the key is valid.
+ */
+export function isValidKeyCode(keyCode) {
+  if (keyCode == Key.Escape) {
+    return false;
+  }
+  for (const k in Key) {
+    if (Key[k] == keyCode) {
+      return true;
     }
   }
+  return (keyCode >= 'A'.charCodeAt(0) && keyCode <= 'Z'.charCodeAt(0)) ||
+      (keyCode >= '0'.charCodeAt(0) && keyCode <= '9'.charCodeAt(0));
+}
 
-  /**
-   * Returns whether the keyboard event has a key modifier, which could affect
-   * how it's handled.
-   * @param {!KeyboardEvent} e
-   * @param {boolean} countShiftAsModifier Whether the 'Shift' key should be
-   *     counted as modifier.
-   * @return {boolean} True if the event has any modifiers.
-   */
-  function hasModifier(e, countShiftAsModifier) {
-    return e.ctrlKey || e.altKey ||
-        // Meta key is only relevant on Mac and CrOS, where we treat Command
-        // and Search (respectively) as modifiers.
-        (isMac && e.metaKey) || (isChromeOS && e.metaKey) ||
-        (countShiftAsModifier && e.shiftKey);
+/**
+ * Converts a keystroke event to string form, ignoring invalid extension
+ * commands.
+ * @param {!KeyboardEvent} e
+ * @return {string} The keystroke as a string.
+ */
+export function keystrokeToString(e) {
+  const output = [];
+  // TODO(devlin): Should this be i18n'd?
+  if (isMac && e.metaKey) {
+    output.push('Command');
+  }
+  if (isChromeOS && e.metaKey) {
+    output.push('Search');
+  }
+  if (e.ctrlKey) {
+    output.push('Ctrl');
+  }
+  if (!e.ctrlKey && e.altKey) {
+    output.push('Alt');
+  }
+  if (e.shiftKey) {
+    output.push('Shift');
   }
 
-  /**
-   * Checks whether the passed in |keyCode| is a valid extension command key.
-   * @param {number} keyCode
-   * @return {boolean} Whether the key is valid.
-   */
-  export function isValidKeyCode(keyCode) {
-    if (keyCode == Key.Escape) {
-      return false;
-    }
-    for (const k in Key) {
-      if (Key[k] == keyCode) {
-        return true;
+  const keyCode = e.keyCode;
+  if (isValidKeyCode(keyCode)) {
+    if ((keyCode >= 'A'.charCodeAt(0) && keyCode <= 'Z'.charCodeAt(0)) ||
+        (keyCode >= '0'.charCodeAt(0) && keyCode <= '9'.charCodeAt(0))) {
+      output.push(String.fromCharCode(keyCode));
+    } else {
+      switch (keyCode) {
+        case Key.Comma:
+          output.push('Comma');
+          break;
+        case Key.Del:
+          output.push('Delete');
+          break;
+        case Key.Down:
+          output.push('Down');
+          break;
+        case Key.End:
+          output.push('End');
+          break;
+        case Key.Home:
+          output.push('Home');
+          break;
+        case Key.Ins:
+          output.push('Insert');
+          break;
+        case Key.Left:
+          output.push('Left');
+          break;
+        case Key.MediaNextTrack:
+          output.push('MediaNextTrack');
+          break;
+        case Key.MediaPlayPause:
+          output.push('MediaPlayPause');
+          break;
+        case Key.MediaPrevTrack:
+          output.push('MediaPrevTrack');
+          break;
+        case Key.MediaStop:
+          output.push('MediaStop');
+          break;
+        case Key.PageDown:
+          output.push('PageDown');
+          break;
+        case Key.PageUp:
+          output.push('PageUp');
+          break;
+        case Key.Period:
+          output.push('Period');
+          break;
+        case Key.Right:
+          output.push('Right');
+          break;
+        case Key.Space:
+          output.push('Space');
+          break;
+        case Key.Tab:
+          output.push('Tab');
+          break;
+        case Key.Up:
+          output.push('Up');
+          break;
       }
     }
-    return (keyCode >= 'A'.charCodeAt(0) && keyCode <= 'Z'.charCodeAt(0)) ||
-        (keyCode >= '0'.charCodeAt(0) && keyCode <= '9'.charCodeAt(0));
   }
 
-  /**
-   * Converts a keystroke event to string form, ignoring invalid extension
-   * commands.
-   * @param {!KeyboardEvent} e
-   * @return {string} The keystroke as a string.
-   */
-  export function keystrokeToString(e) {
-    const output = [];
-    // TODO(devlin): Should this be i18n'd?
-    if (isMac && e.metaKey) {
-      output.push('Command');
-    }
-    if (isChromeOS && e.metaKey) {
-      output.push('Search');
-    }
-    if (e.ctrlKey) {
-      output.push('Ctrl');
-    }
-    if (!e.ctrlKey && e.altKey) {
-      output.push('Alt');
-    }
-    if (e.shiftKey) {
-      output.push('Shift');
-    }
+  return output.join('+');
+}
 
-    const keyCode = e.keyCode;
-    if (isValidKeyCode(keyCode)) {
-      if ((keyCode >= 'A'.charCodeAt(0) && keyCode <= 'Z'.charCodeAt(0)) ||
-          (keyCode >= '0'.charCodeAt(0) && keyCode <= '9'.charCodeAt(0))) {
-        output.push(String.fromCharCode(keyCode));
-      } else {
-        switch (keyCode) {
-          case Key.Comma:
-            output.push('Comma');
-            break;
-          case Key.Del:
-            output.push('Delete');
-            break;
-          case Key.Down:
-            output.push('Down');
-            break;
-          case Key.End:
-            output.push('End');
-            break;
-          case Key.Home:
-            output.push('Home');
-            break;
-          case Key.Ins:
-            output.push('Insert');
-            break;
-          case Key.Left:
-            output.push('Left');
-            break;
-          case Key.MediaNextTrack:
-            output.push('MediaNextTrack');
-            break;
-          case Key.MediaPlayPause:
-            output.push('MediaPlayPause');
-            break;
-          case Key.MediaPrevTrack:
-            output.push('MediaPrevTrack');
-            break;
-          case Key.MediaStop:
-            output.push('MediaStop');
-            break;
-          case Key.PageDown:
-            output.push('PageDown');
-            break;
-          case Key.PageUp:
-            output.push('PageUp');
-            break;
-          case Key.Period:
-            output.push('Period');
-            break;
-          case Key.Right:
-            output.push('Right');
-            break;
-          case Key.Space:
-            output.push('Space');
-            break;
-          case Key.Tab:
-            output.push('Tab');
-            break;
-          case Key.Up:
-            output.push('Up');
-            break;
-        }
-      }
-    }
-
-    return output.join('+');
+/**
+ * Returns true if the event has valid modifiers.
+ * @param {!KeyboardEvent} e The keyboard event to consider.
+ * @return {boolean} True if the event is valid.
+ */
+export function hasValidModifiers(e) {
+  switch (getModifierPolicy(e.keyCode)) {
+    case ModifierPolicy.REQUIRED:
+      return hasModifier(e, false);
+    case ModifierPolicy.NOT_ALLOWED:
+      return !hasModifier(e, true);
   }
-
-  /**
-   * Returns true if the event has valid modifiers.
-   * @param {!KeyboardEvent} e The keyboard event to consider.
-   * @return {boolean} True if the event is valid.
-   */
-  export function hasValidModifiers(e) {
-    switch (getModifierPolicy(e.keyCode)) {
-      case ModifierPolicy.REQUIRED:
-        return hasModifier(e, false);
-      case ModifierPolicy.NOT_ALLOWED:
-        return !hasModifier(e, true);
-    }
-    assertNotReached();
-  }
+  assertNotReached();
+}
diff --git a/chrome/browser/resources/extensions/sidebar.js b/chrome/browser/resources/extensions/sidebar.js
index 4fc5a75e..5252323 100644
--- a/chrome/browser/resources/extensions/sidebar.js
+++ b/chrome/browser/resources/extensions/sidebar.js
@@ -11,38 +11,38 @@
 
 import {navigation, Page} from './navigation_helper.js';
 
-  Polymer({
-    is: 'extensions-sidebar',
+Polymer({
+  is: 'extensions-sidebar',
 
-    _template: html`{__html_template__}`,
+  _template: html`{__html_template__}`,
 
-    properties: {
-      isSupervised: Boolean,
-    },
+  properties: {
+    isSupervised: Boolean,
+  },
 
-    hostAttributes: {
-      role: 'navigation',
-    },
+  hostAttributes: {
+    role: 'navigation',
+  },
 
-    /** @override */
-    attached: function() {
-      this.$.sectionMenu.select(
-          navigation.getCurrentPage().page == Page.SHORTCUTS ? 1 : 0);
-    },
+  /** @override */
+  attached: function() {
+    this.$.sectionMenu.select(
+        navigation.getCurrentPage().page == Page.SHORTCUTS ? 1 : 0);
+  },
 
-    /**
-     * @param {!Event} e
-     * @private
-     */
-    onLinkTap_: function(e) {
-      e.preventDefault();
-      navigation.navigateTo({page: e.target.dataset.path});
-      this.fire('close-drawer');
-    },
+  /**
+   * @param {!Event} e
+   * @private
+   */
+  onLinkTap_: function(e) {
+    e.preventDefault();
+    navigation.navigateTo({page: e.target.dataset.path});
+    this.fire('close-drawer');
+  },
 
-    /** @private */
-    onMoreExtensionsTap_: function() {
-      assert(!this.isSupervised);
-      chrome.metricsPrivate.recordUserAction('Options_GetMoreExtensions');
-    },
-  });
+  /** @private */
+  onMoreExtensionsTap_: function() {
+    assert(!this.isSupervised);
+    chrome.metricsPrivate.recordUserAction('Options_GetMoreExtensions');
+  },
+});
diff --git a/chrome/browser/resources/extensions/toggle_row.js b/chrome/browser/resources/extensions/toggle_row.js
index 9a49b1b..43be17b5 100644
--- a/chrome/browser/resources/extensions/toggle_row.js
+++ b/chrome/browser/resources/extensions/toggle_row.js
@@ -8,69 +8,69 @@
 import {html, Polymer} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
 
 
+/**
+ * An extensions-toggle-row provides a way of having a clickable row that can
+ * modify a cr-toggle, by leveraging the native <label> functionality. It uses
+ * a hidden native <input type="checkbox"> to achieve this.
+ */
+Polymer({
+  is: 'extensions-toggle-row',
+
+  _template: html`{__html_template__}`,
+
+  properties: {
+    checked: Boolean,
+
+    disabled: Boolean,
+  },
+
   /**
-   * An extensions-toggle-row provides a way of having a clickable row that can
-   * modify a cr-toggle, by leveraging the native <label> functionality. It uses
-   * a hidden native <input type="checkbox"> to achieve this.
+   * Exposing the clickable part of extensions-toggle-row for testing
+   * purposes.
+   * @return {!HTMLElement}
    */
-  Polymer({
-    is: 'extensions-toggle-row',
+  getLabel() {
+    return /** @type {!HTMLElement} */ (this.$.label);
+  },
 
-    _template: html`{__html_template__}`,
+  /**
+   * @param {!Event} e
+   * @private
+   */
+  onNativeClick_: function(e) {
+    // Even though the native checkbox is hidden and can't be actually
+    // cilcked/tapped by the user, because it resides within the <label> the
+    // browser emits an extraneous event when the label is clicked. Stop
+    // propagation so that it does not interfere with |onLabelTap_| listener.
+    e.stopPropagation();
+  },
 
-    properties: {
-      checked: Boolean,
+  /**
+   * Fires when the native checkbox changes value. This happens when the user
+   * clicks directly on the <label>.
+   * @param {!Event} e
+   * @private
+   */
+  onNativeChange_: function(e) {
+    e.stopPropagation();
 
-      disabled: Boolean,
-    },
+    // Sync value of native checkbox and cr-toggle and |checked|.
+    this.$.crToggle.checked = this.$.native.checked;
+    this.checked = this.$.native.checked;
 
-    /**
-     * Exposing the clickable part of extensions-toggle-row for testing
-     * purposes.
-     * @return {!HTMLElement}
-     */
-    getLabel() {
-      return /** @type {!HTMLElement} */ (this.$.label);
-    },
+    this.fire('change', this.checked);
+  },
 
-    /**
-     * @param {!Event} e
-     * @private
-     */
-    onNativeClick_: function(e) {
-      // Even though the native checkbox is hidden and can't be actually
-      // cilcked/tapped by the user, because it resides within the <label> the
-      // browser emits an extraneous event when the label is clicked. Stop
-      // propagation so that it does not interfere with |onLabelTap_| listener.
-      e.stopPropagation();
-    },
+  /**
+   * @param {!CustomEvent<boolean>} e
+   * @private
+   */
+  onCrToggleChange_: function(e) {
+    e.stopPropagation();
 
-    /**
-     * Fires when the native checkbox changes value. This happens when the user
-     * clicks directly on the <label>.
-     * @param {!Event} e
-     * @private
-     */
-    onNativeChange_: function(e) {
-      e.stopPropagation();
+    // Sync value of native checkbox and cr-toggle.
+    this.$.native.checked = e.detail;
 
-      // Sync value of native checkbox and cr-toggle and |checked|.
-      this.$.crToggle.checked = this.$.native.checked;
-      this.checked = this.$.native.checked;
-
-      this.fire('change', this.checked);
-    },
-
-    /**
-     * @param {!CustomEvent<boolean>} e
-     * @private
-     */
-    onCrToggleChange_: function(e) {
-      e.stopPropagation();
-
-      // Sync value of native checkbox and cr-toggle.
-      this.$.native.checked = e.detail;
-
-      this.fire('change', this.checked);
-    },
-  });
+    this.fire('change', this.checked);
+  },
+});
diff --git a/chrome/browser/resources/extensions/toolbar.js b/chrome/browser/resources/extensions/toolbar.js
index ea79ff8..8615d4b 100644
--- a/chrome/browser/resources/extensions/toolbar.js
+++ b/chrome/browser/resources/extensions/toolbar.js
@@ -17,187 +17,187 @@
 import {IronA11yAnnouncer} from 'chrome://resources/polymer/v3_0/iron-a11y-announcer/iron-a11y-announcer.js';
 import {html, Polymer} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
 
-  /** @interface */
-  export class ToolbarDelegate {
-    /**
-     * Toggles whether or not the profile is in developer mode.
-     * @param {boolean} inDevMode
-     */
-    setProfileInDevMode(inDevMode) {}
+/** @interface */
+export class ToolbarDelegate {
+  /**
+   * Toggles whether or not the profile is in developer mode.
+   * @param {boolean} inDevMode
+   */
+  setProfileInDevMode(inDevMode) {}
 
-    /**
-     * Opens the dialog to load unpacked extensions.
-     * @return {!Promise}
-     */
-    loadUnpacked() {}
+  /**
+   * Opens the dialog to load unpacked extensions.
+   * @return {!Promise}
+   */
+  loadUnpacked() {}
 
-    /**
-     * Updates all extensions.
-     * @return {!Promise}
-     */
-    updateAllExtensions() {}
-  }
+  /**
+   * Updates all extensions.
+   * @return {!Promise}
+   */
+  updateAllExtensions() {}
+}
 
-  Polymer({
-    is: 'extensions-toolbar',
+Polymer({
+  is: 'extensions-toolbar',
 
-    _template: html`{__html_template__}`,
+  _template: html`{__html_template__}`,
 
-    properties: {
-      /** @type {ToolbarDelegate} */
-      delegate: Object,
+  properties: {
+    /** @type {ToolbarDelegate} */
+    delegate: Object,
 
-      inDevMode: {
-        type: Boolean,
-        value: false,
-        observer: 'onInDevModeChanged_',
-        reflectToAttribute: true,
-      },
-
-      devModeControlledByPolicy: Boolean,
-
-      isSupervised: Boolean,
-
-      // <if expr="chromeos">
-      kioskEnabled: Boolean,
-      // </if>
-
-      canLoadUnpacked: Boolean,
-
-      /** @private */
-      expanded_: Boolean,
-
-      /** @private */
-      showPackDialog_: Boolean,
-
-      /**
-       * Prevents initiating update while update is in progress.
-       * @private
-       */
-      isUpdating_: {type: Boolean, value: false}
+    inDevMode: {
+      type: Boolean,
+      value: false,
+      observer: 'onInDevModeChanged_',
+      reflectToAttribute: true,
     },
 
-    behaviors: [I18nBehavior],
+    devModeControlledByPolicy: Boolean,
 
-    hostAttributes: {
-      role: 'banner',
-    },
-
-    /**
-     * @return {boolean}
-     * @private
-     */
-    shouldDisableDevMode_: function() {
-      return this.devModeControlledByPolicy || this.isSupervised;
-    },
-
-    /**
-     * @return {string}
-     * @private
-     */
-    getTooltipText_: function() {
-      return this.i18n(
-          this.isSupervised ? 'controlledSettingChildRestriction' :
-                              'controlledSettingPolicy');
-    },
-
-    /**
-     * @return {string}
-     * @private
-     */
-    getIcon_: function() {
-      return this.isSupervised ? 'cr20:kite' : 'cr20:domain';
-    },
-
-    /**
-     * @param {!CustomEvent<boolean>} e
-     * @private
-     */
-    onDevModeToggleChange_: function(e) {
-      this.delegate.setProfileInDevMode(e.detail);
-      chrome.metricsPrivate.recordUserAction(
-          'Options_ToggleDeveloperMode_' + (e.detail ? 'Enabled' : 'Disabled'));
-    },
-
-    /**
-     * @param {boolean} current
-     * @param {boolean} previous
-     * @private
-     */
-    onInDevModeChanged_: function(current, previous) {
-      const drawer = this.$.devDrawer;
-      if (this.inDevMode) {
-        if (drawer.hidden) {
-          drawer.hidden = false;
-          // Requesting the offsetTop will cause a reflow (to account for
-          // hidden).
-          /** @suppress {suspiciousCode} */ drawer.offsetTop;
-        }
-      } else {
-        if (previous == undefined) {
-          drawer.hidden = true;
-          return;
-        }
-
-        listenOnce(drawer, 'transitionend', e => {
-          if (!this.inDevMode) {
-            drawer.hidden = true;
-          }
-        });
-      }
-      this.expanded_ = !this.expanded_;
-    },
-
-    /** @private */
-    onLoadUnpackedTap_: function() {
-      this.delegate.loadUnpacked().catch(loadError => {
-        this.fire('load-error', loadError);
-      });
-      chrome.metricsPrivate.recordUserAction('Options_LoadUnpackedExtension');
-    },
-
-    /** @private */
-    onPackTap_: function() {
-      chrome.metricsPrivate.recordUserAction('Options_PackExtension');
-      this.showPackDialog_ = true;
-    },
-
-    /** @private */
-    onPackDialogClose_: function() {
-      this.showPackDialog_ = false;
-      this.$.packExtensions.focus();
-    },
+    isSupervised: Boolean,
 
     // <if expr="chromeos">
-    /** @private */
-    onKioskTap_: function() {
-      this.fire('kiosk-tap');
-    },
+    kioskEnabled: Boolean,
     // </if>
 
+    canLoadUnpacked: Boolean,
+
     /** @private */
-    onUpdateNowTap_: function() {
-      // If already updating, do not initiate another update.
-      if (this.isUpdating_) {
+    expanded_: Boolean,
+
+    /** @private */
+    showPackDialog_: Boolean,
+
+    /**
+     * Prevents initiating update while update is in progress.
+     * @private
+     */
+    isUpdating_: {type: Boolean, value: false}
+  },
+
+  behaviors: [I18nBehavior],
+
+  hostAttributes: {
+    role: 'banner',
+  },
+
+  /**
+   * @return {boolean}
+   * @private
+   */
+  shouldDisableDevMode_: function() {
+    return this.devModeControlledByPolicy || this.isSupervised;
+  },
+
+  /**
+   * @return {string}
+   * @private
+   */
+  getTooltipText_: function() {
+    return this.i18n(
+        this.isSupervised ? 'controlledSettingChildRestriction' :
+                            'controlledSettingPolicy');
+  },
+
+  /**
+   * @return {string}
+   * @private
+   */
+  getIcon_: function() {
+    return this.isSupervised ? 'cr20:kite' : 'cr20:domain';
+  },
+
+  /**
+   * @param {!CustomEvent<boolean>} e
+   * @private
+   */
+  onDevModeToggleChange_: function(e) {
+    this.delegate.setProfileInDevMode(e.detail);
+    chrome.metricsPrivate.recordUserAction(
+        'Options_ToggleDeveloperMode_' + (e.detail ? 'Enabled' : 'Disabled'));
+  },
+
+  /**
+   * @param {boolean} current
+   * @param {boolean} previous
+   * @private
+   */
+  onInDevModeChanged_: function(current, previous) {
+    const drawer = this.$.devDrawer;
+    if (this.inDevMode) {
+      if (drawer.hidden) {
+        drawer.hidden = false;
+        // Requesting the offsetTop will cause a reflow (to account for
+        // hidden).
+        /** @suppress {suspiciousCode} */ drawer.offsetTop;
+      }
+    } else {
+      if (previous == undefined) {
+        drawer.hidden = true;
         return;
       }
 
-      this.isUpdating_ = true;
+      listenOnce(drawer, 'transitionend', e => {
+        if (!this.inDevMode) {
+          drawer.hidden = true;
+        }
+      });
+    }
+    this.expanded_ = !this.expanded_;
+  },
 
-      const toastManager = getInstance();
-      // Keep the toast open indefinitely.
-      toastManager.duration = 0;
-      toastManager.show(this.i18n('toolbarUpdatingToast'), false);
-      this.delegate.updateAllExtensions().then(
-          () => {
-            toastManager.hide();
-            toastManager.duration = 3000;
-            toastManager.show(this.i18n('toolbarUpdateDone'), false);
-            this.isUpdating_ = false;
-          },
-          () => {
-            toastManager.hide();
-            this.isUpdating_ = false;
-          });
-    },
-  });
+  /** @private */
+  onLoadUnpackedTap_: function() {
+    this.delegate.loadUnpacked().catch(loadError => {
+      this.fire('load-error', loadError);
+    });
+    chrome.metricsPrivate.recordUserAction('Options_LoadUnpackedExtension');
+  },
+
+  /** @private */
+  onPackTap_: function() {
+    chrome.metricsPrivate.recordUserAction('Options_PackExtension');
+    this.showPackDialog_ = true;
+  },
+
+  /** @private */
+  onPackDialogClose_: function() {
+    this.showPackDialog_ = false;
+    this.$.packExtensions.focus();
+  },
+
+  // <if expr="chromeos">
+  /** @private */
+  onKioskTap_: function() {
+    this.fire('kiosk-tap');
+  },
+  // </if>
+
+  /** @private */
+  onUpdateNowTap_: function() {
+    // If already updating, do not initiate another update.
+    if (this.isUpdating_) {
+      return;
+    }
+
+    this.isUpdating_ = true;
+
+    const toastManager = getInstance();
+    // Keep the toast open indefinitely.
+    toastManager.duration = 0;
+    toastManager.show(this.i18n('toolbarUpdatingToast'), false);
+    this.delegate.updateAllExtensions().then(
+        () => {
+          toastManager.hide();
+          toastManager.duration = 3000;
+          toastManager.show(this.i18n('toolbarUpdateDone'), false);
+          this.isUpdating_ = false;
+        },
+        () => {
+          toastManager.hide();
+          this.isUpdating_ = false;
+        });
+  },
+});
diff --git a/chrome/browser/signin/chrome_signin_proxying_url_loader_factory.cc b/chrome/browser/signin/chrome_signin_proxying_url_loader_factory.cc
index 10e1b0d..3e5ca05 100644
--- a/chrome/browser/signin/chrome_signin_proxying_url_loader_factory.cc
+++ b/chrome/browser/signin/chrome_signin_proxying_url_loader_factory.cc
@@ -166,8 +166,8 @@
 
   base::OnceClosure destruction_callback_;
 
-  // Messages received by |client_binding_| are forwarded to |target_client_|.
-  mojo::Binding<network::mojom::URLLoaderClient> client_binding_;
+  // Messages received by |client_receiver_| are forwarded to |target_client_|.
+  mojo::Receiver<network::mojom::URLLoaderClient> client_receiver_{this};
   network::mojom::URLLoaderClientPtr target_client_;
 
   // Messages received by |loader_receiver_| are forwarded to |target_loader_|.
@@ -310,11 +310,10 @@
       referrer_origin_(request.referrer.GetOrigin()),
       resource_type_(static_cast<content::ResourceType>(request.resource_type)),
       is_main_frame_(request.is_main_frame),
-      client_binding_(this),
       target_client_(std::move(client)),
       loader_receiver_(this, std::move(loader_receiver)) {
   network::mojom::URLLoaderClientPtr proxy_client;
-  client_binding_.Bind(mojo::MakeRequest(&proxy_client));
+  client_receiver_.Bind(mojo::MakeRequest(&proxy_client));
 
   net::HttpRequestHeaders modified_headers;
   std::vector<std::string> removed_headers;
@@ -347,7 +346,7 @@
       2, base::BindOnce(&InProgressRequest::OnBindingsClosed,
                         base::Unretained(this)));
   loader_receiver_.set_disconnect_handler(closure);
-  client_binding_.set_connection_error_handler(closure);
+  client_receiver_.set_disconnect_handler(closure);
 }
 
 void ProxyingURLLoaderFactory::InProgressRequest::FollowRedirect(
diff --git a/chrome/browser/task_manager/task_manager_browsertest.cc b/chrome/browser/task_manager/task_manager_browsertest.cc
index 401d1ac..bae72c0 100644
--- a/chrome/browser/task_manager/task_manager_browsertest.cc
+++ b/chrome/browser/task_manager/task_manager_browsertest.cc
@@ -516,15 +516,7 @@
   ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows(0, MatchAnyApp()));
 }
 
-// Flaky - crbug.com/102553
-#if defined(OS_LINUX)
-#define MAYBE_NoticeHostedAppTabAfterReload \
-  DISABLED_NoticeHostedAppTabAfterReload
-#else
-#define MAYBE_NoticeHostedAppTabAfterReload NoticeHostedAppTabAfterReload
-#endif
-IN_PROC_BROWSER_TEST_F(TaskManagerBrowserTest,
-                       MAYBE_NoticeHostedAppTabAfterReload) {
+IN_PROC_BROWSER_TEST_F(TaskManagerBrowserTest, NoticeHostedAppTabAfterReload) {
   // The app under test acts on URLs whose host is "localhost",
   // so the URLs we navigate to must have host "localhost".
   GURL base_url = embedded_test_server()->GetURL(
@@ -554,15 +546,7 @@
   ASSERT_NO_FATAL_FAILURE(WaitForTaskManagerRows(0, MatchAnyExtension()));
 }
 
-// Flaky - crbug.com/102553
-#if defined(OS_LINUX)
-#define MAYBE_NoticeHostedAppTabBeforeReload \
-  DISABLED_NoticeHostedAppTabBeforeReload
-#else
-#define MAYBE_NoticeHostedAppTabBeforeReload NoticeHostedAppTabBeforeReload
-#endif
-IN_PROC_BROWSER_TEST_F(TaskManagerBrowserTest,
-                       MAYBE_NoticeHostedAppTabBeforeReload) {
+IN_PROC_BROWSER_TEST_F(TaskManagerBrowserTest, NoticeHostedAppTabBeforeReload) {
   // The app under test acts on URLs whose host is "localhost",
   // so the URLs we navigate to must have host "localhost".
   GURL base_url = embedded_test_server()->GetURL(
diff --git a/chrome/browser/touch_to_fill/android/internal/java/strings/android_touch_to_fill_strings.grd b/chrome/browser/touch_to_fill/android/internal/java/strings/android_touch_to_fill_strings.grd
index 9d3ff28..d2e9ba28 100644
--- a/chrome/browser/touch_to_fill/android/internal/java/strings/android_touch_to_fill_strings.grd
+++ b/chrome/browser/touch_to_fill/android/internal/java/strings/android_touch_to_fill_strings.grd
@@ -126,10 +126,10 @@
         List of credentials to be filled on touch is closed.
       </message>
       <message name="IDS_MANAGE_PASSWORDS" desc="Title of the button at the end of a touch to fill sheet that will open the password preferences when tapped.">
-        Manage Passwords
+        Manage passwords
       </message>
       <message name="IDS_TOUCH_TO_FILL_CONFIRM" desc="Title of the button that confirms filling the only available set of credentials.">
-        Use Password
+        Use password
       </message>
     </messages>
   </release>
diff --git a/chrome/browser/ui/android/strings/android_chrome_strings.grd b/chrome/browser/ui/android/strings/android_chrome_strings.grd
index 6e8221d..e652c8c6 100644
--- a/chrome/browser/ui/android/strings/android_chrome_strings.grd
+++ b/chrome/browser/ui/android/strings/android_chrome_strings.grd
@@ -3477,6 +3477,9 @@
       <message name="IDS_TOP_VIEW_NAMES_FILTER_LABEL" desc="The label shown for the names filter toggle button (allowing the user to exclude names).">
         Names
       </message>
+      <message name="IDS_TOP_VIEW_ADDRESS_FILTER_LABEL" desc="The label shown for the address filter toggle button (allowing the user to exclude names).">
+        Addresses
+      </message>
       <message name="IDS_TOP_VIEW_EMAIL_FILTER_LABEL" desc="The label shown for the email filter toggle button (allowing the user to exclude emails).">
         Email addresses
       </message>
diff --git a/chrome/browser/ui/input_method/input_method_engine_base.cc b/chrome/browser/ui/input_method/input_method_engine_base.cc
index 2af08ea9..645d9fd 100644
--- a/chrome/browser/ui/input_method/input_method_engine_base.cc
+++ b/chrome/browser/ui/input_method/input_method_engine_base.cc
@@ -208,7 +208,7 @@
 void InputMethodEngineBase::Disable() {
   std::string last_component_id{active_component_id_};
   active_component_id_.clear();
-  ConfirmCompositionText(/* reset_engine */ true);
+  ConfirmCompositionText(/* reset_engine */ true, /* keep_selection */ false);
   observer_->OnDeactivated(last_component_id);
 }
 
@@ -423,7 +423,7 @@
 
   // When there is composition text, commit it to the text field first before
   // changing the composition range.
-  ConfirmCompositionText(/* reset_engine */ false);
+  ConfirmCompositionText(/* reset_engine */ false, /* keep_selection */ false);
 
   std::vector<ui::ImeTextSpan> text_spans;
   for (const auto& segment : segments) {
@@ -509,11 +509,12 @@
     input_context->DeleteSurroundingText(offset, number_of_chars);
 }
 
-void InputMethodEngineBase::ConfirmCompositionText(bool reset_engine) {
+void InputMethodEngineBase::ConfirmCompositionText(bool reset_engine,
+                                                   bool keep_selection) {
   ui::IMEInputContextHandlerInterface* input_context =
       ui::IMEBridge::Get()->GetInputContextHandler();
   if (input_context)
-    input_context->ConfirmCompositionText(reset_engine);
+    input_context->ConfirmCompositionText(reset_engine, keep_selection);
 }
 
 }  // namespace input_method
diff --git a/chrome/browser/ui/input_method/input_method_engine_base.h b/chrome/browser/ui/input_method/input_method_engine_base.h
index f4e8af7..265df3ce 100644
--- a/chrome/browser/ui/input_method/input_method_engine_base.h
+++ b/chrome/browser/ui/input_method/input_method_engine_base.h
@@ -159,6 +159,10 @@
   // is not focused.
   bool CommitText(int context_id, const char* text, std::string* error);
 
+  // Notifies InputContextHandler to commit any composition text.
+  // Set |reset_engine| to false if the event was from the extension.
+  void ConfirmCompositionText(bool reset_engine, bool keep_selection);
+
   // Deletes |number_of_chars| unicode characters as the basis of |offset| from
   // the surrounding text. The |offset| is relative position based on current
   // caret.
@@ -242,9 +246,6 @@
   // Sends the key event to the window tree host.
   virtual bool SendKeyEvent(ui::KeyEvent* ui_event,
                             const std::string& code) = 0;
-  // Notifies InputContextHandler to commit any composition text.
-  // Set |reset_engine| to false if the event was from the extension.
-  void ConfirmCompositionText(bool reset_engine);
 
   ui::TextInputType current_input_type_;
 
diff --git a/chrome/browser/ui/views/intent_picker_bubble_view.cc b/chrome/browser/ui/views/intent_picker_bubble_view.cc
index efc3505..fb4553b 100644
--- a/chrome/browser/ui/views/intent_picker_bubble_view.cc
+++ b/chrome/browser/ui/views/intent_picker_bubble_view.cc
@@ -6,6 +6,7 @@
 
 #include <utility>
 
+#include "base/feature_list.h"
 #include "base/i18n/rtl.h"
 #include "base/strings/string_piece.h"
 #include "base/strings/utf_string_conversions.h"
@@ -16,6 +17,7 @@
 #include "chrome/browser/ui/views/chrome_typography.h"
 #include "chrome/browser/ui/views/toolbar/toolbar_ink_drop_util.h"
 #include "chrome/browser/ui/views/toolbar/toolbar_view.h"
+#include "chrome/common/chrome_features.h"
 #include "chrome/grit/generated_resources.h"
 #include "components/url_formatter/elide_url.h"
 #include "content/public/browser/navigation_handle.h"
@@ -514,11 +516,14 @@
   // TODO(crbug.com/826982): allow PWAs to have their decision persisted when
   // there is a central Chrome OS apps registry to store persistence.
   // TODO(crbug.com/1000037): allow to persist remote devices too.
-  auto selected_app_type = app_info_[selected_app_tag_].type;
-  const bool should_enable =
-      selected_app_type != apps::PickerEntryType::kWeb &&
-      selected_app_type != apps::PickerEntryType::kDevice;
-
+  bool should_enable = false;
+  if (base::FeatureList::IsEnabled(features::kAppServiceIntentHandling)) {
+    should_enable = true;
+  } else {
+    auto selected_app_type = app_info_[selected_app_tag_].type;
+    should_enable = selected_app_type != apps::PickerEntryType::kWeb &&
+                    selected_app_type != apps::PickerEntryType::kDevice;
+  }
   // Reset the checkbox state to the default unchecked if becomes disabled.
   if (!should_enable)
     remember_selection_checkbox_->SetChecked(false);
diff --git a/chrome/browser/ui/views/omnibox/omnibox_view_views.cc b/chrome/browser/ui/views/omnibox/omnibox_view_views.cc
index 131cd34..783adeb 100644
--- a/chrome/browser/ui/views/omnibox/omnibox_view_views.cc
+++ b/chrome/browser/ui/views/omnibox/omnibox_view_views.cc
@@ -264,7 +264,7 @@
   // session here.  It may affect the selection status, so order is
   // also important.
   if (IsIMEComposing()) {
-    ConfirmCompositionText();
+    ConfirmCompositionText(/* keep_selection */ false);
     GetInputMethod()->CancelComposition(this);
   }
 
diff --git a/chrome/browser/ui/webui/certificate_viewer_webui.cc b/chrome/browser/ui/webui/certificate_viewer_webui.cc
index 7f7d4392..e686be8 100644
--- a/chrome/browser/ui/webui/certificate_viewer_webui.cc
+++ b/chrome/browser/ui/webui/certificate_viewer_webui.cc
@@ -278,9 +278,7 @@
   return data;
 }
 
-void CertificateViewerDialog::OnDialogShown(
-    content::WebUI* webui,
-    content::RenderViewHost* render_view_host) {
+void CertificateViewerDialog::OnDialogShown(content::WebUI* webui) {
   webui_ = webui;
 }
 
diff --git a/chrome/browser/ui/webui/certificate_viewer_webui.h b/chrome/browser/ui/webui/certificate_viewer_webui.h
index 98958c4..b4e185e 100644
--- a/chrome/browser/ui/webui/certificate_viewer_webui.h
+++ b/chrome/browser/ui/webui/certificate_viewer_webui.h
@@ -54,8 +54,7 @@
       std::vector<content::WebUIMessageHandler*>* handlers) const override;
   void GetDialogSize(gfx::Size* size) const override;
   std::string GetDialogArgs() const override;
-  void OnDialogShown(content::WebUI* webui,
-                     content::RenderViewHost* render_view_host) override;
+  void OnDialogShown(content::WebUI* webui) override;
   void OnDialogClosed(const std::string& json_retval) override;
   void OnCloseContents(content::WebContents* source,
                        bool* out_close_dialog) override;
diff --git a/chrome/browser/ui/webui/chromeos/assistant_optin/assistant_optin_ui.cc b/chrome/browser/ui/webui/chromeos/assistant_optin/assistant_optin_ui.cc
index 9cee749..1ce28bd 100644
--- a/chrome/browser/ui/webui/chromeos/assistant_optin/assistant_optin_ui.cc
+++ b/chrome/browser/ui/webui/chromeos/assistant_optin/assistant_optin_ui.cc
@@ -207,9 +207,7 @@
   return std::string();
 }
 
-void AssistantOptInDialog::OnDialogShown(
-    content::WebUI* webui,
-    content::RenderViewHost* render_view_host) {
+void AssistantOptInDialog::OnDialogShown(content::WebUI* webui) {
   assistant_ui_ = static_cast<AssistantOptInUI*>(webui->GetController());
 }
 
diff --git a/chrome/browser/ui/webui/chromeos/assistant_optin/assistant_optin_ui.h b/chrome/browser/ui/webui/chromeos/assistant_optin/assistant_optin_ui.h
index a93c248..8e39515b 100644
--- a/chrome/browser/ui/webui/chromeos/assistant_optin/assistant_optin_ui.h
+++ b/chrome/browser/ui/webui/chromeos/assistant_optin/assistant_optin_ui.h
@@ -63,8 +63,7 @@
   // ui::WebDialogDelegate
   void GetDialogSize(gfx::Size* size) const override;
   std::string GetDialogArgs() const override;
-  void OnDialogShown(content::WebUI* webui,
-                     content::RenderViewHost* render_view_host) override;
+  void OnDialogShown(content::WebUI* webui) override;
   void OnDialogClosed(const std::string& json_retval) override;
 
  private:
diff --git a/chrome/browser/ui/webui/chromeos/crostini_installer/crostini_installer_dialog.cc b/chrome/browser/ui/webui/chromeos/crostini_installer/crostini_installer_dialog.cc
index 4b553d8a..a22310f 100644
--- a/chrome/browser/ui/webui/chromeos/crostini_installer/crostini_installer_dialog.cc
+++ b/chrome/browser/ui/webui/chromeos/crostini_installer/crostini_installer_dialog.cc
@@ -70,11 +70,9 @@
   return installer_ui_ == nullptr || installer_ui_->can_close();
 }
 
-void CrostiniInstallerDialog::OnDialogShown(
-    content::WebUI* webui,
-    content::RenderViewHost* render_view_host) {
+void CrostiniInstallerDialog::OnDialogShown(content::WebUI* webui) {
   installer_ui_ = static_cast<CrostiniInstallerUI*>(webui->GetController());
-  return SystemWebDialogDelegate::OnDialogShown(webui, render_view_host);
+  return SystemWebDialogDelegate::OnDialogShown(webui);
 }
 
 void CrostiniInstallerDialog::OnCloseContents(content::WebContents* source,
diff --git a/chrome/browser/ui/webui/chromeos/crostini_installer/crostini_installer_dialog.h b/chrome/browser/ui/webui/chromeos/crostini_installer/crostini_installer_dialog.h
index e17a627..2c96d9f 100644
--- a/chrome/browser/ui/webui/chromeos/crostini_installer/crostini_installer_dialog.h
+++ b/chrome/browser/ui/webui/chromeos/crostini_installer/crostini_installer_dialog.h
@@ -26,8 +26,7 @@
   bool ShouldShowCloseButton() const override;
   void AdjustWidgetInitParams(views::Widget::InitParams* params) override;
   bool CanCloseDialog() const override;
-  void OnDialogShown(content::WebUI* webui,
-                     content::RenderViewHost* render_view_host) override;
+  void OnDialogShown(content::WebUI* webui) override;
   void OnCloseContents(content::WebContents* source,
                        bool* out_close_dialog) override;
 
diff --git a/chrome/browser/ui/webui/chromeos/system_web_dialog_delegate.cc b/chrome/browser/ui/webui/chromeos/system_web_dialog_delegate.cc
index 23267bce..c90e0ee 100644
--- a/chrome/browser/ui/webui/chromeos/system_web_dialog_delegate.cc
+++ b/chrome/browser/ui/webui/chromeos/system_web_dialog_delegate.cc
@@ -123,9 +123,7 @@
   return std::string();
 }
 
-void SystemWebDialogDelegate::OnDialogShown(
-    content::WebUI* webui,
-    content::RenderViewHost* render_view_host) {
+void SystemWebDialogDelegate::OnDialogShown(content::WebUI* webui) {
   webui_ = webui;
 
   if (features::IsSplitSettingsEnabled()) {
diff --git a/chrome/browser/ui/webui/chromeos/system_web_dialog_delegate.h b/chrome/browser/ui/webui/chromeos/system_web_dialog_delegate.h
index e9b0e2f..1b58252 100644
--- a/chrome/browser/ui/webui/chromeos/system_web_dialog_delegate.h
+++ b/chrome/browser/ui/webui/chromeos/system_web_dialog_delegate.h
@@ -61,8 +61,7 @@
   void GetDialogSize(gfx::Size* size) const override;
   bool CanResizeDialog() const override;
   std::string GetDialogArgs() const override;
-  void OnDialogShown(content::WebUI* webui,
-                     content::RenderViewHost* render_view_host) override;
+  void OnDialogShown(content::WebUI* webui) override;
   // Note: deletes |this|.
   void OnDialogClosed(const std::string& json_retval) override;
   void OnCloseContents(content::WebContents* source,
diff --git a/chrome/browser/ui/webui/chromeos/terminal/terminal_source.cc b/chrome/browser/ui/webui/chromeos/terminal/terminal_source.cc
index 2f96140..c63f034 100644
--- a/chrome/browser/ui/webui/chromeos/terminal/terminal_source.cc
+++ b/chrome/browser/ui/webui/chromeos/terminal/terminal_source.cc
@@ -13,6 +13,7 @@
 #include "chrome/common/url_constants.h"
 #include "chrome/common/webui_url_constants.h"
 #include "net/base/mime_util.h"
+#include "third_party/zlib/google/compression_utils.h"
 
 namespace {
 // TODO(crbug.com/846546): Initially set to load crosh, but change to
@@ -26,7 +27,15 @@
 void ReadFile(const base::FilePath& path,
               const content::URLDataSource::GotDataCallback& callback) {
   std::string content;
+  // First look for uncompressed resource, then try for gzipped file.
   bool result = base::ReadFileToString(path, &content);
+  if (!result) {
+    result =
+        base::ReadFileToString(base::FilePath(path.value() + ".gz"), &content);
+    std::string uncompressed;
+    result = compression::GzipUncompress(content, &uncompressed);
+    content = std::move(uncompressed);
+  }
   // Allow missing files in <root>/_locales only.
   DCHECK(result || base::FilePath(kTerminalRoot)
                        .Append("_locales")
diff --git a/chrome/browser/ui/webui/constrained_web_dialog_ui.cc b/chrome/browser/ui/webui/constrained_web_dialog_ui.cc
index 3a0975b..b59728f 100644
--- a/chrome/browser/ui/webui/constrained_web_dialog_ui.cc
+++ b/chrome/browser/ui/webui/constrained_web_dialog_ui.cc
@@ -15,7 +15,6 @@
 #include "base/values.h"
 #include "content/public/browser/notification_service.h"
 #include "content/public/browser/render_frame_host.h"
-#include "content/public/browser/render_view_host.h"
 #include "content/public/browser/web_contents.h"
 #include "content/public/browser/web_ui.h"
 #include "content/public/browser/web_ui_message_handler.h"
@@ -28,7 +27,6 @@
 #endif
 
 using content::RenderFrameHost;
-using content::RenderViewHost;
 using content::WebContents;
 using content::WebUIMessageHandler;
 
@@ -85,8 +83,7 @@
     web_ui()->AddMessageHandler(base::WrapUnique(handler));
   }
 
-  dialog_delegate->OnDialogShown(web_ui(),
-                                 render_frame_host->GetRenderViewHost());
+  dialog_delegate->OnDialogShown(web_ui());
 }
 
 void ConstrainedWebDialogUI::OnDialogCloseMessage(const base::ListValue* args) {
diff --git a/chrome/browser/ui/webui/signin/inline_login_handler_dialog_chromeos.cc b/chrome/browser/ui/webui/signin/inline_login_handler_dialog_chromeos.cc
index 9ab19f0..7e3af1e 100644
--- a/chrome/browser/ui/webui/signin/inline_login_handler_dialog_chromeos.cc
+++ b/chrome/browser/ui/webui/signin/inline_login_handler_dialog_chromeos.cc
@@ -128,10 +128,8 @@
   return false;
 }
 
-void InlineLoginHandlerDialogChromeOS::OnDialogShown(
-    content::WebUI* webui,
-    content::RenderViewHost* render_view_host) {
-  SystemWebDialogDelegate::OnDialogShown(webui, render_view_host);
+void InlineLoginHandlerDialogChromeOS::OnDialogShown(content::WebUI* webui) {
+  SystemWebDialogDelegate::OnDialogShown(webui);
   web_modal::WebContentsModalDialogManager::CreateForWebContents(
       webui->GetWebContents());
   web_modal::WebContentsModalDialogManager::FromWebContents(
diff --git a/chrome/browser/ui/webui/signin/inline_login_handler_dialog_chromeos.h b/chrome/browser/ui/webui/signin/inline_login_handler_dialog_chromeos.h
index 5a5e94f..bc650fd 100644
--- a/chrome/browser/ui/webui/signin/inline_login_handler_dialog_chromeos.h
+++ b/chrome/browser/ui/webui/signin/inline_login_handler_dialog_chromeos.h
@@ -46,8 +46,7 @@
   void GetDialogSize(gfx::Size* size) const override;
   std::string GetDialogArgs() const override;
   bool ShouldShowDialogTitle() const override;
-  void OnDialogShown(content::WebUI* webui,
-                     content::RenderViewHost* render_view_host) override;
+  void OnDialogShown(content::WebUI* webui) override;
 
  private:
   InlineLoginHandlerModalDelegate delegate_;
diff --git a/chrome/browser/vr/service/browser_xr_runtime.cc b/chrome/browser/vr/service/browser_xr_runtime.cc
index 0c6825d6..cd06168 100644
--- a/chrome/browser/vr/service/browser_xr_runtime.cc
+++ b/chrome/browser/vr/service/browser_xr_runtime.cc
@@ -396,24 +396,6 @@
   }
 }
 
-void BrowserXRRuntime::OnDeviceActivated(
-    device::mojom::VRDisplayEventReason reason,
-    base::OnceCallback<void(bool)> on_handled) {
-  if (listening_for_activation_service_) {
-    listening_for_activation_service_->OnActivate(reason,
-                                                  std::move(on_handled));
-  } else {
-    std::move(on_handled).Run(true /* will_not_present */);
-  }
-}
-
-void BrowserXRRuntime::OnDeviceIdle(
-    device::mojom::VRDisplayEventReason reason) {
-  for (VRServiceImpl* service : services_) {
-    service->OnDeactivate(reason);
-  }
-}
-
 void BrowserXRRuntime::OnVisibilityStateChanged(
     device::mojom::XRVisibilityState visibility_state) {
   for (VRServiceImpl* service : services_) {
@@ -441,11 +423,6 @@
   if (service == presenting_service_) {
     ExitPresent(service, base::DoNothing());
   }
-  if (service == listening_for_activation_service_) {
-    // Not listening for activation.
-    listening_for_activation_service_ = nullptr;
-    runtime_->SetListeningForActivate(false);
-  }
 }
 
 void BrowserXRRuntime::ExitPresent(
@@ -524,18 +501,6 @@
   StopImmersiveSession(base::DoNothing());
 }
 
-void BrowserXRRuntime::UpdateListeningForActivate(VRServiceImpl* service) {
-  if (service->ListeningForActivate() && service->InFocusedFrame()) {
-    bool was_listening = !!listening_for_activation_service_;
-    listening_for_activation_service_ = service;
-    if (!was_listening)
-      OnListeningForActivate(true);
-  } else if (listening_for_activation_service_ == service) {
-    listening_for_activation_service_ = nullptr;
-    OnListeningForActivate(false);
-  }
-}
-
 void BrowserXRRuntime::InitializeAndGetDisplayInfo(
     content::RenderFrameHost* render_frame_host,
     device::mojom::VRService::GetImmersiveVRDisplayInfoCallback callback) {
@@ -551,8 +516,4 @@
       base::BindOnce(&BrowserXRRuntime::OnInitialized, base::Unretained(this)));
 }
 
-void BrowserXRRuntime::OnListeningForActivate(bool is_listening) {
-  runtime_->SetListeningForActivate(is_listening);
-}
-
 }  // namespace vr
diff --git a/chrome/browser/vr/service/browser_xr_runtime.h b/chrome/browser/vr/service/browser_xr_runtime.h
index abe7dab..d4d566a1 100644
--- a/chrome/browser/vr/service/browser_xr_runtime.h
+++ b/chrome/browser/vr/service/browser_xr_runtime.h
@@ -79,7 +79,6 @@
   VRServiceImpl* GetServiceWithActiveImmersiveSession() {
     return presenting_service_;
   }
-  void UpdateListeningForActivate(VRServiceImpl* service);
 
   device::mojom::VRDisplayInfoPtr GetVRDisplayInfo() {
     return display_info_.Clone();
@@ -103,14 +102,10 @@
   void OnDisplayInfoChanged(
       device::mojom::VRDisplayInfoPtr vr_device_info) override;
   void OnExitPresent() override;
-  void OnDeviceActivated(device::mojom::VRDisplayEventReason reason,
-                         base::OnceCallback<void(bool)> on_handled) override;
-  void OnDeviceIdle(device::mojom::VRDisplayEventReason reason) override;
   void OnVisibilityStateChanged(
       device::mojom::XRVisibilityState visibility_state) override;
 
   void StopImmersiveSession(VRServiceImpl::ExitPresentCallback on_exited);
-  void OnListeningForActivate(bool is_listening);
   void OnRequestSessionResult(
       base::WeakPtr<VRServiceImpl> service,
       device::mojom::XRRuntimeSessionOptionsPtr options,
@@ -129,7 +124,6 @@
   std::set<VRServiceImpl*> services_;
   device::mojom::VRDisplayInfoPtr display_info_;
 
-  VRServiceImpl* listening_for_activation_service_ = nullptr;
   VRServiceImpl* presenting_service_ = nullptr;
 
   mojo::AssociatedReceiver<device::mojom::XRRuntimeEventListener> receiver_{
diff --git a/chrome/browser/vr/service/vr_service_impl.cc b/chrome/browser/vr/service/vr_service_impl.cc
index 9b1cfbb..f903b13 100644
--- a/chrome/browser/vr/service/vr_service_impl.cc
+++ b/chrome/browser/vr/service/vr_service_impl.cc
@@ -219,12 +219,6 @@
   }
 
   in_focused_frame_ = focused;
-  if (ListeningForActivate()) {
-    BrowserXRRuntime* immersive_runtime =
-        runtime_manager_->GetImmersiveVrRuntime();
-    if (immersive_runtime)
-      immersive_runtime->UpdateListeningForActivate(this);
-  }
 
   for (const auto& controller : magic_window_controllers_)
     controller->SetFrameDataRestricted(!focused);
@@ -611,21 +605,6 @@
   }
 }
 
-void VRServiceImpl::SetListeningForActivate(
-    mojo::PendingRemote<device::mojom::VRDisplayClient> display_client) {
-  // TODO(crbug.com/999745): Remove the check if the condition to check if
-  // |display_client| is nullptr is not required.
-  if (display_client)
-    display_client_.Bind(std::move(display_client));
-  else
-    display_client_.reset();
-  BrowserXRRuntime* immersive_runtime =
-      runtime_manager_->GetImmersiveVrRuntime();
-  if (immersive_runtime && display_client_) {
-    immersive_runtime->UpdateListeningForActivate(this);
-  }
-}
-
 void VRServiceImpl::GetImmersiveVRDisplayInfo(
     device::mojom::VRService::GetImmersiveVRDisplayInfoCallback callback) {
   if (!initialization_complete_) {
@@ -669,21 +648,6 @@
     client->OnVisibilityStateChanged(visiblity_state);
 }
 
-void VRServiceImpl::OnActivate(device::mojom::VRDisplayEventReason reason,
-                               base::OnceCallback<void(bool)> on_handled) {
-  DVLOG(2) << __func__;
-  if (display_client_) {
-    display_client_->OnActivate(reason, std::move(on_handled));
-  }
-}
-
-void VRServiceImpl::OnDeactivate(device::mojom::VRDisplayEventReason reason) {
-  DVLOG(2) << __func__;
-  if (display_client_) {
-    display_client_->OnDeactivate(reason);
-  }
-}
-
 content::WebContents* VRServiceImpl::GetWebContents() {
   return content::WebContents::FromRenderFrameHost(render_frame_host_);
 }
diff --git a/chrome/browser/vr/service/vr_service_impl.h b/chrome/browser/vr/service/vr_service_impl.h
index b17188d..44b98156 100644
--- a/chrome/browser/vr/service/vr_service_impl.h
+++ b/chrome/browser/vr/service/vr_service_impl.h
@@ -81,10 +81,6 @@
   void OnExitPresent();
   void OnVisibilityStateChanged(
       device::mojom::XRVisibilityState visibility_state);
-  void OnActivate(device::mojom::VRDisplayEventReason reason,
-                  base::OnceCallback<void(bool)> on_handled);
-  void OnDeactivate(device::mojom::VRDisplayEventReason reason);
-  bool ListeningForActivate() { return !!display_client_; }
   bool InFocusedFrame() { return in_focused_frame_; }
   void OnDisplayInfoChanged();
   void RuntimesChanged();
@@ -95,10 +91,6 @@
 
   content::WebContents* GetWebContents();
 
-  void SetListeningForActivate(
-      mojo::PendingRemote<device::mojom::VRDisplayClient> display_client)
-      override;
-
  private:
   // content::WebContentsObserver implementation
   void OnWebContentsFocused(content::RenderWidgetHost* host) override;
@@ -171,9 +163,6 @@
   // List of callbacks to run when initialization is completed.
   std::vector<base::OnceCallback<void()>> pending_requests_;
 
-  // This is required for WebVR 1.1 backwards compatibility.
-  mojo::Remote<device::mojom::VRDisplayClient> display_client_;
-
   bool initialization_complete_ = false;
   bool in_focused_frame_ = false;
   bool frames_throttled_ = false;
diff --git a/chrome/browser/web_applications/components/manifest_update_task.cc b/chrome/browser/web_applications/components/manifest_update_task.cc
index 44dc2f1..f5e621d 100644
--- a/chrome/browser/web_applications/components/manifest_update_task.cc
+++ b/chrome/browser/web_applications/components/manifest_update_task.cc
@@ -87,7 +87,11 @@
   }
 
   DCHECK(data.manifest);
-  if (!IsUpdateNeededForManifest(*data.manifest)) {
+  std::unique_ptr<WebApplicationInfo> web_application_info =
+      std::make_unique<WebApplicationInfo>();
+  UpdateWebAppInfoFromManifest(*data.manifest, web_application_info.get(),
+                               ForInstallableSite::kYes);
+  if (!IsUpdateNeeded(*web_application_info)) {
     DestroySelf(ManifestUpdateResult::kAppUpToDate);
     return;
   }
@@ -95,29 +99,26 @@
   stage_ = Stage::kPendingWindowsClosed;
   Observe(nullptr);
   ui_manager_.NotifyOnAllAppWindowsClosed(
-      app_id_, base::Bind(&ManifestUpdateTask::OnAllAppWindowsClosed,
-                          AsWeakPtr(), *data.manifest));
+      app_id_, base::BindOnce(&ManifestUpdateTask::OnAllAppWindowsClosed,
+                              AsWeakPtr(), std::move(web_application_info)));
 }
 
-bool ManifestUpdateTask::IsUpdateNeededForManifest(
-    const blink::Manifest& manifest) const {
-  if (app_id_ != GenerateAppIdFromURL(manifest.start_url))
+bool ManifestUpdateTask::IsUpdateNeeded(
+    const WebApplicationInfo& web_application_info) const {
+  if (app_id_ != GenerateAppIdFromURL(web_application_info.app_url))
     return false;
 
-  if (manifest.theme_color != registrar_.GetAppThemeColor(app_id_))
+  if (web_application_info.theme_color != registrar_.GetAppThemeColor(app_id_))
     return true;
 
   // TODO(crbug.com/926083): Check more manifest fields.
   return false;
 }
 
-void ManifestUpdateTask::OnAllAppWindowsClosed(blink::Manifest manifest) {
+void ManifestUpdateTask::OnAllAppWindowsClosed(
+    std::unique_ptr<WebApplicationInfo> web_application_info) {
   DCHECK_EQ(stage_, Stage::kPendingWindowsClosed);
 
-  auto web_application_info = std::make_unique<WebApplicationInfo>();
-  UpdateWebAppInfoFromManifest(manifest, web_application_info.get(),
-                               ForInstallableSite::kYes);
-
   // The app's name must not change due to an automatic update.
   web_application_info->title =
       base::UTF8ToUTF16(registrar_.GetAppShortName(app_id_));
@@ -137,16 +138,23 @@
       break;
   }
 
+  std::unique_ptr<WebApplicationInfo> web_application_info_for_dchecking;
+#if DCHECK_IS_ON()
+  web_application_info_for_dchecking =
+      std::make_unique<WebApplicationInfo>(*web_application_info);
+#endif
+
   stage_ = Stage::kPendingInstallation;
   install_manager_.UpdateWebAppFromInfo(
       app_id_, std::move(web_application_info),
-      base::Bind(&ManifestUpdateTask::OnInstallationComplete, AsWeakPtr(),
-                 std::move(manifest)));
+      base::BindOnce(&ManifestUpdateTask::OnInstallationComplete, AsWeakPtr(),
+                     std::move(web_application_info_for_dchecking)));
 }
 
-void ManifestUpdateTask::OnInstallationComplete(blink::Manifest manifest,
-                                                const AppId& app_id,
-                                                InstallResultCode code) {
+void ManifestUpdateTask::OnInstallationComplete(
+    std::unique_ptr<WebApplicationInfo> opt_web_application_info,
+    const AppId& app_id,
+    InstallResultCode code) {
   DCHECK_EQ(stage_, Stage::kPendingInstallation);
 
   if (!IsSuccess(code)) {
@@ -155,7 +163,7 @@
   }
 
   DCHECK_EQ(app_id_, app_id);
-  DCHECK(!IsUpdateNeededForManifest(manifest));
+  DCHECK(!IsUpdateNeeded(*opt_web_application_info));
   DCHECK_EQ(code, InstallResultCode::kSuccessAlreadyInstalled);
 
   DestroySelf(ManifestUpdateResult::kAppUpdated);
diff --git a/chrome/browser/web_applications/components/manifest_update_task.h b/chrome/browser/web_applications/components/manifest_update_task.h
index 874e1ecf..5a0c495 100644
--- a/chrome/browser/web_applications/components/manifest_update_task.h
+++ b/chrome/browser/web_applications/components/manifest_update_task.h
@@ -12,6 +12,7 @@
 #include "third_party/blink/public/common/manifest/manifest.h"
 
 struct InstallableData;
+struct WebApplicationInfo;
 
 namespace web_app {
 
@@ -71,11 +72,13 @@
   };
 
   void OnDidGetInstallableData(const InstallableData& data);
-  bool IsUpdateNeededForManifest(const blink::Manifest& manifest) const;
-  void OnAllAppWindowsClosed(blink::Manifest manifest);
-  void OnInstallationComplete(blink::Manifest manifest,
-                              const AppId& app_id,
-                              InstallResultCode code);
+  bool IsUpdateNeeded(const WebApplicationInfo& web_application_info) const;
+  void OnAllAppWindowsClosed(
+      std::unique_ptr<WebApplicationInfo> web_application_info);
+  void OnInstallationComplete(
+      std::unique_ptr<WebApplicationInfo> opt_web_application_info,
+      const AppId& app_id,
+      InstallResultCode code);
   void DestroySelf(ManifestUpdateResult result);
 
   const AppRegistrar& registrar_;
diff --git a/chrome/browser/web_applications/components/web_app_data_retriever_unittest.cc b/chrome/browser/web_applications/components/web_app_data_retriever_unittest.cc
index 628fc8e..2497749 100644
--- a/chrome/browser/web_applications/components/web_app_data_retriever_unittest.cc
+++ b/chrome/browser/web_applications/components/web_app_data_retriever_unittest.cc
@@ -24,7 +24,8 @@
 #include "content/public/browser/site_instance.h"
 #include "content/public/test/browser_task_environment.h"
 #include "content/public/test/web_contents_tester.h"
-#include "mojo/public/cpp/bindings/associated_binding.h"
+#include "mojo/public/cpp/bindings/associated_receiver.h"
+#include "mojo/public/cpp/bindings/pending_associated_receiver.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "third_party/blink/public/common/associated_interfaces/associated_interface_provider.h"
 #include "third_party/blink/public/common/manifest/manifest.h"
@@ -52,8 +53,8 @@
   }
 
   void Bind(mojo::ScopedInterfaceEndpointHandle handle) {
-    binding_.Bind(
-        mojo::AssociatedInterfaceRequest<ChromeRenderFrame>(std::move(handle)));
+    receiver_.Bind(
+        mojo::PendingAssociatedReceiver<ChromeRenderFrame>(std::move(handle)));
   }
 
   // Set |web_app_info| to respond on |GetWebApplicationInfo|.
@@ -68,7 +69,7 @@
  private:
   WebApplicationInfo web_app_info_;
 
-  mojo::AssociatedBinding<chrome::mojom::ChromeRenderFrame> binding_{this};
+  mojo::AssociatedReceiver<chrome::mojom::ChromeRenderFrame> receiver_{this};
 };
 
 class WebAppDataRetrieverTest : public ChromeRenderViewHostTestHarness {
diff --git a/chrome/browser/web_applications/test/test_web_app_registry_controller.cc b/chrome/browser/web_applications/test/test_web_app_registry_controller.cc
index 1cdcbe6..a7cdc37b 100644
--- a/chrome/browser/web_applications/test/test_web_app_registry_controller.cc
+++ b/chrome/browser/web_applications/test/test_web_app_registry_controller.cc
@@ -52,11 +52,20 @@
     update->DeleteApp(app_id);
 }
 
+void TestWebAppRegistryController::SetInstallWebAppsAfterSyncDelegate(
+    InstallWebAppsAfterSyncDelegate delegate) {
+  install_web_apps_after_sync_delegate_ = delegate;
+}
+
 void TestWebAppRegistryController::InstallWebAppsAfterSync(
     std::vector<WebApp*> web_apps,
     RepeatingInstallCallback callback) {
-  for (WebApp* web_app : web_apps)
-    callback.Run(web_app->app_id(), InstallResultCode::kSuccessNewInstall);
+  if (install_web_apps_after_sync_delegate_) {
+    install_web_apps_after_sync_delegate_.Run(std::move(web_apps), callback);
+  } else {
+    for (WebApp* web_app : web_apps)
+      callback.Run(web_app->app_id(), InstallResultCode::kSuccessNewInstall);
+  }
 }
 
 void TestWebAppRegistryController::UninstallWebAppsAfterSync(
diff --git a/chrome/browser/web_applications/test/test_web_app_registry_controller.h b/chrome/browser/web_applications/test/test_web_app_registry_controller.h
index 3b891788..d8cc611 100644
--- a/chrome/browser/web_applications/test/test_web_app_registry_controller.h
+++ b/chrome/browser/web_applications/test/test_web_app_registry_controller.h
@@ -7,6 +7,7 @@
 
 #include <memory>
 
+#include "base/callback.h"
 #include "chrome/browser/web_applications/components/web_app_helpers.h"
 #include "chrome/browser/web_applications/web_app_registrar.h"
 #include "chrome/browser/web_applications/web_app_sync_install_delegate.h"
@@ -37,6 +38,12 @@
   void UnregisterApp(const AppId& app_id);
   void UnregisterAll();
 
+  using InstallWebAppsAfterSyncDelegate =
+      base::RepeatingCallback<void(std::vector<WebApp*> web_apps,
+                                   RepeatingInstallCallback callback)>;
+  void SetInstallWebAppsAfterSyncDelegate(
+      InstallWebAppsAfterSyncDelegate delegate);
+
   // SyncInstallDelegate:
   void InstallWebAppsAfterSync(std::vector<WebApp*> web_apps,
                                RepeatingInstallCallback callback) override;
@@ -52,6 +59,8 @@
   WebAppSyncBridge& sync_bridge() { return *sync_bridge_; }
 
  private:
+  InstallWebAppsAfterSyncDelegate install_web_apps_after_sync_delegate_;
+
   std::unique_ptr<TestWebAppDatabaseFactory> database_factory_;
   std::unique_ptr<WebAppRegistrarMutable> mutable_registrar_;
   testing::NiceMock<syncer::MockModelTypeChangeProcessor> mock_processor_;
diff --git a/chrome/browser/web_applications/web_app_database.cc b/chrome/browser/web_applications/web_app_database.cc
index d11eba0..837eb32 100644
--- a/chrome/browser/web_applications/web_app_database.cc
+++ b/chrome/browser/web_applications/web_app_database.cc
@@ -47,11 +47,11 @@
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   DCHECK(opened_);
 
-  DCHECK(!update_data.IsEmpty());
-
   std::unique_ptr<syncer::ModelTypeStore::WriteBatch> write_batch =
       store_->CreateWriteBatch();
 
+  // |update_data| can be empty here but we should write |metadata_change_list|
+  // anyway.
   write_batch->TakeMetadataChangesFrom(std::move(metadata_change_list));
 
   for (const std::unique_ptr<WebApp>& web_app : update_data.apps_to_create) {
diff --git a/chrome/browser/web_applications/web_app_sync_bridge.cc b/chrome/browser/web_applications/web_app_sync_bridge.cc
index f18cc68..c4e47f4 100644
--- a/chrome/browser/web_applications/web_app_sync_bridge.cc
+++ b/chrome/browser/web_applications/web_app_sync_bridge.cc
@@ -23,7 +23,6 @@
 #include "chrome/common/channel_info.h"
 #include "components/sync/base/model_type.h"
 #include "components/sync/base/report_unrecoverable_error.h"
-#include "components/sync/model/entity_data.h"
 #include "components/sync/model/metadata_batch.h"
 #include "components/sync/model/metadata_change_list.h"
 #include "components/sync/model/model_type_store.h"
@@ -34,8 +33,6 @@
 
 namespace web_app {
 
-namespace {
-
 bool AreAppsLocallyInstalledByDefault() {
 #if defined(OS_CHROMEOS)
   // On Chrome OS, sync always locally installs an app.
@@ -45,8 +42,6 @@
 #endif
 }
 
-}  // namespace
-
 std::unique_ptr<syncer::EntityData> CreateSyncEntityData(const WebApp& app) {
   auto entity_data = std::make_unique<syncer::EntityData>();
   entity_data->name = app.name();
@@ -388,6 +383,9 @@
 
 void WebAppSyncBridge::ApplySyncChangesToRegistrar(
     std::unique_ptr<RegistryUpdateData> update_local_data) {
+  if (update_local_data->IsEmpty())
+    return;
+
   std::vector<WebApp*> apps_to_install;
   for (const auto& web_app : update_local_data->apps_to_create)
     apps_to_install.push_back(web_app.get());
diff --git a/chrome/browser/web_applications/web_app_sync_bridge.h b/chrome/browser/web_applications/web_app_sync_bridge.h
index 95b8f704..5489edf 100644
--- a/chrome/browser/web_applications/web_app_sync_bridge.h
+++ b/chrome/browser/web_applications/web_app_sync_bridge.h
@@ -16,6 +16,7 @@
 #include "chrome/browser/web_applications/web_app.h"
 #include "chrome/browser/web_applications/web_app_registrar.h"
 #include "components/sync/model/entity_change.h"
+#include "components/sync/model/entity_data.h"
 #include "components/sync/model/model_type_sync_bridge.h"
 
 class Profile;
@@ -27,6 +28,10 @@
 class ModelTypeChangeProcessor;
 }  // namespace syncer
 
+namespace sync_pb {
+class WebAppSpecifics;
+}  // namespace sync_pb
+
 namespace web_app {
 
 class AbstractWebAppDatabaseFactory;
@@ -126,7 +131,10 @@
   DISALLOW_COPY_AND_ASSIGN(WebAppSyncBridge);
 };
 
+bool AreAppsLocallyInstalledByDefault();
+
 std::unique_ptr<syncer::EntityData> CreateSyncEntityData(const WebApp& app);
+
 void ApplySyncDataToApp(const sync_pb::WebAppSpecifics& sync_data, WebApp* app);
 
 }  // namespace web_app
diff --git a/chrome/browser/web_applications/web_app_sync_bridge_unittest.cc b/chrome/browser/web_applications/web_app_sync_bridge_unittest.cc
index 31ede9b..ce2d2fc 100644
--- a/chrome/browser/web_applications/web_app_sync_bridge_unittest.cc
+++ b/chrome/browser/web_applications/web_app_sync_bridge_unittest.cc
@@ -5,8 +5,11 @@
 #include "chrome/browser/web_applications/web_app_sync_bridge.h"
 
 #include <memory>
+#include <vector>
 
 #include "base/run_loop.h"
+#include "base/stl_util.h"
+#include "base/strings/string_number_conversions.h"
 #include "base/test/bind_test_util.h"
 #include "chrome/browser/web_applications/components/web_app_constants.h"
 #include "chrome/browser/web_applications/components/web_app_helpers.h"
@@ -24,6 +27,16 @@
 
 namespace {
 
+using testing::_;
+
+using AppsList = std::vector<std::unique_ptr<WebApp>>;
+
+void RemoveWebAppFromAppsList(AppsList* apps_list, const AppId& app_id) {
+  base::EraseIf(*apps_list, [app_id](const std::unique_ptr<WebApp>& app) {
+    return app->app_id() == app_id;
+  });
+}
+
 bool IsSyncDataEqual(const WebApp& expected_app,
                      const syncer::EntityData& entity_data) {
   if (!entity_data.specifics.has_web_app())
@@ -63,6 +76,78 @@
   return !data_batch->HasNext();
 }
 
+std::unique_ptr<WebApp> CreateWebApp(const std::string& url) {
+  const GURL launch_url(url);
+  const AppId app_id = GenerateAppIdFromURL(launch_url);
+
+  auto web_app = std::make_unique<WebApp>(app_id);
+  web_app->SetLaunchUrl(launch_url);
+  web_app->SetUserDisplayMode(DisplayMode::kStandalone);
+  web_app->SetName("Name");
+  return web_app;
+}
+
+std::unique_ptr<WebApp> CreateWebAppWithSyncOnlyFields(const std::string& url) {
+  const GURL launch_url(url);
+  const AppId app_id = GenerateAppIdFromURL(launch_url);
+
+  auto web_app = std::make_unique<WebApp>(app_id);
+  web_app->AddSource(Source::kSync);
+  web_app->SetLaunchUrl(launch_url);
+  web_app->SetUserDisplayMode(DisplayMode::kStandalone);
+  return web_app;
+}
+
+AppsList CreateAppsList(const std::string& base_url, int num_apps) {
+  AppsList apps_list;
+
+  for (int i = 0; i < num_apps; ++i) {
+    apps_list.push_back(
+        CreateWebAppWithSyncOnlyFields(base_url + base::NumberToString(i)));
+  }
+
+  return apps_list;
+}
+
+void InsertAppIntoRegistry(Registry* registry, std::unique_ptr<WebApp> app) {
+  AppId app_id = app->app_id();
+  ASSERT_FALSE(base::Contains(*registry, app_id));
+  registry->emplace(std::move(app_id), std::move(app));
+}
+
+void InsertAppsListIntoRegistry(Registry* registry, const AppsList& apps_list) {
+  for (const std::unique_ptr<WebApp>& app : apps_list)
+    registry->emplace(app->app_id(), std::make_unique<WebApp>(*app));
+}
+
+void ConvertAppsListToEntityChangeList(
+    const AppsList& apps_list,
+    syncer::EntityChangeList* sync_data_list) {
+  for (auto& app : apps_list) {
+    std::unique_ptr<syncer::EntityChange> entity_change =
+        syncer::EntityChange::CreateAdd(app->app_id(),
+                                        CreateSyncEntityData(*app));
+    sync_data_list->push_back(std::move(entity_change));
+  }
+}
+
+// Returns true if the app converted from entity_data exists in the apps_list.
+bool RemoveEntityDataAppFromAppsList(const std::string& storage_key,
+                                     const syncer::EntityData& entity_data,
+                                     AppsList* apps_list) {
+  for (auto& app : *apps_list) {
+    if (app->app_id() == storage_key) {
+      if (!IsSyncDataEqual(*app, entity_data))
+        return false;
+
+      RemoveWebAppFromAppsList(apps_list, storage_key);
+      return true;
+    }
+  }
+
+  return false;
+}
+
 }  // namespace
 
 class WebAppSyncBridgeTest : public WebAppTest {
@@ -83,37 +168,9 @@
 
   void InitSyncBridge() { controller().Init(); }
 
-  std::unique_ptr<WebApp> CreateWebApp(const std::string& url) {
-    const GURL launch_url(url);
-    const AppId app_id = GenerateAppIdFromURL(launch_url);
-
-    auto web_app = std::make_unique<WebApp>(app_id);
-    web_app->SetLaunchUrl(launch_url);
-    web_app->SetUserDisplayMode(DisplayMode::kStandalone);
-    web_app->SetName("Name");
-    return web_app;
-  }
-
-  std::unique_ptr<WebApp> CreateWebAppWithSyncOnlyFields(
-      const std::string& url) {
-    const GURL launch_url(url);
-    const AppId app_id = GenerateAppIdFromURL(launch_url);
-
-    auto web_app = std::make_unique<WebApp>(app_id);
-    web_app->AddSource(Source::kSync);
-    web_app->SetLaunchUrl(launch_url);
-    web_app->SetUserDisplayMode(DisplayMode::kStandalone);
-    return web_app;
-  }
-
-  void InsertAppIntoRegistry(Registry* registry, std::unique_ptr<WebApp> app) {
-    AppId app_id = app->app_id();
-    ASSERT_FALSE(base::Contains(*registry, app_id));
-    registry->emplace(std::move(app_id), std::move(app));
-  }
-
-  void InsertAppCopyIntoRegistry(Registry* registry, const WebApp& app) {
-    registry->emplace(app.app_id(), std::make_unique<WebApp>(app));
+  bool IsDatabaseRegistryEqualToRegistrar() {
+    Registry registry = database_factory().ReadRegistry();
+    return IsRegistryEqual(registrar_registry(), registry);
   }
 
  protected:
@@ -127,6 +184,10 @@
     return controller().database_factory();
   }
   WebAppSyncBridge& sync_bridge() { return controller().sync_bridge(); }
+  WebAppRegistrar& registrar() { return controller().mutable_registrar(); }
+  Registry& registrar_registry() {
+    return controller().mutable_registrar().registry();
+  }
 
  private:
   std::unique_ptr<TestWebAppRegistryController> test_registry_controller_;
@@ -156,7 +217,7 @@
 
   database_factory().WriteRegistry(registry);
 
-  EXPECT_CALL(processor(), ModelReadyToSync(testing::_)).Times(1);
+  EXPECT_CALL(processor(), ModelReadyToSync(_)).Times(1);
   InitSyncBridge();
 
   {
@@ -198,4 +259,141 @@
   EXPECT_EQ(app->app_id(), sync_bridge().GetStorageKey(*entity_data));
 }
 
+TEST_F(WebAppSyncBridgeTest, MergeSyncData_LocalSetAndServerSetAreEmpty) {
+  InitSyncBridge();
+
+  syncer::EntityChangeList sync_data_list;
+
+  EXPECT_CALL(processor(), Put(_, _, _)).Times(0);
+
+  sync_bridge().MergeSyncData(sync_bridge().CreateMetadataChangeList(),
+                              std::move(sync_data_list));
+}
+
+TEST_F(WebAppSyncBridgeTest, MergeSyncData_LocalSetEqualsServerSet) {
+  AppsList apps = CreateAppsList("https://example.com/", 10);
+
+  Registry registry;
+  InsertAppsListIntoRegistry(&registry, apps);
+  database_factory().WriteRegistry(registry);
+  InitSyncBridge();
+
+  // The incoming list of apps from the sync server.
+  syncer::EntityChangeList sync_data_list;
+  ConvertAppsListToEntityChangeList(apps, &sync_data_list);
+
+  EXPECT_CALL(processor(), Put(_, _, _)).Times(0);
+
+  sync_bridge().MergeSyncData(sync_bridge().CreateMetadataChangeList(),
+                              std::move(sync_data_list));
+
+  EXPECT_TRUE(IsRegistryEqual(registrar_registry(), registry));
+  EXPECT_TRUE(IsDatabaseRegistryEqualToRegistrar());
+}
+
+TEST_F(WebAppSyncBridgeTest, MergeSyncData_LocalSetGreaterThanServerSet) {
+  AppsList local_and_server_apps = CreateAppsList("https://example.com/", 10);
+  AppsList expected_local_apps_to_upload =
+      CreateAppsList("https://example.org/", 10);
+
+  Registry registry;
+  InsertAppsListIntoRegistry(&registry, local_and_server_apps);
+  InsertAppsListIntoRegistry(&registry, expected_local_apps_to_upload);
+  database_factory().WriteRegistry(registry);
+  InitSyncBridge();
+
+  auto metadata_change_list = sync_bridge().CreateMetadataChangeList();
+  syncer::MetadataChangeList* metadata_ptr = metadata_change_list.get();
+
+  syncer::EntityChangeList sync_data_list;
+  ConvertAppsListToEntityChangeList(local_and_server_apps, &sync_data_list);
+
+  base::RunLoop run_loop;
+  ON_CALL(processor(), Put(_, _, _))
+      .WillByDefault([&](const std::string& storage_key,
+                         std::unique_ptr<syncer::EntityData> entity_data,
+                         syncer::MetadataChangeList* metadata) {
+        EXPECT_EQ(metadata_ptr, metadata);
+        EXPECT_TRUE(RemoveEntityDataAppFromAppsList(
+            storage_key, *entity_data, &expected_local_apps_to_upload));
+        if (expected_local_apps_to_upload.empty())
+          run_loop.Quit();
+      });
+
+  sync_bridge().MergeSyncData(std::move(metadata_change_list),
+                              std::move(sync_data_list));
+  run_loop.Run();
+
+  EXPECT_TRUE(IsRegistryEqual(registrar_registry(), registry));
+  EXPECT_TRUE(IsDatabaseRegistryEqualToRegistrar());
+}
+
+TEST_F(WebAppSyncBridgeTest, MergeSyncData_LocalSetLessThanServerSet) {
+  AppsList local_and_server_apps = CreateAppsList("https://example.com/", 10);
+  AppsList expected_apps_to_install =
+      CreateAppsList("https://example.org/", 10);
+  // These fields are not synced, these are just expected values.
+  for (std::unique_ptr<WebApp>& expected_app_to_install :
+       expected_apps_to_install) {
+    expected_app_to_install->SetIsLocallyInstalled(
+        AreAppsLocallyInstalledByDefault());
+    expected_app_to_install->SetIsInSyncInstall(true);
+  }
+
+  Registry registry;
+  InsertAppsListIntoRegistry(&registry, local_and_server_apps);
+  database_factory().WriteRegistry(registry);
+  InitSyncBridge();
+
+  syncer::EntityChangeList sync_data_list;
+  ConvertAppsListToEntityChangeList(expected_apps_to_install, &sync_data_list);
+  ConvertAppsListToEntityChangeList(local_and_server_apps, &sync_data_list);
+
+  EXPECT_CALL(processor(), Put(_, _, _)).Times(0);
+
+  base::RunLoop run_loop;
+  controller().SetInstallWebAppsAfterSyncDelegate(base::BindLambdaForTesting(
+      [&](std::vector<WebApp*> apps_to_install,
+          TestWebAppRegistryController::RepeatingInstallCallback callback) {
+        for (WebApp* app_to_install : apps_to_install) {
+          // The app must be registered.
+          EXPECT_TRUE(registrar().GetAppById(app_to_install->app_id()));
+          // Add the app copy to the expected registry.
+          registry.emplace(app_to_install->app_id(),
+                           std::make_unique<WebApp>(*app_to_install));
+
+          // Find the app in expected_apps_to_install set and remove the entry.
+          bool found = false;
+          for (const std::unique_ptr<WebApp>& expected_app_to_install :
+               expected_apps_to_install) {
+            if (expected_app_to_install->app_id() == app_to_install->app_id()) {
+              EXPECT_EQ(*expected_app_to_install, *app_to_install);
+              RemoveWebAppFromAppsList(&expected_apps_to_install,
+                                       expected_app_to_install->app_id());
+              found = true;
+              break;
+            }
+          }
+          EXPECT_TRUE(found);
+        }
+
+        EXPECT_TRUE(expected_apps_to_install.empty());
+
+        // Run the callbacks to fulfill the contract.
+        for (WebApp* app_to_install : apps_to_install) {
+          callback.Run(app_to_install->app_id(),
+                       InstallResultCode::kSuccessNewInstall);
+        }
+
+        run_loop.Quit();
+      }));
+
+  sync_bridge().MergeSyncData(sync_bridge().CreateMetadataChangeList(),
+                              std::move(sync_data_list));
+  run_loop.Run();
+
+  EXPECT_TRUE(IsRegistryEqual(registrar_registry(), registry));
+  EXPECT_TRUE(IsDatabaseRegistryEqualToRegistrar());
+}
+
 }  // namespace web_app
diff --git a/chrome/chrome_cleaner/BUILD.gn b/chrome/chrome_cleaner/BUILD.gn
index fbd2d8d..1671a3f 100644
--- a/chrome/chrome_cleaner/BUILD.gn
+++ b/chrome/chrome_cleaner/BUILD.gn
@@ -64,9 +64,6 @@
 }
 
 test("chrome_cleaner_unittests") {
-  # Make this target findable from the "all" target used by the builders.
-  visibility += [ "//.:gn_all" ]
-
   sources = [
     "//chrome/chrome_cleaner/test/test_main.cc",
   ]
@@ -126,3 +123,23 @@
     ]
   }
 }
+
+group("chrome_cleaner") {
+  testonly = true
+
+  # Make this target findable from the "all" target used by the builders.
+  visibility += [ "//.:gn_all" ]
+
+  deps = [
+    ":chrome_cleaner_unittests",
+    "//chrome/chrome_cleaner/executables:chrome_cleanup_tool",
+    "//chrome/chrome_cleaner/executables:software_reporter_tool",
+  ]
+
+  if (is_internal_chrome_cleaner_build) {
+    deps += [
+      "${chrome_cleaner_internal_root}:build_targets",
+      "${chrome_cleaner_internal_root}:test_targets",
+    ]
+  }
+}
diff --git a/chrome/common/extensions/api/input_method_private.json b/chrome/common/extensions/api/input_method_private.json
index 6e3e976..2c4fc78 100644
--- a/chrome/common/extensions/api/input_method_private.json
+++ b/chrome/common/extensions/api/input_method_private.json
@@ -243,6 +243,19 @@
           }
         ]
       }, {
+        "name": "finishComposingText",
+        "type": "function",
+        "description": "Commits the text currently being composed without moving the selected text range",
+        "parameters": [
+          {
+            "type": "function",
+            "name": "callback",
+            "optional": true,
+            "description": "Called when the operation completes.",
+            "parameters": []
+          }
+        ]
+      }, {
         "name": "notifyImeMenuItemActivated",
         "type": "function",
         "description": "Fires the input.ime.onMenuItemActivated event.",
diff --git a/chrome/renderer/extensions/cast_streaming_native_handler.cc b/chrome/renderer/extensions/cast_streaming_native_handler.cc
index 46b4abd..455c66c 100644
--- a/chrome/renderer/extensions/cast_streaming_native_handler.cc
+++ b/chrome/renderer/extensions/cast_streaming_native_handler.cc
@@ -79,10 +79,11 @@
 constexpr int kBitsPerKilobit = 1000;
 
 bool HexDecode(const std::string& input, std::string* output) {
-  std::vector<uint8_t> bytes;
-  if (!base::HexStringToBytes(input, &bytes))
+  DCHECK(output->empty());
+  if (!base::HexStringToString(input, output)) {
+    output->clear();
     return false;
-  output->assign(reinterpret_cast<const char*>(&bytes[0]), bytes.size());
+  }
   return true;
 }
 
diff --git a/chrome/services/app_service/BUILD.gn b/chrome/services/app_service/BUILD.gn
index 3fa14d2..77d9de0 100644
--- a/chrome/services/app_service/BUILD.gn
+++ b/chrome/services/app_service/BUILD.gn
@@ -10,11 +10,13 @@
 
   deps = [
     "//base",
+    "//components/prefs",
     "//mojo/public/cpp/bindings",
+    "//services/service_manager/public/cpp",
   ]
 
   public_deps = [
-    "//chrome/services//app_service/public/cpp:preferred_apps",
+    "//chrome/services/app_service/public/cpp:preferred_apps",
     "//chrome/services/app_service/public/mojom",
   ]
 }
@@ -28,8 +30,8 @@
 
   deps = [
     ":lib",
-    "//chrome/services//app_service/public/cpp:intents",
-    "//chrome/services//app_service/public/cpp:preferred_apps",
+    "//chrome/services/app_service/public/cpp:intents",
+    "//chrome/services/app_service/public/cpp:preferred_apps",
     "//testing/gtest",
   ]
 }
diff --git a/chrome/services/app_service/app_service_impl.cc b/chrome/services/app_service/app_service_impl.cc
index 1ad1e98a..3eee6dfd 100644
--- a/chrome/services/app_service/app_service_impl.cc
+++ b/chrome/services/app_service/app_service_impl.cc
@@ -11,6 +11,7 @@
 #include "chrome/services/app_service/public/mojom/types.mojom.h"
 #include "components/prefs/pref_registry_simple.h"
 #include "components/prefs/pref_service.h"
+#include "components/prefs/scoped_user_pref_update.h"
 #include "services/preferences/public/cpp/pref_service_factory.h"
 #include "services/service_manager/public/cpp/connector.h"
 
@@ -34,7 +35,6 @@
   if (connector) {
     ConnectToPrefService(connector);
   }
-  InitializePreferredApps();
 }
 
 AppServiceImpl::~AppServiceImpl() = default;
@@ -81,7 +81,9 @@
   // TODO: store the opts somewhere.
 
   // Initialise the Preferred Apps in the Subscribers on register.
-  subscriber->InitializePreferredApps(preferred_apps_.GetValue());
+  if (preferred_apps_.IsInitialized()) {
+    subscriber->InitializePreferredApps(preferred_apps_.GetValue());
+  }
 
   // Add the new subscriber to the set.
   subscribers_.Add(std::move(subscriber));
@@ -173,7 +175,20 @@
                                      const std::string& app_id,
                                      apps::mojom::IntentFilterPtr intent_filter,
                                      apps::mojom::IntentPtr intent) {
+  // TODO(crbug.com/853604): Solve the issue where user set preferred app
+  // before pref connected.
+  if (!preferred_apps_.IsInitialized()) {
+    return;
+  }
+
   preferred_apps_.AddPreferredApp(app_id, intent_filter);
+
+  if (pref_service_) {
+    DictionaryPrefUpdate update(pref_service_.get(), kAppServicePreferredApps);
+    DCHECK(PreferredApps::VerifyPreferredApps(update.Get()));
+    PreferredApps::AddPreferredApp(app_id, intent_filter, update.Get());
+  }
+
   for (auto& subscriber : subscribers_) {
     subscriber->OnPreferredAppSet(app_id, intent_filter->Clone());
   }
@@ -186,17 +201,21 @@
                                   std::move(intent));
 }
 
-void AppServiceImpl::OnPublisherDisconnected(apps::mojom::AppType app_type) {
-  publishers_.erase(app_type);
-}
-
 PreferredApps& AppServiceImpl::GetPreferredAppsForTesting() {
   return preferred_apps_;
 }
 
+void AppServiceImpl::OnPublisherDisconnected(apps::mojom::AppType app_type) {
+  publishers_.erase(app_type);
+}
+
 void AppServiceImpl::InitializePreferredApps() {
-  // TODO(crbug.com/853604): Initialise from disk.
-  preferred_apps_.Init(nullptr);
+  DCHECK(pref_service_);
+  preferred_apps_.Init(
+      pref_service_->GetDictionary(kAppServicePreferredApps)->CreateDeepCopy());
+  for (auto& subscriber : subscribers_) {
+    subscriber->InitializePreferredApps(preferred_apps_.GetValue());
+  }
 }
 
 void AppServiceImpl::ConnectToPrefService(
@@ -218,12 +237,13 @@
 
 void AppServiceImpl::OnPrefServiceConnected(
     std::unique_ptr<PrefService> pref_service) {
-  if (!pref_service)
+  if (!pref_service) {
+    // TODO(crbug.com/853604): Handle if not successfully connected.
     return;
+  }
   DCHECK_EQ(nullptr, pref_service_);
   pref_service_ = std::move(pref_service);
-
-  // TODO(crbug.com/853604): use the pref service to get and set preference.
+  InitializePreferredApps();
 }
 
 }  // namespace apps
diff --git a/chrome/services/app_service/app_service_impl_unittest.cc b/chrome/services/app_service/app_service_impl_unittest.cc
index 2e97daa..e3a4a2e 100644
--- a/chrome/services/app_service/app_service_impl_unittest.cc
+++ b/chrome/services/app_service/app_service_impl_unittest.cc
@@ -253,6 +253,7 @@
 TEST_F(AppServiceImplTest, PreferredApps) {
   // Test Initialize.
   AppServiceImpl impl(nullptr);
+  impl.GetPreferredAppsForTesting().Init(nullptr);
 
   // TODO(crbug.com/853604): Update this test after reading from disk done.
   EXPECT_TRUE(impl.GetPreferredAppsForTesting().GetValue().DictEmpty());
diff --git a/chrome/services/app_service/public/cpp/preferred_apps.cc b/chrome/services/app_service/public/cpp/preferred_apps.cc
index c7652eb..eafa69a 100644
--- a/chrome/services/app_service/public/cpp/preferred_apps.cc
+++ b/chrome/services/app_service/public/cpp/preferred_apps.cc
@@ -89,11 +89,13 @@
   auto* condition_type_dict =
       dict->FindKey(ConditionTypeToString(condition_type));
 
-  if (!condition_type_dict)
+  if (!condition_type_dict) {
     return nullptr;
+  }
 
-  if (condition_type != apps::mojom::ConditionType::kPattern)
+  if (condition_type != apps::mojom::ConditionType::kPattern) {
     return condition_type_dict->FindKey(value);
+  }
 
   // For pattern matching, we need to go through all patterns and match types
   // to see if we have a match.
@@ -152,11 +154,13 @@
     base::Value* dict,
     base::Optional<std::string>* best_match_app_id) {
   auto* found_dict = FindDictionaryForTypeAndValue(dict, condition_type, value);
-  if (!found_dict)
+  if (!found_dict) {
     return found_dict;
+  }
   std::string* app_id = found_dict->FindStringKey(kAppId);
-  if (app_id)
+  if (app_id) {
     *best_match_app_id = *app_id;
+  }
   return found_dict;
 }
 
@@ -249,20 +253,22 @@
 
 // static
 // Recursively verifies that the structure of |value| matches what we expect.
-
+//
 // |value| should be a dictionary where each item is either:
 // * key == kAppId and a string value, or
 // * some other string value with a dictionary value.
 bool PreferredApps::VerifyPreferredApps(base::Value* value) {
-  if (!value->is_dict())
+  if (!value->is_dict()) {
     return false;
+  }
   bool all_items_valid = true;
   for (const auto& key_value : value->DictItems()) {
     bool item_valid = false;
-    if (key_value.first == kAppId)
+    if (key_value.first == kAppId) {
       item_valid = key_value.second.is_string();
-    else
+    } else {
       item_valid = VerifyPreferredApps(&key_value.second);
+    }
     if (!item_valid) {
       all_items_valid = false;
       break;
@@ -271,6 +277,24 @@
   return all_items_valid;
 }
 
+// static
+// Add a preferred app for a preferred app dictionary.
+bool PreferredApps::AddPreferredApp(
+    const std::string& app_id,
+    const apps::mojom::IntentFilterPtr& intent_filter,
+    base::Value* preferred_apps) {
+  if (!preferred_apps) {
+    return false;
+  }
+
+  // For an |intent_filter| there could be multiple |conditions|, and for each
+  // condition, there could be multiple |condition_values|. When we set
+  // preferred app for and |intent_filter|, we need to add the preferred app for
+  // all combinations of these |condition_values|.
+  SetPreferredApp(intent_filter->conditions, 0, preferred_apps, app_id);
+  return true;
+}
+
 void PreferredApps::Init(std::unique_ptr<base::Value> preferred_apps) {
   if (preferred_apps && VerifyPreferredApps(preferred_apps.get())) {
     preferred_apps_ = std::move(preferred_apps);
@@ -286,21 +310,16 @@
   if (!preferred_apps_) {
     return false;
   }
-
-  // For an |intent_filter| there could be multiple |conditions|, and for each
-  // condition, there could be multiple |condition_values|. When we set
-  // preferred app for and |intent_filter|, we need to add the preferred app for
-  // all combinations of these |condition_values|.
-  SetPreferredApp(intent_filter->conditions, 0, preferred_apps_.get(), app_id);
-  return true;
+  return AddPreferredApp(app_id, intent_filter, preferred_apps_.get());
 }
 
 base::Optional<std::string> PreferredApps::FindPreferredAppForIntent(
     const apps::mojom::IntentPtr& intent) {
   base::Optional<std::string> best_match_app_id = base::nullopt;
 
-  if (!preferred_apps_)
+  if (!preferred_apps_) {
     return best_match_app_id;
+  }
 
   // Currently only support intent that has the full URL.
   if (!intent->scheme.has_value() || !intent->host.has_value() ||
@@ -314,14 +333,16 @@
   auto* scheme_dict = FindDictAndUpdateBestMatchAppId(
       apps::mojom::ConditionType::kScheme, intent->scheme.value(),
       preferred_apps_.get(), &best_match_app_id);
-  if (!scheme_dict)
+  if (!scheme_dict) {
     return best_match_app_id;
+  }
 
   auto* host_dict = FindDictAndUpdateBestMatchAppId(
       apps::mojom::ConditionType::kHost, intent->host.value(), scheme_dict,
       &best_match_app_id);
-  if (!host_dict)
+  if (!host_dict) {
     return best_match_app_id;
+  }
 
   FindDictAndUpdateBestMatchAppId(apps::mojom::ConditionType::kPattern,
                                   intent->path.value(), host_dict,
@@ -339,4 +360,8 @@
   return preferred_apps_->Clone();
 }
 
+bool PreferredApps::IsInitialized() {
+  return preferred_apps_ != nullptr;
+}
+
 }  // namespace apps
diff --git a/chrome/services/app_service/public/cpp/preferred_apps.h b/chrome/services/app_service/public/cpp/preferred_apps.h
index 7eb9efb9..d084e9d 100644
--- a/chrome/services/app_service/public/cpp/preferred_apps.h
+++ b/chrome/services/app_service/public/cpp/preferred_apps.h
@@ -45,6 +45,11 @@
 
   static bool VerifyPreferredApps(base::Value* dict);
 
+  // Add a preferred app for an |intent_filter| for |preferred_apps|.
+  static bool AddPreferredApp(const std::string& app_id,
+                              const apps::mojom::IntentFilterPtr& intent_filter,
+                              base::Value* preferred_apps);
+
   void Init(std::unique_ptr<base::Value> preferred_apps);
 
   // Add a preferred app for an |intent_filter|.
@@ -61,6 +66,8 @@
   // Get a copy of the preferred apps.
   base::Value GetValue();
 
+  bool IsInitialized();
+
  private:
   std::unique_ptr<base::Value> preferred_apps_;
 
diff --git a/chrome/test/data/webui/extensions/code_section_test.js b/chrome/test/data/webui/extensions/code_section_test.js
index b1e1e400..27c3e7e 100644
--- a/chrome/test/data/webui/extensions/code_section_test.js
+++ b/chrome/test/data/webui/extensions/code_section_test.js
@@ -8,113 +8,113 @@
 import {assert} from 'chrome://resources/js/assert.m.js';
 import {isVisible} from '../test_util.m.js';
 
-  window.extension_code_section_tests = {};
-  extension_code_section_tests.suiteName = 'ExtensionCodeSectionTest';
-  /** @enum {string} */
-  extension_code_section_tests.TestNames = {
-    Layout: 'layout',
-    LongSource: 'long source',
-  };
+window.extension_code_section_tests = {};
+extension_code_section_tests.suiteName = 'ExtensionCodeSectionTest';
+/** @enum {string} */
+extension_code_section_tests.TestNames = {
+  Layout: 'layout',
+  LongSource: 'long source',
+};
 
-  suite(extension_code_section_tests.suiteName, function() {
-    /** @type {ExtensionsCodeSectionElement} */
-    let codeSection;
+suite(extension_code_section_tests.suiteName, function() {
+  /** @type {ExtensionsCodeSectionElement} */
+  let codeSection;
 
-    const couldNotDisplayCode = 'No code here';
+  const couldNotDisplayCode = 'No code here';
 
-    // Initialize an extension item before each test.
-    setup(function() {
-      PolymerTest.clearBody();
-      codeSection = document.createElement('extensions-code-section');
-      codeSection.couldNotDisplayCode = couldNotDisplayCode;
-      document.body.appendChild(codeSection);
-    });
+  // Initialize an extension item before each test.
+  setup(function() {
+    PolymerTest.clearBody();
+    codeSection = document.createElement('extensions-code-section');
+    codeSection.couldNotDisplayCode = couldNotDisplayCode;
+    document.body.appendChild(codeSection);
+  });
 
-    test(assert(extension_code_section_tests.TestNames.Layout), function() {
-      /** @type {chrome.developerPrivate.RequestFileSourceResponse} */
-      const code = {
-        beforeHighlight: 'this part before the highlight\nAnd this too\n',
-        highlight: 'highlight this part\n',
-        afterHighlight: 'this part after the highlight',
+  test(assert(extension_code_section_tests.TestNames.Layout), function() {
+    /** @type {chrome.developerPrivate.RequestFileSourceResponse} */
+    const code = {
+      beforeHighlight: 'this part before the highlight\nAnd this too\n',
+      highlight: 'highlight this part\n',
+      afterHighlight: 'this part after the highlight',
+      message: 'Highlight message',
+    };
+
+    const testIsVisible = isVisible.bind(null, codeSection);
+    expectFalse(!!codeSection.code);
+    expectTrue(codeSection.$$('#scroll-container').hidden);
+    expectFalse(testIsVisible('#main'));
+    expectTrue(testIsVisible('#no-code'));
+
+    codeSection.code = code;
+    codeSection.isActive = true;
+    expectTrue(testIsVisible('#main'));
+    expectFalse(testIsVisible('#no-code'));
+
+    let codeSections =
+        codeSection.shadowRoot.querySelectorAll('#source span span');
+
+    expectEquals(code.beforeHighlight, codeSections[0].textContent);
+    expectEquals(code.highlight, codeSections[1].textContent);
+    expectEquals(code.afterHighlight, codeSections[2].textContent);
+
+    expectEquals(
+        '1\n2\n3\n4', codeSection.$$('#line-numbers span').textContent.trim());
+  });
+
+  test(assert(extension_code_section_tests.TestNames.LongSource), function() {
+    /** @type {chrome.developerPrivate.RequestFileSourceResponse} */
+    let code;
+    let lineNums;
+
+    function setCodeContent(beforeLineCount, afterLineCount) {
+      code = {
+        beforeHighlight: '',
+        highlight: 'highlight',
+        afterHighlight: '',
         message: 'Highlight message',
       };
-
-      const testIsVisible = isVisible.bind(null, codeSection);
-      expectFalse(!!codeSection.code);
-      expectTrue(codeSection.$$('#scroll-container').hidden);
-      expectFalse(testIsVisible('#main'));
-      expectTrue(testIsVisible('#no-code'));
-
-      codeSection.code = code;
-      codeSection.isActive = true;
-      expectTrue(testIsVisible('#main'));
-      expectFalse(testIsVisible('#no-code'));
-
-      let codeSections =
-          codeSection.shadowRoot.querySelectorAll('#source span span');
-
-      expectEquals(code.beforeHighlight, codeSections[0].textContent);
-      expectEquals(code.highlight, codeSections[1].textContent);
-      expectEquals(code.afterHighlight, codeSections[2].textContent);
-
-      expectEquals(
-          '1\n2\n3\n4', codeSection.$$('#line-numbers span').textContent.trim());
-    });
-
-    test(assert(extension_code_section_tests.TestNames.LongSource), function() {
-      /** @type {chrome.developerPrivate.RequestFileSourceResponse} */
-      let code;
-      let lineNums;
-
-      function setCodeContent(beforeLineCount, afterLineCount) {
-        code = {
-          beforeHighlight: '',
-          highlight: 'highlight',
-          afterHighlight: '',
-          message: 'Highlight message',
-        };
-        for (let i = 0; i < beforeLineCount; i++) {
-          code.beforeHighlight += 'a\n';
-        }
-        for (let i = 0; i < afterLineCount; i++) {
-          code.afterHighlight += 'a\n';
-        }
+      for (let i = 0; i < beforeLineCount; i++) {
+        code.beforeHighlight += 'a\n';
       }
+      for (let i = 0; i < afterLineCount; i++) {
+        code.afterHighlight += 'a\n';
+      }
+    }
 
-      setCodeContent(0, 2000);
-      codeSection.code = code;
-      lineNums = codeSection.$$('#line-numbers span').textContent;
-      // Length should be 1000 +- 1.
-      expectTrue(lineNums.split('\n').length >= 999);
-      expectTrue(lineNums.split('\n').length <= 1001);
-      expectTrue(!!lineNums.match(/^1\n/));
-      expectTrue(!!lineNums.match(/1000/));
-      expectFalse(!!lineNums.match(/1001/));
-      expectTrue(codeSection.$$('#line-numbers .more-code.before').hidden);
-      expectFalse(codeSection.$$('#line-numbers .more-code.after').hidden);
+    setCodeContent(0, 2000);
+    codeSection.code = code;
+    lineNums = codeSection.$$('#line-numbers span').textContent;
+    // Length should be 1000 +- 1.
+    expectTrue(lineNums.split('\n').length >= 999);
+    expectTrue(lineNums.split('\n').length <= 1001);
+    expectTrue(!!lineNums.match(/^1\n/));
+    expectTrue(!!lineNums.match(/1000/));
+    expectFalse(!!lineNums.match(/1001/));
+    expectTrue(codeSection.$$('#line-numbers .more-code.before').hidden);
+    expectFalse(codeSection.$$('#line-numbers .more-code.after').hidden);
 
-      setCodeContent(1000, 1000);
-      codeSection.code = code;
-      lineNums = codeSection.$$('#line-numbers span').textContent;
-      // Length should be 1000 +- 1.
-      expectTrue(lineNums.split('\n').length >= 999);
-      expectTrue(lineNums.split('\n').length <= 1001);
-      expectFalse(!!lineNums.match(/^1\n/));
-      expectTrue(!!lineNums.match(/1000/));
-      expectFalse(!!lineNums.match(/1999/));
-      expectFalse(codeSection.$$('#line-numbers .more-code.before').hidden);
-      expectFalse(codeSection.$$('#line-numbers .more-code.after').hidden);
+    setCodeContent(1000, 1000);
+    codeSection.code = code;
+    lineNums = codeSection.$$('#line-numbers span').textContent;
+    // Length should be 1000 +- 1.
+    expectTrue(lineNums.split('\n').length >= 999);
+    expectTrue(lineNums.split('\n').length <= 1001);
+    expectFalse(!!lineNums.match(/^1\n/));
+    expectTrue(!!lineNums.match(/1000/));
+    expectFalse(!!lineNums.match(/1999/));
+    expectFalse(codeSection.$$('#line-numbers .more-code.before').hidden);
+    expectFalse(codeSection.$$('#line-numbers .more-code.after').hidden);
 
-      setCodeContent(2000, 0);
-      codeSection.code = code;
-      lineNums = codeSection.$$('#line-numbers span').textContent;
-      // Length should be 1000 +- 1.
-      expectTrue(lineNums.split('\n').length >= 999);
-      expectTrue(lineNums.split('\n').length <= 1001);
-      expectFalse(!!lineNums.match(/^1\n/));
-      expectTrue(!!lineNums.match(/1002/));
-      expectTrue(!!lineNums.match(/2000/));
-      expectFalse(codeSection.$$('#line-numbers .more-code.before').hidden);
-      expectTrue(codeSection.$$('#line-numbers .more-code.after').hidden);
-    });
+    setCodeContent(2000, 0);
+    codeSection.code = code;
+    lineNums = codeSection.$$('#line-numbers span').textContent;
+    // Length should be 1000 +- 1.
+    expectTrue(lineNums.split('\n').length >= 999);
+    expectTrue(lineNums.split('\n').length <= 1001);
+    expectFalse(!!lineNums.match(/^1\n/));
+    expectTrue(!!lineNums.match(/1002/));
+    expectTrue(!!lineNums.match(/2000/));
+    expectFalse(codeSection.$$('#line-numbers .more-code.before').hidden);
+    expectTrue(codeSection.$$('#line-numbers .more-code.after').hidden);
   });
+});
diff --git a/chrome/test/data/webui/extensions/detail_view_test.js b/chrome/test/data/webui/extensions/detail_view_test.js
index cd53ce5..9d43c48 100644
--- a/chrome/test/data/webui/extensions/detail_view_test.js
+++ b/chrome/test/data/webui/extensions/detail_view_test.js
@@ -12,387 +12,384 @@
 
 import {createExtensionInfo, MockItemDelegate} from './test_util.js';
 
-  window.extension_detail_view_tests = {};
-  extension_detail_view_tests.suiteName = 'ExtensionDetailViewTest';
-  /** @enum {string} */
-  extension_detail_view_tests.TestNames = {
-    Layout: 'layout',
-    LayoutSource: 'layout of source section',
-    ClickableElements: 'clickable elements',
-    Indicator: 'indicator',
-    Warnings: 'warnings',
-  };
+window.extension_detail_view_tests = {};
+extension_detail_view_tests.suiteName = 'ExtensionDetailViewTest';
+/** @enum {string} */
+extension_detail_view_tests.TestNames = {
+  Layout: 'layout',
+  LayoutSource: 'layout of source section',
+  ClickableElements: 'clickable elements',
+  Indicator: 'indicator',
+  Warnings: 'warnings',
+};
 
-  suite(extension_detail_view_tests.suiteName, function() {
-    /**
-     * Extension item created before each test.
-     * @type {Item}
-     */
-    let item;
+suite(extension_detail_view_tests.suiteName, function() {
+  /**
+   * Extension item created before each test.
+   * @type {Item}
+   */
+  let item;
 
-    /**
-     * Backing extension data for the item.
-     * @type {chrome.developerPrivate.ExtensionInfo}
-     */
-    let extensionData;
+  /**
+   * Backing extension data for the item.
+   * @type {chrome.developerPrivate.ExtensionInfo}
+   */
+  let extensionData;
 
-    /** @type {MockItemDelegate} */
-    let mockDelegate;
+  /** @type {MockItemDelegate} */
+  let mockDelegate;
 
-    // Initialize an extension item before each test.
-    setup(function() {
-      PolymerTest.clearBody();
-      extensionData = createExtensionInfo({
-        incognitoAccess: {isEnabled: true, isActive: false},
-        fileAccess: {isEnabled: true, isActive: false},
-        errorCollection: {isEnabled: true, isActive: false},
-      });
-      mockDelegate = new MockItemDelegate();
-      item = document.createElement('extensions-detail-view');
-      item.set('data', extensionData);
-      item.set('delegate', mockDelegate);
-      item.set('inDevMode', false);
-      item.set('incognitoAvailable', true);
-      item.set('showActivityLog', false);
-      document.body.appendChild(item);
+  // Initialize an extension item before each test.
+  setup(function() {
+    PolymerTest.clearBody();
+    extensionData = createExtensionInfo({
+      incognitoAccess: {isEnabled: true, isActive: false},
+      fileAccess: {isEnabled: true, isActive: false},
+      errorCollection: {isEnabled: true, isActive: false},
     });
+    mockDelegate = new MockItemDelegate();
+    item = document.createElement('extensions-detail-view');
+    item.set('data', extensionData);
+    item.set('delegate', mockDelegate);
+    item.set('inDevMode', false);
+    item.set('incognitoAvailable', true);
+    item.set('showActivityLog', false);
+    document.body.appendChild(item);
+  });
 
-    test(assert(extension_detail_view_tests.TestNames.Layout), function() {
+  test(assert(extension_detail_view_tests.TestNames.Layout), function() {
+    flush();
+
+    const testIsVisible = isVisible.bind(null, item);
+    expectTrue(testIsVisible('#closeButton'));
+    expectTrue(testIsVisible('#icon'));
+    expectTrue(testIsVisible('#enable-toggle'));
+    expectFalse(testIsVisible('#extensions-options'));
+    expectTrue(
+        item.$.description.textContent.indexOf('This is an extension') !== -1);
+
+    // Check the checkboxes visibility and state. They should be visible
+    // only if the associated option is enabled, and checked if the
+    // associated option is active.
+    const accessOptions = [
+      {key: 'incognitoAccess', id: '#allow-incognito'},
+      {key: 'fileAccess', id: '#allow-on-file-urls'},
+      {key: 'errorCollection', id: '#collect-errors'},
+    ];
+    const isChecked = id => item.$$(id).checked;
+    for (let option of accessOptions) {
+      expectTrue(isVisible(item, option.id));
+      expectFalse(isChecked(option.id), option.id);
+      item.set('data.' + option.key + '.isEnabled', false);
       flush();
+      expectFalse(isVisible(item, option.id));
+      item.set('data.' + option.key + '.isEnabled', true);
+      item.set('data.' + option.key + '.isActive', true);
+      flush();
+      expectTrue(isVisible(item, option.id));
+      expectTrue(isChecked(option.id));
+    }
 
-      const testIsVisible = isVisible.bind(null, item);
-      expectTrue(testIsVisible('#closeButton'));
-      expectTrue(testIsVisible('#icon'));
-      expectTrue(testIsVisible('#enable-toggle'));
-      expectFalse(testIsVisible('#extensions-options'));
-      expectTrue(
-          item.$.description.textContent.indexOf('This is an extension') !==
-          -1);
+    expectFalse(testIsVisible('#dependent-extensions-list'));
+    item.set(
+        'data.dependentExtensions',
+        [{id: 'aaa', name: 'Dependent1'}, {id: 'bbb', name: 'Dependent2'}]);
+    flush();
+    expectTrue(testIsVisible('#dependent-extensions-list'));
+    expectEquals(
+        2, item.$$('#dependent-extensions-list').querySelectorAll('li').length);
 
-      // Check the checkboxes visibility and state. They should be visible
-      // only if the associated option is enabled, and checked if the
-      // associated option is active.
-      const accessOptions = [
-        {key: 'incognitoAccess', id: '#allow-incognito'},
-        {key: 'fileAccess', id: '#allow-on-file-urls'},
-        {key: 'errorCollection', id: '#collect-errors'},
-      ];
-      const isChecked = id => item.$$(id).checked;
-      for (let option of accessOptions) {
-        expectTrue(isVisible(item, option.id));
-        expectFalse(isChecked(option.id), option.id);
-        item.set('data.' + option.key + '.isEnabled', false);
+    expectFalse(testIsVisible('#permissions-list'));
+    expectFalse(testIsVisible('#host-access'));
+    expectFalse(testIsVisible('extensions-runtime-host-permissions'));
+
+    expectTrue(testIsVisible('#no-permissions'));
+    item.set(
+        'data.permissions',
+        {simplePermissions: ['Permission 1', 'Permission 2']});
+    flush();
+    expectTrue(testIsVisible('#permissions-list'));
+    expectEquals(2, item.$$('#permissions-list').querySelectorAll('li').length);
+    expectFalse(testIsVisible('#no-permissions'));
+    expectFalse(testIsVisible('#host-access'));
+    expectFalse(testIsVisible('extensions-runtime-host-permissions'));
+
+    const optionsUrl =
+        'chrome-extension://' + extensionData.id + '/options.html';
+    item.set('data.optionsPage', {openInTab: true, url: optionsUrl});
+    expectTrue(testIsVisible('#extensions-options'));
+
+    expectFalse(testIsVisible('#extensionsActivityLogLink'));
+    item.set('showActivityLog', true);
+    flush();
+    expectTrue(testIsVisible('#extensionsActivityLogLink'));
+
+    item.set('data.manifestHomePageUrl', 'http://example.com');
+    flush();
+    expectTrue(testIsVisible('#extensionWebsite'));
+    item.set('data.manifestHomePageUrl', '');
+    flush();
+    expectFalse(testIsVisible('#extensionWebsite'));
+
+    item.set('data.webStoreUrl', 'http://example.com');
+    flush();
+    expectTrue(testIsVisible('#viewInStore'));
+    item.set('data.webStoreUrl', '');
+    flush();
+    expectFalse(testIsVisible('#viewInStore'));
+
+    expectFalse(testIsVisible('#id-section'));
+    expectFalse(testIsVisible('#inspectable-views'));
+
+    item.set('inDevMode', true);
+    flush();
+    expectTrue(testIsVisible('#id-section'));
+    expectTrue(testIsVisible('#inspectable-views'));
+
+    assertTrue(item.data.incognitoAccess.isEnabled);
+    item.set('incognitoAvailable', false);
+    flush();
+    expectFalse(testIsVisible('#allow-incognito'));
+
+    item.set('incognitoAvailable', true);
+    flush();
+    expectTrue(testIsVisible('#allow-incognito'));
+
+    // Ensure that the "Extension options" button is disabled when the item
+    // itself is disabled.
+    const extensionOptions = item.$$('#extensions-options');
+    assertFalse(extensionOptions.disabled);
+    item.set('data.state', chrome.developerPrivate.ExtensionState.DISABLED);
+    flush();
+    assertTrue(extensionOptions.disabled);
+
+    expectFalse(testIsVisible('.warning-icon'));
+    item.set('data.runtimeWarnings', ['Dummy warning']);
+    flush();
+    expectTrue(testIsVisible('.warning-icon'));
+
+    expectTrue(testIsVisible('#enable-toggle'));
+    expectFalse(testIsVisible('#terminated-reload-button'));
+    item.set('data.state', chrome.developerPrivate.ExtensionState.TERMINATED);
+    flush();
+    expectFalse(testIsVisible('#enable-toggle'));
+    expectTrue(testIsVisible('#terminated-reload-button'));
+
+    // Ensure that the runtime warning reload button is not visible if there
+    // are runtime warnings and the extension is terminated.
+    item.set('data.runtimeWarnings', ['Dummy warning']);
+    flush();
+    expectFalse(testIsVisible('#warnings-reload-button'));
+    item.set('data.runtimeWarnings', []);
+
+    // Reset item state back to DISABLED.
+    item.set('data.state', chrome.developerPrivate.ExtensionState.DISABLED);
+    flush();
+
+    // Ensure that without runtimeHostPermissions data, the sections are
+    // hidden.
+    expectTrue(testIsVisible('#no-site-access'));
+    expectFalse(testIsVisible('extensions-runtime-host-permissions'));
+    expectFalse(testIsVisible('extensions-host-permissions-toggle-list'));
+
+    // Adding any runtime host permissions should result in the runtime host
+    // controls becoming visible.
+    const allSitesPermissions = {
+      simplePermissions: [],
+      runtimeHostPermissions: {
+        hosts: [{granted: false, host: '<all_urls>'}],
+        hasAllHosts: true,
+        hostAccess: chrome.developerPrivate.HostAccess.ON_CLICK,
+      },
+    };
+    item.set('data.permissions', allSitesPermissions);
+    flush();
+    expectFalse(testIsVisible('#no-site-access'));
+    expectTrue(testIsVisible('extensions-runtime-host-permissions'));
+    expectFalse(testIsVisible('extensions-host-permissions-toggle-list'));
+
+    const someSitesPermissions = {
+      simplePermissions: [],
+      runtimeHostPermissions: {
+        hosts: [
+          {granted: true, host: 'https://chromium.org/*'},
+          {granted: false, host: 'https://example.com/*'}
+        ],
+        hasAllHosts: false,
+        hostAccess: chrome.developerPrivate.HostAccess.ON_SPECIFIC_SITES,
+      },
+    };
+    item.set('data.permissions', someSitesPermissions);
+    flush();
+    expectFalse(testIsVisible('#no-site-access'));
+    expectFalse(testIsVisible('extensions-runtime-host-permissions'));
+    expectTrue(testIsVisible('extensions-host-permissions-toggle-list'));
+  });
+
+  test(assert(extension_detail_view_tests.TestNames.LayoutSource), function() {
+    item.set('data.location', 'FROM_STORE');
+    flush();
+    assertEquals('Chrome Web Store', item.$.source.textContent.trim());
+    assertFalse(isVisible(item, '#load-path'));
+
+    item.set('data.location', 'THIRD_PARTY');
+    flush();
+    assertEquals('Added by a third-party', item.$.source.textContent.trim());
+    assertFalse(isVisible(item, '#load-path'));
+
+    item.set('data.location', 'UNPACKED');
+    item.set('data.prettifiedPath', 'foo/bar/baz/');
+    flush();
+    assertEquals('Unpacked extension', item.$.source.textContent.trim());
+    // Test whether the load path is displayed for unpacked extensions.
+    assertTrue(isVisible(item, '#load-path'));
+
+    item.set('data.location', 'UNKNOWN');
+    item.set('data.prettifiedPath', '');
+    // |locationText| is expected to always be set if location is UNKNOWN.
+    item.set('data.locationText', 'Foo');
+    flush();
+    assertEquals('Foo', item.$.source.textContent.trim());
+    assertFalse(isVisible(item, '#load-path'));
+  });
+
+  test(
+      assert(extension_detail_view_tests.TestNames.ClickableElements),
+      function() {
+        const optionsUrl =
+            'chrome-extension://' + extensionData.id + '/options.html';
+        item.set('data.optionsPage', {openInTab: true, url: optionsUrl});
+        item.set('data.prettifiedPath', 'foo/bar/baz/');
+        item.set('showActivityLog', true);
         flush();
-        expectFalse(isVisible(item, option.id));
-        item.set('data.' + option.key + '.isEnabled', true);
-        item.set('data.' + option.key + '.isActive', true);
-        flush();
-        expectTrue(isVisible(item, option.id));
-        expectTrue(isChecked(option.id));
-      }
 
-      expectFalse(testIsVisible('#dependent-extensions-list'));
-      item.set(
-          'data.dependentExtensions',
-          [{id: 'aaa', name: 'Dependent1'}, {id: 'bbb', name: 'Dependent2'}]);
-      flush();
-      expectTrue(testIsVisible('#dependent-extensions-list'));
-      expectEquals(
-          2,
-          item.$$('#dependent-extensions-list').querySelectorAll('li').length);
-
-      expectFalse(testIsVisible('#permissions-list'));
-      expectFalse(testIsVisible('#host-access'));
-      expectFalse(testIsVisible('extensions-runtime-host-permissions'));
-
-      expectTrue(testIsVisible('#no-permissions'));
-      item.set(
-          'data.permissions',
-          {simplePermissions: ['Permission 1', 'Permission 2']});
-      flush();
-      expectTrue(testIsVisible('#permissions-list'));
-      expectEquals(
-          2, item.$$('#permissions-list').querySelectorAll('li').length);
-      expectFalse(testIsVisible('#no-permissions'));
-      expectFalse(testIsVisible('#host-access'));
-      expectFalse(testIsVisible('extensions-runtime-host-permissions'));
-
-      const optionsUrl =
-          'chrome-extension://' + extensionData.id + '/options.html';
-      item.set('data.optionsPage', {openInTab: true, url: optionsUrl});
-      expectTrue(testIsVisible('#extensions-options'));
-
-      expectFalse(testIsVisible('#extensionsActivityLogLink'));
-      item.set('showActivityLog', true);
-      flush();
-      expectTrue(testIsVisible('#extensionsActivityLogLink'));
-
-      item.set('data.manifestHomePageUrl', 'http://example.com');
-      flush();
-      expectTrue(testIsVisible('#extensionWebsite'));
-      item.set('data.manifestHomePageUrl', '');
-      flush();
-      expectFalse(testIsVisible('#extensionWebsite'));
-
-      item.set('data.webStoreUrl', 'http://example.com');
-      flush();
-      expectTrue(testIsVisible('#viewInStore'));
-      item.set('data.webStoreUrl', '');
-      flush();
-      expectFalse(testIsVisible('#viewInStore'));
-
-      expectFalse(testIsVisible('#id-section'));
-      expectFalse(testIsVisible('#inspectable-views'));
-
-      item.set('inDevMode', true);
-      flush();
-      expectTrue(testIsVisible('#id-section'));
-      expectTrue(testIsVisible('#inspectable-views'));
-
-      assertTrue(item.data.incognitoAccess.isEnabled);
-      item.set('incognitoAvailable', false);
-      flush();
-      expectFalse(testIsVisible('#allow-incognito'));
-
-      item.set('incognitoAvailable', true);
-      flush();
-      expectTrue(testIsVisible('#allow-incognito'));
-
-      // Ensure that the "Extension options" button is disabled when the item
-      // itself is disabled.
-      const extensionOptions = item.$$('#extensions-options');
-      assertFalse(extensionOptions.disabled);
-      item.set('data.state', chrome.developerPrivate.ExtensionState.DISABLED);
-      flush();
-      assertTrue(extensionOptions.disabled);
-
-      expectFalse(testIsVisible('.warning-icon'));
-      item.set('data.runtimeWarnings', ['Dummy warning']);
-      flush();
-      expectTrue(testIsVisible('.warning-icon'));
-
-      expectTrue(testIsVisible('#enable-toggle'));
-      expectFalse(testIsVisible('#terminated-reload-button'));
-      item.set('data.state', chrome.developerPrivate.ExtensionState.TERMINATED);
-      flush();
-      expectFalse(testIsVisible('#enable-toggle'));
-      expectTrue(testIsVisible('#terminated-reload-button'));
-
-      // Ensure that the runtime warning reload button is not visible if there
-      // are runtime warnings and the extension is terminated.
-      item.set('data.runtimeWarnings', ['Dummy warning']);
-      flush();
-      expectFalse(testIsVisible('#warnings-reload-button'));
-      item.set('data.runtimeWarnings', []);
-
-      // Reset item state back to DISABLED.
-      item.set('data.state', chrome.developerPrivate.ExtensionState.DISABLED);
-      flush();
-
-      // Ensure that without runtimeHostPermissions data, the sections are
-      // hidden.
-      expectTrue(testIsVisible('#no-site-access'));
-      expectFalse(testIsVisible('extensions-runtime-host-permissions'));
-      expectFalse(testIsVisible('extensions-host-permissions-toggle-list'));
-
-      // Adding any runtime host permissions should result in the runtime host
-      // controls becoming visible.
-      const allSitesPermissions = {
-        simplePermissions: [],
-        runtimeHostPermissions: {
-          hosts: [{granted: false, host: '<all_urls>'}],
-          hasAllHosts: true,
-          hostAccess: chrome.developerPrivate.HostAccess.ON_CLICK,
-        },
-      };
-      item.set('data.permissions', allSitesPermissions);
-      flush();
-      expectFalse(testIsVisible('#no-site-access'));
-      expectTrue(testIsVisible('extensions-runtime-host-permissions'));
-      expectFalse(testIsVisible('extensions-host-permissions-toggle-list'));
-
-      const someSitesPermissions = {
-        simplePermissions: [],
-        runtimeHostPermissions: {
-          hosts: [
-            {granted: true, host: 'https://chromium.org/*'},
-            {granted: false, host: 'https://example.com/*'}
-          ],
-          hasAllHosts: false,
-          hostAccess: chrome.developerPrivate.HostAccess.ON_SPECIFIC_SITES,
-        },
-      };
-      item.set('data.permissions', someSitesPermissions);
-      flush();
-      expectFalse(testIsVisible('#no-site-access'));
-      expectFalse(testIsVisible('extensions-runtime-host-permissions'));
-      expectTrue(testIsVisible('extensions-host-permissions-toggle-list'));
-    });
-
-    test(assert(extension_detail_view_tests.TestNames.LayoutSource), function() {
-      item.set('data.location', 'FROM_STORE');
-      flush();
-      assertEquals('Chrome Web Store', item.$.source.textContent.trim());
-      assertFalse(isVisible(item, '#load-path'));
-
-      item.set('data.location', 'THIRD_PARTY');
-      flush();
-      assertEquals('Added by a third-party', item.$.source.textContent.trim());
-      assertFalse(isVisible(item, '#load-path'));
-
-      item.set('data.location', 'UNPACKED');
-      item.set('data.prettifiedPath', 'foo/bar/baz/');
-      flush();
-      assertEquals('Unpacked extension', item.$.source.textContent.trim());
-      // Test whether the load path is displayed for unpacked extensions.
-      assertTrue(isVisible(item, '#load-path'));
-
-      item.set('data.location', 'UNKNOWN');
-      item.set('data.prettifiedPath', '');
-      // |locationText| is expected to always be set if location is UNKNOWN.
-      item.set('data.locationText', 'Foo');
-      flush();
-      assertEquals('Foo', item.$.source.textContent.trim());
-      assertFalse(isVisible(item, '#load-path'));
-    });
-
-    test(
-        assert(extension_detail_view_tests.TestNames.ClickableElements),
-        function() {
-          const optionsUrl =
-              'chrome-extension://' + extensionData.id + '/options.html';
-          item.set('data.optionsPage', {openInTab: true, url: optionsUrl});
-          item.set('data.prettifiedPath', 'foo/bar/baz/');
-          item.set('showActivityLog', true);
-          flush();
-
-          let currentPage = null;
-          navigation.addListener(newPage => {
-            currentPage = newPage;
-          });
-
-          // Even though the command line flag is not set for activity log, we
-          // still expect to navigate to it after clicking the link as the logic
-          // to redirect the page back to the details view is in manager.js. Since
-          // this behavior does not happen in the testing environment, we test the
-          // behavior in manager_test.js.
-          item.$$('#extensionsActivityLogLink').click();
-          expectDeepEquals(
-              currentPage,
-              {page: Page.ACTIVITY_LOG, extensionId: extensionData.id});
-
-          // Reset current page and test delegate calls.
-          navigation.navigateTo(
-              {page: Page.DETAILS, extensionId: extensionData.id});
-          currentPage = null;
-
-          mockDelegate.testClickingCalls(
-              item.$$('#allow-incognito').getLabel(), 'setItemAllowedIncognito',
-              [extensionData.id, true]);
-          mockDelegate.testClickingCalls(
-              item.$$('#allow-on-file-urls').getLabel(),
-              'setItemAllowedOnFileUrls', [extensionData.id, true]);
-          mockDelegate.testClickingCalls(
-              item.$$('#collect-errors').getLabel(), 'setItemCollectsErrors',
-              [extensionData.id, true]);
-          mockDelegate.testClickingCalls(
-              item.$$('#extensions-options'), 'showItemOptionsPage',
-              [extensionData]);
-          mockDelegate.testClickingCalls(
-              item.$$('#remove-extension'), 'deleteItem', [extensionData.id]);
-          mockDelegate.testClickingCalls(
-              item.$$('#load-path > a[is=\'action-link\']'), 'showInFolder',
-              [extensionData.id]);
-          mockDelegate.testClickingCalls(
-              item.$$('#warnings-reload-button'), 'reloadItem',
-              [extensionData.id], Promise.resolve());
-
-          // Terminate the extension so the reload button appears.
-          item.set(
-              'data.state', chrome.developerPrivate.ExtensionState.TERMINATED);
-          flush();
-          mockDelegate.testClickingCalls(
-              item.$$('#terminated-reload-button'), 'reloadItem',
-              [extensionData.id], Promise.resolve());
+        let currentPage = null;
+        navigation.addListener(newPage => {
+          currentPage = newPage;
         });
 
-    test(assert(extension_detail_view_tests.TestNames.Indicator), function() {
-      const indicator = item.$$('cr-tooltip-icon');
-      expectTrue(indicator.hidden);
-      item.set('data.controlledInfo', {type: 'POLICY', text: 'policy'});
-      flush();
-      expectFalse(indicator.hidden);
-    });
+        // Even though the command line flag is not set for activity log, we
+        // still expect to navigate to it after clicking the link as the logic
+        // to redirect the page back to the details view is in manager.js. Since
+        // this behavior does not happen in the testing environment, we test the
+        // behavior in manager_test.js.
+        item.$$('#extensionsActivityLogLink').click();
+        expectDeepEquals(
+            currentPage,
+            {page: Page.ACTIVITY_LOG, extensionId: extensionData.id});
 
-    test(assert(extension_detail_view_tests.TestNames.Warnings), function() {
-      const testWarningVisible = function(id, expectVisible) {
-        const f = expectVisible ? expectTrue : expectFalse;
-        f(isVisible(item, id));
-      };
+        // Reset current page and test delegate calls.
+        navigation.navigateTo(
+            {page: Page.DETAILS, extensionId: extensionData.id});
+        currentPage = null;
 
-      testWarningVisible('#runtime-warnings', false);
-      testWarningVisible('#corrupted-warning', false);
-      testWarningVisible('#suspicious-warning', false);
-      testWarningVisible('#blacklisted-warning', false);
-      testWarningVisible('#update-required-warning', false);
+        mockDelegate.testClickingCalls(
+            item.$$('#allow-incognito').getLabel(), 'setItemAllowedIncognito',
+            [extensionData.id, true]);
+        mockDelegate.testClickingCalls(
+            item.$$('#allow-on-file-urls').getLabel(),
+            'setItemAllowedOnFileUrls', [extensionData.id, true]);
+        mockDelegate.testClickingCalls(
+            item.$$('#collect-errors').getLabel(), 'setItemCollectsErrors',
+            [extensionData.id, true]);
+        mockDelegate.testClickingCalls(
+            item.$$('#extensions-options'), 'showItemOptionsPage',
+            [extensionData]);
+        mockDelegate.testClickingCalls(
+            item.$$('#remove-extension'), 'deleteItem', [extensionData.id]);
+        mockDelegate.testClickingCalls(
+            item.$$('#load-path > a[is=\'action-link\']'), 'showInFolder',
+            [extensionData.id]);
+        mockDelegate.testClickingCalls(
+            item.$$('#warnings-reload-button'), 'reloadItem',
+            [extensionData.id], Promise.resolve());
 
-      item.set('data.runtimeWarnings', ['Dummy warning']);
-      flush();
-      testWarningVisible('#runtime-warnings', true);
-      testWarningVisible('#corrupted-warning', false);
-      testWarningVisible('#suspicious-warning', false);
-      testWarningVisible('#blacklisted-warning', false);
-      testWarningVisible('#update-required-warning', false);
+        // Terminate the extension so the reload button appears.
+        item.set(
+            'data.state', chrome.developerPrivate.ExtensionState.TERMINATED);
+        flush();
+        mockDelegate.testClickingCalls(
+            item.$$('#terminated-reload-button'), 'reloadItem',
+            [extensionData.id], Promise.resolve());
+      });
 
-      item.set('data.disableReasons.corruptInstall', true);
-      flush();
-      testWarningVisible('#runtime-warnings', true);
-      testWarningVisible('#corrupted-warning', true);
-      testWarningVisible('#suspicious-warning', false);
-      testWarningVisible('#blacklisted-warning', false);
-      testWarningVisible('#update-required-warning', false);
-
-      item.set('data.disableReasons.suspiciousInstall', true);
-      flush();
-      testWarningVisible('#runtime-warnings', true);
-      testWarningVisible('#corrupted-warning', true);
-      testWarningVisible('#suspicious-warning', true);
-      testWarningVisible('#blacklisted-warning', false);
-      testWarningVisible('#update-required-warning', false);
-
-      item.set('data.blacklistText', 'This item is blacklisted');
-      flush();
-      testWarningVisible('#runtime-warnings', true);
-      testWarningVisible('#corrupted-warning', true);
-      testWarningVisible('#suspicious-warning', true);
-      testWarningVisible('#blacklisted-warning', true);
-      testWarningVisible('#update-required-warning', false);
-
-      item.set('data.blacklistText', null);
-      flush();
-      testWarningVisible('#runtime-warnings', true);
-      testWarningVisible('#corrupted-warning', true);
-      testWarningVisible('#suspicious-warning', true);
-      testWarningVisible('#blacklisted-warning', false);
-      testWarningVisible('#update-required-warning', false);
-
-      item.set('data.disableReasons.updateRequired', true);
-      flush();
-      testWarningVisible('#runtime-warnings', true);
-      testWarningVisible('#corrupted-warning', true);
-      testWarningVisible('#suspicious-warning', true);
-      testWarningVisible('#blacklisted-warning', false);
-      testWarningVisible('#update-required-warning', true);
-
-      item.set('data.runtimeWarnings', []);
-      item.set('data.disableReasons.corruptInstall', false);
-      item.set('data.disableReasons.suspiciousInstall', false);
-      item.set('data.disableReasons.updateRequired', false);
-      flush();
-      testWarningVisible('#runtime-warnings', false);
-      testWarningVisible('#corrupted-warning', false);
-      testWarningVisible('#suspicious-warning', false);
-      testWarningVisible('#blacklisted-warning', false);
-      testWarningVisible('#update-required-warning', false);
-    });
+  test(assert(extension_detail_view_tests.TestNames.Indicator), function() {
+    const indicator = item.$$('cr-tooltip-icon');
+    expectTrue(indicator.hidden);
+    item.set('data.controlledInfo', {type: 'POLICY', text: 'policy'});
+    flush();
+    expectFalse(indicator.hidden);
   });
+
+  test(assert(extension_detail_view_tests.TestNames.Warnings), function() {
+    const testWarningVisible = function(id, expectVisible) {
+      const f = expectVisible ? expectTrue : expectFalse;
+      f(isVisible(item, id));
+    };
+
+    testWarningVisible('#runtime-warnings', false);
+    testWarningVisible('#corrupted-warning', false);
+    testWarningVisible('#suspicious-warning', false);
+    testWarningVisible('#blacklisted-warning', false);
+    testWarningVisible('#update-required-warning', false);
+
+    item.set('data.runtimeWarnings', ['Dummy warning']);
+    flush();
+    testWarningVisible('#runtime-warnings', true);
+    testWarningVisible('#corrupted-warning', false);
+    testWarningVisible('#suspicious-warning', false);
+    testWarningVisible('#blacklisted-warning', false);
+    testWarningVisible('#update-required-warning', false);
+
+    item.set('data.disableReasons.corruptInstall', true);
+    flush();
+    testWarningVisible('#runtime-warnings', true);
+    testWarningVisible('#corrupted-warning', true);
+    testWarningVisible('#suspicious-warning', false);
+    testWarningVisible('#blacklisted-warning', false);
+    testWarningVisible('#update-required-warning', false);
+
+    item.set('data.disableReasons.suspiciousInstall', true);
+    flush();
+    testWarningVisible('#runtime-warnings', true);
+    testWarningVisible('#corrupted-warning', true);
+    testWarningVisible('#suspicious-warning', true);
+    testWarningVisible('#blacklisted-warning', false);
+    testWarningVisible('#update-required-warning', false);
+
+    item.set('data.blacklistText', 'This item is blacklisted');
+    flush();
+    testWarningVisible('#runtime-warnings', true);
+    testWarningVisible('#corrupted-warning', true);
+    testWarningVisible('#suspicious-warning', true);
+    testWarningVisible('#blacklisted-warning', true);
+    testWarningVisible('#update-required-warning', false);
+
+    item.set('data.blacklistText', null);
+    flush();
+    testWarningVisible('#runtime-warnings', true);
+    testWarningVisible('#corrupted-warning', true);
+    testWarningVisible('#suspicious-warning', true);
+    testWarningVisible('#blacklisted-warning', false);
+    testWarningVisible('#update-required-warning', false);
+
+    item.set('data.disableReasons.updateRequired', true);
+    flush();
+    testWarningVisible('#runtime-warnings', true);
+    testWarningVisible('#corrupted-warning', true);
+    testWarningVisible('#suspicious-warning', true);
+    testWarningVisible('#blacklisted-warning', false);
+    testWarningVisible('#update-required-warning', true);
+
+    item.set('data.runtimeWarnings', []);
+    item.set('data.disableReasons.corruptInstall', false);
+    item.set('data.disableReasons.suspiciousInstall', false);
+    item.set('data.disableReasons.updateRequired', false);
+    flush();
+    testWarningVisible('#runtime-warnings', false);
+    testWarningVisible('#corrupted-warning', false);
+    testWarningVisible('#suspicious-warning', false);
+    testWarningVisible('#blacklisted-warning', false);
+    testWarningVisible('#update-required-warning', false);
+  });
+});
diff --git a/chrome/test/data/webui/extensions/error_page_test.js b/chrome/test/data/webui/extensions/error_page_test.js
index 48df47b..b979eed 100644
--- a/chrome/test/data/webui/extensions/error_page_test.js
+++ b/chrome/test/data/webui/extensions/error_page_test.js
@@ -13,195 +13,192 @@
 
 import {ClickMock, createExtensionInfo} from './test_util.js';
 
-  window.extension_error_page_tests = {};
-  extension_error_page_tests.suiteName = 'ExtensionErrorPageTest';
-  /** @enum {string} */
-  extension_error_page_tests.TestNames = {
-    Layout: 'layout',
-    CodeSection: 'code section',
-    ErrorSelection: 'error selection',
+window.extension_error_page_tests = {};
+extension_error_page_tests.suiteName = 'ExtensionErrorPageTest';
+/** @enum {string} */
+extension_error_page_tests.TestNames = {
+  Layout: 'layout',
+  CodeSection: 'code section',
+  ErrorSelection: 'error selection',
+};
+
+/** @implements {ErrorPageDelegate} */
+class MockErrorPageDelegate extends ClickMock {
+  /** @override */
+  deleteErrors(extensionId, errorIds, type) {}
+
+  /** @override */
+  requestFileSource(args) {
+    this.requestFileSourceArgs = args;
+    this.requestFileSourceResolver = new PromiseResolver();
+    return this.requestFileSourceResolver.promise;
+  }
+}
+
+suite(extension_error_page_tests.suiteName, function() {
+  /** @type {chrome.developerPrivate.ExtensionInfo} */
+  let extensionData;
+
+  /** @type {ExtensionsErrorPageElement} */
+  let errorPage;
+
+  /** @type {MockErrorPageDelegate} */
+  let mockDelegate;
+
+  const extensionId = 'a'.repeat(32);
+
+  // Common data for runtime errors.
+  const runtimeErrorBase = {
+    type: chrome.developerPrivate.ErrorType.RUNTIME,
+    extensionId: extensionId,
+    fromIncognito: false,
   };
 
-  /** @implements {ErrorPageDelegate} */
-  class MockErrorPageDelegate extends ClickMock {
-    /** @override */
-    deleteErrors(extensionId, errorIds, type) {}
+  // Common data for manifest errors.
+  const manifestErrorBase = {
+    type: chrome.developerPrivate.ErrorType.MANIFEST,
+    extensionId: extensionId,
+    fromIncognito: false,
+  };
 
-    /** @override */
-    requestFileSource(args) {
-      this.requestFileSourceArgs = args;
-      this.requestFileSourceResolver = new PromiseResolver();
-      return this.requestFileSourceResolver.promise;
-    }
-  }
-
-  suite(extension_error_page_tests.suiteName, function() {
-    /** @type {chrome.developerPrivate.ExtensionInfo} */
-    let extensionData;
-
-    /** @type {ExtensionsErrorPageElement} */
-    let errorPage;
-
-    /** @type {MockErrorPageDelegate} */
-    let mockDelegate;
-
-    const extensionId = 'a'.repeat(32);
-
-    // Common data for runtime errors.
-    const runtimeErrorBase = {
-      type: chrome.developerPrivate.ErrorType.RUNTIME,
-      extensionId: extensionId,
-      fromIncognito: false,
-    };
-
-    // Common data for manifest errors.
-    const manifestErrorBase = {
-      type: chrome.developerPrivate.ErrorType.MANIFEST,
-      extensionId: extensionId,
-      fromIncognito: false,
-    };
-
-    // Initialize an extension item before each test.
-    setup(function() {
-      PolymerTest.clearBody();
-      const runtimeError = Object.assign(
-          {
-            source: 'chrome-extension://' + extensionId + '/source.html',
-            message: 'message',
-            id: 1,
-            severity: chrome.developerPrivate.ErrorLevel.ERROR,
-          },
-          runtimeErrorBase);
-      extensionData = createExtensionInfo({
-        runtimeErrors: [runtimeError],
-        manifestErrors: [],
-      });
-      errorPage = document.createElement('extensions-error-page');
-      mockDelegate = new MockErrorPageDelegate();
-      errorPage.delegate = mockDelegate;
-      errorPage.data = extensionData;
-      document.body.appendChild(errorPage);
+  // Initialize an extension item before each test.
+  setup(function() {
+    PolymerTest.clearBody();
+    const runtimeError = Object.assign(
+        {
+          source: 'chrome-extension://' + extensionId + '/source.html',
+          message: 'message',
+          id: 1,
+          severity: chrome.developerPrivate.ErrorLevel.ERROR,
+        },
+        runtimeErrorBase);
+    extensionData = createExtensionInfo({
+      runtimeErrors: [runtimeError],
+      manifestErrors: [],
     });
-
-    test(assert(extension_error_page_tests.TestNames.Layout), function() {
-      flush();
-
-      const testIsVisible = isVisible.bind(null, errorPage);
-      expectTrue(testIsVisible('#closeButton'));
-      expectTrue(testIsVisible('#heading'));
-      expectTrue(testIsVisible('#errorsList'));
-
-      let errorElements = errorPage.shadowRoot.querySelectorAll('.error-item');
-      expectEquals(1, errorElements.length);
-      let error = errorElements[0];
-      expectEquals(
-          'message', error.querySelector('.error-message').textContent.trim());
-      expectTrue(error.querySelector('iron-icon').icon == 'cr:error');
-
-      const manifestError = Object.assign(
-          {
-            source: 'manifest.json',
-            message: 'invalid key',
-            id: 2,
-            manifestKey: 'permissions',
-          },
-          manifestErrorBase);
-      errorPage.set('data.manifestErrors', [manifestError]);
-      flush();
-      errorElements = errorPage.shadowRoot.querySelectorAll('.error-item');
-      expectEquals(2, errorElements.length);
-      error = errorElements[0];
-      expectEquals(
-          'invalid key',
-          error.querySelector('.error-message').textContent.trim());
-      expectTrue(error.querySelector('iron-icon').icon == 'cr:warning');
-
-      mockDelegate.testClickingCalls(
-          error.querySelector('.icon-delete-gray'), 'deleteErrors',
-          [extensionId, [manifestError.id]]);
-    });
-
-    test(
-        assert(extension_error_page_tests.TestNames.CodeSection),
-        function(done) {
-          flush();
-
-          assertTrue(!!mockDelegate.requestFileSourceArgs);
-          const args = mockDelegate.requestFileSourceArgs;
-          expectEquals(extensionId, args.extensionId);
-          expectEquals('source.html', args.pathSuffix);
-          expectEquals('message', args.message);
-
-          expectTrue(!!mockDelegate.requestFileSourceResolver);
-          const code = {
-            beforeHighlight: 'foo',
-            highlight: 'bar',
-            afterHighlight: 'baz',
-            message: 'quu',
-          };
-          mockDelegate.requestFileSourceResolver.resolve(code);
-          mockDelegate.requestFileSourceResolver.promise.then(function() {
-            flush();
-            expectEquals(code, errorPage.$$('extensions-code-section').code);
-            done();
-          });
-        });
-
-    test(assert(extension_error_page_tests.TestNames.ErrorSelection),
-        function() {
-      const nextRuntimeError = Object.assign(
-          {
-            source: 'chrome-extension://' + extensionId + '/other_source.html',
-            message: 'Other error',
-            id: 2,
-            severity: chrome.developerPrivate.ErrorLevel.ERROR,
-            renderProcessId: 111,
-            renderViewId: 222,
-            canInspect: true,
-            contextUrl: 'http://test.com',
-            stackTrace: [{url: 'url', lineNumber: 123, columnNumber: 321}],
-          },
-          runtimeErrorBase);
-      // Add a new runtime error to the end.
-      errorPage.push('data.runtimeErrors', nextRuntimeError);
-      flush();
-
-      const errorElements =
-          errorPage.shadowRoot.querySelectorAll('.error-item .start');
-      const ironCollapses =
-          errorPage.shadowRoot.querySelectorAll('iron-collapse');
-      expectEquals(2, errorElements.length);
-      expectEquals(2, ironCollapses.length);
-
-      // The first error should be focused by default, and we should have
-      // requested the source for it.
-      expectEquals(
-          extensionData.runtimeErrors[0], errorPage.getSelectedError());
-      expectTrue(!!mockDelegate.requestFileSourceArgs);
-      let args = mockDelegate.requestFileSourceArgs;
-      expectEquals('source.html', args.pathSuffix);
-      expectTrue(ironCollapses[0].opened);
-      expectFalse(ironCollapses[1].opened);
-      mockDelegate.requestFileSourceResolver.resolve(null);
-
-      mockDelegate.requestFileSourceResolver = new PromiseResolver();
-      mockDelegate.requestFileSourceArgs = undefined;
-
-      // Tap the second error. It should now be selected and we should request
-      // the source for it.
-      errorElements[1].click();
-      expectEquals(nextRuntimeError, errorPage.getSelectedError());
-      expectTrue(!!mockDelegate.requestFileSourceArgs);
-      args = mockDelegate.requestFileSourceArgs;
-      expectEquals('other_source.html', args.pathSuffix);
-      expectTrue(ironCollapses[1].opened);
-      expectFalse(ironCollapses[0].opened);
-
-      expectEquals(
-          'Unknown',
-          ironCollapses[0].querySelector('.context-url').textContent.trim());
-      expectEquals(
-          nextRuntimeError.contextUrl,
-          ironCollapses[1].querySelector('.context-url').textContent.trim());
-    });
+    errorPage = document.createElement('extensions-error-page');
+    mockDelegate = new MockErrorPageDelegate();
+    errorPage.delegate = mockDelegate;
+    errorPage.data = extensionData;
+    document.body.appendChild(errorPage);
   });
+
+  test(assert(extension_error_page_tests.TestNames.Layout), function() {
+    flush();
+
+    const testIsVisible = isVisible.bind(null, errorPage);
+    expectTrue(testIsVisible('#closeButton'));
+    expectTrue(testIsVisible('#heading'));
+    expectTrue(testIsVisible('#errorsList'));
+
+    let errorElements = errorPage.shadowRoot.querySelectorAll('.error-item');
+    expectEquals(1, errorElements.length);
+    let error = errorElements[0];
+    expectEquals(
+        'message', error.querySelector('.error-message').textContent.trim());
+    expectTrue(error.querySelector('iron-icon').icon == 'cr:error');
+
+    const manifestError = Object.assign(
+        {
+          source: 'manifest.json',
+          message: 'invalid key',
+          id: 2,
+          manifestKey: 'permissions',
+        },
+        manifestErrorBase);
+    errorPage.set('data.manifestErrors', [manifestError]);
+    flush();
+    errorElements = errorPage.shadowRoot.querySelectorAll('.error-item');
+    expectEquals(2, errorElements.length);
+    error = errorElements[0];
+    expectEquals(
+        'invalid key',
+        error.querySelector('.error-message').textContent.trim());
+    expectTrue(error.querySelector('iron-icon').icon == 'cr:warning');
+
+    mockDelegate.testClickingCalls(
+        error.querySelector('.icon-delete-gray'), 'deleteErrors',
+        [extensionId, [manifestError.id]]);
+  });
+
+  test(
+      assert(extension_error_page_tests.TestNames.CodeSection), function(done) {
+        flush();
+
+        assertTrue(!!mockDelegate.requestFileSourceArgs);
+        const args = mockDelegate.requestFileSourceArgs;
+        expectEquals(extensionId, args.extensionId);
+        expectEquals('source.html', args.pathSuffix);
+        expectEquals('message', args.message);
+
+        expectTrue(!!mockDelegate.requestFileSourceResolver);
+        const code = {
+          beforeHighlight: 'foo',
+          highlight: 'bar',
+          afterHighlight: 'baz',
+          message: 'quu',
+        };
+        mockDelegate.requestFileSourceResolver.resolve(code);
+        mockDelegate.requestFileSourceResolver.promise.then(function() {
+          flush();
+          expectEquals(code, errorPage.$$('extensions-code-section').code);
+          done();
+        });
+      });
+
+  test(assert(extension_error_page_tests.TestNames.ErrorSelection), function() {
+    const nextRuntimeError = Object.assign(
+        {
+          source: 'chrome-extension://' + extensionId + '/other_source.html',
+          message: 'Other error',
+          id: 2,
+          severity: chrome.developerPrivate.ErrorLevel.ERROR,
+          renderProcessId: 111,
+          renderViewId: 222,
+          canInspect: true,
+          contextUrl: 'http://test.com',
+          stackTrace: [{url: 'url', lineNumber: 123, columnNumber: 321}],
+        },
+        runtimeErrorBase);
+    // Add a new runtime error to the end.
+    errorPage.push('data.runtimeErrors', nextRuntimeError);
+    flush();
+
+    const errorElements =
+        errorPage.shadowRoot.querySelectorAll('.error-item .start');
+    const ironCollapses =
+        errorPage.shadowRoot.querySelectorAll('iron-collapse');
+    expectEquals(2, errorElements.length);
+    expectEquals(2, ironCollapses.length);
+
+    // The first error should be focused by default, and we should have
+    // requested the source for it.
+    expectEquals(extensionData.runtimeErrors[0], errorPage.getSelectedError());
+    expectTrue(!!mockDelegate.requestFileSourceArgs);
+    let args = mockDelegate.requestFileSourceArgs;
+    expectEquals('source.html', args.pathSuffix);
+    expectTrue(ironCollapses[0].opened);
+    expectFalse(ironCollapses[1].opened);
+    mockDelegate.requestFileSourceResolver.resolve(null);
+
+    mockDelegate.requestFileSourceResolver = new PromiseResolver();
+    mockDelegate.requestFileSourceArgs = undefined;
+
+    // Tap the second error. It should now be selected and we should request
+    // the source for it.
+    errorElements[1].click();
+    expectEquals(nextRuntimeError, errorPage.getSelectedError());
+    expectTrue(!!mockDelegate.requestFileSourceArgs);
+    args = mockDelegate.requestFileSourceArgs;
+    expectEquals('other_source.html', args.pathSuffix);
+    expectTrue(ironCollapses[1].opened);
+    expectFalse(ironCollapses[0].opened);
+
+    expectEquals(
+        'Unknown',
+        ironCollapses[0].querySelector('.context-url').textContent.trim());
+    expectEquals(
+        nextRuntimeError.contextUrl,
+        ironCollapses[1].querySelector('.context-url').textContent.trim());
+  });
+});
diff --git a/chrome/test/data/webui/extensions/item_list_test.js b/chrome/test/data/webui/extensions/item_list_test.js
index 3b95cbd..8d867cab 100644
--- a/chrome/test/data/webui/extensions/item_list_test.js
+++ b/chrome/test/data/webui/extensions/item_list_test.js
@@ -10,110 +10,109 @@
 import {flush} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
 import {createExtensionInfo, testVisible} from './test_util.js';
 
-  window.extension_item_list_tests = {};
-  extension_item_list_tests.suiteName = 'ExtensionItemListTest';
-  /** @enum {string} */
-  extension_item_list_tests.TestNames = {
-    Filtering: 'item list filtering',
-    NoItemsMsg: 'empty item list',
-    NoSearchResultsMsg: 'empty item list filtering results',
-    LoadTimeData: 'loadTimeData contains isManaged and managedByOrg',
-  };
+window.extension_item_list_tests = {};
+extension_item_list_tests.suiteName = 'ExtensionItemListTest';
+/** @enum {string} */
+extension_item_list_tests.TestNames = {
+  Filtering: 'item list filtering',
+  NoItemsMsg: 'empty item list',
+  NoSearchResultsMsg: 'empty item list filtering results',
+  LoadTimeData: 'loadTimeData contains isManaged and managedByOrg',
+};
 
-  suite(extension_item_list_tests.suiteName, function() {
-    /** @type {extensions.ItemList} */
-    let itemList;
-    let boundTestVisible;
+suite(extension_item_list_tests.suiteName, function() {
+  /** @type {extensions.ItemList} */
+  let itemList;
+  let boundTestVisible;
 
-    // Initialize an extension item before each test.
-    setup(function() {
-      PolymerTest.clearBody();
-      itemList = document.createElement('extensions-item-list');
-      boundTestVisible = testVisible.bind(null, itemList);
+  // Initialize an extension item before each test.
+  setup(function() {
+    PolymerTest.clearBody();
+    itemList = document.createElement('extensions-item-list');
+    boundTestVisible = testVisible.bind(null, itemList);
 
-      const createExt = createExtensionInfo;
-      const extensionItems = [
-        createExt({name: 'Alpha', id: 'a'.repeat(32)}),
-        createExt({name: 'Bravo', id: 'b'.repeat(32)}),
-        createExt({name: 'Charlie', id: 'c'.repeat(32)})
-      ];
-      const appItems = [
-        createExt({name: 'QQ', id: 'q'.repeat(32)}),
-      ];
-      itemList.extensions = extensionItems;
-      itemList.apps = appItems;
-      itemList.filter = '';
-      document.body.appendChild(itemList);
-    });
-
-    test(assert(extension_item_list_tests.TestNames.Filtering), function() {
-      function itemLengthEquals(num) {
-        flush();
-        expectEquals(
-            itemList.shadowRoot.querySelectorAll('extensions-item').length,
-            num);
-      }
-
-      // We should initially show all the items.
-      itemLengthEquals(4);
-
-      // All extension items have an 'a'.
-      itemList.filter = 'a';
-      itemLengthEquals(3);
-      // Filtering is case-insensitive, so all extension items should be shown.
-      itemList.filter = 'A';
-      itemLengthEquals(3);
-      // Only 'Bravo' has a 'b'.
-      itemList.filter = 'b';
-      itemLengthEquals(1);
-      expectEquals('Bravo', itemList.$$('extensions-item').data.name);
-      // Test inner substring (rather than prefix).
-      itemList.filter = 'lph';
-      itemLengthEquals(1);
-      expectEquals('Alpha', itemList.$$('extensions-item').data.name);
-      // Test trailing/leading spaces.
-      itemList.filter = '   Alpha  ';
-      itemLengthEquals(1);
-      expectEquals('Alpha', itemList.$$('extensions-item').data.name);
-      // Test string with no matching items.
-      itemList.filter = 'z';
-      itemLengthEquals(0);
-      // A filter of '' should reset to show all items.
-      itemList.filter = '';
-      itemLengthEquals(4);
-      // A filter of 'q' should should show just the apps item.
-      itemList.filter = 'q';
-      itemLengthEquals(1);
-    });
-
-    test(assert(extension_item_list_tests.TestNames.NoItemsMsg), function() {
-      flush();
-      boundTestVisible('#no-items', false);
-      boundTestVisible('#no-search-results', false);
-
-      itemList.extensions = [];
-      itemList.apps = [];
-      flush();
-      boundTestVisible('#no-items', true);
-      boundTestVisible('#no-search-results', false);
-    });
-
-    test(
-        assert(extension_item_list_tests.TestNames.NoSearchResultsMsg),
-        function() {
-          flush();
-          boundTestVisible('#no-items', false);
-          boundTestVisible('#no-search-results', false);
-
-          itemList.filter = 'non-existent name';
-          flush();
-          boundTestVisible('#no-items', false);
-          boundTestVisible('#no-search-results', true);
-        });
-
-    test(assert(extension_item_list_tests.TestNames.LoadTimeData), function() {
-      // Check that loadTimeData contains these values.
-      loadTimeData.getBoolean('isManaged');
-      loadTimeData.getString('browserManagedByOrg');
-    });
+    const createExt = createExtensionInfo;
+    const extensionItems = [
+      createExt({name: 'Alpha', id: 'a'.repeat(32)}),
+      createExt({name: 'Bravo', id: 'b'.repeat(32)}),
+      createExt({name: 'Charlie', id: 'c'.repeat(32)})
+    ];
+    const appItems = [
+      createExt({name: 'QQ', id: 'q'.repeat(32)}),
+    ];
+    itemList.extensions = extensionItems;
+    itemList.apps = appItems;
+    itemList.filter = '';
+    document.body.appendChild(itemList);
   });
+
+  test(assert(extension_item_list_tests.TestNames.Filtering), function() {
+    function itemLengthEquals(num) {
+      flush();
+      expectEquals(
+          itemList.shadowRoot.querySelectorAll('extensions-item').length, num);
+    }
+
+    // We should initially show all the items.
+    itemLengthEquals(4);
+
+    // All extension items have an 'a'.
+    itemList.filter = 'a';
+    itemLengthEquals(3);
+    // Filtering is case-insensitive, so all extension items should be shown.
+    itemList.filter = 'A';
+    itemLengthEquals(3);
+    // Only 'Bravo' has a 'b'.
+    itemList.filter = 'b';
+    itemLengthEquals(1);
+    expectEquals('Bravo', itemList.$$('extensions-item').data.name);
+    // Test inner substring (rather than prefix).
+    itemList.filter = 'lph';
+    itemLengthEquals(1);
+    expectEquals('Alpha', itemList.$$('extensions-item').data.name);
+    // Test trailing/leading spaces.
+    itemList.filter = '   Alpha  ';
+    itemLengthEquals(1);
+    expectEquals('Alpha', itemList.$$('extensions-item').data.name);
+    // Test string with no matching items.
+    itemList.filter = 'z';
+    itemLengthEquals(0);
+    // A filter of '' should reset to show all items.
+    itemList.filter = '';
+    itemLengthEquals(4);
+    // A filter of 'q' should should show just the apps item.
+    itemList.filter = 'q';
+    itemLengthEquals(1);
+  });
+
+  test(assert(extension_item_list_tests.TestNames.NoItemsMsg), function() {
+    flush();
+    boundTestVisible('#no-items', false);
+    boundTestVisible('#no-search-results', false);
+
+    itemList.extensions = [];
+    itemList.apps = [];
+    flush();
+    boundTestVisible('#no-items', true);
+    boundTestVisible('#no-search-results', false);
+  });
+
+  test(
+      assert(extension_item_list_tests.TestNames.NoSearchResultsMsg),
+      function() {
+        flush();
+        boundTestVisible('#no-items', false);
+        boundTestVisible('#no-search-results', false);
+
+        itemList.filter = 'non-existent name';
+        flush();
+        boundTestVisible('#no-items', false);
+        boundTestVisible('#no-search-results', true);
+      });
+
+  test(assert(extension_item_list_tests.TestNames.LoadTimeData), function() {
+    // Check that loadTimeData contains these values.
+    loadTimeData.getBoolean('isManaged');
+    loadTimeData.getString('browserManagedByOrg');
+  });
+});
diff --git a/chrome/test/data/webui/extensions/item_test.js b/chrome/test/data/webui/extensions/item_test.js
index c5fdce4..6ccf944 100644
--- a/chrome/test/data/webui/extensions/item_test.js
+++ b/chrome/test/data/webui/extensions/item_test.js
@@ -14,342 +14,341 @@
 import {TestService} from './test_service.js';
 import {createExtensionInfo, MockItemDelegate, testVisible} from './test_util.js';
 
+/**
+ * The data used to populate the extension item.
+ * @type {chrome.developerPrivate.ExtensionInfo}
+ */
+const extensionData = createExtensionInfo();
+
+// The normal elements, which should always be shown.
+const normalElements = [
+  {selector: '#name', text: extensionData.name},
+  {selector: '#icon'},
+  {selector: '#description', text: extensionData.description},
+  {selector: '#enable-toggle'},
+  {selector: '#detailsButton'},
+  {selector: '#remove-button'},
+];
+// The developer elements, which should only be shown if in developer
+// mode *and* showing details.
+const devElements = [
+  {selector: '#version', text: extensionData.version},
+  {selector: '#extension-id', text: `ID: ${extensionData.id}`},
+  {selector: '#inspect-views'},
+  {selector: '#inspect-views a[is="action-link"]', text: 'foo.html,'},
+  {
+    selector: '#inspect-views a[is="action-link"]:nth-of-type(2)',
+    text: '1 more…'
+  },
+];
+
+/**
+ * Tests that the elements' visibility matches the expected visibility.
+ * @param {Item} item
+ * @param {Array<Object<string>>} elements
+ * @param {boolean} visibility
+ */
+function testElementsVisibility(item, elements, visibility) {
+  elements.forEach(function(element) {
+    testVisible(item, element.selector, visibility, element.text);
+  });
+}
+
+/** Tests that normal elements are visible. */
+function testNormalElementsAreVisible(item) {
+  testElementsVisibility(item, normalElements, true);
+}
+
+/** Tests that normal elements are hidden. */
+function testNormalElementsAreHidden(item) {
+  testElementsVisibility(item, normalElements, false);
+}
+
+/** Tests that dev elements are visible. */
+function testDeveloperElementsAreVisible(item) {
+  testElementsVisibility(item, devElements, true);
+}
+
+/** Tests that dev elements are hidden. */
+function testDeveloperElementsAreHidden(item) {
+  testElementsVisibility(item, devElements, false);
+}
+
+window.extension_item_tests = {};
+extension_item_tests.suiteName = 'ExtensionItemTest';
+/** @enum {string} */
+extension_item_tests.TestNames = {
+  ElementVisibilityNormalState: 'element visibility: normal state',
+  ElementVisibilityDeveloperState:
+      'element visibility: after enabling developer mode',
+  ClickableItems: 'clickable items',
+  FailedReloadFiresLoadError: 'failed reload fires load error',
+  Warnings: 'warnings',
+  SourceIndicator: 'source indicator',
+  EnableToggle: 'toggle is disabled when necessary',
+  RemoveButton: 'remove button hidden when necessary',
+  HtmlInName: 'html in extension name',
+};
+
+suite(extension_item_tests.suiteName, function() {
   /**
-   * The data used to populate the extension item.
-   * @type {chrome.developerPrivate.ExtensionInfo}
+   * Extension item created before each test.
+   * @type {Item}
    */
-  const extensionData = createExtensionInfo();
+  let item;
 
-  // The normal elements, which should always be shown.
-  const normalElements = [
-    {selector: '#name', text: extensionData.name},
-    {selector: '#icon'},
-    {selector: '#description', text: extensionData.description},
-    {selector: '#enable-toggle'},
-    {selector: '#detailsButton'},
-    {selector: '#remove-button'},
-  ];
-  // The developer elements, which should only be shown if in developer
-  // mode *and* showing details.
-  const devElements = [
-    {selector: '#version', text: extensionData.version},
-    {selector: '#extension-id', text: `ID: ${extensionData.id}`},
-    {selector: '#inspect-views'},
-    {selector: '#inspect-views a[is="action-link"]', text: 'foo.html,'},
-    {
-      selector: '#inspect-views a[is="action-link"]:nth-of-type(2)',
-      text: '1 more…'
-    },
-  ];
+  /** @type {MockItemDelegate} */
+  let mockDelegate;
 
-  /**
-   * Tests that the elements' visibility matches the expected visibility.
-   * @param {Item} item
-   * @param {Array<Object<string>>} elements
-   * @param {boolean} visibility
-   */
-  function testElementsVisibility(item, elements, visibility) {
-    elements.forEach(function(element) {
-      testVisible(item, element.selector, visibility, element.text);
-    });
-  }
+  // Initialize an extension item before each test.
+  setup(function() {
+    PolymerTest.clearBody();
+    mockDelegate = new MockItemDelegate();
+    item = document.createElement('extensions-item');
+    item.data = createExtensionInfo();
+    item.delegate = mockDelegate;
+    document.body.appendChild(item);
+    const toastManager = document.createElement('cr-toast-manager');
+    document.body.appendChild(toastManager);
+  });
 
-  /** Tests that normal elements are visible. */
-  function testNormalElementsAreVisible(item) {
-    testElementsVisibility(item, normalElements, true);
-  }
+  test(
+      assert(extension_item_tests.TestNames.ElementVisibilityNormalState),
+      function() {
+        testNormalElementsAreVisible(item);
+        testDeveloperElementsAreHidden(item);
 
-  /** Tests that normal elements are hidden. */
-  function testNormalElementsAreHidden(item) {
-    testElementsVisibility(item, normalElements, false);
-  }
-
-  /** Tests that dev elements are visible. */
-  function testDeveloperElementsAreVisible(item) {
-    testElementsVisibility(item, devElements, true);
-  }
-
-  /** Tests that dev elements are hidden. */
-  function testDeveloperElementsAreHidden(item) {
-    testElementsVisibility(item, devElements, false);
-  }
-
-  window.extension_item_tests = {};
-  extension_item_tests.suiteName = 'ExtensionItemTest';
-  /** @enum {string} */
-  extension_item_tests.TestNames = {
-    ElementVisibilityNormalState: 'element visibility: normal state',
-    ElementVisibilityDeveloperState:
-        'element visibility: after enabling developer mode',
-    ClickableItems: 'clickable items',
-    FailedReloadFiresLoadError: 'failed reload fires load error',
-    Warnings: 'warnings',
-    SourceIndicator: 'source indicator',
-    EnableToggle: 'toggle is disabled when necessary',
-    RemoveButton: 'remove button hidden when necessary',
-    HtmlInName: 'html in extension name',
-  };
-
-  suite(extension_item_tests.suiteName, function() {
-    /**
-     * Extension item created before each test.
-     * @type {Item}
-     */
-    let item;
-
-    /** @type {MockItemDelegate} */
-    let mockDelegate;
-
-    // Initialize an extension item before each test.
-    setup(function() {
-      PolymerTest.clearBody();
-      mockDelegate = new MockItemDelegate();
-      item = document.createElement('extensions-item');
-      item.data = createExtensionInfo();
-      item.delegate = mockDelegate;
-      document.body.appendChild(item);
-      const toastManager = document.createElement('cr-toast-manager');
-      document.body.appendChild(toastManager);
-    });
-
-    test(
-        assert(extension_item_tests.TestNames.ElementVisibilityNormalState),
-        function() {
-          testNormalElementsAreVisible(item);
-          testDeveloperElementsAreHidden(item);
-
-          expectTrue(item.$['enable-toggle'].checked);
-          item.set('data.state', 'DISABLED');
-          expectFalse(item.$['enable-toggle'].checked);
-          item.set('data.state', 'BLACKLISTED');
-          expectFalse(item.$['enable-toggle'].checked);
-        });
-
-    test(
-        assert(extension_item_tests.TestNames.ElementVisibilityDeveloperState),
-        function() {
-          item.set('inDevMode', true);
-
-          testNormalElementsAreVisible(item);
-          testDeveloperElementsAreVisible(item);
-
-          // Developer reload button should be visible only for enabled unpacked
-          // extensions.
-          testVisible(item, '#dev-reload-button', false);
-
-          item.set('data.location', chrome.developerPrivate.Location.UNPACKED);
-          flush();
-          testVisible(item, '#dev-reload-button', true);
-
-          item.set('data.state', chrome.developerPrivate.ExtensionState.DISABLED);
-          flush();
-          testVisible(item, '#dev-reload-button', false);
-
-          item.set(
-              'data.state', chrome.developerPrivate.ExtensionState.TERMINATED);
-          flush();
-          testVisible(item, '#dev-reload-button', false);
-        });
-
-    /** Tests that the delegate methods are correctly called. */
-    test(assert(extension_item_tests.TestNames.ClickableItems), function() {
-      item.set('inDevMode', true);
-
-      mockDelegate.testClickingCalls(
-          item.$['remove-button'], 'deleteItem', [item.data.id]);
-      mockDelegate.testClickingCalls(
-          item.$['enable-toggle'], 'setItemEnabled', [item.data.id, false]);
-      mockDelegate.testClickingCalls(
-          item.$$('#inspect-views a[is="action-link"]'), 'inspectItemView',
-          [item.data.id, item.data.views[0]]);
-
-      // Setup for testing navigation buttons.
-      let currentPage = null;
-      navigation.addListener(newPage => {
-        currentPage = newPage;
+        expectTrue(item.$['enable-toggle'].checked);
+        item.set('data.state', 'DISABLED');
+        expectFalse(item.$['enable-toggle'].checked);
+        item.set('data.state', 'BLACKLISTED');
+        expectFalse(item.$['enable-toggle'].checked);
       });
 
-      tap(item.$$('#detailsButton'));
-      expectDeepEquals(
-          currentPage, {page: Page.DETAILS, extensionId: item.data.id});
+  test(
+      assert(extension_item_tests.TestNames.ElementVisibilityDeveloperState),
+      function() {
+        item.set('inDevMode', true);
 
-      // Reset current page and test inspect-view navigation.
-      navigation.navigateTo({page: Page.LIST});
-      currentPage = null;
-      tap(item.$$('#inspect-views a[is="action-link"]:nth-of-type(2)'));
-      expectDeepEquals(
-          currentPage, {page: Page.DETAILS, extensionId: item.data.id});
+        testNormalElementsAreVisible(item);
+        testDeveloperElementsAreVisible(item);
 
-      item.set('data.disableReasons.corruptInstall', true);
-      flush();
-      mockDelegate.testClickingCalls(
-          item.$$('#repair-button'), 'repairItem', [item.data.id]);
+        // Developer reload button should be visible only for enabled unpacked
+        // extensions.
+        testVisible(item, '#dev-reload-button', false);
 
-      item.set('data.state', chrome.developerPrivate.ExtensionState.TERMINATED);
-      flush();
-      mockDelegate.testClickingCalls(
-          item.$$('#terminated-reload-button'), 'reloadItem', [item.data.id],
-          Promise.resolve());
+        item.set('data.location', chrome.developerPrivate.Location.UNPACKED);
+        flush();
+        testVisible(item, '#dev-reload-button', true);
 
-      item.set('data.location', chrome.developerPrivate.Location.UNPACKED);
-      item.set('data.state', chrome.developerPrivate.ExtensionState.ENABLED);
-      flush();
+        item.set('data.state', chrome.developerPrivate.ExtensionState.DISABLED);
+        flush();
+        testVisible(item, '#dev-reload-button', false);
+
+        item.set(
+            'data.state', chrome.developerPrivate.ExtensionState.TERMINATED);
+        flush();
+        testVisible(item, '#dev-reload-button', false);
+      });
+
+  /** Tests that the delegate methods are correctly called. */
+  test(assert(extension_item_tests.TestNames.ClickableItems), function() {
+    item.set('inDevMode', true);
+
+    mockDelegate.testClickingCalls(
+        item.$['remove-button'], 'deleteItem', [item.data.id]);
+    mockDelegate.testClickingCalls(
+        item.$['enable-toggle'], 'setItemEnabled', [item.data.id, false]);
+    mockDelegate.testClickingCalls(
+        item.$$('#inspect-views a[is="action-link"]'), 'inspectItemView',
+        [item.data.id, item.data.views[0]]);
+
+    // Setup for testing navigation buttons.
+    let currentPage = null;
+    navigation.addListener(newPage => {
+      currentPage = newPage;
     });
 
-    /** Tests that the reload button properly fires the load-error event. */
-    test(
-        assert(extension_item_tests.TestNames.FailedReloadFiresLoadError),
-        function() {
-          item.set('inDevMode', true);
-          item.set('data.location', chrome.developerPrivate.Location.UNPACKED);
-          flush();
-          testVisible(item, '#dev-reload-button', true);
+    tap(item.$$('#detailsButton'));
+    expectDeepEquals(
+        currentPage, {page: Page.DETAILS, extensionId: item.data.id});
 
-          // Check clicking the reload button. The reload button should fire a
-          // load-error event if and only if the reload fails (indicated by a
-          // rejected promise).
-          // This is a bit of a pain to verify because the promises finish
-          // asynchronously, so we have to use setTimeout()s.
-          let firedLoadError = false;
-          item.addEventListener('load-error', () => {
-            firedLoadError = true;
-          });
+    // Reset current page and test inspect-view navigation.
+    navigation.navigateTo({page: Page.LIST});
+    currentPage = null;
+    tap(item.$$('#inspect-views a[is="action-link"]:nth-of-type(2)'));
+    expectDeepEquals(
+        currentPage, {page: Page.DETAILS, extensionId: item.data.id});
 
-          // This is easier to test with a TestBrowserProxy-style delegate.
-          const proxyDelegate = new TestService();
-          item.delegate = proxyDelegate;
+    item.set('data.disableReasons.corruptInstall', true);
+    flush();
+    mockDelegate.testClickingCalls(
+        item.$$('#repair-button'), 'repairItem', [item.data.id]);
 
-          const verifyEventPromise = function(expectCalled) {
-            return new Promise((resolve, reject) => {
-              setTimeout(() => {
-                expectEquals(expectCalled, firedLoadError);
-                resolve();
-              });
-            });
-          };
+    item.set('data.state', chrome.developerPrivate.ExtensionState.TERMINATED);
+    flush();
+    mockDelegate.testClickingCalls(
+        item.$$('#terminated-reload-button'), 'reloadItem', [item.data.id],
+        Promise.resolve());
 
-          tap(item.$$('#dev-reload-button'));
-          return proxyDelegate.whenCalled('reloadItem')
-              .then(function(id) {
-                expectEquals(item.data.id, id);
-                return verifyEventPromise(false);
-              })
-              .then(function() {
-                proxyDelegate.resetResolver('reloadItem');
-                proxyDelegate.setForceReloadItemError(true);
-                tap(item.$$('#dev-reload-button'));
-                return proxyDelegate.whenCalled('reloadItem');
-              })
-              .then(function(id) {
-                expectEquals(item.data.id, id);
-                return verifyEventPromise(true);
-              });
+    item.set('data.location', chrome.developerPrivate.Location.UNPACKED);
+    item.set('data.state', chrome.developerPrivate.ExtensionState.ENABLED);
+    flush();
+  });
+
+  /** Tests that the reload button properly fires the load-error event. */
+  test(
+      assert(extension_item_tests.TestNames.FailedReloadFiresLoadError),
+      function() {
+        item.set('inDevMode', true);
+        item.set('data.location', chrome.developerPrivate.Location.UNPACKED);
+        flush();
+        testVisible(item, '#dev-reload-button', true);
+
+        // Check clicking the reload button. The reload button should fire a
+        // load-error event if and only if the reload fails (indicated by a
+        // rejected promise).
+        // This is a bit of a pain to verify because the promises finish
+        // asynchronously, so we have to use setTimeout()s.
+        let firedLoadError = false;
+        item.addEventListener('load-error', () => {
+          firedLoadError = true;
         });
 
-    test(assert(extension_item_tests.TestNames.Warnings), function() {
-      const kCorrupt = 1 << 0;
-      const kSuspicious = 1 << 1;
-      const kBlacklisted = 1 << 2;
-      const kRuntime = 1 << 3;
+        // This is easier to test with a TestBrowserProxy-style delegate.
+        const proxyDelegate = new TestService();
+        item.delegate = proxyDelegate;
 
-      function assertWarnings(mask) {
-        assertEquals(
-            !!(mask & kCorrupt), isVisible(item, '#corrupted-warning'));
-        assertEquals(
-            !!(mask & kSuspicious), isVisible(item, '#suspicious-warning'));
-        assertEquals(
-            !!(mask & kBlacklisted), isVisible(item, '#blacklisted-warning'));
-        assertEquals(!!(mask & kRuntime), isVisible(item, '#runtime-warnings'));
-      }
+        const verifyEventPromise = function(expectCalled) {
+          return new Promise((resolve, reject) => {
+            setTimeout(() => {
+              expectEquals(expectCalled, firedLoadError);
+              resolve();
+            });
+          });
+        };
 
-      assertWarnings(0);
+        tap(item.$$('#dev-reload-button'));
+        return proxyDelegate.whenCalled('reloadItem')
+            .then(function(id) {
+              expectEquals(item.data.id, id);
+              return verifyEventPromise(false);
+            })
+            .then(function() {
+              proxyDelegate.resetResolver('reloadItem');
+              proxyDelegate.setForceReloadItemError(true);
+              tap(item.$$('#dev-reload-button'));
+              return proxyDelegate.whenCalled('reloadItem');
+            })
+            .then(function(id) {
+              expectEquals(item.data.id, id);
+              return verifyEventPromise(true);
+            });
+      });
 
-      item.set('data.disableReasons.corruptInstall', true);
-      flush();
-      assertWarnings(kCorrupt);
+  test(assert(extension_item_tests.TestNames.Warnings), function() {
+    const kCorrupt = 1 << 0;
+    const kSuspicious = 1 << 1;
+    const kBlacklisted = 1 << 2;
+    const kRuntime = 1 << 3;
 
-      item.set('data.disableReasons.suspiciousInstall', true);
-      flush();
-      assertWarnings(kCorrupt | kSuspicious);
-
-      item.set('data.blacklistText', 'This item is blacklisted');
-      flush();
-      assertWarnings(kCorrupt | kSuspicious | kBlacklisted);
-
-      item.set('data.blacklistText', null);
-      flush();
-      assertWarnings(kCorrupt | kSuspicious);
-
-      item.set('data.runtimeWarnings', ['Dummy warning']);
-      flush();
-      assertWarnings(kCorrupt | kSuspicious | kRuntime);
-
-      item.set('data.disableReasons.corruptInstall', false);
-      item.set('data.disableReasons.suspiciousInstall', false);
-      item.set('data.runtimeWarnings', []);
-      flush();
-      assertWarnings(0);
-    });
-
-    test(assert(extension_item_tests.TestNames.SourceIndicator), function() {
-      expectFalse(isVisible(item, '#source-indicator'));
-      item.set('data.location', 'UNPACKED');
-      flush();
-      expectTrue(isVisible(item, '#source-indicator'));
-      const icon = item.$$('#source-indicator iron-icon');
-      assertTrue(!!icon);
-      expectEquals('extensions-icons:unpacked', icon.icon);
-
-      item.set('data.location', 'THIRD_PARTY');
-      flush();
-      expectTrue(isVisible(item, '#source-indicator'));
-      expectEquals('extensions-icons:input', icon.icon);
-
-      item.set('data.location', 'UNKNOWN');
-      flush();
-      expectTrue(isVisible(item, '#source-indicator'));
-      expectEquals('extensions-icons:input', icon.icon);
-
-      item.set('data.location', 'FROM_STORE');
-      item.set('data.controlledInfo', {type: 'POLICY', text: 'policy'});
-      flush();
-      expectTrue(isVisible(item, '#source-indicator'));
-      expectEquals('extensions-icons:business', icon.icon);
-
-      item.set('data.controlledInfo', null);
-      flush();
-      expectFalse(isVisible(item, '#source-indicator'));
-    });
-
-    test(assert(extension_item_tests.TestNames.EnableToggle), function() {
-      expectFalse(item.$['enable-toggle'].disabled);
-
-      // Test case where user does not have permission.
-      item.set('data.userMayModify', false);
-      flush();
-      expectTrue(item.$['enable-toggle'].disabled);
-
-      // Test case of a blacklisted extension.
-      item.set('data.userMayModify', true);
-      item.set('data.state', 'BLACKLISTED');
-      flush();
-      expectTrue(item.$['enable-toggle'].disabled);
-    });
-
-    test(assert(extension_item_tests.TestNames.RemoveButton), function() {
-      expectFalse(item.$['remove-button'].hidden);
-      item.set('data.controlledInfo', {type: 'POLICY', text: 'policy'});
-      flush();
-      expectTrue(item.$['remove-button'].hidden);
-    });
-
-    test(assert(extension_item_tests.TestNames.HtmlInName), function() {
-      let name = '<HTML> in the name!';
-      item.set('data.name', name);
-      flush();
-      assertEquals(name, item.$.name.textContent.trim());
-      // "Related to $1" is IDS_MD_EXTENSIONS_EXTENSION_A11Y_ASSOCIATION.
+    function assertWarnings(mask) {
+      assertEquals(!!(mask & kCorrupt), isVisible(item, '#corrupted-warning'));
       assertEquals(
-          `Related to ${name}`, item.$.a11yAssociation.textContent.trim());
-    });
+          !!(mask & kSuspicious), isVisible(item, '#suspicious-warning'));
+      assertEquals(
+          !!(mask & kBlacklisted), isVisible(item, '#blacklisted-warning'));
+      assertEquals(!!(mask & kRuntime), isVisible(item, '#runtime-warnings'));
+    }
+
+    assertWarnings(0);
+
+    item.set('data.disableReasons.corruptInstall', true);
+    flush();
+    assertWarnings(kCorrupt);
+
+    item.set('data.disableReasons.suspiciousInstall', true);
+    flush();
+    assertWarnings(kCorrupt | kSuspicious);
+
+    item.set('data.blacklistText', 'This item is blacklisted');
+    flush();
+    assertWarnings(kCorrupt | kSuspicious | kBlacklisted);
+
+    item.set('data.blacklistText', null);
+    flush();
+    assertWarnings(kCorrupt | kSuspicious);
+
+    item.set('data.runtimeWarnings', ['Dummy warning']);
+    flush();
+    assertWarnings(kCorrupt | kSuspicious | kRuntime);
+
+    item.set('data.disableReasons.corruptInstall', false);
+    item.set('data.disableReasons.suspiciousInstall', false);
+    item.set('data.runtimeWarnings', []);
+    flush();
+    assertWarnings(0);
   });
+
+  test(assert(extension_item_tests.TestNames.SourceIndicator), function() {
+    expectFalse(isVisible(item, '#source-indicator'));
+    item.set('data.location', 'UNPACKED');
+    flush();
+    expectTrue(isVisible(item, '#source-indicator'));
+    const icon = item.$$('#source-indicator iron-icon');
+    assertTrue(!!icon);
+    expectEquals('extensions-icons:unpacked', icon.icon);
+
+    item.set('data.location', 'THIRD_PARTY');
+    flush();
+    expectTrue(isVisible(item, '#source-indicator'));
+    expectEquals('extensions-icons:input', icon.icon);
+
+    item.set('data.location', 'UNKNOWN');
+    flush();
+    expectTrue(isVisible(item, '#source-indicator'));
+    expectEquals('extensions-icons:input', icon.icon);
+
+    item.set('data.location', 'FROM_STORE');
+    item.set('data.controlledInfo', {type: 'POLICY', text: 'policy'});
+    flush();
+    expectTrue(isVisible(item, '#source-indicator'));
+    expectEquals('extensions-icons:business', icon.icon);
+
+    item.set('data.controlledInfo', null);
+    flush();
+    expectFalse(isVisible(item, '#source-indicator'));
+  });
+
+  test(assert(extension_item_tests.TestNames.EnableToggle), function() {
+    expectFalse(item.$['enable-toggle'].disabled);
+
+    // Test case where user does not have permission.
+    item.set('data.userMayModify', false);
+    flush();
+    expectTrue(item.$['enable-toggle'].disabled);
+
+    // Test case of a blacklisted extension.
+    item.set('data.userMayModify', true);
+    item.set('data.state', 'BLACKLISTED');
+    flush();
+    expectTrue(item.$['enable-toggle'].disabled);
+  });
+
+  test(assert(extension_item_tests.TestNames.RemoveButton), function() {
+    expectFalse(item.$['remove-button'].hidden);
+    item.set('data.controlledInfo', {type: 'POLICY', text: 'policy'});
+    flush();
+    expectTrue(item.$['remove-button'].hidden);
+  });
+
+  test(assert(extension_item_tests.TestNames.HtmlInName), function() {
+    let name = '<HTML> in the name!';
+    item.set('data.name', name);
+    flush();
+    assertEquals(name, item.$.name.textContent.trim());
+    // "Related to $1" is IDS_MD_EXTENSIONS_EXTENSION_A11Y_ASSOCIATION.
+    assertEquals(
+        `Related to ${name}`, item.$.a11yAssociation.textContent.trim());
+  });
+});
diff --git a/chrome/test/data/webui/extensions/keyboard_shortcuts_test.js b/chrome/test/data/webui/extensions/keyboard_shortcuts_test.js
index dfb4a72..b36081ff 100644
--- a/chrome/test/data/webui/extensions/keyboard_shortcuts_test.js
+++ b/chrome/test/data/webui/extensions/keyboard_shortcuts_test.js
@@ -13,133 +13,131 @@
 import {TestService} from './test_service.js';
 import {createExtensionInfo} from './test_util.js';
 
-  window.extension_shortcut_tests = {};
-  extension_shortcut_tests.suiteName = 'ExtensionShortcutTest';
-  /** @enum {string} */
-  extension_shortcut_tests.TestNames = {
-    IsValidKeyCode: 'isValidKeyCode',
-    KeyStrokeToString: 'keystrokeToString',
-    Layout: 'Layout',
-    ScopeChange: 'ScopeChange',
-  };
+window.extension_shortcut_tests = {};
+extension_shortcut_tests.suiteName = 'ExtensionShortcutTest';
+/** @enum {string} */
+extension_shortcut_tests.TestNames = {
+  IsValidKeyCode: 'isValidKeyCode',
+  KeyStrokeToString: 'keystrokeToString',
+  Layout: 'Layout',
+  ScopeChange: 'ScopeChange',
+};
 
-  suite(extension_shortcut_tests.suiteName, function() {
-    /** @type {KeyboardShortcuts} */
-    let keyboardShortcuts;
-    /** @type {chrome.developerPrivate.ExtensionInfo} */
-    let noCommands;
-    /** @type {chrome.developerPrivate.ExtensionInfo} */
-    let oneCommand;
-    /** @type {chrome.developerPrivate.ExtensionInfo} */
-    let twoCommands;
+suite(extension_shortcut_tests.suiteName, function() {
+  /** @type {KeyboardShortcuts} */
+  let keyboardShortcuts;
+  /** @type {chrome.developerPrivate.ExtensionInfo} */
+  let noCommands;
+  /** @type {chrome.developerPrivate.ExtensionInfo} */
+  let oneCommand;
+  /** @type {chrome.developerPrivate.ExtensionInfo} */
+  let twoCommands;
 
-    setup(function() {
-      PolymerTest.clearBody();
-      keyboardShortcuts =
-          document.createElement('extensions-keyboard-shortcuts');
-      keyboardShortcuts.delegate = new TestService();
+  setup(function() {
+    PolymerTest.clearBody();
+    keyboardShortcuts = document.createElement('extensions-keyboard-shortcuts');
+    keyboardShortcuts.delegate = new TestService();
 
-      noCommands = createExtensionInfo({id: 'a'.repeat(32)});
-      oneCommand = createExtensionInfo({
-        id: 'b'.repeat(32),
-        commands: [{
-          description: 'Description',
-          keybinding: 'Ctrl+W',
-          name: 'bCommand',
+    noCommands = createExtensionInfo({id: 'a'.repeat(32)});
+    oneCommand = createExtensionInfo({
+      id: 'b'.repeat(32),
+      commands: [{
+        description: 'Description',
+        keybinding: 'Ctrl+W',
+        name: 'bCommand',
+        isActive: true,
+        scope: 'CHROME',
+        isExtensionAction: true,
+      }]
+    });
+    twoCommands = createExtensionInfo({
+      id: 'c'.repeat(32),
+      commands: [
+        {
+          description: 'Another Description',
+          keybinding: 'Alt+F4',
+          name: 'cCommand',
           isActive: true,
+          scope: 'GLOBAL',
+          isExtensionAction: false,
+        },
+        {
+          description: 'Yet Another Description',
+          keybinding: '',
+          name: 'cCommand2',
+          isActive: false,
           scope: 'CHROME',
-          isExtensionAction: true,
-        }]
-      });
-      twoCommands = createExtensionInfo({
-        id: 'c'.repeat(32),
-        commands: [
-          {
-            description: 'Another Description',
-            keybinding: 'Alt+F4',
-            name: 'cCommand',
-            isActive: true,
-            scope: 'GLOBAL',
-            isExtensionAction: false,
-          },
-          {
-            description: 'Yet Another Description',
-            keybinding: '',
-            name: 'cCommand2',
-            isActive: false,
-            scope: 'CHROME',
-            isExtensionAction: false,
-          }
-        ]
-      });
-
-      keyboardShortcuts.set('items', [noCommands, oneCommand, twoCommands]);
-
-      document.body.appendChild(keyboardShortcuts);
-
-      flush();
+          isExtensionAction: false,
+        }
+      ]
     });
 
-    test(assert(extension_shortcut_tests.TestNames.Layout), function() {
-      const isVisibleOnCard = function(e, s) {
-        // We check the light DOM in the card because it's a regular old div,
-        // rather than a fancy-schmancy custom element.
-        return isVisible(e, s, true);
-      };
-      const cards =
-          keyboardShortcuts.$$('#container').querySelectorAll('.shortcut-card');
-      assertEquals(2, cards.length);
+    keyboardShortcuts.set('items', [noCommands, oneCommand, twoCommands]);
 
-      const card1 = cards[0];
-      expectEquals(
-          oneCommand.name, card1.querySelector('.card-title span').textContent);
-      let commands = card1.querySelectorAll('.command-entry');
-      assertEquals(1, commands.length);
-      expectTrue(isVisibleOnCard(commands[0], '.command-name'));
-      expectTrue(isVisibleOnCard(commands[0], 'select.md-select'));
+    document.body.appendChild(keyboardShortcuts);
 
-      const card2 = cards[1];
-      commands = card2.querySelectorAll('.command-entry');
-      assertEquals(2, commands.length);
-    });
-
-    test(extension_shortcut_tests.TestNames.IsValidKeyCode, function() {
-      expectTrue(isValidKeyCode('A'.charCodeAt(0)));
-      expectTrue(isValidKeyCode('F'.charCodeAt(0)));
-      expectTrue(isValidKeyCode('Z'.charCodeAt(0)));
-      expectTrue(isValidKeyCode('4'.charCodeAt(0)));
-      expectTrue(isValidKeyCode(Key.PageUp));
-      expectTrue(isValidKeyCode(Key.MediaPlayPause));
-      expectTrue(isValidKeyCode(Key.Down));
-      expectFalse(isValidKeyCode(16));   // Shift
-      expectFalse(isValidKeyCode(17));   // Ctrl
-      expectFalse(isValidKeyCode(18));   // Alt
-      expectFalse(isValidKeyCode(113));  // F2
-      expectFalse(isValidKeyCode(144));  // Num Lock
-      expectFalse(isValidKeyCode(43));   // +
-      expectFalse(isValidKeyCode(27));   // Escape
-    });
-
-    test(extension_shortcut_tests.TestNames.KeyStrokeToString, function() {
-      // Creating an event with the KeyboardEvent ctor doesn't work. Fake it.
-      const e = {keyCode: 'A'.charCodeAt(0)};
-      expectEquals('A', keystrokeToString(e));
-      e.ctrlKey = true;
-      expectEquals('Ctrl+A', keystrokeToString(e));
-      e.shiftKey = true;
-      expectEquals('Ctrl+Shift+A', keystrokeToString(e));
-    });
-
-    test(extension_shortcut_tests.TestNames.ScopeChange, function() {
-      const selectElement = keyboardShortcuts.$$('select');
-      selectElement.value = 'GLOBAL';
-      selectElement.dispatchEvent(new CustomEvent('change'));
-      return keyboardShortcuts.delegate
-          .whenCalled('updateExtensionCommandScope')
-          .then(params => {
-            assertEquals(oneCommand.id, params[0]);
-            assertEquals(oneCommand.commands[0].name, params[1]);
-            assertEquals(selectElement.value, params[2]);
-          });
-    });
+    flush();
   });
+
+  test(assert(extension_shortcut_tests.TestNames.Layout), function() {
+    const isVisibleOnCard = function(e, s) {
+      // We check the light DOM in the card because it's a regular old div,
+      // rather than a fancy-schmancy custom element.
+      return isVisible(e, s, true);
+    };
+    const cards =
+        keyboardShortcuts.$$('#container').querySelectorAll('.shortcut-card');
+    assertEquals(2, cards.length);
+
+    const card1 = cards[0];
+    expectEquals(
+        oneCommand.name, card1.querySelector('.card-title span').textContent);
+    let commands = card1.querySelectorAll('.command-entry');
+    assertEquals(1, commands.length);
+    expectTrue(isVisibleOnCard(commands[0], '.command-name'));
+    expectTrue(isVisibleOnCard(commands[0], 'select.md-select'));
+
+    const card2 = cards[1];
+    commands = card2.querySelectorAll('.command-entry');
+    assertEquals(2, commands.length);
+  });
+
+  test(extension_shortcut_tests.TestNames.IsValidKeyCode, function() {
+    expectTrue(isValidKeyCode('A'.charCodeAt(0)));
+    expectTrue(isValidKeyCode('F'.charCodeAt(0)));
+    expectTrue(isValidKeyCode('Z'.charCodeAt(0)));
+    expectTrue(isValidKeyCode('4'.charCodeAt(0)));
+    expectTrue(isValidKeyCode(Key.PageUp));
+    expectTrue(isValidKeyCode(Key.MediaPlayPause));
+    expectTrue(isValidKeyCode(Key.Down));
+    expectFalse(isValidKeyCode(16));   // Shift
+    expectFalse(isValidKeyCode(17));   // Ctrl
+    expectFalse(isValidKeyCode(18));   // Alt
+    expectFalse(isValidKeyCode(113));  // F2
+    expectFalse(isValidKeyCode(144));  // Num Lock
+    expectFalse(isValidKeyCode(43));   // +
+    expectFalse(isValidKeyCode(27));   // Escape
+  });
+
+  test(extension_shortcut_tests.TestNames.KeyStrokeToString, function() {
+    // Creating an event with the KeyboardEvent ctor doesn't work. Fake it.
+    const e = {keyCode: 'A'.charCodeAt(0)};
+    expectEquals('A', keystrokeToString(e));
+    e.ctrlKey = true;
+    expectEquals('Ctrl+A', keystrokeToString(e));
+    e.shiftKey = true;
+    expectEquals('Ctrl+Shift+A', keystrokeToString(e));
+  });
+
+  test(extension_shortcut_tests.TestNames.ScopeChange, function() {
+    const selectElement = keyboardShortcuts.$$('select');
+    selectElement.value = 'GLOBAL';
+    selectElement.dispatchEvent(new CustomEvent('change'));
+    return keyboardShortcuts.delegate.whenCalled('updateExtensionCommandScope')
+        .then(params => {
+          assertEquals(oneCommand.id, params[0]);
+          assertEquals(oneCommand.commands[0].name, params[1]);
+          assertEquals(selectElement.value, params[2]);
+        });
+  });
+});
diff --git a/chrome/test/data/webui/extensions/kiosk_mode_test.js b/chrome/test/data/webui/extensions/kiosk_mode_test.js
index 70e5cfa9..f56477375 100644
--- a/chrome/test/data/webui/extensions/kiosk_mode_test.js
+++ b/chrome/test/data/webui/extensions/kiosk_mode_test.js
@@ -12,238 +12,238 @@
 import {flushTasks} from '../test_util.m.js';
 import {TestKioskBrowserProxy} from './test_kiosk_browser_proxy.js';
 
-  window.extension_kiosk_mode_tests = {};
-  extension_kiosk_mode_tests.suiteName = 'kioskModeTests';
-  /** @enum {string} */
-  extension_kiosk_mode_tests.TestNames = {
-    AddButton: 'AddButton',
-    AddError: 'AddError',
-    AutoLaunch: 'AutoLaunch',
-    Bailout: 'Bailout',
-    Layout: 'Layout',
-    Updated: 'Updated',
-  };
+window.extension_kiosk_mode_tests = {};
+extension_kiosk_mode_tests.suiteName = 'kioskModeTests';
+/** @enum {string} */
+extension_kiosk_mode_tests.TestNames = {
+  AddButton: 'AddButton',
+  AddError: 'AddError',
+  AutoLaunch: 'AutoLaunch',
+  Bailout: 'Bailout',
+  Layout: 'Layout',
+  Updated: 'Updated',
+};
 
-  suite(extension_kiosk_mode_tests.suiteName, function() {
-    /** @type {KioskBrowserProxy} */
-    let browserProxy;
+suite(extension_kiosk_mode_tests.suiteName, function() {
+  /** @type {KioskBrowserProxy} */
+  let browserProxy;
 
-    /** @type {ExtensionsKioskDialogElement} */
-    let dialog;
+  /** @type {ExtensionsKioskDialogElement} */
+  let dialog;
 
-    /** @type {!Array<!KioskApp>} */
-    const basicApps = [
-      {
-        id: 'app_1',
-        name: 'App1 Name',
-        iconURL: '',
-        autoLaunch: false,
-        isLoading: false,
-      },
-      {
-        id: 'app_2',
-        name: 'App2 Name',
-        iconURL: '',
-        autoLaunch: false,
-        isLoading: false,
-      },
-    ];
+  /** @type {!Array<!KioskApp>} */
+  const basicApps = [
+    {
+      id: 'app_1',
+      name: 'App1 Name',
+      iconURL: '',
+      autoLaunch: false,
+      isLoading: false,
+    },
+    {
+      id: 'app_2',
+      name: 'App2 Name',
+      iconURL: '',
+      autoLaunch: false,
+      isLoading: false,
+    },
+  ];
 
-    /** @param {!KioskAppSettings} */
-    function setAppSettings(settings) {
-      const appSettings = {
-        apps: [],
-        disableBailout: false,
-        hasAutoLaunchApp: false,
-      };
+  /** @param {!KioskAppSettings} */
+  function setAppSettings(settings) {
+    const appSettings = {
+      apps: [],
+      disableBailout: false,
+      hasAutoLaunchApp: false,
+    };
 
-      browserProxy.setAppSettings(Object.assign({}, appSettings, settings));
-    }
+    browserProxy.setAppSettings(Object.assign({}, appSettings, settings));
+  }
 
-    /** @param {!KioskSettings} */
-    function setInitialSettings(settings) {
-      const initialSettings = {
-        kioskEnabled: true,
-        autoLaunchEnabled: false,
-      };
+  /** @param {!KioskSettings} */
+  function setInitialSettings(settings) {
+    const initialSettings = {
+      kioskEnabled: true,
+      autoLaunchEnabled: false,
+    };
 
-      browserProxy.setInitialSettings(
-          Object.assign({}, initialSettings, settings));
-    }
+    browserProxy.setInitialSettings(
+        Object.assign({}, initialSettings, settings));
+  }
 
-    /** @return {!Promise} */
-    function initPage() {
-      PolymerTest.clearBody();
-      browserProxy.reset();
-      dialog = document.createElement('extensions-kiosk-dialog');
-      document.body.appendChild(dialog);
+  /** @return {!Promise} */
+  function initPage() {
+    PolymerTest.clearBody();
+    browserProxy.reset();
+    dialog = document.createElement('extensions-kiosk-dialog');
+    document.body.appendChild(dialog);
 
-      return browserProxy.whenCalled('getKioskAppSettings')
-          .then(() => flushTasks());
-    }
+    return browserProxy.whenCalled('getKioskAppSettings')
+        .then(() => flushTasks());
+  }
 
-    setup(function() {
-      browserProxy = new TestKioskBrowserProxy();
-      setAppSettings({apps: basicApps.slice(0)});
-      KioskBrowserProxyImpl.instance_ = browserProxy;
+  setup(function() {
+    browserProxy = new TestKioskBrowserProxy();
+    setAppSettings({apps: basicApps.slice(0)});
+    KioskBrowserProxyImpl.instance_ = browserProxy;
 
-      return initPage();
-    });
+    return initPage();
+  });
 
-    test(assert(extension_kiosk_mode_tests.TestNames.Layout), function() {
-      const apps = basicApps.slice(0);
-      apps[1].autoLaunch = true;
-      apps[1].isLoading = true;
-      setAppSettings({apps: apps, hasAutoLaunchApp: true});
+  test(assert(extension_kiosk_mode_tests.TestNames.Layout), function() {
+    const apps = basicApps.slice(0);
+    apps[1].autoLaunch = true;
+    apps[1].isLoading = true;
+    setAppSettings({apps: apps, hasAutoLaunchApp: true});
 
-      return initPage()
-          .then(() => {
-            const items = dialog.shadowRoot.querySelectorAll('.list-item');
-            expectEquals(items.length, 2);
-            expectTrue(items[0].textContent.includes(basicApps[0].name));
-            expectTrue(items[1].textContent.includes(basicApps[1].name));
-            // Second item should show the auto-lauch label.
-            expectTrue(items[0].querySelector('span').hidden);
-            expectFalse(items[1].querySelector('span').hidden);
-            // No permission to edit auto-launch so buttons should be hidden.
-            expectTrue(items[0].querySelector('cr-button').hidden);
-            expectTrue(items[1].querySelector('cr-button').hidden);
-            // Bailout checkbox should be hidden when auto-launch editing
-            // disabled.
-            expectTrue(dialog.$$('cr-checkbox').hidden);
+    return initPage()
+        .then(() => {
+          const items = dialog.shadowRoot.querySelectorAll('.list-item');
+          expectEquals(items.length, 2);
+          expectTrue(items[0].textContent.includes(basicApps[0].name));
+          expectTrue(items[1].textContent.includes(basicApps[1].name));
+          // Second item should show the auto-lauch label.
+          expectTrue(items[0].querySelector('span').hidden);
+          expectFalse(items[1].querySelector('span').hidden);
+          // No permission to edit auto-launch so buttons should be hidden.
+          expectTrue(items[0].querySelector('cr-button').hidden);
+          expectTrue(items[1].querySelector('cr-button').hidden);
+          // Bailout checkbox should be hidden when auto-launch editing
+          // disabled.
+          expectTrue(dialog.$$('cr-checkbox').hidden);
 
-            items[0].querySelector('.icon-delete-gray').click();
-            flush();
-            return browserProxy.whenCalled('removeKioskApp');
-          })
-          .then(appId => {
-            expectEquals(appId, basicApps[0].id);
-          });
-    });
+          items[0].querySelector('.icon-delete-gray').click();
+          flush();
+          return browserProxy.whenCalled('removeKioskApp');
+        })
+        .then(appId => {
+          expectEquals(appId, basicApps[0].id);
+        });
+  });
 
-    test(assert(extension_kiosk_mode_tests.TestNames.AutoLaunch), function() {
-      const apps = basicApps.slice(0);
-      apps[1].autoLaunch = true;
-      setAppSettings({apps: apps, hasAutoLaunchApp: true});
-      setInitialSettings({autoLaunchEnabled: true});
+  test(assert(extension_kiosk_mode_tests.TestNames.AutoLaunch), function() {
+    const apps = basicApps.slice(0);
+    apps[1].autoLaunch = true;
+    setAppSettings({apps: apps, hasAutoLaunchApp: true});
+    setInitialSettings({autoLaunchEnabled: true});
 
-      let buttons;
-      return initPage()
-          .then(() => {
-            buttons = dialog.shadowRoot.querySelectorAll('.list-item cr-button');
-            // Has permission to edit auto-launch so buttons should be seen.
-            expectFalse(buttons[0].hidden);
-            expectFalse(buttons[1].hidden);
+    let buttons;
+    return initPage()
+        .then(() => {
+          buttons = dialog.shadowRoot.querySelectorAll('.list-item cr-button');
+          // Has permission to edit auto-launch so buttons should be seen.
+          expectFalse(buttons[0].hidden);
+          expectFalse(buttons[1].hidden);
 
-            buttons[0].click();
-            return browserProxy.whenCalled('enableKioskAutoLaunch');
-          })
-          .then(appId => {
-            expectEquals(appId, basicApps[0].id);
+          buttons[0].click();
+          return browserProxy.whenCalled('enableKioskAutoLaunch');
+        })
+        .then(appId => {
+          expectEquals(appId, basicApps[0].id);
 
-            buttons[1].click();
-            return browserProxy.whenCalled('disableKioskAutoLaunch');
-          })
-          .then(appId => {
-            expectEquals(appId, basicApps[1].id);
-          });
-    });
+          buttons[1].click();
+          return browserProxy.whenCalled('disableKioskAutoLaunch');
+        })
+        .then(appId => {
+          expectEquals(appId, basicApps[1].id);
+        });
+  });
 
-    test(assert(extension_kiosk_mode_tests.TestNames.Bailout), function() {
-      const apps = basicApps.slice(0);
-      apps[1].autoLaunch = true;
-      setAppSettings({apps: apps, hasAutoLaunchApp: true});
-      setInitialSettings({autoLaunchEnabled: true});
+  test(assert(extension_kiosk_mode_tests.TestNames.Bailout), function() {
+    const apps = basicApps.slice(0);
+    apps[1].autoLaunch = true;
+    setAppSettings({apps: apps, hasAutoLaunchApp: true});
+    setInitialSettings({autoLaunchEnabled: true});
 
-      expectFalse(dialog.$['confirm-dialog'].open);
+    expectFalse(dialog.$['confirm-dialog'].open);
 
-      let bailoutCheckbox;
-      return initPage()
-          .then(() => {
-            bailoutCheckbox = dialog.$$('cr-checkbox');
-            // Bailout checkbox should be usable when auto-launching.
-            expectFalse(bailoutCheckbox.hidden);
-            expectFalse(bailoutCheckbox.disabled);
-            expectFalse(bailoutCheckbox.checked);
+    let bailoutCheckbox;
+    return initPage()
+        .then(() => {
+          bailoutCheckbox = dialog.$$('cr-checkbox');
+          // Bailout checkbox should be usable when auto-launching.
+          expectFalse(bailoutCheckbox.hidden);
+          expectFalse(bailoutCheckbox.disabled);
+          expectFalse(bailoutCheckbox.checked);
 
-            // Making sure canceling doesn't change anything.
-            bailoutCheckbox.click();
-            flush();
-            expectTrue(dialog.$['confirm-dialog'].open);
+          // Making sure canceling doesn't change anything.
+          bailoutCheckbox.click();
+          flush();
+          expectTrue(dialog.$['confirm-dialog'].open);
 
-            dialog.$['confirm-dialog'].querySelector('.cancel-button').click();
-            flush();
-            expectFalse(bailoutCheckbox.checked);
-            expectFalse(dialog.$['confirm-dialog'].open);
-            expectTrue(dialog.$.dialog.open);
+          dialog.$['confirm-dialog'].querySelector('.cancel-button').click();
+          flush();
+          expectFalse(bailoutCheckbox.checked);
+          expectFalse(dialog.$['confirm-dialog'].open);
+          expectTrue(dialog.$.dialog.open);
 
-            // Accepting confirmation dialog should trigger browserProxy call.
-            bailoutCheckbox.click();
-            flush();
-            expectTrue(dialog.$['confirm-dialog'].open);
+          // Accepting confirmation dialog should trigger browserProxy call.
+          bailoutCheckbox.click();
+          flush();
+          expectTrue(dialog.$['confirm-dialog'].open);
 
-            dialog.$['confirm-dialog'].querySelector('.action-button').click();
-            flush();
-            expectTrue(bailoutCheckbox.checked);
-            expectFalse(dialog.$['confirm-dialog'].open);
-            expectTrue(dialog.$.dialog.open);
-            return browserProxy.whenCalled('setDisableBailoutShortcut');
-          })
-          .then(disabled => {
-            expectTrue(disabled);
+          dialog.$['confirm-dialog'].querySelector('.action-button').click();
+          flush();
+          expectTrue(bailoutCheckbox.checked);
+          expectFalse(dialog.$['confirm-dialog'].open);
+          expectTrue(dialog.$.dialog.open);
+          return browserProxy.whenCalled('setDisableBailoutShortcut');
+        })
+        .then(disabled => {
+          expectTrue(disabled);
 
-            // Test clicking on checkbox again should simply re-enable bailout.
-            browserProxy.reset();
-            bailoutCheckbox.click();
-            expectFalse(bailoutCheckbox.checked);
-            expectFalse(dialog.$['confirm-dialog'].open);
-            return browserProxy.whenCalled('setDisableBailoutShortcut');
-          })
-          .then(disabled => {
-            expectFalse(disabled);
-          });
-    });
+          // Test clicking on checkbox again should simply re-enable bailout.
+          browserProxy.reset();
+          bailoutCheckbox.click();
+          expectFalse(bailoutCheckbox.checked);
+          expectFalse(dialog.$['confirm-dialog'].open);
+          return browserProxy.whenCalled('setDisableBailoutShortcut');
+        })
+        .then(disabled => {
+          expectFalse(disabled);
+        });
+  });
 
-    test(assert(extension_kiosk_mode_tests.TestNames.AddButton), function() {
-      const addButton = dialog.$['add-button'];
-      expectTrue(!!addButton);
-      expectTrue(addButton.disabled);
+  test(assert(extension_kiosk_mode_tests.TestNames.AddButton), function() {
+    const addButton = dialog.$['add-button'];
+    expectTrue(!!addButton);
+    expectTrue(addButton.disabled);
 
-      const addInput = dialog.$['add-input'];
-      addInput.value = 'blah';
-      expectFalse(addButton.disabled);
+    const addInput = dialog.$['add-input'];
+    addInput.value = 'blah';
+    expectFalse(addButton.disabled);
 
-      addButton.click();
-      return browserProxy.whenCalled('addKioskApp').then(appId => {
-        expectEquals(appId, 'blah');
-      });
-    });
-
-    test(assert(extension_kiosk_mode_tests.TestNames.Updated), function() {
-      const items = dialog.shadowRoot.querySelectorAll('.list-item');
-      expectTrue(items[0].textContent.includes(basicApps[0].name));
-
-      const newName = 'completely different name';
-
-      window.cr.webUIListenerCallback('kiosk-app-updated', {
-        id: basicApps[0].id,
-        name: newName,
-        iconURL: '',
-        autoLaunch: false,
-        isLoading: false,
-      });
-
-      expectFalse(items[0].textContent.includes(basicApps[0].name));
-      expectTrue(items[0].textContent.includes(newName));
-    });
-
-    test(assert(extension_kiosk_mode_tests.TestNames.AddError), function() {
-      const addInput = dialog.$['add-input'];
-
-      expectFalse(!!addInput.invalid);
-      window.cr.webUIListenerCallback('kiosk-app-error', basicApps[0].id);
-
-      expectTrue(!!addInput.invalid);
-      expectTrue(addInput.errorMessage.includes(basicApps[0].id));
+    addButton.click();
+    return browserProxy.whenCalled('addKioskApp').then(appId => {
+      expectEquals(appId, 'blah');
     });
   });
+
+  test(assert(extension_kiosk_mode_tests.TestNames.Updated), function() {
+    const items = dialog.shadowRoot.querySelectorAll('.list-item');
+    expectTrue(items[0].textContent.includes(basicApps[0].name));
+
+    const newName = 'completely different name';
+
+    window.cr.webUIListenerCallback('kiosk-app-updated', {
+      id: basicApps[0].id,
+      name: newName,
+      iconURL: '',
+      autoLaunch: false,
+      isLoading: false,
+    });
+
+    expectFalse(items[0].textContent.includes(basicApps[0].name));
+    expectTrue(items[0].textContent.includes(newName));
+  });
+
+  test(assert(extension_kiosk_mode_tests.TestNames.AddError), function() {
+    const addInput = dialog.$['add-input'];
+
+    expectFalse(!!addInput.invalid);
+    window.cr.webUIListenerCallback('kiosk-app-error', basicApps[0].id);
+
+    expectTrue(!!addInput.invalid);
+    expectTrue(addInput.errorMessage.includes(basicApps[0].id));
+  });
+});
diff --git a/chrome/test/data/webui/extensions/load_error_test.js b/chrome/test/data/webui/extensions/load_error_test.js
index 4d6d4a73..e3789e89 100644
--- a/chrome/test/data/webui/extensions/load_error_test.js
+++ b/chrome/test/data/webui/extensions/load_error_test.js
@@ -10,81 +10,81 @@
 import {TestService} from './test_service.js';
 import {isElementVisible} from './test_util.js';
 
-  window.extension_load_error_tests = {};
-  extension_load_error_tests.suiteName = 'ExtensionLoadErrorTests';
-  /** @enum {string} */
-  extension_load_error_tests.TestNames = {
-    RetryError: 'RetryError',
-    RetrySuccess: 'RetrySuccess',
-    CodeSection: 'Code Section',
+window.extension_load_error_tests = {};
+extension_load_error_tests.suiteName = 'ExtensionLoadErrorTests';
+/** @enum {string} */
+extension_load_error_tests.TestNames = {
+  RetryError: 'RetryError',
+  RetrySuccess: 'RetrySuccess',
+  CodeSection: 'Code Section',
+};
+
+suite(extension_load_error_tests.suiteName, function() {
+  /** @type {ExtensionsLoadErrorElement} */
+  let loadError;
+
+  /** @type {MockDelegate} */
+  let mockDelegate;
+
+  const fakeGuid = 'uniqueId';
+
+  const stubLoadError = {
+    error: 'error',
+    path: 'some/path/',
+    retryGuid: fakeGuid,
   };
 
-  suite(extension_load_error_tests.suiteName, function() {
-    /** @type {ExtensionsLoadErrorElement} */
-    let loadError;
+  setup(function() {
+    PolymerTest.clearBody();
+    mockDelegate = new TestService();
+    loadError = document.createElement('extensions-load-error');
+    loadError.delegate = mockDelegate;
+    loadError.loadError = stubLoadError;
+    document.body.appendChild(loadError);
+  });
 
-    /** @type {MockDelegate} */
-    let mockDelegate;
+  test(assert(extension_load_error_tests.TestNames.RetryError), function() {
+    const dialogElement = loadError.$$('cr-dialog').getNative();
+    expectFalse(isElementVisible(dialogElement));
+    loadError.show();
+    expectTrue(isElementVisible(dialogElement));
 
-    const fakeGuid = 'uniqueId';
-
-    const stubLoadError = {
-      error: 'error',
-      path: 'some/path/',
-      retryGuid: fakeGuid,
-    };
-
-    setup(function() {
-      PolymerTest.clearBody();
-      mockDelegate = new TestService();
-      loadError = document.createElement('extensions-load-error');
-      loadError.delegate = mockDelegate;
-      loadError.loadError = stubLoadError;
-      document.body.appendChild(loadError);
-    });
-
-    test(assert(extension_load_error_tests.TestNames.RetryError), function() {
-      const dialogElement = loadError.$$('cr-dialog').getNative();
-      expectFalse(isElementVisible(dialogElement));
-      loadError.show();
+    mockDelegate.setRetryLoadUnpackedError(stubLoadError);
+    loadError.$$('.action-button').click();
+    return mockDelegate.whenCalled('retryLoadUnpacked').then(arg => {
+      expectEquals(fakeGuid, arg);
       expectTrue(isElementVisible(dialogElement));
-
-      mockDelegate.setRetryLoadUnpackedError(stubLoadError);
-      loadError.$$('.action-button').click();
-      return mockDelegate.whenCalled('retryLoadUnpacked').then(arg => {
-        expectEquals(fakeGuid, arg);
-        expectTrue(isElementVisible(dialogElement));
-        loadError.$$('.cancel-button').click();
-        expectFalse(isElementVisible(dialogElement));
-      });
-    });
-
-    test(assert(extension_load_error_tests.TestNames.RetrySuccess), function() {
-      const dialogElement = loadError.$$('cr-dialog').getNative();
+      loadError.$$('.cancel-button').click();
       expectFalse(isElementVisible(dialogElement));
-      loadError.show();
-      expectTrue(isElementVisible(dialogElement));
-
-      loadError.$$('.action-button').click();
-      return mockDelegate.whenCalled('retryLoadUnpacked').then(arg => {
-        expectEquals(fakeGuid, arg);
-        expectFalse(isElementVisible(dialogElement));
-      });
-    });
-
-    test(assert(extension_load_error_tests.TestNames.CodeSection), function() {
-      expectTrue(loadError.$.code.$$('#scroll-container').hidden);
-      const loadErrorWithSource = {
-        error: 'Some error',
-        path: '/some/path',
-        source: {
-          beforeHighlight: 'before',
-          highlight: 'highlight',
-          afterHighlight: 'after',
-        },
-      };
-
-      loadError.loadError = loadErrorWithSource;
-      expectFalse(loadError.$.code.$$('#scroll-container').hidden);
     });
   });
+
+  test(assert(extension_load_error_tests.TestNames.RetrySuccess), function() {
+    const dialogElement = loadError.$$('cr-dialog').getNative();
+    expectFalse(isElementVisible(dialogElement));
+    loadError.show();
+    expectTrue(isElementVisible(dialogElement));
+
+    loadError.$$('.action-button').click();
+    return mockDelegate.whenCalled('retryLoadUnpacked').then(arg => {
+      expectEquals(fakeGuid, arg);
+      expectFalse(isElementVisible(dialogElement));
+    });
+  });
+
+  test(assert(extension_load_error_tests.TestNames.CodeSection), function() {
+    expectTrue(loadError.$.code.$$('#scroll-container').hidden);
+    const loadErrorWithSource = {
+      error: 'Some error',
+      path: '/some/path',
+      source: {
+        beforeHighlight: 'before',
+        highlight: 'highlight',
+        afterHighlight: 'after',
+      },
+    };
+
+    loadError.loadError = loadErrorWithSource;
+    expectFalse(loadError.$.code.$$('#scroll-container').hidden);
+  });
+});
diff --git a/chrome/test/data/webui/extensions/manager_test.js b/chrome/test/data/webui/extensions/manager_test.js
index 313e360..8bedcc2 100644
--- a/chrome/test/data/webui/extensions/manager_test.js
+++ b/chrome/test/data/webui/extensions/manager_test.js
@@ -8,127 +8,123 @@
 import {flush} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
 import {eventToPromise} from '../test_util.m.js';
 
-  window.extension_manager_tests = {};
-  extension_manager_tests.suiteName = 'ExtensionManagerTest';
-  /** @enum {string} */
-  extension_manager_tests.TestNames = {
-    ChangePages: 'change pages',
-    ItemListVisibility: 'item list visibility',
-    SplitItems: 'split items',
-    PageTitleUpdate: 'updates the title based on current route',
-  };
+window.extension_manager_tests = {};
+extension_manager_tests.suiteName = 'ExtensionManagerTest';
+/** @enum {string} */
+extension_manager_tests.TestNames = {
+  ChangePages: 'change pages',
+  ItemListVisibility: 'item list visibility',
+  SplitItems: 'split items',
+  PageTitleUpdate: 'updates the title based on current route',
+};
 
-  function getDataByName(list, name) {
-    return assert(list.find(function(el) {
-      return el.name == name;
-    }));
+function getDataByName(list, name) {
+  return assert(list.find(function(el) {
+    return el.name == name;
+  }));
+}
+
+suite(extension_manager_tests.suiteName, function() {
+  /** @type {Manager} */
+  let manager;
+
+  /** @param {string} viewElement */
+  function assertViewActive(tagName) {
+    assertTrue(!!manager.$.viewManager.querySelector(`${tagName}.active`));
   }
 
-  suite(extension_manager_tests.suiteName, function() {
-    /** @type {Manager} */
-    let manager;
+  setup(function() {
+    PolymerTest.clearBody();
+    manager = document.createElement('extensions-manager');
+    document.body.appendChild(manager);
 
-    /** @param {string} viewElement */
-    function assertViewActive(tagName) {
-      assertTrue(!!manager.$.viewManager.querySelector(`${tagName}.active`));
-    }
-
-    setup(function() {
-      PolymerTest.clearBody();
-      manager = document.createElement('extensions-manager');
-      document.body.appendChild(manager);
-
-      // Wait for the first view to be active before starting tests, if one is
-      // not active already. Sometimes, on Mac with native HTML imports
-      // disabled, no views are active at this point.
-      return manager.$.viewManager.querySelector('.active') ?
-          Promise.resolve() :
-          eventToPromise('view-enter-start', manager);
-    });
-
-    test(
-        assert(extension_manager_tests.TestNames.ItemListVisibility),
-        function() {
-          const extension = getDataByName(manager.extensions_, 'My extension 1');
-
-          const list = manager.$['items-list'];
-          const listHasItemWithName = (name) =>
-              !!list.extensions.find(el => el.name == name);
-
-          expectEquals(manager.extensions_, manager.$['items-list'].extensions);
-          expectTrue(listHasItemWithName('My extension 1'));
-
-          manager.removeItem_(extension.id);
-          flush();
-          expectFalse(listHasItemWithName('My extension 1'));
-
-          manager.addItem_('extensions_', extension);
-          flush();
-          expectTrue(listHasItemWithName('My extension 1'));
-        });
-
-    test(assert(extension_manager_tests.TestNames.SplitItems), function() {
-      const sectionHasItemWithName = function(section, name) {
-        return !!manager[section].find(function(el) {
-          return el.name == name;
-        });
-      };
-
-      // Test that we properly split up the items into two sections.
-      expectTrue(sectionHasItemWithName('extensions_', 'My extension 1'));
-      expectTrue(sectionHasItemWithName(
-          'apps_', 'Platform App Test: minimal platform app'));
-      expectTrue(sectionHasItemWithName('apps_', 'hosted_app'));
-      expectTrue(sectionHasItemWithName('apps_', 'Packaged App Test'));
-    });
-
-    test(assert(extension_manager_tests.TestNames.ChangePages), function() {
-      manager.$$('extensions-toolbar').$$('cr-toolbar').$$('#menuButton')
-          .click();
-      flush();
-
-      // We start on the item list.
-      manager.$$('#sidebar').$['sections-extensions'].click();
-      flush();
-      assertViewActive('extensions-item-list');
-
-      // Switch: item list -> keyboard shortcuts.
-      manager.$$('#sidebar').$['sections-shortcuts'].click();
-      flush();
-      assertViewActive('extensions-keyboard-shortcuts');
-
-      // Switch: item list -> detail view.
-      const item = manager.$['items-list'].$$('extensions-item');
-      assert(item);
-      item.onDetailsTap_();
-      flush();
-      assertViewActive('extensions-detail-view');
-
-      // Switch: detail view -> keyboard shortcuts.
-      manager.$$('#sidebar').$['sections-shortcuts'].click();
-      flush();
-      assertViewActive('extensions-keyboard-shortcuts');
-
-      // We get back on the item list.
-      manager.$$('#sidebar').$['sections-extensions'].click();
-      flush();
-      assertViewActive('extensions-item-list');
-    });
-
-    test(assert(extension_manager_tests.TestNames.PageTitleUpdate), function() {
-      expectEquals('Extensions', document.title);
-
-      // Open details view with a valid ID.
-      navigation.navigateTo({
-          page: Page.DETAILS,
-          extensionId: 'ldnnhddmnhbkjipkidpdiheffobcpfmf'
-      });
-      flush();
-      expectEquals('Extensions - My extension 1', document.title);
-
-      // Navigate back to the list view and check the page title.
-      navigation.navigateTo({page: Page.LIST});
-      flush();
-      expectEquals('Extensions', document.title);
-    });
+    // Wait for the first view to be active before starting tests, if one is
+    // not active already. Sometimes, on Mac with native HTML imports
+    // disabled, no views are active at this point.
+    return manager.$.viewManager.querySelector('.active') ?
+        Promise.resolve() :
+        eventToPromise('view-enter-start', manager);
   });
+
+  test(
+      assert(extension_manager_tests.TestNames.ItemListVisibility), function() {
+        const extension = getDataByName(manager.extensions_, 'My extension 1');
+
+        const list = manager.$['items-list'];
+        const listHasItemWithName = (name) =>
+            !!list.extensions.find(el => el.name == name);
+
+        expectEquals(manager.extensions_, manager.$['items-list'].extensions);
+        expectTrue(listHasItemWithName('My extension 1'));
+
+        manager.removeItem_(extension.id);
+        flush();
+        expectFalse(listHasItemWithName('My extension 1'));
+
+        manager.addItem_('extensions_', extension);
+        flush();
+        expectTrue(listHasItemWithName('My extension 1'));
+      });
+
+  test(assert(extension_manager_tests.TestNames.SplitItems), function() {
+    const sectionHasItemWithName = function(section, name) {
+      return !!manager[section].find(function(el) {
+        return el.name == name;
+      });
+    };
+
+    // Test that we properly split up the items into two sections.
+    expectTrue(sectionHasItemWithName('extensions_', 'My extension 1'));
+    expectTrue(sectionHasItemWithName(
+        'apps_', 'Platform App Test: minimal platform app'));
+    expectTrue(sectionHasItemWithName('apps_', 'hosted_app'));
+    expectTrue(sectionHasItemWithName('apps_', 'Packaged App Test'));
+  });
+
+  test(assert(extension_manager_tests.TestNames.ChangePages), function() {
+    manager.$$('extensions-toolbar').$$('cr-toolbar').$$('#menuButton').click();
+    flush();
+
+    // We start on the item list.
+    manager.$$('#sidebar').$['sections-extensions'].click();
+    flush();
+    assertViewActive('extensions-item-list');
+
+    // Switch: item list -> keyboard shortcuts.
+    manager.$$('#sidebar').$['sections-shortcuts'].click();
+    flush();
+    assertViewActive('extensions-keyboard-shortcuts');
+
+    // Switch: item list -> detail view.
+    const item = manager.$['items-list'].$$('extensions-item');
+    assert(item);
+    item.onDetailsTap_();
+    flush();
+    assertViewActive('extensions-detail-view');
+
+    // Switch: detail view -> keyboard shortcuts.
+    manager.$$('#sidebar').$['sections-shortcuts'].click();
+    flush();
+    assertViewActive('extensions-keyboard-shortcuts');
+
+    // We get back on the item list.
+    manager.$$('#sidebar').$['sections-extensions'].click();
+    flush();
+    assertViewActive('extensions-item-list');
+  });
+
+  test(assert(extension_manager_tests.TestNames.PageTitleUpdate), function() {
+    expectEquals('Extensions', document.title);
+
+    // Open details view with a valid ID.
+    navigation.navigateTo(
+        {page: Page.DETAILS, extensionId: 'ldnnhddmnhbkjipkidpdiheffobcpfmf'});
+    flush();
+    expectEquals('Extensions - My extension 1', document.title);
+
+    // Navigate back to the list view and check the page title.
+    navigation.navigateTo({page: Page.LIST});
+    flush();
+    expectEquals('Extensions', document.title);
+  });
+});
diff --git a/chrome/test/data/webui/extensions/manager_unit_test.js b/chrome/test/data/webui/extensions/manager_unit_test.js
index 1c91f19..33c9b444 100644
--- a/chrome/test/data/webui/extensions/manager_unit_test.js
+++ b/chrome/test/data/webui/extensions/manager_unit_test.js
@@ -2,9 +2,11 @@
 // 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 extension-manager unit tests. Unlike
+/**
+ * @fileoverview Suite of tests for extension-manager unit tests. Unlike
  * extension_manager_test.js, these tests are not interacting with the real
- * chrome.developerPrivate API. */
+ * chrome.developerPrivate API.
+ */
 
 import {navigation, Page, Service} from 'chrome://extensions/extensions.js';
 
@@ -13,301 +15,300 @@
 import {TestService} from './test_service.js';
 import {createExtensionInfo} from './test_util.js';
 
-  window.extension_manager_unit_tests = {};
-  extension_manager_unit_tests.suiteName = 'ExtensionManagerUnitTest';
-  /** @enum {string} */
-  extension_manager_unit_tests.TestNames = {
-    EnableAndDisable: 'enable and disable',
-    ItemOrder: 'item order',
-    ProfileSettings: 'profile settings',
-    ToggleIncognitoMode: 'toggle incognito mode',
-    Uninstall: 'uninstall',
-    UninstallFromDetails: 'uninstall while in details view',
-    SetItemData: 'set item data',
-    UpdateItemData: 'update item data',
-  };
+window.extension_manager_unit_tests = {};
+extension_manager_unit_tests.suiteName = 'ExtensionManagerUnitTest';
+/** @enum {string} */
+extension_manager_unit_tests.TestNames = {
+  EnableAndDisable: 'enable and disable',
+  ItemOrder: 'item order',
+  ProfileSettings: 'profile settings',
+  ToggleIncognitoMode: 'toggle incognito mode',
+  Uninstall: 'uninstall',
+  UninstallFromDetails: 'uninstall while in details view',
+  SetItemData: 'set item data',
+  UpdateItemData: 'update item data',
+};
 
-  suite(extension_manager_unit_tests.suiteName, function() {
-    /** @type {Manager} */
-    let manager;
+suite(extension_manager_unit_tests.suiteName, function() {
+  /** @type {Manager} */
+  let manager;
 
-    /** @type {TestService} */
-    let service;
+  /** @type {TestService} */
+  let service;
 
-    /** @type {?KioskBrowserProxy} */
-    let browserProxy;
+  /** @type {?KioskBrowserProxy} */
+  let browserProxy;
 
-    const testActivities = {activities: []};
+  const testActivities = {activities: []};
 
-    setup(function() {
-      PolymerTest.clearBody();
+  setup(function() {
+    PolymerTest.clearBody();
 
-      service = new TestService();
-      Service.instance_ = service;
+    service = new TestService();
+    Service.instance_ = service;
 
-      manager = document.createElement('extensions-manager');
-      document.body.appendChild(manager);
+    manager = document.createElement('extensions-manager');
+    document.body.appendChild(manager);
 
-      // Wait until Manager calls fetches data and initializes itself before
-      // making any assertions.
-      return Promise.all([
-        service.whenCalled('getExtensionsInfo'),
-        service.whenCalled('getProfileConfiguration'),
-      ]);
-    });
-
-    /**
-     * Trigger an event that indicates that an extension was installed.
-     * @param {!chrome.developerPrivate.ExtensionInfo} info
-     */
-    function simulateExtensionInstall(info) {
-      service.itemStateChangedTarget.callListeners({
-        event_type: chrome.developerPrivate.EventType.INSTALLED,
-        extensionInfo: info,
-      });
-    }
-
-    // Test that newly added items are inserted in the correct order.
-    test(assert(extension_manager_unit_tests.TestNames.ItemOrder), function() {
-      expectEquals(0, manager.extensions_.length);
-
-      const alphaFromStore = createExtensionInfo(
-          {location: 'FROM_STORE', name: 'Alpha', id: 'a'.repeat(32)});
-      simulateExtensionInstall(alphaFromStore);
-      expectEquals(1, manager.extensions_.length);
-      expectEquals(alphaFromStore.id, manager.extensions_[0].id);
-
-      // Unpacked extensions come first.
-      const betaUnpacked = createExtensionInfo(
-          {location: 'UNPACKED', name: 'Beta', id: 'b'.repeat(32)});
-      simulateExtensionInstall(betaUnpacked);
-      expectEquals(2, manager.extensions_.length);
-      expectEquals(betaUnpacked.id, manager.extensions_[0].id);
-      expectEquals(alphaFromStore.id, manager.extensions_[1].id);
-
-      // Extensions from the same location are sorted by name.
-      let gammaUnpacked = createExtensionInfo(
-          {location: 'UNPACKED', name: 'Gamma', id: 'c'.repeat(32)});
-      simulateExtensionInstall(gammaUnpacked);
-      expectEquals(3, manager.extensions_.length);
-      expectEquals(betaUnpacked.id, manager.extensions_[0].id);
-      expectEquals(gammaUnpacked.id, manager.extensions_[1].id);
-      expectEquals(alphaFromStore.id, manager.extensions_[2].id);
-
-      // The name-sort should be case-insensitive, and should fall back on
-      // id.
-      const aaFromStore = createExtensionInfo(
-          {location: 'FROM_STORE', name: 'AA', id: 'd'.repeat(32)});
-      simulateExtensionInstall(aaFromStore);
-      const AaFromStore = createExtensionInfo(
-          {location: 'FROM_STORE', name: 'Aa', id: 'e'.repeat(32)});
-      simulateExtensionInstall(AaFromStore);
-      const aAFromStore = createExtensionInfo(
-          {location: 'FROM_STORE', name: 'aA', id: 'f'.repeat(32)});
-      simulateExtensionInstall(aAFromStore);
-
-      expectEquals(6, manager.extensions_.length);
-      expectEquals(betaUnpacked.id, manager.extensions_[0].id);
-      expectEquals(gammaUnpacked.id, manager.extensions_[1].id);
-      expectEquals(aaFromStore.id, manager.extensions_[2].id);
-      expectEquals(AaFromStore.id, manager.extensions_[3].id);
-      expectEquals(aAFromStore.id, manager.extensions_[4].id);
-      expectEquals(alphaFromStore.id, manager.extensions_[5].id);
-    });
-
-    test(assert(extension_manager_unit_tests.TestNames.SetItemData), function() {
-      const description = 'description';
-
-      const extension = createExtensionInfo({description: description});
-      simulateExtensionInstall(extension);
-
-      // The detail view is not present until navigation.
-      expectFalse(!!manager.$$('extensions-detail-view'));
-      navigation.navigateTo({page: Page.DETAILS, extensionId: extension.id});
-      const detailsView = manager.$$('extensions-detail-view');
-      expectTrue(!!detailsView);  // View should now be present.
-      expectEquals(extension.id, detailsView.data.id);
-      expectEquals(description, detailsView.data.description);
-      expectEquals(
-          description,
-          detailsView.$$('.section .section-content').textContent.trim());
-    });
-
-    test(
-        assert(extension_manager_unit_tests.TestNames.UpdateItemData),
-        function() {
-          const oldDescription = 'old description';
-          const newDescription = 'new description';
-
-          const extension = createExtensionInfo({description: oldDescription});
-          simulateExtensionInstall(extension);
-          const secondExtension = createExtensionInfo({
-            description: 'irrelevant',
-            id: 'b'.repeat(32),
-          });
-          simulateExtensionInstall(secondExtension);
-
-          navigation.navigateTo(
-              {page: Page.DETAILS, extensionId: extension.id});
-          const detailsView = manager.$$('extensions-detail-view');
-
-          let extensionCopy = Object.assign({}, extension);
-          extensionCopy.description = newDescription;
-          service.itemStateChangedTarget.callListeners({
-            event_type: chrome.developerPrivate.EventType.PREFS_CHANGED,
-            extensionInfo: extensionCopy,
-          });
-
-          // Updating a different extension shouldn't have any impact.
-          let secondExtensionCopy = Object.assign({}, secondExtension);
-          secondExtensionCopy.description = 'something else';
-          service.itemStateChangedTarget.callListeners({
-            event_type: chrome.developerPrivate.EventType.PREFS_CHANGED,
-            extensionInfo: secondExtensionCopy,
-          });
-          expectEquals(extension.id, detailsView.data.id);
-          expectEquals(newDescription, detailsView.data.description);
-          expectEquals(
-              newDescription,
-              detailsView.$$('.section .section-content').textContent.trim());
-        });
-
-    test(
-        assert(extension_manager_unit_tests.TestNames.ProfileSettings),
-        function() {
-          expectFalse(manager.inDevMode);
-
-          service.profileStateChangedTarget.callListeners(
-              {inDeveloperMode: true});
-          expectTrue(manager.inDevMode);
-
-          service.profileStateChangedTarget.callListeners(
-              {inDeveloperMode: false});
-          expectFalse(manager.inDevMode);
-
-          service.profileStateChangedTarget.callListeners(
-              {canLoadUnpacked: true});
-          expectTrue(manager.canLoadUnpacked);
-
-          service.profileStateChangedTarget.callListeners(
-              {canLoadUnpacked: false});
-          expectFalse(manager.canLoadUnpacked);
-        });
-
-    test(assert(extension_manager_unit_tests.TestNames.Uninstall), function() {
-      expectEquals(0, manager.extensions_.length);
-
-      const extension = createExtensionInfo(
-          {location: 'FROM_STORE', name: 'Alpha', id: 'a'.repeat(32)});
-      simulateExtensionInstall(extension);
-      expectEquals(1, manager.extensions_.length);
-
-      service.itemStateChangedTarget.callListeners({
-        event_type: chrome.developerPrivate.EventType.UNINSTALLED,
-        // When an extension is uninstalled, only the ID is passed back from
-        // C++.
-        item_id: extension.id,
-      });
-
-      expectEquals(0, manager.extensions_.length);
-    });
-
-    /** @param {string} tagName */
-    function assertViewActive(tagName) {
-      expectTrue(!!manager.$.viewManager.querySelector(`${tagName}.active`));
-    }
-
-    test(
-        assert(extension_manager_unit_tests.TestNames.UninstallFromDetails),
-        function(done) {
-          const extension = createExtensionInfo(
-              {location: 'FROM_STORE', name: 'Alpha', id: 'a'.repeat(32)});
-          simulateExtensionInstall(extension);
-
-          navigation.navigateTo({page: Page.DETAILS, extensionId: extension.id});
-          flush();
-          assertViewActive('extensions-detail-view');
-
-          window.addEventListener('popstate', () => {
-            assertViewActive('extensions-item-list');
-            done();
-          });
-
-          service.itemStateChangedTarget.callListeners({
-            event_type: chrome.developerPrivate.EventType.UNINSTALLED,
-            // When an extension is uninstalled, only the ID is passed back from
-            // C++.
-            item_id: extension.id,
-          });
-        });
-
-    test(
-        assert(extension_manager_unit_tests.TestNames.ToggleIncognitoMode),
-        function() {
-          expectEquals(0, manager.extensions_.length);
-          const extension = createExtensionInfo(
-              {location: 'FROM_STORE', name: 'Alpha', id: 'a'.repeat(32)});
-          simulateExtensionInstall(extension);
-          expectEquals(1, manager.extensions_.length);
-
-          expectEquals(extension, manager.extensions_[0]);
-          expectTrue(extension.incognitoAccess.isEnabled);
-          expectFalse(extension.incognitoAccess.isActive);
-
-          // Simulate granting incognito permission.
-          const extensionCopy1 = Object.assign({}, extension);
-          extensionCopy1.incognitoAccess.isActive = true;
-          service.itemStateChangedTarget.callListeners({
-            event_type: chrome.developerPrivate.EventType.LOADED,
-            extensionInfo: extensionCopy1,
-          });
-
-          expectTrue(manager.extensions_[0].incognitoAccess.isActive);
-
-          // Simulate revoking incognito permission.
-          const extensionCopy2 = Object.assign({}, extension);
-          extensionCopy2.incognitoAccess.isActive = false;
-          service.itemStateChangedTarget.callListeners({
-            event_type: chrome.developerPrivate.EventType.LOADED,
-            extensionInfo: extensionCopy2,
-          });
-          expectFalse(manager.extensions_[0].incognitoAccess.isActive);
-        });
-
-    test(
-        assert(extension_manager_unit_tests.TestNames.EnableAndDisable),
-        function() {
-          const ExtensionState = chrome.developerPrivate.ExtensionState;
-          expectEquals(0, manager.extensions_.length);
-          const extension = createExtensionInfo({
-            location: 'FROM_STORE',
-            name: 'My extension 1',
-            id: 'a'.repeat(32)
-          });
-          simulateExtensionInstall(extension);
-          expectEquals(1, manager.extensions_.length);
-
-          expectEquals(extension, manager.extensions_[0]);
-          expectEquals('My extension 1', extension.name);
-          expectEquals(ExtensionState.ENABLED, extension.state);
-
-          // Simulate disabling an extension.
-          const extensionCopy1 = Object.assign({}, extension);
-          extensionCopy1.state = ExtensionState.DISABLED;
-          service.itemStateChangedTarget.callListeners({
-            event_type: chrome.developerPrivate.EventType.LOADED,
-            extensionInfo: extensionCopy1,
-          });
-          expectEquals(ExtensionState.DISABLED, manager.extensions_[0].state);
-
-          // Simulate re-enabling an extension.
-          // Simulate disabling an extension.
-          const extensionCopy2 = Object.assign({}, extension);
-          extensionCopy2.state = ExtensionState.ENABLED;
-          service.itemStateChangedTarget.callListeners({
-            event_type: chrome.developerPrivate.EventType.LOADED,
-            extensionInfo: extensionCopy2,
-          });
-          expectEquals(ExtensionState.ENABLED, manager.extensions_[0].state);
-        });
+    // Wait until Manager calls fetches data and initializes itself before
+    // making any assertions.
+    return Promise.all([
+      service.whenCalled('getExtensionsInfo'),
+      service.whenCalled('getProfileConfiguration'),
+    ]);
   });
+
+  /**
+   * Trigger an event that indicates that an extension was installed.
+   * @param {!chrome.developerPrivate.ExtensionInfo} info
+   */
+  function simulateExtensionInstall(info) {
+    service.itemStateChangedTarget.callListeners({
+      event_type: chrome.developerPrivate.EventType.INSTALLED,
+      extensionInfo: info,
+    });
+  }
+
+  // Test that newly added items are inserted in the correct order.
+  test(assert(extension_manager_unit_tests.TestNames.ItemOrder), function() {
+    expectEquals(0, manager.extensions_.length);
+
+    const alphaFromStore = createExtensionInfo(
+        {location: 'FROM_STORE', name: 'Alpha', id: 'a'.repeat(32)});
+    simulateExtensionInstall(alphaFromStore);
+    expectEquals(1, manager.extensions_.length);
+    expectEquals(alphaFromStore.id, manager.extensions_[0].id);
+
+    // Unpacked extensions come first.
+    const betaUnpacked = createExtensionInfo(
+        {location: 'UNPACKED', name: 'Beta', id: 'b'.repeat(32)});
+    simulateExtensionInstall(betaUnpacked);
+    expectEquals(2, manager.extensions_.length);
+    expectEquals(betaUnpacked.id, manager.extensions_[0].id);
+    expectEquals(alphaFromStore.id, manager.extensions_[1].id);
+
+    // Extensions from the same location are sorted by name.
+    let gammaUnpacked = createExtensionInfo(
+        {location: 'UNPACKED', name: 'Gamma', id: 'c'.repeat(32)});
+    simulateExtensionInstall(gammaUnpacked);
+    expectEquals(3, manager.extensions_.length);
+    expectEquals(betaUnpacked.id, manager.extensions_[0].id);
+    expectEquals(gammaUnpacked.id, manager.extensions_[1].id);
+    expectEquals(alphaFromStore.id, manager.extensions_[2].id);
+
+    // The name-sort should be case-insensitive, and should fall back on
+    // id.
+    const aaFromStore = createExtensionInfo(
+        {location: 'FROM_STORE', name: 'AA', id: 'd'.repeat(32)});
+    simulateExtensionInstall(aaFromStore);
+    const AaFromStore = createExtensionInfo(
+        {location: 'FROM_STORE', name: 'Aa', id: 'e'.repeat(32)});
+    simulateExtensionInstall(AaFromStore);
+    const aAFromStore = createExtensionInfo(
+        {location: 'FROM_STORE', name: 'aA', id: 'f'.repeat(32)});
+    simulateExtensionInstall(aAFromStore);
+
+    expectEquals(6, manager.extensions_.length);
+    expectEquals(betaUnpacked.id, manager.extensions_[0].id);
+    expectEquals(gammaUnpacked.id, manager.extensions_[1].id);
+    expectEquals(aaFromStore.id, manager.extensions_[2].id);
+    expectEquals(AaFromStore.id, manager.extensions_[3].id);
+    expectEquals(aAFromStore.id, manager.extensions_[4].id);
+    expectEquals(alphaFromStore.id, manager.extensions_[5].id);
+  });
+
+  test(assert(extension_manager_unit_tests.TestNames.SetItemData), function() {
+    const description = 'description';
+
+    const extension = createExtensionInfo({description: description});
+    simulateExtensionInstall(extension);
+
+    // The detail view is not present until navigation.
+    expectFalse(!!manager.$$('extensions-detail-view'));
+    navigation.navigateTo({page: Page.DETAILS, extensionId: extension.id});
+    const detailsView = manager.$$('extensions-detail-view');
+    expectTrue(!!detailsView);  // View should now be present.
+    expectEquals(extension.id, detailsView.data.id);
+    expectEquals(description, detailsView.data.description);
+    expectEquals(
+        description,
+        detailsView.$$('.section .section-content').textContent.trim());
+  });
+
+  test(
+      assert(extension_manager_unit_tests.TestNames.UpdateItemData),
+      function() {
+        const oldDescription = 'old description';
+        const newDescription = 'new description';
+
+        const extension = createExtensionInfo({description: oldDescription});
+        simulateExtensionInstall(extension);
+        const secondExtension = createExtensionInfo({
+          description: 'irrelevant',
+          id: 'b'.repeat(32),
+        });
+        simulateExtensionInstall(secondExtension);
+
+        navigation.navigateTo({page: Page.DETAILS, extensionId: extension.id});
+        const detailsView = manager.$$('extensions-detail-view');
+
+        let extensionCopy = Object.assign({}, extension);
+        extensionCopy.description = newDescription;
+        service.itemStateChangedTarget.callListeners({
+          event_type: chrome.developerPrivate.EventType.PREFS_CHANGED,
+          extensionInfo: extensionCopy,
+        });
+
+        // Updating a different extension shouldn't have any impact.
+        let secondExtensionCopy = Object.assign({}, secondExtension);
+        secondExtensionCopy.description = 'something else';
+        service.itemStateChangedTarget.callListeners({
+          event_type: chrome.developerPrivate.EventType.PREFS_CHANGED,
+          extensionInfo: secondExtensionCopy,
+        });
+        expectEquals(extension.id, detailsView.data.id);
+        expectEquals(newDescription, detailsView.data.description);
+        expectEquals(
+            newDescription,
+            detailsView.$$('.section .section-content').textContent.trim());
+      });
+
+  test(
+      assert(extension_manager_unit_tests.TestNames.ProfileSettings),
+      function() {
+        expectFalse(manager.inDevMode);
+
+        service.profileStateChangedTarget.callListeners(
+            {inDeveloperMode: true});
+        expectTrue(manager.inDevMode);
+
+        service.profileStateChangedTarget.callListeners(
+            {inDeveloperMode: false});
+        expectFalse(manager.inDevMode);
+
+        service.profileStateChangedTarget.callListeners(
+            {canLoadUnpacked: true});
+        expectTrue(manager.canLoadUnpacked);
+
+        service.profileStateChangedTarget.callListeners(
+            {canLoadUnpacked: false});
+        expectFalse(manager.canLoadUnpacked);
+      });
+
+  test(assert(extension_manager_unit_tests.TestNames.Uninstall), function() {
+    expectEquals(0, manager.extensions_.length);
+
+    const extension = createExtensionInfo(
+        {location: 'FROM_STORE', name: 'Alpha', id: 'a'.repeat(32)});
+    simulateExtensionInstall(extension);
+    expectEquals(1, manager.extensions_.length);
+
+    service.itemStateChangedTarget.callListeners({
+      event_type: chrome.developerPrivate.EventType.UNINSTALLED,
+      // When an extension is uninstalled, only the ID is passed back from
+      // C++.
+      item_id: extension.id,
+    });
+
+    expectEquals(0, manager.extensions_.length);
+  });
+
+  /** @param {string} tagName */
+  function assertViewActive(tagName) {
+    expectTrue(!!manager.$.viewManager.querySelector(`${tagName}.active`));
+  }
+
+  test(
+      assert(extension_manager_unit_tests.TestNames.UninstallFromDetails),
+      function(done) {
+        const extension = createExtensionInfo(
+            {location: 'FROM_STORE', name: 'Alpha', id: 'a'.repeat(32)});
+        simulateExtensionInstall(extension);
+
+        navigation.navigateTo({page: Page.DETAILS, extensionId: extension.id});
+        flush();
+        assertViewActive('extensions-detail-view');
+
+        window.addEventListener('popstate', () => {
+          assertViewActive('extensions-item-list');
+          done();
+        });
+
+        service.itemStateChangedTarget.callListeners({
+          event_type: chrome.developerPrivate.EventType.UNINSTALLED,
+          // When an extension is uninstalled, only the ID is passed back from
+          // C++.
+          item_id: extension.id,
+        });
+      });
+
+  test(
+      assert(extension_manager_unit_tests.TestNames.ToggleIncognitoMode),
+      function() {
+        expectEquals(0, manager.extensions_.length);
+        const extension = createExtensionInfo(
+            {location: 'FROM_STORE', name: 'Alpha', id: 'a'.repeat(32)});
+        simulateExtensionInstall(extension);
+        expectEquals(1, manager.extensions_.length);
+
+        expectEquals(extension, manager.extensions_[0]);
+        expectTrue(extension.incognitoAccess.isEnabled);
+        expectFalse(extension.incognitoAccess.isActive);
+
+        // Simulate granting incognito permission.
+        const extensionCopy1 = Object.assign({}, extension);
+        extensionCopy1.incognitoAccess.isActive = true;
+        service.itemStateChangedTarget.callListeners({
+          event_type: chrome.developerPrivate.EventType.LOADED,
+          extensionInfo: extensionCopy1,
+        });
+
+        expectTrue(manager.extensions_[0].incognitoAccess.isActive);
+
+        // Simulate revoking incognito permission.
+        const extensionCopy2 = Object.assign({}, extension);
+        extensionCopy2.incognitoAccess.isActive = false;
+        service.itemStateChangedTarget.callListeners({
+          event_type: chrome.developerPrivate.EventType.LOADED,
+          extensionInfo: extensionCopy2,
+        });
+        expectFalse(manager.extensions_[0].incognitoAccess.isActive);
+      });
+
+  test(
+      assert(extension_manager_unit_tests.TestNames.EnableAndDisable),
+      function() {
+        const ExtensionState = chrome.developerPrivate.ExtensionState;
+        expectEquals(0, manager.extensions_.length);
+        const extension = createExtensionInfo({
+          location: 'FROM_STORE',
+          name: 'My extension 1',
+          id: 'a'.repeat(32)
+        });
+        simulateExtensionInstall(extension);
+        expectEquals(1, manager.extensions_.length);
+
+        expectEquals(extension, manager.extensions_[0]);
+        expectEquals('My extension 1', extension.name);
+        expectEquals(ExtensionState.ENABLED, extension.state);
+
+        // Simulate disabling an extension.
+        const extensionCopy1 = Object.assign({}, extension);
+        extensionCopy1.state = ExtensionState.DISABLED;
+        service.itemStateChangedTarget.callListeners({
+          event_type: chrome.developerPrivate.EventType.LOADED,
+          extensionInfo: extensionCopy1,
+        });
+        expectEquals(ExtensionState.DISABLED, manager.extensions_[0].state);
+
+        // Simulate re-enabling an extension.
+        // Simulate disabling an extension.
+        const extensionCopy2 = Object.assign({}, extension);
+        extensionCopy2.state = ExtensionState.ENABLED;
+        service.itemStateChangedTarget.callListeners({
+          event_type: chrome.developerPrivate.EventType.LOADED,
+          extensionInfo: extensionCopy2,
+        });
+        expectEquals(ExtensionState.ENABLED, manager.extensions_[0].state);
+      });
+});
diff --git a/chrome/test/data/webui/extensions/navigation_helper_test.js b/chrome/test/data/webui/extensions/navigation_helper_test.js
index d85abcf..915bf91 100644
--- a/chrome/test/data/webui/extensions/navigation_helper_test.js
+++ b/chrome/test/data/webui/extensions/navigation_helper_test.js
@@ -7,199 +7,194 @@
 import {assert} from 'chrome://resources/js/assert.m.js';
 import {MockMethod} from '../mock_controller.m.js';
 
-  window.extension_navigation_helper_tests = {};
-  extension_navigation_helper_tests.suiteName = 'ExtensionNavigationHelperTest';
-  /** @enum {string} */
-  extension_navigation_helper_tests.TestNames = {
-    Basic: 'basic',
-    Conversions: 'conversions',
-    PushAndReplaceState: 'push and replace state',
-    SupportedRoutes: 'supported routes'
-  };
+window.extension_navigation_helper_tests = {};
+extension_navigation_helper_tests.suiteName = 'ExtensionNavigationHelperTest';
+/** @enum {string} */
+extension_navigation_helper_tests.TestNames = {
+  Basic: 'basic',
+  Conversions: 'conversions',
+  PushAndReplaceState: 'push and replace state',
+  SupportedRoutes: 'supported routes'
+};
 
-  /**
-   * @return {!Promise<void>} A promise that resolves after the next popstate
-   *     event.
-   */
-  function getOnPopState() {
-    return new Promise(function(resolve, reject) {
-      window.addEventListener('popstate', function listener() {
-        window.removeEventListener('popstate', listener);
-        // Resolve asynchronously to allow all other listeners to run.
-        window.setTimeout(resolve, 0);
-      });
+/**
+ * @return {!Promise<void>} A promise that resolves after the next popstate
+ *     event.
+ */
+function getOnPopState() {
+  return new Promise(function(resolve, reject) {
+    window.addEventListener('popstate', function listener() {
+      window.removeEventListener('popstate', listener);
+      // Resolve asynchronously to allow all other listeners to run.
+      window.setTimeout(resolve, 0);
     });
-  }
+  });
+}
 
-  suite(extension_navigation_helper_tests.suiteName, function() {
-    let navigationHelper;
+suite(extension_navigation_helper_tests.suiteName, function() {
+  let navigationHelper;
 
-    setup(function() {
-      PolymerTest.clearBody();
-      navigationHelper = new NavigationHelper();
-    });
+  setup(function() {
+    PolymerTest.clearBody();
+    navigationHelper = new NavigationHelper();
+  });
 
-    test(assert(extension_navigation_helper_tests.TestNames.Basic), function() {
-      const id = 'a'.repeat(32);
-      const mock = new MockMethod();
-      const changePage = function(state) {
-        mock.recordCall([state]);
-      };
+  test(assert(extension_navigation_helper_tests.TestNames.Basic), function() {
+    const id = 'a'.repeat(32);
+    const mock = new MockMethod();
+    const changePage = function(state) {
+      mock.recordCall([state]);
+    };
 
-      navigationHelper.addListener(changePage);
+    navigationHelper.addListener(changePage);
 
-      expectDeepEquals({page: Page.LIST}, navigationHelper.getCurrentPage());
+    expectDeepEquals({page: Page.LIST}, navigationHelper.getCurrentPage());
 
-      let currentLength = history.length;
-      navigationHelper.updateHistory({page: Page.DETAILS, extensionId: id});
-      expectEquals(++currentLength, history.length);
+    let currentLength = history.length;
+    navigationHelper.updateHistory({page: Page.DETAILS, extensionId: id});
+    expectEquals(++currentLength, history.length);
 
-      navigationHelper.updateHistory({page: Page.ERRORS, extensionId: id});
-      expectEquals(++currentLength, history.length);
+    navigationHelper.updateHistory({page: Page.ERRORS, extensionId: id});
+    expectEquals(++currentLength, history.length);
 
-      mock.addExpectation({page: Page.DETAILS, extensionId: id});
-      const waitForPop = getOnPopState();
-      history.back();
-      return waitForPop
-          .then(() => {
-            mock.verifyMock();
+    mock.addExpectation({page: Page.DETAILS, extensionId: id});
+    const waitForPop = getOnPopState();
+    history.back();
+    return waitForPop
+        .then(() => {
+          mock.verifyMock();
 
-            mock.addExpectation({page: Page.LIST});
-            const waitForNextPop = getOnPopState();
-            history.back();
-            return waitForNextPop;
-          })
-          .then(() => {
-            mock.verifyMock();
-          });
-    });
-
-    test(
-        assert(extension_navigation_helper_tests.TestNames.Conversions),
-        function() {
-          const id = 'a'.repeat(32);
-          const stateUrlPairs = {
-            extensions: {
-              url: 'chrome://extensions/',
-              state: {page: Page.LIST},
-            },
-            details: {
-              url: 'chrome://extensions/?id=' + id,
-              state: {page: Page.DETAILS, extensionId: id},
-            },
-            options: {
-              url: 'chrome://extensions/?options=' + id,
-              state: {
-                page: Page.DETAILS,
-                extensionId: id,
-                subpage: Dialog.OPTIONS,
-              },
-            },
-            errors: {
-              url: 'chrome://extensions/?errors=' + id,
-              state: {page: Page.ERRORS, extensionId: id},
-            },
-            shortcuts: {
-              url: 'chrome://extensions/shortcuts',
-              state: {page: Page.SHORTCUTS},
-            },
-          };
-
-          // Test url -> state.
-          for (let key in stateUrlPairs) {
-            let entry = stateUrlPairs[key];
-            history.pushState({}, '', entry.url);
-            expectDeepEquals(
-                entry.state, navigationHelper.getCurrentPage(), key);
-          }
-
-          // Test state -> url.
-          for (let key in stateUrlPairs) {
-            let entry = stateUrlPairs[key];
-            navigationHelper.updateHistory(entry.state);
-            expectEquals(entry.url, location.href, key);
-          }
-        });
-
-    test(
-        assert(extension_navigation_helper_tests.TestNames.PushAndReplaceState),
-        function() {
-          const id1 = 'a'.repeat(32);
-          const id2 = 'b'.repeat(32);
-
-          history.pushState({}, '', 'chrome://extensions/');
-          expectDeepEquals(
-              {page: Page.LIST}, navigationHelper.getCurrentPage());
-
-          let expectedLength = history.length;
-
-          // Navigating to a new page pushes new state.
-          navigationHelper.updateHistory(
-              {page: Page.DETAILS, extensionId: id1});
-          expectEquals(++expectedLength, history.length);
-
-          // Navigating to a subpage (like the options page) just opens a
-          // dialog, and shouldn't push new state.
-          navigationHelper.updateHistory(
-              {page: Page.DETAILS, extensionId: id1, subpage: Dialog.OPTIONS});
-          expectEquals(expectedLength, history.length);
-
-          // Navigating away from a subpage also shouldn't push state (it just
-          // closes the dialog).
-          navigationHelper.updateHistory(
-              {page: Page.DETAILS, extensionId: id1});
-          expectEquals(expectedLength, history.length);
-
-          // Navigating away should push new state.
-          navigationHelper.updateHistory({page: Page.LIST});
-          expectEquals(++expectedLength, history.length);
-
-          // Navigating to a subpage of a different page should push state.
-          navigationHelper.updateHistory(
-              {page: Page.DETAILS, extensionId: id1, subpage: Dialog.OPTIONS});
-          expectEquals(++expectedLength, history.length);
-
-          // Navigating away from a subpage to a page for a different item
-          // should push state.
-          navigationHelper.updateHistory(
-              {page: Page.DETAILS, extensionId: id2});
-          expectEquals(++expectedLength, history.length);
-
-          // Using replaceWith, which passes true for replaceState should not
-          // push state.
-          navigationHelper.updateHistory(
-              {page: Page.DETAILS, extensionId: id1}, true /* replaceState */);
-          expectEquals(expectedLength, history.length);
-        });
-
-    test(
-        assert(extension_navigation_helper_tests.TestNames.SupportedRoutes),
-        function() {
-          function removeEndSlash(url) {
-            const CANONICAL_PATH_REGEX = /([\/-\w]+)\/$/;
-            return url.replace(CANONICAL_PATH_REGEX, '$1');
-          }
-
-          // If it should not redirect, leave newUrl as undefined.
-          function testIfRedirected(url, newUrl) {
-            history.pushState({}, '', url);
-            const testNavigationHelper = new NavigationHelper();
-            expectEquals(
-                removeEndSlash(window.location.href),
-                removeEndSlash(newUrl || url));
-          }
-
-          testIfRedirected('chrome://extensions');
-          testIfRedirected('chrome://extensions/');
-          testIfRedirected('chrome://extensions/shortcuts');
-          testIfRedirected('chrome://extensions/shortcuts/');
-          testIfRedirected(
-              'chrome://extensions/fake-route', 'chrome://extensions');
-          // Test trailing slash works.
-
-          // Test legacy paths
-          testIfRedirected(
-              'chrome://extensions/configureCommands',
-              'chrome://extensions/shortcuts');
+          mock.addExpectation({page: Page.LIST});
+          const waitForNextPop = getOnPopState();
+          history.back();
+          return waitForNextPop;
+        })
+        .then(() => {
+          mock.verifyMock();
         });
   });
+
+  test(
+      assert(extension_navigation_helper_tests.TestNames.Conversions),
+      function() {
+        const id = 'a'.repeat(32);
+        const stateUrlPairs = {
+          extensions: {
+            url: 'chrome://extensions/',
+            state: {page: Page.LIST},
+          },
+          details: {
+            url: 'chrome://extensions/?id=' + id,
+            state: {page: Page.DETAILS, extensionId: id},
+          },
+          options: {
+            url: 'chrome://extensions/?options=' + id,
+            state: {
+              page: Page.DETAILS,
+              extensionId: id,
+              subpage: Dialog.OPTIONS,
+            },
+          },
+          errors: {
+            url: 'chrome://extensions/?errors=' + id,
+            state: {page: Page.ERRORS, extensionId: id},
+          },
+          shortcuts: {
+            url: 'chrome://extensions/shortcuts',
+            state: {page: Page.SHORTCUTS},
+          },
+        };
+
+        // Test url -> state.
+        for (let key in stateUrlPairs) {
+          let entry = stateUrlPairs[key];
+          history.pushState({}, '', entry.url);
+          expectDeepEquals(entry.state, navigationHelper.getCurrentPage(), key);
+        }
+
+        // Test state -> url.
+        for (let key in stateUrlPairs) {
+          let entry = stateUrlPairs[key];
+          navigationHelper.updateHistory(entry.state);
+          expectEquals(entry.url, location.href, key);
+        }
+      });
+
+  test(
+      assert(extension_navigation_helper_tests.TestNames.PushAndReplaceState),
+      function() {
+        const id1 = 'a'.repeat(32);
+        const id2 = 'b'.repeat(32);
+
+        history.pushState({}, '', 'chrome://extensions/');
+        expectDeepEquals({page: Page.LIST}, navigationHelper.getCurrentPage());
+
+        let expectedLength = history.length;
+
+        // Navigating to a new page pushes new state.
+        navigationHelper.updateHistory({page: Page.DETAILS, extensionId: id1});
+        expectEquals(++expectedLength, history.length);
+
+        // Navigating to a subpage (like the options page) just opens a
+        // dialog, and shouldn't push new state.
+        navigationHelper.updateHistory(
+            {page: Page.DETAILS, extensionId: id1, subpage: Dialog.OPTIONS});
+        expectEquals(expectedLength, history.length);
+
+        // Navigating away from a subpage also shouldn't push state (it just
+        // closes the dialog).
+        navigationHelper.updateHistory({page: Page.DETAILS, extensionId: id1});
+        expectEquals(expectedLength, history.length);
+
+        // Navigating away should push new state.
+        navigationHelper.updateHistory({page: Page.LIST});
+        expectEquals(++expectedLength, history.length);
+
+        // Navigating to a subpage of a different page should push state.
+        navigationHelper.updateHistory(
+            {page: Page.DETAILS, extensionId: id1, subpage: Dialog.OPTIONS});
+        expectEquals(++expectedLength, history.length);
+
+        // Navigating away from a subpage to a page for a different item
+        // should push state.
+        navigationHelper.updateHistory({page: Page.DETAILS, extensionId: id2});
+        expectEquals(++expectedLength, history.length);
+
+        // Using replaceWith, which passes true for replaceState should not
+        // push state.
+        navigationHelper.updateHistory(
+            {page: Page.DETAILS, extensionId: id1}, true /* replaceState */);
+        expectEquals(expectedLength, history.length);
+      });
+
+  test(
+      assert(extension_navigation_helper_tests.TestNames.SupportedRoutes),
+      function() {
+        function removeEndSlash(url) {
+          const CANONICAL_PATH_REGEX = /([\/-\w]+)\/$/;
+          return url.replace(CANONICAL_PATH_REGEX, '$1');
+        }
+
+        // If it should not redirect, leave newUrl as undefined.
+        function testIfRedirected(url, newUrl) {
+          history.pushState({}, '', url);
+          const testNavigationHelper = new NavigationHelper();
+          expectEquals(
+              removeEndSlash(window.location.href),
+              removeEndSlash(newUrl || url));
+        }
+
+        testIfRedirected('chrome://extensions');
+        testIfRedirected('chrome://extensions/');
+        testIfRedirected('chrome://extensions/shortcuts');
+        testIfRedirected('chrome://extensions/shortcuts/');
+        testIfRedirected(
+            'chrome://extensions/fake-route', 'chrome://extensions');
+        // Test trailing slash works.
+
+        // Test legacy paths
+        testIfRedirected(
+            'chrome://extensions/configureCommands',
+            'chrome://extensions/shortcuts');
+      });
+});
diff --git a/chrome/test/data/webui/extensions/options_dialog_test.js b/chrome/test/data/webui/extensions/options_dialog_test.js
index abc120e..95f52e6 100644
--- a/chrome/test/data/webui/extensions/options_dialog_test.js
+++ b/chrome/test/data/webui/extensions/options_dialog_test.js
@@ -8,61 +8,61 @@
 import {assert} from 'chrome://resources/js/assert.m.js';
 import {eventToPromise} from '../test_util.m.js';
 
-  window.extension_options_dialog_tests = {};
-  extension_options_dialog_tests.suiteName = 'ExtensionOptionsDialogTests';
-  /** @enum {string} */
-  extension_options_dialog_tests.TestNames = {
-    Layout: 'Layout',
-  };
+window.extension_options_dialog_tests = {};
+extension_options_dialog_tests.suiteName = 'ExtensionOptionsDialogTests';
+/** @enum {string} */
+extension_options_dialog_tests.TestNames = {
+  Layout: 'Layout',
+};
 
-  suite(extension_options_dialog_tests.suiteName, function() {
-    /** @type {ExtensionsOptionsDialogElement} */
-    let optionsDialog;
+suite(extension_options_dialog_tests.suiteName, function() {
+  /** @type {ExtensionsOptionsDialogElement} */
+  let optionsDialog;
 
-    /** @type {chrome.developerPrivate.ExtensionInfo} */
-    let data;
+  /** @type {chrome.developerPrivate.ExtensionInfo} */
+  let data;
 
-    setup(function() {
-      PolymerTest.clearBody();
-      optionsDialog = document.createElement('extensions-options-dialog');
-      document.body.appendChild(optionsDialog);
+  setup(function() {
+    PolymerTest.clearBody();
+    optionsDialog = document.createElement('extensions-options-dialog');
+    document.body.appendChild(optionsDialog);
 
-      const service = Service.getInstance();
-      return service.getExtensionsInfo().then(function(info) {
-        assertEquals(1, info.length);
-        data = info[0];
-      });
-    });
-
-    function isDialogVisible() {
-      const dialogElement = optionsDialog.$.dialog.getNative();
-      const rect = dialogElement.getBoundingClientRect();
-      return rect.width * rect.height > 0;
-    }
-
-    test(assert(extension_options_dialog_tests.TestNames.Layout), function() {
-      // Try showing the dialog.
-      assertFalse(isDialogVisible());
-      optionsDialog.show(data);
-      return eventToPromise('cr-dialog-open', optionsDialog)
-          .then(() => {
-            // Wait more than 50ms for the debounced size update.
-            return new Promise(r => setTimeout(r, 100));
-          })
-          .then(() => {
-            assertTrue(isDialogVisible());
-
-            const dialogElement = optionsDialog.$.dialog.getNative();
-            const rect = dialogElement.getBoundingClientRect();
-            assertGE(rect.width, OptionsDialogMinWidth);
-            assertLE(rect.height, OptionsDialogMaxHeight);
-            // This is the header height with default font size.
-            assertGE(rect.height, 68);
-
-            assertEquals(
-                data.name,
-                assert(optionsDialog.$$('#icon-and-name-wrapper span'))
-                    .textContent.trim());
-          });
+    const service = Service.getInstance();
+    return service.getExtensionsInfo().then(function(info) {
+      assertEquals(1, info.length);
+      data = info[0];
     });
   });
+
+  function isDialogVisible() {
+    const dialogElement = optionsDialog.$.dialog.getNative();
+    const rect = dialogElement.getBoundingClientRect();
+    return rect.width * rect.height > 0;
+  }
+
+  test(assert(extension_options_dialog_tests.TestNames.Layout), function() {
+    // Try showing the dialog.
+    assertFalse(isDialogVisible());
+    optionsDialog.show(data);
+    return eventToPromise('cr-dialog-open', optionsDialog)
+        .then(() => {
+          // Wait more than 50ms for the debounced size update.
+          return new Promise(r => setTimeout(r, 100));
+        })
+        .then(() => {
+          assertTrue(isDialogVisible());
+
+          const dialogElement = optionsDialog.$.dialog.getNative();
+          const rect = dialogElement.getBoundingClientRect();
+          assertGE(rect.width, OptionsDialogMinWidth);
+          assertLE(rect.height, OptionsDialogMaxHeight);
+          // This is the header height with default font size.
+          assertGE(rect.height, 68);
+
+          assertEquals(
+              data.name,
+              assert(optionsDialog.$$('#icon-and-name-wrapper span'))
+                  .textContent.trim());
+        });
+  });
+});
diff --git a/chrome/test/data/webui/extensions/pack_dialog_test.js b/chrome/test/data/webui/extensions/pack_dialog_test.js
index ab1497ae..7848df9f 100644
--- a/chrome/test/data/webui/extensions/pack_dialog_test.js
+++ b/chrome/test/data/webui/extensions/pack_dialog_test.js
@@ -14,221 +14,221 @@
 
 import {isElementVisible} from './test_util.js';
 
-  window.extension_pack_dialog_tests = {};
-  extension_pack_dialog_tests.suiteName = 'ExtensionPackDialogTests';
-  /** @enum {string} */
-  extension_pack_dialog_tests.TestNames = {
-    Interaction: 'Interaction',
-    PackSuccess: 'PackSuccess',
-    PackWarning: 'PackWarning',
-    PackError: 'PackError',
-  };
+window.extension_pack_dialog_tests = {};
+extension_pack_dialog_tests.suiteName = 'ExtensionPackDialogTests';
+/** @enum {string} */
+extension_pack_dialog_tests.TestNames = {
+  Interaction: 'Interaction',
+  PackSuccess: 'PackSuccess',
+  PackWarning: 'PackWarning',
+  PackError: 'PackError',
+};
 
-  /** @implements {PackDialogDelegate} */
-  class MockDelegate {
-    constructor() {
-      this.mockResponse = null;
-      this.rootPromise;
-      this.keyPromise;
-      this.flag = 0;
-    }
-
-    /** @override */
-    choosePackRootDirectory() {
-      this.rootPromise = new PromiseResolver();
-      return this.rootPromise.promise;
-    }
-
-    /** @override */
-    choosePrivateKeyPath() {
-      this.keyPromise = new PromiseResolver();
-      return this.keyPromise.promise;
-    }
-
-    /** @override */
-    packExtension(rootPath, keyPath, flag, callback) {
-      this.rootPath = rootPath;
-      this.keyPath = keyPath;
-      this.flag = flag;
-
-      if (callback && this.mockResponse) {
-        callback(this.mockResponse);
-      }
-    }
+/** @implements {PackDialogDelegate} */
+class MockDelegate {
+  constructor() {
+    this.mockResponse = null;
+    this.rootPromise;
+    this.keyPromise;
+    this.flag = 0;
   }
 
-  suite(extension_pack_dialog_tests.suiteName, function() {
-    /** @type {ExtensionsPackDialogElement} */
-    let packDialog;
+  /** @override */
+  choosePackRootDirectory() {
+    this.rootPromise = new PromiseResolver();
+    return this.rootPromise.promise;
+  }
 
-    /** @type {MockDelegate} */
-    let mockDelegate;
+  /** @override */
+  choosePrivateKeyPath() {
+    this.keyPromise = new PromiseResolver();
+    return this.keyPromise.promise;
+  }
 
-    setup(function() {
-      PolymerTest.clearBody();
-      mockDelegate = new MockDelegate();
-      packDialog = document.createElement('extensions-pack-dialog');
-      packDialog.delegate = mockDelegate;
-      document.body.appendChild(packDialog);
-    });
+  /** @override */
+  packExtension(rootPath, keyPath, flag, callback) {
+    this.rootPath = rootPath;
+    this.keyPath = keyPath;
+    this.flag = flag;
 
-    test(assert(extension_pack_dialog_tests.TestNames.Interaction), function() {
-      const dialogElement = packDialog.$$('cr-dialog').getNative();
+    if (callback && this.mockResponse) {
+      callback(this.mockResponse);
+    }
+  }
+}
 
-      expectTrue(isElementVisible(dialogElement));
-      expectEquals('', packDialog.$$('#root-dir').value);
-      packDialog.$$('#root-dir-browse').click();
-      expectTrue(!!mockDelegate.rootPromise);
-      expectEquals('', packDialog.$$('#root-dir').value);
-      const kRootPath = 'this/is/a/path';
+suite(extension_pack_dialog_tests.suiteName, function() {
+  /** @type {ExtensionsPackDialogElement} */
+  let packDialog;
 
-      const promises = [];
-      promises.push(mockDelegate.rootPromise.promise.then(function() {
-        expectEquals(kRootPath, packDialog.$$('#root-dir').value);
-        expectEquals(kRootPath, packDialog.packDirectory_);
-      }));
+  /** @type {MockDelegate} */
+  let mockDelegate;
 
-      flush();
-      expectEquals('', packDialog.$$('#key-file').value);
-      packDialog.$$('#key-file-browse').click();
-      expectTrue(!!mockDelegate.keyPromise);
-      expectEquals('', packDialog.$$('#key-file').value);
-      const kKeyPath = 'here/is/another/path';
+  setup(function() {
+    PolymerTest.clearBody();
+    mockDelegate = new MockDelegate();
+    packDialog = document.createElement('extensions-pack-dialog');
+    packDialog.delegate = mockDelegate;
+    document.body.appendChild(packDialog);
+  });
 
-      promises.push(mockDelegate.keyPromise.promise.then(function() {
-        expectEquals(kKeyPath, packDialog.$$('#key-file').value);
-        expectEquals(kKeyPath, packDialog.keyFile_);
-      }));
+  test(assert(extension_pack_dialog_tests.TestNames.Interaction), function() {
+    const dialogElement = packDialog.$$('cr-dialog').getNative();
 
-      mockDelegate.rootPromise.resolve(kRootPath);
-      mockDelegate.keyPromise.resolve(kKeyPath);
+    expectTrue(isElementVisible(dialogElement));
+    expectEquals('', packDialog.$$('#root-dir').value);
+    packDialog.$$('#root-dir-browse').click();
+    expectTrue(!!mockDelegate.rootPromise);
+    expectEquals('', packDialog.$$('#root-dir').value);
+    const kRootPath = 'this/is/a/path';
 
-      return Promise.all(promises).then(function() {
-        packDialog.$$('.action-button').click();
-        expectEquals(kRootPath, mockDelegate.rootPath);
-        expectEquals(kKeyPath, mockDelegate.keyPath);
-      });
-    });
+    const promises = [];
+    promises.push(mockDelegate.rootPromise.promise.then(function() {
+      expectEquals(kRootPath, packDialog.$$('#root-dir').value);
+      expectEquals(kRootPath, packDialog.packDirectory_);
+    }));
 
-    test(assert(extension_pack_dialog_tests.TestNames.PackSuccess), function() {
-      const dialogElement = packDialog.$$('cr-dialog').getNative();
-      let packDialogAlert;
-      let alertElement;
+    flush();
+    expectEquals('', packDialog.$$('#key-file').value);
+    packDialog.$$('#key-file-browse').click();
+    expectTrue(!!mockDelegate.keyPromise);
+    expectEquals('', packDialog.$$('#key-file').value);
+    const kKeyPath = 'here/is/another/path';
 
-      expectTrue(isElementVisible(dialogElement));
+    promises.push(mockDelegate.keyPromise.promise.then(function() {
+      expectEquals(kKeyPath, packDialog.$$('#key-file').value);
+      expectEquals(kKeyPath, packDialog.keyFile_);
+    }));
 
-      const kRootPath = 'this/is/a/path';
-      mockDelegate.mockResponse = {
-        status: chrome.developerPrivate.PackStatus.SUCCESS
-      };
+    mockDelegate.rootPromise.resolve(kRootPath);
+    mockDelegate.keyPromise.resolve(kKeyPath);
 
-      packDialog.$$('#root-dir-browse').click();
-      mockDelegate.rootPromise.resolve(kRootPath);
-
-      return mockDelegate.rootPromise.promise
-          .then(() => {
-            expectEquals(kRootPath, packDialog.$$('#root-dir').value);
-            packDialog.$$('.action-button').click();
-
-            return flushTasks();
-          })
-          .then(() => {
-            packDialogAlert = packDialog.$$('extensions-pack-dialog-alert');
-            alertElement = packDialogAlert.$.dialog.getNative();
-            expectTrue(isElementVisible(alertElement));
-            expectTrue(isElementVisible(dialogElement));
-            expectTrue(!!packDialogAlert.$$('.action-button'));
-
-            const wait = eventToPromise('close', dialogElement);
-            // After 'ok', both dialogs should be closed.
-            packDialogAlert.$$('.action-button').click();
-
-            return wait;
-          })
-          .then(() => {
-            expectFalse(isElementVisible(alertElement));
-            expectFalse(isElementVisible(dialogElement));
-          });
-    });
-
-    test(assert(extension_pack_dialog_tests.TestNames.PackError), function() {
-      const dialogElement = packDialog.$$('cr-dialog').getNative();
-      let packDialogAlert;
-      let alertElement;
-
-      expectTrue(isElementVisible(dialogElement));
-
-      const kRootPath = 'this/is/a/path';
-      mockDelegate.mockResponse = {
-        status: chrome.developerPrivate.PackStatus.ERROR
-      };
-
-      packDialog.$$('#root-dir-browse').click();
-      mockDelegate.rootPromise.resolve(kRootPath);
-
-      return mockDelegate.rootPromise.promise.then(() => {
-        expectEquals(kRootPath, packDialog.$$('#root-dir').value);
-        packDialog.$$('.action-button').click();
-        flush();
-
-        // Make sure new alert and the appropriate buttons are visible.
-        packDialogAlert = packDialog.$$('extensions-pack-dialog-alert');
-        alertElement = packDialogAlert.$.dialog.getNative();
-        expectTrue(isElementVisible(alertElement));
-        expectTrue(isElementVisible(dialogElement));
-        expectTrue(!!packDialogAlert.$$('.action-button'));
-
-        // After cancel, original dialog is still open and values unchanged.
-        packDialogAlert.$$('.action-button').click();
-        flush();
-        expectFalse(isElementVisible(alertElement));
-        expectTrue(isElementVisible(dialogElement));
-        expectEquals(kRootPath, packDialog.$$('#root-dir').value);
-      });
-    });
-
-    test(assert(extension_pack_dialog_tests.TestNames.PackWarning), function() {
-      const dialogElement = packDialog.$$('cr-dialog').getNative();
-      let packDialogAlert;
-      let alertElement;
-
-      expectTrue(isElementVisible(dialogElement));
-
-      const kRootPath = 'this/is/a/path';
-      mockDelegate.mockResponse = {
-        status: chrome.developerPrivate.PackStatus.WARNING,
-        item_path: 'item_path',
-        pem_path: 'pem_path',
-        override_flags: 1,
-      };
-
-      packDialog.$$('#root-dir-browse').click();
-      mockDelegate.rootPromise.resolve(kRootPath);
-
-      return mockDelegate.rootPromise.promise
-          .then(() => {
-            expectEquals(kRootPath, packDialog.$$('#root-dir').value);
-            packDialog.$$('.action-button').click();
-            flush();
-
-            // Make sure new alert and the appropriate buttons are visible.
-            packDialogAlert = packDialog.$$('extensions-pack-dialog-alert');
-            alertElement = packDialogAlert.$.dialog.getNative();
-            expectTrue(isElementVisible(alertElement));
-            expectTrue(isElementVisible(dialogElement));
-            expectFalse(packDialogAlert.$$('.cancel-button').hidden);
-            expectFalse(packDialogAlert.$$('.action-button').hidden);
-
-            // Make sure "proceed anyway" try to pack extension again.
-            const whenClosed = eventToPromise('close', packDialogAlert);
-            packDialogAlert.$$('.action-button').click();
-            return whenClosed;
-          })
-          .then(() => {
-            // Make sure packExtension is called again with the right params.
-            expectFalse(isElementVisible(alertElement));
-            expectEquals(
-                mockDelegate.flag, mockDelegate.mockResponse.override_flags);
-          });
+    return Promise.all(promises).then(function() {
+      packDialog.$$('.action-button').click();
+      expectEquals(kRootPath, mockDelegate.rootPath);
+      expectEquals(kKeyPath, mockDelegate.keyPath);
     });
   });
+
+  test(assert(extension_pack_dialog_tests.TestNames.PackSuccess), function() {
+    const dialogElement = packDialog.$$('cr-dialog').getNative();
+    let packDialogAlert;
+    let alertElement;
+
+    expectTrue(isElementVisible(dialogElement));
+
+    const kRootPath = 'this/is/a/path';
+    mockDelegate.mockResponse = {
+      status: chrome.developerPrivate.PackStatus.SUCCESS
+    };
+
+    packDialog.$$('#root-dir-browse').click();
+    mockDelegate.rootPromise.resolve(kRootPath);
+
+    return mockDelegate.rootPromise.promise
+        .then(() => {
+          expectEquals(kRootPath, packDialog.$$('#root-dir').value);
+          packDialog.$$('.action-button').click();
+
+          return flushTasks();
+        })
+        .then(() => {
+          packDialogAlert = packDialog.$$('extensions-pack-dialog-alert');
+          alertElement = packDialogAlert.$.dialog.getNative();
+          expectTrue(isElementVisible(alertElement));
+          expectTrue(isElementVisible(dialogElement));
+          expectTrue(!!packDialogAlert.$$('.action-button'));
+
+          const wait = eventToPromise('close', dialogElement);
+          // After 'ok', both dialogs should be closed.
+          packDialogAlert.$$('.action-button').click();
+
+          return wait;
+        })
+        .then(() => {
+          expectFalse(isElementVisible(alertElement));
+          expectFalse(isElementVisible(dialogElement));
+        });
+  });
+
+  test(assert(extension_pack_dialog_tests.TestNames.PackError), function() {
+    const dialogElement = packDialog.$$('cr-dialog').getNative();
+    let packDialogAlert;
+    let alertElement;
+
+    expectTrue(isElementVisible(dialogElement));
+
+    const kRootPath = 'this/is/a/path';
+    mockDelegate.mockResponse = {
+      status: chrome.developerPrivate.PackStatus.ERROR
+    };
+
+    packDialog.$$('#root-dir-browse').click();
+    mockDelegate.rootPromise.resolve(kRootPath);
+
+    return mockDelegate.rootPromise.promise.then(() => {
+      expectEquals(kRootPath, packDialog.$$('#root-dir').value);
+      packDialog.$$('.action-button').click();
+      flush();
+
+      // Make sure new alert and the appropriate buttons are visible.
+      packDialogAlert = packDialog.$$('extensions-pack-dialog-alert');
+      alertElement = packDialogAlert.$.dialog.getNative();
+      expectTrue(isElementVisible(alertElement));
+      expectTrue(isElementVisible(dialogElement));
+      expectTrue(!!packDialogAlert.$$('.action-button'));
+
+      // After cancel, original dialog is still open and values unchanged.
+      packDialogAlert.$$('.action-button').click();
+      flush();
+      expectFalse(isElementVisible(alertElement));
+      expectTrue(isElementVisible(dialogElement));
+      expectEquals(kRootPath, packDialog.$$('#root-dir').value);
+    });
+  });
+
+  test(assert(extension_pack_dialog_tests.TestNames.PackWarning), function() {
+    const dialogElement = packDialog.$$('cr-dialog').getNative();
+    let packDialogAlert;
+    let alertElement;
+
+    expectTrue(isElementVisible(dialogElement));
+
+    const kRootPath = 'this/is/a/path';
+    mockDelegate.mockResponse = {
+      status: chrome.developerPrivate.PackStatus.WARNING,
+      item_path: 'item_path',
+      pem_path: 'pem_path',
+      override_flags: 1,
+    };
+
+    packDialog.$$('#root-dir-browse').click();
+    mockDelegate.rootPromise.resolve(kRootPath);
+
+    return mockDelegate.rootPromise.promise
+        .then(() => {
+          expectEquals(kRootPath, packDialog.$$('#root-dir').value);
+          packDialog.$$('.action-button').click();
+          flush();
+
+          // Make sure new alert and the appropriate buttons are visible.
+          packDialogAlert = packDialog.$$('extensions-pack-dialog-alert');
+          alertElement = packDialogAlert.$.dialog.getNative();
+          expectTrue(isElementVisible(alertElement));
+          expectTrue(isElementVisible(dialogElement));
+          expectFalse(packDialogAlert.$$('.cancel-button').hidden);
+          expectFalse(packDialogAlert.$$('.action-button').hidden);
+
+          // Make sure "proceed anyway" try to pack extension again.
+          const whenClosed = eventToPromise('close', packDialogAlert);
+          packDialogAlert.$$('.action-button').click();
+          return whenClosed;
+        })
+        .then(() => {
+          // Make sure packExtension is called again with the right params.
+          expectFalse(isElementVisible(alertElement));
+          expectEquals(
+              mockDelegate.flag, mockDelegate.mockResponse.override_flags);
+        });
+  });
+});
diff --git a/chrome/test/data/webui/extensions/shortcut_input_test.js b/chrome/test/data/webui/extensions/shortcut_input_test.js
index cf8f2bb..4921036 100644
--- a/chrome/test/data/webui/extensions/shortcut_input_test.js
+++ b/chrome/test/data/webui/extensions/shortcut_input_test.js
@@ -18,106 +18,104 @@
 
 import {TestService} from './test_service.js';
 
-  window.extension_shortcut_input_tests = {};
-  extension_shortcut_input_tests.suiteName = 'ExtensionShortcutInputTest';
-  /** @enum {string} */
-  extension_shortcut_input_tests.TestNames = {
-    Basic: 'basic',
-  };
+window.extension_shortcut_input_tests = {};
+extension_shortcut_input_tests.suiteName = 'ExtensionShortcutInputTest';
+/** @enum {string} */
+extension_shortcut_input_tests.TestNames = {
+  Basic: 'basic',
+};
 
-  suite(extension_shortcut_input_tests.suiteName, function() {
-    /** @type {ExtensionsShortcutInputElement} */
-    let input;
+suite(extension_shortcut_input_tests.suiteName, function() {
+  /** @type {ExtensionsShortcutInputElement} */
+  let input;
 
-    setup(function() {
-      PolymerTest.clearBody();
-      input = document.createElement('extensions-shortcut-input');
-      input.delegate = new TestService();
-      input.commandName = 'Command';
-      input.item = 'itemid';
-      document.body.appendChild(input);
-      flush();
-    });
-
-    test(assert(extension_shortcut_input_tests.TestNames.Basic), function() {
-      const field = input.$['input'];
-      assertEquals('', field.value);
-      const isClearVisible = isVisible.bind(null, input, '#clear', false);
-      expectFalse(isClearVisible());
-
-      // Click the input. Capture should start.
-      tap(field);
-      return input.delegate.whenCalled('setShortcutHandlingSuspended')
-          .then((arg) => {
-            assertTrue(arg);
-            input.delegate.reset();
-
-            assertEquals('', field.value);
-            expectFalse(isClearVisible());
-
-            // Press character.
-            keyDownOn(field, 'A', []);
-            assertEquals('', field.value);
-            expectTrue(field.errorMessage.startsWith('Include'));
-            // Add shift to character.
-            keyDownOn(field, 'A', ['shift']);
-            assertEquals('', field.value);
-            expectTrue(field.errorMessage.startsWith('Include'));
-            // Press ctrl.
-            keyDownOn(field, 17, ['ctrl']);
-            assertEquals('Ctrl', field.value);
-            assertEquals('Type a letter', field.errorMessage);
-            // Add shift.
-            keyDownOn(field, 16, ['ctrl', 'shift']);
-            assertEquals('Ctrl + Shift', field.value);
-            assertEquals('Type a letter', field.errorMessage);
-            // Remove shift.
-            keyUpOn(field, 16, ['ctrl']);
-            assertEquals('Ctrl', field.value);
-            assertEquals('Type a letter', field.errorMessage);
-            // Add alt (ctrl + alt is invalid).
-            keyDownOn(field, 18, ['ctrl', 'alt']);
-            assertEquals('Ctrl', field.value);
-            // Remove alt.
-            keyUpOn(field, 18, ['ctrl']);
-            assertEquals('Ctrl', field.value);
-            assertEquals('Type a letter', field.errorMessage);
-
-            // Add 'A'. Once a valid shortcut is typed (like Ctrl + A), it is
-            // committed.
-            keyDownOn(field, 65, ['ctrl']);
-            return input.delegate.whenCalled(
-                'updateExtensionCommandKeybinding');
-          })
-          .then((arg) => {
-            input.delegate.reset();
-            expectDeepEquals(['itemid', 'Command', 'Ctrl+A'], arg);
-            assertEquals('Ctrl + A', field.value);
-            assertEquals('Ctrl+A', input.shortcut);
-            expectTrue(isClearVisible());
-
-            // Test clearing the shortcut.
-            tap(input.$['clear']);
-            return input.delegate.whenCalled(
-                'updateExtensionCommandKeybinding');
-          })
-          .then((arg) => {
-            input.delegate.reset();
-            expectDeepEquals(['itemid', 'Command', ''], arg);
-            assertEquals('', input.shortcut);
-            expectFalse(isClearVisible());
-
-            tap(field);
-            return input.delegate.whenCalled('setShortcutHandlingSuspended');
-          })
-          .then((arg) => {
-            input.delegate.reset();
-            expectTrue(arg);
-
-            // Test ending capture using the escape key.
-            keyDownOn(field, 27);  // Escape key.
-            return input.delegate.whenCalled('setShortcutHandlingSuspended');
-          })
-          .then(expectFalse);
-    });
+  setup(function() {
+    PolymerTest.clearBody();
+    input = document.createElement('extensions-shortcut-input');
+    input.delegate = new TestService();
+    input.commandName = 'Command';
+    input.item = 'itemid';
+    document.body.appendChild(input);
+    flush();
   });
+
+  test(assert(extension_shortcut_input_tests.TestNames.Basic), function() {
+    const field = input.$['input'];
+    assertEquals('', field.value);
+    const isClearVisible = isVisible.bind(null, input, '#clear', false);
+    expectFalse(isClearVisible());
+
+    // Click the input. Capture should start.
+    tap(field);
+    return input.delegate.whenCalled('setShortcutHandlingSuspended')
+        .then((arg) => {
+          assertTrue(arg);
+          input.delegate.reset();
+
+          assertEquals('', field.value);
+          expectFalse(isClearVisible());
+
+          // Press character.
+          keyDownOn(field, 'A', []);
+          assertEquals('', field.value);
+          expectTrue(field.errorMessage.startsWith('Include'));
+          // Add shift to character.
+          keyDownOn(field, 'A', ['shift']);
+          assertEquals('', field.value);
+          expectTrue(field.errorMessage.startsWith('Include'));
+          // Press ctrl.
+          keyDownOn(field, 17, ['ctrl']);
+          assertEquals('Ctrl', field.value);
+          assertEquals('Type a letter', field.errorMessage);
+          // Add shift.
+          keyDownOn(field, 16, ['ctrl', 'shift']);
+          assertEquals('Ctrl + Shift', field.value);
+          assertEquals('Type a letter', field.errorMessage);
+          // Remove shift.
+          keyUpOn(field, 16, ['ctrl']);
+          assertEquals('Ctrl', field.value);
+          assertEquals('Type a letter', field.errorMessage);
+          // Add alt (ctrl + alt is invalid).
+          keyDownOn(field, 18, ['ctrl', 'alt']);
+          assertEquals('Ctrl', field.value);
+          // Remove alt.
+          keyUpOn(field, 18, ['ctrl']);
+          assertEquals('Ctrl', field.value);
+          assertEquals('Type a letter', field.errorMessage);
+
+          // Add 'A'. Once a valid shortcut is typed (like Ctrl + A), it is
+          // committed.
+          keyDownOn(field, 65, ['ctrl']);
+          return input.delegate.whenCalled('updateExtensionCommandKeybinding');
+        })
+        .then((arg) => {
+          input.delegate.reset();
+          expectDeepEquals(['itemid', 'Command', 'Ctrl+A'], arg);
+          assertEquals('Ctrl + A', field.value);
+          assertEquals('Ctrl+A', input.shortcut);
+          expectTrue(isClearVisible());
+
+          // Test clearing the shortcut.
+          tap(input.$['clear']);
+          return input.delegate.whenCalled('updateExtensionCommandKeybinding');
+        })
+        .then((arg) => {
+          input.delegate.reset();
+          expectDeepEquals(['itemid', 'Command', ''], arg);
+          assertEquals('', input.shortcut);
+          expectFalse(isClearVisible());
+
+          tap(field);
+          return input.delegate.whenCalled('setShortcutHandlingSuspended');
+        })
+        .then((arg) => {
+          input.delegate.reset();
+          expectTrue(arg);
+
+          // Test ending capture using the escape key.
+          keyDownOn(field, 27);  // Escape key.
+          return input.delegate.whenCalled('setShortcutHandlingSuspended');
+        })
+        .then(expectFalse);
+  });
+});
diff --git a/chrome/test/data/webui/extensions/sidebar_test.js b/chrome/test/data/webui/extensions/sidebar_test.js
index 075a35d..5a596ac 100644
--- a/chrome/test/data/webui/extensions/sidebar_test.js
+++ b/chrome/test/data/webui/extensions/sidebar_test.js
@@ -12,78 +12,78 @@
 
 import {testVisible} from './test_util.js';
 
-  window.extension_sidebar_tests = {};
-  extension_sidebar_tests.suiteName = 'ExtensionSidebarTest';
+window.extension_sidebar_tests = {};
+extension_sidebar_tests.suiteName = 'ExtensionSidebarTest';
 
-  /** @enum {string} */
-  extension_sidebar_tests.TestNames = {
-    LayoutAndClickHandlers: 'layout and click handlers',
-    SetSelected: 'set selected',
-  };
+/** @enum {string} */
+extension_sidebar_tests.TestNames = {
+  LayoutAndClickHandlers: 'layout and click handlers',
+  SetSelected: 'set selected',
+};
 
-  suite(extension_sidebar_tests.suiteName, function() {
-    /** @type {extensions.Sidebar} */
-    let sidebar;
+suite(extension_sidebar_tests.suiteName, function() {
+  /** @type {extensions.Sidebar} */
+  let sidebar;
 
-    setup(function() {
-      PolymerTest.clearBody();
-      sidebar = document.createElement('extensions-sidebar');
-      document.body.appendChild(sidebar);
-    });
+  setup(function() {
+    PolymerTest.clearBody();
+    sidebar = document.createElement('extensions-sidebar');
+    document.body.appendChild(sidebar);
+  });
 
-    test(assert(extension_sidebar_tests.TestNames.SetSelected), function() {
-      const selector = '.section-item.iron-selected';
-      expectFalse(!!sidebar.$$(selector));
+  test(assert(extension_sidebar_tests.TestNames.SetSelected), function() {
+    const selector = '.section-item.iron-selected';
+    expectFalse(!!sidebar.$$(selector));
 
-      window.history.replaceState(undefined, '', '/shortcuts');
-      PolymerTest.clearBody();
-      sidebar = document.createElement('extensions-sidebar');
-      document.body.appendChild(sidebar);
-      const whenSelected = eventToPromise('iron-select', sidebar.$.sectionMenu);
-      flush();
-      return whenSelected
-          .then(function() {
-            expectEquals(sidebar.$$(selector).id, 'sections-shortcuts');
+    window.history.replaceState(undefined, '', '/shortcuts');
+    PolymerTest.clearBody();
+    sidebar = document.createElement('extensions-sidebar');
+    document.body.appendChild(sidebar);
+    const whenSelected = eventToPromise('iron-select', sidebar.$.sectionMenu);
+    flush();
+    return whenSelected
+        .then(function() {
+          expectEquals(sidebar.$$(selector).id, 'sections-shortcuts');
 
-            window.history.replaceState(undefined, '', '/');
-            PolymerTest.clearBody();
-            sidebar = document.createElement('extensions-sidebar');
-            document.body.appendChild(sidebar);
-            const whenSelected =
-                eventToPromise('iron-select', sidebar.$.sectionMenu);
-            flush();
-            return whenSelected;
-          })
-          .then(function() {
-            expectEquals(sidebar.$$(selector).id, 'sections-extensions');
-          });
-    });
-
-    test(
-        assert(extension_sidebar_tests.TestNames.LayoutAndClickHandlers),
-        function(done) {
-          const boundTestVisible = testVisible.bind(null, sidebar);
-          boundTestVisible('#sections-extensions', true);
-          boundTestVisible('#sections-shortcuts', true);
-          boundTestVisible('#more-extensions', true);
-
-          sidebar.isSupervised = true;
+          window.history.replaceState(undefined, '', '/');
+          PolymerTest.clearBody();
+          sidebar = document.createElement('extensions-sidebar');
+          document.body.appendChild(sidebar);
+          const whenSelected =
+              eventToPromise('iron-select', sidebar.$.sectionMenu);
           flush();
-          boundTestVisible('#more-extensions', false);
-
-          let currentPage;
-          navigation.addListener(newPage => {
-            currentPage = newPage;
-          });
-
-          tap(sidebar.$$('#sections-shortcuts'));
-          expectDeepEquals(currentPage, {page: Page.SHORTCUTS});
-
-          tap(sidebar.$$('#sections-extensions'));
-          expectDeepEquals(currentPage, {page: Page.LIST});
-
-          // Clicking on the link for the current page should close the dialog.
-          sidebar.addEventListener('close-drawer', () => done());
-          tap(sidebar.$$('#sections-extensions'));
+          return whenSelected;
+        })
+        .then(function() {
+          expectEquals(sidebar.$$(selector).id, 'sections-extensions');
         });
   });
+
+  test(
+      assert(extension_sidebar_tests.TestNames.LayoutAndClickHandlers),
+      function(done) {
+        const boundTestVisible = testVisible.bind(null, sidebar);
+        boundTestVisible('#sections-extensions', true);
+        boundTestVisible('#sections-shortcuts', true);
+        boundTestVisible('#more-extensions', true);
+
+        sidebar.isSupervised = true;
+        flush();
+        boundTestVisible('#more-extensions', false);
+
+        let currentPage;
+        navigation.addListener(newPage => {
+          currentPage = newPage;
+        });
+
+        tap(sidebar.$$('#sections-shortcuts'));
+        expectDeepEquals(currentPage, {page: Page.SHORTCUTS});
+
+        tap(sidebar.$$('#sections-extensions'));
+        expectDeepEquals(currentPage, {page: Page.LIST});
+
+        // Clicking on the link for the current page should close the dialog.
+        sidebar.addEventListener('close-drawer', () => done());
+        tap(sidebar.$$('#sections-extensions'));
+      });
+});
diff --git a/chrome/test/data/webui/extensions/test_service.js b/chrome/test/data/webui/extensions/test_service.js
index bd3dc818..c6741f7c 100644
--- a/chrome/test/data/webui/extensions/test_service.js
+++ b/chrome/test/data/webui/extensions/test_service.js
@@ -5,218 +5,217 @@
 import {FakeChromeEvent} from '../fake_chrome_event.m.js';
 import {TestBrowserProxy} from '../test_browser_proxy.m.js';
 
-  /** An extensions.Service implementation to be used in tests. */
-  export class TestService extends TestBrowserProxy {
-    constructor() {
-      super([
-        'addRuntimeHostPermission',
-        'deleteActivitiesById',
-        'deleteActivitiesFromExtension',
-        'downloadActivities',
-        'getExtensionActivityLog',
-        'getExtensionsInfo',
-        'getExtensionSize',
-        'getFilteredExtensionActivityLog',
-        'getProfileConfiguration',
-        'loadUnpacked',
-        'retryLoadUnpacked',
-        'reloadItem',
-        'removeRuntimeHostPermission',
-        'setItemHostAccess',
-        'setProfileInDevMode',
-        'setShortcutHandlingSuspended',
-        'shouldIgnoreUpdate',
-        'updateAllExtensions',
-        'updateExtensionCommandKeybinding',
-        'updateExtensionCommandScope',
-      ]);
+/** An extensions.Service implementation to be used in tests. */
+export class TestService extends TestBrowserProxy {
+  constructor() {
+    super([
+      'addRuntimeHostPermission',
+      'deleteActivitiesById',
+      'deleteActivitiesFromExtension',
+      'downloadActivities',
+      'getExtensionActivityLog',
+      'getExtensionsInfo',
+      'getExtensionSize',
+      'getFilteredExtensionActivityLog',
+      'getProfileConfiguration',
+      'loadUnpacked',
+      'retryLoadUnpacked',
+      'reloadItem',
+      'removeRuntimeHostPermission',
+      'setItemHostAccess',
+      'setProfileInDevMode',
+      'setShortcutHandlingSuspended',
+      'shouldIgnoreUpdate',
+      'updateAllExtensions',
+      'updateExtensionCommandKeybinding',
+      'updateExtensionCommandScope',
+    ]);
 
-      this.itemStateChangedTarget = new FakeChromeEvent();
-      this.profileStateChangedTarget = new FakeChromeEvent();
-      this.extensionActivityTarget = new FakeChromeEvent();
+    this.itemStateChangedTarget = new FakeChromeEvent();
+    this.profileStateChangedTarget = new FakeChromeEvent();
+    this.extensionActivityTarget = new FakeChromeEvent();
 
-      /** @type {boolean} */
-      this.acceptRuntimeHostPermission = true;
+    /** @type {boolean} */
+    this.acceptRuntimeHostPermission = true;
 
-      /** @private {!chrome.developerPrivate.LoadError} */
-      this.retryLoadUnpackedError_;
+    /** @private {!chrome.developerPrivate.LoadError} */
+    this.retryLoadUnpackedError_;
 
-      /** @type {boolean} */
-      this.forceReloadItemError_ = false;
+    /** @type {boolean} */
+    this.forceReloadItemError_ = false;
 
-      /** @type {!chrome.activityLogPrivate.ActivityResultSet|undefined} */
-      this.testActivities;
-    }
-
-    /**
-     * @param {!chrome.developerPrivate.LoadError} error
-     */
-    setRetryLoadUnpackedError(error) {
-      this.retryLoadUnpackedError_ = error;
-    }
-
-    /**
-     * @param {boolean} force
-     */
-    setForceReloadItemError(force) {
-      this.forceReloadItemError_ = force;
-    }
-
-    /** @override */
-    addRuntimeHostPermission(id, site) {
-      this.methodCalled('addRuntimeHostPermission', [id, site]);
-      return this.acceptRuntimeHostPermission ? Promise.resolve() :
-                                                Promise.reject();
-    }
-
-    /** @override */
-    getProfileConfiguration() {
-      this.methodCalled('getProfileConfiguration');
-      return Promise.resolve({inDeveloperMode: false});
-    }
-
-    /** @override */
-    getItemStateChangedTarget() {
-      return this.itemStateChangedTarget;
-    }
-
-    /** @override */
-    getProfileStateChangedTarget() {
-      return this.profileStateChangedTarget;
-    }
-
-    /** @override */
-    getExtensionsInfo() {
-      this.methodCalled('getExtensionsInfo');
-      return Promise.resolve([]);
-    }
-
-    /** @override */
-    getExtensionSize() {
-      this.methodCalled('getExtensionSize');
-      return Promise.resolve('20 MB');
-    }
-
-    /** @override */
-    removeRuntimeHostPermission(id, site) {
-      this.methodCalled('removeRuntimeHostPermission', [id, site]);
-      return Promise.resolve();
-    }
-
-    /** @override */
-    setItemHostAccess(id, access) {
-      this.methodCalled('setItemHostAccess', [id, access]);
-    }
-
-    /** @override */
-    setShortcutHandlingSuspended(enable) {
-      this.methodCalled('setShortcutHandlingSuspended', enable);
-    }
-
-    /** @override */
-    shouldIgnoreUpdate(extensionId, eventType) {
-      this.methodCalled('shouldIgnoreUpdate', [extensionId, eventType]);
-    }
-
-    /** @override */
-    updateExtensionCommandKeybinding(item, commandName, keybinding) {
-      this.methodCalled(
-          'updateExtensionCommandKeybinding', [item, commandName, keybinding]);
-    }
-
-    /** @override */
-    updateExtensionCommandScope(item, commandName, scope) {
-      this.methodCalled(
-          'updateExtensionCommandScope', [item, commandName, scope]);
-    }
-
-    /** @override */
-    loadUnpacked() {
-      this.methodCalled('loadUnpacked');
-      return Promise.resolve();
-    }
-
-    /** @override */
-    reloadItem(id) {
-      this.methodCalled('reloadItem', id);
-      return this.forceReloadItemError_ ? Promise.reject() : Promise.resolve();
-    }
-
-    /** @override */
-    retryLoadUnpacked(guid) {
-      this.methodCalled('retryLoadUnpacked', guid);
-      return (this.retryLoadUnpackedError_ !== undefined) ?
-          Promise.reject(this.retryLoadUnpackedError_) :
-          Promise.resolve();
-    }
-
-    /** @override */
-    setProfileInDevMode(inDevMode) {
-      this.methodCalled('setProfileInDevMode', inDevMode);
-    }
-
-    /** @override */
-    updateAllExtensions() {
-      this.methodCalled('updateAllExtensions');
-      return Promise.resolve();
-    }
-
-    /** @override */
-    getExtensionActivityLog(id) {
-      this.methodCalled('getExtensionActivityLog', id);
-      return Promise.resolve(this.testActivities);
-    }
-
-    /** @override */
-    getFilteredExtensionActivityLog(id, searchTerm) {
-      // This is functionally identical to getFilteredExtensionActivityLog in
-      // service.js but we do the filtering here instead of making API calls
-      // with filter objects.
-      this.methodCalled('getFilteredExtensionActivityLog', id, searchTerm);
-
-      // Convert everything to lowercase as searching is not case sensitive.
-      const lowerCaseSearchTerm = searchTerm.toLowerCase();
-
-      const activities = this.testActivities.activities;
-      const apiCallMatches = activities.filter(
-          activity =>
-              activity.apiCall.toLowerCase().includes(lowerCaseSearchTerm));
-      const pageUrlMatches = activities.filter(
-          activity => activity.pageUrl &&
-              activity.pageUrl.toLowerCase().includes(lowerCaseSearchTerm));
-      const argUrlMatches = activities.filter(
-          activity => activity.argUrl &&
-              activity.argUrl.toLowerCase().includes(lowerCaseSearchTerm));
-
-      return Promise.resolve({
-        activities: [...apiCallMatches, ...pageUrlMatches, ...argUrlMatches]
-      });
-    }
-
-    /** @override */
-    deleteActivitiesById(activityIds) {
-      // Pretend to delete all activities specified by activityIds.
-      const newActivities = this.testActivities.activities.filter(
-          activity => !activityIds.includes(activity.activityId));
-      this.testActivities = {activities: newActivities};
-
-      this.methodCalled('deleteActivitiesById', activityIds);
-      return Promise.resolve();
-    }
-
-    /** @override */
-    deleteActivitiesFromExtension(extensionId) {
-      this.methodCalled('deleteActivitiesFromExtension', extensionId);
-      return Promise.resolve();
-    }
-
-    /** @override */
-    getOnExtensionActivity() {
-      return this.extensionActivityTarget;
-    }
-
-    /** @override */
-    downloadActivities(rawActivityData, fileName) {
-      this.methodCalled('downloadActivities', [rawActivityData, fileName]);
-    }
+    /** @type {!chrome.activityLogPrivate.ActivityResultSet|undefined} */
+    this.testActivities;
   }
+
+  /**
+   * @param {!chrome.developerPrivate.LoadError} error
+   */
+  setRetryLoadUnpackedError(error) {
+    this.retryLoadUnpackedError_ = error;
+  }
+
+  /**
+   * @param {boolean} force
+   */
+  setForceReloadItemError(force) {
+    this.forceReloadItemError_ = force;
+  }
+
+  /** @override */
+  addRuntimeHostPermission(id, site) {
+    this.methodCalled('addRuntimeHostPermission', [id, site]);
+    return this.acceptRuntimeHostPermission ? Promise.resolve() :
+                                              Promise.reject();
+  }
+
+  /** @override */
+  getProfileConfiguration() {
+    this.methodCalled('getProfileConfiguration');
+    return Promise.resolve({inDeveloperMode: false});
+  }
+
+  /** @override */
+  getItemStateChangedTarget() {
+    return this.itemStateChangedTarget;
+  }
+
+  /** @override */
+  getProfileStateChangedTarget() {
+    return this.profileStateChangedTarget;
+  }
+
+  /** @override */
+  getExtensionsInfo() {
+    this.methodCalled('getExtensionsInfo');
+    return Promise.resolve([]);
+  }
+
+  /** @override */
+  getExtensionSize() {
+    this.methodCalled('getExtensionSize');
+    return Promise.resolve('20 MB');
+  }
+
+  /** @override */
+  removeRuntimeHostPermission(id, site) {
+    this.methodCalled('removeRuntimeHostPermission', [id, site]);
+    return Promise.resolve();
+  }
+
+  /** @override */
+  setItemHostAccess(id, access) {
+    this.methodCalled('setItemHostAccess', [id, access]);
+  }
+
+  /** @override */
+  setShortcutHandlingSuspended(enable) {
+    this.methodCalled('setShortcutHandlingSuspended', enable);
+  }
+
+  /** @override */
+  shouldIgnoreUpdate(extensionId, eventType) {
+    this.methodCalled('shouldIgnoreUpdate', [extensionId, eventType]);
+  }
+
+  /** @override */
+  updateExtensionCommandKeybinding(item, commandName, keybinding) {
+    this.methodCalled(
+        'updateExtensionCommandKeybinding', [item, commandName, keybinding]);
+  }
+
+  /** @override */
+  updateExtensionCommandScope(item, commandName, scope) {
+    this.methodCalled(
+        'updateExtensionCommandScope', [item, commandName, scope]);
+  }
+
+  /** @override */
+  loadUnpacked() {
+    this.methodCalled('loadUnpacked');
+    return Promise.resolve();
+  }
+
+  /** @override */
+  reloadItem(id) {
+    this.methodCalled('reloadItem', id);
+    return this.forceReloadItemError_ ? Promise.reject() : Promise.resolve();
+  }
+
+  /** @override */
+  retryLoadUnpacked(guid) {
+    this.methodCalled('retryLoadUnpacked', guid);
+    return (this.retryLoadUnpackedError_ !== undefined) ?
+        Promise.reject(this.retryLoadUnpackedError_) :
+        Promise.resolve();
+  }
+
+  /** @override */
+  setProfileInDevMode(inDevMode) {
+    this.methodCalled('setProfileInDevMode', inDevMode);
+  }
+
+  /** @override */
+  updateAllExtensions() {
+    this.methodCalled('updateAllExtensions');
+    return Promise.resolve();
+  }
+
+  /** @override */
+  getExtensionActivityLog(id) {
+    this.methodCalled('getExtensionActivityLog', id);
+    return Promise.resolve(this.testActivities);
+  }
+
+  /** @override */
+  getFilteredExtensionActivityLog(id, searchTerm) {
+    // This is functionally identical to getFilteredExtensionActivityLog in
+    // service.js but we do the filtering here instead of making API calls
+    // with filter objects.
+    this.methodCalled('getFilteredExtensionActivityLog', id, searchTerm);
+
+    // Convert everything to lowercase as searching is not case sensitive.
+    const lowerCaseSearchTerm = searchTerm.toLowerCase();
+
+    const activities = this.testActivities.activities;
+    const apiCallMatches = activities.filter(
+        activity =>
+            activity.apiCall.toLowerCase().includes(lowerCaseSearchTerm));
+    const pageUrlMatches = activities.filter(
+        activity => activity.pageUrl &&
+            activity.pageUrl.toLowerCase().includes(lowerCaseSearchTerm));
+    const argUrlMatches = activities.filter(
+        activity => activity.argUrl &&
+            activity.argUrl.toLowerCase().includes(lowerCaseSearchTerm));
+
+    return Promise.resolve(
+        {activities: [...apiCallMatches, ...pageUrlMatches, ...argUrlMatches]});
+  }
+
+  /** @override */
+  deleteActivitiesById(activityIds) {
+    // Pretend to delete all activities specified by activityIds.
+    const newActivities = this.testActivities.activities.filter(
+        activity => !activityIds.includes(activity.activityId));
+    this.testActivities = {activities: newActivities};
+
+    this.methodCalled('deleteActivitiesById', activityIds);
+    return Promise.resolve();
+  }
+
+  /** @override */
+  deleteActivitiesFromExtension(extensionId) {
+    this.methodCalled('deleteActivitiesFromExtension', extensionId);
+    return Promise.resolve();
+  }
+
+  /** @override */
+  getOnExtensionActivity() {
+    return this.extensionActivityTarget;
+  }
+
+  /** @override */
+  downloadActivities(rawActivityData, fileName) {
+    this.methodCalled('downloadActivities', [rawActivityData, fileName]);
+  }
+}
diff --git a/chrome/test/data/webui/extensions/test_util.js b/chrome/test/data/webui/extensions/test_util.js
index 496a2cb2..6b28675 100644
--- a/chrome/test/data/webui/extensions/test_util.js
+++ b/chrome/test/data/webui/extensions/test_util.js
@@ -8,224 +8,223 @@
 
 import {TestKioskBrowserProxy} from './test_kiosk_browser_proxy.js';
 
-  /** A mock to test that clicking on an element calls a specific method. */
-  export class ClickMock {
-    /**
-     * Tests clicking on an element and expecting a call.
-     * @param {HTMLElement} element The element to click on.
-     * @param {string} callName The function expected to be called.
-     * @param {Array<*>=} opt_expectedArgs The arguments the function is
-     *     expected to be called with.
-     * @param {*=} opt_returnValue The value to return from the function call.
-     */
-    testClickingCalls(element, callName, opt_expectedArgs, opt_returnValue) {
-      const mock = new MockController();
-      const mockMethod = mock.createFunctionMock(this, callName);
-      mockMethod.returnValue = opt_returnValue;
-      MockMethod.prototype.addExpectation.apply(mockMethod, opt_expectedArgs);
-      element.click();
-      mock.verifyMocks();
-    }
+/** A mock to test that clicking on an element calls a specific method. */
+export class ClickMock {
+  /**
+   * Tests clicking on an element and expecting a call.
+   * @param {HTMLElement} element The element to click on.
+   * @param {string} callName The function expected to be called.
+   * @param {Array<*>=} opt_expectedArgs The arguments the function is
+   *     expected to be called with.
+   * @param {*=} opt_returnValue The value to return from the function call.
+   */
+  testClickingCalls(element, callName, opt_expectedArgs, opt_returnValue) {
+    const mock = new MockController();
+    const mockMethod = mock.createFunctionMock(this, callName);
+    mockMethod.returnValue = opt_returnValue;
+    MockMethod.prototype.addExpectation.apply(mockMethod, opt_expectedArgs);
+    element.click();
+    mock.verifyMocks();
+  }
+}
+
+/**
+ * A mock to test receiving expected events and verify that they were called
+ * with the proper detail values.
+ */
+export class ListenerMock {
+  constructor() {
+    /** @private {Object<{satisfied: boolean, args: !Object}>} */
+    this.listeners_ = {};
   }
 
   /**
-   * A mock to test receiving expected events and verify that they were called
-   * with the proper detail values.
+   * @param {string} eventName
+   * @param {Event} e
    */
-  export class ListenerMock {
-    constructor() {
-      /** @private {Object<{satisfied: boolean, args: !Object}>} */
-      this.listeners_ = {};
+  onEvent_(eventName, e) {
+    assert(this.listeners_.hasOwnProperty(eventName));
+    if (this.listeners_[eventName].satisfied) {
+      // Event was already called and checked. We could always make this
+      // more intelligent by allowing for subsequent calls, removing the
+      // listener, etc, but there's no need right now.
+      return;
     }
+    const expected = this.listeners_[eventName].args || {};
+    expectDeepEquals(e.detail, expected);
+    this.listeners_[eventName].satisfied = true;
+  }
 
-    /**
-     * @param {string} eventName
-     * @param {Event} e
-     */
-    onEvent_(eventName, e) {
-      assert(this.listeners_.hasOwnProperty(eventName));
-      if (this.listeners_[eventName].satisfied) {
-        // Event was already called and checked. We could always make this
-        // more intelligent by allowing for subsequent calls, removing the
-        // listener, etc, but there's no need right now.
-        return;
+  /**
+   * Adds an expected event.
+   * @param {!EventTarget} target
+   * @param {string} eventName
+   * @param {Object=} opt_eventArgs If omitted, will check that the details
+   *     are empty (i.e., {}).
+   */
+  addListener(target, eventName, opt_eventArgs) {
+    assert(!this.listeners_.hasOwnProperty(eventName));
+    this.listeners_[eventName] = {args: opt_eventArgs || {}, satisfied: false};
+    target.addEventListener(eventName, this.onEvent_.bind(this, eventName));
+  }
+
+  /** Verifies the expectations set. */
+  verify() {
+    const missingEvents = [];
+    for (const key in this.listeners_) {
+      if (!this.listeners_[key].satisfied) {
+        missingEvents.push(key);
       }
-      const expected = this.listeners_[eventName].args || {};
-      expectDeepEquals(e.detail, expected);
-      this.listeners_[eventName].satisfied = true;
     }
+    expectEquals(0, missingEvents.length, JSON.stringify(missingEvents));
+  }
+}
 
-    /**
-     * Adds an expected event.
-     * @param {!EventTarget} target
-     * @param {string} eventName
-     * @param {Object=} opt_eventArgs If omitted, will check that the details
-     *     are empty (i.e., {}).
-     */
-    addListener(target, eventName, opt_eventArgs) {
-      assert(!this.listeners_.hasOwnProperty(eventName));
-      this.listeners_[eventName] =
-          {args: opt_eventArgs || {}, satisfied: false};
-      target.addEventListener(eventName, this.onEvent_.bind(this, eventName));
-    }
-
-    /** Verifies the expectations set. */
-    verify() {
-      const missingEvents = [];
-      for (const key in this.listeners_) {
-        if (!this.listeners_[key].satisfied) {
-          missingEvents.push(key);
-        }
-      }
-      expectEquals(0, missingEvents.length, JSON.stringify(missingEvents));
-    }
+/**
+ * A mock delegate for the item, capable of testing functionality.
+ * @implements {extensions.ItemDelegate}
+ */
+export class MockItemDelegate extends ClickMock {
+  constructor() {
+    super();
   }
 
-  /**
-   * A mock delegate for the item, capable of testing functionality.
-   * @implements {extensions.ItemDelegate}
-   */
-  export class MockItemDelegate extends ClickMock {
-    constructor() {
-      super();
-    }
+  /** @override */
+  deleteItem(id) {}
 
-    /** @override */
-    deleteItem(id) {}
+  /** @override */
+  setItemEnabled(id, enabled) {}
 
-    /** @override */
-    setItemEnabled(id, enabled) {}
+  /** @override */
+  showItemDetails(id) {}
 
-    /** @override */
-    showItemDetails(id) {}
+  /** @override */
+  setItemAllowedIncognito(id, enabled) {}
 
-    /** @override */
-    setItemAllowedIncognito(id, enabled) {}
+  /** @override */
+  setItemAllowedOnFileUrls(id, enabled) {}
 
-    /** @override */
-    setItemAllowedOnFileUrls(id, enabled) {}
+  /** @override */
+  setItemHostAccess(id, hostAccess) {}
 
-    /** @override */
-    setItemHostAccess(id, hostAccess) {}
+  /** @override */
+  setItemCollectsErrors(id, enabled) {}
 
-    /** @override */
-    setItemCollectsErrors(id, enabled) {}
+  /** @override */
+  inspectItemView(id, view) {}
 
-    /** @override */
-    inspectItemView(id, view) {}
+  /** @override */
+  reloadItem(id) {}
 
-    /** @override */
-    reloadItem(id) {}
+  /** @override */
+  repairItem(id) {}
 
-    /** @override */
-    repairItem(id) {}
+  /** @override */
+  showItemOptionsPage(id) {}
 
-    /** @override */
-    showItemOptionsPage(id) {}
+  /** @override */
+  showInFolder(id) {}
 
-    /** @override */
-    showInFolder(id) {}
-
-    /** @override */
-    getExtensionSize(id) {
-      return Promise.resolve('10 MB');
-    }
+  /** @override */
+  getExtensionSize(id) {
+    return Promise.resolve('10 MB');
   }
+}
 
-  /**
-   * @param {!HTMLElement} element
-   * @return {boolean} whether or not the element passed in is visible
-   */
-  export function isElementVisible(element) {
-    const rect = element.getBoundingClientRect();
-    return rect.width * rect.height > 0;  // Width and height is never negative.
+/**
+ * @param {!HTMLElement} element
+ * @return {boolean} whether or not the element passed in is visible
+ */
+export function isElementVisible(element) {
+  const rect = element.getBoundingClientRect();
+  return rect.width * rect.height > 0;  // Width and height is never negative.
+}
+
+/**
+ * Tests that the element's visibility matches |expectedVisible| and,
+ * optionally, has specific content if it is visible.
+ * @param {!HTMLElement} parentEl The parent element to query for the element.
+ * @param {string} selector The selector to find the element.
+ * @param {boolean} expectedVisible Whether the element should be
+ *     visible.
+ * @param {string=} opt_expectedText The expected textContent value.
+ */
+export function testVisible(
+    parentEl, selector, expectedVisible, opt_expectedText) {
+  const visible = isVisible(parentEl, selector);
+  expectEquals(expectedVisible, visible, selector);
+  if (expectedVisible && visible && opt_expectedText) {
+    const element = parentEl.$$(selector);
+    expectEquals(opt_expectedText, element.textContent.trim(), selector);
   }
+}
 
-  /**
-   * Tests that the element's visibility matches |expectedVisible| and,
-   * optionally, has specific content if it is visible.
-   * @param {!HTMLElement} parentEl The parent element to query for the element.
-   * @param {string} selector The selector to find the element.
-   * @param {boolean} expectedVisible Whether the element should be
-   *     visible.
-   * @param {string=} opt_expectedText The expected textContent value.
-   */
-  export function testVisible(
-      parentEl, selector, expectedVisible, opt_expectedText) {
-    const visible = isVisible(parentEl, selector);
-    expectEquals(expectedVisible, visible, selector);
-    if (expectedVisible && visible && opt_expectedText) {
-      const element = parentEl.$$(selector);
-      expectEquals(opt_expectedText, element.textContent.trim(), selector);
-    }
-  }
-
-  /**
-   * Creates an ExtensionInfo object.
-   * @param {Object=} opt_properties A set of properties that will be used on
-   *     the resulting ExtensionInfo (otherwise defaults will be used).
-   * @return {chrome.developerPrivate.ExtensionInfo}
-   */
-  export function createExtensionInfo(opt_properties) {
-    const id = opt_properties && opt_properties.hasOwnProperty('id') ?
-        opt_properties['id'] :
-        'a'.repeat(32);
-    const baseUrl = 'chrome-extension://' + id + '/';
-    return Object.assign(
-        {
-          commands: [],
-          dependentExtensions: [],
-          description: 'This is an extension',
-          disableReasons: {
-            suspiciousInstall: false,
-            corruptInstall: false,
-            updateRequired: false,
-          },
-          homePage: {specified: false, url: ''},
-          iconUrl: 'chrome://extension-icon/' + id + '/24/0',
-          id: id,
-          incognitoAccess: {isEnabled: true, isActive: false},
-          location: 'FROM_STORE',
-          manifestErrors: [],
-          name: 'Wonderful Extension',
-          runtimeErrors: [],
-          runtimeWarnings: [],
-          permissions: {simplePermissions: []},
-          state: 'ENABLED',
-          type: 'EXTENSION',
-          userMayModify: true,
-          version: '2.0',
-          views: [{url: baseUrl + 'foo.html'}, {url: baseUrl + 'bar.html'}],
+/**
+ * Creates an ExtensionInfo object.
+ * @param {Object=} opt_properties A set of properties that will be used on
+ *     the resulting ExtensionInfo (otherwise defaults will be used).
+ * @return {chrome.developerPrivate.ExtensionInfo}
+ */
+export function createExtensionInfo(opt_properties) {
+  const id = opt_properties && opt_properties.hasOwnProperty('id') ?
+      opt_properties['id'] :
+      'a'.repeat(32);
+  const baseUrl = 'chrome-extension://' + id + '/';
+  return Object.assign(
+      {
+        commands: [],
+        dependentExtensions: [],
+        description: 'This is an extension',
+        disableReasons: {
+          suspiciousInstall: false,
+          corruptInstall: false,
+          updateRequired: false,
         },
-        opt_properties);
-  }
+        homePage: {specified: false, url: ''},
+        iconUrl: 'chrome://extension-icon/' + id + '/24/0',
+        id: id,
+        incognitoAccess: {isEnabled: true, isActive: false},
+        location: 'FROM_STORE',
+        manifestErrors: [],
+        name: 'Wonderful Extension',
+        runtimeErrors: [],
+        runtimeWarnings: [],
+        permissions: {simplePermissions: []},
+        state: 'ENABLED',
+        type: 'EXTENSION',
+        userMayModify: true,
+        version: '2.0',
+        views: [{url: baseUrl + 'foo.html'}, {url: baseUrl + 'bar.html'}],
+      },
+      opt_properties);
+}
 
-  /**
-   * Finds all nodes matching |query| under |root|, within self and children's
-   * Shadow DOM.
-   * @param {!Node} root
-   * @param {string} query The CSS query
-   * @return {!Array<!HTMLElement>}
-   */
-  export function findMatches(root, query) {
-    let elements = new Set();
-    function doSearch(node) {
-      if (node.nodeType == Node.ELEMENT_NODE) {
-        const matches = node.querySelectorAll(query);
-        for (let match of matches) {
-          elements.add(match);
-        }
-      }
-      let child = node.firstChild;
-      while (child !== null) {
-        doSearch(child);
-        child = child.nextSibling;
-      }
-      const shadowRoot = node.shadowRoot;
-      if (shadowRoot) {
-        doSearch(shadowRoot);
+/**
+ * Finds all nodes matching |query| under |root|, within self and children's
+ * Shadow DOM.
+ * @param {!Node} root
+ * @param {string} query The CSS query
+ * @return {!Array<!HTMLElement>}
+ */
+export function findMatches(root, query) {
+  let elements = new Set();
+  function doSearch(node) {
+    if (node.nodeType == Node.ELEMENT_NODE) {
+      const matches = node.querySelectorAll(query);
+      for (let match of matches) {
+        elements.add(match);
       }
     }
-    doSearch(root);
-    return Array.from(elements);
+    let child = node.firstChild;
+    while (child !== null) {
+      doSearch(child);
+      child = child.nextSibling;
+    }
+    const shadowRoot = node.shadowRoot;
+    if (shadowRoot) {
+      doSearch(shadowRoot);
+    }
   }
+  doSearch(root);
+  return Array.from(elements);
+}
diff --git a/chrome/test/data/webui/extensions/toolbar_test.js b/chrome/test/data/webui/extensions/toolbar_test.js
index 731fbc33..ecb8d77 100644
--- a/chrome/test/data/webui/extensions/toolbar_test.js
+++ b/chrome/test/data/webui/extensions/toolbar_test.js
@@ -12,140 +12,140 @@
 import {TestService} from './test_service.js';
 import {testVisible} from './test_util.js';
 
-  /** @fileoverview Suite of tests for extension-toolbar. */
-  window.extension_toolbar_tests = {};
-  extension_toolbar_tests.suiteName = 'ExtensionToolbarTest';
-  /** @enum {string} */
-  extension_toolbar_tests.TestNames = {
-    Layout: 'layout',
-    ClickHandlers: 'click handlers',
-    DevModeToggle: 'dev mode toggle',
-    KioskMode: 'kiosk mode button'
-  };
+/** @fileoverview Suite of tests for extension-toolbar. */
+window.extension_toolbar_tests = {};
+extension_toolbar_tests.suiteName = 'ExtensionToolbarTest';
+/** @enum {string} */
+extension_toolbar_tests.TestNames = {
+  Layout: 'layout',
+  ClickHandlers: 'click handlers',
+  DevModeToggle: 'dev mode toggle',
+  KioskMode: 'kiosk mode button'
+};
 
-  suite(extension_toolbar_tests.suiteName, function() {
-    /** @type {MockDelegate} */
-    let mockDelegate;
+suite(extension_toolbar_tests.suiteName, function() {
+  /** @type {MockDelegate} */
+  let mockDelegate;
 
-    /** @type {ExtensionsToolbarElement} */
-    let toolbar;
+  /** @type {ExtensionsToolbarElement} */
+  let toolbar;
 
-    setup(function() {
-      PolymerTest.clearBody();
-      toolbar = document.createElement('extensions-toolbar');
-      document.body.appendChild(toolbar);
-      toolbar.inDevMode = false;
-      toolbar.devModeControlledByPolicy = false;
-      toolbar.isSupervised = false;
-      if (isChromeOS) {
-        toolbar.kioskEnabled = false;
-      }
-      mockDelegate = new TestService();
-      toolbar.set('delegate', mockDelegate);
-
-      // The toast manager is normally a child of the <extensions-manager>
-      // element, so add it separately for this test.
-      const toastManager = document.createElement('cr-toast-manager');
-      document.body.appendChild(toastManager);
-    });
-
-    test(assert(extension_toolbar_tests.TestNames.Layout), function() {
-      const boundTestVisible = testVisible.bind(null, toolbar);
-      boundTestVisible('#devMode', true);
-      assertEquals(toolbar.$.devMode.disabled, false);
-      boundTestVisible('#loadUnpacked', false);
-      boundTestVisible('#packExtensions', false);
-      boundTestVisible('#updateNow', false);
-      toolbar.set('inDevMode', true);
-      flush();
-
-      boundTestVisible('#devMode', true);
-      assertEquals(toolbar.$.devMode.disabled, false);
-      boundTestVisible('#loadUnpacked', true);
-      boundTestVisible('#packExtensions', true);
-      boundTestVisible('#updateNow', true);
-
-      toolbar.set('canLoadUnpacked', false);
-      flush();
-
-      boundTestVisible('#devMode', true);
-      boundTestVisible('#loadUnpacked', false);
-      boundTestVisible('#packExtensions', true);
-      boundTestVisible('#updateNow', true);
-    });
-
-    test(assert(extension_toolbar_tests.TestNames.DevModeToggle), function() {
-      const toggle = toolbar.$.devMode;
-      assertFalse(toggle.disabled);
-
-      // Test that the dev-mode toggle is disabled when a policy exists.
-      toolbar.set('devModeControlledByPolicy', true);
-      flush();
-      assertTrue(toggle.disabled);
-
-      toolbar.set('devModeControlledByPolicy', false);
-      flush();
-      assertFalse(toggle.disabled);
-
-      // Test that the dev-mode toggle is disabled when the user is supervised.
-      toolbar.set('isSupervised', true);
-      flush();
-      assertTrue(toggle.disabled);
-    });
-
-    test(assert(extension_toolbar_tests.TestNames.ClickHandlers), function() {
-      toolbar.set('inDevMode', true);
-      flush();
-
-      toolbar.$.devMode.click();
-      return mockDelegate.whenCalled('setProfileInDevMode')
-          .then(function(arg) {
-            assertFalse(arg);
-            mockDelegate.reset();
-            toolbar.$.devMode.click();
-            return mockDelegate.whenCalled('setProfileInDevMode');
-          })
-          .then(function(arg) {
-            assertTrue(arg);
-            toolbar.$.loadUnpacked.click();
-            return mockDelegate.whenCalled('loadUnpacked');
-          })
-          .then(function() {
-            const toastManager = getInstance();
-            assertFalse(toastManager.isToastOpen);
-            toolbar.$.updateNow.click();
-            // Simulate user rapidly clicking update button multiple times.
-            toolbar.$.updateNow.click();
-            assertTrue(toastManager.isToastOpen);
-            return mockDelegate.whenCalled('updateAllExtensions');
-          })
-          .then(function() {
-            assertEquals(1, mockDelegate.getCallCount('updateAllExtensions'));
-            assertFalse(!!toolbar.$$('extensions-pack-dialog'));
-            toolbar.$.packExtensions.click();
-            flush();
-            const dialog = toolbar.$$('extensions-pack-dialog');
-            assertTrue(!!dialog);
-
-            if (!isMac) {
-              const whenFocused =
-                  eventToPromise('focus', toolbar.$.packExtensions);
-              dialog.$.dialog.cancel();
-              return whenFocused;
-            }
-          });
-    });
-
+  setup(function() {
+    PolymerTest.clearBody();
+    toolbar = document.createElement('extensions-toolbar');
+    document.body.appendChild(toolbar);
+    toolbar.inDevMode = false;
+    toolbar.devModeControlledByPolicy = false;
+    toolbar.isSupervised = false;
     if (isChromeOS) {
-      test(assert(extension_toolbar_tests.TestNames.KioskMode), function() {
-        const button = toolbar.$.kioskExtensions;
-        expectTrue(button.hidden);
-        toolbar.kioskEnabled = true;
-        expectFalse(button.hidden);
-
-        const whenTapped = eventToPromise('kiosk-tap', toolbar);
-        button.click();
-        return whenTapped;
-      });
+      toolbar.kioskEnabled = false;
     }
+    mockDelegate = new TestService();
+    toolbar.set('delegate', mockDelegate);
+
+    // The toast manager is normally a child of the <extensions-manager>
+    // element, so add it separately for this test.
+    const toastManager = document.createElement('cr-toast-manager');
+    document.body.appendChild(toastManager);
   });
+
+  test(assert(extension_toolbar_tests.TestNames.Layout), function() {
+    const boundTestVisible = testVisible.bind(null, toolbar);
+    boundTestVisible('#devMode', true);
+    assertEquals(toolbar.$.devMode.disabled, false);
+    boundTestVisible('#loadUnpacked', false);
+    boundTestVisible('#packExtensions', false);
+    boundTestVisible('#updateNow', false);
+    toolbar.set('inDevMode', true);
+    flush();
+
+    boundTestVisible('#devMode', true);
+    assertEquals(toolbar.$.devMode.disabled, false);
+    boundTestVisible('#loadUnpacked', true);
+    boundTestVisible('#packExtensions', true);
+    boundTestVisible('#updateNow', true);
+
+    toolbar.set('canLoadUnpacked', false);
+    flush();
+
+    boundTestVisible('#devMode', true);
+    boundTestVisible('#loadUnpacked', false);
+    boundTestVisible('#packExtensions', true);
+    boundTestVisible('#updateNow', true);
+  });
+
+  test(assert(extension_toolbar_tests.TestNames.DevModeToggle), function() {
+    const toggle = toolbar.$.devMode;
+    assertFalse(toggle.disabled);
+
+    // Test that the dev-mode toggle is disabled when a policy exists.
+    toolbar.set('devModeControlledByPolicy', true);
+    flush();
+    assertTrue(toggle.disabled);
+
+    toolbar.set('devModeControlledByPolicy', false);
+    flush();
+    assertFalse(toggle.disabled);
+
+    // Test that the dev-mode toggle is disabled when the user is supervised.
+    toolbar.set('isSupervised', true);
+    flush();
+    assertTrue(toggle.disabled);
+  });
+
+  test(assert(extension_toolbar_tests.TestNames.ClickHandlers), function() {
+    toolbar.set('inDevMode', true);
+    flush();
+
+    toolbar.$.devMode.click();
+    return mockDelegate.whenCalled('setProfileInDevMode')
+        .then(function(arg) {
+          assertFalse(arg);
+          mockDelegate.reset();
+          toolbar.$.devMode.click();
+          return mockDelegate.whenCalled('setProfileInDevMode');
+        })
+        .then(function(arg) {
+          assertTrue(arg);
+          toolbar.$.loadUnpacked.click();
+          return mockDelegate.whenCalled('loadUnpacked');
+        })
+        .then(function() {
+          const toastManager = getInstance();
+          assertFalse(toastManager.isToastOpen);
+          toolbar.$.updateNow.click();
+          // Simulate user rapidly clicking update button multiple times.
+          toolbar.$.updateNow.click();
+          assertTrue(toastManager.isToastOpen);
+          return mockDelegate.whenCalled('updateAllExtensions');
+        })
+        .then(function() {
+          assertEquals(1, mockDelegate.getCallCount('updateAllExtensions'));
+          assertFalse(!!toolbar.$$('extensions-pack-dialog'));
+          toolbar.$.packExtensions.click();
+          flush();
+          const dialog = toolbar.$$('extensions-pack-dialog');
+          assertTrue(!!dialog);
+
+          if (!isMac) {
+            const whenFocused =
+                eventToPromise('focus', toolbar.$.packExtensions);
+            dialog.$.dialog.cancel();
+            return whenFocused;
+          }
+        });
+  });
+
+  if (isChromeOS) {
+    test(assert(extension_toolbar_tests.TestNames.KioskMode), function() {
+      const button = toolbar.$.kioskExtensions;
+      expectTrue(button.hidden);
+      toolbar.kioskEnabled = true;
+      expectFalse(button.hidden);
+
+      const whenTapped = eventToPromise('kiosk-tap', toolbar);
+      button.click();
+      return whenTapped;
+    });
+  }
+});
diff --git a/chromecast/bindings/BUILD.gn b/chromecast/bindings/BUILD.gn
index 0405012..a0cebfc 100644
--- a/chromecast/bindings/BUILD.gn
+++ b/chromecast/bindings/BUILD.gn
@@ -56,7 +56,7 @@
   }
 }
 
-if (is_linux) {
+if (is_linux || is_android) {
   source_set("bindings_manager_cast") {
     sources = [
       "bindings_manager_cast.cc",
@@ -111,7 +111,7 @@
 source_set("browsertests") {
   testonly = true
   deps = []
-  if (is_linux) {
+  if (is_linux || is_android) {
     deps += [ "//chromecast/bindings:browsertests_cast" ]
   }
 }
diff --git a/chromecast/browser/cast_extension_url_loader_factory.cc b/chromecast/browser/cast_extension_url_loader_factory.cc
index c54976c..e4e8f5ad6 100644
--- a/chromecast/browser/cast_extension_url_loader_factory.cc
+++ b/chromecast/browser/cast_extension_url_loader_factory.cc
@@ -51,8 +51,7 @@
       mojo::PendingReceiver<network::mojom::URLLoader> loader_receiver,
       network::mojom::URLLoaderClientPtr client)
       : original_loader_receiver_(this, std::move(loader_receiver)),
-        original_client_(std::move(client)),
-        network_client_binding_(this) {
+        original_client_(std::move(client)) {
     DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
     // If there is a client error, clean up the request.
     original_client_.set_connection_error_handler(base::BindOnce(
@@ -70,13 +69,13 @@
     DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
 
     network::mojom::URLLoaderClientPtr network_client;
-    network_client_binding_.Bind(mojo::MakeRequest(&network_client));
+    network_client_receiver_.Bind(mojo::MakeRequest(&network_client));
 
     network_factory->CreateLoaderAndStart(
         mojo::MakeRequest(&network_loader_), routing_id, request_id, options,
         request, std::move(network_client), traffic_annotation);
 
-    network_client_binding_.set_connection_error_handler(base::BindOnce(
+    network_client_receiver_.set_disconnect_handler(base::BindOnce(
         &CastExtensionURLLoader::OnNetworkError, base::Unretained(this)));
   }
 
@@ -159,7 +158,8 @@
   network::mojom::URLLoaderClientPtr original_client_;
 
   // This is the URLLoaderClient passed to the network URLLoaderFactory.
-  mojo::Binding<network::mojom::URLLoaderClient> network_client_binding_;
+  mojo::Receiver<network::mojom::URLLoaderClient> network_client_receiver_{
+      this};
 
   // This is the URLLoader from the network URLLoaderFactory.
   network::mojom::URLLoaderPtr network_loader_;
diff --git a/chromeos/tools/concat_dbus_conf_files.py b/chromeos/tools/concat_dbus_conf_files.py
new file mode 100755
index 0000000..7bdbeac3
--- /dev/null
+++ b/chromeos/tools/concat_dbus_conf_files.py
@@ -0,0 +1,43 @@
+#!/usr/bin/env python
+# Copyright 2019 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""Concatenates D-Bus busconfig files."""
+
+import sys
+import xml.etree.ElementTree
+
+
+_BUSCONFIG_FILE_HEADER="""<!DOCTYPE busconfig
+  PUBLIC "-//freedesktop//DTD D-Bus Bus Configuration 1.0//EN"
+  "http://www.freedesktop.org/standards/dbus/1.0/busconfig.dtd">
+"""
+
+
+def main():
+  if len(sys.argv) < 3:
+    sys.stderr.write('Usage: %s OUTFILE INFILES\n' % (sys.argv[0]))
+    sys.exit(1)
+
+  out_path = sys.argv[1]
+  in_paths = sys.argv[2:]
+
+  # Parse the first input file.
+  tree = xml.etree.ElementTree.parse(in_paths[0])
+  assert(tree.getroot().tag == 'busconfig')
+
+  # Append the remaining input files to the first file.
+  for path in in_paths[1:]:
+    current_tree = xml.etree.ElementTree.parse(path)
+    assert(current_tree.getroot().tag == 'busconfig')
+    for child in current_tree.getroot():
+      tree.getroot().append(child)
+
+  # Output the result.
+  with open(out_path, "w") as f:
+    f.write(_BUSCONFIG_FILE_HEADER)
+    tree.write(f)
+
+if __name__ == '__main__':
+  main()
diff --git a/components/arc/ime/arc_ime_service.cc b/components/arc/ime/arc_ime_service.cc
index 3dd4c9c..17c0d39 100644
--- a/components/arc/ime/arc_ime_service.cc
+++ b/components/arc/ime/arc_ime_service.cc
@@ -396,9 +396,16 @@
   ime_bridge_->SendSetCompositionText(composition);
 }
 
-void ArcImeService::ConfirmCompositionText() {
+void ArcImeService::ConfirmCompositionText(bool keep_selection) {
+  // TODO(b/134473433) Modify this function so that when keep_selection is
+  // true, the selection is not changed when text committed
+  if (keep_selection) {
+    NOTIMPLEMENTED_LOG_ONCE();
+  }
   InvalidateSurroundingTextAndSelectionRange();
   has_composition_text_ = false;
+  // Note: SendConfirmCompositonText() will commit the text and
+  // keep the selection unchanged
   ime_bridge_->SendConfirmCompositionText();
 }
 
diff --git a/components/arc/ime/arc_ime_service.h b/components/arc/ime/arc_ime_service.h
index 8b59b60..9a19a3d 100644
--- a/components/arc/ime/arc_ime_service.h
+++ b/components/arc/ime/arc_ime_service.h
@@ -112,7 +112,7 @@
 
   // Overridden from ui::TextInputClient:
   void SetCompositionText(const ui::CompositionText& composition) override;
-  void ConfirmCompositionText() override;
+  void ConfirmCompositionText(bool keep_selection) override;
   void ClearCompositionText() override;
   void InsertText(const base::string16& text) override;
   void InsertChar(const ui::KeyEvent& event) override;
diff --git a/components/arc/ime/arc_ime_service_unittest.cc b/components/arc/ime/arc_ime_service_unittest.cc
index ee62ec6..d5d16a9 100644
--- a/components/arc/ime/arc_ime_service_unittest.cc
+++ b/components/arc/ime/arc_ime_service_unittest.cc
@@ -227,7 +227,7 @@
 
   instance_->SetCompositionText(composition);
   EXPECT_TRUE(instance_->HasCompositionText());
-  instance_->ConfirmCompositionText();
+  instance_->ConfirmCompositionText(/* keep_selection */ false);
   EXPECT_FALSE(instance_->HasCompositionText());
 
   instance_->SetCompositionText(composition);
diff --git a/components/download/internal/common/resource_downloader.cc b/components/download/internal/common/resource_downloader.cc
index 47545234..7d7840923 100644
--- a/components/download/internal/common/resource_downloader.cc
+++ b/components/download/internal/common/resource_downloader.cc
@@ -164,8 +164,8 @@
       std::vector<GURL>(1, resource_request_->url), is_background_mode);
 
   network::mojom::URLLoaderClientPtr url_loader_client_ptr;
-  url_loader_client_binding_ =
-      std::make_unique<mojo::Binding<network::mojom::URLLoaderClient>>(
+  url_loader_client_receiver_ =
+      std::make_unique<mojo::Receiver<network::mojom::URLLoaderClient>>(
           url_loader_client_.get(), mojo::MakeRequest(&url_loader_client_ptr));
 
   // Set up the URLLoader
@@ -211,8 +211,8 @@
     url_loader_client_->OnStartLoadingResponseBody(std::move(response_body));
 
   // Bind the new client.
-  url_loader_client_binding_ =
-      std::make_unique<mojo::Binding<network::mojom::URLLoaderClient>>(
+  url_loader_client_receiver_ =
+      std::make_unique<mojo::Receiver<network::mojom::URLLoaderClient>>(
           url_loader_client_.get(), std::move(endpoints->url_loader_client));
 }
 
diff --git a/components/download/internal/common/resource_downloader.h b/components/download/internal/common/resource_downloader.h
index fe7cb243a..0fa309e8 100644
--- a/components/download/internal/common/resource_downloader.h
+++ b/components/download/internal/common/resource_downloader.h
@@ -10,7 +10,7 @@
 #include "components/download/public/common/download_response_handler.h"
 #include "components/download/public/common/download_utils.h"
 #include "components/download/public/common/url_download_handler.h"
-#include "mojo/public/cpp/bindings/binding.h"
+#include "mojo/public/cpp/bindings/receiver.h"
 #include "mojo/public/cpp/bindings/remote.h"
 #include "net/cert/cert_status_flags.h"
 #include "services/device/public/mojom/wake_lock.mojom.h"
@@ -120,9 +120,10 @@
   // Object that will handle the response.
   std::unique_ptr<network::mojom::URLLoaderClient> url_loader_client_;
 
-  // URLLoaderClient binding. It sends any requests to the |url_loader_client_|.
-  std::unique_ptr<mojo::Binding<network::mojom::URLLoaderClient>>
-      url_loader_client_binding_;
+  // URLLoaderClient receiver. It sends any requests to the
+  // |url_loader_client_|.
+  std::unique_ptr<mojo::Receiver<network::mojom::URLLoaderClient>>
+      url_loader_client_receiver_;
 
   // URLLoader for sending out the request.
   network::mojom::URLLoaderPtr url_loader_;
diff --git a/components/drive/BUILD.gn b/components/drive/BUILD.gn
index dc1b3fb..9b8cb960 100644
--- a/components/drive/BUILD.gn
+++ b/components/drive/BUILD.gn
@@ -97,81 +97,24 @@
 if (is_chromeos) {
   source_set("drive_chromeos") {
     sources = [
-      "chromeos/about_resource_loader.cc",
-      "chromeos/about_resource_loader.h",
-      "chromeos/about_resource_root_folder_id_loader.cc",
-      "chromeos/about_resource_root_folder_id_loader.h",
-      "chromeos/change_list_loader.cc",
-      "chromeos/change_list_loader.h",
-      "chromeos/change_list_loader_observer.h",
       "chromeos/change_list_processor.cc",
       "chromeos/change_list_processor.h",
-      "chromeos/default_corpus_change_list_loader.cc",
-      "chromeos/default_corpus_change_list_loader.h",
-      "chromeos/directory_loader.cc",
-      "chromeos/directory_loader.h",
-      "chromeos/drive_change_list_loader.h",
       "chromeos/drive_file_util.cc",
       "chromeos/drive_file_util.h",
       "chromeos/drive_operation_queue.h",
       "chromeos/file_cache.cc",
       "chromeos/file_cache.h",
-      "chromeos/file_system.cc",
-      "chromeos/file_system.h",
-      "chromeos/file_system/copy_operation.cc",
-      "chromeos/file_system/copy_operation.h",
-      "chromeos/file_system/create_directory_operation.cc",
-      "chromeos/file_system/create_directory_operation.h",
-      "chromeos/file_system/create_file_operation.cc",
-      "chromeos/file_system/create_file_operation.h",
-      "chromeos/file_system/download_operation.cc",
-      "chromeos/file_system/download_operation.h",
-      "chromeos/file_system/get_file_for_saving_operation.cc",
-      "chromeos/file_system/get_file_for_saving_operation.h",
-      "chromeos/file_system/move_operation.cc",
-      "chromeos/file_system/move_operation.h",
-      "chromeos/file_system/open_file_operation.cc",
-      "chromeos/file_system/open_file_operation.h",
-      "chromeos/file_system/operation_delegate.cc",
-      "chromeos/file_system/operation_delegate.h",
-      "chromeos/file_system/remove_operation.cc",
-      "chromeos/file_system/remove_operation.h",
-      "chromeos/file_system/search_operation.cc",
-      "chromeos/file_system/search_operation.h",
-      "chromeos/file_system/set_property_operation.cc",
-      "chromeos/file_system/set_property_operation.h",
-      "chromeos/file_system/touch_operation.cc",
-      "chromeos/file_system/touch_operation.h",
-      "chromeos/file_system/truncate_operation.cc",
-      "chromeos/file_system/truncate_operation.h",
       "chromeos/file_system_interface.cc",
       "chromeos/file_system_interface.h",
       "chromeos/file_system_observer.h",
-      "chromeos/loader_controller.cc",
-      "chromeos/loader_controller.h",
       "chromeos/remove_stale_cache_files.cc",
       "chromeos/remove_stale_cache_files.h",
       "chromeos/resource_metadata.cc",
       "chromeos/resource_metadata.h",
-      "chromeos/root_folder_id_loader.h",
       "chromeos/search_metadata.cc",
       "chromeos/search_metadata.h",
-      "chromeos/start_page_token_loader.cc",
-      "chromeos/start_page_token_loader.h",
-      "chromeos/sync/entry_revert_performer.cc",
-      "chromeos/sync/entry_revert_performer.h",
-      "chromeos/sync/entry_update_performer.cc",
-      "chromeos/sync/entry_update_performer.h",
-      "chromeos/sync/remove_performer.cc",
-      "chromeos/sync/remove_performer.h",
-      "chromeos/sync_client.cc",
-      "chromeos/sync_client.h",
       "chromeos/team_drive.cc",
       "chromeos/team_drive.h",
-      "chromeos/team_drive_change_list_loader.cc",
-      "chromeos/team_drive_change_list_loader.h",
-      "chromeos/team_drive_list_loader.cc",
-      "chromeos/team_drive_list_loader.h",
       "chromeos/team_drive_list_observer.h",
     ]
     deps = [
@@ -192,10 +135,6 @@
     sources = [
       "chromeos/drive_test_util.cc",
       "chromeos/drive_test_util.h",
-      "chromeos/dummy_file_system.cc",
-      "chromeos/dummy_file_system.h",
-      "chromeos/fake_file_system.cc",
-      "chromeos/fake_file_system.h",
       "chromeos/fake_free_disk_space_getter.cc",
       "chromeos/fake_free_disk_space_getter.h",
     ]
diff --git a/components/drive/DEPS b/components/drive/DEPS
index 850ce58..851b225 100644
--- a/components/drive/DEPS
+++ b/components/drive/DEPS
@@ -16,48 +16,22 @@
 specific_include_rules = {
   # The following test dependencies should be removed to fully componentize this
   # directory. crbug.com/498951
-  r"(copy_operation_unittest\.cc"
-  r"|create_directory_operation_unittest\.cc"
-  r"|create_file_operation_unittest\.cc"
-  r"|download_operation_unittest\.cc"
-  r"|drive_test_util\.h"
-  r"|entry_revert_performer_unittest\.cc"
-  r"|entry_update_performer_unittest\.cc"
-  r"|get_file_for_saving_operation_unittest\.cc"
-  r"|move_operation_unittest\.cc"
-  r"|open_file_operation_unittest\.cc"
-  r"|operation_test_base\.cc"
-  r"|remove_operation_unittest\.cc"
-  r"|remove_performer_unittest\.cc"
-  r"|search_operation_unittest\.cc"
-  r"|set_property_operation_unittest\.cc"
-  r"|truncate_operation_unittest\.cc"
-  r")": [
+  "drive_test_util\.h": [
     "+content/public/test/test_utils.h",
   ],
 
   # The following test dependencies should be removed to fully componentize this
   # directory. crbug.com/498951
-  r"(about_resource_loader_unittest\.cc"
-  r"|change_list_loader_unittest\.cc"
-  r"|change_list_processor_unittest\.cc"
-  r"|directory_loader_unittest\.cc"
+  r"(change_list_processor_unittest\.cc"
   r"|drive_file_util_unittest\.cc"
-  r"|fake_file_system_unittest\.cc"
   r"|file_cache_unittest\.cc"
   r"|file_system_core_util_unittest\.cc"
-  r"|file_system_unittest\.cc"
   r"|file_write_watcher_unittest\.cc"
   r"|job_scheduler_unittest\.cc"
-  r"|operation_test_base\.h"
   r"|remove_stale_cache_files_unittest\.cc"
   r"|resource_metadata_storage_unittest\.cc"
   r"|resource_metadata_unittest\.cc"
   r"|search_metadata_unittest\.cc"
-  r"|start_page_token_loader_unittest\.cc"
-  r"|sync_client_unittest\.cc"
-  r"|team_drive_change_list_loader_unittest\.cc"
-  r"|team_drive_list_loader_unittest\.cc"
   r")": [
     "+content/public/test/browser_task_environment.h",
   ],
@@ -65,11 +39,7 @@
   # The following test dependencies should be removed to fully componentize this
   # directory. crbug.com/498951
   r"(drive_uploader\.cc"
-  r"|fake_file_system\.cc"
-  r"|file_system_unittest\.cc"
   r"|file_write_watcher_unittest\.cc"
-  r"|get_file_for_saving_operation_unittest\.cc"
-  r"|operation_test_base\.cc"
   r")": [
     "+content/public/browser/browser_thread.h",
   ],
diff --git a/components/drive/about_resource_loader_unittest.cc b/components/drive/about_resource_loader_unittest.cc
deleted file mode 100644
index d9a1340f..0000000
--- a/components/drive/about_resource_loader_unittest.cc
+++ /dev/null
@@ -1,208 +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/drive/chromeos/about_resource_loader.h"
-
-#include <memory>
-
-#include "base/command_line.h"
-#include "base/files/scoped_temp_dir.h"
-#include "base/test/test_mock_time_task_runner.h"
-#include "base/threading/thread_task_runner_handle.h"
-#include "components/drive/chromeos/drive_test_util.h"
-#include "components/drive/chromeos/file_cache.h"
-#include "components/drive/chromeos/resource_metadata.h"
-#include "components/drive/event_logger.h"
-#include "components/drive/job_scheduler.h"
-#include "components/drive/resource_metadata_storage.h"
-#include "components/drive/service/fake_drive_service.h"
-#include "components/drive/service/test_util.h"
-#include "components/prefs/testing_pref_service.h"
-#include "mojo/public/cpp/bindings/pending_remote.h"
-#include "services/network/test/test_network_connection_tracker.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace drive {
-namespace internal {
-
-namespace {
-
-struct DestroyHelper {
-  template <typename T>
-  void operator()(T* object) const {
-    if (object) {
-      object->Destroy();
-    }
-  }
-};
-
-}  // namespace
-
-class AboutResourceLoaderTest : public testing::Test {
- protected:
-  void SetUp() override {
-    task_runner_ = base::MakeRefCounted<base::TestMockTimeTaskRunner>(
-        base::TestMockTimeTaskRunner::Type::kBoundToThread);
-
-    ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
-
-    pref_service_ = std::make_unique<TestingPrefServiceSimple>();
-    test_util::RegisterDrivePrefs(pref_service_->registry());
-
-    logger_ = std::make_unique<EventLogger>();
-
-    drive_service_ = std::make_unique<FakeDriveService>();
-    ASSERT_TRUE(test_util::SetUpTestEntries(drive_service_.get()));
-
-    network::TestNetworkConnectionTracker::GetInstance()->SetConnectionType(
-        network::mojom::ConnectionType::CONNECTION_WIFI);
-    scheduler_ = std::make_unique<JobScheduler>(
-        pref_service_.get(), logger_.get(), drive_service_.get(),
-        network::TestNetworkConnectionTracker::GetInstance(),
-        task_runner_.get(), mojo::NullRemote());
-    metadata_storage_.reset(
-        new ResourceMetadataStorage(temp_dir_.GetPath(), task_runner_.get()));
-    ASSERT_TRUE(metadata_storage_->Initialize());
-
-    cache_.reset(new FileCache(metadata_storage_.get(), temp_dir_.GetPath(),
-                               task_runner_.get(),
-                               nullptr /* free_disk_space_getter */));
-    ASSERT_TRUE(cache_->Initialize());
-
-    metadata_.reset(new ResourceMetadata(metadata_storage_.get(), cache_.get(),
-                                         task_runner_.get()));
-    ASSERT_EQ(FILE_ERROR_OK, metadata_->Initialize());
-
-    about_resource_loader_ = std::make_unique<AboutResourceLoader>(
-        scheduler_.get(), task_runner_->GetMockTickClock());
-  }
-
-  void TearDown() override {
-    // We need to manually reset the objects that implement the Destroy idiom,
-    // that deletes the object on the |task_runner_|. This is simpler than
-    // introducing custom deleters that capture the |task_runner_| and
-    // invoke RunUntilIdle().
-    metadata_.reset();
-    cache_.reset();
-    metadata_storage_.reset();
-    task_runner_->RunUntilIdle();
-  }
-
-  // Adds a new file to the root directory of the service.
-  std::unique_ptr<google_apis::FileResource> AddNewFile(
-      const std::string& title) {
-    google_apis::DriveApiErrorCode error = google_apis::DRIVE_FILE_ERROR;
-    std::unique_ptr<google_apis::FileResource> entry;
-    drive_service_->AddNewFile(
-        "text/plain", "content text", drive_service_->GetRootResourceId(),
-        title,
-        false,  // shared_with_me
-        google_apis::test_util::CreateCopyResultCallback(&error, &entry));
-    task_runner_->RunUntilIdle();
-    EXPECT_EQ(google_apis::HTTP_CREATED, error);
-    return entry;
-  }
-
-  scoped_refptr<base::TestMockTimeTaskRunner> task_runner_;
-  base::ScopedTempDir temp_dir_;
-  std::unique_ptr<TestingPrefServiceSimple> pref_service_;
-  std::unique_ptr<EventLogger> logger_;
-  std::unique_ptr<FakeDriveService> drive_service_;
-  std::unique_ptr<JobScheduler> scheduler_;
-  std::unique_ptr<ResourceMetadataStorage, DestroyHelper> metadata_storage_;
-  std::unique_ptr<FileCache, DestroyHelper> cache_;
-  std::unique_ptr<ResourceMetadata, DestroyHelper> metadata_;
-  std::unique_ptr<AboutResourceLoader> about_resource_loader_;
-};
-
-TEST_F(AboutResourceLoaderTest, AboutResourceLoader) {
-  google_apis::DriveApiErrorCode error[6] = {};
-  std::unique_ptr<google_apis::AboutResource> about[6];
-
-  // No resource is cached at the beginning.
-  ASSERT_FALSE(about_resource_loader_->cached_about_resource());
-
-  // Since no resource is cached, this "Get" should trigger the update.
-  about_resource_loader_->GetAboutResource(
-      google_apis::test_util::CreateCopyResultCallback(error + 0, about + 0));
-  // Since there is one in-flight update, the next "Get" just wait for it.
-  about_resource_loader_->GetAboutResource(
-      google_apis::test_util::CreateCopyResultCallback(error + 1, about + 1));
-
-  task_runner_->RunUntilIdle();
-  EXPECT_EQ(google_apis::HTTP_SUCCESS, error[0]);
-  EXPECT_EQ(google_apis::HTTP_SUCCESS, error[1]);
-  const int64_t first_changestamp = about[0]->largest_change_id();
-  EXPECT_EQ(first_changestamp, about[1]->largest_change_id());
-  ASSERT_TRUE(about_resource_loader_->cached_about_resource());
-  EXPECT_EQ(
-      first_changestamp,
-      about_resource_loader_->cached_about_resource()->largest_change_id());
-
-  // Increment changestamp by 1.
-  AddNewFile("temp");
-  // Explicitly calling UpdateAboutResource will start another API call.
-  about_resource_loader_->UpdateAboutResource(
-      google_apis::test_util::CreateCopyResultCallback(error + 2, about + 2));
-  // It again waits for the in-flight UpdateAboutResoure call, even though this
-  // time there is a cached result.
-  about_resource_loader_->GetAboutResource(
-      google_apis::test_util::CreateCopyResultCallback(error + 3, about + 3));
-
-  task_runner_->RunUntilIdle();
-  EXPECT_EQ(google_apis::HTTP_SUCCESS, error[2]);
-  EXPECT_EQ(google_apis::HTTP_SUCCESS, error[3]);
-  EXPECT_EQ(first_changestamp + 1, about[2]->largest_change_id());
-  EXPECT_EQ(first_changestamp + 1, about[3]->largest_change_id());
-  EXPECT_EQ(
-      first_changestamp + 1,
-      about_resource_loader_->cached_about_resource()->largest_change_id());
-
-  // Increment changestamp by 1.
-  AddNewFile("temp2");
-  // Now no UpdateAboutResource task is running. Returns the cached result.
-  about_resource_loader_->GetAboutResource(
-      google_apis::test_util::CreateCopyResultCallback(error + 4, about + 4));
-  // Explicitly calling UpdateAboutResource will start another API call.
-  about_resource_loader_->UpdateAboutResource(
-      google_apis::test_util::CreateCopyResultCallback(error + 5, about + 5));
-
-  task_runner_->RunUntilIdle();
-  EXPECT_EQ(google_apis::HTTP_NO_CONTENT, error[4]);
-  EXPECT_EQ(google_apis::HTTP_SUCCESS, error[5]);
-  EXPECT_EQ(first_changestamp + 1, about[4]->largest_change_id());
-  EXPECT_EQ(first_changestamp + 2, about[5]->largest_change_id());
-  EXPECT_EQ(
-      first_changestamp + 2,
-      about_resource_loader_->cached_about_resource()->largest_change_id());
-
-  EXPECT_EQ(3, drive_service_->about_resource_load_count());
-}
-
-TEST_F(AboutResourceLoaderTest, EvictCache) {
-  google_apis::DriveApiErrorCode error;
-  std::unique_ptr<google_apis::AboutResource> about;
-
-  // No resource is cached at the beginning.
-  ASSERT_FALSE(about_resource_loader_->cached_about_resource());
-
-  // Since no resource is cached, this "Get" should trigger the update.
-  about_resource_loader_->GetAboutResource(
-      google_apis::test_util::CreateCopyResultCallback(&error, &about));
-
-  task_runner_->RunUntilIdle();
-  EXPECT_EQ(google_apis::HTTP_SUCCESS, error);
-
-  // Should have a cached resource.
-  ASSERT_TRUE(about_resource_loader_->cached_about_resource());
-
-  // Advance the timer should evict the cache.
-  task_runner_->FastForwardUntilNoTasksRemain();
-
-  // Cache should be evicted.
-  ASSERT_FALSE(about_resource_loader_->cached_about_resource());
-}
-
-}  // namespace internal
-}  // namespace drive
diff --git a/components/drive/change_list_loader_unittest.cc b/components/drive/change_list_loader_unittest.cc
deleted file mode 100644
index 6d556ce..0000000
--- a/components/drive/change_list_loader_unittest.cc
+++ /dev/null
@@ -1,407 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "components/drive/chromeos/change_list_loader.h"
-
-#include <stdint.h>
-
-#include <memory>
-
-#include "base/callback_helpers.h"
-#include "base/command_line.h"
-#include "base/files/scoped_temp_dir.h"
-#include "base/macros.h"
-#include "base/run_loop.h"
-#include "base/single_thread_task_runner.h"
-#include "base/threading/thread_task_runner_handle.h"
-#include "components/drive/chromeos/about_resource_loader.h"
-#include "components/drive/chromeos/about_resource_root_folder_id_loader.h"
-#include "components/drive/chromeos/change_list_loader_observer.h"
-#include "components/drive/chromeos/drive_test_util.h"
-#include "components/drive/chromeos/file_cache.h"
-#include "components/drive/chromeos/loader_controller.h"
-#include "components/drive/chromeos/resource_metadata.h"
-#include "components/drive/chromeos/start_page_token_loader.h"
-#include "components/drive/event_logger.h"
-#include "components/drive/file_change.h"
-#include "components/drive/file_system_core_util.h"
-#include "components/drive/job_scheduler.h"
-#include "components/drive/service/fake_drive_service.h"
-#include "components/drive/service/test_util.h"
-#include "components/prefs/testing_pref_service.h"
-#include "content/public/test/browser_task_environment.h"
-#include "google_apis/drive/drive_api_parser.h"
-#include "google_apis/drive/test_util.h"
-#include "mojo/public/cpp/bindings/pending_remote.h"
-#include "services/network/test/test_network_connection_tracker.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace drive {
-namespace internal {
-
-class TestChangeListLoaderObserver : public ChangeListLoaderObserver {
- public:
-  explicit TestChangeListLoaderObserver(ChangeListLoader* loader)
-      : loader_(loader),
-        load_from_server_complete_count_(0),
-        initial_load_complete_count_(0) {
-    loader_->AddObserver(this);
-  }
-
-  ~TestChangeListLoaderObserver() override { loader_->RemoveObserver(this); }
-
-  const FileChange& changed_files() const { return changed_files_; }
-  void clear_changed_files() { changed_files_.ClearForTest(); }
-
-  const FileChange& changed_team_drives() const { return changed_team_drives_; }
-
-  int load_from_server_complete_count() const {
-    return load_from_server_complete_count_;
-  }
-  int initial_load_complete_count() const {
-    return initial_load_complete_count_;
-  }
-
-  // ChageListObserver overrides:
-  void OnFileChanged(const FileChange& changed_files) override {
-    changed_files_.Apply(changed_files);
-  }
-  void OnTeamDrivesChanged(const FileChange& changed_team_drives) override {
-    changed_team_drives_.Apply(changed_team_drives);
-  }
-  void OnLoadFromServerComplete() override {
-    ++load_from_server_complete_count_;
-  }
-  void OnInitialLoadComplete() override { ++initial_load_complete_count_; }
-
- private:
-  ChangeListLoader* loader_;
-  FileChange changed_files_;
-  FileChange changed_team_drives_;
-  int load_from_server_complete_count_;
-  int initial_load_complete_count_;
-
-  DISALLOW_COPY_AND_ASSIGN(TestChangeListLoaderObserver);
-};
-
-class ChangeListLoaderTest : public testing::Test {
- protected:
-  void SetUp() override {
-    ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
-    BuildTestObjects();
-  }
-
-  void BuildTestObjects() {
-    pref_service_ = std::make_unique<TestingPrefServiceSimple>();
-    test_util::RegisterDrivePrefs(pref_service_->registry());
-
-    logger_ = std::make_unique<EventLogger>();
-
-    drive_service_ = std::make_unique<FakeDriveService>();
-    ASSERT_TRUE(test_util::SetUpTestEntries(drive_service_.get()));
-
-    network::TestNetworkConnectionTracker::GetInstance()->SetConnectionType(
-        network::mojom::ConnectionType::CONNECTION_WIFI);
-    scheduler_ = std::make_unique<JobScheduler>(
-        pref_service_.get(), logger_.get(), drive_service_.get(),
-        network::TestNetworkConnectionTracker::GetInstance(),
-        base::ThreadTaskRunnerHandle::Get().get(), mojo::NullRemote());
-    metadata_storage_.reset(new ResourceMetadataStorage(
-        temp_dir_.GetPath(), base::ThreadTaskRunnerHandle::Get().get()));
-    ASSERT_TRUE(metadata_storage_->Initialize());
-
-    cache_.reset(new FileCache(metadata_storage_.get(), temp_dir_.GetPath(),
-                               base::ThreadTaskRunnerHandle::Get().get(),
-                               nullptr /* free_disk_space_getter */));
-    ASSERT_TRUE(cache_->Initialize());
-
-    metadata_.reset(new ResourceMetadata(
-        metadata_storage_.get(), cache_.get(),
-        base::ThreadTaskRunnerHandle::Get().get()));
-    ASSERT_EQ(FILE_ERROR_OK, metadata_->Initialize());
-
-    about_resource_loader_ =
-        std::make_unique<AboutResourceLoader>(scheduler_.get());
-    root_folder_id_loader_ = std::make_unique<AboutResourceRootFolderIdLoader>(
-        about_resource_loader_.get());
-    start_page_token_loader_ = std::make_unique<StartPageTokenLoader>(
-        drive::util::kTeamDriveIdDefaultCorpus, scheduler_.get());
-    loader_controller_ = std::make_unique<LoaderController>();
-    change_list_loader_ = std::make_unique<ChangeListLoader>(
-        logger_.get(), base::ThreadTaskRunnerHandle::Get().get(),
-        metadata_.get(), scheduler_.get(), root_folder_id_loader_.get(),
-        start_page_token_loader_.get(), loader_controller_.get(),
-        util::kTeamDriveIdDefaultCorpus, util::GetDriveMyDriveRootPath());
-  }
-
-  // Adds a new file to the root directory of the service.
-  std::unique_ptr<google_apis::FileResource> AddNewFile(
-      const std::string& title) {
-    google_apis::DriveApiErrorCode error = google_apis::DRIVE_FILE_ERROR;
-    std::unique_ptr<google_apis::FileResource> entry;
-    drive_service_->AddNewFile(
-        "text/plain",
-        "content text",
-        drive_service_->GetRootResourceId(),
-        title,
-        false,  // shared_with_me
-        google_apis::test_util::CreateCopyResultCallback(&error, &entry));
-    base::RunLoop().RunUntilIdle();
-    EXPECT_EQ(google_apis::HTTP_CREATED, error);
-    return entry;
-  }
-
-  content::BrowserTaskEnvironment task_environment_;
-  base::ScopedTempDir temp_dir_;
-  std::unique_ptr<TestingPrefServiceSimple> pref_service_;
-  std::unique_ptr<EventLogger> logger_;
-  std::unique_ptr<FakeDriveService> drive_service_;
-  std::unique_ptr<JobScheduler> scheduler_;
-  std::unique_ptr<ResourceMetadataStorage, test_util::DestroyHelperForTests>
-      metadata_storage_;
-  std::unique_ptr<FileCache, test_util::DestroyHelperForTests> cache_;
-  std::unique_ptr<ResourceMetadata, test_util::DestroyHelperForTests> metadata_;
-  std::unique_ptr<AboutResourceLoader> about_resource_loader_;
-  std::unique_ptr<StartPageTokenLoader> start_page_token_loader_;
-  std::unique_ptr<LoaderController> loader_controller_;
-  std::unique_ptr<ChangeListLoader> change_list_loader_;
-  std::unique_ptr<AboutResourceRootFolderIdLoader> root_folder_id_loader_;
-};
-
-TEST_F(ChangeListLoaderTest, Load) {
-  EXPECT_FALSE(change_list_loader_->IsRefreshing());
-
-  // Start initial load.
-  TestChangeListLoaderObserver observer(change_list_loader_.get());
-
-  EXPECT_EQ(0, drive_service_->about_resource_load_count());
-
-  FileError error = FILE_ERROR_FAILED;
-  change_list_loader_->LoadIfNeeded(
-      google_apis::test_util::CreateCopyResultCallback(&error));
-  EXPECT_TRUE(change_list_loader_->IsRefreshing());
-  base::RunLoop().RunUntilIdle();
-  EXPECT_EQ(FILE_ERROR_OK, error);
-
-  EXPECT_FALSE(change_list_loader_->IsRefreshing());
-  std::string start_page_token;
-  EXPECT_EQ(FILE_ERROR_OK, metadata_->GetStartPageToken(&start_page_token));
-  EXPECT_FALSE(start_page_token.empty());
-  EXPECT_EQ(0, drive_service_->team_drive_list_load_count());
-  EXPECT_EQ(1, drive_service_->file_list_load_count());
-  EXPECT_EQ(1, drive_service_->about_resource_load_count());
-  EXPECT_EQ(1, observer.initial_load_complete_count());
-  EXPECT_EQ(1, observer.load_from_server_complete_count());
-  EXPECT_TRUE(observer.changed_files().empty());
-
-  base::FilePath file_path =
-      util::GetDriveMyDriveRootPath().AppendASCII("File 1.txt");
-  ResourceEntry entry;
-  EXPECT_EQ(FILE_ERROR_OK,
-            metadata_->GetResourceEntryByPath(file_path, &entry));
-
-  // Calling LoadIfNeeded a second time is a no-op, ensure that the
-  // callback is called.
-  error = FILE_ERROR_FAILED;
-  change_list_loader_->LoadIfNeeded(
-      google_apis::test_util::CreateCopyResultCallback(&error));
-  EXPECT_FALSE(change_list_loader_->IsRefreshing());
-  base::RunLoop().RunUntilIdle();
-  EXPECT_EQ(FILE_ERROR_OK, error);
-}
-
-TEST_F(ChangeListLoaderTest, Load_LocalMetadataAvailable) {
-  // Prepare metadata.
-  FileError error = FILE_ERROR_FAILED;
-  change_list_loader_->LoadIfNeeded(
-      google_apis::test_util::CreateCopyResultCallback(&error));
-  base::RunLoop().RunUntilIdle();
-  EXPECT_EQ(FILE_ERROR_OK, error);
-
-  // Reset loader.
-  about_resource_loader_ =
-      std::make_unique<AboutResourceLoader>(scheduler_.get());
-  root_folder_id_loader_ = std::make_unique<AboutResourceRootFolderIdLoader>(
-      about_resource_loader_.get());
-  start_page_token_loader_ = std::make_unique<StartPageTokenLoader>(
-      drive::util::kTeamDriveIdDefaultCorpus, scheduler_.get());
-  change_list_loader_ = std::make_unique<ChangeListLoader>(
-      logger_.get(), base::ThreadTaskRunnerHandle::Get().get(), metadata_.get(),
-      scheduler_.get(), root_folder_id_loader_.get(),
-      start_page_token_loader_.get(), loader_controller_.get(),
-      util::kTeamDriveIdDefaultCorpus, util::GetDriveMyDriveRootPath());
-
-  // Add a file to the service.
-  std::unique_ptr<google_apis::FileResource> gdata_entry =
-      AddNewFile("New File");
-  ASSERT_TRUE(gdata_entry);
-
-  // Start loading. Because local metadata is available, the load results in
-  // returning FILE_ERROR_OK without fetching full list of resources.
-  const int previous_file_list_load_count =
-      drive_service_->file_list_load_count();
-  TestChangeListLoaderObserver observer(change_list_loader_.get());
-
-  change_list_loader_->LoadIfNeeded(
-      google_apis::test_util::CreateCopyResultCallback(&error));
-  EXPECT_TRUE(change_list_loader_->IsRefreshing());
-  base::RunLoop().RunUntilIdle();
-  EXPECT_EQ(FILE_ERROR_OK, error);
-  EXPECT_EQ(previous_file_list_load_count,
-            drive_service_->file_list_load_count());
-  EXPECT_EQ(1, observer.initial_load_complete_count());
-
-  // Update should be checked by Load().
-  std::string start_page_token;
-  EXPECT_EQ(FILE_ERROR_OK, metadata_->GetStartPageToken(&start_page_token));
-  EXPECT_EQ(drive_service_->start_page_token().start_page_token(),
-            start_page_token);
-  EXPECT_EQ(1, drive_service_->change_list_load_count());
-  EXPECT_EQ(1, observer.load_from_server_complete_count());
-  EXPECT_TRUE(
-      observer.changed_files().CountDirectory(util::GetDriveMyDriveRootPath()));
-
-  base::FilePath file_path =
-      util::GetDriveMyDriveRootPath().AppendASCII(gdata_entry->title());
-  ResourceEntry entry;
-  EXPECT_EQ(FILE_ERROR_OK,
-            metadata_->GetResourceEntryByPath(file_path, &entry));
-}
-
-TEST_F(ChangeListLoaderTest, CheckForUpdates) {
-  // CheckForUpdates() results in no-op before load.
-  FileError check_for_updates_error = FILE_ERROR_FAILED;
-  change_list_loader_->CheckForUpdates(
-      google_apis::test_util::CreateCopyResultCallback(
-          &check_for_updates_error));
-  EXPECT_FALSE(change_list_loader_->IsRefreshing());
-  base::RunLoop().RunUntilIdle();
-  EXPECT_EQ(FILE_ERROR_FAILED,
-            check_for_updates_error);  // Callback was not run.
-  std::string start_page_token;
-  EXPECT_EQ(FILE_ERROR_OK, metadata_->GetStartPageToken(&start_page_token));
-  EXPECT_TRUE(start_page_token.empty());
-  EXPECT_EQ(0, drive_service_->file_list_load_count());
-  EXPECT_EQ(0, drive_service_->about_resource_load_count());
-
-  // Start initial load.
-  FileError load_error = FILE_ERROR_FAILED;
-  change_list_loader_->LoadIfNeeded(
-      google_apis::test_util::CreateCopyResultCallback(&load_error));
-  EXPECT_TRUE(change_list_loader_->IsRefreshing());
-
-  // CheckForUpdates() while loading.
-  change_list_loader_->CheckForUpdates(
-      google_apis::test_util::CreateCopyResultCallback(
-          &check_for_updates_error));
-
-  base::RunLoop().RunUntilIdle();
-  EXPECT_FALSE(change_list_loader_->IsRefreshing());
-  EXPECT_EQ(FILE_ERROR_OK, load_error);
-  EXPECT_EQ(FILE_ERROR_OK, check_for_updates_error);
-  EXPECT_EQ(FILE_ERROR_OK, metadata_->GetStartPageToken(&start_page_token));
-  EXPECT_FALSE(start_page_token.empty());
-  EXPECT_EQ(1, drive_service_->file_list_load_count());
-
-  std::string previous_start_page_token = start_page_token;
-  // CheckForUpdates() results in no update.
-  change_list_loader_->CheckForUpdates(
-      google_apis::test_util::CreateCopyResultCallback(
-          &check_for_updates_error));
-  EXPECT_TRUE(change_list_loader_->IsRefreshing());
-  base::RunLoop().RunUntilIdle();
-  EXPECT_FALSE(change_list_loader_->IsRefreshing());
-  EXPECT_EQ(FILE_ERROR_OK, metadata_->GetStartPageToken(&start_page_token));
-  EXPECT_EQ(previous_start_page_token, start_page_token);
-
-  // Add a file to the service.
-  std::unique_ptr<google_apis::FileResource> gdata_entry =
-      AddNewFile("New File");
-  ASSERT_TRUE(gdata_entry);
-
-  // CheckForUpdates() results in update.
-  TestChangeListLoaderObserver observer(change_list_loader_.get());
-  change_list_loader_->CheckForUpdates(
-      google_apis::test_util::CreateCopyResultCallback(
-          &check_for_updates_error));
-  EXPECT_TRUE(change_list_loader_->IsRefreshing());
-  base::RunLoop().RunUntilIdle();
-  EXPECT_FALSE(change_list_loader_->IsRefreshing());
-  EXPECT_EQ(FILE_ERROR_OK, metadata_->GetStartPageToken(&start_page_token));
-  EXPECT_NE(previous_start_page_token, start_page_token);
-  EXPECT_EQ(1, observer.load_from_server_complete_count());
-  EXPECT_TRUE(
-      observer.changed_files().CountDirectory(util::GetDriveMyDriveRootPath()));
-
-  // The new file is found in the local metadata.
-  base::FilePath new_file_path =
-      util::GetDriveMyDriveRootPath().AppendASCII(gdata_entry->title());
-  ResourceEntry entry;
-  EXPECT_EQ(FILE_ERROR_OK,
-            metadata_->GetResourceEntryByPath(new_file_path, &entry));
-}
-
-TEST_F(ChangeListLoaderTest, Lock) {
-  FileError error = FILE_ERROR_FAILED;
-  change_list_loader_->LoadIfNeeded(
-      google_apis::test_util::CreateCopyResultCallback(&error));
-  base::RunLoop().RunUntilIdle();
-  EXPECT_EQ(FILE_ERROR_OK, error);
-
-  // Add a new file.
-  std::unique_ptr<google_apis::FileResource> file = AddNewFile("New File");
-  ASSERT_TRUE(file);
-
-  // Lock the loader.
-  std::unique_ptr<base::ScopedClosureRunner> lock =
-      loader_controller_->GetLock();
-
-  // Start update.
-  TestChangeListLoaderObserver observer(change_list_loader_.get());
-  FileError check_for_updates_error = FILE_ERROR_FAILED;
-  change_list_loader_->CheckForUpdates(
-      google_apis::test_util::CreateCopyResultCallback(
-          &check_for_updates_error));
-  base::RunLoop().RunUntilIdle();
-
-  // Update is pending due to the lock.
-  EXPECT_TRUE(observer.changed_files().empty());
-
-  // Unlock the loader, this should resume the pending update.
-  lock.reset();
-  base::RunLoop().RunUntilIdle();
-  EXPECT_TRUE(
-      observer.changed_files().CountDirectory(util::GetDriveMyDriveRootPath()));
-}
-
-TEST_F(ChangeListLoaderTest, AddTeamDrive) {
-  FileError error = FILE_ERROR_FAILED;
-  change_list_loader_->LoadIfNeeded(
-      google_apis::test_util::CreateCopyResultCallback(&error));
-  base::RunLoop().RunUntilIdle();
-  EXPECT_EQ(FILE_ERROR_OK, error);
-
-  // Add a new team drive
-  {
-    drive_service_->AddTeamDrive("team_drive_id", "team_drive_name");
-    base::RunLoop().RunUntilIdle();
-  }
-
-  // Start update.
-  TestChangeListLoaderObserver observer(change_list_loader_.get());
-  FileError check_for_updates_error = FILE_ERROR_FAILED;
-  change_list_loader_->CheckForUpdates(
-      google_apis::test_util::CreateCopyResultCallback(
-          &check_for_updates_error));
-  base::RunLoop().RunUntilIdle();
-
-  EXPECT_FALSE(observer.changed_files().empty());
-  EXPECT_FALSE(observer.changed_team_drives().empty());
-  EXPECT_EQ(1UL, observer.changed_files().CountDirectory(
-                     util::GetDriveTeamDrivesRootPath()));
-  EXPECT_EQ(1UL, observer.changed_team_drives().CountDirectory(
-                     util::GetDriveTeamDrivesRootPath()));
-}
-}  // namespace internal
-}  // namespace drive
diff --git a/components/drive/chromeos/about_resource_loader.cc b/components/drive/chromeos/about_resource_loader.cc
deleted file mode 100644
index 5971e9e..0000000
--- a/components/drive/chromeos/about_resource_loader.cc
+++ /dev/null
@@ -1,110 +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/drive/chromeos/about_resource_loader.h"
-
-#include <memory>
-#include <vector>
-
-#include "base/bind.h"
-#include "base/threading/thread_task_runner_handle.h"
-#include "components/drive/job_scheduler.h"
-
-namespace drive {
-namespace internal {
-
-namespace {
-// The time period that we will cache the result of UpdateAboutResource.
-constexpr base::TimeDelta kCacheEvictionTimeout =
-    base::TimeDelta::FromMinutes(1);
-}  // namespace
-
-AboutResourceLoader::AboutResourceLoader(JobScheduler* scheduler,
-                                         const base::TickClock* clock)
-    : scheduler_(scheduler), current_update_task_id_(-1) {
-  cache_eviction_timer_ = std::make_unique<base::RetainingOneShotTimer>(
-      FROM_HERE, kCacheEvictionTimeout,
-      base::BindRepeating(&AboutResourceLoader::EvictCachedAboutResource,
-                          base::Unretained(this)),
-      clock);
-}
-
-AboutResourceLoader::~AboutResourceLoader() = default;
-
-void AboutResourceLoader::GetAboutResource(
-    const google_apis::AboutResourceCallback& callback) {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-  DCHECK(callback);
-
-  // If the latest UpdateAboutResource task is still running. Wait for it,
-  if (pending_callbacks_.count(current_update_task_id_)) {
-    pending_callbacks_[current_update_task_id_].emplace_back(callback);
-    return;
-  }
-
-  if (cached_about_resource_) {
-    base::ThreadTaskRunnerHandle::Get()->PostTask(
-        FROM_HERE, base::BindOnce(callback, google_apis::HTTP_NO_CONTENT,
-                                  std::make_unique<google_apis::AboutResource>(
-                                      *cached_about_resource_)));
-  } else {
-    UpdateAboutResource(callback);
-  }
-}
-
-void AboutResourceLoader::UpdateAboutResource(
-    const google_apis::AboutResourceCallback& callback) {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-  DCHECK(callback);
-
-  ++current_update_task_id_;
-  pending_callbacks_[current_update_task_id_].emplace_back(callback);
-
-  scheduler_->GetAboutResource(base::BindRepeating(
-      &AboutResourceLoader::UpdateAboutResourceAfterGetAbout,
-      weak_ptr_factory_.GetWeakPtr(), current_update_task_id_));
-}
-
-void AboutResourceLoader::UpdateAboutResourceAfterGetAbout(
-    int task_id,
-    google_apis::DriveApiErrorCode status,
-    std::unique_ptr<google_apis::AboutResource> about_resource) {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-  FileError error = GDataToFileError(status);
-
-  const std::vector<google_apis::AboutResourceCallback> callbacks =
-      pending_callbacks_[task_id];
-  pending_callbacks_.erase(task_id);
-
-  if (error != FILE_ERROR_OK) {
-    for (auto& callback : callbacks)
-      callback.Run(status, nullptr);
-    return;
-  }
-
-  // Updates the cache when the resource is successfully obtained.
-  if (cached_about_resource_ && cached_about_resource_->largest_change_id() >
-                                    about_resource->largest_change_id()) {
-    LOG(WARNING) << "Local cached about resource is fresher than server, "
-                 << "local = " << cached_about_resource_->largest_change_id()
-                 << ", server = " << about_resource->largest_change_id();
-  }
-  cached_about_resource_ =
-      std::make_unique<google_apis::AboutResource>(*about_resource);
-
-  cache_eviction_timer_->Reset();
-
-  for (auto& callback : callbacks) {
-    callback.Run(status,
-                 std::make_unique<google_apis::AboutResource>(*about_resource));
-  }
-}
-
-void AboutResourceLoader::EvictCachedAboutResource() {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-  cached_about_resource_.reset();
-}
-
-}  // namespace internal
-}  // namespace drive
diff --git a/components/drive/chromeos/about_resource_loader.h b/components/drive/chromeos/about_resource_loader.h
deleted file mode 100644
index d2b513a..0000000
--- a/components/drive/chromeos/about_resource_loader.h
+++ /dev/null
@@ -1,86 +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_DRIVE_CHROMEOS_ABOUT_RESOURCE_LOADER_H_
-#define COMPONENTS_DRIVE_CHROMEOS_ABOUT_RESOURCE_LOADER_H_
-
-#include <map>
-#include <memory>
-#include <vector>
-
-#include "base/macros.h"
-#include "base/memory/weak_ptr.h"
-#include "base/threading/thread_checker.h"
-#include "base/time/default_tick_clock.h"
-#include "base/timer/timer.h"
-#include "google_apis/drive/drive_common_callbacks.h"
-
-namespace drive {
-
-class JobScheduler;
-
-namespace internal {
-
-// This class is responsible to load AboutResource from the server and cache it.
-class AboutResourceLoader {
- public:
-  // |clock| can be injected for testing.
-  explicit AboutResourceLoader(
-      JobScheduler* scheduler,
-      const base::TickClock* clock = base::DefaultTickClock::GetInstance());
-  ~AboutResourceLoader();
-
-  // Returns the cached about resource.
-  // NULL is returned if the cache is not available.
-  const google_apis::AboutResource* cached_about_resource() const {
-    return cached_about_resource_.get();
-  }
-
-  // Gets the 'latest' about resource and asynchronously runs |callback|. I.e.,
-  // 1) If the last call to UpdateAboutResource call is in-flight, wait for it.
-  // 2) Otherwise, if the resource is cached, just returns the cached value.
-  // 3) If neither of the above hold, queries the API server by calling
-  //   |UpdateAboutResource|.
-  void GetAboutResource(const google_apis::AboutResourceCallback& callback);
-
-  // Gets the about resource from the server, and caches it if successful. This
-  // function calls JobScheduler::GetAboutResource internally. The cache will be
-  // used in |GetAboutResource|.
-  void UpdateAboutResource(const google_apis::AboutResourceCallback& callback);
-
- private:
-  // Part of UpdateAboutResource().
-  // This function should be called when the latest about resource is being
-  // fetched from the server. The retrieved about resource is cloned, and one is
-  // cached and the other is passed to callbacks associated with |task_id|.
-  void UpdateAboutResourceAfterGetAbout(
-      int task_id,
-      google_apis::DriveApiErrorCode status,
-      std::unique_ptr<google_apis::AboutResource> about_resource);
-
-  void EvictCachedAboutResource();
-
-  JobScheduler* scheduler_;
-  std::unique_ptr<google_apis::AboutResource> cached_about_resource_;
-
-  // Identifier to denote the latest UpdateAboutResource call.
-  int current_update_task_id_;
-  // Mapping from each UpdateAboutResource task ID to the corresponding
-  // callbacks. Note that there will be multiple callbacks for a single task
-  // when GetAboutResource is called before the task completes.
-  std::map<int, std::vector<google_apis::AboutResourceCallback>>
-      pending_callbacks_;
-
-  std::unique_ptr<base::RetainingOneShotTimer> cache_eviction_timer_;
-
-  THREAD_CHECKER(thread_checker_);
-
-  base::WeakPtrFactory<AboutResourceLoader> weak_ptr_factory_{this};
-  DISALLOW_COPY_AND_ASSIGN(AboutResourceLoader);
-};
-
-}  // namespace internal
-}  // namespace drive
-
-#endif  // COMPONENTS_DRIVE_CHROMEOS_ABOUT_RESOURCE_LOADER_H_
diff --git a/components/drive/chromeos/about_resource_root_folder_id_loader.cc b/components/drive/chromeos/about_resource_root_folder_id_loader.cc
deleted file mode 100644
index 5308c6f6..0000000
--- a/components/drive/chromeos/about_resource_root_folder_id_loader.cc
+++ /dev/null
@@ -1,57 +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/drive/chromeos/about_resource_root_folder_id_loader.h"
-
-#include <memory>
-
-#include "base/bind.h"
-#include "components/drive/chromeos/about_resource_loader.h"
-#include "google_apis/drive/drive_api_parser.h"
-
-namespace drive {
-namespace internal {
-
-AboutResourceRootFolderIdLoader::AboutResourceRootFolderIdLoader(
-    AboutResourceLoader* about_resource_loader)
-    : about_resource_loader_(about_resource_loader) {}
-
-AboutResourceRootFolderIdLoader::~AboutResourceRootFolderIdLoader() = default;
-
-void AboutResourceRootFolderIdLoader::GetRootFolderId(
-    const RootFolderIdCallback& callback) {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-
-  // If we have already read the root folder id, then we can simply return it.
-  if (!root_folder_id_.empty()) {
-    callback.Run(FILE_ERROR_OK, root_folder_id_);
-    return;
-  }
-
-  about_resource_loader_->GetAboutResource(
-      base::BindRepeating(&AboutResourceRootFolderIdLoader::OnGetAboutResource,
-                          weak_ptr_factory_.GetWeakPtr(), callback));
-}
-
-void AboutResourceRootFolderIdLoader::OnGetAboutResource(
-    const RootFolderIdCallback& callback,
-    google_apis::DriveApiErrorCode status,
-    std::unique_ptr<google_apis::AboutResource> about_resource) {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-  FileError error = GDataToFileError(status);
-
-  if (error != FILE_ERROR_OK) {
-    callback.Run(error, base::nullopt);
-    return;
-  }
-
-  DCHECK(about_resource);
-
-  // The root folder id is immutable so we can save it for subsequent calls.
-  root_folder_id_ = about_resource->root_folder_id();
-  callback.Run(error, root_folder_id_);
-}
-
-}  // namespace internal
-}  // namespace drive
diff --git a/components/drive/chromeos/about_resource_root_folder_id_loader.h b/components/drive/chromeos/about_resource_root_folder_id_loader.h
deleted file mode 100644
index 96978ed..0000000
--- a/components/drive/chromeos/about_resource_root_folder_id_loader.h
+++ /dev/null
@@ -1,55 +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_DRIVE_CHROMEOS_ABOUT_RESOURCE_ROOT_FOLDER_ID_LOADER_H_
-#define COMPONENTS_DRIVE_CHROMEOS_ABOUT_RESOURCE_ROOT_FOLDER_ID_LOADER_H_
-
-#include <memory>
-#include <string>
-
-#include "base/memory/weak_ptr.h"
-#include "base/threading/thread_checker.h"
-#include "components/drive/chromeos/root_folder_id_loader.h"
-#include "google_apis/drive/drive_api_error_codes.h"
-
-namespace google_apis {
-class AboutResource;
-}  // namespace google_apis
-
-namespace drive {
-namespace internal {
-
-class AboutResourceLoader;
-
-// Retrieves the root folder id from the about resource loader. This is used
-// to get the root folder ID for the users default corpus. As the value is
-// constant we just use GetAboutResource which will usually retrieve a
-// cached value.
-class AboutResourceRootFolderIdLoader : public RootFolderIdLoader {
- public:
-  explicit AboutResourceRootFolderIdLoader(
-      AboutResourceLoader* about_resource_loader);
-  ~AboutResourceRootFolderIdLoader() override;
-
-  void GetRootFolderId(const RootFolderIdCallback& callback) override;
-
- private:
-  void OnGetAboutResource(
-      const RootFolderIdCallback& callback,
-      google_apis::DriveApiErrorCode error,
-      std::unique_ptr<google_apis::AboutResource> about_resource);
-
-  AboutResourceLoader* about_resource_loader_;  // Not owned.
-  std::string root_folder_id_;
-
-  THREAD_CHECKER(thread_checker_);
-
-  base::WeakPtrFactory<AboutResourceRootFolderIdLoader> weak_ptr_factory_{this};
-  DISALLOW_COPY_AND_ASSIGN(AboutResourceRootFolderIdLoader);
-};
-
-}  // namespace internal
-}  // namespace drive
-
-#endif  // COMPONENTS_DRIVE_CHROMEOS_ABOUT_RESOURCE_ROOT_FOLDER_ID_LOADER_H_
diff --git a/components/drive/chromeos/change_list_loader.cc b/components/drive/chromeos/change_list_loader.cc
deleted file mode 100644
index 78b9e12f..0000000
--- a/components/drive/chromeos/change_list_loader.cc
+++ /dev/null
@@ -1,519 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "components/drive/chromeos/change_list_loader.h"
-
-#include <stddef.h>
-
-#include <memory>
-#include <set>
-#include <utility>
-
-#include "base/bind.h"
-#include "base/bind_helpers.h"
-#include "base/callback.h"
-#include "base/macros.h"
-#include "base/metrics/histogram_macros.h"
-#include "base/strings/strcat.h"
-#include "base/strings/string_number_conversions.h"
-#include "base/synchronization/atomic_flag.h"
-#include "base/threading/thread_task_runner_handle.h"
-#include "base/time/time.h"
-#include "components/drive/chromeos/change_list_loader_observer.h"
-#include "components/drive/chromeos/change_list_processor.h"
-#include "components/drive/chromeos/drive_file_util.h"
-#include "components/drive/chromeos/loader_controller.h"
-#include "components/drive/chromeos/resource_metadata.h"
-#include "components/drive/chromeos/root_folder_id_loader.h"
-#include "components/drive/chromeos/start_page_token_loader.h"
-#include "components/drive/drive_api_util.h"
-#include "components/drive/event_logger.h"
-#include "components/drive/file_change.h"
-#include "components/drive/file_system_core_util.h"
-#include "components/drive/job_scheduler.h"
-#include "google_apis/drive/drive_api_parser.h"
-#include "url/gurl.h"
-
-namespace drive {
-namespace internal {
-
-typedef base::Callback<void(FileError,
-                            std::vector<std::unique_ptr<ChangeList>>)>
-    FeedFetcherCallback;
-
-class ChangeListLoader::FeedFetcher {
- public:
-  virtual ~FeedFetcher() = default;
-  virtual void Run(const FeedFetcherCallback& callback) = 0;
-};
-
-namespace {
-
-constexpr char kDefaultCorpusMsg[] = "default corpus";
-
-// Fetches all the (currently available) resource entries from the server.
-class FullFeedFetcher : public ChangeListLoader::FeedFetcher {
- public:
-  FullFeedFetcher(JobScheduler* scheduler, const std::string& team_drive_id)
-      : scheduler_(scheduler), team_drive_id_(team_drive_id) {}
-
-  ~FullFeedFetcher() override = default;
-
-  void Run(const FeedFetcherCallback& callback) override {
-    DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-    DCHECK(callback);
-
-    // Remember the time stamp for usage stats.
-    start_time_ = base::TimeTicks::Now();
-    // This is full resource list fetch.
-    //
-    // NOTE: Because we already know the largest change ID, here we can use
-    // files.list instead of changes.list for speed. crbug.com/287602
-    scheduler_->GetAllFileList(
-        team_drive_id_, base::Bind(&FullFeedFetcher::OnFileListFetched,
-                                   weak_ptr_factory_.GetWeakPtr(), callback));
-  }
-
- private:
-  void OnFileListFetched(const FeedFetcherCallback& callback,
-                         google_apis::DriveApiErrorCode status,
-                         std::unique_ptr<google_apis::FileList> file_list) {
-    DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-    DCHECK(callback);
-
-    FileError error = GDataToFileError(status);
-    if (error != FILE_ERROR_OK) {
-      callback.Run(error, std::vector<std::unique_ptr<ChangeList>>());
-      return;
-    }
-
-    DCHECK(file_list);
-    change_lists_.push_back(std::make_unique<ChangeList>(*file_list));
-
-    if (!file_list->next_link().is_empty()) {
-      // There is the remaining result so fetch it.
-      scheduler_->GetRemainingFileList(
-          file_list->next_link(),
-          base::Bind(&FullFeedFetcher::OnFileListFetched,
-                     weak_ptr_factory_.GetWeakPtr(), callback));
-      return;
-    }
-
-    base::TimeDelta duration = base::TimeTicks::Now() - start_time_;
-    if (team_drive_id_.empty()) {
-      UMA_HISTOGRAM_LONG_TIMES("Drive.FullFeedLoadTime", duration);
-    } else {
-      UMA_HISTOGRAM_LONG_TIMES("Drive.FullFeedLoadTime.TeamDrives", duration);
-    }
-
-    // Note: The fetcher is managed by ChangeListLoader, and the instance
-    // will be deleted in the callback. Do not touch the fields after this
-    // invocation.
-    callback.Run(FILE_ERROR_OK, std::move(change_lists_));
-  }
-
-  JobScheduler* scheduler_;
-  const std::string team_drive_id_;
-  std::vector<std::unique_ptr<ChangeList>> change_lists_;
-  base::TimeTicks start_time_;
-  THREAD_CHECKER(thread_checker_);
-  base::WeakPtrFactory<FullFeedFetcher> weak_ptr_factory_{this};
-  DISALLOW_COPY_AND_ASSIGN(FullFeedFetcher);
-};
-
-// Fetches the delta changes since |start_change_id|.
-class DeltaFeedFetcher : public ChangeListLoader::FeedFetcher {
- public:
-  DeltaFeedFetcher(JobScheduler* scheduler,
-                   const std::string& team_drive_id,
-                   const std::string& start_page_token)
-      : scheduler_(scheduler),
-        team_drive_id_(team_drive_id),
-        start_page_token_(start_page_token) {}
-
-  ~DeltaFeedFetcher() override = default;
-
-  void Run(const FeedFetcherCallback& callback) override {
-    DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-    DCHECK(callback);
-
-    // Remember the time stamp for usage stats.
-    start_time_ = base::TimeTicks::Now();
-
-    scheduler_->GetChangeList(
-        team_drive_id_, start_page_token_,
-        base::Bind(&DeltaFeedFetcher::OnChangeListFetched,
-                   weak_ptr_factory_.GetWeakPtr(), callback));
-  }
-
- private:
-  void OnChangeListFetched(
-      const FeedFetcherCallback& callback,
-      google_apis::DriveApiErrorCode status,
-      std::unique_ptr<google_apis::ChangeList> change_list) {
-    DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-    DCHECK(callback);
-
-    FileError error = GDataToFileError(status);
-    if (error != FILE_ERROR_OK) {
-      callback.Run(error, std::vector<std::unique_ptr<ChangeList>>());
-      return;
-    }
-
-    DCHECK(change_list);
-    change_lists_.push_back(std::make_unique<ChangeList>(*change_list));
-
-    if (!change_list->next_link().is_empty()) {
-      // There is the remaining result so fetch it.
-      scheduler_->GetRemainingChangeList(
-          change_list->next_link(),
-          base::Bind(&DeltaFeedFetcher::OnChangeListFetched,
-                     weak_ptr_factory_.GetWeakPtr(), callback));
-      return;
-    }
-
-    base::TimeDelta duration = base::TimeTicks::Now() - start_time_;
-    if (team_drive_id_.empty()) {
-      UMA_HISTOGRAM_LONG_TIMES("Drive.DeltaFeedLoadTime", duration);
-    } else {
-      UMA_HISTOGRAM_LONG_TIMES("Drive.DeltaFeedLoadTime.TeamDrives", duration);
-    }
-
-    // Note: The fetcher is managed by ChangeListLoader, and the instance
-    // will be deleted in the callback. Do not touch the fields after this
-    // invocation.
-    callback.Run(FILE_ERROR_OK, std::move(change_lists_));
-  }
-
-  JobScheduler* scheduler_;
-  const std::string team_drive_id_;
-  const std::string start_page_token_;
-  std::vector<std::unique_ptr<ChangeList>> change_lists_;
-  base::TimeTicks start_time_;
-  THREAD_CHECKER(thread_checker_);
-  base::WeakPtrFactory<DeltaFeedFetcher> weak_ptr_factory_{this};
-  DISALLOW_COPY_AND_ASSIGN(DeltaFeedFetcher);
-};
-
-}  // namespace
-
-ChangeListLoader::ChangeListLoader(
-    EventLogger* logger,
-    base::SequencedTaskRunner* blocking_task_runner,
-    ResourceMetadata* resource_metadata,
-    JobScheduler* scheduler,
-    RootFolderIdLoader* root_folder_id_loader,
-    StartPageTokenLoader* start_page_token_loader,
-    LoaderController* loader_controller,
-    const std::string& team_drive_id,
-    const base::FilePath& root_entry_path)
-    : logger_(logger),
-      blocking_task_runner_(blocking_task_runner),
-      in_shutdown_(new base::AtomicFlag),
-      resource_metadata_(resource_metadata),
-      scheduler_(scheduler),
-      root_folder_id_loader_(root_folder_id_loader),
-      start_page_token_loader_(start_page_token_loader),
-      loader_controller_(loader_controller),
-      loaded_(false),
-      team_drive_id_(team_drive_id),
-      team_drive_msg_(team_drive_id_.empty()
-                          ? kDefaultCorpusMsg
-                          : base::StrCat({"team drive id: ", team_drive_id_})),
-      root_entry_path_(root_entry_path) {}
-
-ChangeListLoader::~ChangeListLoader() {
-  in_shutdown_->Set();
-  // Delete |in_shutdown_| with the blocking task runner so that it gets deleted
-  // after all active ChangeListProcessors.
-  blocking_task_runner_->DeleteSoon(FROM_HERE, in_shutdown_.release());
-}
-
-bool ChangeListLoader::IsRefreshing() const {
-  // Callback for change list loading is stored in pending_load_callback_.
-  // It is non-empty if and only if there is an in-flight loading operation.
-  return !pending_load_callback_.empty();
-}
-
-void ChangeListLoader::AddObserver(ChangeListLoaderObserver* observer) {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-  observers_.AddObserver(observer);
-}
-
-void ChangeListLoader::RemoveObserver(ChangeListLoaderObserver* observer) {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-  observers_.RemoveObserver(observer);
-}
-
-void ChangeListLoader::CheckForUpdates(const FileOperationCallback& callback) {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-  DCHECK(callback);
-
-  // We only start to check for updates iff the load is done.
-  // I.e., we ignore checking updates if not loaded to avoid starting the
-  // load without user's explicit interaction (such as opening Drive).
-  if (!loaded_ && !IsRefreshing())
-    return;
-
-  // For each CheckForUpdates() request, always refresh the start_page_token.
-  start_page_token_loader_->UpdateStartPageToken(
-      base::Bind(&ChangeListLoader::OnStartPageTokenLoaderUpdated,
-                 weak_ptr_factory_.GetWeakPtr()));
-
-  if (IsRefreshing()) {
-    // There is in-flight loading. So keep the callback here, and check for
-    // updates when the in-flight loading is completed.
-    pending_update_check_callback_ = callback;
-    return;
-  }
-
-  DCHECK(loaded_);
-  logger_->Log(logging::LOG_INFO, "Checking for updates (%s)",
-               team_drive_msg_.c_str());
-  Load(callback);
-}
-
-void ChangeListLoader::LoadIfNeeded(const FileOperationCallback& callback) {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-  DCHECK(callback);
-
-  // If the metadata is not yet loaded, start loading.
-  if (!loaded_ && !IsRefreshing())
-    Load(callback);
-  else
-    base::ThreadTaskRunnerHandle::Get()->PostTask(
-        FROM_HERE, base::BindOnce(callback, FILE_ERROR_OK));
-}
-
-void ChangeListLoader::Load(const FileOperationCallback& callback) {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-  DCHECK(callback);
-
-  // Check if this is the first time this ChangeListLoader do loading.
-  // Note: IsRefreshing() depends on pending_load_callback_ so check in advance.
-  const bool is_initial_load = (!loaded_ && !IsRefreshing());
-
-  // Register the callback function to be called when it is loaded.
-  pending_load_callback_.push_back(callback);
-
-  // If loading task is already running, do nothing.
-  if (pending_load_callback_.size() > 1)
-    return;
-
-  // Check the current status of local metadata, and start loading if needed.
-  std::string* start_page_token = new std::string();
-  base::PostTaskAndReplyWithResult(
-      blocking_task_runner_.get(), FROM_HERE,
-      base::Bind(&GetStartPageToken, base::Unretained(resource_metadata_),
-                 team_drive_id_, start_page_token),
-      base::Bind(&ChangeListLoader::LoadAfterGetLocalStartPageToken,
-                 weak_ptr_factory_.GetWeakPtr(), is_initial_load,
-                 base::Owned(start_page_token)));
-}
-
-void ChangeListLoader::LoadAfterGetLocalStartPageToken(
-    bool is_initial_load,
-    const std::string* local_start_page_token,
-    FileError error) {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-  DCHECK(local_start_page_token);
-
-  if (error != FILE_ERROR_OK) {
-    OnChangeListLoadComplete(error);
-    return;
-  }
-
-  if (is_initial_load && !local_start_page_token->empty()) {
-    // The local data is usable. Flush callbacks to tell loading was successful.
-    OnChangeListLoadComplete(FILE_ERROR_OK);
-
-    // Continues to load from server in background.
-    // Put dummy callbacks to indicate that fetching is still continuing.
-    pending_load_callback_.push_back(base::DoNothing());
-  }
-
-  root_folder_id_loader_->GetRootFolderId(
-      base::Bind(&ChangeListLoader::LoadAfterGetRootFolderId,
-                 weak_ptr_factory_.GetWeakPtr(), *local_start_page_token));
-}
-
-void ChangeListLoader::LoadAfterGetRootFolderId(
-    const std::string& local_start_page_token,
-    FileError error,
-    base::Optional<std::string> root_folder_id) {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-  DCHECK(!change_feed_fetcher_);
-
-  if (error != FILE_ERROR_OK) {
-    OnChangeListLoadComplete(error);
-    return;
-  }
-
-  DCHECK(root_folder_id);
-
-  start_page_token_loader_->GetStartPageToken(
-      base::Bind(&ChangeListLoader::LoadAfterGetStartPageToken,
-                 weak_ptr_factory_.GetWeakPtr(), local_start_page_token,
-                 std::move(root_folder_id.value())));
-}
-
-void ChangeListLoader::LoadAfterGetStartPageToken(
-    const std::string& local_start_page_token,
-    const std::string& root_folder_id,
-    google_apis::DriveApiErrorCode status,
-    std::unique_ptr<google_apis::StartPageToken> start_page_token) {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-
-  FileError error = GDataToFileError(status);
-  if (error != FILE_ERROR_OK) {
-    OnChangeListLoadComplete(error);
-    return;
-  }
-
-  DCHECK(start_page_token);
-
-  LoadChangeListFromServer(start_page_token->start_page_token(),
-                           local_start_page_token, root_folder_id);
-}
-
-void ChangeListLoader::OnChangeListLoadComplete(FileError error) {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-
-  if (!loaded_ && error == FILE_ERROR_OK) {
-    loaded_ = true;
-    for (auto& observer : observers_)
-      observer.OnInitialLoadComplete();
-  }
-
-  for (auto& callback : pending_load_callback_) {
-    base::ThreadTaskRunnerHandle::Get()->PostTask(
-        FROM_HERE, base::BindOnce(callback, error));
-  }
-  pending_load_callback_.clear();
-
-  // If there is pending update check, try to load the change from the server
-  // again, because there may exist an update during the completed loading.
-  if (pending_update_check_callback_) {
-    auto cb = std::move(pending_update_check_callback_);
-    // TODO(dcheng): Rewrite this to use OnceCallback. Load() currently takes a
-    // callback by const ref, so std::move() won't do anything. :(
-    Load(cb);
-  }
-}
-
-void ChangeListLoader::OnStartPageTokenLoaderUpdated(
-    google_apis::DriveApiErrorCode error,
-    std::unique_ptr<google_apis::StartPageToken> start_page_token) {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-
-  if (drive::GDataToFileError(error) != drive::FILE_ERROR_OK) {
-    logger_->Log(logging::LOG_ERROR,
-                 "Failed to update the start page token (%s) (Error: %s)",
-                 team_drive_msg_.c_str(),
-                 google_apis::DriveApiErrorCodeToString(error).c_str());
-    return;
-  }
-  logger_->Log(logging::LOG_INFO, "Start page token updated (%s) (value: %s)",
-               team_drive_msg_.c_str(),
-               start_page_token->start_page_token().c_str());
-}
-
-void ChangeListLoader::LoadChangeListFromServer(
-    const std::string& remote_start_page_token,
-    const std::string& local_start_page_token,
-    const std::string& root_resource_id) {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-
-  if (local_start_page_token == remote_start_page_token) {
-    // No changes detected, tell the client that the loading was successful.
-    OnChangeListLoadComplete(FILE_ERROR_OK);
-    return;
-  }
-
-  // Set up feed fetcher.
-  bool is_delta_update = !local_start_page_token.empty();
-  if (is_delta_update) {
-    change_feed_fetcher_ = std::make_unique<DeltaFeedFetcher>(
-        scheduler_, team_drive_id_, local_start_page_token);
-  } else {
-    change_feed_fetcher_ =
-        std::make_unique<FullFeedFetcher>(scheduler_, team_drive_id_);
-  }
-
-  change_feed_fetcher_->Run(
-      base::Bind(&ChangeListLoader::LoadChangeListFromServerAfterLoadChangeList,
-                 weak_ptr_factory_.GetWeakPtr(), remote_start_page_token,
-                 root_resource_id, is_delta_update));
-}
-
-void ChangeListLoader::LoadChangeListFromServerAfterLoadChangeList(
-    const std::string& start_page_token,
-    const std::string& root_resource_id,
-    bool is_delta_update,
-    FileError error,
-    std::vector<std::unique_ptr<ChangeList>> change_lists) {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-
-  // Delete the fetcher first.
-  change_feed_fetcher_.reset();
-
-  if (error != FILE_ERROR_OK) {
-    OnChangeListLoadComplete(error);
-    return;
-  }
-
-  ChangeListProcessor* change_list_processor = new ChangeListProcessor(
-      team_drive_id_, root_entry_path_, resource_metadata_, in_shutdown_.get());
-  // Don't send directory content change notification while performing
-  // the initial content retrieval.
-  const bool should_notify_changed_directories = is_delta_update;
-
-  logger_->Log(logging::LOG_INFO, "Apply change lists (%s) (is delta: %d)",
-               team_drive_msg_.c_str(), is_delta_update);
-  loader_controller_->ScheduleRun(base::BindOnce(
-      &drive::util::RunAsyncTask, base::RetainedRef(blocking_task_runner_),
-      FROM_HERE,
-      base::BindOnce(&ChangeListProcessor::ApplyUserChangeList,
-                     base::Unretained(change_list_processor), start_page_token,
-                     root_resource_id, std::move(change_lists),
-                     is_delta_update),
-      base::BindOnce(&ChangeListLoader::LoadChangeListFromServerAfterUpdate,
-                     weak_ptr_factory_.GetWeakPtr(),
-                     base::Owned(change_list_processor),
-                     should_notify_changed_directories, base::Time::Now())));
-}
-
-void ChangeListLoader::LoadChangeListFromServerAfterUpdate(
-    ChangeListProcessor* change_list_processor,
-    bool should_notify_changed_directories,
-    base::Time start_time,
-    FileError error) {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-
-  const base::TimeDelta elapsed = base::Time::Now() - start_time;
-  logger_->Log(logging::LOG_INFO,
-               "Change lists applied (%s) (elapsed time: %sms)",
-               team_drive_msg_.c_str(),
-               base::NumberToString(elapsed.InMilliseconds()).c_str());
-
-  if (should_notify_changed_directories) {
-    for (auto& observer : observers_)
-      observer.OnFileChanged(change_list_processor->changed_files());
-  }
-
-  if (!change_list_processor->changed_team_drives().empty()) {
-    for (auto& observer : observers_) {
-      observer.OnTeamDrivesChanged(
-          change_list_processor->changed_team_drives());
-    }
-  }
-
-  OnChangeListLoadComplete(error);
-
-  for (auto& observer : observers_)
-    observer.OnLoadFromServerComplete();
-}
-
-}  // namespace internal
-}  // namespace drive
diff --git a/components/drive/chromeos/change_list_loader.h b/components/drive/chromeos/change_list_loader.h
deleted file mode 100644
index 1362052d..0000000
--- a/components/drive/chromeos/change_list_loader.h
+++ /dev/null
@@ -1,198 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef COMPONENTS_DRIVE_CHROMEOS_CHANGE_LIST_LOADER_H_
-#define COMPONENTS_DRIVE_CHROMEOS_CHANGE_LIST_LOADER_H_
-
-#include <stdint.h>
-
-#include <memory>
-#include <string>
-#include <vector>
-
-#include "base/callback.h"
-#include "base/macros.h"
-#include "base/memory/ref_counted.h"
-#include "base/observer_list.h"
-#include "base/threading/thread_checker.h"
-#include "components/drive/file_errors.h"
-#include "google_apis/drive/drive_api_error_codes.h"
-#include "google_apis/drive/drive_common_callbacks.h"
-
-namespace base {
-class AtomicFlag;
-class SequencedTaskRunner;
-class Time;
-}  // namespace base
-
-namespace google_apis {
-class StartPageToken;
-}  // namespace google_apis
-
-namespace drive {
-
-class EventLogger;
-class JobScheduler;
-
-namespace internal {
-
-class RootFolderIdLoader;
-class ChangeList;
-class ChangeListLoaderObserver;
-class ChangeListProcessor;
-class LoaderController;
-class ResourceMetadata;
-class StartPageTokenLoader;
-
-// ChangeListLoader is used to load the change list, the full resource list,
-// and directory contents, from Google Drive API.  The class also updates the
-// resource metadata with the change list loaded from the server.
-//
-// Note that the difference between "resource list" and "change list" is
-// subtle hence the two words are often used interchangeably. To be precise,
-// "resource list" refers to metadata from the server when fetching the full
-// resource metadata, or fetching directory contents, whereas "change list"
-// refers to metadata from the server when fetching changes (delta).
-class ChangeListLoader {
- public:
-  // Resource feed fetcher from the server.
-  class FeedFetcher;
-
-  ChangeListLoader(EventLogger* logger,
-                   base::SequencedTaskRunner* blocking_task_runner,
-                   ResourceMetadata* resource_metadata,
-                   JobScheduler* scheduler,
-                   RootFolderIdLoader* root_folder_id_loader,
-                   StartPageTokenLoader* start_page_token_loader,
-                   LoaderController* apply_task_controller,
-                   const std::string& team_drive_id,
-                   const base::FilePath& root_entry_path);
-  ~ChangeListLoader();
-
-  // Indicates whether there is a request for full resource list or change
-  // list fetching is in flight (i.e. directory contents fetching does not
-  // count).
-  bool IsRefreshing() const;
-
-  // Adds and removes the observer.
-  void AddObserver(ChangeListLoaderObserver* observer);
-  void RemoveObserver(ChangeListLoaderObserver* observer);
-
-  // Checks for updates on the server. Does nothing if the change list is now
-  // being loaded or refreshed. |callback| must not be null.
-  // Note: |callback| will be called if the check for updates actually
-  // runs, i.e. it may NOT be called if the checking is ignored.
-  void CheckForUpdates(const FileOperationCallback& callback);
-
-  // Starts the change list loading if needed. If the locally stored metadata is
-  // available, runs |callback| immediately and starts checking server for
-  // updates in background. If the locally stored metadata is not available,
-  // starts loading from the server, and runs |callback| to tell the result to
-  // the caller when it is finished.
-  //
-  // |callback| must not be null.
-  void LoadIfNeeded(const FileOperationCallback& callback);
-
- private:
-  // Starts the resource metadata loading and calls |callback| when it's done.
-  void Load(const FileOperationCallback& callback);
-  void LoadAfterGetLocalStartPageToken(
-      bool is_initial_load,
-      const std::string* local_start_page_token,
-      FileError error);
-  void LoadAfterGetRootFolderId(const std::string& local_start_page_token,
-                                FileError error,
-                                base::Optional<std::string> root_folder_id);
-
-  void LoadAfterGetStartPageToken(
-      const std::string& local_start_page_token,
-      const std::string& root_folder_id,
-      google_apis::DriveApiErrorCode status,
-      std::unique_ptr<google_apis::StartPageToken> start_page_token);
-
-  // Part of Load().
-  // This function should be called when the change list load is complete.
-  // Flushes the callbacks for change list loading and all directory loading.
-  void OnChangeListLoadComplete(FileError error);
-
-  // Called when loading the start page token is completed.
-  void OnStartPageTokenLoaderUpdated(
-      google_apis::DriveApiErrorCode error,
-      std::unique_ptr<google_apis::StartPageToken> start_page_token);
-
-  // ================= Implementation for change list loading =================
-
-  // Part of LoadFromServerIfNeeded().
-  // Starts loading the change list since |local_start_page_token|, or the full
-  // resource list if |local_start_page_token| is empty. If there's no changes
-  // since then, and there are no new team drives changes to apply from
-  // team_drives_change_lists, finishes early.
-  // TODO(sashab): Currently, team_drives_change_lists always contains all of
-  // the team drives. Update this so team_drives_change_lists is only filled
-  // when the TD flag is newly turned on or local data cleared. crbug.com/829154
-  void LoadChangeListFromServer(const std::string& remote_start_page_token,
-                                const std::string& local_start_page_token,
-                                const std::string& root_resource_id);
-
-  // Part of LoadChangeListFromServer().
-  // Called when the entire change list is loaded.
-  void LoadChangeListFromServerAfterLoadChangeList(
-      const std::string& start_page_token,
-      const std::string& root_resource_id,
-      bool is_delta_update,
-      FileError error,
-      std::vector<std::unique_ptr<ChangeList>> change_lists);
-
-  // Part of LoadChangeListFromServer().
-  // Called when the resource metadata is updated.
-  void LoadChangeListFromServerAfterUpdate(
-      ChangeListProcessor* change_list_processor,
-      bool should_notify_changed_directories,
-      base::Time start_time,
-      FileError error);
-
-  EventLogger* logger_;  // Not owned.
-  scoped_refptr<base::SequencedTaskRunner> blocking_task_runner_;
-  std::unique_ptr<base::AtomicFlag> in_shutdown_;
-  ResourceMetadata* resource_metadata_;  // Not owned.
-  JobScheduler* scheduler_;  // Not owned.
-  RootFolderIdLoader* root_folder_id_loader_;      // Not owned.
-  StartPageTokenLoader* start_page_token_loader_;  // Not owned.
-  LoaderController* loader_controller_;  // Not owned.
-  base::ObserverList<ChangeListLoaderObserver>::Unchecked observers_;
-  std::vector<FileOperationCallback> pending_load_callback_;
-  FileOperationCallback pending_update_check_callback_;
-
-  // Running feed fetcher.
-  // TODO(slangley): Do not make this stateful by changing the feed_fetcher
-  // to be base::Owned by the callback.
-  std::unique_ptr<FeedFetcher> change_feed_fetcher_;
-
-  // True if the full resource list is loaded (i.e. the resource metadata is
-  // stored locally).
-  bool loaded_;
-
-  // The team drive id for the changes being loaded by this change list loader.
-  const std::string team_drive_id_;
-
-  // The formatted team drive id message used for logging.
-  const std::string team_drive_msg_;
-
-  // The root entry path for changes being loaded by this change list loader.
-  // Can be a team drive root entry or for the users default corpus will be the
-  // drive root entry.
-  const base::FilePath root_entry_path_;
-
-  THREAD_CHECKER(thread_checker_);
-
-  // Note: This should remain the last member so it'll be destroyed and
-  // invalidate its weak pointers before any other members are destroyed.
-  base::WeakPtrFactory<ChangeListLoader> weak_ptr_factory_{this};
-  DISALLOW_COPY_AND_ASSIGN(ChangeListLoader);
-};
-
-}  // namespace internal
-}  // namespace drive
-
-#endif  // COMPONENTS_DRIVE_CHROMEOS_CHANGE_LIST_LOADER_H_
diff --git a/components/drive/chromeos/change_list_loader_observer.h b/components/drive/chromeos/change_list_loader_observer.h
deleted file mode 100644
index bfbc69e..0000000
--- a/components/drive/chromeos/change_list_loader_observer.h
+++ /dev/null
@@ -1,47 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef COMPONENTS_DRIVE_CHROMEOS_CHANGE_LIST_LOADER_OBSERVER_H_
-#define COMPONENTS_DRIVE_CHROMEOS_CHANGE_LIST_LOADER_OBSERVER_H_
-
-namespace base {
-class FilePath;
-}  // namespace base
-
-namespace drive {
-class FileChange;
-namespace internal {
-
-// Interface for classes that need to observe events from ChangeListLoader.
-// All events are notified on UI thread.
-class ChangeListLoaderObserver {
- public:
-  // Triggered when the content of a directory is reloaded. The content may
-  // changed.  |directory_path| is a virtual directory path representing the
-  // reloaded directory.
-  virtual void OnDirectoryReloaded(const base::FilePath& directory_path) {}
-
-  // Triggered when content(s) in drive has been changed.
-  virtual void OnFileChanged(const FileChange& changed_files) {}
-
-  // Triggered when the users accessible team drives has changed.
-  virtual void OnTeamDrivesChanged(const FileChange& changed_team_drives) {}
-
-  // Triggered when loading from the server is complete.
-  virtual void OnLoadFromServerComplete() {}
-
-  // Triggered when loading is complete for the first time, either from the
-  // the server or the cache. To be precise, for the latter case, we do not
-  // load anything from the cache. We just check that the resource metadata
-  // is stored locally thus can be used.
-  virtual void OnInitialLoadComplete() {}
-
- protected:
-  virtual ~ChangeListLoaderObserver() = default;
-};
-
-}  // namespace internal
-}  // namespace drive
-
-#endif  // COMPONENTS_DRIVE_CHROMEOS_CHANGE_LIST_LOADER_OBSERVER_H_
diff --git a/components/drive/chromeos/default_corpus_change_list_loader.cc b/components/drive/chromeos/default_corpus_change_list_loader.cc
deleted file mode 100644
index 79b10320..0000000
--- a/components/drive/chromeos/default_corpus_change_list_loader.cc
+++ /dev/null
@@ -1,131 +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/drive/chromeos/default_corpus_change_list_loader.h"
-
-#include <memory>
-
-#include "base/bind.h"
-#include "base/bind_helpers.h"
-#include "base/time/clock.h"
-#include "components/drive/chromeos/about_resource_root_folder_id_loader.h"
-#include "components/drive/file_system_core_util.h"
-
-namespace drive {
-namespace internal {
-
-DefaultCorpusChangeListLoader::DefaultCorpusChangeListLoader(
-    EventLogger* logger,
-    base::SequencedTaskRunner* blocking_task_runner,
-    ResourceMetadata* resource_metadata,
-    JobScheduler* scheduler,
-    AboutResourceLoader* about_resource_loader,
-    LoaderController* apply_task_controller,
-    const base::Clock* clock)
-    : logger_(logger),
-      blocking_task_runner_(blocking_task_runner),
-      resource_metadata_(resource_metadata),
-      scheduler_(scheduler),
-      loader_controller_(apply_task_controller) {
-  DCHECK(clock);
-
-  root_folder_id_loader_ =
-      std::make_unique<AboutResourceRootFolderIdLoader>(about_resource_loader);
-
-  start_page_token_loader_ = std::make_unique<StartPageTokenLoader>(
-      util::kTeamDriveIdDefaultCorpus, scheduler_);
-
-  change_list_loader_ = std::make_unique<ChangeListLoader>(
-      logger_, blocking_task_runner_.get(), resource_metadata_, scheduler_,
-      root_folder_id_loader_.get(), start_page_token_loader_.get(),
-      loader_controller_, util::kTeamDriveIdDefaultCorpus,
-      util::GetDriveMyDriveRootPath());
-
-  directory_loader_ = std::make_unique<DirectoryLoader>(
-      logger_, blocking_task_runner_.get(), resource_metadata_, scheduler_,
-      root_folder_id_loader_.get(), start_page_token_loader_.get(),
-      loader_controller_, util::GetDriveMyDriveRootPath(),
-      util::kTeamDriveIdDefaultCorpus, clock);
-
-  team_drive_list_loader_ = std::make_unique<TeamDriveListLoader>(
-      logger_, blocking_task_runner_.get(), resource_metadata, scheduler_,
-      loader_controller_);
-}
-
-DefaultCorpusChangeListLoader::~DefaultCorpusChangeListLoader() = default;
-
-void DefaultCorpusChangeListLoader::AddChangeListLoaderObserver(
-    ChangeListLoaderObserver* observer) {
-  change_list_loader_->AddObserver(observer);
-  directory_loader_->AddObserver(observer);
-}
-
-void DefaultCorpusChangeListLoader::RemoveChangeListLoaderObserver(
-    ChangeListLoaderObserver* observer) {
-  change_list_loader_->RemoveObserver(observer);
-  directory_loader_->RemoveObserver(observer);
-}
-
-void DefaultCorpusChangeListLoader::AddTeamDriveListObserver(
-    TeamDriveListObserver* observer) {
-  team_drive_list_loader_->AddObserver(observer);
-}
-
-void DefaultCorpusChangeListLoader::RemoveTeamDriveListObserver(
-    TeamDriveListObserver* observer) {
-  team_drive_list_loader_->RemoveObserver(observer);
-}
-
-bool DefaultCorpusChangeListLoader::IsRefreshing() {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-  return team_drive_list_loader_->IsRefreshing() ||
-         change_list_loader_->IsRefreshing();
-}
-
-void DefaultCorpusChangeListLoader::LoadIfNeeded(
-    const FileOperationCallback& callback) {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-  // We execute the change list loader and then the team drive loader when it
-  // is completed. If the change list loader detects that it has previously
-  // loaded from the server, then it is a no-op. If it is a fresh load then it
-  // uses GetAllFiles which does not read any change lists with team drive info.
-  change_list_loader_->LoadIfNeeded(base::BindRepeating(
-      &DefaultCorpusChangeListLoader::OnChangeListLoadIfNeeded,
-      weak_ptr_factory_.GetWeakPtr(), callback));
-}
-
-void DefaultCorpusChangeListLoader::OnChangeListLoadIfNeeded(
-    const FileOperationCallback& callback,
-    FileError error) {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-
-  if (error != FILE_ERROR_OK) {
-    callback.Run(error);
-    return;
-  }
-
-  team_drive_list_loader_->LoadIfNeeded(callback);
-}
-
-void DefaultCorpusChangeListLoader::ReadDirectory(
-    const base::FilePath& directory_path,
-    ReadDirectoryEntriesCallback entries_callback,
-    const FileOperationCallback& completion_callback) {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-
-  directory_loader_->ReadDirectory(directory_path, std::move(entries_callback),
-                                   completion_callback);
-
-  // Also start loading all of the user's contents.
-  LoadIfNeeded(base::DoNothing());
-}
-
-void DefaultCorpusChangeListLoader::CheckForUpdates(
-    const FileOperationCallback& callback) {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-  change_list_loader_->CheckForUpdates(callback);
-}
-
-}  // namespace internal
-}  // namespace drive
diff --git a/components/drive/chromeos/default_corpus_change_list_loader.h b/components/drive/chromeos/default_corpus_change_list_loader.h
deleted file mode 100644
index 6bc15c9..0000000
--- a/components/drive/chromeos/default_corpus_change_list_loader.h
+++ /dev/null
@@ -1,90 +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_DRIVE_CHROMEOS_DEFAULT_CORPUS_CHANGE_LIST_LOADER_H_
-#define COMPONENTS_DRIVE_CHROMEOS_DEFAULT_CORPUS_CHANGE_LIST_LOADER_H_
-
-#include <memory>
-
-#include "base/macros.h"
-#include "base/memory/weak_ptr.h"
-#include "base/time/default_clock.h"
-#include "components/drive/chromeos/about_resource_root_folder_id_loader.h"
-#include "components/drive/chromeos/change_list_loader.h"
-#include "components/drive/chromeos/directory_loader.h"
-#include "components/drive/chromeos/drive_change_list_loader.h"
-#include "components/drive/chromeos/start_page_token_loader.h"
-#include "components/drive/chromeos/team_drive_list_loader.h"
-
-namespace drive {
-
-class EventLogger;
-class JobScheduler;
-
-namespace internal {
-
-class AboutResourceLoader;
-class ChangeListLoader;
-class DirectoryLoader;
-class LoaderController;
-class ResourceMetadata;
-
-// Loads change lists, the full resource list, and directory contents for the
-// users default corpus.
-class DefaultCorpusChangeListLoader : public DriveChangeListLoader {
- public:
-  // |clock| can be mocked for testing.
-  DefaultCorpusChangeListLoader(
-      EventLogger* logger,
-      base::SequencedTaskRunner* blocking_task_runner,
-      ResourceMetadata* resource_metadata,
-      JobScheduler* scheduler,
-      AboutResourceLoader* about_resource_loader,
-      LoaderController* apply_task_controller,
-      const base::Clock* clock = base::DefaultClock::GetInstance());
-
-  ~DefaultCorpusChangeListLoader() override;
-
-  // DriveChangeListLoader overrides
-  void AddChangeListLoaderObserver(ChangeListLoaderObserver* observer) override;
-  void RemoveChangeListLoaderObserver(
-      ChangeListLoaderObserver* observer) override;
-  void AddTeamDriveListObserver(TeamDriveListObserver* observer) override;
-  void RemoveTeamDriveListObserver(TeamDriveListObserver* observer) override;
-
-  bool IsRefreshing() override;
-  void LoadIfNeeded(const FileOperationCallback& callback) override;
-  void ReadDirectory(const base::FilePath& directory_path,
-                     ReadDirectoryEntriesCallback entries_callback,
-                     const FileOperationCallback& completion_callback) override;
-  void CheckForUpdates(const FileOperationCallback& callback) override;
-
- private:
-  // Called after calling LoadIfNeeded on team drives.
-  void OnChangeListLoadIfNeeded(const FileOperationCallback& callback,
-                                FileError error);
-
-  std::unique_ptr<internal::AboutResourceRootFolderIdLoader>
-      root_folder_id_loader_;
-  std::unique_ptr<internal::ChangeListLoader> change_list_loader_;
-  std::unique_ptr<internal::DirectoryLoader> directory_loader_;
-  std::unique_ptr<internal::StartPageTokenLoader> start_page_token_loader_;
-  std::unique_ptr<TeamDriveListLoader> team_drive_list_loader_;
-
-  EventLogger* logger_;  // Not owned.
-  scoped_refptr<base::SequencedTaskRunner> blocking_task_runner_;
-  ResourceMetadata* resource_metadata_;         // Not owned.
-  JobScheduler* scheduler_;                     // Not owned.
-  LoaderController* loader_controller_;         // Not owned.
-
-  THREAD_CHECKER(thread_checker_);
-
-  base::WeakPtrFactory<DefaultCorpusChangeListLoader> weak_ptr_factory_{this};
-  DISALLOW_COPY_AND_ASSIGN(DefaultCorpusChangeListLoader);
-};
-
-}  // namespace internal
-}  // namespace drive
-
-#endif  // COMPONENTS_DRIVE_CHROMEOS_DEFAULT_CORPUS_CHANGE_LIST_LOADER_H_
diff --git a/components/drive/chromeos/directory_loader.cc b/components/drive/chromeos/directory_loader.cc
deleted file mode 100644
index 383624624..0000000
--- a/components/drive/chromeos/directory_loader.cc
+++ /dev/null
@@ -1,656 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "components/drive/chromeos/directory_loader.h"
-
-#include <stddef.h>
-
-#include <utility>
-
-#include "base/bind.h"
-#include "base/callback.h"
-#include "base/callback_helpers.h"
-#include "base/macros.h"
-#include "base/memory/ptr_util.h"
-#include "base/metrics/histogram_macros.h"
-#include "base/strings/string_number_conversions.h"
-#include "base/time/clock.h"
-#include "base/time/time.h"
-#include "components/drive/chromeos/change_list_loader_observer.h"
-#include "components/drive/chromeos/change_list_processor.h"
-#include "components/drive/chromeos/drive_file_util.h"
-#include "components/drive/chromeos/loader_controller.h"
-#include "components/drive/chromeos/resource_metadata.h"
-#include "components/drive/chromeos/root_folder_id_loader.h"
-#include "components/drive/chromeos/start_page_token_loader.h"
-#include "components/drive/drive_api_util.h"
-#include "components/drive/event_logger.h"
-#include "components/drive/file_system_core_util.h"
-#include "components/drive/job_scheduler.h"
-#include "google_apis/drive/drive_api_parser.h"
-#include "url/gurl.h"
-
-namespace drive {
-namespace internal {
-
-namespace {
-
-// Minimum changestamp gap required to start loading directory.
-constexpr int kMinimumChangestampGap = 50;
-
-constexpr base::TimeDelta kMinimumPerDirectoryFetchTimeGap =
-    base::TimeDelta::FromSeconds(30);
-
-FileError CheckLocalState(ResourceMetadata* resource_metadata,
-                          const base::FilePath& root_entry_path,
-                          const std::string& team_drive_id,
-                          const std::string& root_folder_id,
-                          const std::string& local_id,
-                          ResourceEntry* entry,
-                          std::string* start_page_token) {
-  DCHECK(start_page_token);
-  // Fill My Drive resource ID.
-  ResourceEntry mydrive;
-  FileError error =
-      resource_metadata->GetResourceEntryByPath(root_entry_path, &mydrive);
-  if (error != FILE_ERROR_OK)
-    return error;
-
-  if (mydrive.resource_id().empty()) {
-    mydrive.set_resource_id(root_folder_id);
-    error = resource_metadata->RefreshEntry(mydrive);
-    if (error != FILE_ERROR_OK)
-      return error;
-  }
-
-  // Get entry.
-  error = resource_metadata->GetResourceEntryById(local_id, entry);
-  if (error != FILE_ERROR_OK)
-    return error;
-
-  // Get the local start page token..
-  return GetStartPageToken(resource_metadata, team_drive_id, start_page_token);
-}
-
-FileError UpdateStartPageToken(ResourceMetadata* resource_metadata,
-                               const DirectoryFetchInfo& directory_fetch_info,
-                               base::FilePath* directory_path,
-                               const base::Clock* clock) {
-  DCHECK(clock);
-  // Update the directory start page token.
-  ResourceEntry directory;
-  FileError error = resource_metadata->GetResourceEntryById(
-      directory_fetch_info.local_id(), &directory);
-  if (error != FILE_ERROR_OK)
-    return error;
-
-  if (!directory.file_info().is_directory())
-    return FILE_ERROR_NOT_A_DIRECTORY;
-
-  DirectorySpecificInfo* directory_specific_info =
-      directory.mutable_directory_specific_info();
-
-  directory_specific_info->set_start_page_token(
-      directory_fetch_info.start_page_token());
-  directory_specific_info->set_last_read_time_ms(
-      clock->Now().ToDeltaSinceWindowsEpoch().InMilliseconds());
-
-  error = resource_metadata->RefreshEntry(directory);
-  if (error != FILE_ERROR_OK)
-    return error;
-
-  // Get the directory path.
-  return resource_metadata->GetFilePath(directory_fetch_info.local_id(),
-                                        directory_path);
-}
-
-}  // namespace
-
-struct DirectoryLoader::ReadDirectoryCallbackState {
-  explicit ReadDirectoryCallbackState(
-      ReadDirectoryEntriesCallback entries_callback)
-      : entries_callback(std::move(entries_callback)) {}
-
-  ReadDirectoryEntriesCallback entries_callback;
-  FileOperationCallback completion_callback;
-  std::set<std::string> sent_entry_names;
-};
-
-// Fetches the resource entries in the directory with |directory_resource_id|.
-class DirectoryLoader::FeedFetcher {
- public:
-  FeedFetcher(DirectoryLoader* loader,
-              const DirectoryFetchInfo& directory_fetch_info,
-              const std::string& root_folder_id)
-      : loader_(loader),
-        directory_fetch_info_(directory_fetch_info),
-        root_folder_id_(root_folder_id) {}
-
-  ~FeedFetcher() = default;
-
-  void Run(const FileOperationCallback& callback) {
-    DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-    DCHECK(callback);
-    DCHECK(!directory_fetch_info_.resource_id().empty());
-
-    // Remember the time stamp for usage stats.
-    start_time_ = base::TimeTicks::Now();
-
-    loader_->scheduler_->GetFileListInDirectory(
-        directory_fetch_info_.resource_id(),
-        base::Bind(&FeedFetcher::OnFileListFetched,
-                   weak_ptr_factory_.GetWeakPtr(), callback));
-  }
-
- private:
-  void OnFileListFetched(const FileOperationCallback& callback,
-                         google_apis::DriveApiErrorCode status,
-                         std::unique_ptr<google_apis::FileList> file_list) {
-    DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-    DCHECK(callback);
-
-    FileError error = GDataToFileError(status);
-    if (error != FILE_ERROR_OK) {
-      callback.Run(error);
-      return;
-    }
-
-    DCHECK(file_list);
-    std::unique_ptr<ChangeList> change_list(new ChangeList(*file_list));
-    GURL next_url = file_list->next_link();
-
-    ResourceEntryVector* entries = new ResourceEntryVector;
-    loader_->loader_controller_->ScheduleRun(base::BindOnce(
-        &drive::util::RunAsyncTask,
-        base::RetainedRef(loader_->blocking_task_runner_), FROM_HERE,
-        base::BindOnce(&ChangeListProcessor::RefreshDirectory,
-                       loader_->resource_metadata_, directory_fetch_info_,
-                       std::move(change_list), entries),
-        base::BindOnce(&FeedFetcher::OnDirectoryRefreshed,
-                       weak_ptr_factory_.GetWeakPtr(), callback, next_url,
-                       base::Owned(entries))));
-  }
-
-  void OnDirectoryRefreshed(
-      const FileOperationCallback& callback,
-      const GURL& next_url,
-      const std::vector<ResourceEntry>* refreshed_entries,
-      FileError error) {
-    DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-    DCHECK(callback);
-
-    if (error != FILE_ERROR_OK) {
-      callback.Run(error);
-      return;
-    }
-
-    loader_->SendEntries(directory_fetch_info_.local_id(), *refreshed_entries);
-
-    if (!next_url.is_empty()) {
-      // There is the remaining result so fetch it.
-      loader_->scheduler_->GetRemainingFileList(
-          next_url,
-          base::Bind(&FeedFetcher::OnFileListFetched,
-                     weak_ptr_factory_.GetWeakPtr(), callback));
-      return;
-    }
-
-    base::TimeDelta duration = base::TimeTicks::Now() - start_time_;
-    if (util::IsTeamDrivesPath(directory_fetch_info_.root_entry_path())) {
-      UMA_HISTOGRAM_TIMES("Drive.DirectoryFeedLoadTime.TeamDrives", duration);
-    } else {
-      UMA_HISTOGRAM_TIMES("Drive.DirectoryFeedLoadTime", duration);
-    }
-
-    // Note: The fetcher is managed by DirectoryLoader, and the instance
-    // will be deleted in the callback. Do not touch the fields after this
-    // invocation.
-    callback.Run(FILE_ERROR_OK);
-  }
-
-  DirectoryLoader* loader_;
-  DirectoryFetchInfo directory_fetch_info_;
-  std::string root_folder_id_;
-  base::TimeTicks start_time_;
-  THREAD_CHECKER(thread_checker_);
-  base::WeakPtrFactory<FeedFetcher> weak_ptr_factory_{this};
-  DISALLOW_COPY_AND_ASSIGN(FeedFetcher);
-};
-
-DirectoryLoader::DirectoryLoader(
-    EventLogger* logger,
-    base::SequencedTaskRunner* blocking_task_runner,
-    ResourceMetadata* resource_metadata,
-    JobScheduler* scheduler,
-    RootFolderIdLoader* root_folder_id_loader,
-    StartPageTokenLoader* start_page_token_loader,
-    LoaderController* loader_controller,
-    const base::FilePath& root_entry_path,
-    const std::string& team_drive_id,
-    const base::Clock* clock)
-    : logger_(logger),
-      blocking_task_runner_(blocking_task_runner),
-      resource_metadata_(resource_metadata),
-      scheduler_(scheduler),
-      root_folder_id_loader_(root_folder_id_loader),
-      start_page_token_loader_(start_page_token_loader),
-      loader_controller_(loader_controller),
-      root_entry_path_(root_entry_path),
-      team_drive_id_(team_drive_id),
-      clock_(clock) {}
-
-DirectoryLoader::~DirectoryLoader() = default;
-
-void DirectoryLoader::AddObserver(ChangeListLoaderObserver* observer) {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-  observers_.AddObserver(observer);
-}
-
-void DirectoryLoader::RemoveObserver(ChangeListLoaderObserver* observer) {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-  observers_.RemoveObserver(observer);
-}
-
-void DirectoryLoader::ReadDirectory(
-    const base::FilePath& directory_path,
-    ReadDirectoryEntriesCallback entries_callback,
-    const FileOperationCallback& completion_callback) {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-  DCHECK(completion_callback);
-
-  ResourceEntry* entry = new ResourceEntry;
-  base::PostTaskAndReplyWithResult(
-      blocking_task_runner_.get(), FROM_HERE,
-      base::Bind(&ResourceMetadata::GetResourceEntryByPath,
-                 base::Unretained(resource_metadata_), directory_path, entry),
-      base::Bind(&DirectoryLoader::ReadDirectoryAfterGetEntry,
-                 weak_ptr_factory_.GetWeakPtr(), directory_path,
-                 base::Passed(std::move(entries_callback)), completion_callback,
-                 true,  // should_try_loading_parent
-                 base::Owned(entry)));
-}
-
-void DirectoryLoader::ReadDirectoryAfterGetEntry(
-    const base::FilePath& directory_path,
-    ReadDirectoryEntriesCallback entries_callback,
-    const FileOperationCallback& completion_callback,
-    bool should_try_loading_parent,
-    const ResourceEntry* entry,
-    FileError error) {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-  DCHECK(completion_callback);
-
-  if (error == FILE_ERROR_NOT_FOUND &&
-      should_try_loading_parent &&
-      util::GetDriveGrandRootPath().IsParent(directory_path)) {
-    // This entry may be found after loading the parent.
-    ReadDirectory(directory_path.DirName(), ReadDirectoryEntriesCallback(),
-                  base::Bind(&DirectoryLoader::ReadDirectoryAfterLoadParent,
-                             weak_ptr_factory_.GetWeakPtr(), directory_path,
-                             base::Passed(std::move(entries_callback)),
-                             completion_callback));
-    return;
-  }
-  if (error != FILE_ERROR_OK) {
-    completion_callback.Run(error);
-    return;
-  }
-
-  if (!entry->file_info().is_directory()) {
-    completion_callback.Run(FILE_ERROR_NOT_A_DIRECTORY);
-    return;
-  }
-
-  DirectoryFetchInfo directory_fetch_info(
-      entry->local_id(), entry->resource_id(),
-      entry->directory_specific_info().start_page_token(), root_entry_path_,
-      directory_path);
-
-  // Register the callback function to be called when it is loaded.
-  const std::string& local_id = directory_fetch_info.local_id();
-  ReadDirectoryCallbackState callback_state(std::move(entries_callback));
-  callback_state.completion_callback = completion_callback;
-  pending_load_callback_[local_id].emplace_back(std::move(callback_state));
-
-  // If loading task for |local_id| is already running, do nothing.
-  if (pending_load_callback_[local_id].size() > 1)
-    return;
-
-  root_folder_id_loader_->GetRootFolderId(
-      base::Bind(&DirectoryLoader::ReadDirectoryAfterGetRootFolderId,
-                 weak_ptr_factory_.GetWeakPtr(), directory_path, local_id));
-}
-
-void DirectoryLoader::ReadDirectoryAfterLoadParent(
-    const base::FilePath& directory_path,
-    ReadDirectoryEntriesCallback entries_callback,
-    const FileOperationCallback& completion_callback,
-    FileError error) {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-  DCHECK(completion_callback);
-
-  if (error != FILE_ERROR_OK) {
-    completion_callback.Run(error);
-    return;
-  }
-
-  ResourceEntry* entry = new ResourceEntry;
-  base::PostTaskAndReplyWithResult(
-      blocking_task_runner_.get(), FROM_HERE,
-      base::Bind(&ResourceMetadata::GetResourceEntryByPath,
-                 base::Unretained(resource_metadata_), directory_path, entry),
-      base::Bind(&DirectoryLoader::ReadDirectoryAfterGetEntry,
-                 weak_ptr_factory_.GetWeakPtr(), directory_path,
-                 base::Passed(std::move(entries_callback)), completion_callback,
-                 false,  // should_try_loading_parent
-                 base::Owned(entry)));
-}
-
-void DirectoryLoader::ReadDirectoryAfterGetRootFolderId(
-    const base::FilePath& directory_path,
-    const std::string& local_id,
-    FileError error,
-    base::Optional<std::string> root_folder_id) {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-
-  if (error != FILE_ERROR_OK) {
-    OnDirectoryLoadComplete(local_id, error);
-    return;
-  }
-
-  DCHECK(root_folder_id);
-
-  start_page_token_loader_->GetStartPageToken(
-      base::Bind(&DirectoryLoader::ReadDirectoryAfterGetStartPageToken,
-                 weak_ptr_factory_.GetWeakPtr(), directory_path, local_id,
-                 root_folder_id.value()));
-}
-
-void DirectoryLoader::ReadDirectoryAfterGetStartPageToken(
-    const base::FilePath& directory_path,
-    const std::string& local_id,
-    const std::string& root_folder_id,
-    google_apis::DriveApiErrorCode status,
-    std::unique_ptr<google_apis::StartPageToken> start_page_token) {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-
-  FileError error = GDataToFileError(status);
-  if (error != FILE_ERROR_OK) {
-    OnDirectoryLoadComplete(local_id, error);
-    return;
-  }
-
-  DCHECK(start_page_token);
-
-  // Check the current status of local metadata, and start loading if needed.
-  ResourceEntry* entry = new ResourceEntry;
-  std::string* local_start_page_token = new std::string();
-  base::PostTaskAndReplyWithResult(
-      blocking_task_runner_.get(), FROM_HERE,
-      base::BindOnce(&CheckLocalState, resource_metadata_, root_entry_path_,
-                     team_drive_id_, root_folder_id, local_id, entry,
-                     local_start_page_token),
-      base::BindOnce(&DirectoryLoader::ReadDirectoryAfterCheckLocalState,
-                     weak_ptr_factory_.GetWeakPtr(), directory_path,
-                     start_page_token->start_page_token(), local_id,
-                     root_folder_id, base::Owned(entry),
-                     base::Owned(local_start_page_token)));
-}
-
-void DirectoryLoader::ReadDirectoryAfterCheckLocalState(
-    const base::FilePath& directory_path,
-    const std::string& remote_start_page_token,
-    const std::string& local_id,
-    const std::string& root_folder_id,
-    const ResourceEntry* entry,
-    const std::string* local_start_page_token,
-    FileError error) {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-  DCHECK(local_start_page_token);
-
-  if (error != FILE_ERROR_OK) {
-    OnDirectoryLoadComplete(local_id, error);
-    return;
-  }
-  // This entry does not exist on the server.
-  if (entry->resource_id().empty()) {
-    OnDirectoryLoadComplete(local_id, FILE_ERROR_OK);
-    return;
-  }
-
-  // Start loading the directory.
-  const std::string& directory_start_page_token =
-      entry->directory_specific_info().start_page_token();
-
-  DirectoryFetchInfo directory_fetch_info(local_id, entry->resource_id(),
-                                          remote_start_page_token,
-                                          root_entry_path_, directory_path);
-
-  int64_t directory_changestamp = 0;
-  // The directory_specific_info may be enpty, so default changestamp to 0.
-  if (!directory_start_page_token.empty() &&
-      !drive::util::ConvertStartPageTokenToChangestamp(
-          directory_start_page_token, &directory_changestamp)) {
-    logger_->Log(
-        logging::LOG_ERROR,
-        "Unable to convert directory start page tokens to changestamps, will "
-        "load directory from server %s; directory start page token: %s ",
-        directory_fetch_info.ToString().c_str(),
-        directory_start_page_token.c_str());
-    LoadDirectoryFromServer(directory_fetch_info, root_folder_id);
-    return;
-  }
-
-  // If we haven't finished loading the drive corpus, local_start_page_token
-  // will be empty. In this case we will keep track of the last time we loaded
-  // the directory, and only reload after an appropriate delay.
-  if (local_start_page_token->empty()) {
-    if (entry->directory_specific_info().has_last_read_time_ms()) {
-      base::Time last_read = base::Time::FromDeltaSinceWindowsEpoch(
-          base::TimeDelta::FromMilliseconds(
-              entry->directory_specific_info().last_read_time_ms()));
-      base::TimeDelta elapsed = clock_->Now() - last_read;
-      if (elapsed < kMinimumPerDirectoryFetchTimeGap) {
-        logger_->Log(
-            logging::LOG_INFO,
-            "Skipping read of directory (%s), contents considered fresh.",
-            directory_fetch_info.ToString().c_str());
-        OnDirectoryLoadComplete(local_id, FILE_ERROR_OK);
-        return;
-      }
-    }
-  }
-
-  int64_t remote_changestamp = 0;
-  int64_t local_changestamp = 0;
-  if (!drive::util::ConvertStartPageTokenToChangestamp(remote_start_page_token,
-                                                       &remote_changestamp) ||
-      !drive::util::ConvertStartPageTokenToChangestamp(*local_start_page_token,
-                                                       &local_changestamp)) {
-    logger_->Log(
-        logging::LOG_ERROR,
-        "Unable to convert start page tokens to changestamps, will load "
-        "directory from server %s; local start page token: %s; "
-        "remote start page token: %s",
-        directory_fetch_info.ToString().c_str(),
-        local_start_page_token->c_str(), remote_start_page_token.c_str());
-    LoadDirectoryFromServer(directory_fetch_info, root_folder_id);
-    return;
-  }
-
-  // Start loading the directory.
-  directory_changestamp = std::max(directory_changestamp, local_changestamp);
-
-  // If the directory's changestamp is up to date or the global changestamp or
-  // the metadata DB is new enough (which means the normal changelist loading
-  // should finish very soon), just schedule to run the callback, as there is no
-  // need to fetch the directory.
-  if (directory_changestamp >= remote_changestamp ||
-      local_changestamp + kMinimumChangestampGap > remote_changestamp) {
-    OnDirectoryLoadComplete(local_id, FILE_ERROR_OK);
-  } else {
-    // Start fetching the directory content, and mark it with the changestamp
-    // |remote_changestamp|.
-    LoadDirectoryFromServer(directory_fetch_info, root_folder_id);
-  }
-}
-
-void DirectoryLoader::OnDirectoryLoadComplete(const std::string& local_id,
-                                              FileError error) {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-
-  LoadCallbackMap::iterator it = pending_load_callback_.find(local_id);
-  if (it == pending_load_callback_.end())
-    return;
-
-  // No need to read metadata when no one needs entries.
-  bool needs_to_send_entries = false;
-  for (size_t i = 0; i < it->second.size(); ++i) {
-    const ReadDirectoryCallbackState& callback_state = it->second[i];
-    if (callback_state.entries_callback)
-      needs_to_send_entries = true;
-  }
-
-  if (!needs_to_send_entries) {
-    OnDirectoryLoadCompleteAfterRead(local_id, nullptr, FILE_ERROR_OK);
-    return;
-  }
-
-  ResourceEntryVector* entries = new ResourceEntryVector;
-  base::PostTaskAndReplyWithResult(
-      blocking_task_runner_.get(),
-      FROM_HERE,
-      base::Bind(&ResourceMetadata::ReadDirectoryById,
-                 base::Unretained(resource_metadata_), local_id, entries),
-      base::Bind(&DirectoryLoader::OnDirectoryLoadCompleteAfterRead,
-                 weak_ptr_factory_.GetWeakPtr(),
-                 local_id,
-                 base::Owned(entries)));
-}
-
-void DirectoryLoader::OnDirectoryLoadCompleteAfterRead(
-    const std::string& local_id,
-    const ResourceEntryVector* entries,
-    FileError error) {
-  LoadCallbackMap::iterator it = pending_load_callback_.find(local_id);
-  if (it != pending_load_callback_.end()) {
-    DVLOG(1) << "Running callback for " << local_id;
-
-    if (error == FILE_ERROR_OK && entries)
-      SendEntries(local_id, *entries);
-
-    for (size_t i = 0; i < it->second.size(); ++i) {
-      const ReadDirectoryCallbackState& callback_state = it->second[i];
-      callback_state.completion_callback.Run(error);
-    }
-    pending_load_callback_.erase(it);
-  }
-}
-
-void DirectoryLoader::SendEntries(const std::string& local_id,
-                                  const ResourceEntryVector& entries) {
-  LoadCallbackMap::iterator it = pending_load_callback_.find(local_id);
-  DCHECK(it != pending_load_callback_.end()) << "local_id: " << local_id;
-
-  for (size_t i = 0; i < it->second.size(); ++i) {
-    ReadDirectoryCallbackState* callback_state = &it->second[i];
-    if (!callback_state->entries_callback)
-      continue;
-
-    // Filter out entries which were already sent.
-    std::unique_ptr<ResourceEntryVector> entries_to_send(
-        new ResourceEntryVector);
-    for (size_t i = 0; i < entries.size(); ++i) {
-      const ResourceEntry& entry = entries[i];
-      if (!callback_state->sent_entry_names.count(entry.base_name())) {
-        callback_state->sent_entry_names.insert(entry.base_name());
-        entries_to_send->push_back(entry);
-      }
-    }
-    std::move(callback_state->entries_callback).Run(std::move(entries_to_send));
-  }
-}
-
-void DirectoryLoader::LoadDirectoryFromServer(
-    const DirectoryFetchInfo& directory_fetch_info,
-    const std::string& root_folder_id) {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-  DCHECK(!directory_fetch_info.empty());
-  DVLOG(1) << "Start loading directory: " << directory_fetch_info.ToString();
-
-  const google_apis::StartPageToken* start_page_token =
-      start_page_token_loader_->cached_start_page_token();
-  DCHECK(start_page_token);
-
-  logger_->Log(logging::LOG_INFO,
-               "Fast-fetch start: %s; Server start page token: %s",
-               directory_fetch_info.ToString().c_str(),
-               start_page_token->start_page_token().c_str());
-
-  FeedFetcher* fetcher =
-      new FeedFetcher(this, directory_fetch_info, root_folder_id);
-
-  fast_fetch_feed_fetcher_set_.insert(base::WrapUnique(fetcher));
-  fetcher->Run(
-      base::Bind(&DirectoryLoader::LoadDirectoryFromServerAfterLoad,
-                 weak_ptr_factory_.GetWeakPtr(),
-                 directory_fetch_info,
-                 fetcher));
-}
-
-void DirectoryLoader::LoadDirectoryFromServerAfterLoad(
-    const DirectoryFetchInfo& directory_fetch_info,
-    FeedFetcher* fetcher,
-    FileError error) {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-  DCHECK(!directory_fetch_info.empty());
-
-  // Delete the fetcher.
-  auto it = fast_fetch_feed_fetcher_set_.find(fetcher);
-  fast_fetch_feed_fetcher_set_.erase(it);
-
-  logger_->Log(logging::LOG_INFO,
-               "Fast-fetch complete: %s => %s",
-               directory_fetch_info.ToString().c_str(),
-               FileErrorToString(error).c_str());
-
-  if (error != FILE_ERROR_OK) {
-    LOG(ERROR) << "Failed to load directory: "
-               << directory_fetch_info.local_id()
-               << ": " << FileErrorToString(error);
-    OnDirectoryLoadComplete(directory_fetch_info.local_id(), error);
-    return;
-  }
-
-  // Update start page token and get the directory path.
-  base::FilePath* directory_path = new base::FilePath;
-  base::PostTaskAndReplyWithResult(
-      blocking_task_runner_.get(), FROM_HERE,
-      base::Bind(&UpdateStartPageToken, resource_metadata_,
-                 directory_fetch_info, directory_path,
-                 base::Unretained(clock_)),
-      base::Bind(
-          &DirectoryLoader::LoadDirectoryFromServerAfterUpdateStartPageToken,
-          weak_ptr_factory_.GetWeakPtr(), directory_fetch_info,
-          base::Owned(directory_path)));
-}
-
-void DirectoryLoader::LoadDirectoryFromServerAfterUpdateStartPageToken(
-    const DirectoryFetchInfo& directory_fetch_info,
-    const base::FilePath* directory_path,
-    FileError error) {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-
-  DVLOG(1) << "Directory loaded: " << directory_fetch_info.ToString();
-  OnDirectoryLoadComplete(directory_fetch_info.local_id(), error);
-
-  // Also notify the observers.
-  if (error == FILE_ERROR_OK && !directory_path->empty()) {
-    for (auto& observer : observers_)
-      observer.OnDirectoryReloaded(*directory_path);
-  }
-}
-
-}  // namespace internal
-}  // namespace drive
diff --git a/components/drive/chromeos/directory_loader.h b/components/drive/chromeos/directory_loader.h
deleted file mode 100644
index 744cd84..0000000
--- a/components/drive/chromeos/directory_loader.h
+++ /dev/null
@@ -1,181 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef COMPONENTS_DRIVE_CHROMEOS_DIRECTORY_LOADER_H_
-#define COMPONENTS_DRIVE_CHROMEOS_DIRECTORY_LOADER_H_
-
-#include <stdint.h>
-
-#include <map>
-#include <memory>
-#include <set>
-#include <string>
-#include <vector>
-
-#include "base/callback.h"
-#include "base/containers/unique_ptr_adapters.h"
-#include "base/macros.h"
-#include "base/memory/ref_counted.h"
-#include "base/observer_list.h"
-#include "base/threading/thread_checker.h"
-#include "base/time/default_clock.h"
-#include "components/drive/chromeos/file_system_interface.h"
-#include "components/drive/file_errors.h"
-#include "google_apis/drive/drive_api_error_codes.h"
-#include "google_apis/drive/drive_common_callbacks.h"
-
-namespace base {
-class Clock;
-class SequencedTaskRunner;
-}  // namespace base
-
-namespace drive {
-
-class EventLogger;
-class JobScheduler;
-class ResourceEntry;
-
-namespace internal {
-
-class RootFolderIdLoader;
-class ChangeListLoaderObserver;
-class DirectoryFetchInfo;
-class LoaderController;
-class ResourceMetadata;
-class StartPageTokenLoader;
-
-// DirectoryLoader is used to load directory contents.
-class DirectoryLoader {
- public:
-  // |clock| can be mocked for testing
-  DirectoryLoader(EventLogger* logger,
-                  base::SequencedTaskRunner* blocking_task_runner,
-                  ResourceMetadata* resource_metadata,
-                  JobScheduler* scheduler,
-                  RootFolderIdLoader* root_folder_id_loader,
-                  StartPageTokenLoader* start_page_token_loader,
-                  LoaderController* apply_task_controller,
-                  const base::FilePath& root_entry_path,
-                  const std::string& team_drive_id,
-                  const base::Clock* clock = base::DefaultClock::GetInstance());
-  ~DirectoryLoader();
-
-  // Adds and removes the observer.
-  void AddObserver(ChangeListLoaderObserver* observer);
-  void RemoveObserver(ChangeListLoaderObserver* observer);
-
-  // Reads the directory contents.
-  // |entries_callback| can be null.
-  // |completion_callback| must not be null.
-  void ReadDirectory(const base::FilePath& directory_path,
-                     ReadDirectoryEntriesCallback entries_callback,
-                     const FileOperationCallback& completion_callback);
-
- private:
-  class FeedFetcher;
-  struct ReadDirectoryCallbackState;
-
-  // Part of ReadDirectory().
-  void ReadDirectoryAfterGetEntry(
-      const base::FilePath& directory_path,
-      ReadDirectoryEntriesCallback entries_callback,
-      const FileOperationCallback& completion_callback,
-      bool should_try_loading_parent,
-      const ResourceEntry* entry,
-      FileError error);
-  void ReadDirectoryAfterLoadParent(
-      const base::FilePath& directory_path,
-      ReadDirectoryEntriesCallback entries_callback,
-      const FileOperationCallback& completion_callback,
-      FileError error);
-  void ReadDirectoryAfterGetRootFolderId(
-      const base::FilePath& directory_path,
-      const std::string& local_id,
-      FileError error,
-      base::Optional<std::string> root_folder_id);
-  void ReadDirectoryAfterGetStartPageToken(
-      const base::FilePath& directory_path,
-      const std::string& local_id,
-      const std::string& root_folder_id,
-      google_apis::DriveApiErrorCode status,
-      std::unique_ptr<google_apis::StartPageToken> start_page_token);
-
-  void ReadDirectoryAfterCheckLocalState(
-      const base::FilePath& directory_path,
-      const std::string& remote_start_page_token,
-      const std::string& local_id,
-      const std::string& root_folder_id,
-      const ResourceEntry* entry,
-      const std::string* local_start_page_token,
-      FileError error);
-
-  // Part of ReadDirectory().
-  // This function should be called when the directory load is complete.
-  // Flushes the callbacks waiting for the directory to be loaded.
-  void OnDirectoryLoadComplete(const std::string& local_id, FileError error);
-  void OnDirectoryLoadCompleteAfterRead(const std::string& local_id,
-                                        const ResourceEntryVector* entries,
-                                        FileError error);
-
-  // Sends |entries| to the callbacks.
-  void SendEntries(const std::string& local_id,
-                   const ResourceEntryVector& entries);
-
-  // ================= Implementation for directory loading =================
-  // Loads the directory contents from server, and updates the local metadata.
-  // Runs |callback| when it is finished.
-  void LoadDirectoryFromServer(const DirectoryFetchInfo& directory_fetch_info,
-                               const std::string& root_folder_id);
-
-  // Part of LoadDirectoryFromServer() for a normal directory.
-  void LoadDirectoryFromServerAfterLoad(
-      const DirectoryFetchInfo& directory_fetch_info,
-      FeedFetcher* fetcher,
-      FileError error);
-
-  // Part of LoadDirectoryFromServer().
-  void LoadDirectoryFromServerAfterUpdateStartPageToken(
-      const DirectoryFetchInfo& directory_fetch_info,
-      const base::FilePath* directory_path,
-      FileError error);
-
-  EventLogger* logger_;  // Not owned.
-  scoped_refptr<base::SequencedTaskRunner> blocking_task_runner_;
-  ResourceMetadata* resource_metadata_;  // Not owned.
-  JobScheduler* scheduler_;  // Not owned.
-  RootFolderIdLoader* root_folder_id_loader_;      // Not owned.
-  StartPageTokenLoader* start_page_token_loader_;  // Not owned
-  LoaderController* loader_controller_;  // Not owned.
-  base::ObserverList<ChangeListLoaderObserver>::Unchecked observers_;
-  typedef std::map<std::string, std::vector<ReadDirectoryCallbackState> >
-      LoadCallbackMap;
-  LoadCallbackMap pending_load_callback_;
-
-  // Set of the running feed fetcher for the fast fetch.
-  std::set<std::unique_ptr<FeedFetcher>, base::UniquePtrComparator>
-      fast_fetch_feed_fetcher_set_;
-
-  // The root entry path for changes being loaded by this directory loader.
-  // Can be a team drive root entry or for the users default corpus will be the
-  // drive root entry.
-  const base::FilePath root_entry_path_;
-
-  // The team drive id for this directory loader. Used to retrieve the start
-  // page token when performing a fast fetch.
-  const std::string team_drive_id_;
-
-  const base::Clock* clock_;  // Not Owned
-
-  THREAD_CHECKER(thread_checker_);
-
-  // Note: This should remain the last member so it'll be destroyed and
-  // invalidate its weak pointers before any other members are destroyed.
-  base::WeakPtrFactory<DirectoryLoader> weak_ptr_factory_{this};
-  DISALLOW_COPY_AND_ASSIGN(DirectoryLoader);
-};
-
-}  // namespace internal
-}  // namespace drive
-
-#endif  // COMPONENTS_DRIVE_CHROMEOS_DIRECTORY_LOADER_H_
diff --git a/components/drive/chromeos/drive_change_list_loader.h b/components/drive/chromeos/drive_change_list_loader.h
deleted file mode 100644
index fcdbad2..0000000
--- a/components/drive/chromeos/drive_change_list_loader.h
+++ /dev/null
@@ -1,62 +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_DRIVE_CHROMEOS_DRIVE_CHANGE_LIST_LOADER_H_
-#define COMPONENTS_DRIVE_CHROMEOS_DRIVE_CHANGE_LIST_LOADER_H_
-
-#include "components/drive/chromeos/file_system_interface.h"
-#include "components/drive/file_errors.h"
-
-namespace drive {
-namespace internal {
-
-class ChangeListLoaderObserver;
-class TeamDriveListObserver;
-
-// DriveChangeListLoader provides an abstraction for loading change lists, the
-// full resource list amd directory contents, from Google Drive API.
-// Implementations of the interface can, for example, include:
-// - An implementation to retrieve from the users default corpus.
-// - An implementation to retrieve from a specific team drive.
-class DriveChangeListLoader {
- public:
-  virtual ~DriveChangeListLoader() = default;
-
-  // Adds and removes an observer for change list loading events.
-  virtual void AddChangeListLoaderObserver(
-      ChangeListLoaderObserver* observer) = 0;
-  virtual void RemoveChangeListLoaderObserver(
-      ChangeListLoaderObserver* observer) = 0;
-
-  // Adds and removes an observer for team drive loading events.
-  virtual void AddTeamDriveListObserver(TeamDriveListObserver* observer) = 0;
-  virtual void RemoveTeamDriveListObserver(TeamDriveListObserver* observer) = 0;
-
-  // Indicates whether there is a request for full resource list or change
-  // list fetching is in flight (i.e. directory contents fetching does not
-  // count).
-  virtual bool IsRefreshing() = 0;
-
-  // Starts the change list loading if needed.
-  // |callback| must not be null.
-  virtual void LoadIfNeeded(const FileOperationCallback& callback) = 0;
-
-  // Check for updates on the server. May do nothing if a change list is
-  // already in the process of being loaded.
-  // |callback| must not be null.
-  virtual void CheckForUpdates(const FileOperationCallback& callback) = 0;
-
-  // Reads the given directory contents.
-  // |entries_callback| can be null.
-  // |completion_callback| must not be null.
-  virtual void ReadDirectory(
-      const base::FilePath& directory_path,
-      ReadDirectoryEntriesCallback entries_callback,
-      const FileOperationCallback& completion_callback) = 0;
-};
-
-}  // namespace internal
-}  // namespace drive
-
-#endif  // COMPONENTS_DRIVE_CHROMEOS_DRIVE_CHANGE_LIST_LOADER_H_
diff --git a/components/drive/chromeos/dummy_file_system.cc b/components/drive/chromeos/dummy_file_system.cc
deleted file mode 100644
index b284bcb38..0000000
--- a/components/drive/chromeos/dummy_file_system.cc
+++ /dev/null
@@ -1,18 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "components/drive/chromeos/dummy_file_system.h"
-#include "base/bind_helpers.h"
-
-namespace drive {
-
-base::Closure DummyFileSystem::GetFileContent(
-    const base::FilePath& file_path,
-    GetFileContentInitializedCallback initialized_callback,
-    const google_apis::GetContentCallback& get_content_callback,
-    const FileOperationCallback& completion_callback) {
-  return base::DoNothing();
-}
-
-}  // namespace drive
diff --git a/components/drive/chromeos/dummy_file_system.h b/components/drive/chromeos/dummy_file_system.h
deleted file mode 100644
index 52a5a7ca..0000000
--- a/components/drive/chromeos/dummy_file_system.h
+++ /dev/null
@@ -1,117 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef COMPONENTS_DRIVE_CHROMEOS_DUMMY_FILE_SYSTEM_H_
-#define COMPONENTS_DRIVE_CHROMEOS_DUMMY_FILE_SYSTEM_H_
-
-#include <stdint.h>
-#include <set>
-#include <string>
-
-#include "components/drive/chromeos/file_system_interface.h"
-
-namespace drive {
-
-// Dummy implementation of FileSystemInterface. All functions do nothing.
-class DummyFileSystem : public FileSystemInterface {
- public:
-  ~DummyFileSystem() override = default;
-  void AddObserver(FileSystemObserver* observer) override {}
-  void RemoveObserver(FileSystemObserver* observer) override {}
-  void CheckForUpdates() override {}
-  void CheckForUpdates(const std::set<std::string>& ids) override {}
-  void TransferFileFromLocalToRemote(
-      const base::FilePath& local_src_file_path,
-      const base::FilePath& remote_dest_file_path,
-      const FileOperationCallback& callback) override {}
-  void OpenFile(const base::FilePath& file_path,
-                OpenMode open_mode,
-                const std::string& mime_type,
-                OpenFileCallback callback) override {}
-  void Copy(const base::FilePath& src_file_path,
-            const base::FilePath& dest_file_path,
-            bool preserve_last_modified,
-            const FileOperationCallback& callback) override {}
-  void Move(const base::FilePath& src_file_path,
-            const base::FilePath& dest_file_path,
-            const FileOperationCallback& callback) override {}
-  void Remove(const base::FilePath& file_path,
-              bool is_recursive,
-              const FileOperationCallback& callback) override {}
-  void CreateDirectory(const base::FilePath& directory_path,
-                       bool is_exclusive,
-                       bool is_recursive,
-                       const FileOperationCallback& callback) override {}
-  void CreateFile(const base::FilePath& file_path,
-                  bool is_exclusive,
-                  const std::string& mime_type,
-                  const FileOperationCallback& callback) override {}
-  void TouchFile(const base::FilePath& file_path,
-                 const base::Time& last_access_time,
-                 const base::Time& last_modified_time,
-                 const FileOperationCallback& callback) override {}
-  void TruncateFile(const base::FilePath& file_path,
-                    int64_t length,
-                    const FileOperationCallback& callback) override {}
-  void Pin(const base::FilePath& file_path,
-           const FileOperationCallback& callback) override {}
-  void Unpin(const base::FilePath& file_path,
-             const FileOperationCallback& callback) override {}
-  void GetFile(const base::FilePath& file_path,
-               GetFileCallback callback) override {}
-  void GetFileForSaving(const base::FilePath& file_path,
-                        GetFileCallback callback) override {}
-  base::Closure GetFileContent(
-      const base::FilePath& file_path,
-      GetFileContentInitializedCallback initialized_callback,
-      const google_apis::GetContentCallback& get_content_callback,
-      const FileOperationCallback& completion_callback) override;
-  void GetResourceEntry(const base::FilePath& file_path,
-                        GetResourceEntryCallback callback) override {}
-  void ReadDirectory(
-      const base::FilePath& file_path,
-      ReadDirectoryEntriesCallback entries_callback,
-      const FileOperationCallback& completion_callback) override {}
-  void Search(const std::string& search_query,
-              const GURL& next_link,
-              SearchCallback callback) override {}
-  void SearchMetadata(const std::string& query,
-                      int options,
-                      int at_most_num_matches,
-                      MetadataSearchOrder order,
-                      SearchMetadataCallback callback) override {}
-  void SearchByHashes(const std::set<std::string>& hashes,
-                      SearchByHashesCallback callback) override {}
-  void GetAvailableSpace(GetAvailableSpaceCallback callback) override {}
-  void GetMetadata(GetFilesystemMetadataCallback callback) override {}
-  void MarkCacheFileAsMounted(const base::FilePath& drive_file_path,
-                              MarkMountedCallback callback) override {}
-  void MarkCacheFileAsUnmounted(
-      const base::FilePath& cache_file_path,
-      const FileOperationCallback& callback) override {}
-  void IsCacheFileMarkedAsMounted(const base::FilePath& drive_file_path,
-                                  IsMountedCallback callback) override {}
-  void AddPermission(const base::FilePath& drive_file_path,
-                     const std::string& email,
-                     google_apis::drive::PermissionRole role,
-                     const FileOperationCallback& callback) override {}
-  void SetProperty(const base::FilePath& drive_file_path,
-                   google_apis::drive::Property::Visibility visibility,
-                   const std::string& key,
-                   const std::string& value,
-                   const FileOperationCallback& callback) override {}
-  void Reset(const FileOperationCallback& callback) override {}
-  void GetPathFromResourceId(const std::string& resource_id,
-                             const GetFilePathCallback& callback) override {}
-  void FreeDiskSpaceIfNeededFor(
-      int64_t num_bytes,
-      const FreeDiskSpaceCallback& callback) override {}
-  void CalculateCacheSize(const CacheSizeCallback& callback) override {}
-  void CalculateEvictableCacheSize(
-      const CacheSizeCallback& callback) override {}
-};
-
-}  // namespace drive
-
-#endif  // COMPONENTS_DRIVE_CHROMEOS_DUMMY_FILE_SYSTEM_H_
diff --git a/components/drive/chromeos/fake_file_system.cc b/components/drive/chromeos/fake_file_system.cc
deleted file mode 100644
index ac201f1..0000000
--- a/components/drive/chromeos/fake_file_system.cc
+++ /dev/null
@@ -1,428 +0,0 @@
-// Copyright (c) 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "components/drive/chromeos/fake_file_system.h"
-
-#include <stddef.h>
-
-#include <memory>
-#include <set>
-#include <utility>
-#include <vector>
-
-#include "base/bind.h"
-#include "base/bind_helpers.h"
-#include "base/callback.h"
-#include "base/files/file_path.h"
-#include "base/files/file_util.h"
-#include "base/logging.h"
-#include "components/drive/drive.pb.h"
-#include "components/drive/file_errors.h"
-#include "components/drive/file_system_core_util.h"
-#include "components/drive/resource_entry_conversion.h"
-#include "components/drive/service/drive_service_interface.h"
-#include "content/public/browser/browser_thread.h"
-#include "google_apis/drive/drive_api_parser.h"
-
-namespace drive {
-namespace test_util {
-
-using content::BrowserThread;
-
-FakeFileSystem::FakeFileSystem(DriveServiceInterface* drive_service)
-    : drive_service_(drive_service) {
-  CHECK(cache_dir_.CreateUniqueTempDir());
-}
-
-FakeFileSystem::~FakeFileSystem() = default;
-
-void FakeFileSystem::AddObserver(FileSystemObserver* observer) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
-}
-
-void FakeFileSystem::RemoveObserver(FileSystemObserver* observer) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
-}
-
-void FakeFileSystem::CheckForUpdates() {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
-}
-
-void FakeFileSystem::CheckForUpdates(const std::set<std::string>& ids) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
-}
-
-void FakeFileSystem::TransferFileFromLocalToRemote(
-    const base::FilePath& local_src_file_path,
-    const base::FilePath& remote_dest_file_path,
-    const FileOperationCallback& callback) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
-}
-
-void FakeFileSystem::OpenFile(const base::FilePath& file_path,
-                              OpenMode open_mode,
-                              const std::string& mime_type,
-                              OpenFileCallback callback) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
-}
-
-void FakeFileSystem::Copy(const base::FilePath& src_file_path,
-                          const base::FilePath& dest_file_path,
-                          bool preserve_last_modified,
-                          const FileOperationCallback& callback) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
-}
-
-void FakeFileSystem::Move(const base::FilePath& src_file_path,
-                          const base::FilePath& dest_file_path,
-                          const FileOperationCallback& callback) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
-}
-
-void FakeFileSystem::Remove(const base::FilePath& file_path,
-                            bool is_recursive,
-                            const FileOperationCallback& callback) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
-}
-
-void FakeFileSystem::CreateDirectory(
-    const base::FilePath& directory_path,
-    bool is_exclusive,
-    bool is_recursive,
-    const FileOperationCallback& callback) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
-}
-
-void FakeFileSystem::CreateFile(const base::FilePath& file_path,
-                                bool is_exclusive,
-                                const std::string& mime_type,
-                                const FileOperationCallback& callback) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
-}
-
-void FakeFileSystem::TouchFile(const base::FilePath& file_path,
-                               const base::Time& last_access_time,
-                               const base::Time& last_modified_time,
-                               const FileOperationCallback& callback) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
-}
-
-void FakeFileSystem::TruncateFile(const base::FilePath& file_path,
-                                  int64_t length,
-                                  const FileOperationCallback& callback) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
-}
-
-void FakeFileSystem::Pin(const base::FilePath& file_path,
-                         const FileOperationCallback& callback) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
-}
-
-void FakeFileSystem::Unpin(const base::FilePath& file_path,
-                           const FileOperationCallback& callback) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
-}
-
-void FakeFileSystem::GetFile(const base::FilePath& file_path,
-                             GetFileCallback callback) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
-}
-
-void FakeFileSystem::GetFileForSaving(const base::FilePath& file_path,
-                                      GetFileCallback callback) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
-}
-
-void FakeFileSystem::IsCacheFileMarkedAsMounted(
-    const base::FilePath& drive_file_path,
-    IsMountedCallback callback) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
-}
-
-base::Closure FakeFileSystem::GetFileContent(
-    const base::FilePath& file_path,
-    GetFileContentInitializedCallback initialized_callback,
-    const google_apis::GetContentCallback& get_content_callback,
-    const FileOperationCallback& completion_callback) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
-
-  GetResourceEntry(
-      file_path,
-      base::Bind(&FakeFileSystem::GetFileContentAfterGetResourceEntry,
-                 weak_ptr_factory_.GetWeakPtr(),
-                 base::Passed(std::move(initialized_callback)),
-                 get_content_callback, completion_callback));
-  return base::DoNothing();
-}
-
-void FakeFileSystem::GetResourceEntry(const base::FilePath& file_path,
-                                      GetResourceEntryCallback callback) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
-
-  if (file_path == util::GetDriveMyDriveRootPath()) {
-    // Specialized for the root entry.
-    drive_service_->GetAboutResource(base::Bind(
-        &FakeFileSystem::GetResourceEntryAfterGetAboutResource,
-        weak_ptr_factory_.GetWeakPtr(), base::Passed(std::move(callback))));
-    return;
-  }
-
-  // Now, we only support files under my drive.
-  DCHECK(util::GetDriveMyDriveRootPath().IsParent(file_path));
-  GetResourceEntry(
-      file_path.DirName(),
-      base::BindOnce(&FakeFileSystem::GetResourceEntryAfterGetParentEntryInfo,
-                     weak_ptr_factory_.GetWeakPtr(), file_path.BaseName(),
-                     std::move(callback)));
-}
-
-void FakeFileSystem::ReadDirectory(
-    const base::FilePath& file_path,
-    ReadDirectoryEntriesCallback entries_callback,
-    const FileOperationCallback& completion_callback) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
-}
-
-void FakeFileSystem::Search(const std::string& search_query,
-                            const GURL& next_link,
-                            SearchCallback callback) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
-}
-
-void FakeFileSystem::SearchMetadata(const std::string& query,
-                                    int options,
-                                    int at_most_num_matches,
-                                    MetadataSearchOrder order,
-                                    SearchMetadataCallback callback) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
-}
-
-void FakeFileSystem::SearchByHashes(const std::set<std::string>& hashes,
-                                    SearchByHashesCallback callback) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
-}
-
-void FakeFileSystem::GetAvailableSpace(GetAvailableSpaceCallback callback) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
-}
-
-void FakeFileSystem::GetMetadata(GetFilesystemMetadataCallback callback) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
-}
-
-void FakeFileSystem::MarkCacheFileAsMounted(
-    const base::FilePath& drive_file_path,
-    MarkMountedCallback callback) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
-}
-
-void FakeFileSystem::MarkCacheFileAsUnmounted(
-    const base::FilePath& cache_file_path,
-    const FileOperationCallback& callback) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
-}
-
-void FakeFileSystem::AddPermission(const base::FilePath& drive_file_path,
-                                   const std::string& email,
-                                   google_apis::drive::PermissionRole role,
-                                   const FileOperationCallback& callback) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
-}
-
-void FakeFileSystem::SetProperty(
-    const base::FilePath& drive_file_path,
-    google_apis::drive::Property::Visibility visibility,
-    const std::string& key,
-    const std::string& value,
-    const FileOperationCallback& callback) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
-}
-
-void FakeFileSystem::Reset(const FileOperationCallback& callback) {
-}
-
-void FakeFileSystem::GetPathFromResourceId(
-    const std::string& resource_id,
-    const GetFilePathCallback& callback) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
-}
-
-void FakeFileSystem::FreeDiskSpaceIfNeededFor(
-    int64_t num_bytes,
-    const FreeDiskSpaceCallback& callback) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
-}
-
-void FakeFileSystem::CalculateCacheSize(const CacheSizeCallback& callback) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
-}
-
-void FakeFileSystem::CalculateEvictableCacheSize(
-    const CacheSizeCallback& callback) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
-}
-
-// Implementation of GetFileContent.
-void FakeFileSystem::GetFileContentAfterGetResourceEntry(
-    GetFileContentInitializedCallback initialized_callback,
-    const google_apis::GetContentCallback& get_content_callback,
-    const FileOperationCallback& completion_callback,
-    FileError error,
-    std::unique_ptr<ResourceEntry> entry) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
-
-  if (error != FILE_ERROR_OK) {
-    completion_callback.Run(error);
-    return;
-  }
-  DCHECK(entry);
-
-  // We're only interested in a file.
-  if (entry->file_info().is_directory()) {
-    completion_callback.Run(FILE_ERROR_NOT_A_FILE);
-    return;
-  }
-
-  // Fetch google_apis::FileResource for its |download_url|.
-  drive_service_->GetFileResource(
-      entry->resource_id(),
-      base::Bind(&FakeFileSystem::GetFileContentAfterGetFileResource,
-                 weak_ptr_factory_.GetWeakPtr(),
-                 base::Passed(std::move(initialized_callback)),
-                 get_content_callback, completion_callback));
-}
-
-void FakeFileSystem::GetFileContentAfterGetFileResource(
-    GetFileContentInitializedCallback initialized_callback,
-    const google_apis::GetContentCallback& get_content_callback,
-    const FileOperationCallback& completion_callback,
-    google_apis::DriveApiErrorCode gdata_error,
-    std::unique_ptr<google_apis::FileResource> gdata_entry) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
-
-  FileError error = GDataToFileError(gdata_error);
-  if (error != FILE_ERROR_OK) {
-    completion_callback.Run(error);
-    return;
-  }
-  DCHECK(gdata_entry);
-
-  std::unique_ptr<ResourceEntry> entry(new ResourceEntry);
-  std::string parent_resource_id;
-  ConvertFileResourceToResourceEntry(*gdata_entry, entry.get(),
-                                     &parent_resource_id);
-  entry->set_parent_local_id(parent_resource_id);
-
-  base::FilePath cache_path =
-      cache_dir_.GetPath().AppendASCII(entry->resource_id());
-  if (entry->file_specific_info().is_hosted_document()) {
-    // For hosted documents return a dummy cache without server request.
-    int result = base::WriteFile(cache_path, "", 0);
-    DCHECK_EQ(0, result);
-  }
-  if (base::PathExists(cache_path)) {
-    // Cache file is found.
-    std::move(initialized_callback)
-        .Run(FILE_ERROR_OK, cache_path, std::move(entry));
-    completion_callback.Run(FILE_ERROR_OK);
-    return;
-  }
-
-  std::move(initialized_callback)
-      .Run(FILE_ERROR_OK, base::FilePath(), std::move(entry));
-  drive_service_->DownloadFile(
-      cache_path,
-      gdata_entry->file_id(),
-      base::Bind(&FakeFileSystem::GetFileContentAfterDownloadFile,
-                 weak_ptr_factory_.GetWeakPtr(),
-                 completion_callback),
-      get_content_callback,
-      google_apis::ProgressCallback());
-}
-
-void FakeFileSystem::GetFileContentAfterDownloadFile(
-    const FileOperationCallback& completion_callback,
-    google_apis::DriveApiErrorCode gdata_error,
-    const base::FilePath& temp_file) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
-  completion_callback.Run(GDataToFileError(gdata_error));
-}
-
-// Implementation of GetResourceEntry.
-void FakeFileSystem::GetResourceEntryAfterGetAboutResource(
-    GetResourceEntryCallback callback,
-    google_apis::DriveApiErrorCode gdata_error,
-    std::unique_ptr<google_apis::AboutResource> about_resource) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
-
-  FileError error = GDataToFileError(gdata_error);
-  if (error != FILE_ERROR_OK) {
-    std::move(callback).Run(error, std::unique_ptr<ResourceEntry>());
-    return;
-  }
-
-  DCHECK(about_resource);
-  std::unique_ptr<ResourceEntry> root(new ResourceEntry);
-  root->mutable_file_info()->set_is_directory(true);
-  root->set_resource_id(about_resource->root_folder_id());
-  root->set_title(util::kDriveMyDriveRootDirName);
-  std::move(callback).Run(error, std::move(root));
-}
-
-void FakeFileSystem::GetResourceEntryAfterGetParentEntryInfo(
-    const base::FilePath& base_name,
-    GetResourceEntryCallback callback,
-    FileError error,
-    std::unique_ptr<ResourceEntry> parent_entry) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
-
-  if (error != FILE_ERROR_OK) {
-    std::move(callback).Run(error, std::unique_ptr<ResourceEntry>());
-    return;
-  }
-
-  DCHECK(parent_entry);
-  drive_service_->GetFileListInDirectory(
-      parent_entry->resource_id(),
-      base::Bind(&FakeFileSystem::GetResourceEntryAfterGetFileList,
-                 weak_ptr_factory_.GetWeakPtr(), base_name,
-                 base::Passed(std::move(callback))));
-}
-
-void FakeFileSystem::GetResourceEntryAfterGetFileList(
-    const base::FilePath& base_name,
-    GetResourceEntryCallback callback,
-    google_apis::DriveApiErrorCode gdata_error,
-    std::unique_ptr<google_apis::FileList> file_list) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
-
-  FileError error = GDataToFileError(gdata_error);
-  if (error != FILE_ERROR_OK) {
-    std::move(callback).Run(error, std::unique_ptr<ResourceEntry>());
-    return;
-  }
-
-  DCHECK(file_list);
-  const std::vector<std::unique_ptr<google_apis::FileResource>>& entries =
-      file_list->items();
-  for (size_t i = 0; i < entries.size(); ++i) {
-    std::unique_ptr<ResourceEntry> entry(new ResourceEntry);
-    std::string parent_resource_id;
-    ConvertFileResourceToResourceEntry(*entries[i], entry.get(),
-                                       &parent_resource_id);
-    entry->set_parent_local_id(parent_resource_id);
-
-    if (entry->base_name() == base_name.AsUTF8Unsafe()) {
-      // Found the target entry.
-      std::move(callback).Run(FILE_ERROR_OK, std::move(entry));
-      return;
-    }
-  }
-
-  std::move(callback).Run(FILE_ERROR_NOT_FOUND,
-                          std::unique_ptr<ResourceEntry>());
-}
-
-}  // namespace test_util
-}  // namespace drive
diff --git a/components/drive/chromeos/fake_file_system.h b/components/drive/chromeos/fake_file_system.h
deleted file mode 100644
index 4940a03..0000000
--- a/components/drive/chromeos/fake_file_system.h
+++ /dev/null
@@ -1,201 +0,0 @@
-// Copyright (c) 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef COMPONENTS_DRIVE_CHROMEOS_FAKE_FILE_SYSTEM_H_
-#define COMPONENTS_DRIVE_CHROMEOS_FAKE_FILE_SYSTEM_H_
-
-#include <stdint.h>
-
-#include <memory>
-#include <set>
-#include <string>
-
-#include "base/callback_forward.h"
-#include "base/files/scoped_temp_dir.h"
-#include "base/macros.h"
-#include "components/drive/chromeos/file_system_interface.h"
-#include "components/drive/file_errors.h"
-#include "google_apis/drive/drive_api_error_codes.h"
-
-namespace google_apis {
-
-class AboutResource;
-class FileResource;
-
-}  // namespace google_apis
-
-namespace drive {
-
-class DriveServiceInterface;
-class FileSystemObserver;
-class ResourceEntry;
-
-namespace test_util {
-
-// This class implements a fake FileSystem which acts like a real Drive
-// file system with FakeDriveService, for testing purpose.
-// Note that this class doesn't support "caching" at the moment, so the number
-// of interactions to the FakeDriveService may be bigger than the real
-// implementation.
-// Currently most methods are empty (not implemented).
-class FakeFileSystem : public FileSystemInterface {
- public:
-  explicit FakeFileSystem(DriveServiceInterface* drive_service);
-  ~FakeFileSystem() override;
-
-  // FileSystemInterface Overrides.
-  void AddObserver(FileSystemObserver* observer) override;
-  void RemoveObserver(FileSystemObserver* observer) override;
-  void CheckForUpdates() override;
-  void CheckForUpdates(const std::set<std::string>& ids) override;
-  void TransferFileFromLocalToRemote(
-      const base::FilePath& local_src_file_path,
-      const base::FilePath& remote_dest_file_path,
-      const FileOperationCallback& callback) override;
-  void OpenFile(const base::FilePath& file_path,
-                OpenMode open_mode,
-                const std::string& mime_type,
-                OpenFileCallback callback) override;
-  void Copy(const base::FilePath& src_file_path,
-            const base::FilePath& dest_file_path,
-            bool preserve_last_modified,
-            const FileOperationCallback& callback) override;
-  void Move(const base::FilePath& src_file_path,
-            const base::FilePath& dest_file_path,
-            const FileOperationCallback& callback) override;
-  void Remove(const base::FilePath& file_path,
-              bool is_recursive,
-              const FileOperationCallback& callback) override;
-  void CreateDirectory(const base::FilePath& directory_path,
-                       bool is_exclusive,
-                       bool is_recursive,
-                       const FileOperationCallback& callback) override;
-  void CreateFile(const base::FilePath& file_path,
-                  bool is_exclusive,
-                  const std::string& mime_type,
-                  const FileOperationCallback& callback) override;
-  void TouchFile(const base::FilePath& file_path,
-                 const base::Time& last_access_time,
-                 const base::Time& last_modified_time,
-                 const FileOperationCallback& callback) override;
-  void TruncateFile(const base::FilePath& file_path,
-                    int64_t length,
-                    const FileOperationCallback& callback) override;
-  void Pin(const base::FilePath& file_path,
-           const FileOperationCallback& callback) override;
-  void Unpin(const base::FilePath& file_path,
-             const FileOperationCallback& callback) override;
-  void GetFile(const base::FilePath& file_path,
-               GetFileCallback callback) override;
-  void GetFileForSaving(const base::FilePath& file_path,
-                        GetFileCallback callback) override;
-  base::Closure GetFileContent(
-      const base::FilePath& file_path,
-      GetFileContentInitializedCallback initialized_callback,
-      const google_apis::GetContentCallback& get_content_callback,
-      const FileOperationCallback& completion_callback) override;
-  void GetResourceEntry(const base::FilePath& file_path,
-                        GetResourceEntryCallback callback) override;
-  void ReadDirectory(const base::FilePath& file_path,
-                     ReadDirectoryEntriesCallback entries_callback,
-                     const FileOperationCallback& completion_callback) override;
-  void Search(const std::string& search_query,
-              const GURL& next_link,
-              SearchCallback callback) override;
-  void SearchMetadata(const std::string& query,
-                      int options,
-                      int at_most_num_matches,
-                      MetadataSearchOrder order,
-                      SearchMetadataCallback callback) override;
-  void SearchByHashes(const std::set<std::string>& hashes,
-                      SearchByHashesCallback callback) override;
-  void GetAvailableSpace(GetAvailableSpaceCallback callback) override;
-  void GetMetadata(GetFilesystemMetadataCallback callback) override;
-  void MarkCacheFileAsMounted(const base::FilePath& drive_file_path,
-                              MarkMountedCallback callback) override;
-  void MarkCacheFileAsUnmounted(const base::FilePath& cache_file_path,
-                                const FileOperationCallback& callback) override;
-  void IsCacheFileMarkedAsMounted(const base::FilePath& drive_file_path,
-                                  IsMountedCallback callback) override;
-  void AddPermission(const base::FilePath& drive_file_path,
-                     const std::string& email,
-                     google_apis::drive::PermissionRole role,
-                     const FileOperationCallback& callback) override;
-  void SetProperty(const base::FilePath& drive_file_path,
-                   google_apis::drive::Property::Visibility visibility,
-                   const std::string& key,
-                   const std::string& value,
-                   const FileOperationCallback& callback) override;
-  void Reset(const FileOperationCallback& callback) override;
-  void GetPathFromResourceId(const std::string& resource_id,
-                             const GetFilePathCallback& callback) override;
-  void FreeDiskSpaceIfNeededFor(int64_t num_bytes,
-                                const FreeDiskSpaceCallback& callback) override;
-  void CalculateCacheSize(const CacheSizeCallback& callback) override;
-  void CalculateEvictableCacheSize(const CacheSizeCallback& callback) override;
-
- private:
-  // Helpers of GetFileContent.
-  // How the method works:
-  // 1) Gets ResourceEntry of the path.
-  // 2) Look at if there is a cache file or not. If found return it.
-  // 3) Otherwise start DownloadFile.
-  // 4) Runs the |completion_callback| upon the download completion.
-  void GetFileContentAfterGetResourceEntry(
-      GetFileContentInitializedCallback initialized_callback,
-      const google_apis::GetContentCallback& get_content_callback,
-      const FileOperationCallback& completion_callback,
-      FileError error,
-      std::unique_ptr<ResourceEntry> entry);
-  void GetFileContentAfterGetFileResource(
-      GetFileContentInitializedCallback initialized_callback,
-      const google_apis::GetContentCallback& get_content_callback,
-      const FileOperationCallback& completion_callback,
-      google_apis::DriveApiErrorCode gdata_error,
-      std::unique_ptr<google_apis::FileResource> gdata_entry);
-  void GetFileContentAfterDownloadFile(
-      const FileOperationCallback& completion_callback,
-      google_apis::DriveApiErrorCode gdata_error,
-      const base::FilePath& temp_file);
-
-  // Helpers of GetResourceEntry.
-  // How the method works:
-  // 1) If the path is root, gets AboutResrouce from the drive service
-  //    and create ResourceEntry.
-  // 2-1) Otherwise, gets the parent's ResourceEntry by recursive call.
-  // 2-2) Then, gets the resource list by restricting the parent with its id.
-  // 2-3) Search the results based on title, and return the ResourceEntry.
-  // Note that adding suffix (e.g. " (2)") for files sharing a same name is
-  // not supported in FakeFileSystem. Thus, even if the server has
-  // files sharing the same name under a directory, the second (or later)
-  // file cannot be taken with the suffixed name.
-  void GetResourceEntryAfterGetAboutResource(
-      GetResourceEntryCallback callback,
-      google_apis::DriveApiErrorCode gdata_error,
-      std::unique_ptr<google_apis::AboutResource> about_resource);
-  void GetResourceEntryAfterGetParentEntryInfo(
-      const base::FilePath& base_name,
-      GetResourceEntryCallback callback,
-      FileError error,
-      std::unique_ptr<ResourceEntry> parent_entry);
-  void GetResourceEntryAfterGetFileList(
-      const base::FilePath& base_name,
-      GetResourceEntryCallback callback,
-      google_apis::DriveApiErrorCode gdata_error,
-      std::unique_ptr<google_apis::FileList> file_list);
-
-  DriveServiceInterface* drive_service_;  // Not owned.
-  base::ScopedTempDir cache_dir_;
-
-  // Note: This should remain the last member so it'll be destroyed and
-  // invalidate the weak pointers before any other members are destroyed.
-  base::WeakPtrFactory<FakeFileSystem> weak_ptr_factory_{this};
-
-  DISALLOW_COPY_AND_ASSIGN(FakeFileSystem);
-};
-
-}  // namespace test_util
-}  // namespace drive
-
-#endif  // COMPONENTS_DRIVE_CHROMEOS_FAKE_FILE_SYSTEM_H_
diff --git a/components/drive/chromeos/file_system.cc b/components/drive/chromeos/file_system.cc
deleted file mode 100644
index a691dcb..0000000
--- a/components/drive/chromeos/file_system.cc
+++ /dev/null
@@ -1,1167 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "components/drive/chromeos/file_system.h"
-
-#include <stddef.h>
-#include <limits>
-#include <map>
-#include <set>
-#include <utility>
-
-#include "base/barrier_closure.h"
-#include "base/bind.h"
-#include "base/bind_helpers.h"
-#include "base/files/file_util.h"
-#include "base/sequenced_task_runner.h"
-#include "base/single_thread_task_runner.h"
-#include "components/drive/chromeos/about_resource_loader.h"
-#include "components/drive/chromeos/default_corpus_change_list_loader.h"
-#include "components/drive/chromeos/drive_file_util.h"
-#include "components/drive/chromeos/file_cache.h"
-#include "components/drive/chromeos/file_system/copy_operation.h"
-#include "components/drive/chromeos/file_system/create_directory_operation.h"
-#include "components/drive/chromeos/file_system/create_file_operation.h"
-#include "components/drive/chromeos/file_system/download_operation.h"
-#include "components/drive/chromeos/file_system/get_file_for_saving_operation.h"
-#include "components/drive/chromeos/file_system/move_operation.h"
-#include "components/drive/chromeos/file_system/open_file_operation.h"
-#include "components/drive/chromeos/file_system/remove_operation.h"
-#include "components/drive/chromeos/file_system/search_operation.h"
-#include "components/drive/chromeos/file_system/set_property_operation.h"
-#include "components/drive/chromeos/file_system/touch_operation.h"
-#include "components/drive/chromeos/file_system/truncate_operation.h"
-#include "components/drive/chromeos/file_system_observer.h"
-#include "components/drive/chromeos/loader_controller.h"
-#include "components/drive/chromeos/remove_stale_cache_files.h"
-#include "components/drive/chromeos/search_metadata.h"
-#include "components/drive/chromeos/start_page_token_loader.h"
-#include "components/drive/chromeos/sync_client.h"
-#include "components/drive/drive.pb.h"
-#include "components/drive/drive_pref_names.h"
-#include "components/drive/file_change.h"
-#include "components/drive/file_system_core_util.h"
-#include "components/drive/job_scheduler.h"
-#include "components/drive/resource_entry_conversion.h"
-#include "google_apis/drive/drive_api_parser.h"
-
-namespace drive {
-namespace {
-
-// Desired QPS for team drive background operations (update checking etc)
-constexpr int kTeamDriveBackgroundOperationQPS = 10;
-
-// Gets a ResourceEntry from the metadata, and overwrites its file info when the
-// cached file is dirty.
-FileError GetLocallyStoredResourceEntry(
-    internal::ResourceMetadata* resource_metadata,
-    internal::FileCache* cache,
-    const base::FilePath& file_path,
-    ResourceEntry* entry) {
-  std::string local_id;
-  FileError error = resource_metadata->GetIdByPath(file_path, &local_id);
-  if (error != FILE_ERROR_OK)
-    return error;
-
-  error = resource_metadata->GetResourceEntryById(local_id, entry);
-  if (error != FILE_ERROR_OK)
-    return error;
-
-  // For entries that will never be cached, use the original resource entry
-  // as is.
-  if (!entry->has_file_specific_info() ||
-      entry->file_specific_info().is_hosted_document())
-    return FILE_ERROR_OK;
-
-  // When cache is not found, use the original resource entry as is.
-  if (!entry->file_specific_info().has_cache_state())
-    return FILE_ERROR_OK;
-
-  // When cache is non-dirty and obsolete (old hash), use the original entry.
-  if (!entry->file_specific_info().cache_state().is_dirty() &&
-      entry->file_specific_info().md5() !=
-      entry->file_specific_info().cache_state().md5())
-    return FILE_ERROR_OK;
-
-  // If there's a valid cache, obtain the file info from the cache file itself.
-  base::FilePath local_cache_path;
-  error = cache->GetFile(local_id, &local_cache_path);
-  if (error != FILE_ERROR_OK)
-    return error;
-
-  base::File::Info file_info;
-  if (!base::GetFileInfo(local_cache_path, &file_info))
-    return FILE_ERROR_NOT_FOUND;
-
-  entry->mutable_file_info()->set_size(file_info.size);
-  return FILE_ERROR_OK;
-}
-
-// Runs the callback with parameters.
-void RunGetResourceEntryCallback(GetResourceEntryCallback callback,
-                                 std::unique_ptr<ResourceEntry> entry,
-                                 FileError error) {
-  DCHECK(callback);
-
-  if (error != FILE_ERROR_OK)
-    entry.reset();
-  std::move(callback).Run(error, std::move(entry));
-}
-
-// Used to implement Pin().
-FileError PinInternal(internal::ResourceMetadata* resource_metadata,
-                      internal::FileCache* cache,
-                      const base::FilePath& file_path,
-                      std::string* local_id) {
-  FileError error = resource_metadata->GetIdByPath(file_path, local_id);
-  if (error != FILE_ERROR_OK)
-    return error;
-
-  ResourceEntry entry;
-  error = resource_metadata->GetResourceEntryById(*local_id, &entry);
-  if (error != FILE_ERROR_OK)
-    return error;
-
-  // TODO(hashimoto): Support pinning directories. crbug.com/127831
-  if (entry.file_info().is_directory())
-    return FILE_ERROR_NOT_A_FILE;
-
-  return cache->Pin(*local_id);
-}
-
-// Used to implement Unpin().
-FileError UnpinInternal(internal::ResourceMetadata* resource_metadata,
-                        internal::FileCache* cache,
-                        const base::FilePath& file_path,
-                        std::string* local_id) {
-  FileError error = resource_metadata->GetIdByPath(file_path, local_id);
-  if (error != FILE_ERROR_OK)
-    return error;
-
-  return cache->Unpin(*local_id);
-}
-
-// Used to implement MarkCacheFileAsMounted().
-FileError MarkCacheFileAsMountedInternal(
-    internal::ResourceMetadata* resource_metadata,
-    internal::FileCache* cache,
-    const base::FilePath& drive_file_path,
-    base::FilePath* cache_file_path) {
-  std::string local_id;
-  FileError error = resource_metadata->GetIdByPath(drive_file_path, &local_id);
-  if (error != FILE_ERROR_OK)
-    return error;
-
-  return cache->MarkAsMounted(local_id, cache_file_path);
-}
-
-// Used to implement IsCacheFileMarkedAsMounted().
-FileError IsCacheFileMarkedAsMountedInternal(
-    internal::ResourceMetadata* resource_metadata,
-    internal::FileCache* cache,
-    const base::FilePath& drive_file_path,
-    bool* result) {
-  std::string local_id;
-  FileError error = resource_metadata->GetIdByPath(drive_file_path, &local_id);
-  if (error != FILE_ERROR_OK)
-    return error;
-
-  *result = cache->IsMarkedAsMounted(local_id);
-  return FILE_ERROR_OK;
-}
-
-// Runs the callback with arguments.
-void RunMarkMountedCallback(MarkMountedCallback callback,
-                            base::FilePath* cache_file_path,
-                            FileError error) {
-  DCHECK(callback);
-  std::move(callback).Run(error, *cache_file_path);
-}
-
-// Runs the callback with arguments.
-void RunIsMountedCallback(IsMountedCallback callback,
-                          bool* result,
-                          FileError error) {
-  DCHECK(callback);
-  std::move(callback).Run(error, *result);
-}
-
-// Callback for internals::GetStartPageToken.
-// |closure| must not be null.
-void OnGetStartPageToken(const base::RepeatingClosure& closure,
-                         FileError error) {
-  DCHECK(closure);
-  closure.Run();
-}
-
-// Thin adapter to map GetFileCallback to FileOperationCallback.
-void GetFileCallbackToFileOperationCallbackAdapter(
-    const FileOperationCallback& callback,
-    FileError error,
-    const base::FilePath& unused_file_path,
-    std::unique_ptr<ResourceEntry> unused_entry) {
-  callback.Run(error);
-}
-
-// Clears |resource_metadata| and |cache|.
-FileError ResetOnBlockingPool(internal::ResourceMetadata* resource_metadata,
-                              internal::FileCache* cache) {
-  FileError error = resource_metadata->Reset();
-  if (error != FILE_ERROR_OK)
-    return error;
-  return cache->ClearAll() ? FILE_ERROR_OK : FILE_ERROR_FAILED;
-}
-
-// Part of GetPathFromResourceId().
-// Obtains |file_path| from |resource_id|. The function should be run on the
-// blocking pool.
-FileError GetPathFromResourceIdOnBlockingPool(
-    internal::ResourceMetadata* resource_metadata,
-    const std::string& resource_id,
-    base::FilePath* file_path) {
-  std::string local_id;
-  const FileError error =
-      resource_metadata->GetIdByResourceId(resource_id, &local_id);
-  if (error != FILE_ERROR_OK)
-    return error;
-  return resource_metadata->GetFilePath(local_id, file_path);
-}
-
-// Part of GetPathFromResourceId().
-// Called when GetPathFromResourceIdInBlockingPool is complete.
-void GetPathFromResourceIdAfterGetPath(base::FilePath* file_path,
-                                       const GetFilePathCallback& callback,
-                                       FileError error) {
-  callback.Run(error, *file_path);
-}
-
-bool FreeDiskSpaceIfNeededForOnBlockingPool(internal::FileCache* cache,
-                                            int64_t num_bytes) {
-  return cache->FreeDiskSpaceIfNeededFor(num_bytes);
-}
-
-int64_t CalculateCacheSizeOnBlockingPool(internal::FileCache* cache) {
-  return cache->CalculateCacheSize();
-}
-
-int64_t CalculateEvictableCacheSizeOnBlockingPool(internal::FileCache* cache) {
-  return cache->CalculateEvictableCacheSize();
-}
-
-// Adapter for using FileOperationCallback as google_apis::EntryActionCallback.
-void RunFileOperationCallbackAsEntryActionCallback(
-    const FileOperationCallback& callback,
-    google_apis::DriveApiErrorCode error) {
-  callback.Run(GDataToFileError(error));
-}
-
-// Checks if the |entry|'s hash is included in |hashes|.
-bool CheckHashes(const std::set<std::string>& hashes,
-                 const ResourceEntry& entry) {
-  return hashes.find(entry.file_specific_info().md5()) != hashes.end();
-}
-
-// Runs |callback| with |error| and the list of HashAndFilePath obtained from
-// |original_result|.
-void RunSearchByHashesCallback(
-    SearchByHashesCallback callback,
-    FileError error,
-    std::unique_ptr<MetadataSearchResultVector> original_result) {
-  std::vector<HashAndFilePath> result;
-  if (error != FILE_ERROR_OK) {
-    std::move(callback).Run(error, result);
-    return;
-  }
-  for (const auto& search_result : *original_result) {
-    HashAndFilePath hash_and_path;
-    hash_and_path.hash = search_result.md5;
-    hash_and_path.path = search_result.path;
-    result.push_back(hash_and_path);
-  }
-  std::move(callback).Run(FILE_ERROR_OK, result);
-}
-
-}  // namespace
-
-struct FileSystem::CreateDirectoryParams {
-  base::FilePath directory_path;
-  bool is_exclusive;
-  bool is_recursive;
-  FileOperationCallback callback;
-};
-
-FileSystem::FileSystem(EventLogger* logger,
-                       internal::FileCache* cache,
-                       JobScheduler* scheduler,
-                       internal::ResourceMetadata* resource_metadata,
-                       base::SequencedTaskRunner* blocking_task_runner,
-                       const base::FilePath& temporary_file_directory,
-                       const base::Clock* clock)
-    : logger_(logger),
-      cache_(cache),
-      scheduler_(scheduler),
-      resource_metadata_(resource_metadata),
-      blocking_task_runner_(blocking_task_runner),
-      temporary_file_directory_(temporary_file_directory),
-      clock_(clock) {
-  ResetComponents();
-}
-
-FileSystem::~FileSystem() {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-
-  default_corpus_change_list_loader_->RemoveChangeListLoaderObserver(this);
-  default_corpus_change_list_loader_->RemoveTeamDriveListObserver(this);
-}
-
-void FileSystem::Reset(const FileOperationCallback& callback) {
-  // Discard the current loader and operation objects and renew them. This is to
-  // avoid that changes initiated before the metadata reset is applied after the
-  // reset, which may cause an inconsistent state.
-  // TODO(kinaba): callbacks held in the subcomponents are discarded. We might
-  // want to have a way to abort and flush callbacks in in-flight operations.
-  ResetComponents();
-
-  base::PostTaskAndReplyWithResult(
-      blocking_task_runner_.get(),
-      FROM_HERE,
-      base::Bind(&ResetOnBlockingPool, resource_metadata_, cache_),
-      callback);
-}
-
-void FileSystem::ResetComponents() {
-  file_system::OperationDelegate* delegate = this;
-
-  about_resource_loader_ =
-      std::make_unique<internal::AboutResourceLoader>(scheduler_);
-  loader_controller_ = std::make_unique<internal::LoaderController>();
-
-  default_corpus_change_list_loader_ =
-      std::make_unique<internal::DefaultCorpusChangeListLoader>(
-          logger_, blocking_task_runner_.get(), resource_metadata_, scheduler_,
-          about_resource_loader_.get(), loader_controller_.get(), clock_);
-
-  default_corpus_change_list_loader_->AddChangeListLoaderObserver(this);
-  default_corpus_change_list_loader_->AddTeamDriveListObserver(this);
-
-  sync_client_ = std::make_unique<internal::SyncClient>(
-      blocking_task_runner_.get(), delegate, scheduler_, resource_metadata_,
-      cache_, loader_controller_.get(), temporary_file_directory_);
-
-  team_drive_operation_queue_ =
-      std::make_unique<internal::DriveBackgroundOperationQueue<
-          internal::TeamDriveChangeListLoader>>(
-          kTeamDriveBackgroundOperationQPS);
-
-  copy_operation_ = std::make_unique<file_system::CopyOperation>(
-      blocking_task_runner_.get(), delegate, scheduler_, resource_metadata_,
-      cache_);
-  create_directory_operation_ =
-      std::make_unique<file_system::CreateDirectoryOperation>(
-          blocking_task_runner_.get(), delegate, resource_metadata_);
-  create_file_operation_ = std::make_unique<file_system::CreateFileOperation>(
-      blocking_task_runner_.get(), delegate, resource_metadata_);
-  move_operation_ = std::make_unique<file_system::MoveOperation>(
-      blocking_task_runner_.get(), delegate, resource_metadata_);
-  open_file_operation_ = std::make_unique<file_system::OpenFileOperation>(
-      blocking_task_runner_.get(), delegate, scheduler_, resource_metadata_,
-      cache_, temporary_file_directory_);
-  remove_operation_ = std::make_unique<file_system::RemoveOperation>(
-      blocking_task_runner_.get(), delegate, resource_metadata_, cache_);
-  touch_operation_ = std::make_unique<file_system::TouchOperation>(
-      blocking_task_runner_.get(), delegate, resource_metadata_);
-  truncate_operation_ = std::make_unique<file_system::TruncateOperation>(
-      blocking_task_runner_.get(), delegate, scheduler_, resource_metadata_,
-      cache_, temporary_file_directory_);
-  download_operation_ = std::make_unique<file_system::DownloadOperation>(
-      blocking_task_runner_.get(), delegate, scheduler_, resource_metadata_,
-      cache_, temporary_file_directory_);
-  search_operation_ = std::make_unique<file_system::SearchOperation>(
-      blocking_task_runner_.get(), scheduler_, resource_metadata_,
-      loader_controller_.get());
-  get_file_for_saving_operation_ =
-      std::make_unique<file_system::GetFileForSavingOperation>(
-
-          logger_, blocking_task_runner_.get(), delegate, scheduler_,
-          resource_metadata_, cache_, temporary_file_directory_);
-  set_property_operation_ = std::make_unique<file_system::SetPropertyOperation>(
-      blocking_task_runner_.get(), delegate, resource_metadata_);
-}
-
-void FileSystem::CheckForUpdates() {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-  DVLOG(1) << "CheckForUpdates";
-
-  size_t num_callbacks = team_drive_change_list_loaders_.size() + 1;
-
-  base::RepeatingClosure closure = base::BarrierClosure(
-      num_callbacks, base::BindOnce(&FileSystem::OnUpdateCompleted,
-                                    weak_ptr_factory_.GetWeakPtr()));
-
-  for (auto& team_drive : team_drive_change_list_loaders_) {
-    auto update_checked_closure =
-        base::Bind(&FileSystem::OnUpdateChecked, weak_ptr_factory_.GetWeakPtr(),
-                   team_drive.first, closure);
-    if (!team_drive.second->IsRefreshing()) {
-      team_drive_operation_queue_->AddOperation(
-          team_drive.second->GetWeakPtr(),
-          base::BindOnce(&internal::TeamDriveChangeListLoader::CheckForUpdates,
-                         team_drive.second->GetWeakPtr()),
-          update_checked_closure);
-    } else {
-      // If the change list loader is refreshing, then calling CheckForUpdates
-      // will just add the callback to a queue to be called when the refresh
-      // is complete.
-      team_drive.second->CheckForUpdates(update_checked_closure);
-    }
-  }
-
-  default_corpus_change_list_loader_->CheckForUpdates(
-      base::Bind(&FileSystem::OnUpdateChecked, weak_ptr_factory_.GetWeakPtr(),
-                 std::string(), closure));
-}
-
-void FileSystem::CheckForUpdates(const std::set<std::string>& ids) {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-
-  base::RepeatingClosure closure = base::BarrierClosure(
-      ids.size(), base::BindOnce(&FileSystem::OnUpdateCompleted,
-                                 weak_ptr_factory_.GetWeakPtr()));
-
-  for (const auto& id : ids) {
-    if (id.empty()) {
-      default_corpus_change_list_loader_->CheckForUpdates(
-          base::Bind(&FileSystem::OnUpdateChecked,
-                     weak_ptr_factory_.GetWeakPtr(), std::string(), closure));
-    } else {
-      auto it = team_drive_change_list_loaders_.find(id);
-
-      // It is possible for the team drive to have been deleted by the time we
-      // receive the push notification.
-      if (it != team_drive_change_list_loaders_.end()) {
-        auto update_checked_closure =
-            base::Bind(&FileSystem::OnUpdateChecked,
-                       weak_ptr_factory_.GetWeakPtr(), it->first, closure);
-        if (!it->second->IsRefreshing()) {
-          team_drive_operation_queue_->AddOperation(
-              it->second->GetWeakPtr(),
-              base::BindOnce(
-                  &internal::TeamDriveChangeListLoader::CheckForUpdates,
-                  it->second->GetWeakPtr()),
-              update_checked_closure);
-        } else {
-          // If the change list loader is refreshing, then calling
-          // CheckForUpdates will just add the callback to a queue to be called
-          // when the refresh is complete.
-          it->second->CheckForUpdates(update_checked_closure);
-        }
-      } else {
-        closure.Run();
-      }
-    }
-  }
-}
-
-void FileSystem::OnUpdateChecked(const std::string& team_drive_id,
-                                 const base::RepeatingClosure& closure,
-                                 FileError error) {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-  DVLOG(1) << "CheckForUpdates finished: " << FileErrorToString(error);
-
-  last_update_metadata_[team_drive_id].last_update_check_error = error;
-  last_update_metadata_[team_drive_id].last_update_check_time =
-      base::Time::Now();
-  closure.Run();
-}
-
-void FileSystem::OnUpdateCompleted() {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-}
-
-void FileSystem::AddObserver(FileSystemObserver* observer) {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-  observers_.AddObserver(observer);
-}
-
-void FileSystem::RemoveObserver(FileSystemObserver* observer) {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-  observers_.RemoveObserver(observer);
-}
-
-void FileSystem::TransferFileFromLocalToRemote(
-    const base::FilePath& local_src_file_path,
-    const base::FilePath& remote_dest_file_path,
-    const FileOperationCallback& callback) {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-  DCHECK(callback);
-  copy_operation_->TransferFileFromLocalToRemote(local_src_file_path,
-                                                 remote_dest_file_path,
-                                                 callback);
-}
-
-void FileSystem::Copy(const base::FilePath& src_file_path,
-                      const base::FilePath& dest_file_path,
-                      bool preserve_last_modified,
-                      const FileOperationCallback& callback) {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-  DCHECK(callback);
-  copy_operation_->Copy(
-      src_file_path, dest_file_path, preserve_last_modified, callback);
-}
-
-void FileSystem::Move(const base::FilePath& src_file_path,
-                      const base::FilePath& dest_file_path,
-                      const FileOperationCallback& callback) {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-  DCHECK(callback);
-  move_operation_->Move(src_file_path, dest_file_path, callback);
-}
-
-void FileSystem::Remove(const base::FilePath& file_path,
-                        bool is_recursive,
-                        const FileOperationCallback& callback) {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-  DCHECK(callback);
-  remove_operation_->Remove(file_path, is_recursive, callback);
-}
-
-void FileSystem::CreateDirectory(
-    const base::FilePath& directory_path,
-    bool is_exclusive,
-    bool is_recursive,
-    const FileOperationCallback& callback) {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-  DCHECK(callback);
-
-  CreateDirectoryParams params;
-  params.directory_path = directory_path;
-  params.is_exclusive = is_exclusive;
-  params.is_recursive = is_recursive;
-  params.callback = callback;
-
-  // Ensure its parent directory is loaded to the local metadata.
-  ReadDirectory(directory_path.DirName(),
-                ReadDirectoryEntriesCallback(),
-                base::Bind(&FileSystem::CreateDirectoryAfterRead,
-                           weak_ptr_factory_.GetWeakPtr(), params));
-}
-
-void FileSystem::CreateDirectoryAfterRead(const CreateDirectoryParams& params,
-                                          FileError error) {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-  DCHECK(params.callback);
-
-  DVLOG_IF(1, error != FILE_ERROR_OK) << "ReadDirectory failed. "
-                                      << FileErrorToString(error);
-
-  create_directory_operation_->CreateDirectory(
-      params.directory_path, params.is_exclusive, params.is_recursive,
-      params.callback);
-}
-
-void FileSystem::CreateFile(const base::FilePath& file_path,
-                            bool is_exclusive,
-                            const std::string& mime_type,
-                            const FileOperationCallback& callback) {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-  DCHECK(callback);
-  create_file_operation_->CreateFile(
-      file_path, is_exclusive, mime_type, callback);
-}
-
-void FileSystem::TouchFile(const base::FilePath& file_path,
-                           const base::Time& last_access_time,
-                           const base::Time& last_modified_time,
-                           const FileOperationCallback& callback) {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-  DCHECK(callback);
-  touch_operation_->TouchFile(
-      file_path, last_access_time, last_modified_time, callback);
-}
-
-void FileSystem::TruncateFile(const base::FilePath& file_path,
-                              int64_t length,
-                              const FileOperationCallback& callback) {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-  DCHECK(callback);
-  truncate_operation_->Truncate(file_path, length, callback);
-}
-
-void FileSystem::Pin(const base::FilePath& file_path,
-                     const FileOperationCallback& callback) {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-  DCHECK(callback);
-
-  std::string* local_id = new std::string;
-  base::PostTaskAndReplyWithResult(
-      blocking_task_runner_.get(),
-      FROM_HERE,
-      base::Bind(&PinInternal, resource_metadata_, cache_, file_path, local_id),
-      base::Bind(&FileSystem::FinishPin,
-                 weak_ptr_factory_.GetWeakPtr(),
-                 callback,
-                 base::Owned(local_id)));
-}
-
-void FileSystem::FinishPin(const FileOperationCallback& callback,
-                           const std::string* local_id,
-                           FileError error) {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-  DCHECK(callback);
-
-  if (error == FILE_ERROR_OK)
-    sync_client_->AddFetchTask(*local_id);
-  callback.Run(error);
-}
-
-void FileSystem::Unpin(const base::FilePath& file_path,
-                       const FileOperationCallback& callback) {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-  DCHECK(callback);
-
-  std::string* local_id = new std::string;
-  base::PostTaskAndReplyWithResult(
-      blocking_task_runner_.get(),
-      FROM_HERE,
-      base::Bind(
-          &UnpinInternal, resource_metadata_, cache_, file_path, local_id),
-      base::Bind(&FileSystem::FinishUnpin,
-                 weak_ptr_factory_.GetWeakPtr(),
-                 callback,
-                 base::Owned(local_id)));
-}
-
-void FileSystem::FinishUnpin(const FileOperationCallback& callback,
-                             const std::string* local_id,
-                             FileError error) {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-  DCHECK(callback);
-
-  if (error == FILE_ERROR_OK)
-    sync_client_->RemoveFetchTask(*local_id);
-  callback.Run(error);
-}
-
-void FileSystem::GetFile(const base::FilePath& file_path,
-                         GetFileCallback callback) {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-  DCHECK(callback);
-
-  download_operation_->EnsureFileDownloadedByPath(
-      file_path, ClientContext(USER_INITIATED),
-      GetFileContentInitializedCallback(), google_apis::GetContentCallback(),
-      std::move(callback));
-}
-
-void FileSystem::GetFileForSaving(const base::FilePath& file_path,
-                                  GetFileCallback callback) {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-  DCHECK(callback);
-
-  get_file_for_saving_operation_->GetFileForSaving(file_path,
-                                                   std::move(callback));
-}
-
-base::Closure FileSystem::GetFileContent(
-    const base::FilePath& file_path,
-    GetFileContentInitializedCallback initialized_callback,
-    const google_apis::GetContentCallback& get_content_callback,
-    const FileOperationCallback& completion_callback) {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-  DCHECK(initialized_callback);
-  DCHECK(get_content_callback);
-  DCHECK(completion_callback);
-
-  return download_operation_->EnsureFileDownloadedByPath(
-      file_path, ClientContext(USER_INITIATED), std::move(initialized_callback),
-      get_content_callback,
-      base::Bind(&GetFileCallbackToFileOperationCallbackAdapter,
-                 completion_callback));
-}
-
-void FileSystem::GetResourceEntry(const base::FilePath& file_path,
-                                  GetResourceEntryCallback callback) {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-  DCHECK(callback);
-
-  ReadDirectory(file_path.DirName(), ReadDirectoryEntriesCallback(),
-                base::Bind(&FileSystem::GetResourceEntryAfterRead,
-                           weak_ptr_factory_.GetWeakPtr(), file_path,
-                           base::Passed(std::move(callback))));
-}
-
-void FileSystem::GetResourceEntryAfterRead(const base::FilePath& file_path,
-                                           GetResourceEntryCallback callback,
-                                           FileError error) {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-  DCHECK(callback);
-
-  DVLOG_IF(1, error != FILE_ERROR_OK) << "ReadDirectory failed. "
-                                      << FileErrorToString(error);
-
-  std::unique_ptr<ResourceEntry> entry(new ResourceEntry);
-  ResourceEntry* entry_ptr = entry.get();
-  base::PostTaskAndReplyWithResult(
-      blocking_task_runner_.get(), FROM_HERE,
-      base::BindOnce(&GetLocallyStoredResourceEntry, resource_metadata_, cache_,
-                     file_path, entry_ptr),
-      base::BindOnce(&RunGetResourceEntryCallback, std::move(callback),
-                     std::move(entry)));
-}
-
-void FileSystem::ReadDirectory(
-    const base::FilePath& directory_path,
-    ReadDirectoryEntriesCallback entries_callback,
-    const FileOperationCallback& completion_callback) {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-  DCHECK(completion_callback);
-
-  if (util::GetDriveTeamDrivesRootPath().IsParent(directory_path)) {
-    // If we do not match a single team drive then we will run the default
-    // corpus loader to read the directory.
-    for (auto& team_drive_loader : team_drive_change_list_loaders_) {
-      const base::FilePath& team_drive_path =
-          team_drive_loader.second->root_entry_path();
-      if (team_drive_path == directory_path ||
-          team_drive_path.IsParent(directory_path)) {
-        team_drive_loader.second->ReadDirectory(
-            directory_path, std::move(entries_callback), completion_callback);
-        return;
-      }
-    }
-  }
-  // Fall through to the default corpus loader if no team drive loader is found.
-  // We do not refresh the list of team drives from the server until the first
-  // ReadDirectory is called on the default corpus change list loader.
-  default_corpus_change_list_loader_->ReadDirectory(
-      directory_path, std::move(entries_callback), completion_callback);
-}
-
-void FileSystem::GetAvailableSpace(GetAvailableSpaceCallback callback) {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-  DCHECK(callback);
-
-  about_resource_loader_->GetAboutResource(base::Bind(
-      &FileSystem::OnGetAboutResource, weak_ptr_factory_.GetWeakPtr(),
-      base::Passed(std::move(callback))));
-}
-
-void FileSystem::OnGetAboutResource(
-    GetAvailableSpaceCallback callback,
-    google_apis::DriveApiErrorCode status,
-    std::unique_ptr<google_apis::AboutResource> about_resource) {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-  DCHECK(callback);
-
-  FileError error = GDataToFileError(status);
-  if (error != FILE_ERROR_OK) {
-    std::move(callback).Run(error, -1, -1);
-    return;
-  }
-  DCHECK(about_resource);
-
-  std::move(callback).Run(FILE_ERROR_OK, about_resource->quota_bytes_total(),
-                          about_resource->quota_bytes_used_aggregate());
-}
-
-void FileSystem::Search(const std::string& search_query,
-                        const GURL& next_link,
-                        SearchCallback callback) {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-  DCHECK(callback);
-  search_operation_->Search(search_query, next_link, std::move(callback));
-}
-
-void FileSystem::SearchMetadata(const std::string& query,
-                                int options,
-                                int at_most_num_matches,
-                                MetadataSearchOrder order,
-                                SearchMetadataCallback callback) {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-
-  drive::internal::SearchMetadata(
-      blocking_task_runner_, resource_metadata_, query,
-      base::Bind(&drive::internal::MatchesType, options), at_most_num_matches,
-      order, std::move(callback));
-}
-
-void FileSystem::SearchByHashes(const std::set<std::string>& hashes,
-                                SearchByHashesCallback callback) {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-  drive::internal::SearchMetadata(
-      blocking_task_runner_, resource_metadata_,
-      /* any file name */ "", base::Bind(&CheckHashes, hashes),
-      std::numeric_limits<size_t>::max(),
-      drive::MetadataSearchOrder::LAST_ACCESSED,
-      base::BindOnce(&RunSearchByHashesCallback, std::move(callback)));
-}
-
-void FileSystem::OnFileChangedByOperation(const FileChange& changed_files) {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-
-  for (auto& observer : observers_)
-    observer.OnFileChanged(changed_files);
-}
-
-void FileSystem::OnEntryUpdatedByOperation(const ClientContext& context,
-                                           const std::string& local_id) {
-  sync_client_->AddUpdateTask(context, local_id);
-}
-
-void FileSystem::OnDriveSyncError(file_system::DriveSyncErrorType type,
-                                  const std::string& local_id) {
-  base::FilePath* file_path = new base::FilePath;
-  base::PostTaskAndReplyWithResult(
-      blocking_task_runner_.get(),
-      FROM_HERE,
-      base::Bind(&internal::ResourceMetadata::GetFilePath,
-                 base::Unretained(resource_metadata_),
-                 local_id,
-                 file_path),
-      base::Bind(&FileSystem::OnDriveSyncErrorAfterGetFilePath,
-                 weak_ptr_factory_.GetWeakPtr(),
-                 type,
-                 base::Owned(file_path)));
-}
-
-void FileSystem::OnDriveSyncErrorAfterGetFilePath(
-    file_system::DriveSyncErrorType type,
-    const base::FilePath* file_path,
-    FileError error) {
-  if (error != FILE_ERROR_OK)
-    return;
-  for (auto& observer : observers_)
-    observer.OnDriveSyncError(type, *file_path);
-}
-
-bool FileSystem::WaitForSyncComplete(const std::string& local_id,
-                                     const FileOperationCallback& callback) {
-  return sync_client_->WaitForUpdateTaskToComplete(local_id, callback);
-}
-
-void FileSystem::OnDirectoryReloaded(const base::FilePath& directory_path) {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-
-  for (auto& observer : observers_)
-    observer.OnDirectoryChanged(directory_path);
-}
-
-void FileSystem::OnFileChanged(const FileChange& changed_files) {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-
-  for (auto& observer : observers_)
-    observer.OnFileChanged(changed_files);
-}
-
-void FileSystem::OnTeamDrivesChanged(const FileChange& changed_team_drives) {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-  std::set<std::string> added_team_drives;
-  std::set<std::string> removed_team_drives;
-
-  for (const auto& entry : changed_team_drives.map()) {
-    for (const auto& change : entry.second.list()) {
-      DCHECK(!change.team_drive_id().empty());
-      if (change.IsDelete()) {
-        if (team_drive_change_list_loaders_.erase(change.team_drive_id()) > 0) {
-          // If we were tracking the update status we can remove that as well.
-          last_update_metadata_.erase(change.team_drive_id());
-          removed_team_drives.insert(change.team_drive_id());
-        }
-      } else if (change.IsAddOrUpdate()) {
-        // If this is an update (e.g. a renamed team drive), then just erase the
-        // existing entry so we can re-add it with the new path.
-        team_drive_change_list_loaders_.erase(change.team_drive_id());
-
-        auto loader = std::make_unique<internal::TeamDriveChangeListLoader>(
-            change.team_drive_id(), entry.first, logger_,
-            blocking_task_runner_.get(), resource_metadata_, scheduler_,
-            loader_controller_.get());
-        loader->AddChangeListLoaderObserver(this);
-        team_drive_operation_queue_->AddOperation(
-            loader->GetWeakPtr(),
-            base::BindOnce(&internal::TeamDriveChangeListLoader::LoadIfNeeded,
-                           loader->GetWeakPtr()),
-            base::DoNothing());
-        team_drive_change_list_loaders_.emplace(change.team_drive_id(),
-                                                std::move(loader));
-        added_team_drives.insert(change.team_drive_id());
-      }
-    }
-  }
-  for (auto& observer : observers_) {
-    observer.OnTeamDrivesUpdated(added_team_drives, removed_team_drives);
-  }
-}
-
-void FileSystem::OnLoadFromServerComplete() {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-  sync_client_->StartCheckingExistingPinnedFiles();
-}
-
-void FileSystem::OnInitialLoadComplete() {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-  blocking_task_runner_->PostTask(
-      FROM_HERE, base::BindOnce(&internal::RemoveStaleCacheFiles, cache_,
-                                resource_metadata_));
-  sync_client_->StartProcessingBacklog();
-}
-
-void FileSystem::OnTeamDriveListLoaded(
-    const std::vector<internal::TeamDrive>& team_drives_list,
-    const std::vector<internal::TeamDrive>& added_team_drives,
-    const std::vector<internal::TeamDrive>& removed_team_drives) {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-
-  for (auto& team_drive_loader : team_drive_change_list_loaders_) {
-    team_drive_loader.second->RemoveChangeListLoaderObserver(this);
-  }
-  team_drive_change_list_loaders_.clear();
-
-  std::set<std::string> added_team_drives_ids;
-  for (const auto& team_drive : team_drives_list) {
-    auto loader = std::make_unique<internal::TeamDriveChangeListLoader>(
-        team_drive.team_drive_id(), team_drive.team_drive_path(), logger_,
-        blocking_task_runner_.get(), resource_metadata_, scheduler_,
-        loader_controller_.get());
-    loader->AddChangeListLoaderObserver(this);
-    team_drive_operation_queue_->AddOperation(
-        loader->GetWeakPtr(),
-        base::BindOnce(&internal::TeamDriveChangeListLoader::LoadIfNeeded,
-                       loader->GetWeakPtr()),
-        base::DoNothing());
-    team_drive_change_list_loaders_.emplace(team_drive.team_drive_id(),
-                                            std::move(loader));
-    added_team_drives_ids.insert(team_drive.team_drive_id());
-  }
-  for (auto& observer : observers_) {
-    observer.OnTeamDrivesUpdated(added_team_drives_ids, {});
-  }
-}
-
-void FileSystem::GetMetadata(GetFilesystemMetadataCallback callback) {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-  DCHECK(callback);
-
-  FileSystemMetadata* metadata = new FileSystemMetadata();
-  std::map<std::string, FileSystemMetadata>* team_drive_metadata =
-      new std::map<std::string, FileSystemMetadata>();
-
-  size_t num_callbacks = team_drive_change_list_loaders_.size() + 1;
-
-  base::RepeatingClosure closure = base::BarrierClosure(
-      num_callbacks,
-      base::BindOnce(&FileSystem::OnGetMetadata, weak_ptr_factory_.GetWeakPtr(),
-                     std::move(callback), base::Owned(metadata),
-                     base::Owned(team_drive_metadata)));
-
-  metadata->refreshing = default_corpus_change_list_loader_->IsRefreshing();
-  metadata->path = util::GetDriveGrandRootPath().value();
-  metadata->last_update_check_time =
-      last_update_metadata_[util::kTeamDriveIdDefaultCorpus]
-          .last_update_check_time;
-  metadata->last_update_check_error =
-      last_update_metadata_[util::kTeamDriveIdDefaultCorpus]
-          .last_update_check_error;
-
-  base::PostTaskAndReplyWithResult(
-      blocking_task_runner_.get(), FROM_HERE,
-      base::Bind(&internal::GetStartPageToken,
-                 base::Unretained(resource_metadata_),
-                 util::kTeamDriveIdDefaultCorpus,
-                 base::Unretained(&(metadata->start_page_token))),
-      base::Bind(&OnGetStartPageToken, closure));
-
-  for (auto& team_drive : team_drive_change_list_loaders_) {
-    const FileSystemMetadata& last_update_metadata =
-        last_update_metadata_[team_drive.first];
-    FileSystemMetadata& md = (*team_drive_metadata)[team_drive.first];
-
-    md.refreshing = team_drive.second->IsRefreshing();
-    md.path = team_drive.second->root_entry_path().value();
-    md.last_update_check_time = last_update_metadata.last_update_check_time;
-    md.last_update_check_error = last_update_metadata.last_update_check_error;
-
-    base::PostTaskAndReplyWithResult(
-        blocking_task_runner_.get(), FROM_HERE,
-        base::Bind(&internal::GetStartPageToken,
-                   base::Unretained(resource_metadata_), team_drive.first,
-                   base::Unretained(&(md.start_page_token))),
-        base::Bind(&OnGetStartPageToken, closure));
-  }
-}
-
-void FileSystem::OnGetMetadata(
-    GetFilesystemMetadataCallback callback,
-    drive::FileSystemMetadata* default_corpus_metadata,
-    std::map<std::string, drive::FileSystemMetadata>* team_drive_metadata) {
-  DCHECK(callback);
-  DCHECK(default_corpus_metadata);
-  DCHECK(team_drive_metadata);
-
-  std::move(callback).Run(*default_corpus_metadata, *team_drive_metadata);
-}
-
-void FileSystem::MarkCacheFileAsMounted(const base::FilePath& drive_file_path,
-                                        MarkMountedCallback callback) {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-  DCHECK(callback);
-
-  base::FilePath* cache_file_path = new base::FilePath;
-  base::PostTaskAndReplyWithResult(
-      blocking_task_runner_.get(), FROM_HERE,
-      base::BindOnce(&MarkCacheFileAsMountedInternal, resource_metadata_,
-                     cache_, drive_file_path, cache_file_path),
-      base::BindOnce(&RunMarkMountedCallback, std::move(callback),
-                     base::Owned(cache_file_path)));
-}
-
-void FileSystem::IsCacheFileMarkedAsMounted(
-    const base::FilePath& drive_file_path,
-    IsMountedCallback callback) {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-  DCHECK(callback);
-
-  bool* is_mounted = new bool(false);
-  base::PostTaskAndReplyWithResult(
-      blocking_task_runner_.get(), FROM_HERE,
-      base::BindOnce(&IsCacheFileMarkedAsMountedInternal, resource_metadata_,
-                     cache_, drive_file_path, is_mounted),
-      base::BindOnce(&RunIsMountedCallback, std::move(callback),
-                     base::Owned(is_mounted)));
-}
-
-void FileSystem::MarkCacheFileAsUnmounted(
-    const base::FilePath& cache_file_path,
-    const FileOperationCallback& callback) {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-  DCHECK(callback);
-
-  if (!cache_->IsUnderFileCacheDirectory(cache_file_path)) {
-    callback.Run(FILE_ERROR_FAILED);
-    return;
-  }
-
-  base::PostTaskAndReplyWithResult(
-      blocking_task_runner_.get(),
-      FROM_HERE,
-      base::Bind(&internal::FileCache::MarkAsUnmounted,
-                 base::Unretained(cache_),
-                 cache_file_path),
-      callback);
-}
-
-void FileSystem::AddPermission(const base::FilePath& drive_file_path,
-                               const std::string& email,
-                               google_apis::drive::PermissionRole role,
-                               const FileOperationCallback& callback) {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-  DCHECK(callback);
-
-  // Resolve the resource id.
-  ResourceEntry* const entry = new ResourceEntry;
-  base::PostTaskAndReplyWithResult(
-      blocking_task_runner_.get(),
-      FROM_HERE,
-      base::Bind(&internal::ResourceMetadata::GetResourceEntryByPath,
-                 base::Unretained(resource_metadata_),
-                 drive_file_path,
-                 entry),
-      base::Bind(&FileSystem::AddPermissionAfterGetResourceEntry,
-                 weak_ptr_factory_.GetWeakPtr(),
-                 email,
-                 role,
-                 callback,
-                 base::Owned(entry)));
-}
-
-void FileSystem::AddPermissionAfterGetResourceEntry(
-    const std::string& email,
-    google_apis::drive::PermissionRole role,
-    const FileOperationCallback& callback,
-    ResourceEntry* entry,
-    FileError error) {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-
-  if (error != FILE_ERROR_OK) {
-    callback.Run(error);
-    return;
-  }
-
-  scheduler_->AddPermission(
-      entry->resource_id(),
-      email,
-      role,
-      base::Bind(&RunFileOperationCallbackAsEntryActionCallback, callback));
-}
-
-void FileSystem::SetProperty(
-    const base::FilePath& drive_file_path,
-    google_apis::drive::Property::Visibility visibility,
-    const std::string& key,
-    const std::string& value,
-    const FileOperationCallback& callback) {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-  DCHECK(callback);
-
-  set_property_operation_->SetProperty(drive_file_path, visibility, key, value,
-                                       callback);
-}
-
-void FileSystem::OpenFile(const base::FilePath& file_path,
-                          OpenMode open_mode,
-                          const std::string& mime_type,
-                          OpenFileCallback callback) {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-  DCHECK(callback);
-
-  open_file_operation_->OpenFile(file_path, open_mode, mime_type,
-                                 std::move(callback));
-}
-
-void FileSystem::GetPathFromResourceId(const std::string& resource_id,
-                                       const GetFilePathCallback& callback) {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-  DCHECK(callback);
-
-  base::FilePath* const file_path = new base::FilePath();
-  base::PostTaskAndReplyWithResult(
-      blocking_task_runner_.get(),
-      FROM_HERE,
-      base::Bind(&GetPathFromResourceIdOnBlockingPool,
-                 resource_metadata_,
-                 resource_id,
-                 file_path),
-      base::Bind(&GetPathFromResourceIdAfterGetPath,
-                 base::Owned(file_path),
-                 callback));
-}
-
-void FileSystem::FreeDiskSpaceIfNeededFor(
-    int64_t num_bytes,
-    const FreeDiskSpaceCallback& callback) {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-  DCHECK(callback);
-  base::PostTaskAndReplyWithResult(
-      blocking_task_runner_.get(), FROM_HERE,
-      base::Bind(&FreeDiskSpaceIfNeededForOnBlockingPool, cache_, num_bytes),
-      callback);
-}
-
-void FileSystem::CalculateCacheSize(const CacheSizeCallback& callback) {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-  DCHECK(callback);
-  base::PostTaskAndReplyWithResult(
-      blocking_task_runner_.get(), FROM_HERE,
-      base::Bind(&CalculateCacheSizeOnBlockingPool, cache_), callback);
-}
-
-void FileSystem::CalculateEvictableCacheSize(
-    const CacheSizeCallback& callback) {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-  DCHECK(callback);
-  base::PostTaskAndReplyWithResult(
-      blocking_task_runner_.get(), FROM_HERE,
-      base::Bind(&CalculateEvictableCacheSizeOnBlockingPool, cache_), callback);
-}
-}  // namespace drive
diff --git a/components/drive/chromeos/file_system.h b/components/drive/chromeos/file_system.h
deleted file mode 100644
index 6a238f3c3..0000000
--- a/components/drive/chromeos/file_system.h
+++ /dev/null
@@ -1,336 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef COMPONENTS_DRIVE_CHROMEOS_FILE_SYSTEM_H_
-#define COMPONENTS_DRIVE_CHROMEOS_FILE_SYSTEM_H_
-
-#include <stdint.h>
-
-#include <map>
-#include <memory>
-#include <set>
-#include <string>
-#include <vector>
-
-#include "base/macros.h"
-#include "base/memory/ref_counted.h"
-#include "base/memory/weak_ptr.h"
-#include "base/observer_list.h"
-#include "base/threading/thread_checker.h"
-#include "base/time/default_clock.h"
-#include "components/drive/chromeos/change_list_loader_observer.h"
-#include "components/drive/chromeos/drive_operation_queue.h"
-#include "components/drive/chromeos/file_system/operation_delegate.h"
-#include "components/drive/chromeos/file_system_interface.h"
-#include "components/drive/chromeos/team_drive_change_list_loader.h"
-#include "components/drive/chromeos/team_drive_list_observer.h"
-#include "google_apis/drive/drive_api_error_codes.h"
-
-namespace base {
-class SequencedTaskRunner;
-}  // namespace base
-
-namespace google_apis {
-class AboutResource;
-class ResourceEntry;
-}  // namespace google_apis
-
-namespace drive {
-struct ClientContext;
-class EventLogger;
-class FileSystemObserver;
-class JobScheduler;
-
-namespace internal {
-class AboutResourceLoader;
-class DriveChangeListLoader;
-class FileCache;
-class LoaderController;
-class ResourceMetadata;
-class SyncClient;
-class TeamDrive;
-}  // namespace internal
-
-namespace file_system {
-class CopyOperation;
-class CreateDirectoryOperation;
-class CreateFileOperation;
-class DownloadOperation;
-class GetFileForSavingOperation;
-class MoveOperation;
-class OpenFileOperation;
-class RemoveOperation;
-class SearchOperation;
-class SetPropertyOperation;
-class TouchOperation;
-class TruncateOperation;
-}  // namespace file_system
-
-// The production implementation of FileSystemInterface.
-class FileSystem : public FileSystemInterface,
-                   public internal::ChangeListLoaderObserver,
-                   public internal::TeamDriveListObserver,
-                   public file_system::OperationDelegate {
- public:
-  // |clock| can be mocked for testing.
-  FileSystem(EventLogger* logger,
-             internal::FileCache* cache,
-             JobScheduler* scheduler,
-             internal::ResourceMetadata* resource_metadata,
-             base::SequencedTaskRunner* blocking_task_runner,
-             const base::FilePath& temporary_file_directory,
-             const base::Clock* clock = base::DefaultClock::GetInstance());
-  ~FileSystem() override;
-
-  // FileSystemInterface overrides.
-  void AddObserver(FileSystemObserver* observer) override;
-  void RemoveObserver(FileSystemObserver* observer) override;
-  void CheckForUpdates() override;
-  void CheckForUpdates(const std::set<std::string>& ids) override;
-  void Search(const std::string& search_query,
-              const GURL& next_link,
-              SearchCallback callback) override;
-  void SearchMetadata(const std::string& query,
-                      int options,
-                      int at_most_num_matches,
-                      MetadataSearchOrder order,
-                      SearchMetadataCallback callback) override;
-  void SearchByHashes(const std::set<std::string>& hashes,
-                      SearchByHashesCallback callback) override;
-  void TransferFileFromLocalToRemote(
-      const base::FilePath& local_src_file_path,
-      const base::FilePath& remote_dest_file_path,
-      const FileOperationCallback& callback) override;
-  void OpenFile(const base::FilePath& file_path,
-                OpenMode open_mode,
-                const std::string& mime_type,
-                OpenFileCallback callback) override;
-  void Copy(const base::FilePath& src_file_path,
-            const base::FilePath& dest_file_path,
-            bool preserve_last_modified,
-            const FileOperationCallback& callback) override;
-  void Move(const base::FilePath& src_file_path,
-            const base::FilePath& dest_file_path,
-            const FileOperationCallback& callback) override;
-  void Remove(const base::FilePath& file_path,
-              bool is_recursive,
-              const FileOperationCallback& callback) override;
-  void CreateDirectory(const base::FilePath& directory_path,
-                       bool is_exclusive,
-                       bool is_recursive,
-                       const FileOperationCallback& callback) override;
-  void CreateFile(const base::FilePath& file_path,
-                  bool is_exclusive,
-                  const std::string& mime_type,
-                  const FileOperationCallback& callback) override;
-  void TouchFile(const base::FilePath& file_path,
-                 const base::Time& last_access_time,
-                 const base::Time& last_modified_time,
-                 const FileOperationCallback& callback) override;
-  void TruncateFile(const base::FilePath& file_path,
-                    int64_t length,
-                    const FileOperationCallback& callback) override;
-  void Pin(const base::FilePath& file_path,
-           const FileOperationCallback& callback) override;
-  void Unpin(const base::FilePath& file_path,
-             const FileOperationCallback& callback) override;
-  void GetFile(const base::FilePath& file_path,
-               GetFileCallback callback) override;
-  void GetFileForSaving(const base::FilePath& file_path,
-                        GetFileCallback callback) override;
-  base::Closure GetFileContent(
-      const base::FilePath& file_path,
-      GetFileContentInitializedCallback initialized_callback,
-      const google_apis::GetContentCallback& get_content_callback,
-      const FileOperationCallback& completion_callback) override;
-  void GetResourceEntry(const base::FilePath& file_path,
-                        GetResourceEntryCallback callback) override;
-  void ReadDirectory(const base::FilePath& directory_path,
-                     ReadDirectoryEntriesCallback entries_callback,
-                     const FileOperationCallback& completion_callback) override;
-  void GetAvailableSpace(GetAvailableSpaceCallback callback) override;
-  void GetMetadata(GetFilesystemMetadataCallback callback) override;
-  void MarkCacheFileAsMounted(const base::FilePath& drive_file_path,
-                              MarkMountedCallback callback) override;
-  void IsCacheFileMarkedAsMounted(const base::FilePath& drive_file_path,
-                                  IsMountedCallback callback) override;
-  void MarkCacheFileAsUnmounted(const base::FilePath& cache_file_path,
-                                const FileOperationCallback& callback) override;
-  void AddPermission(const base::FilePath& drive_file_path,
-                     const std::string& email,
-                     google_apis::drive::PermissionRole role,
-                     const FileOperationCallback& callback) override;
-  void SetProperty(const base::FilePath& drive_file_path,
-                   google_apis::drive::Property::Visibility visibility,
-                   const std::string& key,
-                   const std::string& value,
-                   const FileOperationCallback& callback) override;
-  void Reset(const FileOperationCallback& callback) override;
-  void GetPathFromResourceId(const std::string& resource_id,
-                             const GetFilePathCallback& callback) override;
-  void FreeDiskSpaceIfNeededFor(int64_t num_bytes,
-                                const FreeDiskSpaceCallback& callback) override;
-  void CalculateCacheSize(const CacheSizeCallback& callback) override;
-  void CalculateEvictableCacheSize(const CacheSizeCallback& callback) override;
-
-  // file_system::OperationDelegate overrides.
-  void OnFileChangedByOperation(const FileChange& changed_files) override;
-  void OnEntryUpdatedByOperation(const ClientContext& context,
-                                 const std::string& local_id) override;
-  void OnDriveSyncError(file_system::DriveSyncErrorType type,
-                        const std::string& local_id) override;
-  bool WaitForSyncComplete(const std::string& local_id,
-                           const FileOperationCallback& callback) override;
-
-  // ChangeListLoader::Observer overrides.
-  // Used to propagate events from ChangeListLoader.
-  void OnDirectoryReloaded(const base::FilePath& directory_path) override;
-  void OnFileChanged(const FileChange& changed_files) override;
-  void OnTeamDrivesChanged(const FileChange& changed_team_drives) override;
-  void OnLoadFromServerComplete() override;
-  void OnInitialLoadComplete() override;
-
-  // TeamDriveListObserver overrides.
-  void OnTeamDriveListLoaded(
-      const std::vector<internal::TeamDrive>& team_drives_list,
-      const std::vector<internal::TeamDrive>& added_team_drives,
-      const std::vector<internal::TeamDrive>& removed_team_drives) override;
-
-  // Used by tests.
-  internal::DriveChangeListLoader* change_list_loader_for_testing() {
-    return default_corpus_change_list_loader_.get();
-  }
-  internal::SyncClient* sync_client_for_testing() { return sync_client_.get(); }
-
-  internal::DriveBackgroundOperationQueue<internal::TeamDriveChangeListLoader>*
-  team_drive_operation_queue_for_testing() {
-    return team_drive_operation_queue_.get();
-  }
-
- private:
-  struct CreateDirectoryParams;
-
-  // Used for initialization and Reset(). (Re-)initializes sub components that
-  // need to be recreated during the reset of resource metadata and the cache.
-  void ResetComponents();
-
-  // Part of CreateDirectory(). Called after ReadDirectory()
-  // is called and made sure that the resource metadata is loaded.
-  void CreateDirectoryAfterRead(const CreateDirectoryParams& params,
-                                FileError error);
-
-  void FinishPin(const FileOperationCallback& callback,
-                 const std::string* local_id,
-                 FileError error);
-
-  void FinishUnpin(const FileOperationCallback& callback,
-                   const std::string* local_id,
-                   FileError error);
-
-  // Callback for handling about resource fetch.
-  void OnGetAboutResource(
-      GetAvailableSpaceCallback callback,
-      google_apis::DriveApiErrorCode status,
-      std::unique_ptr<google_apis::AboutResource> about_resource);
-
-  // Stores any file error as a result of Checking updates.
-  void OnUpdateChecked(const std::string& team_drive_id,
-                       const base::RepeatingClosure& closure,
-                       FileError error);
-
-  // Part of CheckForUpdates(). Called when
-  // ChangeListLoader::CheckForUpdates() is complete.
-  void OnUpdateCompleted();
-
-  // Part of GetResourceEntry().
-  // Called when ReadDirectory() is complete.
-  void GetResourceEntryAfterRead(const base::FilePath& file_path,
-                                 GetResourceEntryCallback callback,
-                                 FileError error);
-
-  void OnGetMetadata(
-      GetFilesystemMetadataCallback callback,
-      drive::FileSystemMetadata* default_corpus_metadata,
-      std::map<std::string, drive::FileSystemMetadata>* team_drive_metadata);
-
-  // Part of AddPermission.
-  void AddPermissionAfterGetResourceEntry(
-      const std::string& email,
-      google_apis::drive::PermissionRole role,
-      const FileOperationCallback& callback,
-      ResourceEntry* entry,
-      FileError error);
-
-  // Part of OnDriveSyncError().
-  virtual void OnDriveSyncErrorAfterGetFilePath(
-      file_system::DriveSyncErrorType type,
-      const base::FilePath* file_path,
-      FileError error);
-
-  // Sub components owned by DriveIntegrationService.
-  EventLogger* logger_;
-  internal::FileCache* cache_;
-  JobScheduler* scheduler_;
-  internal::ResourceMetadata* resource_metadata_;
-
-  // Stores debug update metadata for default corpus and team drive.
-  std::map<std::string, FileSystemMetadata> last_update_metadata_;
-
-  // Used to load about resource.
-  std::unique_ptr<internal::AboutResourceLoader> about_resource_loader_;
-
-  // Used to control ChangeListLoader.
-  std::unique_ptr<internal::LoaderController> loader_controller_;
-
-  // Used to retrieve changelists from the default corpus.
-  std::unique_ptr<internal::DriveChangeListLoader>
-      default_corpus_change_list_loader_;
-
-  std::unique_ptr<internal::DriveBackgroundOperationQueue<
-      internal::TeamDriveChangeListLoader>>
-      team_drive_operation_queue_;
-
-  // Used to retrieve changelists for team drives. The key for the map is the
-  // team_drive_id.
-  std::map<std::string, std::unique_ptr<internal::TeamDriveChangeListLoader>>
-      team_drive_change_list_loaders_;
-
-  std::unique_ptr<internal::SyncClient> sync_client_;
-
-  base::ObserverList<FileSystemObserver>::Unchecked observers_;
-
-  scoped_refptr<base::SequencedTaskRunner> blocking_task_runner_;
-
-  base::FilePath temporary_file_directory_;
-
-  const base::Clock* clock_;  // Not owned.
-
-  // Implementation of each file system operation.
-  std::unique_ptr<file_system::CopyOperation> copy_operation_;
-  std::unique_ptr<file_system::CreateDirectoryOperation>
-      create_directory_operation_;
-  std::unique_ptr<file_system::CreateFileOperation> create_file_operation_;
-  std::unique_ptr<file_system::MoveOperation> move_operation_;
-  std::unique_ptr<file_system::OpenFileOperation> open_file_operation_;
-  std::unique_ptr<file_system::RemoveOperation> remove_operation_;
-  std::unique_ptr<file_system::TouchOperation> touch_operation_;
-  std::unique_ptr<file_system::TruncateOperation> truncate_operation_;
-  std::unique_ptr<file_system::DownloadOperation> download_operation_;
-  std::unique_ptr<file_system::SearchOperation> search_operation_;
-  std::unique_ptr<file_system::GetFileForSavingOperation>
-      get_file_for_saving_operation_;
-  std::unique_ptr<file_system::SetPropertyOperation> set_property_operation_;
-
-  THREAD_CHECKER(thread_checker_);
-
-  // Note: This should remain the last member so it'll be destroyed and
-  // invalidate the weak pointers before any other members are destroyed.
-  base::WeakPtrFactory<FileSystem> weak_ptr_factory_{this};
-
-  DISALLOW_COPY_AND_ASSIGN(FileSystem);
-};
-
-}  // namespace drive
-
-#endif  // COMPONENTS_DRIVE_CHROMEOS_FILE_SYSTEM_H_
diff --git a/components/drive/chromeos/file_system/copy_operation.cc b/components/drive/chromeos/file_system/copy_operation.cc
deleted file mode 100644
index 168c28c3..0000000
--- a/components/drive/chromeos/file_system/copy_operation.cc
+++ /dev/null
@@ -1,677 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "components/drive/chromeos/file_system/copy_operation.h"
-
-#include <stdint.h>
-
-#include <string>
-#include <utility>
-
-#include "base/bind.h"
-#include "base/task_runner_util.h"
-#include "components/drive/chromeos/file_cache.h"
-#include "components/drive/chromeos/file_system/create_file_operation.h"
-#include "components/drive/chromeos/file_system/operation_delegate.h"
-#include "components/drive/chromeos/resource_metadata.h"
-#include "components/drive/drive.pb.h"
-#include "components/drive/drive_api_util.h"
-#include "components/drive/file_change.h"
-#include "components/drive/file_system_core_util.h"
-#include "components/drive/job_scheduler.h"
-#include "components/drive/resource_entry_conversion.h"
-#include "google_apis/drive/drive_api_parser.h"
-
-namespace drive {
-namespace file_system {
-
-struct CopyOperation::CopyParams {
-  base::FilePath src_file_path;
-  base::FilePath dest_file_path;
-  bool preserve_last_modified;
-  FileOperationCallback callback;
-  ResourceEntry src_entry;
-  ResourceEntry parent_entry;
-};
-
-// Enum for categorizing where a gdoc represented by a JSON file exists.
-enum JsonGdocLocationType {
-  NOT_IN_METADATA,
-  IS_ORPHAN,
-  HAS_PARENT,
-};
-
-struct CopyOperation::TransferJsonGdocParams {
-  TransferJsonGdocParams(const FileOperationCallback& callback,
-                         const std::string& resource_id,
-                         const ResourceEntry& parent_entry,
-                         const std::string& new_title)
-      : callback(callback),
-        resource_id(resource_id),
-        parent_resource_id(parent_entry.resource_id()),
-        parent_local_id(parent_entry.local_id()),
-        new_title(new_title),
-        location_type(NOT_IN_METADATA) {
-  }
-  // Parameters supplied or calculated from operation arguments.
-  const FileOperationCallback callback;
-  const std::string resource_id;
-  const std::string parent_resource_id;
-  const std::string parent_local_id;
-  const std::string new_title;
-
-  // Values computed during operation.
-  JsonGdocLocationType location_type;  // types where the gdoc file is located.
-  std::string local_id;  // the local_id of the file (if exists in metadata.)
-  base::FilePath changed_path;
-};
-
-namespace {
-
-FileError TryToCopyLocally(internal::ResourceMetadata* metadata,
-                           internal::FileCache* cache,
-                           CopyOperation::CopyParams* params,
-                           std::vector<std::string>* updated_local_ids,
-                           bool* directory_changed,
-                           bool* should_copy_on_server) {
-  FileError error = metadata->GetResourceEntryByPath(params->src_file_path,
-                                                     &params->src_entry);
-  if (error != FILE_ERROR_OK)
-    return error;
-
-  error = metadata->GetResourceEntryByPath(params->dest_file_path.DirName(),
-                                           &params->parent_entry);
-  if (error != FILE_ERROR_OK)
-    return error;
-
-  if (!params->parent_entry.file_info().is_directory())
-    return FILE_ERROR_NOT_A_DIRECTORY;
-
-  // Drive File System doesn't support recursive copy.
-  if (params->src_entry.file_info().is_directory())
-    return FILE_ERROR_NOT_A_FILE;
-
-  // Check destination.
-  ResourceEntry dest_entry;
-  error = metadata->GetResourceEntryByPath(params->dest_file_path, &dest_entry);
-  switch (error) {
-    case FILE_ERROR_OK:
-      // File API spec says it is an error to try to "copy a file to a path
-      // occupied by a directory".
-      if (dest_entry.file_info().is_directory())
-        return FILE_ERROR_INVALID_OPERATION;
-
-      // Move the existing entry to the trash.
-      dest_entry.set_parent_local_id(util::kDriveTrashDirLocalId);
-      error = metadata->RefreshEntry(dest_entry);
-      if (error != FILE_ERROR_OK)
-        return error;
-      updated_local_ids->push_back(dest_entry.local_id());
-      *directory_changed = true;
-      break;
-    case FILE_ERROR_NOT_FOUND:
-      break;
-    default:
-      return error;
-  }
-
-  // If the cache file is not present and the entry exists on the server,
-  // server side copy should be used.
-  if (!params->src_entry.file_specific_info().cache_state().is_present() &&
-      !params->src_entry.resource_id().empty()) {
-    *should_copy_on_server = true;
-    return FILE_ERROR_OK;
-  }
-
-  // Copy locally.
-  ResourceEntry entry;
-  const int64_t now = base::Time::Now().ToInternalValue();
-  const int64_t last_modified =
-      params->preserve_last_modified
-          ? params->src_entry.file_info().last_modified()
-          : now;
-  entry.set_title(params->dest_file_path.BaseName().AsUTF8Unsafe());
-  entry.set_parent_local_id(params->parent_entry.local_id());
-  entry.mutable_file_specific_info()->set_content_mime_type(
-      params->src_entry.file_specific_info().content_mime_type());
-  entry.set_metadata_edit_state(ResourceEntry::DIRTY);
-  entry.set_modification_date(base::Time::Now().ToInternalValue());
-  entry.mutable_file_info()->set_last_modified(last_modified);
-  // preserve_last_modified=true preserves last_modified only.
-  // Regardless of preserve_last_modified's value, last_modified_by_me is
-  // always set to the same value as last_modified.
-  // This means that, even if preserve_last_modified=true, last_modified_by_me
-  // of the new file may differ from that of the original file.
-  // This behavior is due to the limitation in Drive API that we can not
-  // set different timestamps to last_modified and last_modified_by_me.
-  entry.set_last_modified_by_me(last_modified);
-  entry.mutable_file_info()->set_last_accessed(now);
-
-  std::string local_id;
-  error = metadata->AddEntry(entry, &local_id);
-  if (error != FILE_ERROR_OK)
-    return error;
-  updated_local_ids->push_back(local_id);
-  *directory_changed = true;
-
-  if (!params->src_entry.file_specific_info().cache_state().is_present()) {
-    DCHECK(params->src_entry.resource_id().empty());
-    // Locally created empty file may have no cache file.
-    return FILE_ERROR_OK;
-  }
-
-  base::FilePath cache_file_path;
-  error = cache->GetFile(params->src_entry.local_id(), &cache_file_path);
-  if (error != FILE_ERROR_OK)
-    return error;
-
-  return cache->Store(local_id, std::string(), cache_file_path,
-                      internal::FileCache::FILE_OPERATION_COPY);
-}
-
-// Stores the entry returned from the server and returns its path.
-FileError UpdateLocalStateForServerSideOperation(
-    internal::ResourceMetadata* metadata,
-    std::unique_ptr<google_apis::FileResource> file_resource,
-    ResourceEntry* entry,
-    base::FilePath* file_path) {
-  DCHECK(file_resource);
-
-  std::string parent_resource_id;
-  ConvertFileResourceToResourceEntry(*file_resource, entry,
-                                     &parent_resource_id);
-
-  if (parent_resource_id.empty())
-    return FILE_ERROR_NOT_A_FILE;
-
-  std::string parent_local_id;
-  FileError error = metadata->GetIdByResourceId(parent_resource_id,
-                                                &parent_local_id);
-  if (error != FILE_ERROR_OK)
-    return error;
-  entry->set_parent_local_id(parent_local_id);
-
-  std::string local_id;
-  error = metadata->AddEntry(*entry, &local_id);
-  // Depending on timing, the metadata may have inserted via change list
-  // already. So, FILE_ERROR_EXISTS is not an error.
-  if (error == FILE_ERROR_EXISTS)
-    error = metadata->GetIdByResourceId(entry->resource_id(), &local_id);
-
-  if (error != FILE_ERROR_OK)
-    return error;
-
-  return metadata->GetFilePath(local_id, file_path);
-}
-
-// Stores the file at |local_file_path| to the cache as a content of entry at
-// |remote_dest_path|, and marks it dirty.
-FileError UpdateLocalStateForScheduleTransfer(
-    internal::ResourceMetadata* metadata,
-    internal::FileCache* cache,
-    const base::FilePath& local_src_path,
-    const base::FilePath& remote_dest_path,
-    ResourceEntry* entry,
-    std::string* local_id) {
-  FileError error = metadata->GetIdByPath(remote_dest_path, local_id);
-  if (error != FILE_ERROR_OK)
-    return error;
-
-  error = metadata->GetResourceEntryById(*local_id, entry);
-  if (error != FILE_ERROR_OK)
-    return error;
-
-  return cache->Store(*local_id, std::string(), local_src_path,
-                      internal::FileCache::FILE_OPERATION_COPY);
-}
-
-// Gets the file size of the |local_path|, and the ResourceEntry for the parent
-// of |remote_path| to prepare the necessary information for transfer.
-FileError PrepareTransferFileFromLocalToRemote(
-    internal::ResourceMetadata* metadata,
-    const base::FilePath& local_src_path,
-    const base::FilePath& remote_dest_path,
-    std::string* gdoc_resource_id,
-    ResourceEntry* parent_entry) {
-  FileError error = metadata->GetResourceEntryByPath(
-      remote_dest_path.DirName(), parent_entry);
-  if (error != FILE_ERROR_OK)
-    return error;
-
-  // The destination's parent must be a directory.
-  if (!parent_entry->file_info().is_directory())
-    return FILE_ERROR_NOT_A_DIRECTORY;
-
-  // Try to parse GDoc File and extract the resource id, if necessary.
-  // Failing isn't problem. It'd be handled as a regular file, then.
-  if (util::HasHostedDocumentExtension(local_src_path))
-    *gdoc_resource_id = util::ReadResourceIdFromGDocFile(local_src_path);
-  return FILE_ERROR_OK;
-}
-
-// Performs local work before server-side work for transferring JSON-represented
-// gdoc files.
-FileError LocalWorkForTransferJsonGdocFile(
-    internal::ResourceMetadata* metadata,
-    CopyOperation::TransferJsonGdocParams* params) {
-  std::string local_id;
-  FileError error = metadata->GetIdByResourceId(params->resource_id, &local_id);
-  if (error != FILE_ERROR_OK) {
-    params->location_type = NOT_IN_METADATA;
-    return error == FILE_ERROR_NOT_FOUND ? FILE_ERROR_OK : error;
-  }
-
-  ResourceEntry entry;
-  error = metadata->GetResourceEntryById(local_id, &entry);
-  if (error != FILE_ERROR_OK)
-    return error;
-  params->local_id = entry.local_id();
-
-  if (entry.parent_local_id() == util::kDriveOtherDirLocalId) {
-    params->location_type = IS_ORPHAN;
-    entry.set_title(params->new_title);
-    entry.set_parent_local_id(params->parent_local_id);
-    entry.set_metadata_edit_state(ResourceEntry::DIRTY);
-    entry.set_modification_date(base::Time::Now().ToInternalValue());
-    error = metadata->RefreshEntry(entry);
-    if (error != FILE_ERROR_OK)
-      return error;
-    return metadata->GetFilePath(local_id, &params->changed_path);
-  }
-
-  params->location_type = HAS_PARENT;
-  return FILE_ERROR_OK;
-}
-
-}  // namespace
-
-CopyOperation::CopyOperation(base::SequencedTaskRunner* blocking_task_runner,
-                             OperationDelegate* delegate,
-                             JobScheduler* scheduler,
-                             internal::ResourceMetadata* metadata,
-                             internal::FileCache* cache)
-    : blocking_task_runner_(blocking_task_runner),
-      delegate_(delegate),
-      scheduler_(scheduler),
-      metadata_(metadata),
-      cache_(cache),
-      create_file_operation_(
-          new CreateFileOperation(blocking_task_runner, delegate, metadata)) {}
-
-CopyOperation::~CopyOperation() {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-}
-
-void CopyOperation::Copy(const base::FilePath& src_file_path,
-                         const base::FilePath& dest_file_path,
-                         bool preserve_last_modified,
-                         const FileOperationCallback& callback) {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-  DCHECK(callback);
-
-  CopyParams* params = new CopyParams;
-  params->src_file_path = src_file_path;
-  params->dest_file_path = dest_file_path;
-  params->preserve_last_modified = preserve_last_modified;
-  params->callback = callback;
-
-  std::vector<std::string>* updated_local_ids = new std::vector<std::string>;
-  bool* directory_changed = new bool(false);
-  bool* should_copy_on_server = new bool(false);
-  base::PostTaskAndReplyWithResult(
-      blocking_task_runner_.get(),
-      FROM_HERE,
-      base::Bind(&TryToCopyLocally, metadata_, cache_, params,
-                 updated_local_ids, directory_changed, should_copy_on_server),
-      base::Bind(&CopyOperation::CopyAfterTryToCopyLocally,
-                 weak_ptr_factory_.GetWeakPtr(), base::Owned(params),
-                 base::Owned(updated_local_ids), base::Owned(directory_changed),
-                 base::Owned(should_copy_on_server)));
-}
-
-void CopyOperation::CopyAfterTryToCopyLocally(
-    const CopyParams* params,
-    const std::vector<std::string>* updated_local_ids,
-    const bool* directory_changed,
-    const bool* should_copy_on_server,
-    FileError error) {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-  DCHECK(params->callback);
-
-  for (const auto& id : *updated_local_ids) {
-    // Syncing for copy should be done in background, so pass the BACKGROUND
-    // context. See: crbug.com/420278.
-    delegate_->OnEntryUpdatedByOperation(ClientContext(BACKGROUND), id);
-  }
-
-  if (*directory_changed) {
-    FileChange changed_file;
-    DCHECK(!params->src_entry.file_info().is_directory());
-    changed_file.Update(params->dest_file_path, FileChange::FILE_TYPE_FILE,
-                        FileChange::CHANGE_TYPE_ADD_OR_UPDATE);
-    delegate_->OnFileChangedByOperation(changed_file);
-  }
-
-  if (error != FILE_ERROR_OK || !*should_copy_on_server) {
-    params->callback.Run(error);
-    return;
-  }
-
-  if (params->parent_entry.resource_id().empty()) {
-    // Parent entry may be being synced.
-    const bool waiting = delegate_->WaitForSyncComplete(
-        params->parent_entry.local_id(),
-        base::Bind(&CopyOperation::CopyAfterParentSync,
-                   weak_ptr_factory_.GetWeakPtr(), *params));
-    if (!waiting)
-      params->callback.Run(FILE_ERROR_NOT_FOUND);
-  } else {
-    CopyAfterGetParentResourceId(*params, &params->parent_entry, FILE_ERROR_OK);
-  }
-}
-
-void CopyOperation::CopyAfterParentSync(const CopyParams& params,
-                                        FileError error) {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-  DCHECK(params.callback);
-
-  if (error != FILE_ERROR_OK) {
-    params.callback.Run(error);
-    return;
-  }
-
-  ResourceEntry* parent = new ResourceEntry;
-  base::PostTaskAndReplyWithResult(
-      blocking_task_runner_.get(),
-      FROM_HERE,
-      base::Bind(&internal::ResourceMetadata::GetResourceEntryById,
-                 base::Unretained(metadata_),
-                 params.parent_entry.local_id(),
-                 parent),
-      base::Bind(&CopyOperation::CopyAfterGetParentResourceId,
-                 weak_ptr_factory_.GetWeakPtr(),
-                 params,
-                 base::Owned(parent)));
-}
-
-void CopyOperation::CopyAfterGetParentResourceId(const CopyParams& params,
-                                                 const ResourceEntry* parent,
-                                                 FileError error) {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-  DCHECK(params.callback);
-
-  if (error != FILE_ERROR_OK) {
-    params.callback.Run(error);
-    return;
-  }
-
-  base::FilePath new_title = params.dest_file_path.BaseName();
-  if (params.src_entry.file_specific_info().is_hosted_document()) {
-    // Drop the document extension, which should not be in the title.
-    // TODO(yoshiki): Remove this code with crbug.com/223304.
-    new_title = new_title.RemoveExtension();
-  }
-
-  base::Time last_modified =
-      params.preserve_last_modified ?
-      base::Time::FromInternalValue(
-          params.src_entry.file_info().last_modified()) : base::Time();
-
-  CopyResourceOnServer(
-      params.src_entry.resource_id(), parent->resource_id(),
-      new_title.AsUTF8Unsafe(), last_modified, params.callback);
-}
-
-void CopyOperation::TransferFileFromLocalToRemote(
-    const base::FilePath& local_src_path,
-    const base::FilePath& remote_dest_path,
-    const FileOperationCallback& callback) {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-  DCHECK(callback);
-
-  std::string* gdoc_resource_id = new std::string;
-  ResourceEntry* parent_entry = new ResourceEntry;
-  base::PostTaskAndReplyWithResult(
-      blocking_task_runner_.get(),
-      FROM_HERE,
-      base::Bind(
-          &PrepareTransferFileFromLocalToRemote,
-          metadata_, local_src_path, remote_dest_path,
-          gdoc_resource_id, parent_entry),
-      base::Bind(
-          &CopyOperation::TransferFileFromLocalToRemoteAfterPrepare,
-          weak_ptr_factory_.GetWeakPtr(),
-          local_src_path, remote_dest_path, callback,
-          base::Owned(gdoc_resource_id), base::Owned(parent_entry)));
-}
-
-void CopyOperation::TransferFileFromLocalToRemoteAfterPrepare(
-    const base::FilePath& local_src_path,
-    const base::FilePath& remote_dest_path,
-    const FileOperationCallback& callback,
-    std::string* gdoc_resource_id,
-    ResourceEntry* parent_entry,
-    FileError error) {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-  DCHECK(callback);
-
-  if (error != FILE_ERROR_OK) {
-    callback.Run(error);
-    return;
-  }
-
-  // For regular files, schedule the transfer.
-  if (gdoc_resource_id->empty()) {
-    ScheduleTransferRegularFile(local_src_path, remote_dest_path, callback);
-    return;
-  }
-
-  // GDoc file may contain a resource ID in the old format.
-  const std::string canonicalized_resource_id =
-      util::CanonicalizeResourceId(*gdoc_resource_id);
-
-  // Drop the document extension, which should not be in the title.
-  // TODO(yoshiki): Remove this code with crbug.com/223304.
-  const std::string new_title =
-      remote_dest_path.BaseName().RemoveExtension().AsUTF8Unsafe();
-
-  // This is uploading a JSON file representing a hosted document.
-  TransferJsonGdocParams* params = new TransferJsonGdocParams(
-      callback, canonicalized_resource_id, *parent_entry, new_title);
-  base::PostTaskAndReplyWithResult(
-      blocking_task_runner_.get(),
-      FROM_HERE,
-      base::Bind(&LocalWorkForTransferJsonGdocFile, metadata_, params),
-      base::Bind(&CopyOperation::TransferJsonGdocFileAfterLocalWork,
-                 weak_ptr_factory_.GetWeakPtr(), base::Owned(params)));
-}
-
-void CopyOperation::TransferJsonGdocFileAfterLocalWork(
-    TransferJsonGdocParams* params,
-    FileError error) {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-
-  if (error != FILE_ERROR_OK) {
-    params->callback.Run(error);
-    return;
-  }
-
-  switch (params->location_type) {
-    // When |resource_id| is found in the local metadata and it has a specific
-    // parent folder, we assume the user's intention is to copy the document and
-    // thus perform the server-side copy operation.
-    case HAS_PARENT:
-      CopyResourceOnServer(params->resource_id,
-                           params->parent_resource_id,
-                           params->new_title,
-                           base::Time(),
-                           params->callback);
-      break;
-    // When |resource_id| has no parent, we just set the new destination folder
-    // as the parent, for sharing the document between the original source.
-    // This reparenting is already done in LocalWorkForTransferJsonGdocFile().
-    case IS_ORPHAN: {
-      DCHECK(!params->changed_path.empty());
-      // Syncing for copy should be done in background, so pass the BACKGROUND
-      // context. See: crbug.com/420278.
-      delegate_->OnEntryUpdatedByOperation(ClientContext(BACKGROUND),
-                                           params->local_id);
-
-      FileChange changed_file;
-      changed_file.Update(
-          params->changed_path,
-          FileChange::FILE_TYPE_FILE,  // This must be a hosted document.
-          FileChange::CHANGE_TYPE_ADD_OR_UPDATE);
-      delegate_->OnFileChangedByOperation(changed_file);
-      params->callback.Run(error);
-      break;
-    }
-    // When the |resource_id| is not in the local metadata, assume it to be a
-    // document just now shared on the server but not synced locally.
-    // Same as the IS_ORPHAN case, we want to deal the case by setting parent,
-    // but this time we need to resort to server side operation.
-    case NOT_IN_METADATA:
-      scheduler_->UpdateResource(
-          params->resource_id, params->parent_resource_id, params->new_title,
-          base::Time(), base::Time(), google_apis::drive::Properties(),
-          ClientContext(USER_INITIATED),
-          base::Bind(&CopyOperation::UpdateAfterServerSideOperation,
-                     weak_ptr_factory_.GetWeakPtr(), params->callback));
-      break;
-  }
-}
-
-void CopyOperation::CopyResourceOnServer(
-    const std::string& resource_id,
-    const std::string& parent_resource_id,
-    const std::string& new_title,
-    const base::Time& last_modified,
-    const FileOperationCallback& callback) {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-  DCHECK(callback);
-
-  scheduler_->CopyResource(
-      resource_id, parent_resource_id, new_title, last_modified,
-      base::Bind(&CopyOperation::UpdateAfterServerSideOperation,
-                 weak_ptr_factory_.GetWeakPtr(),
-                 callback));
-}
-
-void CopyOperation::UpdateAfterServerSideOperation(
-    const FileOperationCallback& callback,
-    google_apis::DriveApiErrorCode status,
-    std::unique_ptr<google_apis::FileResource> entry) {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-  DCHECK(callback);
-
-  FileError error = GDataToFileError(status);
-  if (error != FILE_ERROR_OK) {
-    callback.Run(error);
-    return;
-  }
-
-  ResourceEntry* resource_entry = new ResourceEntry;
-
-  // The copy on the server side is completed successfully. Update the local
-  // metadata.
-  base::FilePath* file_path = new base::FilePath;
-  base::PostTaskAndReplyWithResult(
-      blocking_task_runner_.get(), FROM_HERE,
-      base::BindOnce(&UpdateLocalStateForServerSideOperation, metadata_,
-                     std::move(entry), resource_entry, file_path),
-      base::BindOnce(&CopyOperation::UpdateAfterLocalStateUpdate,
-                     weak_ptr_factory_.GetWeakPtr(), callback,
-                     base::Owned(file_path), base::Owned(resource_entry)));
-}
-
-void CopyOperation::UpdateAfterLocalStateUpdate(
-    const FileOperationCallback& callback,
-    base::FilePath* file_path,
-    const ResourceEntry* entry,
-    FileError error) {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-  DCHECK(callback);
-
-  if (error == FILE_ERROR_OK) {
-    FileChange changed_file;
-    changed_file.Update(*file_path, *entry,
-                        FileChange::CHANGE_TYPE_ADD_OR_UPDATE);
-    delegate_->OnFileChangedByOperation(changed_file);
-  }
-  callback.Run(error);
-}
-
-void CopyOperation::ScheduleTransferRegularFile(
-    const base::FilePath& local_src_path,
-    const base::FilePath& remote_dest_path,
-    const FileOperationCallback& callback) {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-  DCHECK(callback);
-
-  create_file_operation_->CreateFile(
-      remote_dest_path,
-      false,  // Not exclusive (OK even if a file already exists).
-      std::string(),  // no specific mime type; CreateFile should guess it.
-      base::Bind(&CopyOperation::ScheduleTransferRegularFileAfterCreate,
-                 weak_ptr_factory_.GetWeakPtr(),
-                 local_src_path, remote_dest_path, callback));
-}
-
-void CopyOperation::ScheduleTransferRegularFileAfterCreate(
-    const base::FilePath& local_src_path,
-    const base::FilePath& remote_dest_path,
-    const FileOperationCallback& callback,
-    FileError error) {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-  DCHECK(callback);
-
-  if (error != FILE_ERROR_OK) {
-    callback.Run(error);
-    return;
-  }
-
-  std::string* local_id = new std::string;
-  ResourceEntry* entry = new ResourceEntry;
-  base::PostTaskAndReplyWithResult(
-      blocking_task_runner_.get(),
-      FROM_HERE,
-      base::Bind(&UpdateLocalStateForScheduleTransfer,
-                 metadata_,
-                 cache_,
-                 local_src_path,
-                 remote_dest_path,
-                 entry,
-                 local_id),
-      base::Bind(
-          &CopyOperation::ScheduleTransferRegularFileAfterUpdateLocalState,
-          weak_ptr_factory_.GetWeakPtr(),
-          callback,
-          remote_dest_path,
-          base::Owned(entry),
-          base::Owned(local_id)));
-}
-
-void CopyOperation::ScheduleTransferRegularFileAfterUpdateLocalState(
-    const FileOperationCallback& callback,
-    const base::FilePath& remote_dest_path,
-    const ResourceEntry* entry,
-    std::string* local_id,
-    FileError error) {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-  DCHECK(callback);
-
-  if (error == FILE_ERROR_OK) {
-    FileChange changed_file;
-    changed_file.Update(remote_dest_path, *entry,
-                        FileChange::CHANGE_TYPE_ADD_OR_UPDATE);
-    delegate_->OnFileChangedByOperation(changed_file);
-    // Syncing for copy should be done in background, so pass the BACKGROUND
-    // context. See: crbug.com/420278.
-    delegate_->OnEntryUpdatedByOperation(ClientContext(BACKGROUND), *local_id);
-  }
-  callback.Run(error);
-}
-
-}  // namespace file_system
-}  // namespace drive
diff --git a/components/drive/chromeos/file_system/copy_operation.h b/components/drive/chromeos/file_system/copy_operation.h
deleted file mode 100644
index c1854ee..0000000
--- a/components/drive/chromeos/file_system/copy_operation.h
+++ /dev/null
@@ -1,183 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef COMPONENTS_DRIVE_CHROMEOS_FILE_SYSTEM_COPY_OPERATION_H_
-#define COMPONENTS_DRIVE_CHROMEOS_FILE_SYSTEM_COPY_OPERATION_H_
-
-#include <memory>
-#include <string>
-#include <vector>
-
-#include "base/macros.h"
-#include "base/memory/ref_counted.h"
-#include "base/memory/weak_ptr.h"
-#include "base/threading/thread_checker.h"
-#include "components/drive/file_errors.h"
-#include "google_apis/drive/drive_api_error_codes.h"
-
-namespace base {
-class FilePath;
-class SequencedTaskRunner;
-class Time;
-}  // namespace base
-
-namespace google_apis {
-class FileResource;
-}  // namespace google_apis
-
-namespace drive {
-
-class JobScheduler;
-class ResourceEntry;
-
-namespace internal {
-class FileCache;
-class ResourceMetadata;
-}  // namespace internal
-
-namespace file_system {
-
-class CreateFileOperation;
-class OperationDelegate;
-
-// This class encapsulates the drive Copy function.  It is responsible for
-// sending the request to the drive API, then updating the local state and
-// metadata to reflect the new state.
-class CopyOperation {
- public:
-  CopyOperation(base::SequencedTaskRunner* blocking_task_runner,
-                OperationDelegate* delegate,
-                JobScheduler* scheduler,
-                internal::ResourceMetadata* metadata,
-                internal::FileCache* cache);
-  ~CopyOperation();
-
-  // Performs the copy operation on the file at drive path |src_file_path|
-  // with a target of |dest_file_path|.
-  // If |preserve_last_modified| is set to true, this tries to preserve
-  // last modified time stamp. This is supported only on Drive API v2.
-  // Regardless of preserve_last_modified's value, last_modified_by_me timestamp
-  // will always be set to the same timestamp as last_modified.
-  // Invokes |callback| when finished with the result of the operation.
-  // |callback| must not be null.
-  void Copy(const base::FilePath& src_file_path,
-            const base::FilePath& dest_file_path,
-            bool preserve_last_modified,
-            const FileOperationCallback& callback);
-
-  // Initiates transfer of |local_src_file_path| to |remote_dest_file_path|.
-  // |local_src_file_path| must be a file from the local file system.
-  // |remote_dest_file_path| is the virtual destination path within Drive file
-  // system.
-  //
-  // |callback| must not be null.
-  void TransferFileFromLocalToRemote(
-      const base::FilePath& local_src_file_path,
-      const base::FilePath& remote_dest_file_path,
-      const FileOperationCallback& callback);
-
-  // Params for Copy().
-  struct CopyParams;
-
-  // Params for TransferJsonGdocFileAfterLocalWork.
-  struct TransferJsonGdocParams;
-
- private:
-  // Part of Copy(). Called after trying to copy locally.
-  void CopyAfterTryToCopyLocally(
-      const CopyParams* params,
-      const std::vector<std::string>* updated_local_ids,
-      const bool* directory_changed,
-      const bool* should_copy_on_server,
-      FileError error);
-
-  // Part of Copy(). Called after the parent entry gets synced.
-  void CopyAfterParentSync(const CopyParams& params, FileError error);
-
-  // Part of Copy(). Called after the parent resource ID is resolved.
-  void CopyAfterGetParentResourceId(const CopyParams& params,
-                                    const ResourceEntry* parent,
-                                    FileError error);
-
-  // Part of TransferFileFromLocalToRemote(). Called after preparation is done.
-  // |gdoc_resource_id| and |parent_resource_id| is available only if the file
-  // is JSON GDoc file.
-  void TransferFileFromLocalToRemoteAfterPrepare(
-      const base::FilePath& local_src_path,
-      const base::FilePath& remote_dest_path,
-      const FileOperationCallback& callback,
-      std::string* gdoc_resource_id,
-      ResourceEntry* parent_entry,
-      FileError error);
-
-  // Part of TransferFileFromLocalToRemote().
-  void TransferJsonGdocFileAfterLocalWork(TransferJsonGdocParams* params,
-                                          FileError error);
-
-  // Copies resource with |resource_id| into the directory |parent_resource_id|
-  // with renaming it to |new_title|.
-  void CopyResourceOnServer(const std::string& resource_id,
-                            const std::string& parent_resource_id,
-                            const std::string& new_title,
-                            const base::Time& last_modified,
-                            const FileOperationCallback& callback);
-
-  // Part of CopyResourceOnServer and TransferFileFromLocalToRemote.
-  // Called after server side operation is done.
-  void UpdateAfterServerSideOperation(
-      const FileOperationCallback& callback,
-      google_apis::DriveApiErrorCode status,
-      std::unique_ptr<google_apis::FileResource> entry);
-
-  // Part of CopyResourceOnServer and TransferFileFromLocalToRemote.
-  // Called after local state update is done.
-  void UpdateAfterLocalStateUpdate(const FileOperationCallback& callback,
-                                   base::FilePath* file_path,
-                                   const ResourceEntry* entry,
-                                   FileError error);
-
-  // Creates an empty file on the server at |remote_dest_path| to ensure
-  // the location, stores a file at |local_file_path| in cache and marks it
-  // dirty, so that SyncClient will upload the data later.
-  void ScheduleTransferRegularFile(const base::FilePath& local_src_path,
-                                   const base::FilePath& remote_dest_path,
-                                   const FileOperationCallback& callback);
-
-  // Part of ScheduleTransferRegularFile(). Called after file creation.
-  void ScheduleTransferRegularFileAfterCreate(
-      const base::FilePath& local_src_path,
-      const base::FilePath& remote_dest_path,
-      const FileOperationCallback& callback,
-      FileError error);
-
-  // Part of ScheduleTransferRegularFile(). Called after updating local state
-  // is completed.
-  void ScheduleTransferRegularFileAfterUpdateLocalState(
-      const FileOperationCallback& callback,
-      const base::FilePath& remote_dest_path,
-      const ResourceEntry* entry,
-      std::string* local_id,
-      FileError error);
-
-  scoped_refptr<base::SequencedTaskRunner> blocking_task_runner_;
-  OperationDelegate* delegate_;
-  JobScheduler* scheduler_;
-  internal::ResourceMetadata* metadata_;
-  internal::FileCache* cache_;
-
-  // Uploading a new file is internally implemented by creating a dirty file.
-  std::unique_ptr<CreateFileOperation> create_file_operation_;
-
-  THREAD_CHECKER(thread_checker_);
-
-  // Note: This should remain the last member so it'll be destroyed and
-  // invalidate the weak pointers before any other members are destroyed.
-  base::WeakPtrFactory<CopyOperation> weak_ptr_factory_{this};
-  DISALLOW_COPY_AND_ASSIGN(CopyOperation);
-};
-
-}  // namespace file_system
-}  // namespace drive
-
-#endif  // COMPONENTS_DRIVE_CHROMEOS_FILE_SYSTEM_COPY_OPERATION_H_
diff --git a/components/drive/chromeos/file_system/create_directory_operation.cc b/components/drive/chromeos/file_system/create_directory_operation.cc
deleted file mode 100644
index 464c55d..0000000
--- a/components/drive/chromeos/file_system/create_directory_operation.cc
+++ /dev/null
@@ -1,184 +0,0 @@
-// Copyright (c) 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "components/drive/chromeos/file_system/create_directory_operation.h"
-
-#include <stddef.h>
-
-#include "base/bind.h"
-#include "components/drive/chromeos/file_system/operation_delegate.h"
-#include "components/drive/chromeos/resource_metadata.h"
-#include "components/drive/drive.pb.h"
-#include "components/drive/file_change.h"
-#include "components/drive/file_system_core_util.h"
-#include "components/drive/job_scheduler.h"
-
-namespace drive {
-namespace file_system {
-
-namespace {
-
-FileError CreateDirectoryRecursively(internal::ResourceMetadata* metadata,
-                                     const std::string& parent_local_id,
-                                     const base::FilePath& relative_file_path,
-                                     std::set<std::string>* updated_local_ids,
-                                     FileChange* changed_files) {
-  // Split the first component and remaining ones of |relative_file_path|.
-  std::vector<base::FilePath::StringType> components;
-  relative_file_path.GetComponents(&components);
-  DCHECK(!components.empty());
-  base::FilePath title(components[0]);
-  base::FilePath remaining_path;
-  title.AppendRelativePath(relative_file_path, &remaining_path);
-
-  ResourceEntry entry;
-  const int64_t now = base::Time::Now().ToInternalValue();
-  entry.set_title(title.AsUTF8Unsafe());
-  entry.mutable_file_info()->set_is_directory(true);
-  entry.mutable_file_info()->set_last_modified(now);
-  entry.set_last_modified_by_me(now);
-  entry.mutable_file_info()->set_last_accessed(now);
-  entry.set_parent_local_id(parent_local_id);
-  entry.set_metadata_edit_state(ResourceEntry::DIRTY);
-  entry.set_modification_date(base::Time::Now().ToInternalValue());
-
-  std::string local_id;
-  FileError error = metadata->AddEntry(entry, &local_id);
-  if (error != FILE_ERROR_OK)
-    return error;
-
-  base::FilePath path;
-  error = metadata->GetFilePath(local_id, &path);
-  if (error != FILE_ERROR_OK)
-    return error;
-
-  updated_local_ids->insert(local_id);
-  DCHECK(changed_files);
-  changed_files->Update(path, FileChange::FILE_TYPE_DIRECTORY,
-                        FileChange::CHANGE_TYPE_ADD_OR_UPDATE);
-
-  if (remaining_path.empty())  // All directories are created successfully.
-    return FILE_ERROR_OK;
-
-  // Create descendant directories.
-  return CreateDirectoryRecursively(
-      metadata, local_id, remaining_path, updated_local_ids, changed_files);
-}
-
-FileError UpdateLocalState(internal::ResourceMetadata* metadata,
-                           const base::FilePath& directory_path,
-                           bool is_exclusive,
-                           bool is_recursive,
-                           std::set<std::string>* updated_local_ids,
-                           FileChange* changed_files) {
-  // Get the existing deepest entry.
-  std::vector<base::FilePath::StringType> components;
-  directory_path.GetComponents(&components);
-
-  if (components.empty() ||
-      components[0] != util::GetDriveGrandRootPath().value())
-    return FILE_ERROR_NOT_FOUND;
-
-  base::FilePath existing_deepest_path(components[0]);
-  std::string local_id = util::kDriveGrandRootLocalId;
-  for (size_t i = 1; i < components.size(); ++i) {
-    const std::string component = base::FilePath(components[i]).AsUTF8Unsafe();
-    std::string child_local_id;
-    FileError error =
-        metadata->GetChildId(local_id, component, &child_local_id);
-    if (error == FILE_ERROR_NOT_FOUND)
-      break;
-    if (error != FILE_ERROR_OK)
-      return error;
-    existing_deepest_path = existing_deepest_path.Append(components[i]);
-    local_id = child_local_id;
-  }
-
-  ResourceEntry entry;
-  FileError error = metadata->GetResourceEntryById(local_id, &entry);
-  if (error != FILE_ERROR_OK)
-    return error;
-
-  if (!entry.file_info().is_directory())
-    return FILE_ERROR_NOT_A_DIRECTORY;
-
-  if (directory_path == existing_deepest_path)
-    return is_exclusive ? FILE_ERROR_EXISTS : FILE_ERROR_OK;
-
-  // If it is not recursive creation, the found directory must be the direct
-  // parent of |directory_path| to ensure creating exact one directory.
-  if (!is_recursive && existing_deepest_path != directory_path.DirName())
-    return FILE_ERROR_NOT_FOUND;
-
-  // Create directories under the found directory.
-  base::FilePath remaining_path;
-  existing_deepest_path.AppendRelativePath(directory_path, &remaining_path);
-  return CreateDirectoryRecursively(metadata,
-                                    entry.local_id(),
-                                    remaining_path,
-                                    updated_local_ids,
-                                    changed_files);
-}
-
-}  // namespace
-
-CreateDirectoryOperation::CreateDirectoryOperation(
-    base::SequencedTaskRunner* blocking_task_runner,
-    OperationDelegate* delegate,
-    internal::ResourceMetadata* metadata)
-    : blocking_task_runner_(blocking_task_runner),
-      delegate_(delegate),
-      metadata_(metadata) {}
-
-CreateDirectoryOperation::~CreateDirectoryOperation() {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-}
-
-void CreateDirectoryOperation::CreateDirectory(
-    const base::FilePath& directory_path,
-    bool is_exclusive,
-    bool is_recursive,
-    const FileOperationCallback& callback) {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-  DCHECK(callback);
-
-  std::set<std::string>* updated_local_ids = new std::set<std::string>;
-  FileChange* changed_files(new FileChange);
-  base::PostTaskAndReplyWithResult(
-      blocking_task_runner_.get(),
-      FROM_HERE,
-      base::Bind(&UpdateLocalState,
-                 metadata_,
-                 directory_path,
-                 is_exclusive,
-                 is_recursive,
-                 updated_local_ids,
-                 changed_files),
-      base::Bind(
-          &CreateDirectoryOperation::CreateDirectoryAfterUpdateLocalState,
-          weak_ptr_factory_.GetWeakPtr(),
-          callback,
-          base::Owned(updated_local_ids),
-          base::Owned(changed_files)));
-}
-
-void CreateDirectoryOperation::CreateDirectoryAfterUpdateLocalState(
-    const FileOperationCallback& callback,
-    const std::set<std::string>* updated_local_ids,
-    const FileChange* changed_files,
-    FileError error) {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-  DCHECK(callback);
-
-  for (const auto& id : *updated_local_ids) {
-    delegate_->OnEntryUpdatedByOperation(ClientContext(USER_INITIATED), id);
-  }
-
-  delegate_->OnFileChangedByOperation(*changed_files);
-
-  callback.Run(error);
-}
-
-}  // namespace file_system
-}  // namespace drive
diff --git a/components/drive/chromeos/file_system/create_directory_operation.h b/components/drive/chromeos/file_system/create_directory_operation.h
deleted file mode 100644
index bf16bbb..0000000
--- a/components/drive/chromeos/file_system/create_directory_operation.h
+++ /dev/null
@@ -1,78 +0,0 @@
-// Copyright (c) 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef COMPONENTS_DRIVE_CHROMEOS_FILE_SYSTEM_CREATE_DIRECTORY_OPERATION_H_
-#define COMPONENTS_DRIVE_CHROMEOS_FILE_SYSTEM_CREATE_DIRECTORY_OPERATION_H_
-
-#include <set>
-
-#include "base/macros.h"
-#include "base/memory/ref_counted.h"
-#include "base/memory/weak_ptr.h"
-#include "base/threading/thread_checker.h"
-#include "components/drive/file_errors.h"
-
-namespace base {
-class FilePath;
-class SequencedTaskRunner;
-}  // namespace base
-
-namespace drive {
-
-class FileChange;
-
-namespace internal {
-class ResourceMetadata;
-}  // namespace internal
-
-namespace file_system {
-
-class OperationDelegate;
-
-// This class encapsulates the drive Create Directory function.  It is
-// responsible for sending the request to the drive API, then updating the
-// local state and metadata to reflect the new state.
-class CreateDirectoryOperation {
- public:
-  CreateDirectoryOperation(base::SequencedTaskRunner* blocking_task_runner,
-                           OperationDelegate* delegate,
-                           internal::ResourceMetadata* metadata);
-  ~CreateDirectoryOperation();
-
-  // Creates a new directory at |directory_path|.
-  // If |is_exclusive| is true, an error is raised in case a directory exists
-  // already at the |directory_path|.
-  // If |is_recursive| is true, the invocation creates parent directories as
-  // needed just like mkdir -p does.
-  // Invokes |callback| when finished with the result of the operation.
-  // |callback| must not be null.
-  void CreateDirectory(const base::FilePath& directory_path,
-                       bool is_exclusive,
-                       bool is_recursive,
-                       const FileOperationCallback& callback);
-
- private:
-  // Part of CreateDirectory(). Called after UpdateLocalState().
-  void CreateDirectoryAfterUpdateLocalState(
-      const FileOperationCallback& callback,
-      const std::set<std::string>* updated_local_ids,
-      const FileChange* changed_directories,
-      FileError error);
-
-  scoped_refptr<base::SequencedTaskRunner> blocking_task_runner_;
-  OperationDelegate* delegate_;
-  internal::ResourceMetadata* metadata_;
-
-  THREAD_CHECKER(thread_checker_);
-
-  // Note: This should remain the last member so it'll be destroyed and
-  // invalidate the weak pointers before any other members are destroyed.
-  base::WeakPtrFactory<CreateDirectoryOperation> weak_ptr_factory_{this};
-  DISALLOW_COPY_AND_ASSIGN(CreateDirectoryOperation);
-};
-
-}  // namespace file_system
-}  // namespace drive
-
-#endif  // COMPONENTS_DRIVE_CHROMEOS_FILE_SYSTEM_CREATE_DIRECTORY_OPERATION_H_
diff --git a/components/drive/chromeos/file_system/create_file_operation.cc b/components/drive/chromeos/file_system/create_file_operation.cc
deleted file mode 100644
index 657a9db..0000000
--- a/components/drive/chromeos/file_system/create_file_operation.cc
+++ /dev/null
@@ -1,139 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "components/drive/chromeos/file_system/create_file_operation.h"
-
-#include <string>
-
-#include "base/bind.h"
-#include "base/files/file_util.h"
-#include "components/drive/chromeos/file_system/operation_delegate.h"
-#include "components/drive/chromeos/resource_metadata.h"
-#include "components/drive/drive.pb.h"
-#include "components/drive/file_change.h"
-#include "components/drive/job_scheduler.h"
-#include "net/base/mime_util.h"
-
-namespace drive {
-namespace file_system {
-
-namespace {
-
-const char kMimeTypeOctetStream[] = "application/octet-stream";
-
-// Updates local state.
-FileError UpdateLocalState(internal::ResourceMetadata* metadata,
-                           const base::FilePath& file_path,
-                           const std::string& mime_type_in,
-                           ResourceEntry* entry) {
-  DCHECK(metadata);
-
-  FileError error = metadata->GetResourceEntryByPath(file_path, entry);
-  if (error == FILE_ERROR_OK)
-    return FILE_ERROR_EXISTS;
-
-  if (error != FILE_ERROR_NOT_FOUND)
-    return error;
-
-  // If parent path is not a directory, it is an error.
-  ResourceEntry parent;
-  if (metadata->GetResourceEntryByPath(
-          file_path.DirName(), &parent) != FILE_ERROR_OK ||
-      !parent.file_info().is_directory())
-    return FILE_ERROR_NOT_A_DIRECTORY;
-
-  // If mime_type is not set or "application/octet-stream", guess from the
-  // |file_path|. If it is still unsure, use octet-stream by default.
-  std::string mime_type = mime_type_in;
-  if ((mime_type.empty() || mime_type == kMimeTypeOctetStream) &&
-      !net::GetMimeTypeFromFile(file_path, &mime_type))
-    mime_type = kMimeTypeOctetStream;
-
-  // Add the entry to the local resource metadata.
-  const int64_t now = base::Time::Now().ToInternalValue();
-  entry->mutable_file_info()->set_last_modified(now);
-  entry->set_last_modified_by_me(now);
-  entry->mutable_file_info()->set_last_accessed(now);
-  entry->set_title(file_path.BaseName().AsUTF8Unsafe());
-  entry->set_parent_local_id(parent.local_id());
-  entry->set_metadata_edit_state(ResourceEntry::DIRTY);
-  entry->set_modification_date(base::Time::Now().ToInternalValue());
-  entry->mutable_file_specific_info()->set_content_mime_type(mime_type);
-
-  std::string local_id;
-  error = metadata->AddEntry(*entry, &local_id);
-  entry->set_local_id(local_id);
-  return error;
-}
-
-}  // namespace
-
-CreateFileOperation::CreateFileOperation(
-    base::SequencedTaskRunner* blocking_task_runner,
-    OperationDelegate* delegate,
-    internal::ResourceMetadata* metadata)
-    : blocking_task_runner_(blocking_task_runner),
-      delegate_(delegate),
-      metadata_(metadata) {}
-
-CreateFileOperation::~CreateFileOperation() {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-}
-
-void CreateFileOperation::CreateFile(const base::FilePath& file_path,
-                                     bool is_exclusive,
-                                     const std::string& mime_type,
-                                     const FileOperationCallback& callback) {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-  DCHECK(callback);
-
-  ResourceEntry* entry = new ResourceEntry;
-  base::PostTaskAndReplyWithResult(
-      blocking_task_runner_.get(),
-      FROM_HERE,
-      base::Bind(&UpdateLocalState,
-                 metadata_,
-                 file_path,
-                 mime_type,
-                 entry),
-      base::Bind(&CreateFileOperation::CreateFileAfterUpdateLocalState,
-                 weak_ptr_factory_.GetWeakPtr(),
-                 callback,
-                 file_path,
-                 is_exclusive,
-                 base::Owned(entry)));
-}
-
-void CreateFileOperation::CreateFileAfterUpdateLocalState(
-    const FileOperationCallback& callback,
-    const base::FilePath& file_path,
-    bool is_exclusive,
-    ResourceEntry* entry,
-    FileError error) {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-  DCHECK(callback);
-
-  if (error == FILE_ERROR_EXISTS) {
-    // Error if an exclusive mode is requested, or the entry is not a file.
-    error = (is_exclusive ||
-             entry->file_info().is_directory() ||
-             entry->file_specific_info().is_hosted_document()) ?
-        FILE_ERROR_EXISTS : FILE_ERROR_OK;
-  } else if (error == FILE_ERROR_OK) {
-    DCHECK(!entry->file_info().is_directory());
-
-    // Notify delegate if the file was newly created.
-    FileChange changed_file;
-    changed_file.Update(file_path, FileChange::FILE_TYPE_FILE,
-                        FileChange::CHANGE_TYPE_ADD_OR_UPDATE);
-    delegate_->OnFileChangedByOperation(changed_file);
-    // Synchronize in the background.
-    delegate_->OnEntryUpdatedByOperation(ClientContext(BACKGROUND),
-                                         entry->local_id());
-  }
-  callback.Run(error);
-}
-
-}  // namespace file_system
-}  // namespace drive
diff --git a/components/drive/chromeos/file_system/create_file_operation.h b/components/drive/chromeos/file_system/create_file_operation.h
deleted file mode 100644
index 2d8ca6d..0000000
--- a/components/drive/chromeos/file_system/create_file_operation.h
+++ /dev/null
@@ -1,76 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef COMPONENTS_DRIVE_CHROMEOS_FILE_SYSTEM_CREATE_FILE_OPERATION_H_
-#define COMPONENTS_DRIVE_CHROMEOS_FILE_SYSTEM_CREATE_FILE_OPERATION_H_
-
-#include "base/macros.h"
-#include "base/memory/ref_counted.h"
-#include "base/memory/weak_ptr.h"
-#include "base/threading/thread_checker.h"
-#include "components/drive/file_errors.h"
-
-namespace base {
-class FilePath;
-class SequencedTaskRunner;
-}  // namespace base
-
-namespace drive {
-
-namespace internal {
-class ResourceMetadata;
-}  // namespace internal
-
-class ResourceEntry;
-
-namespace file_system {
-
-class OperationDelegate;
-
-// This class encapsulates the drive CreateFile function.  It is responsible for
-// sending the request to the drive API, then updating the local state and
-// metadata to reflect the new state.
-class CreateFileOperation {
- public:
-  CreateFileOperation(base::SequencedTaskRunner* blocking_task_runner,
-                      OperationDelegate* delegate,
-                      internal::ResourceMetadata* metadata);
-  ~CreateFileOperation();
-
-  // Creates an empty file at |file_path|. When the file
-  // already exists at that path, the operation fails if |is_exclusive| is true,
-  // and it succeeds without doing anything if the flag is false.
-  // If |mime_type| is non-empty, it is used as the mime type of the entry. If
-  // the parameter is empty, the type is guessed from |file_path|.
-  //
-  // |callback| must not be null.
-  void CreateFile(const base::FilePath& file_path,
-                  bool is_exclusive,
-                  const std::string& mime_type,
-                  const FileOperationCallback& callback);
-
- private:
-  // Part of CreateFile(). Called after the updating local state is completed.
-  void CreateFileAfterUpdateLocalState(const FileOperationCallback& callback,
-                                       const base::FilePath& file_path,
-                                       bool is_exclusive,
-                                       ResourceEntry* entry,
-                                       FileError error);
-
-  scoped_refptr<base::SequencedTaskRunner> blocking_task_runner_;
-  OperationDelegate* delegate_;
-  internal::ResourceMetadata* metadata_;
-
-  THREAD_CHECKER(thread_checker_);
-
-  // Note: This should remain the last member so it'll be destroyed and
-  // invalidate the weak pointers before any other members are destroyed.
-  base::WeakPtrFactory<CreateFileOperation> weak_ptr_factory_{this};
-  DISALLOW_COPY_AND_ASSIGN(CreateFileOperation);
-};
-
-}  // namespace file_system
-}  // namespace drive
-
-#endif  // COMPONENTS_DRIVE_CHROMEOS_FILE_SYSTEM_CREATE_FILE_OPERATION_H_
diff --git a/components/drive/chromeos/file_system/download_operation.cc b/components/drive/chromeos/file_system/download_operation.cc
deleted file mode 100644
index 5c84c74..0000000
--- a/components/drive/chromeos/file_system/download_operation.cc
+++ /dev/null
@@ -1,523 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "components/drive/chromeos/file_system/download_operation.h"
-
-#include <stdint.h>
-
-#include <utility>
-
-#include "base/bind.h"
-#include "base/callback_helpers.h"
-#include "base/files/file_path.h"
-#include "base/files/file_util.h"
-#include "base/logging.h"
-#include "base/macros.h"
-#include "base/memory/ptr_util.h"
-#include "base/task_runner_util.h"
-#include "components/drive/chromeos/file_cache.h"
-#include "components/drive/chromeos/file_system/operation_delegate.h"
-#include "components/drive/chromeos/resource_metadata.h"
-#include "components/drive/drive.pb.h"
-#include "components/drive/file_change.h"
-#include "components/drive/file_errors.h"
-#include "components/drive/file_system_core_util.h"
-#include "components/drive/job_scheduler.h"
-#include "google_apis/drive/drive_api_error_codes.h"
-
-namespace drive {
-namespace file_system {
-namespace {
-
-// Generates an unused file path with |extension| to |out_path|, as a descendant
-// of |dir|, with its parent directory created.
-bool GeneratesUniquePathWithExtension(
-    const base::FilePath& dir,
-    const base::FilePath::StringType& extension,
-    base::FilePath* out_path) {
-  base::FilePath subdir;
-  if (!base::CreateTemporaryDirInDir(dir, base::FilePath::StringType(),
-                                     &subdir)) {
-    return false;
-  }
-  *out_path = subdir.Append(FILE_PATH_LITERAL("tmp") + extension);
-  return true;
-}
-
-// Prepares for downloading the file. Allocates the enough space for the file
-// in the cache.
-// If succeeded, returns FILE_ERROR_OK with |temp_download_file| storing the
-// path to the file in the cache.
-FileError PrepareForDownloadFile(internal::FileCache* cache,
-                                 int64_t expected_file_size,
-                                 const base::FilePath& temporary_file_directory,
-                                 base::FilePath* temp_download_file) {
-  DCHECK(cache);
-  DCHECK(temp_download_file);
-
-  // Ensure enough space in the cache.
-  if (!cache->FreeDiskSpaceIfNeededFor(expected_file_size))
-    return FILE_ERROR_NO_LOCAL_SPACE;
-
-  return base::CreateTemporaryFileInDir(
-      temporary_file_directory,
-      temp_download_file) ? FILE_ERROR_OK : FILE_ERROR_FAILED;
-}
-
-// If the resource is a hosted document, creates a JSON file representing the
-// resource locally, and returns FILE_ERROR_OK with |cache_file_path| storing
-// the path to the JSON file.
-// If the resource is a regular file and its local cache is available,
-// returns FILE_ERROR_OK with |cache_file_path| storing the path to the
-// cache file.
-// If the resource is a regular file but its local cache is NOT available,
-// returns FILE_ERROR_OK, but |cache_file_path| is kept empty.
-// Otherwise returns error code.
-FileError CheckPreConditionForEnsureFileDownloaded(
-    internal::ResourceMetadata* metadata,
-    internal::FileCache* cache,
-    const base::FilePath& temporary_file_directory,
-    const std::string& local_id,
-    ResourceEntry* entry,
-    base::FilePath* cache_file_path,
-    base::FilePath* temp_download_file_path) {
-  DCHECK(metadata);
-  DCHECK(cache);
-  DCHECK(cache_file_path);
-
-  FileError error = metadata->GetResourceEntryById(local_id, entry);
-  if (error != FILE_ERROR_OK)
-    return error;
-
-  if (entry->file_info().is_directory())
-    return FILE_ERROR_NOT_A_FILE;
-
-  // For a hosted document, we create a special JSON file to represent the
-  // document instead of fetching the document content in one of the exported
-  // formats. The JSON file contains the edit URL and resource ID of the
-  // document.
-  if (entry->file_specific_info().is_hosted_document()) {
-    base::FilePath::StringType extension = base::FilePath::FromUTF8Unsafe(
-        entry->file_specific_info().document_extension()).value();
-    base::FilePath gdoc_file_path;
-    base::File::Info file_info;
-    // We add the gdoc file extension in the temporary file, so that in cross
-    // profile drag-and-drop between Drive folders, the destination profiles's
-    // CopyOperation can detect the special JSON file only by the path.
-    if (!GeneratesUniquePathWithExtension(temporary_file_directory, extension,
-                                          &gdoc_file_path) ||
-        !util::CreateGDocFile(gdoc_file_path, GURL(entry->alternate_url()),
-                              entry->resource_id()) ||
-        !base::GetFileInfo(gdoc_file_path,
-                           reinterpret_cast<base::File::Info*>(&file_info)))
-      return FILE_ERROR_FAILED;
-
-    *cache_file_path = gdoc_file_path;
-    entry->mutable_file_info()->set_size(file_info.size);
-    return FILE_ERROR_OK;
-  }
-
-  if (!entry->file_specific_info().cache_state().is_present()) {
-    // This file has no cache file.
-    if (!entry->resource_id().empty()) {
-      // This entry exists on the server, leave |cache_file_path| empty to
-      // start download.
-      return PrepareForDownloadFile(cache, entry->file_info().size(),
-                                    temporary_file_directory,
-                                    temp_download_file_path);
-    }
-
-    // This entry does not exist on the server, store an empty file and mark it
-    // as dirty.
-    base::FilePath empty_file;
-    if (!base::CreateTemporaryFileInDir(temporary_file_directory, &empty_file))
-      return FILE_ERROR_FAILED;
-    error = cache->Store(local_id, std::string(), empty_file,
-                         internal::FileCache::FILE_OPERATION_MOVE);
-    if (error != FILE_ERROR_OK)
-      return error;
-
-    error = metadata->GetResourceEntryById(local_id, entry);
-    if (error != FILE_ERROR_OK)
-      return error;
-  }
-
-  // Leave |cache_file_path| empty when the stored file is obsolete and has no
-  // local modification.
-  if (!entry->file_specific_info().cache_state().is_dirty() &&
-      entry->file_specific_info().md5() !=
-      entry->file_specific_info().cache_state().md5()) {
-    return PrepareForDownloadFile(cache, entry->file_info().size(),
-                                  temporary_file_directory,
-                                  temp_download_file_path);
-  }
-
-  // Fill |cache_file_path| with the path to the cached file.
-  error = cache->GetFile(local_id, cache_file_path);
-  if (error != FILE_ERROR_OK)
-    return error;
-
-  // If the cache file is to be returned as the download result, the file info
-  // of the cache needs to be returned via |entry|.
-  // TODO(kinaba): crbug.com/246469. The logic below is similar to that in
-  // drive::FileSystem::CheckLocalModificationAndRun. We should merge them.
-  base::File::Info file_info;
-  if (base::GetFileInfo(*cache_file_path, &file_info))
-    entry->mutable_file_info()->set_size(file_info.size);
-
-  return FILE_ERROR_OK;
-}
-
-struct CheckPreconditionForEnsureFileDownloadedParams {
-  internal::ResourceMetadata* metadata;
-  internal::FileCache* cache;
-  base::FilePath temporary_file_directory;
-};
-
-// Calls CheckPreConditionForEnsureFileDownloaded() with the entry specified by
-// the given ID. Also fills |drive_file_path| with the path of the entry.
-FileError CheckPreConditionForEnsureFileDownloadedByLocalId(
-    const CheckPreconditionForEnsureFileDownloadedParams& params,
-    const std::string& local_id,
-    base::FilePath* drive_file_path,
-    base::FilePath* cache_file_path,
-    base::FilePath* temp_download_file_path,
-    ResourceEntry* entry) {
-  FileError error = params.metadata->GetFilePath(local_id, drive_file_path);
-  if (error != FILE_ERROR_OK)
-    return error;
-  return CheckPreConditionForEnsureFileDownloaded(
-      params.metadata, params.cache, params.temporary_file_directory, local_id,
-      entry, cache_file_path, temp_download_file_path);
-}
-
-// Calls CheckPreConditionForEnsureFileDownloaded() with the entry specified by
-// the given file path.
-FileError CheckPreConditionForEnsureFileDownloadedByPath(
-    const CheckPreconditionForEnsureFileDownloadedParams& params,
-    const base::FilePath& file_path,
-    base::FilePath* cache_file_path,
-    base::FilePath* temp_download_file_path,
-    ResourceEntry* entry) {
-  std::string local_id;
-  FileError error = params.metadata->GetIdByPath(file_path, &local_id);
-  if (error != FILE_ERROR_OK)
-    return error;
-  return CheckPreConditionForEnsureFileDownloaded(
-      params.metadata, params.cache, params.temporary_file_directory, local_id,
-      entry, cache_file_path, temp_download_file_path);
-}
-
-// Stores the downloaded file at |downloaded_file_path| into |cache|.
-// If succeeded, returns FILE_ERROR_OK with |cache_file_path| storing the
-// path to the cache file.
-// If failed, returns an error code with deleting |downloaded_file_path|.
-FileError UpdateLocalStateForDownloadFile(
-    internal::ResourceMetadata* metadata,
-    internal::FileCache* cache,
-    const ResourceEntry& entry_before_download,
-    google_apis::DriveApiErrorCode gdata_error,
-    const base::FilePath& downloaded_file_path,
-    ResourceEntry* entry_after_update,
-    base::FilePath* cache_file_path) {
-  DCHECK(cache);
-
-  // Downloaded file should be deleted on errors.
-  base::ScopedClosureRunner file_deleter(
-      base::BindOnce(base::IgnoreResult(&base::DeleteFile),
-                     downloaded_file_path, false /* recursive */));
-
-  FileError error = GDataToFileError(gdata_error);
-  if (error != FILE_ERROR_OK)
-    return error;
-
-  const std::string& local_id = entry_before_download.local_id();
-
-  // Do not overwrite locally edited file with server side contents.
-  ResourceEntry entry;
-  error = metadata->GetResourceEntryById(local_id, &entry);
-  if (error != FILE_ERROR_OK)
-    return error;
-  if (entry.file_specific_info().cache_state().is_dirty())
-    return FILE_ERROR_IN_USE;
-
-  // Here the download is completed successfully, so store it into the cache.
-  error = cache->Store(local_id,
-                       entry_before_download.file_specific_info().md5(),
-                       downloaded_file_path,
-                       internal::FileCache::FILE_OPERATION_MOVE);
-  if (error != FILE_ERROR_OK)
-    return error;
-  base::OnceClosure unused_file_deleter_closure = file_deleter.Release();
-
-  error = metadata->GetResourceEntryById(local_id, entry_after_update);
-  if (error != FILE_ERROR_OK)
-    return error;
-
-  return cache->GetFile(local_id, cache_file_path);
-}
-
-}  // namespace
-
-class DownloadOperation::DownloadParams {
- public:
-  DownloadParams(GetFileContentInitializedCallback initialized_callback,
-                 const google_apis::GetContentCallback get_content_callback,
-                 GetFileCallback completion_callback,
-                 std::unique_ptr<ResourceEntry> entry)
-      : initialized_callback_(std::move(initialized_callback)),
-        get_content_callback_(get_content_callback),
-        completion_callback_(std::move(completion_callback)),
-        entry_(std::move(entry)),
-        was_cancelled_(false) {
-    DCHECK(!completion_callback_.is_null());
-    DCHECK(entry_);
-  }
-
-  base::Closure GetCancelClosure() {
-    return base::Bind(&DownloadParams::Cancel, weak_ptr_factory_.GetWeakPtr());
-  }
-
-  void OnCacheFileFound(const base::FilePath& cache_file_path) {
-    if (!initialized_callback_.is_null()) {
-      std::move(initialized_callback_)
-          .Run(FILE_ERROR_OK, cache_file_path,
-               std::make_unique<ResourceEntry>(*entry_));
-    }
-    std::move(completion_callback_)
-        .Run(FILE_ERROR_OK, cache_file_path, std::move(entry_));
-  }
-
-  void OnStartDownloading(const base::Closure& cancel_download_closure) {
-    cancel_download_closure_ = cancel_download_closure;
-    if (initialized_callback_.is_null()) {
-      return;
-    }
-
-    DCHECK(entry_);
-    std::move(initialized_callback_)
-        .Run(FILE_ERROR_OK, base::FilePath(),
-             std::make_unique<ResourceEntry>(*entry_));
-  }
-
-  void OnError(FileError error) {
-    std::move(completion_callback_)
-        .Run(error, base::FilePath(), std::unique_ptr<ResourceEntry>());
-  }
-
-  void OnDownloadCompleted(const base::FilePath& cache_file_path,
-                           std::unique_ptr<ResourceEntry> entry) {
-    std::move(completion_callback_)
-        .Run(FILE_ERROR_OK, cache_file_path, std::move(entry));
-  }
-
-  const google_apis::GetContentCallback& get_content_callback() const {
-    return get_content_callback_;
-  }
-
-  const ResourceEntry& entry() const { return *entry_; }
-
-  bool was_cancelled() const { return was_cancelled_; }
-
- private:
-  void Cancel() {
-    was_cancelled_ = true;
-    if (!cancel_download_closure_.is_null())
-      cancel_download_closure_.Run();
-  }
-
-  GetFileContentInitializedCallback initialized_callback_;
-  const google_apis::GetContentCallback get_content_callback_;
-  GetFileCallback completion_callback_;
-
-  std::unique_ptr<ResourceEntry> entry_;
-  base::Closure cancel_download_closure_;
-  bool was_cancelled_;
-
-  base::WeakPtrFactory<DownloadParams> weak_ptr_factory_{this};
-  DISALLOW_COPY_AND_ASSIGN(DownloadParams);
-};
-
-DownloadOperation::DownloadOperation(
-    base::SequencedTaskRunner* blocking_task_runner,
-    OperationDelegate* delegate,
-    JobScheduler* scheduler,
-    internal::ResourceMetadata* metadata,
-    internal::FileCache* cache,
-    const base::FilePath& temporary_file_directory)
-    : blocking_task_runner_(blocking_task_runner),
-      delegate_(delegate),
-      scheduler_(scheduler),
-      metadata_(metadata),
-      cache_(cache),
-      temporary_file_directory_(temporary_file_directory) {}
-
-DownloadOperation::~DownloadOperation() = default;
-
-base::Closure DownloadOperation::EnsureFileDownloadedByLocalId(
-    const std::string& local_id,
-    const ClientContext& context,
-    GetFileContentInitializedCallback initialized_callback,
-    const google_apis::GetContentCallback& get_content_callback,
-    GetFileCallback completion_callback) {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-  DCHECK(!completion_callback.is_null());
-
-  CheckPreconditionForEnsureFileDownloadedParams params;
-  params.metadata = metadata_;
-  params.cache = cache_;
-  params.temporary_file_directory = temporary_file_directory_;
-  base::FilePath* drive_file_path = new base::FilePath;
-  base::FilePath* cache_file_path = new base::FilePath;
-  base::FilePath* temp_download_file_path = new base::FilePath;
-  ResourceEntry* entry = new ResourceEntry;
-  std::unique_ptr<DownloadParams> download_params(new DownloadParams(
-      std::move(initialized_callback), get_content_callback,
-      std::move(completion_callback), base::WrapUnique(entry)));
-  base::Closure cancel_closure = download_params->GetCancelClosure();
-  base::PostTaskAndReplyWithResult(
-      blocking_task_runner_.get(), FROM_HERE,
-      base::BindOnce(&CheckPreConditionForEnsureFileDownloadedByLocalId, params,
-                     local_id, drive_file_path, cache_file_path,
-                     temp_download_file_path, entry),
-      base::BindOnce(
-          &DownloadOperation::EnsureFileDownloadedAfterCheckPreCondition,
-          weak_ptr_factory_.GetWeakPtr(), std::move(download_params), context,
-          base::Owned(drive_file_path), base::Owned(cache_file_path),
-          base::Owned(temp_download_file_path)));
-  return cancel_closure;
-}
-
-base::Closure DownloadOperation::EnsureFileDownloadedByPath(
-    const base::FilePath& file_path,
-    const ClientContext& context,
-    GetFileContentInitializedCallback initialized_callback,
-    const google_apis::GetContentCallback& get_content_callback,
-    GetFileCallback completion_callback) {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-  DCHECK(!completion_callback.is_null());
-
-  CheckPreconditionForEnsureFileDownloadedParams params;
-  params.metadata = metadata_;
-  params.cache = cache_;
-  params.temporary_file_directory = temporary_file_directory_;
-  base::FilePath* drive_file_path = new base::FilePath(file_path);
-  base::FilePath* cache_file_path = new base::FilePath;
-  base::FilePath* temp_download_file_path = new base::FilePath;
-  ResourceEntry* entry = new ResourceEntry;
-  std::unique_ptr<DownloadParams> download_params(new DownloadParams(
-      std::move(initialized_callback), get_content_callback,
-      std::move(completion_callback), base::WrapUnique(entry)));
-  base::Closure cancel_closure = download_params->GetCancelClosure();
-  base::PostTaskAndReplyWithResult(
-      blocking_task_runner_.get(), FROM_HERE,
-      base::BindOnce(&CheckPreConditionForEnsureFileDownloadedByPath, params,
-                     file_path, cache_file_path, temp_download_file_path,
-                     entry),
-      base::BindOnce(
-          &DownloadOperation::EnsureFileDownloadedAfterCheckPreCondition,
-          weak_ptr_factory_.GetWeakPtr(), std::move(download_params), context,
-          base::Owned(drive_file_path), base::Owned(cache_file_path),
-          base::Owned(temp_download_file_path)));
-  return cancel_closure;
-}
-
-void DownloadOperation::EnsureFileDownloadedAfterCheckPreCondition(
-    std::unique_ptr<DownloadParams> params,
-    const ClientContext& context,
-    base::FilePath* drive_file_path,
-    base::FilePath* cache_file_path,
-    base::FilePath* temp_download_file_path,
-    FileError error) {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-  DCHECK(params);
-  DCHECK(drive_file_path);
-  DCHECK(cache_file_path);
-
-  if (error != FILE_ERROR_OK) {
-    // During precondition check, an error is found.
-    params->OnError(error);
-    return;
-  }
-
-  if (!cache_file_path->empty()) {
-    // The cache file is found.
-    params->OnCacheFileFound(*cache_file_path);
-    return;
-  }
-
-  if (params->was_cancelled()) {
-    params->OnError(FILE_ERROR_ABORT);
-    return;
-  }
-
-  DCHECK(!params->entry().resource_id().empty());
-  DownloadParams* params_ptr = params.get();
-  JobID id = scheduler_->DownloadFile(
-      *drive_file_path,
-      params_ptr->entry().file_info().size(),
-      *temp_download_file_path,
-      params_ptr->entry().resource_id(),
-      context,
-      base::Bind(&DownloadOperation::EnsureFileDownloadedAfterDownloadFile,
-                 weak_ptr_factory_.GetWeakPtr(),
-                 *drive_file_path,
-                 base::Passed(&params)),
-      params_ptr->get_content_callback());
-
-  // Notify via |initialized_callback| if necessary.
-  params_ptr->OnStartDownloading(
-      base::Bind(&DownloadOperation::CancelJob,
-                 weak_ptr_factory_.GetWeakPtr(), id));
-}
-
-void DownloadOperation::EnsureFileDownloadedAfterDownloadFile(
-    const base::FilePath& drive_file_path,
-    std::unique_ptr<DownloadParams> params,
-    google_apis::DriveApiErrorCode gdata_error,
-    const base::FilePath& downloaded_file_path) {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-
-  DownloadParams* params_ptr = params.get();
-  ResourceEntry* entry_after_update = new ResourceEntry;
-  base::FilePath* cache_file_path = new base::FilePath;
-  base::PostTaskAndReplyWithResult(
-      blocking_task_runner_.get(), FROM_HERE,
-      base::BindOnce(&UpdateLocalStateForDownloadFile, metadata_, cache_,
-                     params_ptr->entry(), gdata_error, downloaded_file_path,
-                     entry_after_update, cache_file_path),
-      base::BindOnce(
-          &DownloadOperation::EnsureFileDownloadedAfterUpdateLocalState,
-          weak_ptr_factory_.GetWeakPtr(), drive_file_path, std::move(params),
-          base::WrapUnique(entry_after_update), base::Owned(cache_file_path)));
-}
-
-void DownloadOperation::EnsureFileDownloadedAfterUpdateLocalState(
-    const base::FilePath& file_path,
-    std::unique_ptr<DownloadParams> params,
-    std::unique_ptr<ResourceEntry> entry_after_update,
-    base::FilePath* cache_file_path,
-    FileError error) {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-
-  if (error != FILE_ERROR_OK) {
-    params->OnError(error);
-    return;
-  }
-  DCHECK(!entry_after_update->file_info().is_directory());
-
-  FileChange changed_files;
-  changed_files.Update(file_path, FileChange::FILE_TYPE_FILE,
-                       FileChange::CHANGE_TYPE_ADD_OR_UPDATE);
-  // Storing to cache changes the "offline available" status, hence notify.
-  delegate_->OnFileChangedByOperation(changed_files);
-  params->OnDownloadCompleted(*cache_file_path, std::move(entry_after_update));
-}
-
-void DownloadOperation::CancelJob(JobID job_id) {
-  scheduler_->CancelJob(job_id);
-}
-
-}  // namespace file_system
-}  // namespace drive
diff --git a/components/drive/chromeos/file_system/download_operation.h b/components/drive/chromeos/file_system/download_operation.h
deleted file mode 100644
index 6c09e8b..0000000
--- a/components/drive/chromeos/file_system/download_operation.h
+++ /dev/null
@@ -1,134 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef COMPONENTS_DRIVE_CHROMEOS_FILE_SYSTEM_DOWNLOAD_OPERATION_H_
-#define COMPONENTS_DRIVE_CHROMEOS_FILE_SYSTEM_DOWNLOAD_OPERATION_H_
-
-#include <memory>
-
-#include "base/macros.h"
-#include "base/threading/thread_checker.h"
-#include "components/drive/chromeos/file_system_interface.h"
-#include "components/drive/file_errors.h"
-#include "components/drive/job_list.h"
-#include "google_apis/drive/drive_api_error_codes.h"
-
-namespace base {
-class FilePath;
-class SequencedTaskRunner;
-}  // namespace base
-
-namespace google_apis {
-class ResourceEntry;
-}  // namespace google_apis
-
-namespace drive {
-
-class JobScheduler;
-class ResourceEntry;
-struct ClientContext;
-
-namespace internal {
-class FileCache;
-class ResourceMetadata;
-}  // namespace internal
-
-namespace file_system {
-
-class OperationDelegate;
-
-class DownloadOperation {
- public:
-  DownloadOperation(base::SequencedTaskRunner* blocking_task_runner,
-                    OperationDelegate* delegate,
-                    JobScheduler* scheduler,
-                    internal::ResourceMetadata* metadata,
-                    internal::FileCache* cache,
-                    const base::FilePath& temporary_file_directory);
-  ~DownloadOperation();
-
-  // Ensures that the file content specified by |local_id| is locally
-  // downloaded and returns a closure to cancel the task.
-  // For hosted documents, this method may create a JSON file representing the
-  // file.
-  // For regular files, if the locally cached file is found, returns it.
-  // If not found, start to download the file from the server.
-  // When a JSON file is created, the cache file is found or downloading is
-  // being started, |initialized_callback| is called with |local_file|
-  // for JSON file or the cache file, or with |cancel_download_closure| for
-  // downloading.
-  // During the downloading |get_content_callback| will be called periodically
-  // with the downloaded content.
-  // Upon completion or an error is found, |completion_callback| will be called.
-  // |initialized_callback| and |get_content_callback| can be null if not
-  // needed.
-  // |completion_callback| must not be null.
-  base::Closure EnsureFileDownloadedByLocalId(
-      const std::string& local_id,
-      const ClientContext& context,
-      GetFileContentInitializedCallback initialized_callback,
-      const google_apis::GetContentCallback& get_content_callback,
-      GetFileCallback completion_callback);
-
-  // Does the same thing as EnsureFileDownloadedByLocalId for the file
-  // specified by |file_path|.
-  base::Closure EnsureFileDownloadedByPath(
-      const base::FilePath& file_path,
-      const ClientContext& context,
-      GetFileContentInitializedCallback initialized_callback,
-      const google_apis::GetContentCallback& get_content_callback,
-      GetFileCallback completion_callback);
-
- private:
-  // Parameters for EnsureFileDownloaded.
-  class DownloadParams;
-
-  // Part of EnsureFileDownloaded(). Called upon the completion of precondition
-  // check.
-  void EnsureFileDownloadedAfterCheckPreCondition(
-      std::unique_ptr<DownloadParams> params,
-      const ClientContext& context,
-      base::FilePath* drive_file_path,
-      base::FilePath* cache_file_path,
-      base::FilePath* temp_download_file_path,
-      FileError error);
-
-  // Part of EnsureFileDownloaded(). Called after the actual downloading.
-  void EnsureFileDownloadedAfterDownloadFile(
-      const base::FilePath& drive_file_path,
-      std::unique_ptr<DownloadParams> params,
-      google_apis::DriveApiErrorCode gdata_error,
-      const base::FilePath& downloaded_file_path);
-
-  // Part of EnsureFileDownloaded(). Called after updating local state is
-  // completed.
-  void EnsureFileDownloadedAfterUpdateLocalState(
-      const base::FilePath& file_path,
-      std::unique_ptr<DownloadParams> params,
-      std::unique_ptr<ResourceEntry> entry_after_update,
-      base::FilePath* cache_file_path,
-      FileError error);
-
-  // Cancels the job with |job_id| in the scheduler.
-  void CancelJob(JobID job_id);
-
-  scoped_refptr<base::SequencedTaskRunner> blocking_task_runner_;
-  OperationDelegate* delegate_;
-  JobScheduler* scheduler_;
-  internal::ResourceMetadata* metadata_;
-  internal::FileCache* cache_;
-  const base::FilePath temporary_file_directory_;
-
-  THREAD_CHECKER(thread_checker_);
-
-  // Note: This should remain the last member so it'll be destroyed and
-  // invalidate its weak pointers before any other members are destroyed.
-  base::WeakPtrFactory<DownloadOperation> weak_ptr_factory_{this};
-  DISALLOW_COPY_AND_ASSIGN(DownloadOperation);
-};
-
-}  // namespace file_system
-}  // namespace drive
-
-#endif  // COMPONENTS_DRIVE_CHROMEOS_FILE_SYSTEM_DOWNLOAD_OPERATION_H_
diff --git a/components/drive/chromeos/file_system/get_file_for_saving_operation.cc b/components/drive/chromeos/file_system/get_file_for_saving_operation.cc
deleted file mode 100644
index 828a716..0000000
--- a/components/drive/chromeos/file_system/get_file_for_saving_operation.cc
+++ /dev/null
@@ -1,194 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "components/drive/chromeos/file_system/get_file_for_saving_operation.h"
-
-#include <utility>
-
-#include "base/bind.h"
-#include "base/bind_helpers.h"
-#include "base/callback_helpers.h"
-#include "base/sequenced_task_runner.h"
-#include "components/drive/chromeos/file_cache.h"
-#include "components/drive/chromeos/file_system/create_file_operation.h"
-#include "components/drive/chromeos/file_system/download_operation.h"
-#include "components/drive/chromeos/file_system/operation_delegate.h"
-#include "components/drive/event_logger.h"
-#include "components/drive/file_write_watcher.h"
-#include "components/drive/job_scheduler.h"
-
-namespace drive {
-namespace file_system {
-
-namespace {
-
-FileError OpenCacheFileForWrite(
-    internal::ResourceMetadata* metadata,
-    internal::FileCache* cache,
-    const std::string& local_id,
-    std::unique_ptr<base::ScopedClosureRunner>* file_closer,
-    ResourceEntry* entry) {
-  FileError error = cache->OpenForWrite(local_id, file_closer);
-  if (error != FILE_ERROR_OK)
-    return error;
-  return metadata->GetResourceEntryById(local_id, entry);
-}
-
-}  // namespace
-
-GetFileForSavingOperation::GetFileForSavingOperation(
-    EventLogger* logger,
-    base::SequencedTaskRunner* blocking_task_runner,
-    OperationDelegate* delegate,
-    JobScheduler* scheduler,
-    internal::ResourceMetadata* metadata,
-    internal::FileCache* cache,
-    const base::FilePath& temporary_file_directory)
-    : logger_(logger),
-      create_file_operation_(
-          new CreateFileOperation(blocking_task_runner, delegate, metadata)),
-      download_operation_(new DownloadOperation(blocking_task_runner,
-                                                delegate,
-                                                scheduler,
-                                                metadata,
-                                                cache,
-                                                temporary_file_directory)),
-      file_write_watcher_(new internal::FileWriteWatcher(blocking_task_runner)),
-      blocking_task_runner_(blocking_task_runner),
-      delegate_(delegate),
-      metadata_(metadata),
-      cache_(cache) {}
-
-GetFileForSavingOperation::~GetFileForSavingOperation() = default;
-
-void GetFileForSavingOperation::GetFileForSaving(
-    const base::FilePath& file_path,
-    GetFileCallback callback) {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-  DCHECK(callback);
-
-  create_file_operation_->CreateFile(
-      file_path,
-      false,          // error_if_already_exists
-      std::string(),  // no specific mime type
-      base::Bind(&GetFileForSavingOperation::GetFileForSavingAfterCreate,
-                 weak_ptr_factory_.GetWeakPtr(), file_path,
-                 base::Passed(std::move(callback))));
-}
-
-void GetFileForSavingOperation::GetFileForSavingAfterCreate(
-    const base::FilePath& file_path,
-    GetFileCallback callback,
-    FileError error) {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-  DCHECK(callback);
-
-  if (error != FILE_ERROR_OK) {
-    std::move(callback).Run(error, base::FilePath(),
-                            std::unique_ptr<ResourceEntry>());
-    return;
-  }
-
-  download_operation_->EnsureFileDownloadedByPath(
-      file_path, ClientContext(USER_INITIATED),
-      GetFileContentInitializedCallback(), google_apis::GetContentCallback(),
-      base::Bind(&GetFileForSavingOperation::GetFileForSavingAfterDownload,
-                 weak_ptr_factory_.GetWeakPtr(),
-                 base::Passed(std::move(callback))));
-}
-
-void GetFileForSavingOperation::GetFileForSavingAfterDownload(
-    GetFileCallback callback,
-    FileError error,
-    const base::FilePath& cache_path,
-    std::unique_ptr<ResourceEntry> entry) {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-  DCHECK(callback);
-
-  if (error != FILE_ERROR_OK) {
-    std::move(callback).Run(error, base::FilePath(),
-                            std::unique_ptr<ResourceEntry>());
-    return;
-  }
-
-  const std::string& local_id = entry->local_id();
-  ResourceEntry* entry_ptr = entry.get();
-  std::unique_ptr<base::ScopedClosureRunner>* file_closer =
-      new std::unique_ptr<base::ScopedClosureRunner>;
-  base::PostTaskAndReplyWithResult(
-      blocking_task_runner_.get(), FROM_HERE,
-      base::BindOnce(&OpenCacheFileForWrite, metadata_, cache_, local_id,
-                     file_closer, entry_ptr),
-      base::BindOnce(
-          &GetFileForSavingOperation::GetFileForSavingAfterOpenForWrite,
-          weak_ptr_factory_.GetWeakPtr(), std::move(callback), cache_path,
-          std::move(entry), base::Owned(file_closer)));
-}
-
-void GetFileForSavingOperation::GetFileForSavingAfterOpenForWrite(
-    GetFileCallback callback,
-    const base::FilePath& cache_path,
-    std::unique_ptr<ResourceEntry> entry,
-    std::unique_ptr<base::ScopedClosureRunner>* file_closer,
-    FileError error) {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-  DCHECK(callback);
-
-  if (error != FILE_ERROR_OK) {
-    std::move(callback).Run(error, base::FilePath(),
-                            std::unique_ptr<ResourceEntry>());
-    return;
-  }
-
-  const std::string& local_id = entry->local_id();
-  file_write_watcher_->StartWatch(
-      cache_path,
-      base::Bind(&GetFileForSavingOperation::GetFileForSavingAfterWatch,
-                 weak_ptr_factory_.GetWeakPtr(),
-                 base::Passed(std::move(callback)), cache_path,
-                 base::Passed(&entry)),
-      base::Bind(&GetFileForSavingOperation::OnWriteEvent,
-                 weak_ptr_factory_.GetWeakPtr(), local_id,
-                 base::Passed(file_closer)));
-}
-
-void GetFileForSavingOperation::GetFileForSavingAfterWatch(
-    GetFileCallback callback,
-    const base::FilePath& cache_path,
-    std::unique_ptr<ResourceEntry> entry,
-    bool success) {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-  DCHECK(callback);
-
-  logger_->Log(logging::LOG_INFO, "Started watching modification to %s [%s].",
-               entry->local_id().c_str(),
-               success ? "ok" : "fail");
-
-  if (!success) {
-    std::move(callback).Run(FILE_ERROR_FAILED, base::FilePath(),
-                            std::unique_ptr<ResourceEntry>());
-    return;
-  }
-
-  std::move(callback).Run(FILE_ERROR_OK, cache_path, std::move(entry));
-}
-
-void GetFileForSavingOperation::OnWriteEvent(
-    const std::string& local_id,
-    std::unique_ptr<base::ScopedClosureRunner> file_closer) {
-  logger_->Log(logging::LOG_INFO, "Detected modification to %s.",
-               local_id.c_str());
-
-  delegate_->OnEntryUpdatedByOperation(ClientContext(USER_INITIATED), local_id);
-
-  // Clients may have enlarged the file. By FreeDiskpSpaceIfNeededFor(0),
-  // we try to ensure (0 + the-minimum-safe-margin = 512MB as of now) space.
-  blocking_task_runner_->PostTask(
-      FROM_HERE, base::BindOnce(base::IgnoreResult(
-                     base::Bind(&internal::FileCache::FreeDiskSpaceIfNeededFor,
-                                base::Unretained(cache_), 0))));
-}
-
-}  // namespace file_system
-}  // namespace drive
diff --git a/components/drive/chromeos/file_system/get_file_for_saving_operation.h b/components/drive/chromeos/file_system/get_file_for_saving_operation.h
deleted file mode 100644
index 859a917..0000000
--- a/components/drive/chromeos/file_system/get_file_for_saving_operation.h
+++ /dev/null
@@ -1,109 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef COMPONENTS_DRIVE_CHROMEOS_FILE_SYSTEM_GET_FILE_FOR_SAVING_OPERATION_H_
-#define COMPONENTS_DRIVE_CHROMEOS_FILE_SYSTEM_GET_FILE_FOR_SAVING_OPERATION_H_
-
-#include <memory>
-
-#include "base/macros.h"
-#include "base/memory/ref_counted.h"
-#include "base/memory/weak_ptr.h"
-#include "base/threading/thread_checker.h"
-#include "components/drive/chromeos/file_system_interface.h"
-#include "components/drive/file_errors.h"
-
-namespace base {
-class FilePath;
-class ScopedClosureRunner;
-class SequencedTaskRunner;
-}  // namespace base
-
-namespace drive {
-namespace internal {
-class FileCache;
-class FileWriteWatcher;
-class ResourceMetadata;
-}  // namespace internal
-
-class EventLogger;
-class JobScheduler;
-class ResourceEntry;
-
-namespace file_system {
-
-class CreateFileOperation;
-class DownloadOperation;
-class OperationDelegate;
-
-// Implements GetFileForSaving() operation that prepares a local cache for
-// a Drive file whose next modification is monitored and notified to the
-// OperationDelegate.
-// TODO(kinaba): crbug.com/269424: we might want to monitor all the changes
-// to the cache directory, not just the one immediately after the save dialog.
-class GetFileForSavingOperation {
- public:
-  GetFileForSavingOperation(EventLogger* logger,
-                            base::SequencedTaskRunner* blocking_task_runner,
-                            OperationDelegate* delegate,
-                            JobScheduler* scheduler,
-                            internal::ResourceMetadata* metadata,
-                            internal::FileCache* cache,
-                            const base::FilePath& temporary_file_directory);
-  ~GetFileForSavingOperation();
-
-  // Makes sure that |file_path| in the file system is available in the local
-  // cache, and marks it as dirty. The next modification to the cache file is
-  // watched and is automatically notified to the delegate. If the entry is not
-  // present in the file system, it is created.
-  void GetFileForSaving(const base::FilePath& file_path,
-                        GetFileCallback callback);
-
-  internal::FileWriteWatcher* file_write_watcher_for_testing() {
-    return file_write_watcher_.get();
-  }
-
- private:
-  void GetFileForSavingAfterCreate(const base::FilePath& file_path,
-                                   GetFileCallback callback,
-                                   FileError error);
-  void GetFileForSavingAfterDownload(GetFileCallback callback,
-                                     FileError error,
-                                     const base::FilePath& cache_path,
-                                     std::unique_ptr<ResourceEntry> entry);
-  void GetFileForSavingAfterOpenForWrite(
-      GetFileCallback callback,
-      const base::FilePath& cache_path,
-      std::unique_ptr<ResourceEntry> entry,
-      std::unique_ptr<base::ScopedClosureRunner>* file_closer,
-      FileError error);
-  void GetFileForSavingAfterWatch(GetFileCallback callback,
-                                  const base::FilePath& cache_path,
-                                  std::unique_ptr<ResourceEntry> entry,
-                                  bool success);
-  // Called when the cache file for |local_id| is written.
-  void OnWriteEvent(const std::string& local_id,
-                    std::unique_ptr<base::ScopedClosureRunner> file_closer);
-
-  EventLogger* logger_;
-  std::unique_ptr<CreateFileOperation> create_file_operation_;
-  std::unique_ptr<DownloadOperation> download_operation_;
-  std::unique_ptr<internal::FileWriteWatcher> file_write_watcher_;
-  scoped_refptr<base::SequencedTaskRunner> blocking_task_runner_;
-  OperationDelegate* delegate_;
-  internal::ResourceMetadata* metadata_;
-  internal::FileCache* cache_;
-
-  THREAD_CHECKER(thread_checker_);
-
-  // Note: This should remain the last member so it'll be destroyed and
-  // invalidate the weak pointers before any other members are destroyed.
-  base::WeakPtrFactory<GetFileForSavingOperation> weak_ptr_factory_{this};
-  DISALLOW_COPY_AND_ASSIGN(GetFileForSavingOperation);
-};
-
-}  // namespace file_system
-}  // namespace drive
-
-#endif  // COMPONENTS_DRIVE_CHROMEOS_FILE_SYSTEM_GET_FILE_FOR_SAVING_OPERATION_H_
diff --git a/components/drive/chromeos/file_system/move_operation.cc b/components/drive/chromeos/file_system/move_operation.cc
deleted file mode 100644
index dc682cb..0000000
--- a/components/drive/chromeos/file_system/move_operation.cc
+++ /dev/null
@@ -1,120 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "components/drive/chromeos/file_system/move_operation.h"
-
-#include "base/bind.h"
-#include "base/sequenced_task_runner.h"
-#include "components/drive/chromeos/file_system/operation_delegate.h"
-#include "components/drive/chromeos/resource_metadata.h"
-#include "components/drive/drive.pb.h"
-#include "components/drive/file_change.h"
-#include "components/drive/job_scheduler.h"
-
-namespace drive {
-namespace file_system {
-namespace {
-
-// Looks up ResourceEntry for source entry and the destination directory.
-FileError UpdateLocalState(internal::ResourceMetadata* metadata,
-                           const base::FilePath& src_path,
-                           const base::FilePath& dest_path,
-                           FileChange* changed_files,
-                           std::string* local_id) {
-  ResourceEntry entry;
-  FileError error = metadata->GetResourceEntryByPath(src_path, &entry);
-  if (error != FILE_ERROR_OK)
-    return error;
-  *local_id = entry.local_id();
-
-  ResourceEntry parent_entry;
-  error = metadata->GetResourceEntryByPath(dest_path.DirName(), &parent_entry);
-  if (error != FILE_ERROR_OK)
-    return error;
-
-  // The parent must be a directory.
-  if (!parent_entry.file_info().is_directory())
-    return FILE_ERROR_NOT_A_DIRECTORY;
-
-  changed_files->Update(src_path, entry, FileChange::CHANGE_TYPE_DELETE);
-
-  // Strip the extension for a hosted document if necessary.
-  const std::string new_extension =
-      base::FilePath(dest_path.Extension()).AsUTF8Unsafe();
-  const bool has_hosted_document_extension =
-      entry.has_file_specific_info() &&
-      entry.file_specific_info().is_hosted_document() &&
-      new_extension == entry.file_specific_info().document_extension();
-  const std::string new_title =
-      has_hosted_document_extension ?
-      dest_path.BaseName().RemoveExtension().AsUTF8Unsafe() :
-      dest_path.BaseName().AsUTF8Unsafe();
-
-  entry.set_title(new_title);
-  entry.set_parent_local_id(parent_entry.local_id());
-  entry.set_metadata_edit_state(ResourceEntry::DIRTY);
-  entry.set_modification_date(base::Time::Now().ToInternalValue());
-  error = metadata->RefreshEntry(entry);
-  if (error != FILE_ERROR_OK)
-    return error;
-
-  changed_files->Update(dest_path, entry,
-                        FileChange::CHANGE_TYPE_ADD_OR_UPDATE);
-  return FILE_ERROR_OK;
-}
-
-}  // namespace
-
-MoveOperation::MoveOperation(base::SequencedTaskRunner* blocking_task_runner,
-                             OperationDelegate* delegate,
-                             internal::ResourceMetadata* metadata)
-    : blocking_task_runner_(blocking_task_runner),
-      delegate_(delegate),
-      metadata_(metadata) {}
-
-MoveOperation::~MoveOperation() {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-}
-
-void MoveOperation::Move(const base::FilePath& src_file_path,
-                         const base::FilePath& dest_file_path,
-                         const FileOperationCallback& callback) {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-  DCHECK(callback);
-
-  FileChange* changed_files = new FileChange;
-  std::string* local_id = new std::string;
-  base::PostTaskAndReplyWithResult(
-      blocking_task_runner_.get(),
-      FROM_HERE,
-      base::Bind(&UpdateLocalState,
-                 metadata_,
-                 src_file_path,
-                 dest_file_path,
-                 changed_files,
-                 local_id),
-      base::Bind(&MoveOperation::MoveAfterUpdateLocalState,
-                 weak_ptr_factory_.GetWeakPtr(),
-                 callback,
-                 base::Owned(changed_files),
-                 base::Owned(local_id)));
-}
-
-void MoveOperation::MoveAfterUpdateLocalState(
-    const FileOperationCallback& callback,
-    const FileChange* changed_files,
-    const std::string* local_id,
-    FileError error) {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-  if (error == FILE_ERROR_OK) {
-    // Notify the change of directory.
-    delegate_->OnFileChangedByOperation(*changed_files);
-    delegate_->OnEntryUpdatedByOperation(ClientContext(USER_INITIATED),
-                                         *local_id);
-  }
-  callback.Run(error);
-}
-
-}  // namespace file_system
-}  // namespace drive
diff --git a/components/drive/chromeos/file_system/move_operation.h b/components/drive/chromeos/file_system/move_operation.h
deleted file mode 100644
index ede00a5..0000000
--- a/components/drive/chromeos/file_system/move_operation.h
+++ /dev/null
@@ -1,79 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef COMPONENTS_DRIVE_CHROMEOS_FILE_SYSTEM_MOVE_OPERATION_H_
-#define COMPONENTS_DRIVE_CHROMEOS_FILE_SYSTEM_MOVE_OPERATION_H_
-
-#include <memory>
-#include <set>
-
-#include "base/macros.h"
-#include "base/memory/ref_counted.h"
-#include "base/memory/weak_ptr.h"
-#include "base/threading/thread_checker.h"
-#include "components/drive/file_errors.h"
-#include "google_apis/drive/drive_api_error_codes.h"
-
-namespace base {
-class FilePath;
-class SequencedTaskRunner;
-}  // namespace base
-
-namespace google_apis {
-class ResourceEntry;
-}  // namespace google_apis
-
-namespace drive {
-
-class FileChange;
-class ResourceEntry;
-
-namespace internal {
-class ResourceMetadata;
-}  // namespace internal
-
-namespace file_system {
-
-class OperationDelegate;
-
-// This class encapsulates the drive Move function.  It is responsible for
-// updating the local metadata entry.
-class MoveOperation {
- public:
-  MoveOperation(base::SequencedTaskRunner* blocking_task_runner,
-                OperationDelegate* delegate,
-                internal::ResourceMetadata* metadata);
-  ~MoveOperation();
-
-  // Performs the move operation on the file at drive path |src_file_path|
-  // with a target of |dest_file_path|.
-  // Invokes |callback| when finished with the result of the operation.
-  // |callback| must not be null.
-  void Move(const base::FilePath& src_file_path,
-            const base::FilePath& dest_file_path,
-            const FileOperationCallback& callback);
-
- private:
-  // Part of Move(). Called after updating the local state.
-  void MoveAfterUpdateLocalState(const FileOperationCallback& callback,
-                                 const FileChange* changed_file,
-                                 const std::string* local_id,
-                                 FileError error);
-
-  scoped_refptr<base::SequencedTaskRunner> blocking_task_runner_;
-  OperationDelegate* delegate_;
-  internal::ResourceMetadata* metadata_;
-
-  THREAD_CHECKER(thread_checker_);
-
-  // Note: This should remain the last member so it'll be destroyed and
-  // invalidate the weak pointers before any other members are destroyed.
-  base::WeakPtrFactory<MoveOperation> weak_ptr_factory_{this};
-  DISALLOW_COPY_AND_ASSIGN(MoveOperation);
-};
-
-}  // namespace file_system
-}  // namespace drive
-
-#endif  // COMPONENTS_DRIVE_CHROMEOS_FILE_SYSTEM_MOVE_OPERATION_H_
diff --git a/components/drive/chromeos/file_system/open_file_operation.cc b/components/drive/chromeos/file_system/open_file_operation.cc
deleted file mode 100644
index cbb3822..0000000
--- a/components/drive/chromeos/file_system/open_file_operation.cc
+++ /dev/null
@@ -1,176 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "components/drive/chromeos/file_system/open_file_operation.h"
-
-#include "base/bind.h"
-#include "base/bind_helpers.h"
-#include "base/callback_helpers.h"
-#include "base/files/file_path.h"
-#include "base/logging.h"
-#include "base/task_runner_util.h"
-#include "base/threading/thread_task_runner_handle.h"
-#include "components/drive/chromeos/file_cache.h"
-#include "components/drive/chromeos/file_system/create_file_operation.h"
-#include "components/drive/chromeos/file_system/download_operation.h"
-#include "components/drive/chromeos/file_system/operation_delegate.h"
-#include "components/drive/drive.pb.h"
-#include "components/drive/file_errors.h"
-#include "components/drive/job_scheduler.h"
-
-namespace drive {
-namespace file_system {
-
-OpenFileOperation::OpenFileOperation(
-    base::SequencedTaskRunner* blocking_task_runner,
-    OperationDelegate* delegate,
-    JobScheduler* scheduler,
-    internal::ResourceMetadata* metadata,
-    internal::FileCache* cache,
-    const base::FilePath& temporary_file_directory)
-    : blocking_task_runner_(blocking_task_runner),
-      delegate_(delegate),
-      cache_(cache),
-      create_file_operation_(
-          new CreateFileOperation(blocking_task_runner, delegate, metadata)),
-      download_operation_(new DownloadOperation(blocking_task_runner,
-                                                delegate,
-                                                scheduler,
-                                                metadata,
-                                                cache,
-                                                temporary_file_directory)) {}
-
-OpenFileOperation::~OpenFileOperation() = default;
-
-void OpenFileOperation::OpenFile(const base::FilePath& file_path,
-                                 OpenMode open_mode,
-                                 const std::string& mime_type,
-                                 OpenFileCallback callback) {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-  DCHECK(callback);
-
-  switch (open_mode) {
-    case OPEN_FILE:
-      // It is not necessary to create a new file even if not exists.
-      // So call OpenFileAfterCreateFile directly with FILE_ERROR_OK
-      // to skip file creation.
-      OpenFileAfterCreateFile(file_path, std::move(callback), FILE_ERROR_OK);
-      break;
-    case CREATE_FILE:
-      create_file_operation_->CreateFile(
-          file_path,
-          true,  // exclusive: fail if already exists
-          mime_type,
-          base::BindRepeating(&OpenFileOperation::OpenFileAfterCreateFile,
-                              weak_ptr_factory_.GetWeakPtr(), file_path,
-                              base::Passed(std::move(callback))));
-      break;
-    case OPEN_OR_CREATE_FILE:
-      create_file_operation_->CreateFile(
-          file_path,
-          false,  // not-exclusive
-          mime_type,
-          base::BindRepeating(&OpenFileOperation::OpenFileAfterCreateFile,
-                              weak_ptr_factory_.GetWeakPtr(), file_path,
-                              base::Passed(std::move(callback))));
-      break;
-  }
-}
-
-void OpenFileOperation::OpenFileAfterCreateFile(const base::FilePath& file_path,
-                                                OpenFileCallback callback,
-                                                FileError error) {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-  DCHECK(callback);
-
-  if (error != FILE_ERROR_OK) {
-    std::move(callback).Run(error, base::FilePath(), base::Closure());
-    return;
-  }
-
-  download_operation_->EnsureFileDownloadedByPath(
-      file_path, ClientContext(USER_INITIATED),
-      GetFileContentInitializedCallback(), google_apis::GetContentCallback(),
-      base::BindOnce(&OpenFileOperation::OpenFileAfterFileDownloaded,
-                     weak_ptr_factory_.GetWeakPtr(), std::move(callback)));
-}
-
-void OpenFileOperation::OpenFileAfterFileDownloaded(
-    OpenFileCallback callback,
-    FileError error,
-    const base::FilePath& local_file_path,
-    std::unique_ptr<ResourceEntry> entry) {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-  DCHECK(callback);
-
-  if (error == FILE_ERROR_OK) {
-    DCHECK(entry);
-    DCHECK(entry->has_file_specific_info());
-    if (entry->file_specific_info().is_hosted_document())
-      // No support for opening a hosted document.
-      error = FILE_ERROR_INVALID_OPERATION;
-  }
-
-  if (error != FILE_ERROR_OK) {
-    std::move(callback).Run(error, base::FilePath(), base::Closure());
-    return;
-  }
-
-  std::unique_ptr<base::ScopedClosureRunner>* file_closer =
-      new std::unique_ptr<base::ScopedClosureRunner>;
-  base::PostTaskAndReplyWithResult(
-      blocking_task_runner_.get(), FROM_HERE,
-      base::BindOnce(&internal::FileCache::OpenForWrite,
-                     base::Unretained(cache_), entry->local_id(), file_closer),
-      base::BindOnce(&OpenFileOperation::OpenFileAfterOpenForWrite,
-                     weak_ptr_factory_.GetWeakPtr(), local_file_path,
-                     entry->local_id(), std::move(callback),
-                     base::Owned(file_closer)));
-}
-
-void OpenFileOperation::OpenFileAfterOpenForWrite(
-    const base::FilePath& local_file_path,
-    const std::string& local_id,
-    OpenFileCallback callback,
-    std::unique_ptr<base::ScopedClosureRunner>* file_closer,
-    FileError error) {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-  DCHECK(callback);
-
-  if (error != FILE_ERROR_OK) {
-    std::move(callback).Run(error, base::FilePath(), base::Closure());
-    return;
-  }
-
-  ++open_files_[local_id];
-  std::move(callback).Run(
-      error, local_file_path,
-      base::BindRepeating(&OpenFileOperation::CloseFile,
-                          weak_ptr_factory_.GetWeakPtr(), local_id,
-                          base::Passed(file_closer)));
-}
-
-void OpenFileOperation::CloseFile(
-    const std::string& local_id,
-    std::unique_ptr<base::ScopedClosureRunner> file_closer) {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-  DCHECK_GT(open_files_[local_id], 0);
-
-  if (--open_files_[local_id] == 0) {
-    // All clients closes this file, so notify to upload the file.
-    open_files_.erase(local_id);
-    delegate_->OnEntryUpdatedByOperation(ClientContext(USER_INITIATED),
-                                         local_id);
-
-    // Clients may have enlarged the file. By FreeDiskpSpaceIfNeededFor(0),
-    // we try to ensure (0 + the-minimum-safe-margin = 512MB as of now) space.
-    blocking_task_runner_->PostTask(
-        FROM_HERE, base::BindOnce(base::IgnoreResult(base::Bind(
-                       &internal::FileCache::FreeDiskSpaceIfNeededFor,
-                       base::Unretained(cache_), 0))));
-  }
-}
-
-}  // namespace file_system
-}  // namespace drive
diff --git a/components/drive/chromeos/file_system/open_file_operation.h b/components/drive/chromeos/file_system/open_file_operation.h
deleted file mode 100644
index 81a693e..0000000
--- a/components/drive/chromeos/file_system/open_file_operation.h
+++ /dev/null
@@ -1,109 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef COMPONENTS_DRIVE_CHROMEOS_FILE_SYSTEM_OPEN_FILE_OPERATION_H_
-#define COMPONENTS_DRIVE_CHROMEOS_FILE_SYSTEM_OPEN_FILE_OPERATION_H_
-
-#include <map>
-#include <memory>
-
-#include "base/macros.h"
-#include "base/memory/ref_counted.h"
-#include "base/memory/weak_ptr.h"
-#include "base/threading/thread_checker.h"
-#include "components/drive/chromeos/file_system_interface.h"
-#include "components/drive/file_errors.h"
-
-namespace base {
-class FilePath;
-class ScopedClosureRunner;
-class SequencedTaskRunner;
-}  // namespace base
-
-namespace drive {
-
-class JobScheduler;
-class ResourceEntry;
-
-namespace internal {
-class ResourceMetadata;
-class FileCache;
-}  // namespace internal
-
-namespace file_system {
-
-class CreateFileOperation;
-class DownloadOperation;
-class OperationDelegate;
-
-class OpenFileOperation {
- public:
-  OpenFileOperation(base::SequencedTaskRunner* blocking_task_runner,
-                    OperationDelegate* delegate,
-                    JobScheduler* scheduler,
-                    internal::ResourceMetadata* metadata,
-                    internal::FileCache* cache,
-                    const base::FilePath& temporary_file_directory);
-  ~OpenFileOperation();
-
-  // Opens the file at |file_path|.
-  // If the file is not actually downloaded, this method starts
-  // to download it to the cache, and then runs |callback| upon the
-  // completion with the path to the local cache file.
-  // See also the definition of OpenMode for its meaning.
-  // If |mime_type| is non empty and the file is created by this OpenFile()
-  // call, the mime type is used as the file's property.
-  // |callback| must not be null.
-  void OpenFile(const base::FilePath& file_path,
-                OpenMode open_mode,
-                const std::string& mime_type,
-                OpenFileCallback callback);
-
- private:
-  // Part of OpenFile(). Called after file creation is completed.
-  void OpenFileAfterCreateFile(const base::FilePath& file_path,
-                               OpenFileCallback callback,
-                               FileError error);
-
-  // Part of OpenFile(). Called after file downloading is completed.
-  void OpenFileAfterFileDownloaded(OpenFileCallback callback,
-                                   FileError error,
-                                   const base::FilePath& local_file_path,
-                                   std::unique_ptr<ResourceEntry> entry);
-
-  // Part of OpenFile(). Called after opening the cache file.
-  void OpenFileAfterOpenForWrite(
-      const base::FilePath& local_file_path,
-      const std::string& local_id,
-      OpenFileCallback callback,
-      std::unique_ptr<base::ScopedClosureRunner>* file_closer,
-      FileError error);
-
-  // Closes the file with |local_id|.
-  void CloseFile(const std::string& local_id,
-                 std::unique_ptr<base::ScopedClosureRunner> file_closer);
-
-  scoped_refptr<base::SequencedTaskRunner> blocking_task_runner_;
-  OperationDelegate* delegate_;
-  internal::FileCache* cache_;
-
-  std::unique_ptr<CreateFileOperation> create_file_operation_;
-  std::unique_ptr<DownloadOperation> download_operation_;
-
-  // The map from local id for an opened file to the number how many times
-  // the file is opened.
-  std::map<std::string, int> open_files_;
-
-  THREAD_CHECKER(thread_checker_);
-
-  // Note: This should remain the last member so it'll be destroyed and
-  // invalidate its weak pointers before any other members are destroyed.
-  base::WeakPtrFactory<OpenFileOperation> weak_ptr_factory_{this};
-  DISALLOW_COPY_AND_ASSIGN(OpenFileOperation);
-};
-
-}  // namespace file_system
-}  // namespace drive
-
-#endif  // COMPONENTS_DRIVE_CHROMEOS_FILE_SYSTEM_OPEN_FILE_OPERATION_H_
diff --git a/components/drive/chromeos/file_system/operation_delegate.cc b/components/drive/chromeos/file_system/operation_delegate.cc
deleted file mode 100644
index 0570e4a..0000000
--- a/components/drive/chromeos/file_system/operation_delegate.cc
+++ /dev/null
@@ -1,17 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "components/drive/chromeos/file_system/operation_delegate.h"
-
-namespace drive {
-namespace file_system {
-
-bool OperationDelegate::WaitForSyncComplete(
-    const std::string& local_id,
-    const FileOperationCallback& callback) {
-  return false;
-}
-
-}  // namespace file_system
-}  // namespace drive
diff --git a/components/drive/chromeos/file_system/operation_delegate.h b/components/drive/chromeos/file_system/operation_delegate.h
deleted file mode 100644
index edbcc6b..0000000
--- a/components/drive/chromeos/file_system/operation_delegate.h
+++ /dev/null
@@ -1,57 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef COMPONENTS_DRIVE_CHROMEOS_FILE_SYSTEM_OPERATION_DELEGATE_H_
-#define COMPONENTS_DRIVE_CHROMEOS_FILE_SYSTEM_OPERATION_DELEGATE_H_
-
-#include "components/drive/file_errors.h"
-
-namespace drive {
-
-struct ClientContext;
-class FileChange;
-
-namespace file_system {
-
-// Error type of sync client.
-// Keep it synced with "DriveSyncErrorType" in file_manager_private.idl.
-enum DriveSyncErrorType {
-  // Request to delete a file without permission.
-  DRIVE_SYNC_ERROR_DELETE_WITHOUT_PERMISSION,
-  // Google Drive is temporary unavailable.
-  DRIVE_SYNC_ERROR_SERVICE_UNAVAILABLE,
-  // There is no server space to sync a file.
-  DRIVE_SYNC_ERROR_NO_SERVER_SPACE,
-  // Errors other than above ones. No fallback is provided for the error.
-  DRIVE_SYNC_ERROR_MISC,
-};
-
-// Passes notifications from Drive operations back to the file system.
-class OperationDelegate {
- public:
-  // Sent when a content of a directory has been changed.
-  // |directory_path| is a virtual directory path representing the
-  // changed directory.
-  virtual void OnFileChangedByOperation(const FileChange& changed_files) {}
-
-  // Sent when an entry is updated and sync is needed. The passed |context| is
-  // used for syncing.
-  virtual void OnEntryUpdatedByOperation(const ClientContext& context,
-                                         const std::string& local_id) {}
-
-  // Sent when a specific drive sync error occurred.
-  // |local_id| is the local ID of the resource entry.
-  virtual void OnDriveSyncError(DriveSyncErrorType type,
-                                const std::string& local_id) {}
-
-  // Waits for the sync task to complete and runs the callback.
-  // Returns false if no task is found for the spcecified ID.
-  virtual bool WaitForSyncComplete(const std::string& local_id,
-                                   const FileOperationCallback& callback);
-};
-
-}  // namespace file_system
-}  // namespace drive
-
-#endif  // COMPONENTS_DRIVE_CHROMEOS_FILE_SYSTEM_OPERATION_DELEGATE_H_
diff --git a/components/drive/chromeos/file_system/remove_operation.cc b/components/drive/chromeos/file_system/remove_operation.cc
deleted file mode 100644
index f676c96..0000000
--- a/components/drive/chromeos/file_system/remove_operation.cc
+++ /dev/null
@@ -1,126 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "components/drive/chromeos/file_system/remove_operation.h"
-
-#include "base/bind.h"
-#include "base/sequenced_task_runner.h"
-#include "components/drive/chromeos/file_cache.h"
-#include "components/drive/chromeos/file_system/operation_delegate.h"
-#include "components/drive/chromeos/resource_metadata.h"
-#include "components/drive/drive.pb.h"
-#include "components/drive/file_change.h"
-#include "components/drive/file_system_core_util.h"
-#include "components/drive/job_scheduler.h"
-
-namespace drive {
-namespace file_system {
-
-namespace {
-
-// Removes cache file and moves the metadata entry to the trash.
-FileError UpdateLocalState(internal::ResourceMetadata* metadata,
-                           internal::FileCache* cache,
-                           const base::FilePath& path,
-                           bool is_recursive,
-                           std::string* local_id,
-                           ResourceEntry* entry,
-                           base::FilePath* changed_path) {
-  FileError error = metadata->GetIdByPath(path, local_id);
-  if (error != FILE_ERROR_OK)
-    return error;
-
-  error = metadata->GetResourceEntryById(*local_id, entry);
-  if (error != FILE_ERROR_OK)
-    return error;
-
-  if (entry->file_info().is_directory() && !is_recursive) {
-    // Check emptiness of the directory.
-    ResourceEntryVector entries;
-    error = metadata->ReadDirectoryByPath(path, &entries);
-    if (error != FILE_ERROR_OK)
-      return error;
-    if (!entries.empty())
-      return FILE_ERROR_NOT_EMPTY;
-  }
-
-  error = cache->Remove(*local_id);
-  if (error != FILE_ERROR_OK)
-    return error;
-
-  *changed_path = path;
-
-  // Move to the trash.
-  entry->set_parent_local_id(util::kDriveTrashDirLocalId);
-  return metadata->RefreshEntry(*entry);
-}
-
-}  // namespace
-
-RemoveOperation::RemoveOperation(
-    base::SequencedTaskRunner* blocking_task_runner,
-    OperationDelegate* delegate,
-    internal::ResourceMetadata* metadata,
-    internal::FileCache* cache)
-    : blocking_task_runner_(blocking_task_runner),
-      delegate_(delegate),
-      metadata_(metadata),
-      cache_(cache) {}
-
-RemoveOperation::~RemoveOperation() {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-}
-
-void RemoveOperation::Remove(const base::FilePath& path,
-                             bool is_recursive,
-                             const FileOperationCallback& callback) {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-  DCHECK(callback);
-
-  std::string* local_id = new std::string;
-  base::FilePath* changed_path = new base::FilePath;
-  ResourceEntry* entry = new ResourceEntry;
-  base::PostTaskAndReplyWithResult(
-      blocking_task_runner_.get(),
-      FROM_HERE,
-      base::Bind(&UpdateLocalState,
-                 metadata_,
-                 cache_,
-                 path,
-                 is_recursive,
-                 local_id,
-                 entry,
-                 changed_path),
-      base::Bind(&RemoveOperation::RemoveAfterUpdateLocalState,
-                 weak_ptr_factory_.GetWeakPtr(),
-                 callback,
-                 base::Owned(local_id),
-                 base::Owned(entry),
-                 base::Owned(changed_path)));
-}
-
-void RemoveOperation::RemoveAfterUpdateLocalState(
-    const FileOperationCallback& callback,
-    const std::string* local_id,
-    const ResourceEntry* entry,
-    const base::FilePath* changed_path,
-    FileError error) {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-  DCHECK(callback);
-
-  if (!changed_path->empty()) {
-    FileChange changed_file;
-    changed_file.Update(*changed_path, *entry, FileChange::CHANGE_TYPE_DELETE);
-    if (error == FILE_ERROR_OK) {
-      delegate_->OnFileChangedByOperation(changed_file);
-      delegate_->OnEntryUpdatedByOperation(ClientContext(USER_INITIATED),
-                                           *local_id);
-    }
-  }
-
-  callback.Run(error);
-}
-
-}  // namespace file_system
-}  // namespace drive
diff --git a/components/drive/chromeos/file_system/remove_operation.h b/components/drive/chromeos/file_system/remove_operation.h
deleted file mode 100644
index 78ca914..0000000
--- a/components/drive/chromeos/file_system/remove_operation.h
+++ /dev/null
@@ -1,78 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef COMPONENTS_DRIVE_CHROMEOS_FILE_SYSTEM_REMOVE_OPERATION_H_
-#define COMPONENTS_DRIVE_CHROMEOS_FILE_SYSTEM_REMOVE_OPERATION_H_
-
-#include <memory>
-
-#include "base/macros.h"
-#include "base/memory/ref_counted.h"
-#include "base/memory/weak_ptr.h"
-#include "base/threading/thread_checker.h"
-#include "components/drive/file_errors.h"
-#include "google_apis/drive/drive_api_error_codes.h"
-
-namespace base {
-class FilePath;
-class SequencedTaskRunner;
-}  // namespace base
-
-namespace drive {
-
-class ResourceEntry;
-
-namespace internal {
-class FileCache;
-class ResourceMetadata;
-}  // namespace internal
-
-namespace file_system {
-
-class OperationDelegate;
-
-// This class encapsulates the drive Remove function.  It is responsible for
-// moving the removed entry to the trash.
-class RemoveOperation {
- public:
-  RemoveOperation(base::SequencedTaskRunner* blocking_task_runner,
-                  OperationDelegate* delegate,
-                  internal::ResourceMetadata* metadata,
-                  internal::FileCache* cache);
-  ~RemoveOperation();
-
-  // Removes the resource at |path|. If |path| is a directory and |is_recursive|
-  // is set, it recursively removes all the descendants. If |is_recursive| is
-  // not set, it succeeds only when the directory is empty.
-  //
-  // |callback| must not be null.
-  void Remove(const base::FilePath& path,
-              bool is_recursive,
-              const FileOperationCallback& callback);
-
- private:
-  // Part of Remove(). Called after UpdateLocalState() completion.
-  void RemoveAfterUpdateLocalState(const FileOperationCallback& callback,
-                                   const std::string* local_id,
-                                   const ResourceEntry* entry,
-                                   const base::FilePath* changed_directory_path,
-                                   FileError error);
-
-  scoped_refptr<base::SequencedTaskRunner> blocking_task_runner_;
-  OperationDelegate* delegate_;
-  internal::ResourceMetadata* metadata_;
-  internal::FileCache* cache_;
-
-  THREAD_CHECKER(thread_checker_);
-
-  // Note: This should remain the last member so it'll be destroyed and
-  // invalidate the weak pointers before any other members are destroyed.
-  base::WeakPtrFactory<RemoveOperation> weak_ptr_factory_{this};
-  DISALLOW_COPY_AND_ASSIGN(RemoveOperation);
-};
-
-}  // namespace file_system
-}  // namespace drive
-
-#endif  // COMPONENTS_DRIVE_CHROMEOS_FILE_SYSTEM_REMOVE_OPERATION_H_
diff --git a/components/drive/chromeos/file_system/search_operation.cc b/components/drive/chromeos/file_system/search_operation.cc
deleted file mode 100644
index 696722c4..0000000
--- a/components/drive/chromeos/file_system/search_operation.cc
+++ /dev/null
@@ -1,176 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "components/drive/chromeos/file_system/search_operation.h"
-
-#include <stddef.h>
-
-#include <memory>
-#include <string>
-#include <utility>
-#include <vector>
-
-#include "base/bind.h"
-#include "base/bind_helpers.h"
-#include "base/callback.h"
-#include "components/drive/chromeos/loader_controller.h"
-#include "components/drive/chromeos/resource_metadata.h"
-#include "components/drive/drive_api_util.h"
-#include "components/drive/file_system_core_util.h"
-#include "components/drive/job_scheduler.h"
-#include "components/drive/resource_entry_conversion.h"
-#include "google_apis/drive/drive_api_parser.h"
-#include "url/gurl.h"
-
-namespace drive {
-namespace file_system {
-namespace {
-
-// Computes the path of each item in |file_list| returned from the server
-// and stores to |result|, by using |resource_metadata|. If the metadata is not
-// up to date and did not contain an item, adds the item to "drive/other" for
-// temporally assigning a path.
-FileError ResolveSearchResultOnBlockingPool(
-    internal::ResourceMetadata* resource_metadata,
-    std::unique_ptr<google_apis::FileList> file_list,
-    std::vector<SearchResultInfo>* result) {
-  DCHECK(resource_metadata);
-  DCHECK(result);
-
-  const std::vector<std::unique_ptr<google_apis::FileResource>>& entries =
-      file_list->items();
-  result->reserve(entries.size());
-  for (size_t i = 0; i < entries.size(); ++i) {
-    std::string local_id;
-    FileError error = resource_metadata->GetIdByResourceId(
-        entries[i]->file_id(), &local_id);
-
-    ResourceEntry entry;
-    if (error == FILE_ERROR_OK)
-      error = resource_metadata->GetResourceEntryById(local_id, &entry);
-
-    if (error == FILE_ERROR_NOT_FOUND) {
-      std::string original_parent_id;
-      ConvertFileResourceToResourceEntry(*entries[i], &entry,
-                                         &original_parent_id);
-
-      // The result is absent in local resource metadata. This can happen if
-      // the metadata is not synced to the latest server state yet. In that
-      // case, we temporarily add the file to the special "drive/other"
-      // directory in order to assign a path, which is needed to access the
-      // file through FileSystem API.
-      //
-      // It will be moved to the right place when the metadata gets synced
-      // in normal loading process in ChangeListProcessor.
-      entry.set_parent_local_id(util::kDriveOtherDirLocalId);
-      error = resource_metadata->AddEntry(entry, &local_id);
-    }
-    if (error != FILE_ERROR_OK)
-      return error;
-    base::FilePath path;
-    error = resource_metadata->GetFilePath(local_id, &path);
-    if (error != FILE_ERROR_OK)
-      return error;
-    result->push_back(SearchResultInfo(path, entry.file_info().is_directory()));
-  }
-
-  return FILE_ERROR_OK;
-}
-
-}  // namespace
-
-SearchOperation::SearchOperation(
-    base::SequencedTaskRunner* blocking_task_runner,
-    JobScheduler* scheduler,
-    internal::ResourceMetadata* metadata,
-    internal::LoaderController* loader_controller)
-    : blocking_task_runner_(blocking_task_runner),
-      scheduler_(scheduler),
-      metadata_(metadata),
-      loader_controller_(loader_controller) {}
-
-SearchOperation::~SearchOperation() = default;
-
-void SearchOperation::Search(const std::string& search_query,
-                             const GURL& next_link,
-                             SearchCallback callback) {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-  DCHECK(callback);
-
-  if (next_link.is_empty()) {
-    // This is first request for the |search_query|.
-    scheduler_->Search(search_query,
-                       base::Bind(&SearchOperation::SearchAfterGetFileList,
-                                  weak_ptr_factory_.GetWeakPtr(),
-                                  base::Passed(std::move(callback))));
-  } else {
-    // There is the remaining result so fetch it.
-    scheduler_->GetRemainingFileList(
-        next_link, base::Bind(&SearchOperation::SearchAfterGetFileList,
-                              weak_ptr_factory_.GetWeakPtr(),
-                              base::Passed(std::move(callback))));
-  }
-}
-
-void SearchOperation::SearchAfterGetFileList(
-    SearchCallback callback,
-    google_apis::DriveApiErrorCode gdata_error,
-    std::unique_ptr<google_apis::FileList> file_list) {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-  DCHECK(callback);
-
-  FileError error = GDataToFileError(gdata_error);
-  if (error != FILE_ERROR_OK) {
-    std::move(callback).Run(error, GURL(),
-                            std::unique_ptr<std::vector<SearchResultInfo>>());
-    return;
-  }
-
-  DCHECK(file_list);
-
-  GURL next_url = file_list->next_link();
-
-  std::unique_ptr<std::vector<SearchResultInfo>> result(
-      new std::vector<SearchResultInfo>);
-  if (file_list->items().empty()) {
-    // Short cut. If the resource entry is empty, we don't need to refresh
-    // the resource metadata.
-    std::move(callback).Run(FILE_ERROR_OK, next_url, std::move(result));
-    return;
-  }
-
-  // ResolveSearchResultOnBlockingPool() may add entries newly created on the
-  // server to the local metadata.
-  // This may race with sync tasks so we should ask LoaderController here.
-  std::vector<SearchResultInfo>* result_ptr = result.get();
-  loader_controller_->ScheduleRun(base::BindOnce(
-      &drive::util::RunAsyncTask, base::RetainedRef(blocking_task_runner_),
-      FROM_HERE,
-      base::BindOnce(&ResolveSearchResultOnBlockingPool, metadata_,
-                     std::move(file_list), result_ptr),
-      base::BindOnce(&SearchOperation::SearchAfterResolveSearchResult,
-                     weak_ptr_factory_.GetWeakPtr(), std::move(callback),
-                     next_url, std::move(result))));
-}
-
-void SearchOperation::SearchAfterResolveSearchResult(
-    SearchCallback callback,
-    const GURL& next_link,
-    std::unique_ptr<std::vector<SearchResultInfo>> result,
-    FileError error) {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-  DCHECK(callback);
-  DCHECK(result);
-
-  if (error != FILE_ERROR_OK) {
-    std::move(callback).Run(error, GURL(),
-                            std::unique_ptr<std::vector<SearchResultInfo>>());
-    return;
-  }
-
-  std::move(callback).Run(error, next_link, std::move(result));
-}
-
-}  // namespace file_system
-}  // namespace drive
diff --git a/components/drive/chromeos/file_system/search_operation.h b/components/drive/chromeos/file_system/search_operation.h
deleted file mode 100644
index 2246974..0000000
--- a/components/drive/chromeos/file_system/search_operation.h
+++ /dev/null
@@ -1,86 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef COMPONENTS_DRIVE_CHROMEOS_FILE_SYSTEM_SEARCH_OPERATION_H_
-#define COMPONENTS_DRIVE_CHROMEOS_FILE_SYSTEM_SEARCH_OPERATION_H_
-
-#include <memory>
-
-#include "base/macros.h"
-#include "base/memory/ref_counted.h"
-#include "base/memory/weak_ptr.h"
-#include "base/threading/thread_checker.h"
-#include "components/drive/chromeos/file_system_interface.h"
-#include "components/drive/file_errors.h"
-#include "google_apis/drive/drive_api_error_codes.h"
-
-namespace base {
-class SequencedTaskRunner;
-}  // namespace base
-
-namespace google_apis {
-class FileList;
-}  // namespace google_apis
-
-namespace drive {
-
-class JobScheduler;
-
-namespace internal {
-class LoaderController;
-class ResourceMetadata;
-}  // namespace internal
-
-namespace file_system {
-
-// This class encapsulates the drive Search function. It is responsible for
-// sending the request to the drive API.
-class SearchOperation {
- public:
-  SearchOperation(base::SequencedTaskRunner* blocking_task_runner,
-                  JobScheduler* scheduler,
-                  internal::ResourceMetadata* metadata,
-                  internal::LoaderController* loader_controller);
-  ~SearchOperation();
-
-  // Performs server side content search operation for |search_query|.  If
-  // |next_link| is set, this is the search result url that will be fetched.
-  // Upon completion, |callback| will be called with the result.  This is
-  // implementation of FileSystemInterface::Search() method.
-  //
-  // |callback| must not be null.
-  void Search(const std::string& search_query,
-              const GURL& next_link,
-              SearchCallback callback);
-
- private:
-  // Part of Search(), called after the FileList is fetched from the server.
-  void SearchAfterGetFileList(SearchCallback callback,
-                              google_apis::DriveApiErrorCode gdata_error,
-                              std::unique_ptr<google_apis::FileList> file_list);
-
-  // Part of Search(), called after |result| is filled on the blocking pool.
-  void SearchAfterResolveSearchResult(
-      SearchCallback callback,
-      const GURL& next_link,
-      std::unique_ptr<std::vector<SearchResultInfo>> result,
-      FileError error);
-
-  scoped_refptr<base::SequencedTaskRunner> blocking_task_runner_;
-  JobScheduler* scheduler_;
-  internal::ResourceMetadata* metadata_;
-  internal::LoaderController* loader_controller_;
-
-  THREAD_CHECKER(thread_checker_);
-
-  // Note: This should remain the last member so it'll be destroyed and
-  // invalidate the weak pointers before any other members are destroyed.
-  base::WeakPtrFactory<SearchOperation> weak_ptr_factory_{this};
-  DISALLOW_COPY_AND_ASSIGN(SearchOperation);
-};
-
-}  // namespace file_system
-}  // namespace drive
-
-#endif  // COMPONENTS_DRIVE_CHROMEOS_FILE_SYSTEM_SEARCH_OPERATION_H_
diff --git a/components/drive/chromeos/file_system/set_property_operation.cc b/components/drive/chromeos/file_system/set_property_operation.cc
deleted file mode 100644
index bc256c3..0000000
--- a/components/drive/chromeos/file_system/set_property_operation.cc
+++ /dev/null
@@ -1,119 +0,0 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "components/drive/chromeos/file_system/set_property_operation.h"
-
-#include "base/bind.h"
-#include "base/files/file_path.h"
-#include "base/sequenced_task_runner.h"
-#include "components/drive/chromeos/file_system/operation_delegate.h"
-#include "components/drive/chromeos/resource_metadata.h"
-#include "components/drive/drive.pb.h"
-#include "components/drive/file_errors.h"
-#include "components/drive/job_scheduler.h"
-
-namespace drive {
-namespace file_system {
-
-namespace {
-
-// Adds the property to resource entry. Overwrites existing property if exists.
-// If no change has been made (same key, visibility and value is already added)
-// then FILE_ERROR_EXISTS is returned.
-FileError UpdateLocalState(internal::ResourceMetadata* metadata,
-                           const base::FilePath& file_path,
-                           google_apis::drive::Property::Visibility visibility,
-                           const std::string& key,
-                           const std::string& value,
-                           ResourceEntry* entry) {
-  using google_apis::drive::Property;
-  FileError error = metadata->GetResourceEntryByPath(file_path, entry);
-  if (error != FILE_ERROR_OK)
-    return error;
-
-  Property_Visibility proto_visibility = Property_Visibility_PRIVATE;
-  switch (visibility) {
-    case Property::VISIBILITY_PRIVATE:
-      proto_visibility = Property_Visibility_PRIVATE;
-      break;
-    case Property::VISIBILITY_PUBLIC:
-      proto_visibility = Property_Visibility_PUBLIC;
-      break;
-  }
-
-  ::drive::Property* property_to_update = nullptr;
-  for (auto& property : *entry->mutable_new_properties()) {
-    if (property.visibility() == proto_visibility && property.key() == key) {
-      // Exactly the same property exists, so don't update the local state.
-      if (property.value() == value)
-        return FILE_ERROR_EXISTS;
-      property_to_update = &property;
-      break;
-    }
-  }
-
-  // If no property to update has been found, then add a new one.
-  if (!property_to_update)
-    property_to_update = entry->mutable_new_properties()->Add();
-
-  property_to_update->set_visibility(proto_visibility);
-  property_to_update->set_key(key);
-  property_to_update->set_value(value);
-  entry->set_metadata_edit_state(ResourceEntry::DIRTY);
-  entry->set_modification_date(base::Time::Now().ToInternalValue());
-
-  return metadata->RefreshEntry(*entry);
-}
-
-}  // namespace
-
-SetPropertyOperation::SetPropertyOperation(
-    base::SequencedTaskRunner* blocking_task_runner,
-    OperationDelegate* delegate,
-    internal::ResourceMetadata* metadata)
-    : blocking_task_runner_(blocking_task_runner),
-      delegate_(delegate),
-      metadata_(metadata) {}
-
-SetPropertyOperation::~SetPropertyOperation() = default;
-
-void SetPropertyOperation::SetProperty(
-    const base::FilePath& file_path,
-    google_apis::drive::Property::Visibility visibility,
-    const std::string& key,
-    const std::string& value,
-    const FileOperationCallback& callback) {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-  DCHECK(callback);
-
-  ResourceEntry* entry = new ResourceEntry;
-  base::PostTaskAndReplyWithResult(
-      blocking_task_runner_.get(), FROM_HERE,
-      base::Bind(&UpdateLocalState, metadata_, file_path, visibility, key,
-                 value, entry),
-      base::Bind(&SetPropertyOperation::SetPropertyAfterUpdateLocalState,
-                 weak_ptr_factory_.GetWeakPtr(), callback, base::Owned(entry)));
-}
-
-void SetPropertyOperation::SetPropertyAfterUpdateLocalState(
-    const FileOperationCallback& callback,
-    const ResourceEntry* entry,
-    FileError result) {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-  DCHECK(callback);
-
-  if (result == FILE_ERROR_OK) {
-    // Do not notify about the file change, as properties are write only and
-    // cannot be read, so there is no visible change.
-    delegate_->OnEntryUpdatedByOperation(ClientContext(USER_INITIATED),
-                                         entry->local_id());
-  }
-
-  // Even if exists, return success, as the set property operation always
-  // overwrites existing values.
-  callback.Run(result == FILE_ERROR_EXISTS ? FILE_ERROR_OK : result);
-}
-
-}  // namespace file_system
-}  // namespace drive
diff --git a/components/drive/chromeos/file_system/set_property_operation.h b/components/drive/chromeos/file_system/set_property_operation.h
deleted file mode 100644
index 9f0b729d..0000000
--- a/components/drive/chromeos/file_system/set_property_operation.h
+++ /dev/null
@@ -1,70 +0,0 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef COMPONENTS_DRIVE_CHROMEOS_FILE_SYSTEM_SET_PROPERTY_OPERATION_H_
-#define COMPONENTS_DRIVE_CHROMEOS_FILE_SYSTEM_SET_PROPERTY_OPERATION_H_
-
-#include <string>
-
-#include "base/macros.h"
-#include "base/memory/ref_counted.h"
-#include "base/memory/weak_ptr.h"
-#include "base/threading/thread_checker.h"
-#include "components/drive/file_errors.h"
-#include "google_apis/drive/drive_api_requests.h"
-
-namespace base {
-class FilePath;
-class SequencedTaskRunner;
-}  // namespace base
-
-namespace drive {
-namespace internal {
-class ResourceMetadata;
-}  // namespace internal
-
-class ResourceEntry;
-
-namespace file_system {
-
-class OperationDelegate;
-
-class SetPropertyOperation {
- public:
-  SetPropertyOperation(base::SequencedTaskRunner* blocking_task_runner,
-                       OperationDelegate* delegate,
-                       internal::ResourceMetadata* metadata);
-  ~SetPropertyOperation();
-
-  // Sets the |key| property on the entry at |drive_file_path| with the
-  // specified |visibility|. If the property already exists, it will be
-  // overwritten.
-  void SetProperty(const base::FilePath& drive_file_path,
-                   google_apis::drive::Property::Visibility visibility,
-                   const std::string& key,
-                   const std::string& value,
-                   const FileOperationCallback& callback);
-
- private:
-  // Part of SetProperty(). Runs after updating the local state.
-  void SetPropertyAfterUpdateLocalState(const FileOperationCallback& callback,
-                                        const ResourceEntry* entry,
-                                        FileError result);
-
-  scoped_refptr<base::SequencedTaskRunner> blocking_task_runner_;
-  OperationDelegate* delegate_;
-  internal::ResourceMetadata* metadata_;
-
-  THREAD_CHECKER(thread_checker_);
-
-  // Note: This should remain the last member so it'll be destroyed and
-  // invalidate the weak pointers before any other members are destroyed.
-  base::WeakPtrFactory<SetPropertyOperation> weak_ptr_factory_{this};
-  DISALLOW_COPY_AND_ASSIGN(SetPropertyOperation);
-};
-
-}  // namespace file_system
-}  // namespace drive
-
-#endif  // COMPONENTS_DRIVE_CHROMEOS_FILE_SYSTEM_SET_PROPERTY_OPERATION_H_
diff --git a/components/drive/chromeos/file_system/touch_operation.cc b/components/drive/chromeos/file_system/touch_operation.cc
deleted file mode 100644
index 8249f679..0000000
--- a/components/drive/chromeos/file_system/touch_operation.cc
+++ /dev/null
@@ -1,95 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "components/drive/chromeos/file_system/touch_operation.h"
-
-#include "base/bind.h"
-#include "base/files/file_path.h"
-#include "base/sequenced_task_runner.h"
-#include "base/time/time.h"
-#include "components/drive/chromeos/file_system/operation_delegate.h"
-#include "components/drive/chromeos/resource_metadata.h"
-#include "components/drive/file_change.h"
-#include "components/drive/file_errors.h"
-#include "components/drive/job_scheduler.h"
-
-namespace drive {
-namespace file_system {
-
-namespace {
-
-// Updates the timestamps of the entry specified by |file_path|.
-FileError UpdateLocalState(internal::ResourceMetadata* metadata,
-                           const base::FilePath& file_path,
-                           const base::Time& last_access_time,
-                           const base::Time& last_modified_time,
-                           ResourceEntry* entry) {
-  FileError error = metadata->GetResourceEntryByPath(file_path, entry);
-  if (error != FILE_ERROR_OK)
-    return error;
-
-  PlatformFileInfoProto* file_info = entry->mutable_file_info();
-  if (!last_access_time.is_null())
-    file_info->set_last_accessed(last_access_time.ToInternalValue());
-  if (!last_modified_time.is_null()) {
-    file_info->set_last_modified(last_modified_time.ToInternalValue());
-    entry->set_last_modified_by_me(last_modified_time.ToInternalValue());
-  }
-  entry->set_metadata_edit_state(ResourceEntry::DIRTY);
-  entry->set_modification_date(base::Time::Now().ToInternalValue());
-  return metadata->RefreshEntry(*entry);
-}
-
-}  // namespace
-
-TouchOperation::TouchOperation(base::SequencedTaskRunner* blocking_task_runner,
-                               OperationDelegate* delegate,
-                               internal::ResourceMetadata* metadata)
-    : blocking_task_runner_(blocking_task_runner),
-      delegate_(delegate),
-      metadata_(metadata) {}
-
-TouchOperation::~TouchOperation() = default;
-
-void TouchOperation::TouchFile(const base::FilePath& file_path,
-                               const base::Time& last_access_time,
-                               const base::Time& last_modified_time,
-                               const FileOperationCallback& callback) {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-  DCHECK(callback);
-
-  ResourceEntry* entry = new ResourceEntry;
-  base::PostTaskAndReplyWithResult(
-      blocking_task_runner_.get(), FROM_HERE,
-      base::Bind(&UpdateLocalState, metadata_, file_path, last_access_time,
-                 last_modified_time, entry),
-      base::Bind(&TouchOperation::TouchFileAfterUpdateLocalState,
-                 weak_ptr_factory_.GetWeakPtr(), file_path, callback,
-                 base::Owned(entry)));
-}
-
-void TouchOperation::TouchFileAfterUpdateLocalState(
-    const base::FilePath& file_path,
-    const FileOperationCallback& callback,
-    const ResourceEntry* entry,
-    FileError error) {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-  DCHECK(callback);
-
-  FileChange changed_files;
-  changed_files.Update(file_path, entry->file_info().is_directory()
-                                      ? FileChange::FILE_TYPE_DIRECTORY
-                                      : FileChange::FILE_TYPE_FILE,
-                       FileChange::CHANGE_TYPE_ADD_OR_UPDATE);
-
-  if (error == FILE_ERROR_OK) {
-    delegate_->OnFileChangedByOperation(changed_files);
-    delegate_->OnEntryUpdatedByOperation(ClientContext(USER_INITIATED),
-                                         entry->local_id());
-  }
-  callback.Run(error);
-}
-
-}  // namespace file_system
-}  // namespace drive
diff --git a/components/drive/chromeos/file_system/touch_operation.h b/components/drive/chromeos/file_system/touch_operation.h
deleted file mode 100644
index 8712382..0000000
--- a/components/drive/chromeos/file_system/touch_operation.h
+++ /dev/null
@@ -1,68 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef COMPONENTS_DRIVE_CHROMEOS_FILE_SYSTEM_TOUCH_OPERATION_H_
-#define COMPONENTS_DRIVE_CHROMEOS_FILE_SYSTEM_TOUCH_OPERATION_H_
-
-#include "base/macros.h"
-#include "base/memory/ref_counted.h"
-#include "base/memory/weak_ptr.h"
-#include "base/threading/thread_checker.h"
-#include "components/drive/file_errors.h"
-
-namespace base {
-class FilePath;
-class SequencedTaskRunner;
-class Time;
-}  // namespace base
-
-namespace drive {
-namespace internal {
-class ResourceMetadata;
-}  // namespace internal
-
-class ResourceEntry;
-
-namespace file_system {
-
-class OperationDelegate;
-
-class TouchOperation {
- public:
-  TouchOperation(base::SequencedTaskRunner* blocking_task_runner,
-                 OperationDelegate* delegate,
-                 internal::ResourceMetadata* metadata);
-  ~TouchOperation();
-
-  // Touches the file by updating last access time and last modified time.
-  // Upon completion, invokes |callback|.
-  // |last_access_time|, |last_modified_time| and |callback| must not be null.
-  void TouchFile(const base::FilePath& file_path,
-                 const base::Time& last_access_time,
-                 const base::Time& last_modified_time,
-                 const FileOperationCallback& callback);
-
- private:
-  // Part of TouchFile(). Runs after updating the local state.
-  void TouchFileAfterUpdateLocalState(const base::FilePath& file_path,
-                                      const FileOperationCallback& callback,
-                                      const ResourceEntry* entry,
-                                      FileError error);
-
-  scoped_refptr<base::SequencedTaskRunner> blocking_task_runner_;
-  OperationDelegate* delegate_;
-  internal::ResourceMetadata* metadata_;
-
-  THREAD_CHECKER(thread_checker_);
-
-  // Note: This should remain the last member so it'll be destroyed and
-  // invalidate the weak pointers before any other members are destroyed.
-  base::WeakPtrFactory<TouchOperation> weak_ptr_factory_{this};
-  DISALLOW_COPY_AND_ASSIGN(TouchOperation);
-};
-
-}  // namespace file_system
-}  // namespace drive
-
-#endif  // COMPONENTS_DRIVE_CHROMEOS_FILE_SYSTEM_TOUCH_OPERATION_H_
diff --git a/components/drive/chromeos/file_system/truncate_operation.cc b/components/drive/chromeos/file_system/truncate_operation.cc
deleted file mode 100644
index 6d13c66..0000000
--- a/components/drive/chromeos/file_system/truncate_operation.cc
+++ /dev/null
@@ -1,141 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "components/drive/chromeos/file_system/truncate_operation.h"
-
-#include "base/bind.h"
-#include "base/callback_helpers.h"
-#include "base/files/file.h"
-#include "base/files/file_path.h"
-#include "base/logging.h"
-#include "base/sequenced_task_runner.h"
-#include "base/task_runner_util.h"
-#include "base/threading/thread_task_runner_handle.h"
-#include "components/drive/chromeos/file_cache.h"
-#include "components/drive/chromeos/file_system/download_operation.h"
-#include "components/drive/chromeos/file_system/operation_delegate.h"
-#include "components/drive/drive.pb.h"
-#include "components/drive/file_errors.h"
-#include "components/drive/job_scheduler.h"
-
-namespace drive {
-namespace file_system {
-namespace {
-
-// Truncates the local file at |local_cache_path| to the |length| bytes,
-// then marks the resource is dirty on |cache|.
-FileError TruncateOnBlockingPool(internal::ResourceMetadata* metadata,
-                                 internal::FileCache* cache,
-                                 const std::string& local_id,
-                                 const base::FilePath& local_cache_path,
-                                 int64_t length) {
-  DCHECK(metadata);
-  DCHECK(cache);
-
-  std::unique_ptr<base::ScopedClosureRunner> file_closer;
-  FileError error = cache->OpenForWrite(local_id, &file_closer);
-  if (error != FILE_ERROR_OK)
-    return error;
-
-  base::File file(local_cache_path,
-                  base::File::FLAG_OPEN | base::File::FLAG_WRITE);
-  if (!file.IsValid())
-    return FILE_ERROR_FAILED;
-
-  if (!file.SetLength(length))
-    return FILE_ERROR_FAILED;
-
-  return FILE_ERROR_OK;
-}
-
-}  // namespace
-
-TruncateOperation::TruncateOperation(
-    base::SequencedTaskRunner* blocking_task_runner,
-    OperationDelegate* delegate,
-    JobScheduler* scheduler,
-    internal::ResourceMetadata* metadata,
-    internal::FileCache* cache,
-    const base::FilePath& temporary_file_directory)
-    : blocking_task_runner_(blocking_task_runner),
-      delegate_(delegate),
-      metadata_(metadata),
-      cache_(cache),
-      download_operation_(new DownloadOperation(blocking_task_runner,
-                                                delegate,
-                                                scheduler,
-                                                metadata,
-                                                cache,
-                                                temporary_file_directory)) {}
-
-TruncateOperation::~TruncateOperation() = default;
-
-void TruncateOperation::Truncate(const base::FilePath& file_path,
-                                 int64_t length,
-                                 const FileOperationCallback& callback) {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-  DCHECK(callback);
-
-  if (length < 0) {
-    base::ThreadTaskRunnerHandle::Get()->PostTask(
-        FROM_HERE, base::BindOnce(callback, FILE_ERROR_INVALID_OPERATION));
-    return;
-  }
-
-  // TODO(kinaba): http://crbug.com/132780.
-  // Optimize the cases for small |length|, at least for |length| == 0.
-  download_operation_->EnsureFileDownloadedByPath(
-      file_path,
-      ClientContext(USER_INITIATED),
-      GetFileContentInitializedCallback(),
-      google_apis::GetContentCallback(),
-      base::Bind(&TruncateOperation::TruncateAfterEnsureFileDownloadedByPath,
-                 weak_ptr_factory_.GetWeakPtr(), length, callback));
-}
-
-void TruncateOperation::TruncateAfterEnsureFileDownloadedByPath(
-    int64_t length,
-    const FileOperationCallback& callback,
-    FileError error,
-    const base::FilePath& local_file_path,
-    std::unique_ptr<ResourceEntry> entry) {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-  DCHECK(callback);
-
-  if (error != FILE_ERROR_OK) {
-    callback.Run(error);
-    return;
-  }
-  DCHECK(entry);
-  DCHECK(entry->has_file_specific_info());
-
-  if (entry->file_specific_info().is_hosted_document()) {
-    callback.Run(FILE_ERROR_INVALID_OPERATION);
-    return;
-  }
-
-  base::PostTaskAndReplyWithResult(
-      blocking_task_runner_.get(),
-      FROM_HERE,
-      base::Bind(&TruncateOnBlockingPool,
-                 metadata_, cache_, entry->local_id(), local_file_path, length),
-      base::Bind(
-          &TruncateOperation::TruncateAfterTruncateOnBlockingPool,
-          weak_ptr_factory_.GetWeakPtr(), entry->local_id(), callback));
-}
-
-void TruncateOperation::TruncateAfterTruncateOnBlockingPool(
-    const std::string& local_id,
-    const FileOperationCallback& callback,
-    FileError error) {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-  DCHECK(callback);
-
-  delegate_->OnEntryUpdatedByOperation(ClientContext(USER_INITIATED), local_id);
-
-  callback.Run(error);
-}
-
-}  // namespace file_system
-}  // namespace drive
diff --git a/components/drive/chromeos/file_system/truncate_operation.h b/components/drive/chromeos/file_system/truncate_operation.h
deleted file mode 100644
index d9fe24f..0000000
--- a/components/drive/chromeos/file_system/truncate_operation.h
+++ /dev/null
@@ -1,92 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef COMPONENTS_DRIVE_CHROMEOS_FILE_SYSTEM_TRUNCATE_OPERATION_H_
-#define COMPONENTS_DRIVE_CHROMEOS_FILE_SYSTEM_TRUNCATE_OPERATION_H_
-
-#include <stdint.h>
-
-#include <memory>
-
-#include "base/macros.h"
-#include "base/memory/ref_counted.h"
-#include "base/memory/weak_ptr.h"
-#include "base/threading/thread_checker.h"
-#include "components/drive/file_errors.h"
-
-namespace base {
-class FilePath;
-class SequencedTaskRunner;
-}  // namespace base
-
-namespace drive {
-
-class JobScheduler;
-class ResourceEntry;
-
-namespace internal {
-class FileCache;
-class ResourceMetadata;
-}  // namespace internal
-
-namespace file_system {
-
-class OperationDelegate;
-class DownloadOperation;
-
-// This class encapsulates the drive Truncate function. It is responsible for
-// fetching the content from the Drive server if necessary, truncating the
-// file content actually, and then notifying the file is locally modified and
-// that it is necessary to upload the file to the server.
-class TruncateOperation {
- public:
-  TruncateOperation(base::SequencedTaskRunner* blocking_task_runner,
-                    OperationDelegate* delegate,
-                    JobScheduler* scheduler,
-                    internal::ResourceMetadata* metadata,
-                    internal::FileCache* cache,
-                    const base::FilePath& temporary_file_directory);
-  ~TruncateOperation();
-
-  // Performs the truncate operation on the file at drive path |file_path| to
-  // |length| bytes. Invokes |callback| when finished with the result of the
-  // operation. |callback| must not be null.
-  void Truncate(const base::FilePath& file_path,
-                int64_t length,
-                const FileOperationCallback& callback);
-
- private:
-  // Part of Truncate(). Called after EnsureFileDownloadedByPath() is complete.
-  void TruncateAfterEnsureFileDownloadedByPath(
-      int64_t length,
-      const FileOperationCallback& callback,
-      FileError error,
-      const base::FilePath& local_file_path,
-      std::unique_ptr<ResourceEntry> resource_entry);
-
-  // Part of Truncate(). Called after TruncateOnBlockingPool() is complete.
-  void TruncateAfterTruncateOnBlockingPool(
-      const std::string& local_id,
-      const FileOperationCallback& callback,
-      FileError error);
-
-  scoped_refptr<base::SequencedTaskRunner> blocking_task_runner_;
-  OperationDelegate* delegate_;
-  internal::ResourceMetadata* metadata_;
-  internal::FileCache* cache_;
-
-  std::unique_ptr<DownloadOperation> download_operation_;
-
-  THREAD_CHECKER(thread_checker_);
-
-  // Note: This should remain the last member so it'll be destroyed and
-  // invalidate the weak pointers before any other members are destroyed.
-  base::WeakPtrFactory<TruncateOperation> weak_ptr_factory_{this};
-  DISALLOW_COPY_AND_ASSIGN(TruncateOperation);
-};
-
-}  // namespace file_system
-}  // namespace drive
-
-#endif  // COMPONENTS_DRIVE_CHROMEOS_FILE_SYSTEM_TRUNCATE_OPERATION_H_
diff --git a/components/drive/chromeos/loader_controller.cc b/components/drive/chromeos/loader_controller.cc
deleted file mode 100644
index 639824e..0000000
--- a/components/drive/chromeos/loader_controller.cc
+++ /dev/null
@@ -1,54 +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/drive/chromeos/loader_controller.h"
-
-#include <utility>
-
-#include "base/bind.h"
-#include "base/callback_helpers.h"
-
-namespace drive {
-namespace internal {
-
-LoaderController::LoaderController() : lock_count_(0) {}
-
-LoaderController::~LoaderController() {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-}
-
-std::unique_ptr<base::ScopedClosureRunner> LoaderController::GetLock() {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-
-  ++lock_count_;
-  return std::make_unique<base::ScopedClosureRunner>(base::BindOnce(
-      &LoaderController::Unlock, weak_ptr_factory_.GetWeakPtr()));
-}
-
-void LoaderController::ScheduleRun(base::OnceClosure task) {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-  DCHECK(task);
-
-  if (lock_count_ > 0) {
-    pending_tasks_.push_back(std::move(task));
-  } else {
-    std::move(task).Run();
-  }
-}
-
-void LoaderController::Unlock() {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-  DCHECK_LT(0, lock_count_);
-
-  if (--lock_count_ > 0)
-    return;
-
-  std::vector<base::OnceClosure> tasks;
-  tasks.swap(pending_tasks_);
-  for (auto& task : tasks)
-    std::move(task).Run();
-}
-
-}  // namespace internal
-}  // namespace drive
diff --git a/components/drive/chromeos/loader_controller.h b/components/drive/chromeos/loader_controller.h
deleted file mode 100644
index 551cbd23..0000000
--- a/components/drive/chromeos/loader_controller.h
+++ /dev/null
@@ -1,61 +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_DRIVE_CHROMEOS_LOADER_CONTROLLER_H_
-#define COMPONENTS_DRIVE_CHROMEOS_LOADER_CONTROLLER_H_
-
-#include <memory>
-#include <vector>
-
-#include "base/callback_forward.h"
-#include "base/macros.h"
-#include "base/memory/weak_ptr.h"
-#include "base/threading/thread_checker.h"
-
-namespace base {
-class ScopedClosureRunner;
-}
-
-namespace drive {
-namespace internal {
-
-// Delays execution of tasks as long as more than one lock is alive.
-// Used to ensure that ChangeListLoader does not cause race condition by adding
-// new entries created by sync tasks before they do.
-// All code which may add entries found on the server to the local metadata
-// should use this class.
-// TODO(slangley): Consider specific unit tests for LoaderController. Currently
-// it is tested as an artifact of other unit tests.
-class LoaderController {
- public:
-  LoaderController();
-  ~LoaderController();
-
-  // Increments the lock count and returns an object which decrements the count
-  // on its destruction.
-  // While the lock count is positive, tasks will be pending.
-  // TODO(slangley): Return ScopedClosureRunner directly, rather than one that
-  // is wrapped in a unique_ptr.
-  std::unique_ptr<base::ScopedClosureRunner> GetLock();
-
-  // Runs the task if the lock count is 0, otherwise it will be pending.
-  void ScheduleRun(base::OnceClosure task);
-
- private:
-  // Decrements the lock count.
-  void Unlock();
-
-  int lock_count_;
-  std::vector<base::OnceClosure> pending_tasks_;
-
-  THREAD_CHECKER(thread_checker_);
-
-  base::WeakPtrFactory<LoaderController> weak_ptr_factory_{this};
-  DISALLOW_COPY_AND_ASSIGN(LoaderController);
-};
-
-}  // namespace internal
-}  // namespace drive
-
-#endif  // COMPONENTS_DRIVE_CHROMEOS_LOADER_CONTROLLER_H_
diff --git a/components/drive/chromeos/root_folder_id_loader.h b/components/drive/chromeos/root_folder_id_loader.h
deleted file mode 100644
index d77eb25c..0000000
--- a/components/drive/chromeos/root_folder_id_loader.h
+++ /dev/null
@@ -1,34 +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_DRIVE_CHROMEOS_ROOT_FOLDER_ID_LOADER_H_
-#define COMPONENTS_DRIVE_CHROMEOS_ROOT_FOLDER_ID_LOADER_H_
-
-#include <string>
-
-#include "base/callback.h"
-#include "base/optional.h"
-#include "components/drive/file_errors.h"
-
-namespace drive {
-namespace internal {
-
-using RootFolderIdCallback =
-    base::RepeatingCallback<void(FileError, base::Optional<std::string>)>;
-
-// RootFolderIdLoader is an interface that will load the root_folder_id for
-// change list loader and directory loader.
-class RootFolderIdLoader {
- public:
-  virtual ~RootFolderIdLoader() = default;
-
-  // Retrieve the root folder id, which may be obtained from the server or
-  // potentially could be a constant value.
-  virtual void GetRootFolderId(const RootFolderIdCallback& callback) = 0;
-};
-
-}  // namespace internal
-}  // namespace drive
-
-#endif  // COMPONENTS_DRIVE_CHROMEOS_ROOT_FOLDER_ID_LOADER_H_
diff --git a/components/drive/chromeos/start_page_token_loader.cc b/components/drive/chromeos/start_page_token_loader.cc
deleted file mode 100644
index 647c4db1..0000000
--- a/components/drive/chromeos/start_page_token_loader.cc
+++ /dev/null
@@ -1,93 +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/drive/chromeos/start_page_token_loader.h"
-
-#include "base/bind.h"
-#include "base/threading/thread_task_runner_handle.h"
-#include "components/drive/job_scheduler.h"
-
-using google_apis::StartPageToken;
-using google_apis::StartPageTokenCallback;
-
-namespace drive {
-namespace internal {
-
-StartPageTokenLoader::StartPageTokenLoader(const std::string& team_drive_id,
-                                           JobScheduler* scheduler)
-    : team_drive_id_(team_drive_id),
-      scheduler_(scheduler),
-      current_update_task_id_(-1),
-      pending_update_callbacks_(),
-      cached_start_page_token_() {}
-
-StartPageTokenLoader::~StartPageTokenLoader() = default;
-
-const StartPageToken* StartPageTokenLoader::cached_start_page_token() const {
-  return cached_start_page_token_.get();
-}
-
-void StartPageTokenLoader::GetStartPageToken(
-    const StartPageTokenCallback& callback) {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-  DCHECK(callback);
-
-  // If the update task is running, then we will wait for it.
-  if (!pending_update_callbacks_[current_update_task_id_].empty()) {
-    pending_update_callbacks_[current_update_task_id_].emplace_back(callback);
-    return;
-  }
-
-  if (cached_start_page_token_) {
-    base::ThreadTaskRunnerHandle::Get()->PostTask(
-        FROM_HERE, base::BindOnce(callback, google_apis::HTTP_NO_CONTENT,
-                                  std::make_unique<StartPageToken>(
-                                      *cached_start_page_token_)));
-  } else {
-    UpdateStartPageToken(callback);
-  }
-}
-
-void StartPageTokenLoader::UpdateStartPageToken(
-    const StartPageTokenCallback& callback) {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-  DCHECK(callback);
-
-  pending_update_callbacks_[++current_update_task_id_].emplace_back(callback);
-
-  scheduler_->GetStartPageToken(
-      team_drive_id_,
-      base::BindRepeating(&StartPageTokenLoader::UpdateStartPageTokenAfterGet,
-                          weak_ptr_factory_.GetWeakPtr(),
-                          current_update_task_id_));
-}
-
-void StartPageTokenLoader::UpdateStartPageTokenAfterGet(
-    int task_id,
-    google_apis::DriveApiErrorCode status,
-    std::unique_ptr<StartPageToken> start_page_token) {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-  FileError error = GDataToFileError(status);
-
-  std::vector<StartPageTokenCallback> callbacks =
-      pending_update_callbacks_[task_id];
-  pending_update_callbacks_.erase(task_id);
-
-  if (error != FILE_ERROR_OK) {
-    for (auto& callback : callbacks) {
-      callback.Run(status, nullptr);
-    }
-    return;
-  }
-
-  cached_start_page_token_ =
-      std::make_unique<StartPageToken>(*start_page_token);
-
-  for (auto& callback : callbacks) {
-    callback.Run(status, std::make_unique<StartPageToken>(*start_page_token));
-  }
-}
-
-}  // namespace internal
-}  // namespace drive
diff --git a/components/drive/chromeos/start_page_token_loader.h b/components/drive/chromeos/start_page_token_loader.h
deleted file mode 100644
index 2bc43f3..0000000
--- a/components/drive/chromeos/start_page_token_loader.h
+++ /dev/null
@@ -1,84 +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_DRIVE_CHROMEOS_START_PAGE_TOKEN_LOADER_H_
-#define COMPONENTS_DRIVE_CHROMEOS_START_PAGE_TOKEN_LOADER_H_
-
-#include <map>
-#include <string>
-
-#include "base/macros.h"
-#include "base/memory/weak_ptr.h"
-#include "base/threading/thread_checker.h"
-#include "google_apis/drive/drive_api_requests.h"
-
-namespace drive {
-
-class JobScheduler;
-
-namespace internal {
-
-// Loads from the server and caches the start page token for a given team drive
-// id. This class is used to determine where to start retrieving changes from
-// the server, and as an optimization will cache the result until an
-// update is triggered using UpdateStartPageToken.
-class StartPageTokenLoader {
- public:
-  StartPageTokenLoader(const std::string& team_drive_id,
-                       JobScheduler* scheduler);
-  ~StartPageTokenLoader();
-
-  // Returns the cached start page token. If there is no cached start page token
-  // then nullptr is returned.
-  const google_apis::StartPageToken* cached_start_page_token() const;
-
-  // Gets the most recent start page token and asynchronously runs |callback|.
-  // How this works is:
-  // - If there is an UpdateStartPageToken in flight, wait for the result and
-  //   return it.
-  // - It there is NOT an UpdateStartPageToken in flight, and there is a
-  //   cached start page token, then return the cached value.
-  // - If neither of the above are true, then start an UpdateStartPageToken
-  //   request and return the result.
-  void GetStartPageToken(const google_apis::StartPageTokenCallback& callback);
-
-  // Gets the start page token from the server, and caches it if successful.
-  // This function calls JobScheduler::GetStartPageToken internally. The
-  // cached result will be used by GetStartPageToken.
-  void UpdateStartPageToken(
-      const google_apis::StartPageTokenCallback& callback);
-
- private:
-  // This callback is used when the result of UpdateStartPage token returns from
-  // the server.
-  void UpdateStartPageTokenAfterGet(
-      int task_id,
-      google_apis::DriveApiErrorCode status,
-      std::unique_ptr<google_apis::StartPageToken> start_page_token);
-
-  // This start page token loader is bound to a single team_drive_id, and will
-  // always request the token for it. If team_drive_id_ is empty, then it
-  // retrieves the start page token for the users corpus.
-  const std::string team_drive_id_;
-  JobScheduler* scheduler_;  // Not owned
-  THREAD_CHECKER(thread_checker_);
-
-  // We may have more than one update in flight at any time (multiple calls
-  // to UpdateStartPageToken will produce this scenario). We ensure that any
-  // calls to GetStartPageToken are bound to the update that was in progress
-  // when the GetStartPageToken was called, using the callback map below.
-  int current_update_task_id_;
-  std::map<int, std::vector<google_apis::StartPageTokenCallback>>
-      pending_update_callbacks_;
-  std::unique_ptr<google_apis::StartPageToken> cached_start_page_token_;
-
-  base::WeakPtrFactory<StartPageTokenLoader> weak_ptr_factory_{this};
-  DISALLOW_COPY_AND_ASSIGN(StartPageTokenLoader);
-};
-
-}  // namespace internal
-
-}  // namespace drive
-
-#endif  // COMPONENTS_DRIVE_CHROMEOS_START_PAGE_TOKEN_LOADER_H_
diff --git a/components/drive/chromeos/sync/entry_revert_performer.cc b/components/drive/chromeos/sync/entry_revert_performer.cc
deleted file mode 100644
index 6786106..0000000
--- a/components/drive/chromeos/sync/entry_revert_performer.cc
+++ /dev/null
@@ -1,171 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "components/drive/chromeos/sync/entry_revert_performer.h"
-
-#include <utility>
-
-#include "base/bind.h"
-#include "components/drive/chromeos/change_list_processor.h"
-#include "components/drive/chromeos/file_system/operation_delegate.h"
-#include "components/drive/chromeos/resource_metadata.h"
-#include "components/drive/drive.pb.h"
-#include "components/drive/drive_api_util.h"
-#include "components/drive/file_change.h"
-#include "components/drive/job_scheduler.h"
-#include "components/drive/resource_entry_conversion.h"
-#include "google_apis/drive/drive_api_parser.h"
-
-namespace drive {
-namespace internal {
-namespace {
-
-FileError FinishRevert(ResourceMetadata* metadata,
-                       const std::string& local_id,
-                       google_apis::DriveApiErrorCode status,
-                       std::unique_ptr<google_apis::FileResource> file_resource,
-                       FileChange* changed_files) {
-  ResourceEntry entry;
-  std::string parent_resource_id;
-  FileError error = GDataToFileError(status);
-  switch (error) {
-    case FILE_ERROR_OK:
-      ConvertFileResourceToResourceEntry(*file_resource, &entry,
-                                         &parent_resource_id);
-      break;
-
-    case FILE_ERROR_NOT_FOUND:
-      entry.set_deleted(true);
-      break;
-
-    default:
-      return error;
-  }
-
-  base::FilePath original_path;
-  error = metadata->GetFilePath(local_id, &original_path);
-  if (error != FILE_ERROR_OK)
-    return error;
-
-  if (entry.deleted()) {
-    error = metadata->RemoveEntry(local_id);
-    if (error != FILE_ERROR_OK)
-      return error;
-
-    changed_files->Update(
-        original_path,
-        FileChange::FILE_TYPE_NO_INFO,  // Undetermined type for deleted file.
-        FileChange::CHANGE_TYPE_DELETE);
-  } else {
-    changed_files->Update(original_path, entry, FileChange::CHANGE_TYPE_DELETE);
-
-    error = ChangeListProcessor::SetParentLocalIdOfEntry(metadata, &entry,
-                                                         parent_resource_id);
-    if (error != FILE_ERROR_OK)
-      return error;
-
-    entry.set_local_id(local_id);
-    error = metadata->RefreshEntry(entry);
-    if (error != FILE_ERROR_OK)
-      return error;
-
-    base::FilePath new_path;
-    error = metadata->GetFilePath(local_id, &new_path);
-    if (error != FILE_ERROR_OK)
-      return error;
-
-    changed_files->Update(new_path, entry,
-                          FileChange::CHANGE_TYPE_ADD_OR_UPDATE);
-  }
-  return FILE_ERROR_OK;
-}
-
-}  // namespace
-
-EntryRevertPerformer::EntryRevertPerformer(
-    base::SequencedTaskRunner* blocking_task_runner,
-    file_system::OperationDelegate* delegate,
-    JobScheduler* scheduler,
-    ResourceMetadata* metadata)
-    : blocking_task_runner_(blocking_task_runner),
-      delegate_(delegate),
-      scheduler_(scheduler),
-      metadata_(metadata) {}
-
-EntryRevertPerformer::~EntryRevertPerformer() {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-}
-
-void EntryRevertPerformer::RevertEntry(const std::string& local_id,
-                                       const ClientContext& context,
-                                       const FileOperationCallback& callback) {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-  DCHECK(callback);
-
-  std::unique_ptr<ResourceEntry> entry(new ResourceEntry);
-  ResourceEntry* entry_ptr = entry.get();
-  base::PostTaskAndReplyWithResult(
-      blocking_task_runner_.get(), FROM_HERE,
-      base::BindOnce(&ResourceMetadata::GetResourceEntryById,
-                     base::Unretained(metadata_), local_id, entry_ptr),
-      base::BindOnce(&EntryRevertPerformer::RevertEntryAfterPrepare,
-                     weak_ptr_factory_.GetWeakPtr(), context, callback,
-                     std::move(entry)));
-}
-
-void EntryRevertPerformer::RevertEntryAfterPrepare(
-    const ClientContext& context,
-    const FileOperationCallback& callback,
-    std::unique_ptr<ResourceEntry> entry,
-    FileError error) {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-  DCHECK(callback);
-
-  if (error == FILE_ERROR_OK && entry->resource_id().empty())
-    error = FILE_ERROR_INVALID_OPERATION;
-
-  if (error != FILE_ERROR_OK) {
-    callback.Run(error);
-    return;
-  }
-
-  scheduler_->GetFileResource(
-      entry->resource_id(),
-      context,
-      base::Bind(&EntryRevertPerformer::RevertEntryAfterGetFileResource,
-                 weak_ptr_factory_.GetWeakPtr(), callback, entry->local_id()));
-}
-
-void EntryRevertPerformer::RevertEntryAfterGetFileResource(
-    const FileOperationCallback& callback,
-    const std::string& local_id,
-    google_apis::DriveApiErrorCode status,
-    std::unique_ptr<google_apis::FileResource> entry) {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-  DCHECK(callback);
-
-  FileChange* changed_files = new FileChange;
-  base::PostTaskAndReplyWithResult(
-      blocking_task_runner_.get(), FROM_HERE,
-      base::BindOnce(&FinishRevert, metadata_, local_id, status,
-                     std::move(entry), changed_files),
-      base::BindOnce(&EntryRevertPerformer::RevertEntryAfterFinishRevert,
-                     weak_ptr_factory_.GetWeakPtr(), callback,
-                     base::Owned(changed_files)));
-}
-
-void EntryRevertPerformer::RevertEntryAfterFinishRevert(
-    const FileOperationCallback& callback,
-    const FileChange* changed_files,
-    FileError error) {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-  DCHECK(callback);
-
-  delegate_->OnFileChangedByOperation(*changed_files);
-
-  callback.Run(error);
-}
-
-}  // namespace internal
-}  // namespace drive
diff --git a/components/drive/chromeos/sync/entry_revert_performer.h b/components/drive/chromeos/sync/entry_revert_performer.h
deleted file mode 100644
index f7ec6076..0000000
--- a/components/drive/chromeos/sync/entry_revert_performer.h
+++ /dev/null
@@ -1,93 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef COMPONENTS_DRIVE_CHROMEOS_SYNC_ENTRY_REVERT_PERFORMER_H_
-#define COMPONENTS_DRIVE_CHROMEOS_SYNC_ENTRY_REVERT_PERFORMER_H_
-
-#include <memory>
-#include <set>
-
-#include "base/macros.h"
-#include "base/memory/ref_counted.h"
-#include "base/memory/weak_ptr.h"
-#include "base/threading/thread_checker.h"
-#include "components/drive/file_errors.h"
-#include "google_apis/drive/drive_api_error_codes.h"
-
-namespace base {
-class SequencedTaskRunner;
-}  // namespace base
-
-namespace google_apis {
-class FileResource;
-}  // namespace google_apis
-
-namespace drive {
-
-class FileChange;
-class JobScheduler;
-class ResourceEntry;
-struct ClientContext;
-
-namespace file_system {
-class OperationDelegate;
-}  // namespace file_system
-
-namespace internal {
-
-class ResourceMetadata;
-
-// This class is responsible to revert local changes of an entry.
-class EntryRevertPerformer {
- public:
-  EntryRevertPerformer(base::SequencedTaskRunner* blocking_task_runner,
-                       file_system::OperationDelegate* delegate,
-                       JobScheduler* scheduler,
-                       ResourceMetadata* metadata);
-  ~EntryRevertPerformer();
-
-  // Requests the server for metadata of the entry specified by |local_id|
-  // and overwrites the locally stored entry with it.
-  // Invokes |callback| when finished with the result of the operation.
-  // |callback| must not be null.
-  void RevertEntry(const std::string& local_id,
-                   const ClientContext& context,
-                   const FileOperationCallback& callback);
-
- private:
-  // Part of RevertEntry(). Called after local metadata look up.
-  void RevertEntryAfterPrepare(const ClientContext& context,
-                               const FileOperationCallback& callback,
-                               std::unique_ptr<ResourceEntry> entry,
-                               FileError error);
-
-  // Part of RevertEntry(). Called after GetFileResource is completed.
-  void RevertEntryAfterGetFileResource(
-      const FileOperationCallback& callback,
-      const std::string& local_id,
-      google_apis::DriveApiErrorCode status,
-      std::unique_ptr<google_apis::FileResource> entry);
-
-  // Part of RevertEntry(). Called after local metadata is updated.
-  void RevertEntryAfterFinishRevert(const FileOperationCallback& callback,
-                                    const FileChange* changed_files,
-                                    FileError error);
-
-  scoped_refptr<base::SequencedTaskRunner> blocking_task_runner_;
-  file_system::OperationDelegate* delegate_;
-  JobScheduler* scheduler_;
-  ResourceMetadata* metadata_;
-
-  THREAD_CHECKER(thread_checker_);
-
-  // Note: This should remain the last member so it'll be destroyed and
-  // invalidate the weak pointers before any other members are destroyed.
-  base::WeakPtrFactory<EntryRevertPerformer> weak_ptr_factory_{this};
-  DISALLOW_COPY_AND_ASSIGN(EntryRevertPerformer);
-};
-
-}  // namespace internal
-}  // namespace drive
-
-#endif  // COMPONENTS_DRIVE_CHROMEOS_SYNC_ENTRY_REVERT_PERFORMER_H_
diff --git a/components/drive/chromeos/sync/entry_update_performer.cc b/components/drive/chromeos/sync/entry_update_performer.cc
deleted file mode 100644
index 0a461f9..0000000
--- a/components/drive/chromeos/sync/entry_update_performer.cc
+++ /dev/null
@@ -1,453 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "components/drive/chromeos/sync/entry_update_performer.h"
-
-#include <stdint.h>
-
-#include <set>
-
-#include "base/bind.h"
-#include "base/callback_helpers.h"
-#include "base/files/file_util.h"
-#include "components/drive/chromeos/file_cache.h"
-#include "components/drive/chromeos/file_system/operation_delegate.h"
-#include "components/drive/chromeos/loader_controller.h"
-#include "components/drive/chromeos/resource_metadata.h"
-#include "components/drive/chromeos/sync/entry_revert_performer.h"
-#include "components/drive/chromeos/sync/remove_performer.h"
-#include "components/drive/drive.pb.h"
-#include "components/drive/file_change.h"
-#include "components/drive/file_system_core_util.h"
-#include "components/drive/job_scheduler.h"
-#include "google_apis/drive/drive_api_parser.h"
-
-namespace drive {
-namespace internal {
-
-struct EntryUpdatePerformer::LocalState {
-  LocalState() : cache_file_size(0), should_content_update(false) {}
-
-  ResourceEntry entry;
-  ResourceEntry parent_entry;
-  base::FilePath drive_file_path;
-  base::FilePath cache_file_path;
-  int64_t cache_file_size;
-  bool should_content_update;
-};
-
-namespace {
-
-struct PropertyCompare {
-  bool operator()(const drive::Property& x, const drive::Property& y) const {
-    if (x.key() < y.key())
-      return true;
-    if (x.key() > y.key())
-      return false;
-    if (x.value() < y.value())
-      return true;
-    if (y.value() > y.value())
-      return false;
-    return x.visibility() < y.visibility();
-  }
-};
-
-// Looks up ResourceEntry for source entry and its parent.
-FileError PrepareUpdate(ResourceMetadata* metadata,
-                        FileCache* cache,
-                        const std::string& local_id,
-                        EntryUpdatePerformer::LocalState* local_state) {
-  FileError error = metadata->GetResourceEntryById(local_id,
-                                                   &local_state->entry);
-  if (error != FILE_ERROR_OK)
-    return error;
-
-  error = metadata->GetResourceEntryById(local_state->entry.parent_local_id(),
-                                         &local_state->parent_entry);
-  if (error != FILE_ERROR_OK)
-    return error;
-
-  error = metadata->GetFilePath(local_id, &local_state->drive_file_path);
-  if (error != FILE_ERROR_OK)
-    return error;
-
-  if (!local_state->entry.file_info().is_directory() &&
-      !local_state->entry.file_specific_info().cache_state().is_present() &&
-      local_state->entry.resource_id().empty()) {
-    // Locally created file with no cache file, store an empty file.
-    base::FilePath empty_file;
-    if (!base::CreateTemporaryFile(&empty_file))
-      return FILE_ERROR_FAILED;
-    error = cache->Store(local_id, std::string(), empty_file,
-                         FileCache::FILE_OPERATION_MOVE);
-    if (error != FILE_ERROR_OK)
-      return error;
-    error = metadata->GetResourceEntryById(local_id, &local_state->entry);
-    if (error != FILE_ERROR_OK)
-      return error;
-  }
-
-  // Check if content update is needed or not.
-  if (local_state->entry.file_specific_info().cache_state().is_dirty() &&
-      !cache->IsOpenedForWrite(local_id)) {
-    // Update cache entry's MD5 if needed.
-    if (local_state->entry.file_specific_info().cache_state().md5().empty()) {
-      error = cache->UpdateMd5(local_id);
-      if (error != FILE_ERROR_OK)
-        return error;
-      error = metadata->GetResourceEntryById(local_id, &local_state->entry);
-      if (error != FILE_ERROR_OK)
-        return error;
-    }
-
-    if (local_state->entry.file_specific_info().cache_state().md5() ==
-        local_state->entry.file_specific_info().md5()) {
-      error = cache->ClearDirty(local_id);
-      if (error != FILE_ERROR_OK)
-        return error;
-    } else {
-      error = cache->GetFile(local_id, &local_state->cache_file_path);
-      if (error != FILE_ERROR_OK)
-        return error;
-      const bool result = base::GetFileSize(local_state->cache_file_path,
-                                            &local_state->cache_file_size);
-      if (!result)
-        return FILE_ERROR_FAILED;
-      local_state->should_content_update = true;
-    }
-  }
-
-  // Update metadata_edit_state.
-  switch (local_state->entry.metadata_edit_state()) {
-    case ResourceEntry::CLEAN:  // Nothing to do.
-    case ResourceEntry::SYNCING:  // Error during the last update. Go ahead.
-      break;
-
-    case ResourceEntry::DIRTY:
-      local_state->entry.set_metadata_edit_state(ResourceEntry::SYNCING);
-      error = metadata->RefreshEntry(local_state->entry);
-      if (error != FILE_ERROR_OK)
-        return error;
-      break;
-  }
-  return FILE_ERROR_OK;
-}
-
-FileError FinishUpdate(
-    ResourceMetadata* metadata,
-    FileCache* cache,
-    std::unique_ptr<EntryUpdatePerformer::LocalState> local_state,
-    std::unique_ptr<google_apis::FileResource> file_resource,
-    FileChange* changed_files) {
-  ResourceEntry entry;
-  FileError error =
-      metadata->GetResourceEntryById(local_state->entry.local_id(), &entry);
-  if (error != FILE_ERROR_OK)
-    return error;
-
-  // When creating new entries, update check may add a new entry with the same
-  // resource ID before us. If such an entry exists, remove it.
-  std::string existing_local_id;
-  error =
-      metadata->GetIdByResourceId(file_resource->file_id(), &existing_local_id);
-
-  switch (error) {
-    case FILE_ERROR_OK:
-      if (existing_local_id != local_state->entry.local_id()) {
-        base::FilePath existing_entry_path;
-        error = metadata->GetFilePath(existing_local_id, &existing_entry_path);
-        if (error != FILE_ERROR_OK)
-          return error;
-        error = metadata->RemoveEntry(existing_local_id);
-        if (error != FILE_ERROR_OK)
-          return error;
-        changed_files->Update(existing_entry_path, entry,
-                              FileChange::CHANGE_TYPE_DELETE);
-      }
-      break;
-    case FILE_ERROR_NOT_FOUND:
-      break;
-    default:
-      return error;
-  }
-
-  // Update metadata_edit_state and MD5.
-  switch (entry.metadata_edit_state()) {
-    case ResourceEntry::CLEAN:  // Nothing to do.
-    case ResourceEntry::DIRTY:  // Entry was edited again during the update.
-      break;
-
-    case ResourceEntry::SYNCING:
-      entry.set_metadata_edit_state(ResourceEntry::CLEAN);
-      break;
-  }
-  if (!entry.file_info().is_directory())
-    entry.mutable_file_specific_info()->set_md5(file_resource->md5_checksum());
-  entry.set_resource_id(file_resource->file_id());
-
-  // Keep only those properties which have been added or changed in the proto
-  // during the update.
-  std::set<drive::Property, PropertyCompare> synced_properties(
-      local_state->entry.new_properties().begin(),
-      local_state->entry.new_properties().end());
-
-  google::protobuf::RepeatedPtrField<drive::Property> not_synced_properties;
-  for (const auto& property : entry.new_properties()) {
-    if (!synced_properties.count(property)) {
-      Property* const not_synced_property = not_synced_properties.Add();
-      not_synced_property->CopyFrom(property);
-    }
-  }
-  entry.mutable_new_properties()->Swap(&not_synced_properties);
-
-  error = metadata->RefreshEntry(entry);
-  if (error != FILE_ERROR_OK)
-    return error;
-  base::FilePath entry_path;
-  error = metadata->GetFilePath(local_state->entry.local_id(), &entry_path);
-  if (error != FILE_ERROR_OK)
-    return error;
-  changed_files->Update(entry_path, entry,
-                        FileChange::CHANGE_TYPE_ADD_OR_UPDATE);
-
-  // Clear dirty bit unless the file has been edited during update.
-  if (entry.file_specific_info().cache_state().is_dirty() &&
-      entry.file_specific_info().cache_state().md5() ==
-      entry.file_specific_info().md5()) {
-    error = cache->ClearDirty(local_state->entry.local_id());
-    if (error != FILE_ERROR_OK)
-      return error;
-  }
-  return FILE_ERROR_OK;
-}
-
-}  // namespace
-
-EntryUpdatePerformer::EntryUpdatePerformer(
-    base::SequencedTaskRunner* blocking_task_runner,
-    file_system::OperationDelegate* delegate,
-    JobScheduler* scheduler,
-    ResourceMetadata* metadata,
-    FileCache* cache,
-    LoaderController* loader_controller)
-    : blocking_task_runner_(blocking_task_runner),
-      delegate_(delegate),
-      scheduler_(scheduler),
-      metadata_(metadata),
-      cache_(cache),
-      loader_controller_(loader_controller),
-      remove_performer_(new RemovePerformer(blocking_task_runner,
-                                            delegate,
-                                            scheduler,
-                                            metadata)),
-      entry_revert_performer_(new EntryRevertPerformer(blocking_task_runner,
-                                                       delegate,
-                                                       scheduler,
-                                                       metadata)) {}
-
-EntryUpdatePerformer::~EntryUpdatePerformer() {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-}
-
-void EntryUpdatePerformer::UpdateEntry(const std::string& local_id,
-                                       const ClientContext& context,
-                                       const FileOperationCallback& callback) {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-  DCHECK(callback);
-
-  std::unique_ptr<LocalState> local_state(new LocalState);
-  LocalState* const local_state_ptr = local_state.get();
-  base::PostTaskAndReplyWithResult(
-      blocking_task_runner_.get(),
-      FROM_HERE,
-      base::Bind(&PrepareUpdate, metadata_, cache_, local_id, local_state_ptr),
-      base::Bind(&EntryUpdatePerformer::UpdateEntryAfterPrepare,
-                 weak_ptr_factory_.GetWeakPtr(), context, callback,
-                 base::Passed(&local_state)));
-}
-
-void EntryUpdatePerformer::UpdateEntryAfterPrepare(
-    const ClientContext& context,
-    const FileOperationCallback& callback,
-    std::unique_ptr<LocalState> local_state,
-    FileError error) {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-  DCHECK(callback);
-
-  if (error != FILE_ERROR_OK) {
-    callback.Run(error);
-    return;
-  }
-
-  // Trashed entry should be removed.
-  if (local_state->entry.parent_local_id() == util::kDriveTrashDirLocalId) {
-    remove_performer_->Remove(local_state->entry.local_id(), context, callback);
-    return;
-  }
-
-  // Parent was locally created and needs update. Just return for now.
-  // This entry should be updated again after the parent update completes.
-  if (local_state->parent_entry.resource_id().empty() &&
-      local_state->parent_entry.metadata_edit_state() != ResourceEntry::CLEAN) {
-    callback.Run(FILE_ERROR_OK);
-    return;
-  }
-
-  base::Time last_modified = base::Time::FromInternalValue(
-      local_state->entry.file_info().last_modified());
-  base::Time last_accessed = base::Time::FromInternalValue(
-      local_state->entry.file_info().last_accessed());
-
-  // Compose a list of new properties from the proto.
-  google_apis::drive::Properties properties;
-  for (const auto& proto_property : local_state->entry.new_properties()) {
-    google_apis::drive::Property property;
-    switch (proto_property.visibility()) {
-      case Property_Visibility_PRIVATE:
-        property.set_visibility(
-            google_apis::drive::Property::VISIBILITY_PRIVATE);
-        break;
-      case Property_Visibility_PUBLIC:
-        property.set_visibility(
-            google_apis::drive::Property::VISIBILITY_PUBLIC);
-        break;
-    }
-    property.set_key(proto_property.key());
-    property.set_value(proto_property.value());
-    properties.push_back(property);
-  }
-
-  // Perform content update.
-  if (local_state->should_content_update) {
-    if (local_state->entry.resource_id().empty()) {
-      // Not locking the loader intentionally here to avoid making the UI
-      // unresponsive while uploading large files.
-      // FinishUpdate() is responsible to resolve conflicts caused by this.
-      std::unique_ptr<base::ScopedClosureRunner> null_loader_lock;
-
-      UploadNewFileOptions options;
-      options.modified_date = last_modified;
-      options.last_viewed_by_me_date = last_accessed;
-      options.properties = properties;
-      LocalState* const local_state_ptr = local_state.get();
-      scheduler_->UploadNewFile(
-          local_state_ptr->parent_entry.resource_id(),
-          local_state_ptr->cache_file_size, local_state_ptr->drive_file_path,
-          local_state_ptr->cache_file_path, local_state_ptr->entry.title(),
-          local_state_ptr->entry.file_specific_info().content_mime_type(),
-          options, context,
-          base::Bind(&EntryUpdatePerformer::UpdateEntryAfterUpdateResource,
-                     weak_ptr_factory_.GetWeakPtr(), context, callback,
-                     base::Passed(&local_state),
-                     base::Passed(&null_loader_lock)));
-    } else {
-      UploadExistingFileOptions options;
-      options.title = local_state->entry.title();
-      options.parent_resource_id = local_state->parent_entry.resource_id();
-      options.modified_date = last_modified;
-      options.last_viewed_by_me_date = last_accessed;
-      options.properties = properties;
-      LocalState* const local_state_ptr = local_state.get();
-      scheduler_->UploadExistingFile(
-          local_state_ptr->entry.resource_id(),
-          local_state_ptr->cache_file_size, local_state_ptr->drive_file_path,
-          local_state_ptr->cache_file_path,
-          local_state_ptr->entry.file_specific_info().content_mime_type(),
-          options, context,
-          base::Bind(
-              &EntryUpdatePerformer::UpdateEntryAfterUpdateResource,
-              weak_ptr_factory_.GetWeakPtr(), context, callback,
-              base::Passed(&local_state),
-              base::Passed(std::unique_ptr<base::ScopedClosureRunner>())));
-    }
-    return;
-  }
-
-  // Create directory.
-  if (local_state->entry.file_info().is_directory() &&
-      local_state->entry.resource_id().empty()) {
-    // Lock the loader to avoid race conditions.
-    std::unique_ptr<base::ScopedClosureRunner> loader_lock =
-        loader_controller_->GetLock();
-
-    AddNewDirectoryOptions options;
-    options.modified_date = last_modified;
-    options.last_viewed_by_me_date = last_accessed;
-    options.properties = properties;
-    LocalState* const local_state_ptr = local_state.get();
-    scheduler_->AddNewDirectory(
-        local_state_ptr->parent_entry.resource_id(),
-        local_state_ptr->entry.title(), options, context,
-        base::Bind(&EntryUpdatePerformer::UpdateEntryAfterUpdateResource,
-                   weak_ptr_factory_.GetWeakPtr(), context, callback,
-                   base::Passed(&local_state), base::Passed(&loader_lock)));
-    return;
-  }
-
-  // No need to perform update.
-  if (local_state->entry.metadata_edit_state() == ResourceEntry::CLEAN ||
-      local_state->entry.resource_id().empty()) {
-    callback.Run(FILE_ERROR_OK);
-    return;
-  }
-
-  // Perform metadata update.
-  LocalState* const local_state_ptr = local_state.get();
-  scheduler_->UpdateResource(
-      local_state_ptr->entry.resource_id(),
-      local_state_ptr->parent_entry.resource_id(),
-      local_state_ptr->entry.title(), last_modified, last_accessed, properties,
-      context,
-      base::Bind(&EntryUpdatePerformer::UpdateEntryAfterUpdateResource,
-                 weak_ptr_factory_.GetWeakPtr(), context, callback,
-                 base::Passed(&local_state),
-                 base::Passed(std::unique_ptr<base::ScopedClosureRunner>())));
-}
-
-void EntryUpdatePerformer::UpdateEntryAfterUpdateResource(
-    const ClientContext& context,
-    const FileOperationCallback& callback,
-    std::unique_ptr<LocalState> local_state,
-    std::unique_ptr<base::ScopedClosureRunner> loader_lock,
-    google_apis::DriveApiErrorCode status,
-    std::unique_ptr<google_apis::FileResource> entry) {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-  DCHECK(callback);
-
-  if (status == google_apis::HTTP_FORBIDDEN) {
-    // Editing this entry is not allowed, revert local changes.
-    entry_revert_performer_->RevertEntry(local_state->entry.local_id(), context,
-                                         callback);
-    return;
-  }
-
-  FileError error = GDataToFileError(status);
-  if (error != FILE_ERROR_OK) {
-    callback.Run(error);
-    return;
-  }
-
-  FileChange* changed_files = new FileChange;
-  base::PostTaskAndReplyWithResult(
-      blocking_task_runner_.get(), FROM_HERE,
-      base::Bind(&FinishUpdate, metadata_, cache_, base::Passed(&local_state),
-                 base::Passed(&entry), changed_files),
-      base::Bind(&EntryUpdatePerformer::UpdateEntryAfterFinish,
-                 weak_ptr_factory_.GetWeakPtr(), callback,
-                 base::Owned(changed_files)));
-}
-
-void EntryUpdatePerformer::UpdateEntryAfterFinish(
-    const FileOperationCallback& callback,
-    const FileChange* changed_files,
-    FileError error) {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-  DCHECK(callback);
-
-  delegate_->OnFileChangedByOperation(*changed_files);
-  callback.Run(error);
-}
-
-}  // namespace internal
-}  // namespace drive
diff --git a/components/drive/chromeos/sync/entry_update_performer.h b/components/drive/chromeos/sync/entry_update_performer.h
deleted file mode 100644
index db97cc0..0000000
--- a/components/drive/chromeos/sync/entry_update_performer.h
+++ /dev/null
@@ -1,106 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef COMPONENTS_DRIVE_CHROMEOS_SYNC_ENTRY_UPDATE_PERFORMER_H_
-#define COMPONENTS_DRIVE_CHROMEOS_SYNC_ENTRY_UPDATE_PERFORMER_H_
-
-#include <memory>
-
-#include "base/macros.h"
-#include "base/memory/ref_counted.h"
-#include "base/memory/weak_ptr.h"
-#include "base/threading/thread_checker.h"
-#include "components/drive/file_errors.h"
-#include "google_apis/drive/drive_api_error_codes.h"
-
-namespace base {
-class ScopedClosureRunner;
-class SequencedTaskRunner;
-}  // namespace base
-
-namespace google_apis {
-class FileResource;
-}  // namespace google_apis
-
-namespace drive {
-
-class FileChange;
-class JobScheduler;
-struct ClientContext;
-
-namespace file_system {
-class OperationDelegate;
-}  // namespace file_system
-
-namespace internal {
-
-class EntryRevertPerformer;
-class FileCache;
-class LoaderController;
-class RemovePerformer;
-class ResourceMetadata;
-
-// This class is responsible to perform server side update of an entry.
-class EntryUpdatePerformer {
- public:
-  EntryUpdatePerformer(base::SequencedTaskRunner* blocking_task_runner,
-                       file_system::OperationDelegate* delegate,
-                       JobScheduler* scheduler,
-                       ResourceMetadata* metadata,
-                       FileCache* cache,
-                       LoaderController* loader_controller);
-  ~EntryUpdatePerformer();
-
-  // Requests the server to update the metadata of the entry specified by
-  // |local_id| with the locally stored one.
-  // Invokes |callback| when finished with the result of the operation.
-  // |callback| must not be null.
-  void UpdateEntry(const std::string& local_id,
-                   const ClientContext& context,
-                   const FileOperationCallback& callback);
-
-  struct LocalState;
-
- private:
-  // Part of UpdateEntry(). Called after local metadata look up.
-  void UpdateEntryAfterPrepare(const ClientContext& context,
-                               const FileOperationCallback& callback,
-                               std::unique_ptr<LocalState> local_state,
-                               FileError error);
-
-  // Part of UpdateEntry(). Called after UpdateResource is completed.
-  void UpdateEntryAfterUpdateResource(
-      const ClientContext& context,
-      const FileOperationCallback& callback,
-      std::unique_ptr<LocalState> local_state,
-      std::unique_ptr<base::ScopedClosureRunner> loader_lock,
-      google_apis::DriveApiErrorCode status,
-      std::unique_ptr<google_apis::FileResource> entry);
-
-  // Part of UpdateEntry(). Called after FinishUpdate is completed.
-  void UpdateEntryAfterFinish(const FileOperationCallback& callback,
-                              const FileChange* changed_files,
-                              FileError error);
-
-  scoped_refptr<base::SequencedTaskRunner> blocking_task_runner_;
-  file_system::OperationDelegate* delegate_;
-  JobScheduler* scheduler_;
-  ResourceMetadata* metadata_;
-  FileCache* cache_;
-  LoaderController* loader_controller_;
-  std::unique_ptr<RemovePerformer> remove_performer_;
-  std::unique_ptr<EntryRevertPerformer> entry_revert_performer_;
-
-  THREAD_CHECKER(thread_checker_);
-
-  // Note: This should remain the last member so it'll be destroyed and
-  // invalidate the weak pointers before any other members are destroyed.
-  base::WeakPtrFactory<EntryUpdatePerformer> weak_ptr_factory_{this};
-  DISALLOW_COPY_AND_ASSIGN(EntryUpdatePerformer);
-};
-
-}  // namespace internal
-}  // namespace drive
-
-#endif  // COMPONENTS_DRIVE_CHROMEOS_SYNC_ENTRY_UPDATE_PERFORMER_H_
diff --git a/components/drive/chromeos/sync/remove_performer.cc b/components/drive/chromeos/sync/remove_performer.cc
deleted file mode 100644
index 744bb28..0000000
--- a/components/drive/chromeos/sync/remove_performer.cc
+++ /dev/null
@@ -1,251 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "components/drive/chromeos/sync/remove_performer.h"
-
-#include "base/bind.h"
-#include "base/sequenced_task_runner.h"
-#include "components/drive/chromeos/file_system/operation_delegate.h"
-#include "components/drive/chromeos/resource_metadata.h"
-#include "components/drive/chromeos/sync/entry_revert_performer.h"
-#include "components/drive/drive.pb.h"
-#include "components/drive/drive_api_util.h"
-#include "components/drive/file_system_core_util.h"
-#include "components/drive/job_scheduler.h"
-#include "components/drive/resource_entry_conversion.h"
-#include "google_apis/drive/drive_api_parser.h"
-
-namespace drive {
-namespace internal {
-
-namespace {
-
-// Updates local metadata and after remote unparenting.
-FileError UpdateLocalStateAfterUnparent(ResourceMetadata* metadata,
-                                        const std::string& local_id) {
-  ResourceEntry entry;
-  FileError error = metadata->GetResourceEntryById(local_id, &entry);
-  if (error != FILE_ERROR_OK)
-    return error;
-  entry.set_parent_local_id(util::kDriveOtherDirLocalId);
-  return metadata->RefreshEntry(entry);
-}
-
-// Utility function to run ResourceMetadata::RemoveEntry from UI thread.
-void RemoveEntryOnUIThread(base::SequencedTaskRunner* blocking_task_runner,
-                           ResourceMetadata* metadata,
-                           const std::string& local_id,
-                           const FileOperationCallback& callback) {
-  base::PostTaskAndReplyWithResult(
-      blocking_task_runner,
-      FROM_HERE,
-      base::Bind(&ResourceMetadata::RemoveEntry,
-                 base::Unretained(metadata), local_id),
-      callback);
-}
-
-}  // namespace
-
-RemovePerformer::RemovePerformer(
-    base::SequencedTaskRunner* blocking_task_runner,
-    file_system::OperationDelegate* delegate,
-    JobScheduler* scheduler,
-    ResourceMetadata* metadata)
-    : blocking_task_runner_(blocking_task_runner),
-      delegate_(delegate),
-      scheduler_(scheduler),
-      metadata_(metadata),
-      entry_revert_performer_(new EntryRevertPerformer(blocking_task_runner,
-                                                       delegate,
-                                                       scheduler,
-                                                       metadata)) {}
-
-RemovePerformer::~RemovePerformer() {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-}
-
-// Returns |entry| corresponding to |local_id|.
-// Adding to that, removes the entry when it does not exist on the server.
-FileError TryToRemoveLocally(ResourceMetadata* metadata,
-                             const std::string& local_id,
-                             ResourceEntry* entry) {
-  FileError error = metadata->GetResourceEntryById(local_id, entry);
-  if (error != FILE_ERROR_OK || !entry->resource_id().empty())
-    return error;
-  return metadata->RemoveEntry(local_id);
-}
-
-void RemovePerformer::Remove(const std::string& local_id,
-                             const ClientContext& context,
-                             const FileOperationCallback& callback) {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-  DCHECK(callback);
-
-  ResourceEntry* entry = new ResourceEntry;
-  base::PostTaskAndReplyWithResult(
-      blocking_task_runner_.get(),
-      FROM_HERE,
-      base::Bind(&TryToRemoveLocally, metadata_, local_id, entry),
-      base::Bind(&RemovePerformer::RemoveAfterGetResourceEntry,
-                 weak_ptr_factory_.GetWeakPtr(),
-                 context,
-                 callback,
-                 base::Owned(entry)));
-}
-
-void RemovePerformer::RemoveAfterGetResourceEntry(
-    const ClientContext& context,
-    const FileOperationCallback& callback,
-    const ResourceEntry* entry,
-    FileError error) {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-  DCHECK(callback);
-
-  if (error != FILE_ERROR_OK || entry->resource_id().empty()) {
-    callback.Run(error);
-    return;
-  }
-
-  // To match with the behavior of drive.google.com:
-  // Removal of shared entries under MyDrive is just removing from the parent.
-  // The entry will stay in shared-with-me (in other words, in "drive/other".)
-  //
-  // TODO(kinaba): to be more precise, we might be better to branch by whether
-  // or not the current account is an owner of the file. The code below is
-  // written under the assumption that |shared_with_me| coincides with that.
-  if (entry->shared_with_me()) {
-    UnparentResource(context, callback, entry->resource_id(),
-                     entry->local_id());
-  } else {
-    // Otherwise try sending the entry to trash.
-    TrashResource(context, callback, entry->resource_id(), entry->local_id());
-  }
-}
-
-void RemovePerformer::TrashResource(const ClientContext& context,
-                                    const FileOperationCallback& callback,
-                                    const std::string& resource_id,
-                                    const std::string& local_id) {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-  DCHECK(callback);
-
-  scheduler_->TrashResource(
-      resource_id,
-      context,
-      base::Bind(&RemovePerformer::TrashResourceAfterUpdateRemoteState,
-                 weak_ptr_factory_.GetWeakPtr(), context, callback, local_id));
-}
-
-void RemovePerformer::TrashResourceAfterUpdateRemoteState(
-    const ClientContext& context,
-    const FileOperationCallback& callback,
-    const std::string& local_id,
-    google_apis::DriveApiErrorCode status) {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-  DCHECK(callback);
-
-  if (status == google_apis::HTTP_FORBIDDEN) {
-    // Editing this entry is not allowed, revert local changes.
-    entry_revert_performer_->RevertEntry(local_id, context, callback);
-    delegate_->OnDriveSyncError(
-        file_system::DRIVE_SYNC_ERROR_DELETE_WITHOUT_PERMISSION, local_id);
-    return;
-  }
-
-  FileError error = GDataToFileError(status);
-  if (error == FILE_ERROR_NOT_FOUND) {  // Remove local entry when not found.
-    RemoveEntryOnUIThread(blocking_task_runner_.get(), metadata_, local_id,
-                          callback);
-    return;
-  }
-
-  // Now we're done. If the entry is trashed on the server, it'll be also
-  // deleted locally on the next update.
-  callback.Run(error);
-}
-
-void RemovePerformer::UnparentResource(const ClientContext& context,
-                                       const FileOperationCallback& callback,
-                                       const std::string& resource_id,
-                                       const std::string& local_id) {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-  DCHECK(callback);
-
-  scheduler_->GetFileResource(
-      resource_id,
-      context,
-      base::Bind(&RemovePerformer::UnparentResourceAfterGetFileResource,
-                 weak_ptr_factory_.GetWeakPtr(), context, callback, local_id));
-}
-
-void RemovePerformer::UnparentResourceAfterGetFileResource(
-    const ClientContext& context,
-    const FileOperationCallback& callback,
-    const std::string& local_id,
-    google_apis::DriveApiErrorCode status,
-    std::unique_ptr<google_apis::FileResource> file_resource) {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-  DCHECK(callback);
-
-  FileError error = GDataToFileError(status);
-  if (error == FILE_ERROR_NOT_FOUND) {  // Remove local entry when not found.
-    RemoveEntryOnUIThread(blocking_task_runner_.get(), metadata_, local_id,
-                          callback);
-    return;
-  }
-
-  if (error != FILE_ERROR_OK) {
-    callback.Run(error);
-    return;
-  }
-
-  ResourceEntry entry;
-  std::string parent_resource_id;
-  ConvertFileResourceToResourceEntry(*file_resource, &entry,
-                                     &parent_resource_id);
-
-  if (!entry.shared_with_me()) {
-    // shared_with_me() has changed on the server.
-    UnparentResourceAfterUpdateRemoteState(callback, local_id,
-                                           google_apis::HTTP_CONFLICT);
-    return;
-  }
-
-  if (parent_resource_id.empty()) {
-    // This entry is unparented already.
-    UnparentResourceAfterUpdateRemoteState(callback, local_id,
-                                           google_apis::HTTP_NO_CONTENT);
-    return;
-  }
-
-  scheduler_->RemoveResourceFromDirectory(
-      parent_resource_id,
-      entry.resource_id(),
-      context,
-      base::Bind(&RemovePerformer::UnparentResourceAfterUpdateRemoteState,
-                 weak_ptr_factory_.GetWeakPtr(), callback, local_id));
-}
-
-void RemovePerformer::UnparentResourceAfterUpdateRemoteState(
-    const FileOperationCallback& callback,
-    const std::string& local_id,
-    google_apis::DriveApiErrorCode status) {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-  DCHECK(callback);
-
-  FileError error = GDataToFileError(status);
-  if (error != FILE_ERROR_OK) {
-    callback.Run(error);
-    return;
-  }
-
-  base::PostTaskAndReplyWithResult(
-      blocking_task_runner_.get(),
-      FROM_HERE,
-      base::Bind(&UpdateLocalStateAfterUnparent, metadata_, local_id),
-      callback);
-}
-
-}  // namespace internal
-}  // namespace drive
diff --git a/components/drive/chromeos/sync/remove_performer.h b/components/drive/chromeos/sync/remove_performer.h
deleted file mode 100644
index a043a95d..0000000
--- a/components/drive/chromeos/sync/remove_performer.h
+++ /dev/null
@@ -1,115 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef COMPONENTS_DRIVE_CHROMEOS_SYNC_REMOVE_PERFORMER_H_
-#define COMPONENTS_DRIVE_CHROMEOS_SYNC_REMOVE_PERFORMER_H_
-
-#include <memory>
-
-#include "base/macros.h"
-#include "base/memory/ref_counted.h"
-#include "base/memory/weak_ptr.h"
-#include "base/threading/thread_checker.h"
-#include "components/drive/file_errors.h"
-#include "google_apis/drive/drive_api_error_codes.h"
-
-namespace base {
-class SequencedTaskRunner;
-}
-
-namespace google_apis {
-class FileResource;
-}
-
-namespace drive {
-
-class JobScheduler;
-class ResourceEntry;
-struct ClientContext;
-
-namespace file_system {
-class OperationDelegate;
-}  // namespace file_system
-
-namespace internal {
-
-class EntryRevertPerformer;
-class ResourceMetadata;
-
-// This class encapsulates the drive Remove function.  It is responsible for
-// sending the request to the drive API, then updating the local state and
-// metadata to reflect the new state.
-class RemovePerformer {
- public:
-  RemovePerformer(base::SequencedTaskRunner* blocking_task_runner,
-                  file_system::OperationDelegate* delegate,
-                  JobScheduler* scheduler,
-                  ResourceMetadata* metadata);
-  ~RemovePerformer();
-
-  // Removes the resource.
-  //
-  // |callback| must not be null.
-  void Remove(const std::string& local_id,
-              const ClientContext& context,
-              const FileOperationCallback& callback);
-
- private:
-  // Part of Remove(). Called after GetResourceEntry() completion.
-  void RemoveAfterGetResourceEntry(const ClientContext& context,
-                                   const FileOperationCallback& callback,
-                                   const ResourceEntry* entry,
-                                   FileError error);
-
-  // Requests the server to move the specified resource to the trash.
-  void TrashResource(const ClientContext& context,
-                     const FileOperationCallback& callback,
-                     const std::string& resource_id,
-                     const std::string& local_id);
-
-  // Part of TrashResource(). Called after server-side removal is done.
-  void TrashResourceAfterUpdateRemoteState(
-      const ClientContext& context,
-      const FileOperationCallback& callback,
-      const std::string& local_id,
-      google_apis::DriveApiErrorCode status);
-
-  // Requests the server to detach the specified resource from its parent.
-  void UnparentResource(const ClientContext& context,
-                        const FileOperationCallback& callback,
-                        const std::string& resource_id,
-                        const std::string& local_id);
-
-  // Part of UnparentResource().
-  void UnparentResourceAfterGetFileResource(
-      const ClientContext& context,
-      const FileOperationCallback& callback,
-      const std::string& local_id,
-      google_apis::DriveApiErrorCode status,
-      std::unique_ptr<google_apis::FileResource> file_resource);
-
-  // Part of UnparentResource().
-  void UnparentResourceAfterUpdateRemoteState(
-      const FileOperationCallback& callback,
-      const std::string& local_id,
-      google_apis::DriveApiErrorCode status);
-
-  scoped_refptr<base::SequencedTaskRunner> blocking_task_runner_;
-  file_system::OperationDelegate* delegate_;
-  JobScheduler* scheduler_;
-  ResourceMetadata* metadata_;
-  std::unique_ptr<EntryRevertPerformer> entry_revert_performer_;
-
-  THREAD_CHECKER(thread_checker_);
-
-  // Note: This should remain the last member so it'll be destroyed and
-  // invalidate the weak pointers before any other members are destroyed.
-  base::WeakPtrFactory<RemovePerformer> weak_ptr_factory_{this};
-  DISALLOW_COPY_AND_ASSIGN(RemovePerformer);
-};
-
-}  // namespace internal
-}  // namespace drive
-
-#endif  // COMPONENTS_DRIVE_CHROMEOS_SYNC_REMOVE_PERFORMER_H_
diff --git a/components/drive/chromeos/sync_client.cc b/components/drive/chromeos/sync_client.cc
deleted file mode 100644
index 523d94e0..0000000
--- a/components/drive/chromeos/sync_client.cc
+++ /dev/null
@@ -1,493 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "components/drive/chromeos/sync_client.h"
-
-#include <stddef.h>
-
-#include <vector>
-
-#include "base/bind.h"
-#include "base/bind_helpers.h"
-#include "base/threading/thread_task_runner_handle.h"
-#include "components/drive/chromeos/file_cache.h"
-#include "components/drive/chromeos/file_system/download_operation.h"
-#include "components/drive/chromeos/file_system/operation_delegate.h"
-#include "components/drive/chromeos/sync/entry_update_performer.h"
-#include "components/drive/drive.pb.h"
-#include "components/drive/file_system_core_util.h"
-#include "components/drive/job_scheduler.h"
-#include "google_apis/drive/task_util.h"
-
-namespace drive {
-namespace internal {
-
-namespace {
-
-// The delay constant is used to delay processing a sync task. We should not
-// process SyncTasks immediately for the following reasons:
-//
-// 1) For fetching, the user may accidentally click on "Make available
-//    offline" checkbox on a file, and immediately cancel it in a second.
-//    It's a waste to fetch the file in this case.
-//
-// 2) For uploading, file writing via HTML5 file system API is performed in
-//    two steps: 1) truncate a file to 0 bytes, 2) write contents. We
-//    shouldn't start uploading right after the step 1). Besides, the user
-//    may edit the same file repeatedly in a short period of time.
-//
-// TODO(satorux): We should find a way to handle the upload case more nicely,
-// and shorten the delay. crbug.com/134774
-const int kDelaySeconds = 1;
-
-// The delay constant is used to delay retrying a sync task on server errors.
-const int kLongDelaySeconds = 600;
-
-// Iterates entries and appends IDs to |to_fetch| if the file is pinned but not
-// fetched (not present locally), to |to_update| if the file needs update.
-void CollectBacklog(ResourceMetadata* metadata,
-                    std::vector<std::string>* to_fetch,
-                    std::vector<std::string>* to_update) {
-  DCHECK(to_fetch);
-  DCHECK(to_update);
-
-  std::unique_ptr<ResourceMetadata::Iterator> it = metadata->GetIterator();
-  for (; !it->IsAtEnd(); it->Advance()) {
-    const std::string& local_id = it->GetID();
-    const ResourceEntry& entry = it->GetValue();
-    if (entry.parent_local_id() == util::kDriveTrashDirLocalId) {
-      to_update->push_back(local_id);
-      continue;
-    }
-
-    bool should_update = false;
-    switch (entry.metadata_edit_state()) {
-      case ResourceEntry::CLEAN:
-        break;
-      case ResourceEntry::SYNCING:
-      case ResourceEntry::DIRTY:
-        should_update = true;
-        break;
-    }
-
-    if (entry.file_specific_info().cache_state().is_pinned() &&
-        !entry.file_specific_info().cache_state().is_present())
-      to_fetch->push_back(local_id);
-
-    if (entry.file_specific_info().cache_state().is_dirty())
-      should_update = true;
-
-    if (should_update)
-      to_update->push_back(local_id);
-  }
-  DCHECK(!it->HasError());
-}
-
-// Iterates cache entries and collects IDs of ones with obsolete cache files.
-void CheckExistingPinnedFiles(ResourceMetadata* metadata,
-                              FileCache* cache,
-                              std::vector<std::string>* local_ids) {
-  std::unique_ptr<ResourceMetadata::Iterator> it = metadata->GetIterator();
-  for (; !it->IsAtEnd(); it->Advance()) {
-    const ResourceEntry& entry = it->GetValue();
-    const FileCacheEntry& cache_state =
-        entry.file_specific_info().cache_state();
-    const std::string& local_id = it->GetID();
-    if (!cache_state.is_pinned() || !cache_state.is_present())
-      continue;
-
-    // If MD5s don't match, it indicates the local cache file is stale, unless
-    // the file is dirty (the MD5 is "local"). We should never re-fetch the
-    // file when we have a locally modified version.
-    if (entry.file_specific_info().md5() == cache_state.md5() ||
-        cache_state.is_dirty())
-      continue;
-
-    FileError error = cache->Remove(local_id);
-    if (error != FILE_ERROR_OK) {
-      LOG(WARNING) << "Failed to remove cache entry: " << local_id;
-      continue;
-    }
-
-    error = cache->Pin(local_id);
-    if (error != FILE_ERROR_OK) {
-      LOG(WARNING) << "Failed to pin cache entry: " << local_id;
-      continue;
-    }
-
-    local_ids->push_back(local_id);
-  }
-  DCHECK(!it->HasError());
-}
-
-// Gets the parent entry of the entry specified by the ID.
-FileError GetParentResourceEntry(ResourceMetadata* metadata,
-                                 const std::string& local_id,
-                                 ResourceEntry* parent) {
-  ResourceEntry entry;
-  FileError error = metadata->GetResourceEntryById(local_id, &entry);
-  if (error != FILE_ERROR_OK)
-    return error;
-  return metadata->GetResourceEntryById(entry.parent_local_id(), parent);
-}
-
-}  // namespace
-
-SyncClient::SyncTask::SyncTask()
-    : state(SUSPENDED), context(BACKGROUND), should_run_again(false) {}
-SyncClient::SyncTask::SyncTask(const SyncTask& other) = default;
-SyncClient::SyncTask::~SyncTask() = default;
-
-SyncClient::SyncClient(base::SequencedTaskRunner* blocking_task_runner,
-                       file_system::OperationDelegate* delegate,
-                       JobScheduler* scheduler,
-                       ResourceMetadata* metadata,
-                       FileCache* cache,
-                       LoaderController* loader_controller,
-                       const base::FilePath& temporary_file_directory)
-    : blocking_task_runner_(blocking_task_runner),
-      operation_delegate_(delegate),
-      metadata_(metadata),
-      cache_(cache),
-      download_operation_(
-          new file_system::DownloadOperation(blocking_task_runner,
-                                             delegate,
-                                             scheduler,
-                                             metadata,
-                                             cache,
-                                             temporary_file_directory)),
-      entry_update_performer_(new EntryUpdatePerformer(blocking_task_runner,
-                                                       delegate,
-                                                       scheduler,
-                                                       metadata,
-                                                       cache,
-                                                       loader_controller)),
-      delay_(base::TimeDelta::FromSeconds(kDelaySeconds)),
-      long_delay_(base::TimeDelta::FromSeconds(kLongDelaySeconds)) {}
-
-SyncClient::~SyncClient() {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-}
-
-void SyncClient::StartProcessingBacklog() {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-
-  std::vector<std::string>* to_fetch = new std::vector<std::string>;
-  std::vector<std::string>* to_update = new std::vector<std::string>;
-  blocking_task_runner_->PostTaskAndReply(
-      FROM_HERE,
-      base::BindOnce(&CollectBacklog, metadata_, to_fetch, to_update),
-      base::BindOnce(&SyncClient::OnGetLocalIdsOfBacklog,
-                     weak_ptr_factory_.GetWeakPtr(), base::Owned(to_fetch),
-                     base::Owned(to_update)));
-}
-
-void SyncClient::StartCheckingExistingPinnedFiles() {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-
-  std::vector<std::string>* local_ids = new std::vector<std::string>;
-  blocking_task_runner_->PostTaskAndReply(
-      FROM_HERE,
-      base::BindOnce(&CheckExistingPinnedFiles, metadata_, cache_, local_ids),
-      base::BindOnce(&SyncClient::AddFetchTasks, weak_ptr_factory_.GetWeakPtr(),
-                     base::Owned(local_ids)));
-}
-
-void SyncClient::AddFetchTask(const std::string& local_id) {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-  AddFetchTaskInternal(local_id, delay_);
-}
-
-void SyncClient::RemoveFetchTask(const std::string& local_id) {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-
-  SyncTasks::iterator it = tasks_.find(SyncTasks::key_type(FETCH, local_id));
-  if (it == tasks_.end())
-    return;
-
-  SyncTask* task = &it->second;
-  switch (task->state) {
-    case SUSPENDED:
-    case PENDING:
-      OnTaskComplete(FETCH, local_id, FILE_ERROR_ABORT);
-      break;
-    case RUNNING:
-      if (task->cancel_closure)
-        task->cancel_closure.Run();
-      break;
-  }
-}
-
-void SyncClient::AddUpdateTask(const ClientContext& context,
-                               const std::string& local_id) {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-  AddUpdateTaskInternal(context, local_id, delay_);
-}
-
-bool SyncClient:: WaitForUpdateTaskToComplete(
-    const std::string& local_id,
-    const FileOperationCallback& callback) {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-
-  SyncTasks::iterator it = tasks_.find(SyncTasks::key_type(UPDATE, local_id));
-  if (it == tasks_.end())
-    return false;
-
-  SyncTask* task = &it->second;
-  task->waiting_callbacks.push_back(callback);
-  return true;
-}
-
-base::Closure SyncClient::PerformFetchTask(const std::string& local_id,
-                                           const ClientContext& context) {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-  return download_operation_->EnsureFileDownloadedByLocalId(
-      local_id,
-      context,
-      GetFileContentInitializedCallback(),
-      google_apis::GetContentCallback(),
-      base::Bind(&SyncClient::OnFetchFileComplete,
-                 weak_ptr_factory_.GetWeakPtr(),
-                 local_id));
-}
-
-void SyncClient::AddFetchTaskInternal(const std::string& local_id,
-                                      const base::TimeDelta& delay) {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-
-  SyncTask task;
-  task.state = PENDING;
-  task.context = ClientContext(BACKGROUND);
-  task.task = base::Bind(&SyncClient::PerformFetchTask,
-                         base::Unretained(this),
-                         local_id);
-  AddTask(SyncTasks::key_type(FETCH, local_id), task, delay);
-}
-
-base::Closure SyncClient::PerformUpdateTask(const std::string& local_id,
-                                            const ClientContext& context) {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-  entry_update_performer_->UpdateEntry(
-      local_id,
-      context,
-      base::Bind(&SyncClient::OnTaskComplete,
-                 weak_ptr_factory_.GetWeakPtr(),
-                 UPDATE,
-                 local_id));
-  return base::Closure();
-}
-
-void SyncClient::AddUpdateTaskInternal(const ClientContext& context,
-                                       const std::string& local_id,
-                                       const base::TimeDelta& delay) {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-
-  SyncTask task;
-  task.state = PENDING;
-  task.context = context;
-  task.task = base::Bind(&SyncClient::PerformUpdateTask,
-                         base::Unretained(this),
-                         local_id);
-  AddTask(SyncTasks::key_type(UPDATE, local_id), task, delay);
-}
-
-void SyncClient::AddTask(const SyncTasks::key_type& key,
-                         const SyncTask& task,
-                         const base::TimeDelta& delay) {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-
-  SyncTasks::iterator it = tasks_.find(key);
-  if (it != tasks_.end()) {
-    switch (it->second.state) {
-      case SUSPENDED:
-        // Activate the task.
-        it->second.state = PENDING;
-        break;
-      case PENDING:
-        // The same task will run, do nothing.
-        return;
-      case RUNNING:
-        // Something has changed since the task started. Schedule rerun.
-        it->second.should_run_again = true;
-        return;
-    }
-  } else {
-    tasks_[key] = task;
-  }
-  DCHECK_EQ(PENDING, task.state);
-  base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
-      FROM_HERE,
-      base::BindOnce(&SyncClient::StartTask, weak_ptr_factory_.GetWeakPtr(),
-                     key),
-      delay);
-}
-
-void SyncClient::StartTask(const SyncTasks::key_type& key) {
-  ResourceEntry* parent = new ResourceEntry;
-  base::PostTaskAndReplyWithResult(
-      blocking_task_runner_.get(),
-      FROM_HERE,
-      base::Bind(&GetParentResourceEntry, metadata_, key.second, parent),
-      base::Bind(&SyncClient::StartTaskAfterGetParentResourceEntry,
-                 weak_ptr_factory_.GetWeakPtr(),
-                 key,
-                 base::Owned(parent)));
-}
-
-void SyncClient::StartTaskAfterGetParentResourceEntry(
-    const SyncTasks::key_type& key,
-    const ResourceEntry* parent,
-    FileError error) {
-  const SyncType type = key.first;
-  const std::string& local_id = key.second;
-  SyncTasks::iterator it = tasks_.find(key);
-  if (it == tasks_.end())
-    return;
-
-  SyncTask* task = &it->second;
-  switch (task->state) {
-    case SUSPENDED:
-    case PENDING:
-      break;
-    case RUNNING:  // Do nothing.
-      return;
-  }
-
-  if (error != FILE_ERROR_OK) {
-    OnTaskComplete(type, local_id, error);
-    return;
-  }
-
-  if (type == UPDATE &&
-      parent->resource_id().empty() &&
-      parent->local_id() != util::kDriveTrashDirLocalId) {
-    // Parent entry needs to be synced to get a resource ID.
-    // Suspend the task and register it as a dependent task of the parent.
-    const SyncTasks::key_type key_parent(type, parent->local_id());
-    SyncTasks::iterator it_parent = tasks_.find(key_parent);
-    if (it_parent == tasks_.end()) {
-      OnTaskComplete(type, local_id, FILE_ERROR_INVALID_OPERATION);
-      LOG(WARNING) << "Parent task not found: type = " << type << ", id = "
-                   << local_id << ", parent_id = " << parent->local_id();
-      return;
-    }
-    task->state = SUSPENDED;
-    it_parent->second.dependent_tasks.push_back(key);
-    return;
-  }
-
-  // Run the task.
-  task->state = RUNNING;
-  task->cancel_closure = task->task.Run(task->context);
-}
-
-void SyncClient::OnGetLocalIdsOfBacklog(
-    const std::vector<std::string>* to_fetch,
-    const std::vector<std::string>* to_update) {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-
-  // Give priority to upload tasks over fetch tasks, so that dirty files are
-  // uploaded as soon as possible.
-  for (size_t i = 0; i < to_update->size(); ++i) {
-    const std::string& local_id = (*to_update)[i];
-    DVLOG(1) << "Queuing to update: " << local_id;
-    AddUpdateTask(ClientContext(BACKGROUND), local_id);
-  }
-
-  for (size_t i = 0; i < to_fetch->size(); ++i) {
-    const std::string& local_id = (*to_fetch)[i];
-    DVLOG(1) << "Queuing to fetch: " << local_id;
-    AddFetchTaskInternal(local_id, delay_);
-  }
-}
-
-void SyncClient::AddFetchTasks(const std::vector<std::string>* local_ids) {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-
-  for (size_t i = 0; i < local_ids->size(); ++i)
-    AddFetchTask((*local_ids)[i]);
-}
-
-void SyncClient::OnTaskComplete(SyncType type,
-                                const std::string& local_id,
-                                FileError error) {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-
-  const SyncTasks::key_type key(type, local_id);
-  SyncTasks::iterator it = tasks_.find(key);
-  DCHECK(it != tasks_.end());
-
-  base::TimeDelta retry_delay = base::TimeDelta::FromSeconds(0);
-
-  switch (error) {
-    case FILE_ERROR_OK:
-      DVLOG(1) << "Completed: type = " << type << ", id = " << local_id;
-      break;
-    case FILE_ERROR_ABORT:
-      // Ignore it because this is caused by user's cancel operations.
-      break;
-    case FILE_ERROR_NO_CONNECTION:
-      // Run the task again so that we'll retry once the connection is back.
-      it->second.should_run_again = true;
-      it->second.context = ClientContext(BACKGROUND);
-      break;
-    case FILE_ERROR_SERVICE_UNAVAILABLE:
-      // Run the task again so that we'll retry once the service is back.
-      it->second.should_run_again = true;
-      it->second.context = ClientContext(BACKGROUND);
-      retry_delay = long_delay_;
-      operation_delegate_->OnDriveSyncError(
-          file_system::DRIVE_SYNC_ERROR_SERVICE_UNAVAILABLE, local_id);
-      break;
-    case FILE_ERROR_NO_SERVER_SPACE:
-      operation_delegate_->OnDriveSyncError(
-          file_system::DRIVE_SYNC_ERROR_NO_SERVER_SPACE, local_id);
-      break;
-    default:
-      operation_delegate_->OnDriveSyncError(
-          file_system::DRIVE_SYNC_ERROR_MISC, local_id);
-      LOG(WARNING) << "Failed: type = " << type << ", id = " << local_id
-                   << ": " << FileErrorToString(error);
-  }
-
-  for (size_t i = 0; i < it->second.waiting_callbacks.size(); ++i) {
-    base::ThreadTaskRunnerHandle::Get()->PostTask(
-        FROM_HERE, base::BindOnce(it->second.waiting_callbacks[i], error));
-  }
-  it->second.waiting_callbacks.clear();
-
-  if (it->second.should_run_again) {
-    DVLOG(1) << "Running again: type = " << type << ", id = " << local_id;
-    it->second.state = PENDING;
-    it->second.should_run_again = false;
-    base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
-        FROM_HERE,
-        base::BindOnce(&SyncClient::StartTask, weak_ptr_factory_.GetWeakPtr(),
-                       key),
-        retry_delay);
-  } else {
-    for (size_t i = 0; i < it->second.dependent_tasks.size(); ++i)
-      StartTask(it->second.dependent_tasks[i]);
-    tasks_.erase(it);
-  }
-}
-
-void SyncClient::OnFetchFileComplete(const std::string& local_id,
-                                     FileError error,
-                                     const base::FilePath& local_path,
-                                     std::unique_ptr<ResourceEntry> entry) {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-  OnTaskComplete(FETCH, local_id, error);
-  if (error == FILE_ERROR_ABORT) {
-    // If user cancels download, unpin the file so that we do not sync the file
-    // again.
-    base::PostTaskAndReplyWithResult(
-        blocking_task_runner_.get(), FROM_HERE,
-        base::Bind(&FileCache::Unpin, base::Unretained(cache_), local_id),
-        base::DoNothing::Repeatedly<FileError>());
-  }
-}
-
-}  // namespace internal
-}  // namespace drive
diff --git a/components/drive/chromeos/sync_client.h b/components/drive/chromeos/sync_client.h
deleted file mode 100644
index 24d03e79..0000000
--- a/components/drive/chromeos/sync_client.h
+++ /dev/null
@@ -1,199 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef COMPONENTS_DRIVE_CHROMEOS_SYNC_CLIENT_H_
-#define COMPONENTS_DRIVE_CHROMEOS_SYNC_CLIENT_H_
-
-#include <map>
-#include <memory>
-#include <string>
-#include <vector>
-
-#include "base/callback.h"
-#include "base/macros.h"
-#include "base/memory/weak_ptr.h"
-#include "base/threading/thread_checker.h"
-#include "base/time/time.h"
-#include "components/drive/chromeos/resource_metadata.h"
-#include "components/drive/file_errors.h"
-#include "components/drive/job_scheduler.h"
-
-namespace base {
-class SequencedTaskRunner;
-}
-
-namespace drive {
-
-class JobScheduler;
-class ResourceEntry;
-struct ClientContext;
-
-namespace file_system {
-class DownloadOperation;
-class OperationDelegate;
-}
-
-namespace internal {
-
-class EntryUpdatePerformer;
-class FileCache;
-class LoaderController;
-class ResourceMetadata;
-
-// The SyncClient is used to synchronize pinned files on Drive and the
-// cache on the local drive.
-//
-// If the user logs out before fetching of the pinned files is complete, this
-// client resumes fetching operations next time the user logs in, based on
-// the states left in the cache.
-class SyncClient {
- public:
-  SyncClient(base::SequencedTaskRunner* blocking_task_runner,
-             file_system::OperationDelegate* delegate,
-             JobScheduler* scheduler,
-             ResourceMetadata* metadata,
-             FileCache* cache,
-             LoaderController* loader_controller,
-             const base::FilePath& temporary_file_directory);
-  virtual ~SyncClient();
-
-  // Adds a fetch task.
-  void AddFetchTask(const std::string& local_id);
-
-  // Removes a fetch task.
-  void RemoveFetchTask(const std::string& local_id);
-
-  // Adds a update task.
-  void AddUpdateTask(const ClientContext& context, const std::string& local_id);
-
-  // Waits for the update task to complete and runs the callback.
-  // Returns false if no task is found for the spcecified ID.
-  bool WaitForUpdateTaskToComplete(const std::string& local_id,
-                                   const FileOperationCallback& callback);
-
-  // Starts processing the backlog (i.e. pinned-but-not-filed files and
-  // dirty-but-not-uploaded files). Kicks off retrieval of the local
-  // IDs of these files, and then starts the sync loop.
-  void StartProcessingBacklog();
-
-  // Starts checking the existing pinned files to see if these are
-  // up to date. If stale files are detected, the local IDs of these files
-  // are added and the sync loop is started.
-  void StartCheckingExistingPinnedFiles();
-
-  // Sets a delay for testing.
-  void set_delay_for_testing(const base::TimeDelta& delay) {
-    delay_ = delay;
-  }
-
- private:
-  // Types of sync tasks.
-  enum SyncType {
-    FETCH,  // Fetch a file from the Drive server.
-    UPDATE,  // Updates an entry's metadata or content on the Drive server.
-  };
-
-  // States of sync tasks.
-  enum SyncState {
-    SUSPENDED,  // Task is currently inactive.
-    PENDING,  // Task is going to run.
-    RUNNING,  // Task is running.
-  };
-
-  typedef std::pair<SyncType, std::string> SyncTaskKey;
-
-  struct SyncTask {
-    SyncTask();
-    SyncTask(const SyncTask& other);
-    ~SyncTask();
-    SyncState state;
-    ClientContext context;
-    base::Callback<base::Closure(const ClientContext& context)> task;
-    bool should_run_again;
-    base::Closure cancel_closure;
-    std::vector<SyncTaskKey> dependent_tasks;
-    std::vector<FileOperationCallback> waiting_callbacks;
-  };
-
-  typedef std::map<SyncTaskKey, SyncTask> SyncTasks;
-
-  // Performs a FETCH task.
-  base::Closure PerformFetchTask(const std::string& local_id,
-                                 const ClientContext& context);
-
-  // Adds a FETCH task.
-  void AddFetchTaskInternal(const std::string& local_id,
-                            const base::TimeDelta& delay);
-
-  // Performs a UPDATE task.
-  base::Closure PerformUpdateTask(const std::string& local_id,
-                                  const ClientContext& context);
-
-  // Adds a UPDATE task.
-  void AddUpdateTaskInternal(const ClientContext& context,
-                             const std::string& local_id,
-                             const base::TimeDelta& delay);
-
-  // Adds the given task. If the same task is found, does nothing.
-  void AddTask(const SyncTasks::key_type& key,
-               const SyncTask& task,
-               const base::TimeDelta& delay);
-
-  // Called when a task is ready to start.
-  void StartTask(const SyncTasks::key_type& key);
-  void StartTaskAfterGetParentResourceEntry(const SyncTasks::key_type& key,
-                                            const ResourceEntry* parent,
-                                            FileError error);
-
-  // Called when the local IDs of files in the backlog are obtained.
-  void OnGetLocalIdsOfBacklog(const std::vector<std::string>* to_fetch,
-                              const std::vector<std::string>* to_update);
-
-  // Adds fetch tasks.
-  void AddFetchTasks(const std::vector<std::string>* local_ids);
-
-  // Called when a task is completed.
-  void OnTaskComplete(SyncType type,
-                      const std::string& local_id,
-                      FileError error);
-
-  // Called when the file for |local_id| is fetched.
-  void OnFetchFileComplete(const std::string& local_id,
-                           FileError error,
-                           const base::FilePath& local_path,
-                           std::unique_ptr<ResourceEntry> entry);
-
-  scoped_refptr<base::SequencedTaskRunner> blocking_task_runner_;
-  file_system::OperationDelegate* operation_delegate_;
-  ResourceMetadata* metadata_;
-  FileCache* cache_;
-
-  // Used to fetch pinned files.
-  std::unique_ptr<file_system::DownloadOperation> download_operation_;
-
-  // Used to update entry metadata.
-  std::unique_ptr<EntryUpdatePerformer> entry_update_performer_;
-
-  // Sync tasks to be processed.
-  SyncTasks tasks_;
-
-  // The delay is used for delaying processing tasks in AddTask().
-  base::TimeDelta delay_;
-
-  // The delay is used for delaying retry of tasks on server errors.
-  base::TimeDelta long_delay_;
-
-  THREAD_CHECKER(thread_checker_);
-
-  // Note: This should remain the last member so it'll be destroyed and
-  // invalidate its weak pointers before any other members are destroyed.
-  base::WeakPtrFactory<SyncClient> weak_ptr_factory_{this};
-
-  DISALLOW_COPY_AND_ASSIGN(SyncClient);
-};
-
-}  // namespace internal
-}  // namespace drive
-
-#endif  // COMPONENTS_DRIVE_CHROMEOS_SYNC_CLIENT_H_
diff --git a/components/drive/chromeos/team_drive_change_list_loader.cc b/components/drive/chromeos/team_drive_change_list_loader.cc
deleted file mode 100644
index 0d57eff..0000000
--- a/components/drive/chromeos/team_drive_change_list_loader.cc
+++ /dev/null
@@ -1,155 +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/drive/chromeos/team_drive_change_list_loader.h"
-
-#include <memory>
-
-#include "base/sequenced_task_runner.h"
-#include "components/drive/chromeos/change_list_loader.h"
-#include "components/drive/chromeos/directory_loader.h"
-#include "components/drive/chromeos/root_folder_id_loader.h"
-#include "components/drive/chromeos/start_page_token_loader.h"
-
-namespace drive {
-namespace internal {
-
-namespace {
-
-class ConstantRootFolderIdLoader : public RootFolderIdLoader {
- public:
-  explicit ConstantRootFolderIdLoader(const std::string& team_drive_id)
-      : team_drive_id_(team_drive_id) {}
-  ~ConstantRootFolderIdLoader() override = default;
-
-  void GetRootFolderId(const RootFolderIdCallback& callback) override {
-    callback.Run(FILE_ERROR_OK, team_drive_id_);
-  }
-
- private:
-  const std::string team_drive_id_;
-};
-
-}  // namespace
-
-TeamDriveChangeListLoader::TeamDriveChangeListLoader(
-    const std::string& team_drive_id,
-    const base::FilePath& root_entry_path,
-    EventLogger* logger,
-    base::SequencedTaskRunner* blocking_task_runner,
-    ResourceMetadata* resource_metadata,
-    JobScheduler* scheduler,
-    LoaderController* apply_task_controller)
-    : team_drive_id_(team_drive_id), root_entry_path_(root_entry_path) {
-  root_folder_id_loader_ =
-      std::make_unique<ConstantRootFolderIdLoader>(team_drive_id_);
-
-  start_page_token_loader_ =
-      std::make_unique<StartPageTokenLoader>(team_drive_id_, scheduler);
-
-  change_list_loader_ = std::make_unique<ChangeListLoader>(
-      logger, blocking_task_runner, resource_metadata, scheduler,
-      root_folder_id_loader_.get(), start_page_token_loader_.get(),
-      apply_task_controller, team_drive_id_, root_entry_path_);
-  change_list_loader_->AddObserver(this);
-
-  directory_loader_ = std::make_unique<DirectoryLoader>(
-      logger, blocking_task_runner, resource_metadata, scheduler,
-      root_folder_id_loader_.get(), start_page_token_loader_.get(),
-      apply_task_controller, root_entry_path_, team_drive_id);
-  directory_loader_->AddObserver(this);
-}
-
-TeamDriveChangeListLoader::~TeamDriveChangeListLoader() = default;
-
-base::WeakPtr<TeamDriveChangeListLoader>
-TeamDriveChangeListLoader::GetWeakPtr() {
-  return weak_ptr_factory_.GetWeakPtr();
-}
-
-// DriveChangeListLoader overrides
-void TeamDriveChangeListLoader::AddChangeListLoaderObserver(
-    ChangeListLoaderObserver* observer) {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-  change_list_loader_observers_.AddObserver(observer);
-}
-
-void TeamDriveChangeListLoader::RemoveChangeListLoaderObserver(
-    ChangeListLoaderObserver* observer) {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-  change_list_loader_observers_.RemoveObserver(observer);
-}
-
-void TeamDriveChangeListLoader::AddTeamDriveListObserver(
-    TeamDriveListObserver* observer) {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-}
-
-void TeamDriveChangeListLoader::RemoveTeamDriveListObserver(
-    TeamDriveListObserver* observer) {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-}
-
-bool TeamDriveChangeListLoader::IsRefreshing() {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-  return change_list_loader_->IsRefreshing();
-}
-
-void TeamDriveChangeListLoader::LoadIfNeeded(
-    const FileOperationCallback& callback) {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-  change_list_loader_->LoadIfNeeded(callback);
-}
-
-void TeamDriveChangeListLoader::ReadDirectory(
-    const base::FilePath& directory_path,
-    ReadDirectoryEntriesCallback entries_callback,
-    const FileOperationCallback& completion_callback) {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-  DCHECK(root_entry_path_ == directory_path ||
-         root_entry_path_.IsParent(directory_path))
-      << "Directory paths are not related: " << root_entry_path_.value()
-      << " -> " << directory_path.value();
-
-  directory_loader_->ReadDirectory(directory_path, std::move(entries_callback),
-                                   completion_callback);
-}
-
-void TeamDriveChangeListLoader::CheckForUpdates(
-    const FileOperationCallback& callback) {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-  change_list_loader_->CheckForUpdates(callback);
-}
-
-void TeamDriveChangeListLoader::OnDirectoryReloaded(
-    const base::FilePath& directory_path) {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-  for (auto& observer : change_list_loader_observers_) {
-    observer.OnDirectoryReloaded(directory_path);
-  }
-}
-
-void TeamDriveChangeListLoader::OnFileChanged(const FileChange& changed_files) {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-  for (auto& observer : change_list_loader_observers_) {
-    observer.OnFileChanged(changed_files);
-  }
-}
-
-void TeamDriveChangeListLoader::OnLoadFromServerComplete() {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-  for (auto& observer : change_list_loader_observers_) {
-    observer.OnLoadFromServerComplete();
-  }
-}
-
-void TeamDriveChangeListLoader::OnInitialLoadComplete() {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-  for (auto& observer : change_list_loader_observers_) {
-    observer.OnInitialLoadComplete();
-  }
-}
-
-}  // namespace internal
-}  // namespace drive
diff --git a/components/drive/chromeos/team_drive_change_list_loader.h b/components/drive/chromeos/team_drive_change_list_loader.h
deleted file mode 100644
index 8f0da7fa..0000000
--- a/components/drive/chromeos/team_drive_change_list_loader.h
+++ /dev/null
@@ -1,90 +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_DRIVE_CHROMEOS_TEAM_DRIVE_CHANGE_LIST_LOADER_H_
-#define COMPONENTS_DRIVE_CHROMEOS_TEAM_DRIVE_CHANGE_LIST_LOADER_H_
-
-#include <memory>
-#include <string>
-
-#include "base/files/file_path.h"
-#include "base/memory/weak_ptr.h"
-#include "base/observer_list.h"
-#include "components/drive/chromeos/change_list_loader_observer.h"
-#include "components/drive/chromeos/drive_change_list_loader.h"
-
-namespace drive {
-
-class EventLogger;
-class JobScheduler;
-
-namespace internal {
-
-class ChangeListLoader;
-class DirectoryLoader;
-class LoaderController;
-class RootFolderIdLoader;
-class StartPageTokenLoader;
-
-// TeamDriveChangeListLoader loads change lists for a specific team drive id.
-// It uses directory loader and change list loader to retrieve change lists
-// into resouce metadata. There should be one TeamDriveChangeListLoader created
-// for every team drive that the user has access to.
-class TeamDriveChangeListLoader : public DriveChangeListLoader,
-                                  public ChangeListLoaderObserver {
- public:
-  TeamDriveChangeListLoader(const std::string& team_drive_id,
-                            const base::FilePath& root_entry_path,
-                            EventLogger* logger,
-                            base::SequencedTaskRunner* blocking_task_runner,
-                            ResourceMetadata* resource_metadata,
-                            JobScheduler* scheduler,
-                            LoaderController* apply_task_controller);
-
-  ~TeamDriveChangeListLoader() override;
-
-  const base::FilePath& root_entry_path() const { return root_entry_path_; }
-  base::WeakPtr<TeamDriveChangeListLoader> GetWeakPtr();
-
-  // DriveChangeListLoader overrides
-  void AddChangeListLoaderObserver(ChangeListLoaderObserver* observer) override;
-  void RemoveChangeListLoaderObserver(
-      ChangeListLoaderObserver* observer) override;
-  void AddTeamDriveListObserver(TeamDriveListObserver* observer) override;
-  void RemoveTeamDriveListObserver(TeamDriveListObserver* observer) override;
-  bool IsRefreshing() override;
-  void LoadIfNeeded(const FileOperationCallback& callback) override;
-  void ReadDirectory(const base::FilePath& directory_path,
-                     ReadDirectoryEntriesCallback entries_callback,
-                     const FileOperationCallback& completion_callback) override;
-  void CheckForUpdates(const FileOperationCallback& callback) override;
-
-  // ChangeListLoaderObserver overrides
-  void OnDirectoryReloaded(const base::FilePath& directory_path) override;
-  void OnFileChanged(const FileChange& changed_files) override;
-  void OnLoadFromServerComplete() override;
-  void OnInitialLoadComplete() override;
-
- private:
-  std::unique_ptr<RootFolderIdLoader> root_folder_id_loader_;
-  std::unique_ptr<StartPageTokenLoader> start_page_token_loader_;
-  std::unique_ptr<ChangeListLoader> change_list_loader_;
-  std::unique_ptr<DirectoryLoader> directory_loader_;
-
-  const std::string team_drive_id_;
-  const base::FilePath root_entry_path_;
-  base::ObserverList<ChangeListLoaderObserver>::Unchecked
-      change_list_loader_observers_;
-
-  THREAD_CHECKER(thread_checker_);
-
-  base::WeakPtrFactory<TeamDriveChangeListLoader> weak_ptr_factory_{this};
-
-  DISALLOW_COPY_AND_ASSIGN(TeamDriveChangeListLoader);
-};
-
-}  // namespace internal
-}  // namespace drive
-
-#endif  // COMPONENTS_DRIVE_CHROMEOS_TEAM_DRIVE_CHANGE_LIST_LOADER_H_
diff --git a/components/drive/chromeos/team_drive_list_loader.cc b/components/drive/chromeos/team_drive_list_loader.cc
deleted file mode 100644
index 3c49b0bf..0000000
--- a/components/drive/chromeos/team_drive_list_loader.cc
+++ /dev/null
@@ -1,347 +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/drive/chromeos/team_drive_list_loader.h"
-
-#include <algorithm>
-#include <map>
-#include <memory>
-#include <string>
-#include <utility>
-
-#include "base/bind.h"
-#include "base/sequenced_task_runner.h"
-#include "base/synchronization/atomic_flag.h"
-#include "components/drive/chromeos/change_list_loader.h"
-#include "components/drive/chromeos/change_list_processor.h"
-#include "components/drive/chromeos/loader_controller.h"
-#include "components/drive/drive.pb.h"
-#include "components/drive/drive_api_util.h"
-#include "components/drive/event_logger.h"
-#include "components/drive/file_change.h"
-#include "components/drive/file_system_core_util.h"
-#include "components/drive/job_scheduler.h"
-
-namespace drive {
-namespace internal {
-
-namespace {
-
-// Add any new team drives, or update existing team drives in resource
-// metadata.
-FileError AddOrUpdateTeamDrives(ResourceEntryVector team_drives,
-                                ResourceMetadata* metadata,
-                                base::AtomicFlag* in_shutdown) {
-  DCHECK(metadata);
-  DCHECK(in_shutdown);
-  for (const auto& entry : team_drives) {
-    if (in_shutdown->IsSet()) {
-      return FILE_ERROR_ABORT;
-    }
-    DCHECK_EQ(entry.parent_local_id(), util::kDriveTeamDrivesDirLocalId);
-
-    std::string local_id;
-    FileError error =
-        metadata->GetIdByResourceId(entry.resource_id(), &local_id);
-
-    ResourceEntry existing_entry;
-    if (error == FILE_ERROR_OK) {
-      error = metadata->GetResourceEntryById(local_id, &existing_entry);
-    }
-
-    switch (error) {
-      // Existing entry in metadata, see if we need to update it
-      case FILE_ERROR_OK:
-        if (entry.base_name() != existing_entry.base_name()) {
-          existing_entry.set_base_name(entry.base_name());
-          error = metadata->RefreshEntry(existing_entry);
-        }
-        break;
-      // Add a new entry to metadata
-      case FILE_ERROR_NOT_FOUND: {
-        std::string local_id;
-        error = metadata->AddEntry(entry, &local_id);
-        break;
-      }
-      default:
-        return error;
-    }
-    if (error != FILE_ERROR_OK) {
-      return error;
-    }
-  }
-  return FILE_ERROR_OK;
-}
-
-// Remove the supplied list of team drives from the resource metadata.
-FileError RemoveTeamDrives(ResourceEntryVector team_drives,
-                           ResourceMetadata* metadata,
-                           base::AtomicFlag* in_shutdown) {
-  DCHECK(metadata);
-  DCHECK(in_shutdown);
-  FileError result = FILE_ERROR_OK;
-  for (const auto& entry : team_drives) {
-    if (in_shutdown->IsSet()) {
-      return FILE_ERROR_ABORT;
-    }
-    result = metadata->RemoveEntry(entry.local_id());
-    if (result != FILE_ERROR_OK) {
-      return result;
-    }
-  }
-  return result;
-}
-
-}  // namespace
-
-// Used to notify observers of the result of loading the team drives.
-struct TeamDriveListLoader::TeamDriveUpdateData {
-  std::vector<TeamDrive> all_team_drives;
-  std::vector<TeamDrive> added_team_drives;
-  std::vector<TeamDrive> removed_team_drives;
-};
-
-TeamDriveListLoader::TeamDriveListLoader(
-    EventLogger* logger,
-    base::SequencedTaskRunner* blocking_task_runner,
-    ResourceMetadata* resource_metadata,
-    JobScheduler* scheduler,
-    LoaderController* apply_task_controller)
-    : logger_(logger),
-      blocking_task_runner_(blocking_task_runner),
-      in_shutdown_(new base::AtomicFlag),
-      pending_load_callbacks_(),
-      resource_metadata_(resource_metadata),
-      scheduler_(scheduler),
-      loader_controller_(apply_task_controller) {}
-
-TeamDriveListLoader::~TeamDriveListLoader() {
-  in_shutdown_->Set();
-  // Delete |in_shutdown_| with the blocking task runner so that it gets deleted
-  // after all active ChangeListProcessors.
-  blocking_task_runner_->DeleteSoon(FROM_HERE, in_shutdown_.release());
-}
-
-void TeamDriveListLoader::AddObserver(TeamDriveListObserver* observer) {
-  observers_.AddObserver(observer);
-}
-
-void TeamDriveListLoader::RemoveObserver(TeamDriveListObserver* observer) {
-  observers_.RemoveObserver(observer);
-}
-
-bool TeamDriveListLoader::IsRefreshing() const {
-  return !pending_load_callbacks_.empty();
-}
-
-void TeamDriveListLoader::CheckForUpdates(
-    const FileOperationCallback& callback) {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-  DCHECK(callback);
-
-  if (IsRefreshing()) {
-    pending_load_callbacks_.emplace_back(callback);
-    return;
-  }
-
-  pending_load_callbacks_.emplace_back(callback);
-  scheduler_->GetAllTeamDriveList(
-      base::BindRepeating(&TeamDriveListLoader::OnTeamDriveListLoaded,
-                          weak_ptr_factory_.GetWeakPtr()));
-}
-
-void TeamDriveListLoader::LoadIfNeeded(const FileOperationCallback& callback) {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-  DCHECK(callback);
-
-  if (!loaded_ && !IsRefreshing()) {
-    CheckForUpdates(callback);
-  } else {
-    callback.Run(FILE_ERROR_OK);
-  }
-}
-
-void TeamDriveListLoader::OnTeamDriveListLoaded(
-    google_apis::DriveApiErrorCode status,
-    std::unique_ptr<google_apis::TeamDriveList> team_drives) {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-
-  FileError error = GDataToFileError(status);
-  if (error != FILE_ERROR_OK) {
-    logger_->Log(logging::LOG_ERROR,
-                 "Failed to retrieve the list of team drives: %s",
-                 google_apis::DriveApiErrorCodeToString(status).c_str());
-    OnTeamDriveListLoadComplete(error);
-    return;
-  }
-
-  change_lists_.push_back(std::make_unique<ChangeList>(*team_drives));
-
-  if (!team_drives->next_page_token().empty()) {
-    scheduler_->GetRemainingTeamDriveList(
-        team_drives->next_page_token(),
-        base::BindRepeating(&TeamDriveListLoader::OnTeamDriveListLoaded,
-                            weak_ptr_factory_.GetWeakPtr()));
-    return;
-  }
-
-  ResourceEntryVector team_drive_resource_vector;
-  for (auto& change_list : change_lists_) {
-    std::move(change_list->entries().begin(), change_list->entries().end(),
-              std::back_inserter(team_drive_resource_vector));
-  }
-
-  // We will store the current list of team drives in local_resources.
-  std::unique_ptr<ResourceEntryVector> local_resources =
-      std::make_unique<ResourceEntryVector>();
-
-  base::PostTaskAndReplyWithResult(
-      blocking_task_runner_.get(), FROM_HERE,
-      base::BindRepeating(&ResourceMetadata::ReadDirectoryByPath,
-                          base::Unretained(resource_metadata_),
-                          util::GetDriveTeamDrivesRootPath(),
-                          local_resources.get()),
-      base::BindRepeating(&TeamDriveListLoader::OnReadDirectoryByPath,
-                          weak_ptr_factory_.GetWeakPtr(),
-                          base::Owned(local_resources.release()),
-                          base::Passed(std::move(team_drive_resource_vector))));
-}
-
-void TeamDriveListLoader::OnReadDirectoryByPath(
-    ResourceEntryVector* local_resources,
-    ResourceEntryVector remote_resources,
-    FileError error) {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-  DCHECK(local_resources);
-
-  // We need to sort vectors to use std::set_difference
-  std::sort(local_resources->begin(), local_resources->end(),
-            [](const ResourceEntry& lhs, const ResourceEntry& rhs) {
-              return lhs.resource_id() < rhs.resource_id();
-            });
-  std::sort(remote_resources.begin(), remote_resources.end(),
-            [](const ResourceEntry& lhs, const ResourceEntry& rhs) {
-              return lhs.resource_id() < rhs.resource_id();
-            });
-
-  // Removed team drives are the ResourceEntry's that are present in
-  // local_resources but missing from remote_resources.
-  ResourceEntryVector removed_team_drives;
-  std::set_difference(local_resources->begin(), local_resources->end(),
-                      remote_resources.begin(), remote_resources.end(),
-                      std::back_inserter(removed_team_drives),
-                      [](const ResourceEntry& lhs, const ResourceEntry& rhs) {
-                        return lhs.resource_id() < rhs.resource_id();
-                      });
-
-  // Added team drives are the ResourceEntry's that are present in
-  // remote_resources but missing from local_resources.
-  ResourceEntryVector added_team_drives;
-  std::set_difference(remote_resources.begin(), remote_resources.end(),
-                      local_resources->begin(), local_resources->end(),
-                      std::back_inserter(added_team_drives),
-                      [](const ResourceEntry& lhs, const ResourceEntry& rhs) {
-                        return lhs.resource_id() < rhs.resource_id();
-                      });
-
-  // We need to store the list of team drives, the added drives and the
-  // removed drives so we can notify observers on completion.
-  TeamDriveUpdateData team_drive_updates;
-  std::transform(remote_resources.begin(), remote_resources.end(),
-                 std::back_inserter(team_drive_updates.all_team_drives),
-                 [](const ResourceEntry& entry) -> TeamDrive {
-                   return {entry.resource_id(), entry.base_name(),
-                           drive::util::GetDriveTeamDrivesRootPath().Append(
-                               util::NormalizeFileName(entry.base_name()))};
-                 });
-
-  // Create a copy of the added team drives list to notify observers.
-  std::transform(added_team_drives.begin(), added_team_drives.end(),
-                 std::back_inserter(team_drive_updates.added_team_drives),
-                 [](const ResourceEntry& entry) -> TeamDrive {
-                   return {entry.resource_id(), entry.base_name(),
-                           drive::util::GetDriveTeamDrivesRootPath().Append(
-                               util::NormalizeFileName(entry.base_name()))};
-                 });
-
-  // Create a copy of the removed team drives list to notify observers.
-  std::transform(removed_team_drives.begin(), removed_team_drives.end(),
-                 std::back_inserter(team_drive_updates.removed_team_drives),
-                 [](const ResourceEntry& entry) -> TeamDrive {
-                   return {entry.resource_id()};
-                 });
-
-  // Remove team drives that have been deleted.
-  loader_controller_->ScheduleRun(base::BindOnce(
-      &drive::util::RunAsyncTask, base::RetainedRef(blocking_task_runner_),
-      FROM_HERE,
-      base::BindOnce(&RemoveTeamDrives, std::move(removed_team_drives),
-                     base::Unretained(resource_metadata_),
-                     base::Unretained(in_shutdown_.get())),
-      base::BindOnce(&TeamDriveListLoader::OnTeamDrivesRemoved,
-                     weak_ptr_factory_.GetWeakPtr(),
-                     std::move(remote_resources),
-                     std::move(team_drive_updates))));
-}
-
-void TeamDriveListLoader::OnTeamDrivesRemoved(
-    ResourceEntryVector remote_resources,
-    TeamDriveUpdateData team_drive_updates,
-    FileError error) {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-
-  if (error != FILE_ERROR_OK) {
-    logger_->Log(logging::LOG_ERROR, "Failed to remove team drives: %s",
-                 drive::FileErrorToString(error).c_str());
-    OnTeamDriveListLoadComplete(error);
-    return;
-  }
-
-  loader_controller_->ScheduleRun(base::BindOnce(
-      &drive::util::RunAsyncTask, base::RetainedRef(blocking_task_runner_),
-      FROM_HERE,
-      base::BindOnce(&AddOrUpdateTeamDrives, std::move(remote_resources),
-                     base::Unretained(resource_metadata_),
-                     base::Unretained(in_shutdown_.get())),
-      base::BindOnce(&TeamDriveListLoader::OnAddOrUpdateTeamDrives,
-                     weak_ptr_factory_.GetWeakPtr(),
-                     std::move(team_drive_updates))));
-}
-
-void TeamDriveListLoader::OnAddOrUpdateTeamDrives(
-    TeamDriveUpdateData team_drive_updates,
-    FileError error) {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-
-  if (error != FILE_ERROR_OK) {
-    logger_->Log(logging::LOG_ERROR, "Failed to add or update team drives: %s",
-                 drive::FileErrorToString(error).c_str());
-    OnTeamDriveListLoadComplete(error);
-    return;
-  }
-
-  for (auto& observer : observers_) {
-    observer.OnTeamDriveListLoaded(team_drive_updates.all_team_drives,
-                                   team_drive_updates.added_team_drives,
-                                   team_drive_updates.removed_team_drives);
-  }
-
-  OnTeamDriveListLoadComplete(FILE_ERROR_OK);
-}
-
-void TeamDriveListLoader::OnTeamDriveListLoadComplete(FileError error) {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-
-  if (error == FILE_ERROR_OK) {
-    loaded_ = true;
-  }
-
-  for (auto& callback : pending_load_callbacks_) {
-    callback.Run(error);
-  }
-  pending_load_callbacks_.clear();
-}
-
-}  // namespace internal
-}  // namespace drive
diff --git a/components/drive/chromeos/team_drive_list_loader.h b/components/drive/chromeos/team_drive_list_loader.h
deleted file mode 100644
index bfda6021..0000000
--- a/components/drive/chromeos/team_drive_list_loader.h
+++ /dev/null
@@ -1,107 +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_DRIVE_CHROMEOS_TEAM_DRIVE_LIST_LOADER_H_
-#define COMPONENTS_DRIVE_CHROMEOS_TEAM_DRIVE_LIST_LOADER_H_
-
-#include <memory>
-#include <string>
-#include <vector>
-
-#include "base/macros.h"
-#include "base/memory/weak_ptr.h"
-#include "base/observer_list.h"
-#include "base/threading/thread_checker.h"
-#include "components/drive/chromeos/resource_metadata.h"
-#include "components/drive/chromeos/team_drive_list_observer.h"
-#include "components/drive/file_errors.h"
-#include "google_apis/drive/drive_api_requests.h"
-
-namespace base {
-class AtomicFlag;
-class SequencedTaskRunner;
-}  // namespace base
-
-namespace drive {
-
-class EventLogger;
-class JobScheduler;
-
-namespace internal {
-
-class ChangeList;
-class LoaderController;
-
-// Loads from the server the complete list of the users team drives. This class
-// is used to obtain the initial list of team drives that a user has access to,
-// so that team drive specific change lists and XMPP notifications can be
-// accessed.
-// Upon loading the resource metadata will be updated to reflect the team drives
-// that the user has access to.
-class TeamDriveListLoader {
- public:
-  TeamDriveListLoader(EventLogger* logger,
-                      base::SequencedTaskRunner* blocking_task_runner,
-                      ResourceMetadata* resource_metadata,
-                      JobScheduler* scheduler,
-                      LoaderController* apply_task_controller);
-
-  ~TeamDriveListLoader();
-
-  // Indicates whether there is a request for the team drives list in progress.
-  bool IsRefreshing() const;
-
-  // Gets the team drive list for the user from the server. |callback| must not
-  // be null.
-  void CheckForUpdates(const FileOperationCallback& callback);
-
-  // Loads the state of the users team drives. |callback| must not be null.
-  void LoadIfNeeded(const FileOperationCallback& callback);
-
-  // Adds or removes an observer for team drive related changes.
-  void AddObserver(TeamDriveListObserver* observer);
-  void RemoveObserver(TeamDriveListObserver* observer);
-
- private:
-  struct TeamDriveUpdateData;
-
-  void OnTeamDriveListLoaded(
-      google_apis::DriveApiErrorCode status,
-      std::unique_ptr<google_apis::TeamDriveList> team_drives);
-
-  void OnReadDirectoryByPath(ResourceEntryVector* local_resources,
-                             ResourceEntryVector remote_resources,
-                             FileError error);
-
-  void OnTeamDrivesRemoved(ResourceEntryVector remote_resources,
-                           TeamDriveUpdateData team_drive_updates,
-                           FileError error);
-
-  void OnAddOrUpdateTeamDrives(TeamDriveUpdateData team_drive_updates,
-                               FileError error);
-
-  void OnTeamDriveListLoadComplete(FileError error);
-
-  EventLogger* logger_;  // Not owned.
-  scoped_refptr<base::SequencedTaskRunner> blocking_task_runner_;
-  std::unique_ptr<base::AtomicFlag> in_shutdown_;
-  std::vector<std::unique_ptr<ChangeList>> change_lists_;
-  std::vector<FileOperationCallback> pending_load_callbacks_;
-  bool loaded_ = false;
-  base::ObserverList<TeamDriveListObserver>::Unchecked observers_;
-
-  ResourceMetadata* resource_metadata_;  // Not owned.
-  JobScheduler* scheduler_;              // Not owned.
-  LoaderController* loader_controller_;  // Not owned.
-
-  THREAD_CHECKER(thread_checker_);
-
-  base::WeakPtrFactory<TeamDriveListLoader> weak_ptr_factory_{this};
-  DISALLOW_COPY_AND_ASSIGN(TeamDriveListLoader);
-};
-
-}  // namespace internal
-}  // namespace drive
-
-#endif  // COMPONENTS_DRIVE_CHROMEOS_TEAM_DRIVE_LIST_LOADER_H_
diff --git a/components/drive/directory_loader_unittest.cc b/components/drive/directory_loader_unittest.cc
deleted file mode 100644
index a19503c..0000000
--- a/components/drive/directory_loader_unittest.cc
+++ /dev/null
@@ -1,431 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "components/drive/chromeos/directory_loader.h"
-
-#include <memory>
-
-#include "base/bind.h"
-#include "base/callback_helpers.h"
-#include "base/files/scoped_temp_dir.h"
-#include "base/macros.h"
-#include "base/test/test_mock_time_task_runner.h"
-#include "base/threading/thread_task_runner_handle.h"
-#include "base/time/clock.h"
-#include "components/drive/chromeos/about_resource_loader.h"
-#include "components/drive/chromeos/about_resource_root_folder_id_loader.h"
-#include "components/drive/chromeos/change_list_loader_observer.h"
-#include "components/drive/chromeos/drive_test_util.h"
-#include "components/drive/chromeos/file_cache.h"
-#include "components/drive/chromeos/loader_controller.h"
-#include "components/drive/chromeos/resource_metadata.h"
-#include "components/drive/chromeos/root_folder_id_loader.h"
-#include "components/drive/chromeos/start_page_token_loader.h"
-#include "components/drive/event_logger.h"
-#include "components/drive/file_system_core_util.h"
-#include "components/drive/job_scheduler.h"
-#include "components/drive/service/fake_drive_service.h"
-#include "components/drive/service/test_util.h"
-#include "components/prefs/testing_pref_service.h"
-#include "content/public/test/browser_task_environment.h"
-#include "google_apis/drive/drive_api_parser.h"
-#include "google_apis/drive/test_util.h"
-#include "mojo/public/cpp/bindings/pending_remote.h"
-#include "services/network/test/test_network_connection_tracker.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace drive {
-namespace internal {
-
-namespace {
-
-class TestDirectoryLoaderObserver : public ChangeListLoaderObserver {
- public:
-  explicit TestDirectoryLoaderObserver(DirectoryLoader* loader)
-      : loader_(loader) {
-    loader_->AddObserver(this);
-  }
-
-  ~TestDirectoryLoaderObserver() override { loader_->RemoveObserver(this); }
-
-  const std::set<base::FilePath>& changed_directories() const {
-    return changed_directories_;
-  }
-  void clear_changed_directories() { changed_directories_.clear(); }
-
-  // ChageListObserver overrides:
-  void OnDirectoryReloaded(const base::FilePath& directory_path) override {
-    changed_directories_.insert(directory_path);
-  }
-
- private:
-  DirectoryLoader* loader_;
-  std::set<base::FilePath> changed_directories_;
-
-  DISALLOW_COPY_AND_ASSIGN(TestDirectoryLoaderObserver);
-};
-
-void AccumulateReadDirectoryResult(
-    ResourceEntryVector* out_entries,
-    std::unique_ptr<ResourceEntryVector> entries) {
-  ASSERT_TRUE(entries);
-  out_entries->insert(out_entries->end(), entries->begin(), entries->end());
-}
-
-class FakeRootFolderIdLoader : public RootFolderIdLoader {
- public:
-  explicit FakeRootFolderIdLoader(const std::string& root_folder_id)
-      : root_folder_id_(root_folder_id) {}
-
-  void GetRootFolderId(const RootFolderIdCallback& callback) override {
-    callback.Run(FILE_ERROR_OK, root_folder_id_);
-  }
-
- private:
-  const std::string root_folder_id_;
-};
-
-struct DestroyHelper {
-  template <typename T>
-  void operator()(T* object) const {
-    if (object) {
-      object->Destroy();
-    }
-  }
-};
-
-}  // namespace
-
-class DirectoryLoaderTest : public testing::Test {
- protected:
-  void SetUp() override {
-    task_runner_ = base::MakeRefCounted<base::TestMockTimeTaskRunner>(
-        base::TestMockTimeTaskRunner::Type::kBoundToThread);
-
-    ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
-    pref_service_ = std::make_unique<TestingPrefServiceSimple>();
-    test_util::RegisterDrivePrefs(pref_service_->registry());
-
-    logger_ = std::make_unique<EventLogger>();
-
-    drive_service_ = std::make_unique<FakeDriveService>();
-    ASSERT_TRUE(test_util::SetUpTestEntries(drive_service_.get()));
-
-    network::TestNetworkConnectionTracker::GetInstance()->SetConnectionType(
-        network::mojom::ConnectionType::CONNECTION_WIFI);
-    scheduler_ = std::make_unique<JobScheduler>(
-        pref_service_.get(), logger_.get(), drive_service_.get(),
-        network::TestNetworkConnectionTracker::GetInstance(),
-        task_runner_.get(), mojo::NullRemote());
-    metadata_storage_.reset(
-        new ResourceMetadataStorage(temp_dir_.GetPath(), task_runner_.get()));
-    ASSERT_TRUE(metadata_storage_->Initialize());
-
-    cache_.reset(new FileCache(metadata_storage_.get(), temp_dir_.GetPath(),
-                               task_runner_.get(),
-                               nullptr /* free_disk_space_getter */));
-    ASSERT_TRUE(cache_->Initialize());
-
-    metadata_.reset(new ResourceMetadata(metadata_storage_.get(), cache_.get(),
-                                         task_runner_.get()));
-    ASSERT_EQ(FILE_ERROR_OK, metadata_->Initialize());
-
-    about_resource_loader_ =
-        std::make_unique<AboutResourceLoader>(scheduler_.get());
-    root_folder_id_loader_ = std::make_unique<AboutResourceRootFolderIdLoader>(
-        about_resource_loader_.get());
-    start_page_token_loader_ = std::make_unique<StartPageTokenLoader>(
-        drive::util::kTeamDriveIdDefaultCorpus, scheduler_.get());
-    loader_controller_ = std::make_unique<LoaderController>();
-    directory_loader_ = std::make_unique<DirectoryLoader>(
-        logger_.get(), task_runner_.get(), metadata_.get(), scheduler_.get(),
-        root_folder_id_loader_.get(), start_page_token_loader_.get(),
-        loader_controller_.get(), util::GetDriveMyDriveRootPath(),
-        drive::util::kTeamDriveIdDefaultCorpus, task_runner_->GetMockClock());
-  }
-
-  void TearDown() override {
-    // We need to manually reset the objects that implement the Destroy idiom,
-    // that deletes the object on the |task_runner_|. This is simpler than
-    // introducing custom deleters that capture the |task_runner_| and
-    // invoke RunUntilIdle().
-    metadata_.reset();
-    cache_.reset();
-    metadata_storage_.reset();
-    task_runner_->RunUntilIdle();
-  }
-  // Adds a new file to the root directory of the service.
-  std::unique_ptr<google_apis::FileResource> AddNewFile(
-      const std::string& title) {
-    google_apis::DriveApiErrorCode error = google_apis::DRIVE_FILE_ERROR;
-    std::unique_ptr<google_apis::FileResource> entry;
-    drive_service_->AddNewFile(
-        "text/plain",
-        "content text",
-        drive_service_->GetRootResourceId(),
-        title,
-        false,  // shared_with_me
-        google_apis::test_util::CreateCopyResultCallback(&error, &entry));
-    task_runner_->RunUntilIdle();
-    EXPECT_EQ(google_apis::HTTP_CREATED, error);
-    return entry;
-  }
-
-  // Creates a ResourceEntry for a directory with explicitly set resource_id.
-  ResourceEntry CreateDirectoryEntryWithResourceId(
-      const std::string& title,
-      const std::string& resource_id,
-      const std::string& parent_local_id) {
-    ResourceEntry entry;
-    entry.set_title(title);
-    entry.set_resource_id(resource_id);
-    entry.set_parent_local_id(parent_local_id);
-    entry.mutable_file_info()->set_is_directory(true);
-    entry.mutable_directory_specific_info()->set_start_page_token("0");
-    return entry;
-  }
-
-  void AddTeamDriveRootEntry(const std::string& team_drive_id,
-                             const std::string& team_drive_name) {
-    std::string local_id;
-    ASSERT_EQ(
-        FILE_ERROR_OK,
-        metadata_->GetIdByPath(util::GetDriveTeamDrivesRootPath(), &local_id));
-
-    std::string root_local_id = local_id;
-    ASSERT_EQ(
-        FILE_ERROR_OK,
-        metadata_->AddEntry(CreateDirectoryEntryWithResourceId(
-                                team_drive_name, team_drive_id, root_local_id),
-                            &local_id));
-  }
-
-  scoped_refptr<base::TestMockTimeTaskRunner> task_runner_;
-  base::ScopedTempDir temp_dir_;
-  std::unique_ptr<TestingPrefServiceSimple> pref_service_;
-  std::unique_ptr<EventLogger> logger_;
-  std::unique_ptr<FakeDriveService> drive_service_;
-  std::unique_ptr<JobScheduler> scheduler_;
-  std::unique_ptr<ResourceMetadataStorage, DestroyHelper> metadata_storage_;
-  std::unique_ptr<FileCache, DestroyHelper> cache_;
-  std::unique_ptr<ResourceMetadata, DestroyHelper> metadata_;
-  std::unique_ptr<AboutResourceLoader> about_resource_loader_;
-  std::unique_ptr<StartPageTokenLoader> start_page_token_loader_;
-  std::unique_ptr<LoaderController> loader_controller_;
-  std::unique_ptr<DirectoryLoader> directory_loader_;
-  std::unique_ptr<AboutResourceRootFolderIdLoader> root_folder_id_loader_;
-};
-
-TEST_F(DirectoryLoaderTest, ReadDirectory_GrandRoot) {
-  TestDirectoryLoaderObserver observer(directory_loader_.get());
-
-  // Load grand root.
-  FileError error = FILE_ERROR_FAILED;
-  ResourceEntryVector entries;
-  directory_loader_->ReadDirectory(
-      util::GetDriveGrandRootPath(),
-      base::Bind(&AccumulateReadDirectoryResult, &entries),
-      google_apis::test_util::CreateCopyResultCallback(&error));
-  task_runner_->RunUntilIdle();
-  EXPECT_EQ(FILE_ERROR_OK, error);
-  EXPECT_EQ(0U, observer.changed_directories().size());
-  observer.clear_changed_directories();
-
-  // My Drive has resource ID.
-  ResourceEntry entry;
-  EXPECT_EQ(FILE_ERROR_OK,
-            metadata_->GetResourceEntryByPath(util::GetDriveMyDriveRootPath(),
-                                              &entry));
-  EXPECT_EQ(drive_service_->GetRootResourceId(), entry.resource_id());
-}
-
-TEST_F(DirectoryLoaderTest, ReadDirectory_MyDrive) {
-  TestDirectoryLoaderObserver observer(directory_loader_.get());
-
-  // My Drive does not have resource ID yet.
-  ResourceEntry entry;
-  EXPECT_EQ(FILE_ERROR_OK,
-            metadata_->GetResourceEntryByPath(util::GetDriveMyDriveRootPath(),
-                                              &entry));
-  EXPECT_TRUE(entry.resource_id().empty());
-
-  // Load My Drive.
-  FileError error = FILE_ERROR_FAILED;
-  ResourceEntryVector entries;
-  directory_loader_->ReadDirectory(
-      util::GetDriveMyDriveRootPath(),
-      base::Bind(&AccumulateReadDirectoryResult, &entries),
-      google_apis::test_util::CreateCopyResultCallback(&error));
-  task_runner_->RunUntilIdle();
-  EXPECT_EQ(FILE_ERROR_OK, error);
-  EXPECT_EQ(1U, observer.changed_directories().count(
-      util::GetDriveMyDriveRootPath()));
-
-  // My Drive has resource ID.
-  EXPECT_EQ(FILE_ERROR_OK,
-            metadata_->GetResourceEntryByPath(util::GetDriveMyDriveRootPath(),
-                                              &entry));
-  EXPECT_EQ(drive_service_->GetRootResourceId(), entry.resource_id());
-  EXPECT_EQ(drive_service_->start_page_token().start_page_token(),
-            entry.directory_specific_info().start_page_token());
-
-  // My Drive's child is present.
-  base::FilePath file_path =
-      util::GetDriveMyDriveRootPath().AppendASCII("File 1.txt");
-  EXPECT_EQ(FILE_ERROR_OK,
-            metadata_->GetResourceEntryByPath(file_path, &entry));
-}
-
-// Ensure that multiple requests in succession do not hit the backend until the
-// time to refresh expires.
-TEST_F(DirectoryLoaderTest, ReadDirectory_MyDriveTimedCache) {
-  TestDirectoryLoaderObserver observer(directory_loader_.get());
-
-  // My Drive does not have resource ID yet.
-  ResourceEntry entry;
-  EXPECT_EQ(FILE_ERROR_OK, metadata_->GetResourceEntryByPath(
-                               util::GetDriveMyDriveRootPath(), &entry));
-  EXPECT_TRUE(entry.resource_id().empty());
-
-  // Load My Drive.
-  FileError error = FILE_ERROR_FAILED;
-  ResourceEntryVector entries;
-  directory_loader_->ReadDirectory(
-      util::GetDriveMyDriveRootPath(),
-      base::Bind(&AccumulateReadDirectoryResult, &entries),
-      google_apis::test_util::CreateCopyResultCallback(&error));
-  task_runner_->RunUntilIdle();
-  EXPECT_EQ(FILE_ERROR_OK, error);
-  EXPECT_EQ(1U, observer.changed_directories().count(
-                    util::GetDriveMyDriveRootPath()));
-
-  // My Drive has resource ID.
-  EXPECT_EQ(FILE_ERROR_OK, metadata_->GetResourceEntryByPath(
-                               util::GetDriveMyDriveRootPath(), &entry));
-  EXPECT_EQ(drive_service_->GetRootResourceId(), entry.resource_id());
-  EXPECT_EQ(drive_service_->start_page_token().start_page_token(),
-            entry.directory_specific_info().start_page_token());
-  EXPECT_TRUE(entry.directory_specific_info().has_last_read_time_ms());
-  int64_t read_time = entry.directory_specific_info().last_read_time_ms();
-
-  // Move forward 1 second, should not cause a new read of the backend.
-  observer.clear_changed_directories();
-  task_runner_->FastForwardBy(base::TimeDelta::FromSeconds(1));
-  directory_loader_->ReadDirectory(
-      util::GetDriveMyDriveRootPath(),
-      base::Bind(&AccumulateReadDirectoryResult, &entries),
-      google_apis::test_util::CreateCopyResultCallback(&error));
-  task_runner_->RunUntilIdle();
-  EXPECT_EQ(FILE_ERROR_OK, error);
-  EXPECT_EQ(FILE_ERROR_OK, metadata_->GetResourceEntryByPath(
-                               util::GetDriveMyDriveRootPath(), &entry));
-  EXPECT_EQ(read_time, entry.directory_specific_info().last_read_time_ms());
-
-  // Move forward 60 seconds, should cause a new read of the backend.
-  observer.clear_changed_directories();
-  task_runner_->FastForwardBy(base::TimeDelta::FromSeconds(60));
-  directory_loader_->ReadDirectory(
-      util::GetDriveMyDriveRootPath(),
-      base::Bind(&AccumulateReadDirectoryResult, &entries),
-      google_apis::test_util::CreateCopyResultCallback(&error));
-  task_runner_->RunUntilIdle();
-  EXPECT_EQ(FILE_ERROR_OK, error);
-  EXPECT_EQ(FILE_ERROR_OK, metadata_->GetResourceEntryByPath(
-                               util::GetDriveMyDriveRootPath(), &entry));
-  EXPECT_LT(read_time, entry.directory_specific_info().last_read_time_ms());
-}
-
-TEST_F(DirectoryLoaderTest, ReadDirectory_MultipleCalls) {
-  TestDirectoryLoaderObserver observer(directory_loader_.get());
-
-  // Load grand root.
-  FileError error = FILE_ERROR_FAILED;
-  ResourceEntryVector entries;
-  directory_loader_->ReadDirectory(
-      util::GetDriveGrandRootPath(),
-      base::Bind(&AccumulateReadDirectoryResult, &entries),
-      google_apis::test_util::CreateCopyResultCallback(&error));
-
-  // Load grand root again without waiting for the result.
-  FileError error2 = FILE_ERROR_FAILED;
-  ResourceEntryVector entries2;
-  directory_loader_->ReadDirectory(
-      util::GetDriveGrandRootPath(),
-      base::Bind(&AccumulateReadDirectoryResult, &entries2),
-      google_apis::test_util::CreateCopyResultCallback(&error2));
-  task_runner_->RunUntilIdle();
-
-  // Callback is called for each method call.
-  EXPECT_EQ(FILE_ERROR_OK, error);
-  EXPECT_EQ(FILE_ERROR_OK, error2);
-}
-
-TEST_F(DirectoryLoaderTest, Lock) {
-  // Lock the loader.
-  std::unique_ptr<base::ScopedClosureRunner> lock =
-      loader_controller_->GetLock();
-
-  // Start loading.
-  TestDirectoryLoaderObserver observer(directory_loader_.get());
-  FileError error = FILE_ERROR_FAILED;
-  ResourceEntryVector entries;
-  directory_loader_->ReadDirectory(
-      util::GetDriveMyDriveRootPath(),
-      base::Bind(&AccumulateReadDirectoryResult, &entries),
-      google_apis::test_util::CreateCopyResultCallback(&error));
-  task_runner_->RunUntilIdle();
-
-  // Update is pending due to the lock.
-  EXPECT_TRUE(observer.changed_directories().empty());
-
-  // Unlock the loader, this should resume the pending udpate.
-  lock.reset();
-  task_runner_->RunUntilIdle();
-  EXPECT_EQ(1U, observer.changed_directories().count(
-      util::GetDriveMyDriveRootPath()));
-}
-
-TEST_F(DirectoryLoaderTest, TeamDrive) {
-  constexpr char kTeamDriveId[] = "team_drive_id";
-  constexpr char kTeamDriveName[] = "Team Drive";
-  constexpr char kTeamDriveStartPageToken[] = "12345";
-  const base::FilePath team_drive_path =
-      util::GetDriveTeamDrivesRootPath().AppendASCII(kTeamDriveName);
-
-  auto fake_root_folder_id_loader =
-      std::make_unique<FakeRootFolderIdLoader>(kTeamDriveId);
-  auto start_page_token_loader =
-      std::make_unique<StartPageTokenLoader>(kTeamDriveId, scheduler_.get());
-  auto local_directory_loader = std::make_unique<DirectoryLoader>(
-      logger_.get(), base::ThreadTaskRunnerHandle::Get().get(), metadata_.get(),
-      scheduler_.get(), fake_root_folder_id_loader.get(),
-      start_page_token_loader.get(), loader_controller_.get(), team_drive_path,
-      kTeamDriveId);
-
-  AddTeamDriveRootEntry(kTeamDriveId, kTeamDriveName);
-
-  drive_service_->AddTeamDrive(kTeamDriveId, kTeamDriveName,
-                               kTeamDriveStartPageToken);
-
-  FileError error = FILE_ERROR_FAILED;
-  ResourceEntryVector entries;
-
-  local_directory_loader->ReadDirectory(
-      team_drive_path, base::Bind(&AccumulateReadDirectoryResult, &entries),
-      google_apis::test_util::CreateCopyResultCallback(&error));
-  task_runner_->RunUntilIdle();
-  EXPECT_EQ(FILE_ERROR_OK, error);
-  EXPECT_EQ(1, drive_service_->start_page_token_load_count());
-  EXPECT_EQ(1, drive_service_->directory_load_count());
-
-  // If we checked the folder, we should see that it's start page token has been
-  // updated.
-  ResourceEntry entry;
-  EXPECT_EQ(FILE_ERROR_OK,
-            metadata_->GetResourceEntryByPath(team_drive_path, &entry));
-  EXPECT_EQ(kTeamDriveStartPageToken,
-            entry.directory_specific_info().start_page_token());
-}
-}  // namespace internal
-}  // namespace drive
diff --git a/components/drive/fake_file_system_unittest.cc b/components/drive/fake_file_system_unittest.cc
deleted file mode 100644
index 057f07c..0000000
--- a/components/drive/fake_file_system_unittest.cc
+++ /dev/null
@@ -1,159 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "components/drive/chromeos/fake_file_system.h"
-
-#include <memory>
-
-#include "base/files/file_util.h"
-#include "base/run_loop.h"
-#include "components/drive/file_system_core_util.h"
-#include "components/drive/service/fake_drive_service.h"
-#include "components/drive/service/test_util.h"
-#include "content/public/test/browser_task_environment.h"
-#include "google_apis/drive/test_util.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace drive {
-namespace test_util {
-
-class FakeFileSystemTest : public ::testing::Test {
- protected:
-  void SetUp() override {
-    // Initialize FakeDriveService.
-    fake_drive_service_ = std::make_unique<FakeDriveService>();
-    ASSERT_TRUE(SetUpTestEntries(fake_drive_service_.get()));
-
-    // Create a testee instance.
-    fake_file_system_ =
-        std::make_unique<FakeFileSystem>(fake_drive_service_.get());
-  }
-
-  content::BrowserTaskEnvironment task_environment_;
-  std::unique_ptr<FakeDriveService> fake_drive_service_;
-  std::unique_ptr<FakeFileSystem> fake_file_system_;
-};
-
-TEST_F(FakeFileSystemTest, GetFileContent) {
-  FileError initialize_error = FILE_ERROR_FAILED;
-  std::unique_ptr<ResourceEntry> entry;
-  base::FilePath cache_file_path;
-  google_apis::test_util::TestGetContentCallback get_content_callback;
-  FileError completion_error = FILE_ERROR_FAILED;
-
-  const base::FilePath kDriveFile =
-      util::GetDriveMyDriveRootPath().AppendASCII("File 1.txt");
-
-  // For the first time, the file should be downloaded from the service.
-  base::Closure cancel_download = fake_file_system_->GetFileContent(
-      kDriveFile,
-      google_apis::test_util::CreateCopyResultCallback(
-          &initialize_error, &cache_file_path, &entry),
-      get_content_callback.callback(),
-      google_apis::test_util::CreateCopyResultCallback(&completion_error));
-  base::RunLoop().RunUntilIdle();
-
-  EXPECT_EQ(FILE_ERROR_OK, initialize_error);
-  EXPECT_TRUE(entry);
-
-  // No cache file is available yet.
-  EXPECT_TRUE(cache_file_path.empty());
-
-  // The download should be happened so the |get_content_callback|
-  // should have the actual data.
-  std::string content = get_content_callback.GetConcatenatedData();
-  EXPECT_EQ(26U, content.size());
-  EXPECT_EQ(FILE_ERROR_OK, completion_error);
-
-  initialize_error = FILE_ERROR_FAILED;
-  entry.reset();
-  get_content_callback.mutable_data()->clear();
-  completion_error = FILE_ERROR_FAILED;
-
-  // For the second time, the cache file should be found.
-  cancel_download = fake_file_system_->GetFileContent(
-      kDriveFile,
-      google_apis::test_util::CreateCopyResultCallback(
-          &initialize_error, &cache_file_path, &entry),
-      get_content_callback.callback(),
-      google_apis::test_util::CreateCopyResultCallback(&completion_error));
-  base::RunLoop().RunUntilIdle();
-
-  EXPECT_EQ(FILE_ERROR_OK, initialize_error);
-  EXPECT_TRUE(entry);
-
-  // Cache file should be available.
-  ASSERT_FALSE(cache_file_path.empty());
-
-  // There should be a cache file so no data should be downloaded.
-  EXPECT_TRUE(get_content_callback.data().empty());
-  EXPECT_EQ(FILE_ERROR_OK, completion_error);
-
-  // Make sure the cached file's content.
-  std::string cache_file_content;
-  ASSERT_TRUE(
-      base::ReadFileToString(cache_file_path, &cache_file_content));
-  EXPECT_EQ(content, cache_file_content);
-}
-
-TEST_F(FakeFileSystemTest, GetFileContent_Directory) {
-  FileError initialize_error = FILE_ERROR_FAILED;
-  std::unique_ptr<ResourceEntry> entry;
-  base::FilePath cache_file_path;
-  google_apis::test_util::TestGetContentCallback get_content_callback;
-  FileError completion_error = FILE_ERROR_FAILED;
-  base::Closure cancel_download = fake_file_system_->GetFileContent(
-      util::GetDriveMyDriveRootPath(),
-      google_apis::test_util::CreateCopyResultCallback(
-          &initialize_error, &cache_file_path, &entry),
-      get_content_callback.callback(),
-      google_apis::test_util::CreateCopyResultCallback(&completion_error));
-  base::RunLoop().RunUntilIdle();
-
-  EXPECT_EQ(FILE_ERROR_NOT_A_FILE, completion_error);
-}
-
-TEST_F(FakeFileSystemTest, GetResourceEntry) {
-  FileError error = FILE_ERROR_FAILED;
-  std::unique_ptr<ResourceEntry> entry;
-  fake_file_system_->GetResourceEntry(
-      util::GetDriveMyDriveRootPath().AppendASCII(
-          "Directory 1/Sub Directory Folder"),
-      google_apis::test_util::CreateCopyResultCallback(&error, &entry));
-  base::RunLoop().RunUntilIdle();
-
-  ASSERT_EQ(FILE_ERROR_OK, error);
-  ASSERT_TRUE(entry);
-  EXPECT_EQ("sub_dir_folder_resource_id", entry->resource_id());
-}
-
-TEST_F(FakeFileSystemTest, GetResourceEntry_Root) {
-  FileError error = FILE_ERROR_FAILED;
-  std::unique_ptr<ResourceEntry> entry;
-  fake_file_system_->GetResourceEntry(
-      util::GetDriveMyDriveRootPath(),
-      google_apis::test_util::CreateCopyResultCallback(&error, &entry));
-  base::RunLoop().RunUntilIdle();
-
-  ASSERT_EQ(FILE_ERROR_OK, error);
-  ASSERT_TRUE(entry);
-  EXPECT_TRUE(entry->file_info().is_directory());
-  EXPECT_EQ(fake_drive_service_->GetRootResourceId(), entry->resource_id());
-  EXPECT_EQ(util::kDriveMyDriveRootDirName, entry->title());
-}
-
-TEST_F(FakeFileSystemTest, GetResourceEntry_Invalid) {
-  FileError error = FILE_ERROR_FAILED;
-  std::unique_ptr<ResourceEntry> entry;
-  fake_file_system_->GetResourceEntry(
-      util::GetDriveMyDriveRootPath().AppendASCII("Invalid File Name"),
-      google_apis::test_util::CreateCopyResultCallback(&error, &entry));
-  base::RunLoop().RunUntilIdle();
-
-  ASSERT_EQ(FILE_ERROR_NOT_FOUND, error);
-  ASSERT_FALSE(entry);
-}
-
-}  // namespace test_util
-}  // namespace drive
diff --git a/components/drive/file_system/copy_operation_unittest.cc b/components/drive/file_system/copy_operation_unittest.cc
deleted file mode 100644
index e2f0306..0000000
--- a/components/drive/file_system/copy_operation_unittest.cc
+++ /dev/null
@@ -1,525 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "components/drive/chromeos/file_system/copy_operation.h"
-
-#include <memory>
-
-#include "base/bind.h"
-#include "base/files/file_util.h"
-#include "base/task_runner_util.h"
-#include "components/drive/chromeos/file_cache.h"
-#include "components/drive/chromeos/resource_metadata.h"
-#include "components/drive/drive_api_util.h"
-#include "components/drive/file_change.h"
-#include "components/drive/file_system/operation_test_base.h"
-#include "components/drive/file_system_core_util.h"
-#include "components/drive/service/fake_drive_service.h"
-#include "content/public/test/test_utils.h"
-#include "google_apis/drive/drive_api_parser.h"
-#include "google_apis/drive/test_util.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace drive {
-namespace file_system {
-
-namespace {
-
-// Used to handle WaitForSyncComplete() calls.
-bool CopyWaitForSyncCompleteArguments(std::string* out_local_id,
-                                      FileOperationCallback* out_callback,
-                                      const std::string& local_id,
-                                      const FileOperationCallback& callback) {
-  *out_local_id = local_id;
-  *out_callback = callback;
-  return true;
-}
-
-}  // namespace
-
-class CopyOperationTest : public OperationTestBase {
- protected:
-  void SetUp() override {
-   OperationTestBase::SetUp();
-   operation_ = std::make_unique<CopyOperation>(
-       blocking_task_runner(), delegate(), scheduler(), metadata(), cache());
-  }
-
-  std::unique_ptr<CopyOperation> operation_;
-};
-
-TEST_F(CopyOperationTest, TransferFileFromLocalToRemote_RegularFile) {
-  const base::FilePath local_src_path = temp_dir().AppendASCII("local.txt");
-  const base::FilePath remote_dest_path(
-      FILE_PATH_LITERAL("drive/root/remote.txt"));
-
-  // Prepare a local file.
-  ASSERT_TRUE(
-      google_apis::test_util::WriteStringToFile(local_src_path, "hello"));
-  // Confirm that the remote file does not exist.
-  ResourceEntry entry;
-  ASSERT_EQ(FILE_ERROR_NOT_FOUND,
-            GetLocalResourceEntry(remote_dest_path, &entry));
-
-  // Transfer the local file to Drive.
-  FileError error = FILE_ERROR_FAILED;
-  operation_->TransferFileFromLocalToRemote(
-      local_src_path,
-      remote_dest_path,
-      google_apis::test_util::CreateCopyResultCallback(&error));
-  content::RunAllTasksUntilIdle();
-  EXPECT_EQ(FILE_ERROR_OK, error);
-
-  // TransferFileFromLocalToRemote stores a copy of the local file in the cache,
-  // marks it dirty and requests the observer to upload the file.
-  EXPECT_EQ(FILE_ERROR_OK, GetLocalResourceEntry(remote_dest_path, &entry));
-  EXPECT_EQ(1U, delegate()->updated_local_ids().count(entry.local_id()));
-  EXPECT_TRUE(entry.file_specific_info().cache_state().is_present());
-  EXPECT_TRUE(entry.file_specific_info().cache_state().is_dirty());
-
-  EXPECT_EQ(1U, delegate()->get_changed_files().size());
-  EXPECT_TRUE(delegate()->get_changed_files().count(remote_dest_path));
-}
-
-TEST_F(CopyOperationTest, TransferFileFromLocalToRemote_Overwrite) {
-  const base::FilePath local_src_path = temp_dir().AppendASCII("local.txt");
-  const base::FilePath remote_dest_path(
-      FILE_PATH_LITERAL("drive/root/File 1.txt"));
-
-  // Prepare a local file.
-  EXPECT_TRUE(
-      google_apis::test_util::WriteStringToFile(local_src_path, "hello"));
-  // Confirm that the remote file exists.
-  ResourceEntry entry;
-  EXPECT_EQ(FILE_ERROR_OK, GetLocalResourceEntry(remote_dest_path, &entry));
-
-  // Transfer the local file to Drive.
-  FileError error = FILE_ERROR_FAILED;
-  operation_->TransferFileFromLocalToRemote(
-      local_src_path,
-      remote_dest_path,
-      google_apis::test_util::CreateCopyResultCallback(&error));
-  content::RunAllTasksUntilIdle();
-  EXPECT_EQ(FILE_ERROR_OK, error);
-
-  // TransferFileFromLocalToRemote stores a copy of the local file in the cache,
-  // marks it dirty and requests the observer to upload the file.
-  EXPECT_EQ(FILE_ERROR_OK, GetLocalResourceEntry(remote_dest_path, &entry));
-  EXPECT_EQ(1U, delegate()->updated_local_ids().count(entry.local_id()));
-  EXPECT_TRUE(entry.file_specific_info().cache_state().is_present());
-  EXPECT_TRUE(entry.file_specific_info().cache_state().is_dirty());
-
-  EXPECT_EQ(1U, delegate()->get_changed_files().size());
-  EXPECT_TRUE(delegate()->get_changed_files().count(remote_dest_path));
-}
-
-TEST_F(CopyOperationTest,
-       TransferFileFromLocalToRemote_ExistingHostedDocument) {
-  const base::FilePath local_src_path = temp_dir().AppendASCII("local.gdoc");
-  const base::FilePath remote_dest_path(FILE_PATH_LITERAL(
-      "drive/root/Directory 1/copied.gdoc"));
-
-  // Prepare a local file, which is a json file of a hosted document, which
-  // matches "drive/root/Document 1 excludeDir-test".
-  ASSERT_TRUE(util::CreateGDocFile(
-      local_src_path,
-      GURL("https://3_document_self_link/5_document_resource_id"),
-      "5_document_resource_id"));
-
-  ResourceEntry entry;
-  ASSERT_EQ(FILE_ERROR_NOT_FOUND,
-            GetLocalResourceEntry(remote_dest_path, &entry));
-
-  // Transfer the local file to Drive.
-  FileError error = FILE_ERROR_FAILED;
-  operation_->TransferFileFromLocalToRemote(
-      local_src_path,
-      remote_dest_path,
-      google_apis::test_util::CreateCopyResultCallback(&error));
-  content::RunAllTasksUntilIdle();
-  EXPECT_EQ(FILE_ERROR_OK, error);
-
-  EXPECT_EQ(FILE_ERROR_OK, GetLocalResourceEntry(remote_dest_path, &entry));
-
-  EXPECT_EQ(1U, delegate()->get_changed_files().size());
-  EXPECT_TRUE(delegate()->get_changed_files().count(remote_dest_path));
-  // New copy is created.
-  EXPECT_NE("5_document_resource_id", entry.resource_id());
-}
-
-TEST_F(CopyOperationTest, TransferFileFromLocalToRemote_OrphanHostedDocument) {
-  const base::FilePath local_src_path = temp_dir().AppendASCII("local.gdoc");
-  const base::FilePath remote_dest_path(FILE_PATH_LITERAL(
-      "drive/root/Directory 1/moved.gdoc"));
-
-  // Prepare a local file, which is a json file of a hosted document, which
-  // matches "drive/other/Orphan Document".
-  ASSERT_TRUE(util::CreateGDocFile(
-      local_src_path,
-      GURL("https://3_document_self_link/orphan_doc_1"),
-      "orphan_doc_1"));
-
-  ResourceEntry entry;
-  ASSERT_EQ(FILE_ERROR_NOT_FOUND,
-            GetLocalResourceEntry(remote_dest_path, &entry));
-
-  // Transfer the local file to Drive.
-  FileError error = FILE_ERROR_FAILED;
-  operation_->TransferFileFromLocalToRemote(
-      local_src_path,
-      remote_dest_path,
-      google_apis::test_util::CreateCopyResultCallback(&error));
-  content::RunAllTasksUntilIdle();
-  EXPECT_EQ(FILE_ERROR_OK, error);
-
-  EXPECT_EQ(FILE_ERROR_OK, GetLocalResourceEntry(remote_dest_path, &entry));
-  EXPECT_EQ(ResourceEntry::DIRTY, entry.metadata_edit_state());
-  EXPECT_TRUE(delegate()->updated_local_ids().count(entry.local_id()));
-
-  EXPECT_EQ(1U, delegate()->get_changed_files().size());
-  EXPECT_TRUE(delegate()->get_changed_files().count(remote_dest_path));
-  // The original document got new parent.
-  EXPECT_EQ("orphan_doc_1", entry.resource_id());
-}
-
-TEST_F(CopyOperationTest, TransferFileFromLocalToRemote_NewHostedDocument) {
-  const base::FilePath local_src_path = temp_dir().AppendASCII("local.gdoc");
-  const base::FilePath remote_dest_path(FILE_PATH_LITERAL(
-      "drive/root/Directory 1/moved.gdoc"));
-
-  // Create a hosted document on the server that is not synced to local yet.
-  google_apis::DriveApiErrorCode gdata_error = google_apis::DRIVE_OTHER_ERROR;
-  std::unique_ptr<google_apis::FileResource> new_gdoc_entry;
-  fake_service()->AddNewFile(
-      "application/vnd.google-apps.document", "", "", "title", true,
-      google_apis::test_util::CreateCopyResultCallback(&gdata_error,
-                                                       &new_gdoc_entry));
-  content::RunAllTasksUntilIdle();
-  ASSERT_EQ(google_apis::HTTP_CREATED, gdata_error);
-
-  // Prepare a local file, which is a json file of the added hosted document.
-  ASSERT_TRUE(util::CreateGDocFile(
-      local_src_path,
-      GURL("https://3_document_self_link/" + new_gdoc_entry->file_id()),
-      new_gdoc_entry->file_id()));
-
-  ResourceEntry entry;
-  ASSERT_EQ(FILE_ERROR_NOT_FOUND,
-            GetLocalResourceEntry(remote_dest_path, &entry));
-
-  // Transfer the local file to Drive.
-  FileError error = FILE_ERROR_FAILED;
-  operation_->TransferFileFromLocalToRemote(
-      local_src_path,
-      remote_dest_path,
-      google_apis::test_util::CreateCopyResultCallback(&error));
-  content::RunAllTasksUntilIdle();
-  EXPECT_EQ(FILE_ERROR_OK, error);
-
-  EXPECT_EQ(FILE_ERROR_OK, GetLocalResourceEntry(remote_dest_path, &entry));
-
-  EXPECT_EQ(1U, delegate()->get_changed_files().size());
-  EXPECT_TRUE(delegate()->get_changed_files().count(remote_dest_path));
-  // The original document got new parent.
-  EXPECT_EQ(new_gdoc_entry->file_id(), entry.resource_id());
-}
-
-TEST_F(CopyOperationTest, CopyNotExistingFile) {
-  base::FilePath src_path(FILE_PATH_LITERAL("drive/root/Dummy file.txt"));
-  base::FilePath dest_path(FILE_PATH_LITERAL("drive/root/Test.log"));
-
-  ResourceEntry entry;
-  ASSERT_EQ(FILE_ERROR_NOT_FOUND, GetLocalResourceEntry(src_path, &entry));
-
-  FileError error = FILE_ERROR_OK;
-  operation_->Copy(src_path,
-                   dest_path,
-                   false,
-                   google_apis::test_util::CreateCopyResultCallback(&error));
-  content::RunAllTasksUntilIdle();
-  EXPECT_EQ(FILE_ERROR_NOT_FOUND, error);
-
-  EXPECT_EQ(FILE_ERROR_NOT_FOUND, GetLocalResourceEntry(src_path, &entry));
-  EXPECT_EQ(FILE_ERROR_NOT_FOUND, GetLocalResourceEntry(dest_path, &entry));
-  EXPECT_TRUE(delegate()->get_changed_files().empty());
-}
-
-TEST_F(CopyOperationTest, CopyFileToNonExistingDirectory) {
-  base::FilePath src_path(FILE_PATH_LITERAL("drive/root/File 1.txt"));
-  base::FilePath dest_path(FILE_PATH_LITERAL("drive/root/Dummy/Test.log"));
-
-  ResourceEntry entry;
-  ASSERT_EQ(FILE_ERROR_OK, GetLocalResourceEntry(src_path, &entry));
-  ASSERT_EQ(FILE_ERROR_NOT_FOUND,
-            GetLocalResourceEntry(dest_path.DirName(), &entry));
-
-  FileError error = FILE_ERROR_OK;
-  operation_->Copy(src_path,
-                   dest_path,
-                   false,
-                   google_apis::test_util::CreateCopyResultCallback(&error));
-  content::RunAllTasksUntilIdle();
-  EXPECT_EQ(FILE_ERROR_NOT_FOUND, error);
-
-  EXPECT_EQ(FILE_ERROR_OK, GetLocalResourceEntry(src_path, &entry));
-  EXPECT_EQ(FILE_ERROR_NOT_FOUND, GetLocalResourceEntry(dest_path, &entry));
-  EXPECT_TRUE(delegate()->get_changed_files().empty());
-}
-
-// Test the case where the parent of the destination path is an existing file,
-// not a directory.
-TEST_F(CopyOperationTest, CopyFileToInvalidPath) {
-  base::FilePath src_path(FILE_PATH_LITERAL(
-      "drive/root/Document 1 excludeDir-test.gdoc"));
-  base::FilePath dest_path(FILE_PATH_LITERAL(
-      "drive/root/Duplicate Name.txt/Document 1 excludeDir-test.gdoc"));
-
-  ResourceEntry entry;
-  ASSERT_EQ(FILE_ERROR_OK, GetLocalResourceEntry(src_path, &entry));
-  ASSERT_EQ(FILE_ERROR_OK, GetLocalResourceEntry(dest_path.DirName(), &entry));
-  ASSERT_FALSE(entry.file_info().is_directory());
-
-  FileError error = FILE_ERROR_OK;
-  operation_->Copy(src_path,
-                   dest_path,
-                   false,
-                   google_apis::test_util::CreateCopyResultCallback(&error));
-  content::RunAllTasksUntilIdle();
-  EXPECT_EQ(FILE_ERROR_NOT_A_DIRECTORY, error);
-
-  EXPECT_EQ(FILE_ERROR_OK, GetLocalResourceEntry(src_path, &entry));
-  EXPECT_EQ(FILE_ERROR_NOT_FOUND, GetLocalResourceEntry(dest_path, &entry));
-  EXPECT_TRUE(delegate()->get_changed_files().empty());
-}
-
-TEST_F(CopyOperationTest, CopyDirtyFile) {
-  base::FilePath src_path(FILE_PATH_LITERAL("drive/root/File 1.txt"));
-  base::FilePath dest_path(FILE_PATH_LITERAL(
-      "drive/root/Directory 1/New File.txt"));
-
-  ResourceEntry src_entry;
-  EXPECT_EQ(FILE_ERROR_OK, GetLocalResourceEntry(src_path, &src_entry));
-
-  // Store a dirty cache file.
-  base::FilePath temp_file;
-  EXPECT_TRUE(base::CreateTemporaryFileInDir(temp_dir(), &temp_file));
-  std::string contents = "test content";
-  EXPECT_TRUE(google_apis::test_util::WriteStringToFile(temp_file, contents));
-  FileError error = FILE_ERROR_FAILED;
-  base::PostTaskAndReplyWithResult(
-      blocking_task_runner(),
-      FROM_HERE,
-      base::Bind(&internal::FileCache::Store,
-                 base::Unretained(cache()),
-                 src_entry.local_id(),
-                 std::string(),
-                 temp_file,
-                 internal::FileCache::FILE_OPERATION_MOVE),
-      google_apis::test_util::CreateCopyResultCallback(&error));
-  content::RunAllTasksUntilIdle();
-  EXPECT_EQ(FILE_ERROR_OK, error);
-
-  // Copy.
-  operation_->Copy(src_path,
-                   dest_path,
-                   false,
-                   google_apis::test_util::CreateCopyResultCallback(&error));
-  content::RunAllTasksUntilIdle();
-  EXPECT_EQ(FILE_ERROR_OK, error);
-
-  ResourceEntry dest_entry;
-  EXPECT_EQ(FILE_ERROR_OK, GetLocalResourceEntry(dest_path, &dest_entry));
-  EXPECT_EQ(ResourceEntry::DIRTY, dest_entry.metadata_edit_state());
-
-  EXPECT_EQ(1u, delegate()->updated_local_ids().size());
-  EXPECT_TRUE(delegate()->updated_local_ids().count(dest_entry.local_id()));
-  EXPECT_EQ(1u, delegate()->get_changed_files().size());
-  EXPECT_TRUE(delegate()->get_changed_files().count(dest_path));
-
-  // Copied cache file should be dirty.
-  EXPECT_TRUE(dest_entry.file_specific_info().cache_state().is_dirty());
-
-  // File contents should match.
-  base::FilePath cache_file_path;
-  base::PostTaskAndReplyWithResult(
-      blocking_task_runner(),
-      FROM_HERE,
-      base::Bind(&internal::FileCache::GetFile,
-                 base::Unretained(cache()),
-                 dest_entry.local_id(),
-                 &cache_file_path),
-      google_apis::test_util::CreateCopyResultCallback(&error));
-  content::RunAllTasksUntilIdle();
-  EXPECT_EQ(FILE_ERROR_OK, error);
-
-  std::string copied_contents;
-  EXPECT_TRUE(base::ReadFileToString(cache_file_path, &copied_contents));
-  EXPECT_EQ(contents, copied_contents);
-}
-
-TEST_F(CopyOperationTest, CopyFileOverwriteFile) {
-  base::FilePath src_path(FILE_PATH_LITERAL("drive/root/File 1.txt"));
-  base::FilePath dest_path(FILE_PATH_LITERAL(
-      "drive/root/Directory 1/SubDirectory File 1.txt"));
-
-  ResourceEntry old_dest_entry;
-  EXPECT_EQ(FILE_ERROR_OK, GetLocalResourceEntry(dest_path, &old_dest_entry));
-
-  FileError error = FILE_ERROR_OK;
-  operation_->Copy(src_path,
-                   dest_path,
-                   false,
-                   google_apis::test_util::CreateCopyResultCallback(&error));
-  content::RunAllTasksUntilIdle();
-  EXPECT_EQ(FILE_ERROR_OK, error);
-
-  ResourceEntry new_dest_entry;
-  EXPECT_EQ(FILE_ERROR_OK, GetLocalResourceEntry(dest_path, &new_dest_entry));
-
-  EXPECT_EQ(1u, delegate()->updated_local_ids().size());
-  EXPECT_TRUE(delegate()->updated_local_ids().count(old_dest_entry.local_id()));
-  EXPECT_EQ(1u, delegate()->get_changed_files().size());
-  EXPECT_TRUE(delegate()->get_changed_files().count(dest_path));
-}
-
-TEST_F(CopyOperationTest, CopyFileOverwriteDirectory) {
-  base::FilePath src_path(FILE_PATH_LITERAL("drive/root/File 1.txt"));
-  base::FilePath dest_path(FILE_PATH_LITERAL("drive/root/Directory 1"));
-
-  FileError error = FILE_ERROR_OK;
-  operation_->Copy(src_path,
-                   dest_path,
-                   false,
-                   google_apis::test_util::CreateCopyResultCallback(&error));
-  content::RunAllTasksUntilIdle();
-  EXPECT_EQ(FILE_ERROR_INVALID_OPERATION, error);
-}
-
-TEST_F(CopyOperationTest, CopyDirectory) {
-  base::FilePath src_path(FILE_PATH_LITERAL("drive/root/Directory 1"));
-  base::FilePath dest_path(FILE_PATH_LITERAL("drive/root/New Directory"));
-
-  ResourceEntry entry;
-  ASSERT_EQ(FILE_ERROR_OK, GetLocalResourceEntry(src_path, &entry));
-  ASSERT_TRUE(entry.file_info().is_directory());
-  ASSERT_EQ(FILE_ERROR_OK, GetLocalResourceEntry(dest_path.DirName(), &entry));
-  ASSERT_TRUE(entry.file_info().is_directory());
-
-  FileError error = FILE_ERROR_OK;
-  operation_->Copy(src_path,
-                   dest_path,
-                   false,
-                   google_apis::test_util::CreateCopyResultCallback(&error));
-  content::RunAllTasksUntilIdle();
-  EXPECT_EQ(FILE_ERROR_NOT_A_FILE, error);
-}
-
-TEST_F(CopyOperationTest, PreserveLastModified) {
-  base::FilePath src_path(FILE_PATH_LITERAL("drive/root/File 1.txt"));
-  base::FilePath dest_path(FILE_PATH_LITERAL("drive/root/File 2.txt"));
-
-  ResourceEntry entry;
-  ASSERT_EQ(FILE_ERROR_OK, GetLocalResourceEntry(src_path, &entry));
-  ASSERT_EQ(FILE_ERROR_OK,
-            GetLocalResourceEntry(dest_path.DirName(), &entry));
-
-  FileError error = FILE_ERROR_OK;
-  operation_->Copy(src_path,
-                   dest_path,
-                   true,  // Preserve last modified.
-                   google_apis::test_util::CreateCopyResultCallback(&error));
-  content::RunAllTasksUntilIdle();
-  EXPECT_EQ(FILE_ERROR_OK, error);
-
-  ResourceEntry entry2;
-  EXPECT_EQ(FILE_ERROR_OK, GetLocalResourceEntry(src_path, &entry));
-  EXPECT_EQ(FILE_ERROR_OK, GetLocalResourceEntry(dest_path, &entry2));
-
-  EXPECT_NE(entry.file_info().last_modified(), entry.last_modified_by_me());
-  EXPECT_EQ(entry.file_info().last_modified(),
-            entry2.file_info().last_modified());
-  // Even with preserve_last_modified enabled, last_modified_by_me is forced to
-  // the same value as last_modified.
-  EXPECT_EQ(entry.file_info().last_modified(), entry2.last_modified_by_me());
-}
-
-TEST_F(CopyOperationTest, WaitForSyncComplete) {
-  // Create a directory locally.
-  base::FilePath src_path(FILE_PATH_LITERAL("drive/root/File 1.txt"));
-  base::FilePath directory_path(FILE_PATH_LITERAL("drive/root/New Directory"));
-  base::FilePath dest_path = directory_path.AppendASCII("File 1.txt");
-
-  ResourceEntry directory_parent;
-  EXPECT_EQ(FILE_ERROR_OK,
-            GetLocalResourceEntry(directory_path.DirName(), &directory_parent));
-
-  ResourceEntry directory;
-  directory.set_parent_local_id(directory_parent.local_id());
-  directory.set_title(directory_path.BaseName().AsUTF8Unsafe());
-  directory.mutable_file_info()->set_is_directory(true);
-  directory.set_metadata_edit_state(ResourceEntry::DIRTY);
-
-  std::string directory_local_id;
-  FileError error = FILE_ERROR_FAILED;
-  base::PostTaskAndReplyWithResult(
-      blocking_task_runner(),
-      FROM_HERE,
-      base::Bind(&internal::ResourceMetadata::AddEntry,
-                 base::Unretained(metadata()), directory, &directory_local_id),
-      google_apis::test_util::CreateCopyResultCallback(&error));
-  content::RunAllTasksUntilIdle();
-  EXPECT_EQ(FILE_ERROR_OK, error);
-
-  // Try to copy a file to the new directory which lacks resource ID.
-  // This should result in waiting for the directory to sync.
-  std::string waited_local_id;
-  FileOperationCallback pending_callback;
-  delegate()->set_wait_for_sync_complete_handler(
-      base::Bind(&CopyWaitForSyncCompleteArguments,
-                 &waited_local_id, &pending_callback));
-
-  FileError copy_error = FILE_ERROR_FAILED;
-  operation_->Copy(src_path,
-                   dest_path,
-                   true,  // Preserve last modified.
-                   google_apis::test_util::CreateCopyResultCallback(
-                       &copy_error));
-  content::RunAllTasksUntilIdle();
-  EXPECT_EQ(directory_local_id, waited_local_id);
-  ASSERT_FALSE(pending_callback.is_null());
-
-  // Add a new directory to the server and store the resource ID locally.
-  google_apis::DriveApiErrorCode status = google_apis::DRIVE_OTHER_ERROR;
-  std::unique_ptr<google_apis::FileResource> file_resource;
-  fake_service()->AddNewDirectory(
-      directory_parent.resource_id(), directory.title(),
-      AddNewDirectoryOptions(),
-      google_apis::test_util::CreateCopyResultCallback(&status,
-                                                       &file_resource));
-  content::RunAllTasksUntilIdle();
-  EXPECT_EQ(google_apis::HTTP_CREATED, status);
-  ASSERT_TRUE(file_resource);
-
-  directory.set_local_id(directory_local_id);
-  directory.set_resource_id(file_resource->file_id());
-  base::PostTaskAndReplyWithResult(
-      blocking_task_runner(),
-      FROM_HERE,
-      base::Bind(&internal::ResourceMetadata::RefreshEntry,
-                 base::Unretained(metadata()), directory),
-      google_apis::test_util::CreateCopyResultCallback(&error));
-  content::RunAllTasksUntilIdle();
-  EXPECT_EQ(FILE_ERROR_OK, error);
-
-  // Resume the copy operation.
-  pending_callback.Run(FILE_ERROR_OK);
-  content::RunAllTasksUntilIdle();
-
-  EXPECT_EQ(FILE_ERROR_OK, copy_error);
-  ResourceEntry entry;
-  EXPECT_EQ(FILE_ERROR_OK, GetLocalResourceEntry(dest_path, &entry));
-}
-
-}  // namespace file_system
-}  // namespace drive
diff --git a/components/drive/file_system/create_directory_operation_unittest.cc b/components/drive/file_system/create_directory_operation_unittest.cc
deleted file mode 100644
index 6edc966..0000000
--- a/components/drive/file_system/create_directory_operation_unittest.cc
+++ /dev/null
@@ -1,128 +0,0 @@
-// Copyright (c) 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "components/drive/chromeos/file_system/create_directory_operation.h"
-
-#include "components/drive/file_system/operation_test_base.h"
-#include "content/public/test/test_utils.h"
-#include "google_apis/drive/test_util.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace drive {
-namespace file_system {
-
-class CreateDirectoryOperationTest : public OperationTestBase {
- protected:
-  // Returns FILE_ERROR_OK if a directory is found at |path|.
-  FileError FindDirectory(const base::FilePath& path) {
-    ResourceEntry entry;
-    FileError error = GetLocalResourceEntry(path, &entry);
-    if (error == FILE_ERROR_OK && !entry.file_info().is_directory())
-      error = FILE_ERROR_NOT_A_DIRECTORY;
-    return error;
-  }
-};
-
-TEST_F(CreateDirectoryOperationTest, CreateDirectory) {
-  CreateDirectoryOperation operation(blocking_task_runner(),
-                                     delegate(),
-                                     metadata());
-
-  const base::FilePath kExistingFile(
-      FILE_PATH_LITERAL("drive/root/File 1.txt"));
-  const base::FilePath kExistingDirectory(
-      FILE_PATH_LITERAL("drive/root/Directory 1"));
-  const base::FilePath kNewDirectory1(
-      FILE_PATH_LITERAL("drive/root/New Directory"));
-  const base::FilePath kNewDirectory2 =
-      kNewDirectory1.AppendASCII("New Directory 2/a/b/c");
-
-  // Create a new directory, not recursively.
-  EXPECT_EQ(FILE_ERROR_NOT_FOUND, FindDirectory(kNewDirectory1));
-
-  FileError error = FILE_ERROR_FAILED;
-  operation.CreateDirectory(
-      kNewDirectory1,
-      true, // is_exclusive
-      false,  // is_recursive
-      google_apis::test_util::CreateCopyResultCallback(&error));
-  content::RunAllTasksUntilIdle();
-  EXPECT_EQ(FILE_ERROR_OK, error);
-  EXPECT_EQ(FILE_ERROR_OK, FindDirectory(kNewDirectory1));
-  EXPECT_EQ(1U, delegate()->get_changed_files().size());
-  EXPECT_EQ(
-      1U,
-      delegate()->get_changed_files().CountDirectory(kNewDirectory1.DirName()));
-
-  ResourceEntry entry;
-  EXPECT_EQ(FILE_ERROR_OK, GetLocalResourceEntry(kNewDirectory1, &entry));
-  EXPECT_EQ(ResourceEntry::DIRTY, entry.metadata_edit_state());
-  EXPECT_TRUE(entry.file_info().is_directory());
-  EXPECT_FALSE(base::Time::FromInternalValue(
-      entry.file_info().last_modified()).is_null());
-  EXPECT_FALSE(
-      base::Time::FromInternalValue(entry.last_modified_by_me()).is_null());
-  EXPECT_FALSE(base::Time::FromInternalValue(
-      entry.file_info().last_accessed()).is_null());
-  EXPECT_EQ(1U, delegate()->updated_local_ids().size());
-  EXPECT_EQ(1U, delegate()->updated_local_ids().count(entry.local_id()));
-
-  // Create a new directory recursively.
-  EXPECT_EQ(FILE_ERROR_NOT_FOUND, FindDirectory(kNewDirectory2));
-  operation.CreateDirectory(
-      kNewDirectory2,
-      true, // is_exclusive
-      false,  // is_recursive
-      google_apis::test_util::CreateCopyResultCallback(&error));
-  content::RunAllTasksUntilIdle();
-  EXPECT_EQ(FILE_ERROR_NOT_FOUND, error);
-  EXPECT_EQ(FILE_ERROR_NOT_FOUND, FindDirectory(kNewDirectory2));
-
-  operation.CreateDirectory(
-      kNewDirectory2,
-      true, // is_exclusive
-      true,  // is_recursive
-      google_apis::test_util::CreateCopyResultCallback(&error));
-  content::RunAllTasksUntilIdle();
-  EXPECT_EQ(FILE_ERROR_OK, error);
-  EXPECT_EQ(FILE_ERROR_OK, FindDirectory(kNewDirectory2));
-
-  // Try to create an existing directory.
-  operation.CreateDirectory(
-      kExistingDirectory,
-      true, // is_exclusive
-      false,  // is_recursive
-      google_apis::test_util::CreateCopyResultCallback(&error));
-  content::RunAllTasksUntilIdle();
-  EXPECT_EQ(FILE_ERROR_EXISTS, error);
-
-  operation.CreateDirectory(
-      kExistingDirectory,
-      false, // is_exclusive
-      false,  // is_recursive
-      google_apis::test_util::CreateCopyResultCallback(&error));
-  content::RunAllTasksUntilIdle();
-  EXPECT_EQ(FILE_ERROR_OK, error);
-
-  // Try to create a directory with a path for an existing file.
-  operation.CreateDirectory(
-      kExistingFile,
-      false, // is_exclusive
-      true,  // is_recursive
-      google_apis::test_util::CreateCopyResultCallback(&error));
-  content::RunAllTasksUntilIdle();
-  EXPECT_EQ(FILE_ERROR_NOT_A_DIRECTORY, error);
-
-  // Try to create a directory under a file.
-  operation.CreateDirectory(
-      kExistingFile.AppendASCII("New Directory"),
-      false, // is_exclusive
-      true,  // is_recursive
-      google_apis::test_util::CreateCopyResultCallback(&error));
-  content::RunAllTasksUntilIdle();
-  EXPECT_EQ(FILE_ERROR_NOT_A_DIRECTORY, error);
-}
-
-}  // namespace file_system
-}  // namespace drive
diff --git a/components/drive/file_system/create_file_operation_unittest.cc b/components/drive/file_system/create_file_operation_unittest.cc
deleted file mode 100644
index 884b79cd..0000000
--- a/components/drive/file_system/create_file_operation_unittest.cc
+++ /dev/null
@@ -1,163 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "components/drive/chromeos/file_system/create_file_operation.h"
-
-#include "components/drive/file_change.h"
-#include "components/drive/file_system/operation_test_base.h"
-#include "content/public/test/test_utils.h"
-#include "google_apis/drive/test_util.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace drive {
-namespace file_system {
-
-typedef OperationTestBase CreateFileOperationTest;
-
-TEST_F(CreateFileOperationTest, CreateFile) {
-  CreateFileOperation operation(blocking_task_runner(),
-                                delegate(),
-                                metadata());
-
-  const base::FilePath kFilePath(FILE_PATH_LITERAL("drive/root/New File.txt"));
-  FileError error = FILE_ERROR_FAILED;
-  operation.CreateFile(
-      kFilePath,
-      true,  // is_exclusive
-      std::string(),  // no predetermined mime type
-      google_apis::test_util::CreateCopyResultCallback(&error));
-  content::RunAllTasksUntilIdle();
-  EXPECT_EQ(FILE_ERROR_OK, error);
-
-  ResourceEntry entry;
-  EXPECT_EQ(FILE_ERROR_OK, GetLocalResourceEntry(kFilePath, &entry));
-  EXPECT_EQ(ResourceEntry::DIRTY, entry.metadata_edit_state());
-  EXPECT_FALSE(base::Time::FromInternalValue(
-      entry.file_info().last_modified()).is_null());
-  EXPECT_FALSE(
-      base::Time::FromInternalValue(entry.last_modified_by_me()).is_null());
-  EXPECT_FALSE(base::Time::FromInternalValue(
-      entry.file_info().last_accessed()).is_null());
-
-  EXPECT_EQ(1u, delegate()->get_changed_files().size());
-  EXPECT_EQ(1u, delegate()->get_changed_files().count(kFilePath));
-  EXPECT_EQ(1u, delegate()->updated_local_ids().size());
-  EXPECT_EQ(1u, delegate()->updated_local_ids().count(entry.local_id()));
-}
-
-TEST_F(CreateFileOperationTest, CreateFileIsExclusive) {
-  CreateFileOperation operation(blocking_task_runner(),
-                                delegate(),
-                                metadata());
-
-  const base::FilePath kExistingFile(
-      FILE_PATH_LITERAL("drive/root/File 1.txt"));
-  const base::FilePath kExistingDirectory(
-      FILE_PATH_LITERAL("drive/root/Directory 1"));
-  const base::FilePath kNonExistingFile(
-      FILE_PATH_LITERAL("drive/root/Directory 1/not exist.png"));
-  const base::FilePath kFileInNonExistingDirectory(
-      FILE_PATH_LITERAL("drive/root/not exist/not exist.png"));
-
-  // Create fails if is_exclusive = true and a file exists.
-  FileError error = FILE_ERROR_FAILED;
-  operation.CreateFile(
-      kExistingFile,
-      true,  // is_exclusive
-      std::string(),  // no predetermined mime type
-      google_apis::test_util::CreateCopyResultCallback(&error));
-  content::RunAllTasksUntilIdle();
-  EXPECT_EQ(FILE_ERROR_EXISTS, error);
-
-  // Create succeeds if is_exclusive = false and a file exists.
-  operation.CreateFile(
-      kExistingFile,
-      false,  // is_exclusive
-      std::string(),  // no predetermined mime type
-      google_apis::test_util::CreateCopyResultCallback(&error));
-  content::RunAllTasksUntilIdle();
-  EXPECT_EQ(FILE_ERROR_OK, error);
-
-  // Create fails if a directory existed even when is_exclusive = false.
-  operation.CreateFile(
-      kExistingDirectory,
-      false,  // is_exclusive
-      std::string(),  // no predetermined mime type
-      google_apis::test_util::CreateCopyResultCallback(&error));
-  content::RunAllTasksUntilIdle();
-  EXPECT_EQ(FILE_ERROR_EXISTS, error);
-
-  // Create succeeds if no entry exists.
-  operation.CreateFile(
-      kNonExistingFile,
-      true,   // is_exclusive
-      std::string(),  // no predetermined mime type
-      google_apis::test_util::CreateCopyResultCallback(&error));
-  content::RunAllTasksUntilIdle();
-  EXPECT_EQ(FILE_ERROR_OK, error);
-
-  // Create fails if the parent directory does not exist.
-  operation.CreateFile(
-      kFileInNonExistingDirectory,
-      false,  // is_exclusive
-      std::string(),  // no predetermined mime type
-      google_apis::test_util::CreateCopyResultCallback(&error));
-  content::RunAllTasksUntilIdle();
-  EXPECT_EQ(FILE_ERROR_NOT_A_DIRECTORY, error);
-}
-
-TEST_F(CreateFileOperationTest, CreateFileMimeType) {
-  CreateFileOperation operation(blocking_task_runner(),
-                                delegate(),
-                                metadata());
-
-  const base::FilePath kPng1(FILE_PATH_LITERAL("drive/root/1.png"));
-  const base::FilePath kPng2(FILE_PATH_LITERAL("drive/root/2.png"));
-  const base::FilePath kUnknown(FILE_PATH_LITERAL("drive/root/3.unknown"));
-  const std::string kSpecialMimeType("application/x-createfile-test");
-
-  FileError error = FILE_ERROR_FAILED;
-  operation.CreateFile(
-      kPng1,
-      false,  // is_exclusive
-      std::string(),  // no predetermined mime type
-      google_apis::test_util::CreateCopyResultCallback(&error));
-  content::RunAllTasksUntilIdle();
-  EXPECT_EQ(FILE_ERROR_OK, error);
-
-  // If no mime type is specified, it is guessed from the file name.
-  ResourceEntry entry;
-  ASSERT_EQ(FILE_ERROR_OK, GetLocalResourceEntry(kPng1, &entry));
-  EXPECT_EQ("image/png", entry.file_specific_info().content_mime_type());
-
-  error = FILE_ERROR_FAILED;
-  operation.CreateFile(
-      kPng2,
-      false,  // is_exclusive
-      kSpecialMimeType,
-      google_apis::test_util::CreateCopyResultCallback(&error));
-  content::RunAllTasksUntilIdle();
-  EXPECT_EQ(FILE_ERROR_OK, error);
-
-  // If the mime type is explicitly set, respect it.
-  ASSERT_EQ(FILE_ERROR_OK, GetLocalResourceEntry(kPng2, &entry));
-  EXPECT_EQ(kSpecialMimeType, entry.file_specific_info().content_mime_type());
-
-  error = FILE_ERROR_FAILED;
-  operation.CreateFile(
-      kUnknown,
-      false,  // is_exclusive
-      std::string(),  // no predetermined mime type
-      google_apis::test_util::CreateCopyResultCallback(&error));
-  content::RunAllTasksUntilIdle();
-  EXPECT_EQ(FILE_ERROR_OK, error);
-
-  // If the mime type is not set and unknown, default to octet-stream.
-  ASSERT_EQ(FILE_ERROR_OK, GetLocalResourceEntry(kUnknown, &entry));
-  EXPECT_EQ("application/octet-stream",
-            entry.file_specific_info().content_mime_type());
-}
-
-}  // namespace file_system
-}  // namespace drive
diff --git a/components/drive/file_system/download_operation_unittest.cc b/components/drive/file_system/download_operation_unittest.cc
deleted file mode 100644
index 58625b8d..0000000
--- a/components/drive/file_system/download_operation_unittest.cc
+++ /dev/null
@@ -1,510 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "components/drive/chromeos/file_system/download_operation.h"
-
-#include <stddef.h>
-#include <stdint.h>
-
-#include <memory>
-
-#include "base/bind.h"
-#include "base/files/file_util.h"
-#include "base/task_runner_util.h"
-#include "components/drive/chromeos/fake_free_disk_space_getter.h"
-#include "components/drive/chromeos/file_cache.h"
-#include "components/drive/file_change.h"
-#include "components/drive/file_system/operation_test_base.h"
-#include "components/drive/file_system_core_util.h"
-#include "components/drive/job_scheduler.h"
-#include "components/drive/service/fake_drive_service.h"
-#include "content/public/test/test_utils.h"
-#include "google_apis/drive/test_util.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace drive {
-namespace file_system {
-
-class DownloadOperationTest : public OperationTestBase {
- protected:
-  void SetUp() override {
-    OperationTestBase::SetUp();
-
-    operation_ = std::make_unique<DownloadOperation>(
-        blocking_task_runner(), delegate(), scheduler(), metadata(), cache(),
-        temp_dir());
-  }
-
-  std::unique_ptr<DownloadOperation> operation_;
-};
-
-TEST_F(DownloadOperationTest,
-       EnsureFileDownloadedByPath_FromServer_EnoughSpace) {
-  base::FilePath file_in_root(FILE_PATH_LITERAL("drive/root/File 1.txt"));
-  ResourceEntry src_entry;
-  ASSERT_EQ(FILE_ERROR_OK, GetLocalResourceEntry(file_in_root, &src_entry));
-  const int64_t file_size = src_entry.file_info().size();
-
-  // Pretend we have enough space.
-  fake_free_disk_space_getter()->set_default_value(
-      file_size + drive::internal::kMinFreeSpaceInBytes);
-
-  FileError error = FILE_ERROR_FAILED;
-  base::FilePath file_path;
-  std::unique_ptr<ResourceEntry> entry;
-  operation_->EnsureFileDownloadedByPath(
-      file_in_root,
-      ClientContext(USER_INITIATED),
-      GetFileContentInitializedCallback(),
-      google_apis::GetContentCallback(),
-      google_apis::test_util::CreateCopyResultCallback(
-          &error, &file_path, &entry));
-  content::RunAllTasksUntilIdle();
-
-  EXPECT_EQ(FILE_ERROR_OK, error);
-  ASSERT_TRUE(entry);
-  EXPECT_FALSE(entry->file_specific_info().is_hosted_document());
-
-  // The transfered file is cached and the change of "offline available"
-  // attribute is notified.
-  EXPECT_EQ(1U, delegate()->get_changed_files().size());
-  EXPECT_EQ(1U, delegate()->get_changed_files().count(file_in_root));
-}
-
-TEST_F(DownloadOperationTest,
-       EnsureFileDownloadedByPath_FromServer_NoSpaceAtAll) {
-  base::FilePath file_in_root(FILE_PATH_LITERAL("drive/root/File 1.txt"));
-
-  // Pretend we have no space at all.
-  fake_free_disk_space_getter()->set_default_value(0);
-
-  FileError error = FILE_ERROR_OK;
-  base::FilePath file_path;
-  std::unique_ptr<ResourceEntry> entry;
-  operation_->EnsureFileDownloadedByPath(
-      file_in_root,
-      ClientContext(USER_INITIATED),
-      GetFileContentInitializedCallback(),
-      google_apis::GetContentCallback(),
-      google_apis::test_util::CreateCopyResultCallback(
-          &error, &file_path, &entry));
-  content::RunAllTasksUntilIdle();
-
-  EXPECT_EQ(FILE_ERROR_NO_LOCAL_SPACE, error);
-}
-
-TEST_F(DownloadOperationTest,
-       EnsureFileDownloadedByPath_FromServer_NoEnoughSpaceButCanFreeUp) {
-  base::FilePath file_in_root(FILE_PATH_LITERAL("drive/root/File 1.txt"));
-  ResourceEntry src_entry;
-  ASSERT_EQ(FILE_ERROR_OK, GetLocalResourceEntry(file_in_root, &src_entry));
-  const int64_t file_size = src_entry.file_info().size();
-
-  // Make another file cached.
-  // This file's cache file will be removed to free up the disk space.
-  base::FilePath cached_file(
-      FILE_PATH_LITERAL("drive/root/Duplicate Name.txt"));
-  FileError error = FILE_ERROR_FAILED;
-  base::FilePath file_path;
-  std::unique_ptr<ResourceEntry> entry;
-  operation_->EnsureFileDownloadedByPath(
-      cached_file,
-      ClientContext(USER_INITIATED),
-      GetFileContentInitializedCallback(),
-      google_apis::GetContentCallback(),
-      google_apis::test_util::CreateCopyResultCallback(
-          &error, &file_path, &entry));
-  content::RunAllTasksUntilIdle();
-  EXPECT_EQ(FILE_ERROR_OK, error);
-  ASSERT_TRUE(entry);
-  EXPECT_TRUE(entry->file_specific_info().cache_state().is_present());
-
-  // Pretend we have no space first (checked before downloading a file),
-  // but then start reporting we have space. This is to emulate that
-  // the disk space was freed up by removing temporary files.
-  fake_free_disk_space_getter()->set_default_value(
-      file_size + drive::internal::kMinFreeSpaceInBytes);
-  fake_free_disk_space_getter()->PushFakeValue(0);
-  fake_free_disk_space_getter()->PushFakeValue(0);
-
-  operation_->EnsureFileDownloadedByPath(
-      file_in_root,
-      ClientContext(USER_INITIATED),
-      GetFileContentInitializedCallback(),
-      google_apis::GetContentCallback(),
-      google_apis::test_util::CreateCopyResultCallback(
-          &error, &file_path, &entry));
-  content::RunAllTasksUntilIdle();
-
-  EXPECT_EQ(FILE_ERROR_OK, error);
-  ASSERT_TRUE(entry);
-  EXPECT_FALSE(entry->file_specific_info().is_hosted_document());
-
-  // The transfered file is cached and the change of "offline available"
-  // attribute is notified.
-  EXPECT_EQ(2U, delegate()->get_changed_files().size());
-  EXPECT_TRUE(delegate()->get_changed_files().count(file_in_root));
-  EXPECT_TRUE(delegate()->get_changed_files().count(cached_file));
-
-  // The cache for the other file should be removed in order to free up space.
-  ResourceEntry cached_file_entry;
-  EXPECT_EQ(FILE_ERROR_OK,
-            GetLocalResourceEntry(cached_file, &cached_file_entry));
-  EXPECT_FALSE(
-      cached_file_entry.file_specific_info().cache_state().is_present());
-}
-
-TEST_F(DownloadOperationTest,
-       EnsureFileDownloadedByPath_FromServer_EnoughSpaceButBecomeFull) {
-  base::FilePath file_in_root(FILE_PATH_LITERAL("drive/root/File 1.txt"));
-  ResourceEntry src_entry;
-  ASSERT_EQ(FILE_ERROR_OK, GetLocalResourceEntry(file_in_root, &src_entry));
-  const int64_t file_size = src_entry.file_info().size();
-
-  // Pretend we have enough space first (checked before downloading a file),
-  // but then start reporting we have not enough space. This is to emulate that
-  // the disk space becomes full after the file is downloaded for some reason
-  // (ex. the actual file was larger than the expected size).
-  fake_free_disk_space_getter()->PushFakeValue(
-      file_size + drive::internal::kMinFreeSpaceInBytes);
-  fake_free_disk_space_getter()->set_default_value(
-      drive::internal::kMinFreeSpaceInBytes - 1);
-
-  FileError error = FILE_ERROR_OK;
-  base::FilePath file_path;
-  std::unique_ptr<ResourceEntry> entry;
-  operation_->EnsureFileDownloadedByPath(
-      file_in_root,
-      ClientContext(USER_INITIATED),
-      GetFileContentInitializedCallback(),
-      google_apis::GetContentCallback(),
-      google_apis::test_util::CreateCopyResultCallback(
-          &error, &file_path, &entry));
-  content::RunAllTasksUntilIdle();
-
-  EXPECT_EQ(FILE_ERROR_NO_LOCAL_SPACE, error);
-}
-
-TEST_F(DownloadOperationTest, EnsureFileDownloadedByPath_FromCache) {
-  base::FilePath temp_file;
-  ASSERT_TRUE(base::CreateTemporaryFileInDir(temp_dir(), &temp_file));
-
-  base::FilePath file_in_root(FILE_PATH_LITERAL("drive/root/File 1.txt"));
-  ResourceEntry src_entry;
-  ASSERT_EQ(FILE_ERROR_OK, GetLocalResourceEntry(file_in_root, &src_entry));
-
-  // Store something as cached version of this file.
-  FileError error = FILE_ERROR_OK;
-  base::PostTaskAndReplyWithResult(
-      blocking_task_runner(),
-      FROM_HERE,
-      base::Bind(&internal::FileCache::Store,
-                 base::Unretained(cache()),
-                 GetLocalId(file_in_root),
-                 src_entry.file_specific_info().md5(),
-                 temp_file,
-                 internal::FileCache::FILE_OPERATION_COPY),
-      google_apis::test_util::CreateCopyResultCallback(&error));
-  content::RunAllTasksUntilIdle();
-  EXPECT_EQ(FILE_ERROR_OK, error);
-
-  base::FilePath file_path;
-  std::unique_ptr<ResourceEntry> entry;
-  operation_->EnsureFileDownloadedByPath(
-      file_in_root,
-      ClientContext(USER_INITIATED),
-      GetFileContentInitializedCallback(),
-      google_apis::GetContentCallback(),
-      google_apis::test_util::CreateCopyResultCallback(
-          &error, &file_path, &entry));
-  content::RunAllTasksUntilIdle();
-
-  EXPECT_EQ(FILE_ERROR_OK, error);
-  ASSERT_TRUE(entry);
-  EXPECT_FALSE(entry->file_specific_info().is_hosted_document());
-}
-
-TEST_F(DownloadOperationTest, EnsureFileDownloadedByPath_HostedDocument) {
-  base::FilePath file_in_root(FILE_PATH_LITERAL(
-      "drive/root/Document 1 excludeDir-test.gdoc"));
-
-  FileError error = FILE_ERROR_FAILED;
-  base::FilePath file_path;
-  std::unique_ptr<ResourceEntry> entry;
-  operation_->EnsureFileDownloadedByPath(
-      file_in_root,
-      ClientContext(USER_INITIATED),
-      GetFileContentInitializedCallback(),
-      google_apis::GetContentCallback(),
-      google_apis::test_util::CreateCopyResultCallback(
-          &error, &file_path, &entry));
-  content::RunAllTasksUntilIdle();
-
-  EXPECT_EQ(FILE_ERROR_OK, error);
-  ASSERT_TRUE(entry);
-  EXPECT_TRUE(entry->file_specific_info().is_hosted_document());
-  EXPECT_FALSE(file_path.empty());
-
-  EXPECT_EQ(GURL(entry->alternate_url()), util::ReadUrlFromGDocFile(file_path));
-  EXPECT_EQ(entry->resource_id(), util::ReadResourceIdFromGDocFile(file_path));
-  EXPECT_EQ(FILE_PATH_LITERAL(".gdoc"), file_path.Extension());
-}
-
-TEST_F(DownloadOperationTest, EnsureFileDownloadedByLocalId) {
-  base::FilePath file_in_root(FILE_PATH_LITERAL("drive/root/File 1.txt"));
-  ResourceEntry src_entry;
-  ASSERT_EQ(FILE_ERROR_OK, GetLocalResourceEntry(file_in_root, &src_entry));
-
-  FileError error = FILE_ERROR_OK;
-  base::FilePath file_path;
-  std::unique_ptr<ResourceEntry> entry;
-  operation_->EnsureFileDownloadedByLocalId(
-      GetLocalId(file_in_root),
-      ClientContext(USER_INITIATED),
-      GetFileContentInitializedCallback(),
-      google_apis::GetContentCallback(),
-      google_apis::test_util::CreateCopyResultCallback(
-          &error, &file_path, &entry));
-  content::RunAllTasksUntilIdle();
-
-  EXPECT_EQ(FILE_ERROR_OK, error);
-  ASSERT_TRUE(entry);
-  EXPECT_FALSE(entry->file_specific_info().is_hosted_document());
-
-  // The transfered file is cached and the change of "offline available"
-  // attribute is notified.
-  EXPECT_EQ(1U, delegate()->get_changed_files().size());
-  EXPECT_EQ(1U, delegate()->get_changed_files().count(file_in_root));
-}
-
-TEST_F(DownloadOperationTest,
-       EnsureFileDownloadedByPath_WithGetContentCallback) {
-  base::FilePath file_in_root(FILE_PATH_LITERAL("drive/root/File 1.txt"));
-
-  {
-    FileError initialized_error = FILE_ERROR_FAILED;
-    std::unique_ptr<ResourceEntry> entry, entry_dontcare;
-    base::FilePath local_path, local_path_dontcare;
-    google_apis::test_util::TestGetContentCallback get_content_callback;
-    FileError completion_error = FILE_ERROR_FAILED;
-    base::Closure cancel_download = operation_->EnsureFileDownloadedByPath(
-        file_in_root,
-        ClientContext(USER_INITIATED),
-        google_apis::test_util::CreateCopyResultCallback(
-            &initialized_error, &local_path, &entry),
-        get_content_callback.callback(),
-        google_apis::test_util::CreateCopyResultCallback(
-            &completion_error, &local_path_dontcare, &entry_dontcare));
-    content::RunAllTasksUntilIdle();
-
-    // For the first time, file is downloaded from the remote server.
-    // In this case, |local_path| is empty.
-    EXPECT_EQ(FILE_ERROR_OK, initialized_error);
-    ASSERT_TRUE(entry);
-    ASSERT_TRUE(local_path.empty());
-    EXPECT_FALSE(cancel_download.is_null());
-    // Content is available through the second callback argument.
-    EXPECT_EQ(static_cast<size_t>(entry->file_info().size()),
-              get_content_callback.GetConcatenatedData().size());
-    EXPECT_EQ(FILE_ERROR_OK, completion_error);
-
-    // The transfered file is cached and the change of "offline available"
-    // attribute is notified.
-    EXPECT_EQ(1U, delegate()->get_changed_files().size());
-    EXPECT_EQ(1U, delegate()->get_changed_files().count(file_in_root));
-  }
-
-  {
-    FileError initialized_error = FILE_ERROR_FAILED;
-    std::unique_ptr<ResourceEntry> entry, entry_dontcare;
-    base::FilePath local_path, local_path_dontcare;
-    google_apis::test_util::TestGetContentCallback get_content_callback;
-    FileError completion_error = FILE_ERROR_FAILED;
-    base::Closure cancel_download = operation_->EnsureFileDownloadedByPath(
-        file_in_root,
-        ClientContext(USER_INITIATED),
-        google_apis::test_util::CreateCopyResultCallback(
-            &initialized_error, &local_path, &entry),
-        get_content_callback.callback(),
-        google_apis::test_util::CreateCopyResultCallback(
-            &completion_error, &local_path_dontcare, &entry_dontcare));
-    content::RunAllTasksUntilIdle();
-
-    // Try second download. In this case, the file should be cached, so
-    // |local_path| should not be empty.
-    EXPECT_EQ(FILE_ERROR_OK, initialized_error);
-    ASSERT_TRUE(entry);
-    ASSERT_TRUE(!local_path.empty());
-    EXPECT_FALSE(cancel_download.is_null());
-    // The content is available from the cache file.
-    EXPECT_TRUE(get_content_callback.data().empty());
-    int64_t local_file_size = 0;
-    base::GetFileSize(local_path, &local_file_size);
-    EXPECT_EQ(entry->file_info().size(), local_file_size);
-    EXPECT_EQ(FILE_ERROR_OK, completion_error);
-  }
-}
-
-TEST_F(DownloadOperationTest, EnsureFileDownloadedByLocalId_FromCache) {
-  base::FilePath temp_file;
-  ASSERT_TRUE(base::CreateTemporaryFileInDir(temp_dir(), &temp_file));
-
-  base::FilePath file_in_root(FILE_PATH_LITERAL("drive/root/File 1.txt"));
-  ResourceEntry src_entry;
-  ASSERT_EQ(FILE_ERROR_OK, GetLocalResourceEntry(file_in_root, &src_entry));
-
-  // Store something as cached version of this file.
-  FileError error = FILE_ERROR_FAILED;
-  base::PostTaskAndReplyWithResult(
-      blocking_task_runner(),
-      FROM_HERE,
-      base::Bind(&internal::FileCache::Store,
-                 base::Unretained(cache()),
-                 GetLocalId(file_in_root),
-                 src_entry.file_specific_info().md5(),
-                 temp_file,
-                 internal::FileCache::FILE_OPERATION_COPY),
-      google_apis::test_util::CreateCopyResultCallback(&error));
-  content::RunAllTasksUntilIdle();
-  EXPECT_EQ(FILE_ERROR_OK, error);
-
-  // The file is obtained from the cache.
-  // Hence the downloading should work even if the drive service is offline.
-  fake_service()->set_offline(true);
-
-  base::FilePath file_path;
-  std::unique_ptr<ResourceEntry> entry;
-  operation_->EnsureFileDownloadedByLocalId(
-      GetLocalId(file_in_root),
-      ClientContext(USER_INITIATED),
-      GetFileContentInitializedCallback(),
-      google_apis::GetContentCallback(),
-      google_apis::test_util::CreateCopyResultCallback(
-          &error, &file_path, &entry));
-  content::RunAllTasksUntilIdle();
-
-  EXPECT_EQ(FILE_ERROR_OK, error);
-  ASSERT_TRUE(entry);
-  EXPECT_FALSE(entry->file_specific_info().is_hosted_document());
-}
-
-TEST_F(DownloadOperationTest, EnsureFileDownloadedByPath_DirtyCache) {
-  base::FilePath file_in_root(FILE_PATH_LITERAL("drive/root/File 1.txt"));
-  ResourceEntry src_entry;
-  ASSERT_EQ(FILE_ERROR_OK, GetLocalResourceEntry(file_in_root, &src_entry));
-
-  // Prepare a dirty file to store to cache that has a different size than
-  // stored in resource metadata.
-  base::FilePath dirty_file = temp_dir().AppendASCII("dirty.txt");
-  size_t dirty_size = src_entry.file_info().size() + 10;
-  google_apis::test_util::WriteStringToFile(dirty_file,
-                                            std::string(dirty_size, 'x'));
-
-  // Store the file as a cache, marking it to be dirty.
-  FileError error = FILE_ERROR_FAILED;
-  base::PostTaskAndReplyWithResult(
-      blocking_task_runner(),
-      FROM_HERE,
-      base::Bind(&internal::FileCache::Store,
-                 base::Unretained(cache()),
-                 GetLocalId(file_in_root),
-                 std::string(),
-                 dirty_file,
-                 internal::FileCache::FILE_OPERATION_COPY),
-      google_apis::test_util::CreateCopyResultCallback(&error));
-  content::RunAllTasksUntilIdle();
-  EXPECT_EQ(FILE_ERROR_OK, error);
-
-  // Record values passed to GetFileContentInitializedCallback().
-  FileError init_error;
-  base::FilePath init_path;
-  std::unique_ptr<ResourceEntry> init_entry;
-  base::FilePath file_path;
-  std::unique_ptr<ResourceEntry> entry;
-  base::Closure cancel_callback = operation_->EnsureFileDownloadedByPath(
-      file_in_root,
-      ClientContext(USER_INITIATED),
-      google_apis::test_util::CreateCopyResultCallback(
-          &init_error, &init_path, &init_entry),
-      google_apis::GetContentCallback(),
-      google_apis::test_util::CreateCopyResultCallback(
-          &error, &file_path, &entry));
-  content::RunAllTasksUntilIdle();
-
-  EXPECT_EQ(FILE_ERROR_OK, error);
-  // Check that the result of local modification is propagated.
-  EXPECT_EQ(static_cast<int64_t>(dirty_size), init_entry->file_info().size());
-  EXPECT_EQ(static_cast<int64_t>(dirty_size), entry->file_info().size());
-}
-
-TEST_F(DownloadOperationTest, EnsureFileDownloadedByPath_LocallyCreatedFile) {
-  // Add a new file with an empty resource ID.
-  base::FilePath file_path(FILE_PATH_LITERAL("drive/root/New File.txt"));
-  ResourceEntry parent;
-  ASSERT_EQ(FILE_ERROR_OK, GetLocalResourceEntry(file_path.DirName(), &parent));
-
-  ResourceEntry new_file;
-  new_file.set_title("New File.txt");
-  new_file.set_parent_local_id(parent.local_id());
-
-  FileError error = FILE_ERROR_FAILED;
-  std::string local_id;
-  base::PostTaskAndReplyWithResult(
-      blocking_task_runner(),
-      FROM_HERE,
-      base::Bind(&internal::ResourceMetadata::AddEntry,
-                 base::Unretained(metadata()),
-                 new_file,
-                 &local_id),
-      google_apis::test_util::CreateCopyResultCallback(&error));
-  content::RunAllTasksUntilIdle();
-  EXPECT_EQ(FILE_ERROR_OK, error);
-
-  // Empty cache file should be returned.
-  base::FilePath cache_file_path;
-  std::unique_ptr<ResourceEntry> entry;
-  operation_->EnsureFileDownloadedByPath(
-      file_path,
-      ClientContext(USER_INITIATED),
-      GetFileContentInitializedCallback(),
-      google_apis::GetContentCallback(),
-      google_apis::test_util::CreateCopyResultCallback(
-          &error, &cache_file_path, &entry));
-  content::RunAllTasksUntilIdle();
-  EXPECT_EQ(FILE_ERROR_OK, error);
-
-  int64_t cache_file_size = 0;
-  EXPECT_TRUE(base::GetFileSize(cache_file_path, &cache_file_size));
-  EXPECT_EQ(static_cast<int64_t>(0), cache_file_size);
-  ASSERT_TRUE(entry);
-  EXPECT_EQ(cache_file_size, entry->file_info().size());
-}
-
-TEST_F(DownloadOperationTest, CancelBeforeDownloadStarts) {
-  base::FilePath file_in_root(FILE_PATH_LITERAL("drive/root/File 1.txt"));
-  ResourceEntry src_entry;
-  ASSERT_EQ(FILE_ERROR_OK, GetLocalResourceEntry(file_in_root, &src_entry));
-
-  // Start operation.
-  FileError error = FILE_ERROR_OK;
-  base::FilePath file_path;
-  std::unique_ptr<ResourceEntry> entry;
-  base::Closure cancel_closure = operation_->EnsureFileDownloadedByLocalId(
-      GetLocalId(file_in_root),
-      ClientContext(USER_INITIATED),
-      GetFileContentInitializedCallback(),
-      google_apis::GetContentCallback(),
-      google_apis::test_util::CreateCopyResultCallback(
-          &error, &file_path, &entry));
-
-  // Cancel immediately.
-  ASSERT_FALSE(cancel_closure.is_null());
-  cancel_closure.Run();
-  content::RunAllTasksUntilIdle();
-
-  EXPECT_EQ(FILE_ERROR_ABORT, error);
-}
-
-}  // namespace file_system
-}  // namespace drive
diff --git a/components/drive/file_system/get_file_for_saving_operation_unittest.cc b/components/drive/file_system/get_file_for_saving_operation_unittest.cc
deleted file mode 100644
index d5118c8..0000000
--- a/components/drive/file_system/get_file_for_saving_operation_unittest.cc
+++ /dev/null
@@ -1,158 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "components/drive/chromeos/file_system/get_file_for_saving_operation.h"
-
-#include <stdint.h>
-
-#include <memory>
-
-#include "base/callback.h"
-#include "base/files/file_path.h"
-#include "base/files/file_util.h"
-#include "base/memory/ref_counted.h"
-#include "base/run_loop.h"
-#include "base/single_thread_task_runner.h"
-#include "base/task_runner_util.h"
-#include "components/drive/drive.pb.h"
-#include "components/drive/file_change.h"
-#include "components/drive/file_errors.h"
-#include "components/drive/file_system/operation_test_base.h"
-#include "components/drive/file_write_watcher.h"
-#include "components/drive/job_scheduler.h"
-#include "content/public/test/test_utils.h"
-#include "google_apis/drive/test_util.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace drive {
-namespace file_system {
-
-namespace {
-
-// If OnCacheFileUploadNeededByOperation is called, records the local ID and
-// calls |quit_closure|.
-class TestDelegate : public OperationDelegate {
- public:
-  void set_quit_closure(const base::Closure& quit_closure) {
-    quit_closure_ = quit_closure;
-  }
-
-  const std::string& updated_local_id() const {
-    return updated_local_id_;
-  }
-
-  // OperationDelegate overrides.
-  void OnEntryUpdatedByOperation(const ClientContext& /* context */,
-                                 const std::string& local_id) override {
-    updated_local_id_ = local_id;
-    if (!quit_closure_.is_null())
-      quit_closure_.Run();
-  }
-
- private:
-  std::string updated_local_id_;
-  base::Closure quit_closure_;
-};
-
-}  // namespace
-
-class GetFileForSavingOperationTest : public OperationTestBase {
- protected:
-  // FileWriteWatcher requires TYPE_IO message loop to run.
-  GetFileForSavingOperationTest()
-      : OperationTestBase(content::BrowserTaskEnvironment::IO_MAINLOOP) {}
-
-  void SetUp() override {
-    OperationTestBase::SetUp();
-
-    operation_ = std::make_unique<GetFileForSavingOperation>(
-        logger(), blocking_task_runner(), &delegate_, scheduler(), metadata(),
-        cache(), temp_dir());
-    operation_->file_write_watcher_for_testing()->DisableDelayForTesting();
-  }
-
-  TestDelegate delegate_;
-  std::unique_ptr<GetFileForSavingOperation> operation_;
-};
-
-TEST_F(GetFileForSavingOperationTest, GetFileForSaving_Exist) {
-  base::FilePath drive_path(FILE_PATH_LITERAL("drive/root/File 1.txt"));
-  ResourceEntry src_entry;
-  ASSERT_EQ(FILE_ERROR_OK, GetLocalResourceEntry(drive_path, &src_entry));
-
-  // Run the operation.
-  FileError error = FILE_ERROR_FAILED;
-  std::unique_ptr<ResourceEntry> entry;
-  base::FilePath local_path;
-  operation_->GetFileForSaving(
-      drive_path,
-      google_apis::test_util::CreateCopyResultCallback(
-          &error, &local_path, &entry));
-  content::RunAllTasksUntilIdle();
-
-  // Checks that the file is retrieved.
-  EXPECT_EQ(FILE_ERROR_OK, error);
-  ASSERT_TRUE(entry);
-  EXPECT_EQ(src_entry.resource_id(), entry->resource_id());
-
-  // Checks that it presents in cache and marked dirty.
-  EXPECT_TRUE(entry->file_specific_info().cache_state().is_present());
-  EXPECT_TRUE(entry->file_specific_info().cache_state().is_dirty());
-
-  // Write something to the cache and checks that the event is reported.
-  {
-    base::RunLoop run_loop;
-    delegate_.set_quit_closure(run_loop.QuitClosure());
-    google_apis::test_util::WriteStringToFile(local_path, "hello");
-    run_loop.Run();
-    EXPECT_EQ(GetLocalId(drive_path), delegate_.updated_local_id());
-  }
-}
-
-TEST_F(GetFileForSavingOperationTest, GetFileForSaving_NotExist) {
-  base::FilePath drive_path(FILE_PATH_LITERAL("drive/root/NotExist.txt"));
-  ResourceEntry src_entry;
-  ASSERT_EQ(FILE_ERROR_NOT_FOUND,
-            GetLocalResourceEntry(drive_path, &src_entry));
-
-  // Run the operation.
-  FileError error = FILE_ERROR_FAILED;
-  std::unique_ptr<ResourceEntry> entry;
-  base::FilePath local_path;
-  operation_->GetFileForSaving(
-      drive_path,
-      google_apis::test_util::CreateCopyResultCallback(
-          &error, &local_path, &entry));
-  content::RunAllTasksUntilIdle();
-
-  // Checks that the file is created and retrieved.
-  EXPECT_EQ(FILE_ERROR_OK, error);
-  EXPECT_EQ(FILE_ERROR_OK, GetLocalResourceEntry(drive_path, &src_entry));
-  int64_t size = -1;
-  EXPECT_TRUE(base::GetFileSize(local_path, &size));
-  EXPECT_EQ(0, size);
-}
-
-TEST_F(GetFileForSavingOperationTest, GetFileForSaving_Directory) {
-  base::FilePath drive_path(FILE_PATH_LITERAL("drive/root/Directory 1"));
-  ResourceEntry src_entry;
-  ASSERT_EQ(FILE_ERROR_OK, GetLocalResourceEntry(drive_path, &src_entry));
-  ASSERT_TRUE(src_entry.file_info().is_directory());
-
-  // Run the operation.
-  FileError error = FILE_ERROR_FAILED;
-  std::unique_ptr<ResourceEntry> entry;
-  base::FilePath local_path;
-  operation_->GetFileForSaving(
-      drive_path,
-      google_apis::test_util::CreateCopyResultCallback(
-          &error, &local_path, &entry));
-  content::RunAllTasksUntilIdle();
-
-  // Checks that an error is returned.
-  EXPECT_EQ(FILE_ERROR_EXISTS, error);
-}
-
-}  // namespace file_system
-}  // namespace drive
diff --git a/components/drive/file_system/move_operation_unittest.cc b/components/drive/file_system/move_operation_unittest.cc
deleted file mode 100644
index 5d605f3..0000000
--- a/components/drive/file_system/move_operation_unittest.cc
+++ /dev/null
@@ -1,142 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "components/drive/chromeos/file_system/move_operation.h"
-
-#include <memory>
-
-#include "components/drive/file_change.h"
-#include "components/drive/file_system/operation_test_base.h"
-#include "content/public/test/test_utils.h"
-#include "google_apis/drive/test_util.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace drive {
-namespace file_system {
-
-class MoveOperationTest : public OperationTestBase {
- protected:
-  void SetUp() override {
-   OperationTestBase::SetUp();
-   operation_ = std::make_unique<MoveOperation>(blocking_task_runner(),
-                                                delegate(), metadata());
-  }
-
-  std::unique_ptr<MoveOperation> operation_;
-};
-
-TEST_F(MoveOperationTest, MoveFileInSameDirectory) {
-  const base::FilePath src_path(
-      FILE_PATH_LITERAL("drive/root/Directory 1/SubDirectory File 1.txt"));
-  const base::FilePath dest_path(
-      FILE_PATH_LITERAL("drive/root/Directory 1/Test.log"));
-
-  ResourceEntry src_entry, dest_entry;
-  ASSERT_EQ(FILE_ERROR_OK, GetLocalResourceEntry(src_path, &src_entry));
-  ASSERT_EQ(FILE_ERROR_NOT_FOUND,
-            GetLocalResourceEntry(dest_path, &dest_entry));
-
-  FileError error = FILE_ERROR_FAILED;
-  operation_->Move(src_path,
-                   dest_path,
-                   google_apis::test_util::CreateCopyResultCallback(&error));
-  content::RunAllTasksUntilIdle();
-  EXPECT_EQ(FILE_ERROR_OK, error);
-
-  EXPECT_EQ(FILE_ERROR_OK, GetLocalResourceEntry(dest_path, &dest_entry));
-  EXPECT_EQ(src_entry.local_id(), dest_entry.local_id());
-  EXPECT_EQ(ResourceEntry::DIRTY, dest_entry.metadata_edit_state());
-  EXPECT_EQ(FILE_ERROR_NOT_FOUND, GetLocalResourceEntry(src_path, &src_entry));
-
-  EXPECT_EQ(2U, delegate()->get_changed_files().size());
-  EXPECT_TRUE(delegate()->get_changed_files().count(src_path));
-  EXPECT_TRUE(delegate()->get_changed_files().count(dest_path));
-
-  EXPECT_EQ(1U, delegate()->updated_local_ids().size());
-  EXPECT_TRUE(delegate()->updated_local_ids().count(src_entry.local_id()));
-}
-
-TEST_F(MoveOperationTest, MoveFileFromRootToSubDirectory) {
-  base::FilePath src_path(FILE_PATH_LITERAL("drive/root/File 1.txt"));
-  base::FilePath dest_path(
-      FILE_PATH_LITERAL("drive/root/Directory 1/Test.log"));
-
-  ResourceEntry src_entry, dest_entry;
-  ASSERT_EQ(FILE_ERROR_OK, GetLocalResourceEntry(src_path, &src_entry));
-  ASSERT_EQ(FILE_ERROR_NOT_FOUND,
-            GetLocalResourceEntry(dest_path, &dest_entry));
-
-  FileError error = FILE_ERROR_FAILED;
-  operation_->Move(src_path,
-                   dest_path,
-                   google_apis::test_util::CreateCopyResultCallback(&error));
-  content::RunAllTasksUntilIdle();
-  EXPECT_EQ(FILE_ERROR_OK, error);
-
-  EXPECT_EQ(FILE_ERROR_OK, GetLocalResourceEntry(dest_path, &dest_entry));
-  EXPECT_EQ(src_entry.local_id(), dest_entry.local_id());
-  EXPECT_EQ(ResourceEntry::DIRTY, dest_entry.metadata_edit_state());
-  EXPECT_EQ(FILE_ERROR_NOT_FOUND, GetLocalResourceEntry(src_path, &src_entry));
-
-  EXPECT_EQ(2U, delegate()->get_changed_files().size());
-  EXPECT_TRUE(delegate()->get_changed_files().count(src_path));
-  EXPECT_TRUE(delegate()->get_changed_files().count(dest_path));
-
-  EXPECT_EQ(1U, delegate()->updated_local_ids().size());
-  EXPECT_TRUE(delegate()->updated_local_ids().count(src_entry.local_id()));
-}
-
-TEST_F(MoveOperationTest, MoveNotExistingFile) {
-  base::FilePath src_path(FILE_PATH_LITERAL("drive/root/Dummy file.txt"));
-  base::FilePath dest_path(FILE_PATH_LITERAL("drive/root/Test.log"));
-
-  FileError error = FILE_ERROR_OK;
-  operation_->Move(src_path,
-                   dest_path,
-                   google_apis::test_util::CreateCopyResultCallback(&error));
-  content::RunAllTasksUntilIdle();
-  EXPECT_EQ(FILE_ERROR_NOT_FOUND, error);
-
-  ResourceEntry entry;
-  EXPECT_EQ(FILE_ERROR_NOT_FOUND, GetLocalResourceEntry(src_path, &entry));
-  EXPECT_EQ(FILE_ERROR_NOT_FOUND, GetLocalResourceEntry(dest_path, &entry));
-}
-
-TEST_F(MoveOperationTest, MoveFileToNonExistingDirectory) {
-  base::FilePath src_path(FILE_PATH_LITERAL("drive/root/File 1.txt"));
-  base::FilePath dest_path(FILE_PATH_LITERAL("drive/root/Dummy/Test.log"));
-
-  FileError error = FILE_ERROR_OK;
-  operation_->Move(src_path,
-                   dest_path,
-                   google_apis::test_util::CreateCopyResultCallback(&error));
-  content::RunAllTasksUntilIdle();
-  EXPECT_EQ(FILE_ERROR_NOT_FOUND, error);
-
-  ResourceEntry entry;
-  EXPECT_EQ(FILE_ERROR_OK, GetLocalResourceEntry(src_path, &entry));
-  EXPECT_EQ(FILE_ERROR_NOT_FOUND, GetLocalResourceEntry(dest_path, &entry));
-}
-
-// Test the case where the parent of |dest_file_path| is a existing file,
-// not a directory.
-TEST_F(MoveOperationTest, MoveFileToInvalidPath) {
-  base::FilePath src_path(FILE_PATH_LITERAL("drive/root/File 1.txt"));
-  base::FilePath dest_path(
-      FILE_PATH_LITERAL("drive/root/Duplicate Name.txt/Test.log"));
-
-  FileError error = FILE_ERROR_OK;
-  operation_->Move(src_path,
-                   dest_path,
-                   google_apis::test_util::CreateCopyResultCallback(&error));
-  content::RunAllTasksUntilIdle();
-  EXPECT_EQ(FILE_ERROR_NOT_A_DIRECTORY, error);
-
-  ResourceEntry entry;
-  EXPECT_EQ(FILE_ERROR_OK, GetLocalResourceEntry(src_path, &entry));
-  EXPECT_EQ(FILE_ERROR_NOT_FOUND, GetLocalResourceEntry(dest_path, &entry));
-}
-
-}  // namespace file_system
-}  // namespace drive
diff --git a/components/drive/file_system/open_file_operation_unittest.cc b/components/drive/file_system/open_file_operation_unittest.cc
deleted file mode 100644
index ae99c316c..0000000
--- a/components/drive/file_system/open_file_operation_unittest.cc
+++ /dev/null
@@ -1,259 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "components/drive/chromeos/file_system/open_file_operation.h"
-
-#include <stdint.h>
-
-#include <map>
-#include <memory>
-
-#include "base/files/file_path.h"
-#include "base/files/file_util.h"
-#include "base/task_runner_util.h"
-#include "components/drive/chromeos/file_cache.h"
-#include "components/drive/drive.pb.h"
-#include "components/drive/file_change.h"
-#include "components/drive/file_errors.h"
-#include "components/drive/file_system/operation_test_base.h"
-#include "content/public/test/test_utils.h"
-#include "google_apis/drive/test_util.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace drive {
-namespace file_system {
-
-class OpenFileOperationTest : public OperationTestBase {
- protected:
-  void SetUp() override {
-    OperationTestBase::SetUp();
-
-    operation_ = std::make_unique<OpenFileOperation>(
-        blocking_task_runner(), delegate(), scheduler(), metadata(), cache(),
-        temp_dir());
-  }
-
-  std::unique_ptr<OpenFileOperation> operation_;
-};
-
-TEST_F(OpenFileOperationTest, OpenExistingFile) {
-  const base::FilePath file_in_root(
-      FILE_PATH_LITERAL("drive/root/File 1.txt"));
-  ResourceEntry src_entry;
-  ASSERT_EQ(FILE_ERROR_OK, GetLocalResourceEntry(file_in_root, &src_entry));
-  const int64_t file_size = src_entry.file_info().size();
-
-  FileError error = FILE_ERROR_FAILED;
-  base::FilePath file_path;
-  base::Closure close_callback;
-  operation_->OpenFile(
-      file_in_root,
-      OPEN_FILE,
-      std::string(),  // mime_type
-      google_apis::test_util::CreateCopyResultCallback(
-          &error, &file_path, &close_callback));
-  content::RunAllTasksUntilIdle();
-
-  EXPECT_EQ(FILE_ERROR_OK, error);
-  ASSERT_TRUE(base::PathExists(file_path));
-  int64_t local_file_size;
-  ASSERT_TRUE(base::GetFileSize(file_path, &local_file_size));
-  EXPECT_EQ(file_size, local_file_size);
-
-  ASSERT_FALSE(close_callback.is_null());
-  close_callback.Run();
-  EXPECT_EQ(1U, delegate()->updated_local_ids().count(src_entry.local_id()));
-}
-
-TEST_F(OpenFileOperationTest, OpenNonExistingFile) {
-  const base::FilePath file_in_root(
-      FILE_PATH_LITERAL("drive/root/not-exist.txt"));
-
-  FileError error = FILE_ERROR_FAILED;
-  base::FilePath file_path;
-  base::Closure close_callback;
-  operation_->OpenFile(
-      file_in_root,
-      OPEN_FILE,
-      std::string(),  // mime_type
-      google_apis::test_util::CreateCopyResultCallback(
-          &error, &file_path, &close_callback));
-  content::RunAllTasksUntilIdle();
-  EXPECT_EQ(FILE_ERROR_NOT_FOUND, error);
-  EXPECT_TRUE(close_callback.is_null());
-}
-
-TEST_F(OpenFileOperationTest, CreateExistingFile) {
-  const base::FilePath file_in_root(
-      FILE_PATH_LITERAL("drive/root/File 1.txt"));
-  ResourceEntry src_entry;
-  ASSERT_EQ(FILE_ERROR_OK, GetLocalResourceEntry(file_in_root, &src_entry));
-
-  FileError error = FILE_ERROR_FAILED;
-  base::FilePath file_path;
-  base::Closure close_callback;
-  operation_->OpenFile(
-      file_in_root,
-      CREATE_FILE,
-      std::string(),  // mime_type
-      google_apis::test_util::CreateCopyResultCallback(
-          &error, &file_path, &close_callback));
-  content::RunAllTasksUntilIdle();
-
-  EXPECT_EQ(FILE_ERROR_EXISTS, error);
-  EXPECT_TRUE(close_callback.is_null());
-}
-
-TEST_F(OpenFileOperationTest, CreateNonExistingFile) {
-  const base::FilePath file_in_root(
-      FILE_PATH_LITERAL("drive/root/not-exist.txt"));
-
-  FileError error = FILE_ERROR_FAILED;
-  base::FilePath file_path;
-  base::Closure close_callback;
-  operation_->OpenFile(
-      file_in_root,
-      CREATE_FILE,
-      std::string(),  // mime_type
-      google_apis::test_util::CreateCopyResultCallback(
-          &error, &file_path, &close_callback));
-  content::RunAllTasksUntilIdle();
-
-  EXPECT_EQ(1U, delegate()->get_changed_files().size());
-  EXPECT_TRUE(delegate()->get_changed_files().count(file_in_root));
-
-  EXPECT_EQ(FILE_ERROR_OK, error);
-  ASSERT_TRUE(base::PathExists(file_path));
-  int64_t local_file_size;
-  ASSERT_TRUE(base::GetFileSize(file_path, &local_file_size));
-  EXPECT_EQ(0, local_file_size);  // Should be an empty file.
-
-  ASSERT_FALSE(close_callback.is_null());
-  close_callback.Run();
-  EXPECT_EQ(1U,
-            delegate()->updated_local_ids().count(GetLocalId(file_in_root)));
-}
-
-TEST_F(OpenFileOperationTest, OpenOrCreateExistingFile) {
-  const base::FilePath file_in_root(
-      FILE_PATH_LITERAL("drive/root/File 1.txt"));
-  ResourceEntry src_entry;
-  ASSERT_EQ(FILE_ERROR_OK, GetLocalResourceEntry(file_in_root, &src_entry));
-  const int64_t file_size = src_entry.file_info().size();
-
-  FileError error = FILE_ERROR_FAILED;
-  base::FilePath file_path;
-  base::Closure close_callback;
-  operation_->OpenFile(
-      file_in_root,
-      OPEN_OR_CREATE_FILE,
-      std::string(),  // mime_type
-      google_apis::test_util::CreateCopyResultCallback(
-          &error, &file_path, &close_callback));
-  content::RunAllTasksUntilIdle();
-
-  // Notified because 'available offline' status of the existing file changes.
-  EXPECT_EQ(1U, delegate()->get_changed_files().size());
-  EXPECT_TRUE(delegate()->get_changed_files().count(file_in_root));
-
-  EXPECT_EQ(FILE_ERROR_OK, error);
-  ASSERT_TRUE(base::PathExists(file_path));
-  int64_t local_file_size;
-  ASSERT_TRUE(base::GetFileSize(file_path, &local_file_size));
-  EXPECT_EQ(file_size, local_file_size);
-
-  ASSERT_FALSE(close_callback.is_null());
-  close_callback.Run();
-  EXPECT_EQ(1U, delegate()->updated_local_ids().count(src_entry.local_id()));
-
-  ResourceEntry result_entry;
-  EXPECT_EQ(FILE_ERROR_OK, GetLocalResourceEntry(file_in_root, &result_entry));
-  EXPECT_TRUE(result_entry.file_specific_info().cache_state().is_present());
-  EXPECT_TRUE(result_entry.file_specific_info().cache_state().is_dirty());
-}
-
-TEST_F(OpenFileOperationTest, OpenOrCreateNonExistingFile) {
-  const base::FilePath file_in_root(
-      FILE_PATH_LITERAL("drive/root/not-exist.txt"));
-
-  FileError error = FILE_ERROR_FAILED;
-  base::FilePath file_path;
-  base::Closure close_callback;
-  operation_->OpenFile(
-      file_in_root,
-      OPEN_OR_CREATE_FILE,
-      std::string(),  // mime_type
-      google_apis::test_util::CreateCopyResultCallback(
-          &error, &file_path, &close_callback));
-  content::RunAllTasksUntilIdle();
-
-  EXPECT_EQ(FILE_ERROR_OK, error);
-  ASSERT_TRUE(base::PathExists(file_path));
-  int64_t local_file_size;
-  ASSERT_TRUE(base::GetFileSize(file_path, &local_file_size));
-  EXPECT_EQ(0, local_file_size);  // Should be an empty file.
-
-  ASSERT_FALSE(close_callback.is_null());
-  close_callback.Run();
-  EXPECT_EQ(1U,
-            delegate()->updated_local_ids().count(GetLocalId(file_in_root)));
-}
-
-TEST_F(OpenFileOperationTest, OpenFileTwice) {
-  const base::FilePath file_in_root(
-      FILE_PATH_LITERAL("drive/root/File 1.txt"));
-  ResourceEntry src_entry;
-  ASSERT_EQ(FILE_ERROR_OK, GetLocalResourceEntry(file_in_root, &src_entry));
-  const int64_t file_size = src_entry.file_info().size();
-
-  FileError error = FILE_ERROR_FAILED;
-  base::FilePath file_path;
-  base::Closure close_callback;
-  operation_->OpenFile(
-      file_in_root,
-      OPEN_FILE,
-      std::string(),  // mime_type
-      google_apis::test_util::CreateCopyResultCallback(
-          &error, &file_path, &close_callback));
-  content::RunAllTasksUntilIdle();
-
-  EXPECT_EQ(FILE_ERROR_OK, error);
-  ASSERT_TRUE(base::PathExists(file_path));
-  int64_t local_file_size;
-  ASSERT_TRUE(base::GetFileSize(file_path, &local_file_size));
-  EXPECT_EQ(file_size, local_file_size);
-
-  // Open again.
-  error = FILE_ERROR_FAILED;
-  base::Closure close_callback2;
-  operation_->OpenFile(
-      file_in_root,
-      OPEN_FILE,
-      std::string(),  // mime_type
-      google_apis::test_util::CreateCopyResultCallback(
-          &error, &file_path, &close_callback2));
-  content::RunAllTasksUntilIdle();
-
-  EXPECT_EQ(FILE_ERROR_OK, error);
-  ASSERT_TRUE(base::PathExists(file_path));
-  ASSERT_TRUE(base::GetFileSize(file_path, &local_file_size));
-  EXPECT_EQ(file_size, local_file_size);
-
-  ASSERT_FALSE(close_callback.is_null());
-  ASSERT_FALSE(close_callback2.is_null());
-
-  close_callback.Run();
-
-  // There still remains a client opening the file, so it shouldn't be
-  // uploaded yet.
-  EXPECT_TRUE(delegate()->updated_local_ids().empty());
-
-  close_callback2.Run();
-
-  // Here, all the clients close the file, so it should be uploaded then.
-  EXPECT_EQ(1U, delegate()->updated_local_ids().count(src_entry.local_id()));
-}
-
-}  // namespace file_system
-}  // namespace drive
diff --git a/components/drive/file_system/operation_test_base.cc b/components/drive/file_system/operation_test_base.cc
deleted file mode 100644
index 23ba905..0000000
--- a/components/drive/file_system/operation_test_base.cc
+++ /dev/null
@@ -1,196 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "components/drive/file_system/operation_test_base.h"
-
-#include <memory>
-
-#include "base/bind.h"
-#include "base/task/post_task.h"
-#include "components/drive/chromeos/about_resource_loader.h"
-#include "components/drive/chromeos/about_resource_root_folder_id_loader.h"
-#include "components/drive/chromeos/change_list_loader.h"
-#include "components/drive/chromeos/fake_free_disk_space_getter.h"
-#include "components/drive/chromeos/file_cache.h"
-#include "components/drive/chromeos/file_system/operation_delegate.h"
-#include "components/drive/chromeos/loader_controller.h"
-#include "components/drive/chromeos/resource_metadata.h"
-#include "components/drive/chromeos/start_page_token_loader.h"
-#include "components/drive/event_logger.h"
-#include "components/drive/file_change.h"
-#include "components/drive/file_system_core_util.h"
-#include "components/drive/job_scheduler.h"
-#include "components/drive/service/fake_drive_service.h"
-#include "components/drive/service/test_util.h"
-#include "components/prefs/testing_pref_service.h"
-#include "content/public/test/test_utils.h"
-#include "google_apis/drive/test_util.h"
-#include "mojo/public/cpp/bindings/pending_remote.h"
-#include "services/network/test/test_network_connection_tracker.h"
-
-namespace drive {
-namespace file_system {
-
-OperationTestBase::LoggingDelegate::LoggingDelegate() = default;
-
-OperationTestBase::LoggingDelegate::~LoggingDelegate() = default;
-
-void OperationTestBase::LoggingDelegate::OnFileChangedByOperation(
-    const FileChange& changed_files) {
-  changed_files_.Apply(changed_files);
-}
-
-void OperationTestBase::LoggingDelegate::OnEntryUpdatedByOperation(
-    const ClientContext& /* client_context */,
-    const std::string& local_id) {
-  updated_local_ids_.insert(local_id);
-}
-
-void OperationTestBase::LoggingDelegate::OnDriveSyncError(
-    DriveSyncErrorType type, const std::string& local_id) {
-  drive_sync_errors_.push_back(type);
-}
-
-bool OperationTestBase::LoggingDelegate::WaitForSyncComplete(
-    const std::string& local_id,
-    const FileOperationCallback& callback) {
-  return wait_for_sync_complete_handler_.is_null() ?
-      false : wait_for_sync_complete_handler_.Run(local_id, callback);
-}
-
-OperationTestBase::~OperationTestBase() = default;
-
-void OperationTestBase::SetUp() {
-  blocking_task_runner_ =
-      base::CreateSequencedTaskRunner({base::ThreadPool(), base::MayBlock()});
-
-  pref_service_ = std::make_unique<TestingPrefServiceSimple>();
-  test_util::RegisterDrivePrefs(pref_service_->registry());
-
-  ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
-
-  logger_ = std::make_unique<EventLogger>();
-
-  fake_drive_service_ = std::make_unique<FakeDriveService>();
-  ASSERT_TRUE(test_util::SetUpTestEntries(fake_drive_service_.get()));
-
-  network::TestNetworkConnectionTracker::GetInstance()->SetConnectionType(
-      network::mojom::ConnectionType::CONNECTION_WIFI);
-  scheduler_ = std::make_unique<JobScheduler>(
-      pref_service_.get(), logger_.get(), fake_drive_service_.get(),
-      network::TestNetworkConnectionTracker::GetInstance(),
-      blocking_task_runner_.get(), mojo::NullRemote());
-
-  metadata_storage_.reset(new internal::ResourceMetadataStorage(
-      temp_dir_.GetPath(), blocking_task_runner_.get()));
-  bool success = false;
-  base::PostTaskAndReplyWithResult(
-      blocking_task_runner_.get(),
-      FROM_HERE,
-      base::Bind(&internal::ResourceMetadataStorage::Initialize,
-                 base::Unretained(metadata_storage_.get())),
-      google_apis::test_util::CreateCopyResultCallback(&success));
-  content::RunAllTasksUntilIdle();
-  ASSERT_TRUE(success);
-
-  fake_free_disk_space_getter_ = std::make_unique<FakeFreeDiskSpaceGetter>();
-  cache_.reset(new internal::FileCache(
-      metadata_storage_.get(), temp_dir_.GetPath(), blocking_task_runner_.get(),
-      fake_free_disk_space_getter_.get()));
-  success = false;
-  base::PostTaskAndReplyWithResult(
-      blocking_task_runner_.get(),
-      FROM_HERE,
-      base::Bind(&internal::FileCache::Initialize,
-                 base::Unretained(cache_.get())),
-      google_apis::test_util::CreateCopyResultCallback(&success));
-  content::RunAllTasksUntilIdle();
-  ASSERT_TRUE(success);
-
-  metadata_.reset(new internal::ResourceMetadata(metadata_storage_.get(),
-                                                 cache_.get(),
-                                                 blocking_task_runner_));
-
-  FileError error = FILE_ERROR_FAILED;
-  base::PostTaskAndReplyWithResult(
-      blocking_task_runner_.get(),
-      FROM_HERE,
-      base::Bind(&internal::ResourceMetadata::Initialize,
-                 base::Unretained(metadata_.get())),
-      google_apis::test_util::CreateCopyResultCallback(&error));
-  content::RunAllTasksUntilIdle();
-  ASSERT_EQ(FILE_ERROR_OK, error);
-
-  // Makes sure the FakeDriveService's content is loaded to the metadata_.
-  about_resource_loader_ =
-      std::make_unique<internal::AboutResourceLoader>(scheduler_.get());
-  root_folder_id_loader_ =
-      std::make_unique<internal::AboutResourceRootFolderIdLoader>(
-          about_resource_loader_.get());
-  start_page_token_loader_ = std::make_unique<internal::StartPageTokenLoader>(
-      drive::util::kTeamDriveIdDefaultCorpus, scheduler_.get());
-  loader_controller_ = std::make_unique<internal::LoaderController>();
-  change_list_loader_ = std::make_unique<internal::ChangeListLoader>(
-      logger_.get(), blocking_task_runner_.get(), metadata_.get(),
-      scheduler_.get(), root_folder_id_loader_.get(),
-      start_page_token_loader_.get(), loader_controller_.get(),
-      util::kTeamDriveIdDefaultCorpus, util::GetDriveMyDriveRootPath());
-  change_list_loader_->LoadIfNeeded(
-      google_apis::test_util::CreateCopyResultCallback(&error));
-  content::RunAllTasksUntilIdle();
-  ASSERT_EQ(FILE_ERROR_OK, error);
-}
-
-FileError OperationTestBase::GetLocalResourceEntry(const base::FilePath& path,
-                                                   ResourceEntry* entry) {
-  FileError error = FILE_ERROR_FAILED;
-  base::PostTaskAndReplyWithResult(
-      blocking_task_runner(), FROM_HERE,
-      base::Bind(&internal::ResourceMetadata::GetResourceEntryByPath,
-                 base::Unretained(metadata()), path, entry),
-      google_apis::test_util::CreateCopyResultCallback(&error));
-  content::RunAllTasksUntilIdle();
-  return error;
-}
-
-FileError OperationTestBase::GetLocalResourceEntryById(
-    const std::string& local_id,
-    ResourceEntry* entry) {
-  FileError error = FILE_ERROR_FAILED;
-  base::PostTaskAndReplyWithResult(
-      blocking_task_runner(), FROM_HERE,
-      base::Bind(&internal::ResourceMetadata::GetResourceEntryById,
-                 base::Unretained(metadata()), local_id, entry),
-      google_apis::test_util::CreateCopyResultCallback(&error));
-  content::RunAllTasksUntilIdle();
-  return error;
-}
-
-std::string OperationTestBase::GetLocalId(const base::FilePath& path) {
-  std::string local_id;
-  FileError error = FILE_ERROR_FAILED;
-  base::PostTaskAndReplyWithResult(
-      blocking_task_runner(), FROM_HERE,
-      base::Bind(&internal::ResourceMetadata::GetIdByPath,
-                 base::Unretained(metadata()), path, &local_id),
-      google_apis::test_util::CreateCopyResultCallback(&error));
-  content::RunAllTasksUntilIdle();
-  EXPECT_EQ(FILE_ERROR_OK, error) << path.value();
-  return local_id;
-}
-
-FileError OperationTestBase::CheckForUpdates() {
-  FileError error = FILE_ERROR_FAILED;
-  change_list_loader_->CheckForUpdates(
-      google_apis::test_util::CreateCopyResultCallback(&error));
-  content::RunAllTasksUntilIdle();
-  return error;
-}
-
-OperationTestBase::OperationTestBase(
-    std::unique_ptr<content::BrowserTaskEnvironment> task_environment)
-    : task_environment_(std::move(task_environment)) {}
-
-}  // namespace file_system
-}  // namespace drive
diff --git a/components/drive/file_system/operation_test_base.h b/components/drive/file_system/operation_test_base.h
deleted file mode 100644
index 1a6c6676..0000000
--- a/components/drive/file_system/operation_test_base.h
+++ /dev/null
@@ -1,180 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef COMPONENTS_DRIVE_FILE_SYSTEM_OPERATION_TEST_BASE_H_
-#define COMPONENTS_DRIVE_FILE_SYSTEM_OPERATION_TEST_BASE_H_
-
-#include <set>
-
-#include "base/files/scoped_temp_dir.h"
-#include "components/drive/chromeos/drive_test_util.h"
-#include "components/drive/chromeos/file_system/operation_delegate.h"
-#include "components/drive/drive.pb.h"
-#include "components/drive/file_change.h"
-#include "components/drive/file_errors.h"
-#include "content/public/test/browser_task_environment.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-class TestingPrefServiceSimple;
-
-namespace base {
-class SequencedTaskRunner;
-}  // namespace base
-
-namespace drive {
-struct ClientContext;
-class EventLogger;
-class FakeDriveService;
-class FakeFreeDiskSpaceGetter;
-class JobScheduler;
-
-namespace internal {
-class AboutResourceLoader;
-class AboutResourceRootFolderIdLoader;
-class ChangeListLoader;
-class FileCache;
-class LoaderController;
-class ResourceMetadata;
-class ResourceMetadataStorage;
-class StartPageTokenLoader;
-}  // namespace internal
-
-namespace file_system {
-
-// Base fixture class for testing Drive file system operations. It sets up the
-// basic set of Drive internal classes (ResourceMetadata, Cache, etc) on top of
-// FakeDriveService for testing.
-class OperationTestBase : public testing::Test {
- protected:
-  // OperationDelegate that records all the events.
-  class LoggingDelegate : public OperationDelegate {
-   public:
-    typedef base::Callback<bool(
-        const std::string& local_id,
-        const FileOperationCallback& callback)> WaitForSyncCompleteHandler;
-
-    LoggingDelegate();
-    ~LoggingDelegate();
-
-    // OperationDelegate overrides.
-    void OnFileChangedByOperation(const FileChange& changed_files) override;
-    void OnEntryUpdatedByOperation(const ClientContext& context,
-                                   const std::string& local_id) override;
-    void OnDriveSyncError(DriveSyncErrorType type,
-                          const std::string& local_id) override;
-    bool WaitForSyncComplete(const std::string& local_id,
-                             const FileOperationCallback& callback) override;
-
-    // Gets the set of changed paths.
-    const FileChange& get_changed_files() { return changed_files_; }
-
-    // Gets the set of updated local IDs.
-    const std::set<std::string>& updated_local_ids() const {
-      return updated_local_ids_;
-    }
-
-    // Gets the list of drive sync errors.
-    const std::vector<DriveSyncErrorType>& drive_sync_errors() const {
-      return drive_sync_errors_;
-    }
-
-    // Sets the callback used to handle WaitForSyncComplete() method calls.
-    void set_wait_for_sync_complete_handler(
-        const WaitForSyncCompleteHandler& wait_for_sync_complete_handler) {
-      wait_for_sync_complete_handler_ = wait_for_sync_complete_handler;
-    }
-
-   private:
-    FileChange changed_files_;
-    std::set<std::string> updated_local_ids_;
-    std::vector<DriveSyncErrorType> drive_sync_errors_;
-    WaitForSyncCompleteHandler wait_for_sync_complete_handler_;
-  };
-
-  template <typename... Args>
-  OperationTestBase(Args... args)
-      : OperationTestBase(
-            std::make_unique<content::BrowserTaskEnvironment>(args...)) {}
-
-  ~OperationTestBase() override;
-
-  // testing::Test overrides.
-  void SetUp() override;
-
-  // Returns the path of the temporary directory for putting test files.
-  base::FilePath temp_dir() const { return temp_dir_.GetPath(); }
-
-  // Synchronously gets the resource entry corresponding to the path from local
-  // ResourceMetadta.
-  FileError GetLocalResourceEntry(const base::FilePath& path,
-                                  ResourceEntry* entry);
-
-  // Synchronously gets the resource entry corresponding to the ID from local
-  // ResourceMetadta.
-  FileError GetLocalResourceEntryById(const std::string& local_id,
-                                      ResourceEntry* entry);
-
-  // Gets the local ID of the entry specified by the path.
-  std::string GetLocalId(const base::FilePath& path);
-
-  // Synchronously updates |metadata_| by fetching the change feed from the
-  // |fake_service_|.
-  FileError CheckForUpdates();
-
-  // Accessors for the components.
-  FakeDriveService* fake_service() {
-    return fake_drive_service_.get();
-  }
-  EventLogger* logger() { return logger_.get(); }
-  LoggingDelegate* delegate() { return &delegate_; }
-  JobScheduler* scheduler() { return scheduler_.get(); }
-  base::SequencedTaskRunner* blocking_task_runner() {
-    return blocking_task_runner_.get();
-  }
-  FakeFreeDiskSpaceGetter* fake_free_disk_space_getter() {
-    return fake_free_disk_space_getter_.get();
-  }
-  internal::FileCache* cache() { return cache_.get(); }
-  internal::ResourceMetadata* metadata() { return metadata_.get(); }
-  internal::LoaderController* loader_controller() {
-    return loader_controller_.get();
-  }
-  internal::ChangeListLoader* change_list_loader() {
-    return change_list_loader_.get();
-  }
-
- private:
-  // The template constructor has to be in the header but it delegates to this
-  // constructor to initialize all other members out-of-line.
-  explicit OperationTestBase(
-      std::unique_ptr<content::BrowserTaskEnvironment> task_environment);
-
-  std::unique_ptr<content::BrowserTaskEnvironment> task_environment_;
-  scoped_refptr<base::SequencedTaskRunner> blocking_task_runner_;
-  std::unique_ptr<TestingPrefServiceSimple> pref_service_;
-  base::ScopedTempDir temp_dir_;
-
-  LoggingDelegate delegate_;
-  std::unique_ptr<EventLogger> logger_;
-  std::unique_ptr<FakeDriveService> fake_drive_service_;
-  std::unique_ptr<JobScheduler> scheduler_;
-  std::unique_ptr<internal::ResourceMetadataStorage,
-                  test_util::DestroyHelperForTests>
-      metadata_storage_;
-  std::unique_ptr<FakeFreeDiskSpaceGetter> fake_free_disk_space_getter_;
-  std::unique_ptr<internal::FileCache, test_util::DestroyHelperForTests> cache_;
-  std::unique_ptr<internal::ResourceMetadata, test_util::DestroyHelperForTests>
-      metadata_;
-  std::unique_ptr<internal::AboutResourceLoader> about_resource_loader_;
-  std::unique_ptr<internal::StartPageTokenLoader> start_page_token_loader_;
-  std::unique_ptr<internal::LoaderController> loader_controller_;
-  std::unique_ptr<internal::ChangeListLoader> change_list_loader_;
-  std::unique_ptr<internal::AboutResourceRootFolderIdLoader>
-      root_folder_id_loader_;
-};
-
-}  // namespace file_system
-}  // namespace drive
-
-#endif  // COMPONENTS_DRIVE_FILE_SYSTEM_OPERATION_TEST_BASE_H_
diff --git a/components/drive/file_system/remove_operation_unittest.cc b/components/drive/file_system/remove_operation_unittest.cc
deleted file mode 100644
index c0802cb..0000000
--- a/components/drive/file_system/remove_operation_unittest.cc
+++ /dev/null
@@ -1,132 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "components/drive/chromeos/file_system/remove_operation.h"
-
-#include "components/drive/file_change.h"
-#include "components/drive/file_system/operation_test_base.h"
-#include "components/drive/file_system_core_util.h"
-#include "content/public/test/test_utils.h"
-#include "google_apis/drive/test_util.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace drive {
-namespace file_system {
-
-typedef OperationTestBase RemoveOperationTest;
-
-TEST_F(RemoveOperationTest, RemoveFile) {
-  RemoveOperation operation(blocking_task_runner(), delegate(), metadata(),
-                            cache());
-
-  base::FilePath nonexisting_file(
-      FILE_PATH_LITERAL("drive/root/Dummy file.txt"));
-  base::FilePath file_in_root(FILE_PATH_LITERAL("drive/root/File 1.txt"));
-  base::FilePath file_in_subdir(
-      FILE_PATH_LITERAL("drive/root/Directory 1/SubDirectory File 1.txt"));
-
-  // Remove a file in root.
-  ResourceEntry entry;
-  FileError error = FILE_ERROR_FAILED;
-  ASSERT_EQ(FILE_ERROR_OK, GetLocalResourceEntry(file_in_root, &entry));
-  operation.Remove(file_in_root,
-                   false,  // is_recursive
-                   google_apis::test_util::CreateCopyResultCallback(&error));
-  content::RunAllTasksUntilIdle();
-  EXPECT_EQ(FILE_ERROR_OK, error);
-  EXPECT_EQ(FILE_ERROR_NOT_FOUND, GetLocalResourceEntry(file_in_root, &entry));
-
-  const std::string id_file_in_root = entry.local_id();
-  EXPECT_EQ(FILE_ERROR_OK, GetLocalResourceEntryById(id_file_in_root, &entry));
-  EXPECT_EQ(util::kDriveTrashDirLocalId, entry.parent_local_id());
-
-  // Remove a file in subdirectory.
-  error = FILE_ERROR_FAILED;
-  ASSERT_EQ(FILE_ERROR_OK, GetLocalResourceEntry(file_in_subdir, &entry));
-  const std::string resource_id = entry.resource_id();
-
-  operation.Remove(file_in_subdir,
-                   false,  // is_recursive
-                   google_apis::test_util::CreateCopyResultCallback(&error));
-  content::RunAllTasksUntilIdle();
-  EXPECT_EQ(FILE_ERROR_OK, error);
-  EXPECT_EQ(FILE_ERROR_NOT_FOUND,
-            GetLocalResourceEntry(file_in_subdir, &entry));
-
-  const std::string id_file_in_subdir = entry.local_id();
-  EXPECT_EQ(FILE_ERROR_OK,
-            GetLocalResourceEntryById(id_file_in_subdir, &entry));
-  EXPECT_EQ(util::kDriveTrashDirLocalId, entry.parent_local_id());
-
-  // Try removing non-existing file.
-  error = FILE_ERROR_FAILED;
-  ASSERT_EQ(FILE_ERROR_NOT_FOUND,
-            GetLocalResourceEntry(nonexisting_file, &entry));
-  operation.Remove(nonexisting_file,
-                   false,  // is_recursive
-                   google_apis::test_util::CreateCopyResultCallback(&error));
-  content::RunAllTasksUntilIdle();
-  EXPECT_EQ(FILE_ERROR_NOT_FOUND, error);
-
-  // Verify delegate notifications.
-  EXPECT_EQ(2U, delegate()->get_changed_files().size());
-  EXPECT_TRUE(delegate()->get_changed_files().count(file_in_root));
-  EXPECT_TRUE(delegate()->get_changed_files().count(file_in_subdir));
-
-  EXPECT_EQ(2U, delegate()->updated_local_ids().size());
-  EXPECT_TRUE(delegate()->updated_local_ids().count(id_file_in_root));
-  EXPECT_TRUE(delegate()->updated_local_ids().count(id_file_in_subdir));
-}
-
-TEST_F(RemoveOperationTest, RemoveDirectory) {
-  RemoveOperation operation(blocking_task_runner(), delegate(), metadata(),
-                            cache());
-
-  base::FilePath empty_dir(FILE_PATH_LITERAL(
-      "drive/root/Directory 1/Sub Directory Folder/Sub Sub Directory Folder"));
-  base::FilePath non_empty_dir(FILE_PATH_LITERAL(
-      "drive/root/Directory 1"));
-  base::FilePath file_in_non_empty_dir(FILE_PATH_LITERAL(
-      "drive/root/Directory 1/SubDirectory File 1.txt"));
-
-  // Empty directory can be removed even with is_recursive = false.
-  FileError error = FILE_ERROR_FAILED;
-  ResourceEntry entry;
-  operation.Remove(empty_dir,
-                   false,  // is_recursive
-                   google_apis::test_util::CreateCopyResultCallback(&error));
-  content::RunAllTasksUntilIdle();
-  EXPECT_EQ(FILE_ERROR_OK, error);
-  EXPECT_EQ(FILE_ERROR_NOT_FOUND,
-            GetLocalResourceEntry(empty_dir, &entry));
-
-  // Non-empty directory, cannot.
-  error = FILE_ERROR_FAILED;
-  ASSERT_EQ(FILE_ERROR_OK, GetLocalResourceEntry(non_empty_dir, &entry));
-  operation.Remove(non_empty_dir,
-                   false,  // is_recursive
-                   google_apis::test_util::CreateCopyResultCallback(&error));
-  content::RunAllTasksUntilIdle();
-  EXPECT_EQ(FILE_ERROR_NOT_EMPTY, error);
-  EXPECT_EQ(FILE_ERROR_OK,
-            GetLocalResourceEntry(non_empty_dir, &entry));
-
-  // With is_recursive = true, it can be deleted, however. Descendant entries
-  // are removed together.
-  error = FILE_ERROR_FAILED;
-  ASSERT_EQ(FILE_ERROR_OK,
-            GetLocalResourceEntry(file_in_non_empty_dir, &entry));
-  operation.Remove(non_empty_dir,
-                   true,  // is_recursive
-                   google_apis::test_util::CreateCopyResultCallback(&error));
-  content::RunAllTasksUntilIdle();
-  EXPECT_EQ(FILE_ERROR_OK, error);
-  EXPECT_EQ(FILE_ERROR_NOT_FOUND,
-            GetLocalResourceEntry(non_empty_dir, &entry));
-  EXPECT_EQ(FILE_ERROR_NOT_FOUND,
-            GetLocalResourceEntry(file_in_non_empty_dir, &entry));
-}
-
-}  // namespace file_system
-}  // namespace drive
diff --git a/components/drive/file_system/search_operation_unittest.cc b/components/drive/file_system/search_operation_unittest.cc
deleted file mode 100644
index 28c1bb7..0000000
--- a/components/drive/file_system/search_operation_unittest.cc
+++ /dev/null
@@ -1,160 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "components/drive/chromeos/file_system/search_operation.h"
-
-#include <stddef.h>
-
-#include "base/callback_helpers.h"
-#include "components/drive/chromeos/loader_controller.h"
-#include "components/drive/file_system/operation_test_base.h"
-#include "components/drive/service/fake_drive_service.h"
-#include "content/public/test/test_utils.h"
-#include "google_apis/drive/drive_api_parser.h"
-#include "google_apis/drive/test_util.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace drive {
-namespace file_system {
-
-typedef OperationTestBase SearchOperationTest;
-
-TEST_F(SearchOperationTest, ContentSearch) {
-  SearchOperation operation(blocking_task_runner(), scheduler(), metadata(),
-                            loader_controller());
-
-  std::set<std::string> expected_results;
-  expected_results.insert(
-      "drive/root/Directory 1/Sub Directory Folder/Sub Sub Directory Folder");
-  expected_results.insert("drive/root/Directory 1/Sub Directory Folder");
-  expected_results.insert("drive/root/Directory 1/SubDirectory File 1.txt");
-  expected_results.insert("drive/root/Directory 1");
-  expected_results.insert("drive/root/Directory 2 excludeDir-test");
-
-  FileError error = FILE_ERROR_FAILED;
-  GURL next_link;
-  std::unique_ptr<std::vector<SearchResultInfo>> results;
-
-  operation.Search("Directory", GURL(),
-                   google_apis::test_util::CreateCopyResultCallback(
-                       &error, &next_link, &results));
-  content::RunAllTasksUntilIdle();
-
-  EXPECT_EQ(FILE_ERROR_OK, error);
-  EXPECT_TRUE(next_link.is_empty());
-  EXPECT_EQ(expected_results.size(), results->size());
-  for (size_t i = 0; i < results->size(); i++) {
-    EXPECT_TRUE(expected_results.count(results->at(i).path.AsUTF8Unsafe()))
-        << results->at(i).path.AsUTF8Unsafe();
-  }
-}
-
-TEST_F(SearchOperationTest, ContentSearchWithNewEntry) {
-  SearchOperation operation(blocking_task_runner(), scheduler(), metadata(),
-                            loader_controller());
-
-  // Create a new directory in the drive service.
-  google_apis::DriveApiErrorCode status = google_apis::DRIVE_OTHER_ERROR;
-  std::unique_ptr<google_apis::FileResource> server_entry;
-  fake_service()->AddNewDirectory(
-      fake_service()->GetRootResourceId(), "New Directory 1!",
-      AddNewDirectoryOptions(),
-      google_apis::test_util::CreateCopyResultCallback(&status, &server_entry));
-  content::RunAllTasksUntilIdle();
-  ASSERT_EQ(google_apis::HTTP_CREATED, status);
-
-  // As the result of the first Search(), only entries in the current file
-  // system snapshot are expected to be returned in the "right" path. New
-  // entries like "New Directory 1!" is temporarily added to "drive/other".
-  std::set<std::string> expected_results;
-  expected_results.insert("drive/root/Directory 1");
-  expected_results.insert("drive/other/New Directory 1!");
-
-  FileError error = FILE_ERROR_FAILED;
-  GURL next_link;
-  std::unique_ptr<std::vector<SearchResultInfo>> results;
-
-  operation.Search("\"Directory 1\"", GURL(),
-                   google_apis::test_util::CreateCopyResultCallback(
-                       &error, &next_link, &results));
-  content::RunAllTasksUntilIdle();
-
-  EXPECT_EQ(FILE_ERROR_OK, error);
-  EXPECT_TRUE(next_link.is_empty());
-  ASSERT_EQ(expected_results.size(), results->size());
-  for (size_t i = 0; i < results->size(); i++) {
-    EXPECT_TRUE(expected_results.count(results->at(i).path.AsUTF8Unsafe()))
-        << results->at(i).path.AsUTF8Unsafe();
-  }
-
-  // Load the change from FakeDriveService.
-  ASSERT_EQ(FILE_ERROR_OK, CheckForUpdates());
-
-  // Now the new entry must be reported to be in the right directory.
-  expected_results.clear();
-  expected_results.insert("drive/root/Directory 1");
-  expected_results.insert("drive/root/New Directory 1!");
-  error = FILE_ERROR_FAILED;
-  operation.Search("\"Directory 1\"", GURL(),
-                   google_apis::test_util::CreateCopyResultCallback(
-                       &error, &next_link, &results));
-  content::RunAllTasksUntilIdle();
-
-  EXPECT_EQ(FILE_ERROR_OK, error);
-  EXPECT_TRUE(next_link.is_empty());
-  ASSERT_EQ(expected_results.size(), results->size());
-  for (size_t i = 0; i < results->size(); i++) {
-    EXPECT_TRUE(expected_results.count(results->at(i).path.AsUTF8Unsafe()))
-        << results->at(i).path.AsUTF8Unsafe();
-  }
-}
-
-TEST_F(SearchOperationTest, ContentSearchEmptyResult) {
-  SearchOperation operation(blocking_task_runner(), scheduler(), metadata(),
-                            loader_controller());
-
-  FileError error = FILE_ERROR_FAILED;
-  GURL next_link;
-  std::unique_ptr<std::vector<SearchResultInfo>> results;
-
-  operation.Search("\"no-match query\"", GURL(),
-                   google_apis::test_util::CreateCopyResultCallback(
-                       &error, &next_link, &results));
-  content::RunAllTasksUntilIdle();
-
-  EXPECT_EQ(FILE_ERROR_OK, error);
-  EXPECT_TRUE(next_link.is_empty());
-  EXPECT_EQ(0U, results->size());
-}
-
-TEST_F(SearchOperationTest, Lock) {
-  SearchOperation operation(blocking_task_runner(), scheduler(), metadata(),
-                            loader_controller());
-
-  // Lock.
-  std::unique_ptr<base::ScopedClosureRunner> lock =
-      loader_controller()->GetLock();
-
-  // Search does not return the result as long as lock is alive.
-  FileError error = FILE_ERROR_FAILED;
-  GURL next_link;
-  std::unique_ptr<std::vector<SearchResultInfo>> results;
-
-  operation.Search("\"Directory 1\"", GURL(),
-                   google_apis::test_util::CreateCopyResultCallback(
-                       &error, &next_link, &results));
-  content::RunAllTasksUntilIdle();
-  EXPECT_EQ(FILE_ERROR_FAILED, error);
-  EXPECT_FALSE(results);
-
-  // Unlock, this should resume the pending search.
-  lock.reset();
-  content::RunAllTasksUntilIdle();
-  EXPECT_EQ(FILE_ERROR_OK, error);
-  ASSERT_TRUE(results);
-  EXPECT_EQ(1u, results->size());
-}
-
-}  // namespace file_system
-}  // namespace drive
diff --git a/components/drive/file_system/set_property_operation_unittest.cc b/components/drive/file_system/set_property_operation_unittest.cc
deleted file mode 100644
index d597d58..0000000
--- a/components/drive/file_system/set_property_operation_unittest.cc
+++ /dev/null
@@ -1,153 +0,0 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "components/drive/chromeos/file_system/set_property_operation.h"
-
-#include "base/files/file_path.h"
-#include "components/drive/drive.pb.h"
-#include "components/drive/file_errors.h"
-#include "components/drive/file_system/operation_test_base.h"
-#include "content/public/test/test_utils.h"
-#include "google_apis/drive/drive_api_requests.h"
-#include "google_apis/drive/test_util.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace drive {
-namespace file_system {
-namespace {
-
-const base::FilePath::CharType kTestPath[] =
-    FILE_PATH_LITERAL("drive/root/File 1.txt");
-const char kTestKey[] = "key";
-const char kTestValue[] = "value";
-const char kTestAnotherValue[] = "another-value";
-
-}  // namespace
-
-typedef OperationTestBase SetPropertyOperationTest;
-
-TEST_F(SetPropertyOperationTest, SetProperty) {
-  SetPropertyOperation operation(blocking_task_runner(), delegate(),
-                                 metadata());
-
-  const base::FilePath test_path(kTestPath);
-  FileError result = FILE_ERROR_FAILED;
-  operation.SetProperty(
-      test_path, google_apis::drive::Property::Visibility::VISIBILITY_PRIVATE,
-      kTestKey, kTestValue,
-      google_apis::test_util::CreateCopyResultCallback(&result));
-  content::RunAllTasksUntilIdle();
-  EXPECT_EQ(FILE_ERROR_OK, result);
-
-  ResourceEntry entry;
-  EXPECT_EQ(FILE_ERROR_OK, GetLocalResourceEntry(test_path, &entry));
-  EXPECT_EQ(ResourceEntry::DIRTY, entry.metadata_edit_state());
-  ASSERT_EQ(1, entry.new_properties().size());
-  const drive::Property property = entry.new_properties().Get(0);
-  EXPECT_EQ(Property_Visibility_PRIVATE, property.visibility());
-  EXPECT_EQ(kTestKey, property.key());
-  EXPECT_EQ(kTestValue, property.value());
-
-  EXPECT_EQ(0u, delegate()->get_changed_files().size());
-  EXPECT_FALSE(delegate()->get_changed_files().count(test_path));
-
-  EXPECT_EQ(1u, delegate()->updated_local_ids().size());
-  EXPECT_TRUE(delegate()->updated_local_ids().count(entry.local_id()));
-}
-
-TEST_F(SetPropertyOperationTest, SetProperty_Duplicate) {
-  SetPropertyOperation operation(blocking_task_runner(), delegate(),
-                                 metadata());
-
-  const base::FilePath test_path(kTestPath);
-  FileError result = FILE_ERROR_FAILED;
-  operation.SetProperty(
-      test_path, google_apis::drive::Property::Visibility::VISIBILITY_PRIVATE,
-      kTestKey, kTestValue,
-      google_apis::test_util::CreateCopyResultCallback(&result));
-  operation.SetProperty(
-      test_path, google_apis::drive::Property::Visibility::VISIBILITY_PRIVATE,
-      kTestKey, kTestValue,
-      google_apis::test_util::CreateCopyResultCallback(&result));
-  content::RunAllTasksUntilIdle();
-  EXPECT_EQ(FILE_ERROR_OK, result);
-
-  ResourceEntry entry;
-  EXPECT_EQ(FILE_ERROR_OK, GetLocalResourceEntry(test_path, &entry));
-  EXPECT_EQ(1, entry.new_properties().size());
-}
-
-TEST_F(SetPropertyOperationTest, SetProperty_Overwrite) {
-  SetPropertyOperation operation(blocking_task_runner(), delegate(),
-                                 metadata());
-
-  const base::FilePath test_path(kTestPath);
-  FileError result = FILE_ERROR_FAILED;
-  operation.SetProperty(
-      test_path, google_apis::drive::Property::Visibility::VISIBILITY_PUBLIC,
-      kTestKey, kTestValue,
-      google_apis::test_util::CreateCopyResultCallback(&result));
-  operation.SetProperty(
-      test_path, google_apis::drive::Property::Visibility::VISIBILITY_PUBLIC,
-      kTestKey, kTestAnotherValue,
-      google_apis::test_util::CreateCopyResultCallback(&result));
-  content::RunAllTasksUntilIdle();
-  EXPECT_EQ(FILE_ERROR_OK, result);
-
-  ResourceEntry entry;
-  EXPECT_EQ(FILE_ERROR_OK, GetLocalResourceEntry(test_path, &entry));
-  ASSERT_EQ(1, entry.new_properties().size());
-  const drive::Property property = entry.new_properties().Get(0);
-  EXPECT_EQ(Property_Visibility_PUBLIC, property.visibility());
-  EXPECT_EQ(kTestKey, property.key());
-  EXPECT_EQ(kTestAnotherValue, property.value());
-}
-
-TEST_F(SetPropertyOperationTest, SetProperty_DifferentVisibilities) {
-  SetPropertyOperation operation(blocking_task_runner(), delegate(),
-                                 metadata());
-
-  {
-    const base::FilePath test_path(kTestPath);
-    FileError result = FILE_ERROR_FAILED;
-    operation.SetProperty(
-        test_path, google_apis::drive::Property::Visibility::VISIBILITY_PRIVATE,
-        kTestKey, kTestValue,
-        google_apis::test_util::CreateCopyResultCallback(&result));
-    content::RunAllTasksUntilIdle();
-    EXPECT_EQ(FILE_ERROR_OK, result);
-
-    ResourceEntry entry;
-    EXPECT_EQ(FILE_ERROR_OK, GetLocalResourceEntry(test_path, &entry));
-    ASSERT_EQ(1, entry.new_properties().size());
-    const drive::Property property = entry.new_properties().Get(0);
-    EXPECT_EQ(Property_Visibility_PRIVATE, property.visibility());
-    EXPECT_EQ(kTestKey, property.key());
-    EXPECT_EQ(kTestValue, property.value());
-  }
-
-  // Insert another property with the same key, same value but different
-  // visibility.
-  {
-    const base::FilePath test_path(kTestPath);
-    FileError result = FILE_ERROR_FAILED;
-    operation.SetProperty(
-        test_path, google_apis::drive::Property::Visibility::VISIBILITY_PUBLIC,
-        kTestKey, kTestAnotherValue,
-        google_apis::test_util::CreateCopyResultCallback(&result));
-    content::RunAllTasksUntilIdle();
-    EXPECT_EQ(FILE_ERROR_OK, result);
-
-    ResourceEntry entry;
-    EXPECT_EQ(FILE_ERROR_OK, GetLocalResourceEntry(test_path, &entry));
-    ASSERT_EQ(2, entry.new_properties().size());
-    const drive::Property property = entry.new_properties().Get(1);
-    EXPECT_EQ(Property_Visibility_PUBLIC, property.visibility());
-    EXPECT_EQ(kTestKey, property.key());
-    EXPECT_EQ(kTestAnotherValue, property.value());
-  }
-}
-
-}  // namespace file_system
-}  // namespace drive
diff --git a/components/drive/file_system/touch_operation_unittest.cc b/components/drive/file_system/touch_operation_unittest.cc
deleted file mode 100644
index 3bb5bd83..0000000
--- a/components/drive/file_system/touch_operation_unittest.cc
+++ /dev/null
@@ -1,64 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "components/drive/chromeos/file_system/touch_operation.h"
-
-#include "base/files/file_path.h"
-#include "base/time/time.h"
-#include "components/drive/chromeos/resource_metadata.h"
-#include "components/drive/drive.pb.h"
-#include "components/drive/file_errors.h"
-#include "components/drive/file_system/operation_test_base.h"
-#include "google_apis/drive/test_util.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace drive {
-namespace file_system {
-
-typedef OperationTestBase TouchOperationTest;
-
-TEST_F(TouchOperationTest, TouchFile) {
-  TouchOperation operation(blocking_task_runner(),
-                           delegate(),
-                           metadata());
-
-  const base::FilePath kTestPath(FILE_PATH_LITERAL("drive/root/File 1.txt"));
-  const base::Time::Exploded kLastAccessTime = {
-    2012, 7, 0, 19, 15, 59, 13, 123
-  };
-  const base::Time::Exploded kLastModifiedTime = {
-    2013, 7, 0, 19, 15, 59, 13, 123
-  };
-
-  FileError error = FILE_ERROR_FAILED;
-  base::Time last_access_time_utc;
-  base::Time last_modified_time_utc;
-  EXPECT_TRUE(
-      base::Time::FromUTCExploded(kLastAccessTime, &last_access_time_utc));
-  EXPECT_TRUE(
-      base::Time::FromUTCExploded(kLastModifiedTime, &last_modified_time_utc));
-  operation.TouchFile(kTestPath, last_access_time_utc, last_modified_time_utc,
-                      google_apis::test_util::CreateCopyResultCallback(&error));
-  content::RunAllTasksUntilIdle();
-  EXPECT_EQ(FILE_ERROR_OK, error);
-
-  ResourceEntry entry;
-  EXPECT_EQ(FILE_ERROR_OK, GetLocalResourceEntry(kTestPath, &entry));
-  EXPECT_EQ(last_access_time_utc,
-            base::Time::FromInternalValue(entry.file_info().last_accessed()));
-  EXPECT_EQ(last_modified_time_utc,
-            base::Time::FromInternalValue(entry.file_info().last_modified()));
-  EXPECT_EQ(last_modified_time_utc,
-            base::Time::FromInternalValue(entry.last_modified_by_me()));
-  EXPECT_EQ(ResourceEntry::DIRTY, entry.metadata_edit_state());
-
-  EXPECT_EQ(1U, delegate()->get_changed_files().size());
-  EXPECT_TRUE(delegate()->get_changed_files().count(kTestPath));
-
-  EXPECT_EQ(1U, delegate()->updated_local_ids().size());
-  EXPECT_TRUE(delegate()->updated_local_ids().count(entry.local_id()));
-}
-
-}  // namespace file_system
-}  // namespace drive
diff --git a/components/drive/file_system/truncate_operation_unittest.cc b/components/drive/file_system/truncate_operation_unittest.cc
deleted file mode 100644
index b5a77e3..0000000
--- a/components/drive/file_system/truncate_operation_unittest.cc
+++ /dev/null
@@ -1,139 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "components/drive/chromeos/file_system/truncate_operation.h"
-
-#include <stdint.h>
-
-#include <memory>
-
-#include "base/bind.h"
-#include "base/files/file_path.h"
-#include "base/files/file_util.h"
-#include "base/task_runner_util.h"
-#include "components/drive/chromeos/fake_free_disk_space_getter.h"
-#include "components/drive/drive.pb.h"
-#include "components/drive/file_system/operation_test_base.h"
-#include "content/public/test/test_utils.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace drive {
-namespace file_system {
-
-class TruncateOperationTest : public OperationTestBase {
- protected:
-  void SetUp() override {
-    OperationTestBase::SetUp();
-
-    operation_ = std::make_unique<TruncateOperation>(
-        blocking_task_runner(), delegate(), scheduler(), metadata(), cache(),
-        temp_dir());
-  }
-
-  std::unique_ptr<TruncateOperation> operation_;
-};
-
-TEST_F(TruncateOperationTest, Truncate) {
-  base::FilePath file_in_root(FILE_PATH_LITERAL("drive/root/File 1.txt"));
-  ResourceEntry src_entry;
-  ASSERT_EQ(FILE_ERROR_OK, GetLocalResourceEntry(file_in_root, &src_entry));
-  const int64_t file_size = src_entry.file_info().size();
-
-  // Make sure the file has at least 2 bytes.
-  ASSERT_GE(file_size, 2);
-
-  FileError error = FILE_ERROR_FAILED;
-  operation_->Truncate(
-      file_in_root,
-      1,  // Truncate to 1 byte.
-      google_apis::test_util::CreateCopyResultCallback(&error));
-  content::RunAllTasksUntilIdle();
-  EXPECT_EQ(FILE_ERROR_OK, error);
-
-  base::FilePath local_path;
-  error = FILE_ERROR_FAILED;
-  base::PostTaskAndReplyWithResult(
-      blocking_task_runner(),
-      FROM_HERE,
-      base::Bind(&internal::FileCache::GetFile,
-                 base::Unretained(cache()),
-                 GetLocalId(file_in_root), &local_path),
-      google_apis::test_util::CreateCopyResultCallback(&error));
-  content::RunAllTasksUntilIdle();
-  ASSERT_EQ(FILE_ERROR_OK, error);
-
-  // The local file should be truncated.
-  int64_t local_file_size = 0;
-  base::GetFileSize(local_path, &local_file_size);
-  EXPECT_EQ(1, local_file_size);
-}
-
-TEST_F(TruncateOperationTest, NegativeSize) {
-  base::FilePath file_in_root(FILE_PATH_LITERAL("drive/root/File 1.txt"));
-  ResourceEntry src_entry;
-  ASSERT_EQ(FILE_ERROR_OK, GetLocalResourceEntry(file_in_root, &src_entry));
-  const int64_t file_size = src_entry.file_info().size();
-
-  // Make sure the file has at least 2 bytes.
-  ASSERT_GE(file_size, 2);
-
-  FileError error = FILE_ERROR_FAILED;
-  operation_->Truncate(
-      file_in_root,
-      -1,  // Truncate to "-1" byte.
-      google_apis::test_util::CreateCopyResultCallback(&error));
-  content::RunAllTasksUntilIdle();
-  EXPECT_EQ(FILE_ERROR_INVALID_OPERATION, error);
-}
-
-TEST_F(TruncateOperationTest, HostedDocument) {
-  base::FilePath file_in_root(FILE_PATH_LITERAL(
-      "drive/root/Document 1 excludeDir-test.gdoc"));
-
-  FileError error = FILE_ERROR_FAILED;
-  operation_->Truncate(
-      file_in_root,
-      1,  // Truncate to 1 byte.
-      google_apis::test_util::CreateCopyResultCallback(&error));
-  content::RunAllTasksUntilIdle();
-  EXPECT_EQ(FILE_ERROR_INVALID_OPERATION, error);
-}
-
-TEST_F(TruncateOperationTest, Extend) {
-  base::FilePath file_in_root(FILE_PATH_LITERAL("drive/root/File 1.txt"));
-  ResourceEntry src_entry;
-  ASSERT_EQ(FILE_ERROR_OK, GetLocalResourceEntry(file_in_root, &src_entry));
-  const int64_t file_size = src_entry.file_info().size();
-
-  FileError error = FILE_ERROR_FAILED;
-  operation_->Truncate(
-      file_in_root,
-      file_size + 10,  // Extend to 10 bytes.
-      google_apis::test_util::CreateCopyResultCallback(&error));
-  content::RunAllTasksUntilIdle();
-  EXPECT_EQ(FILE_ERROR_OK, error);
-
-  base::FilePath local_path;
-  error = FILE_ERROR_FAILED;
-  base::PostTaskAndReplyWithResult(
-      blocking_task_runner(),
-      FROM_HERE,
-      base::Bind(&internal::FileCache::GetFile,
-                 base::Unretained(cache()),
-                 GetLocalId(file_in_root), &local_path),
-      google_apis::test_util::CreateCopyResultCallback(&error));
-  content::RunAllTasksUntilIdle();
-  ASSERT_EQ(FILE_ERROR_OK, error);
-
-  // The local file should be truncated.
-  std::string content;
-  ASSERT_TRUE(base::ReadFileToString(local_path, &content));
-
-  EXPECT_EQ(file_size + 10, static_cast<int64_t>(content.size()));
-  // All trailing 10 bytes should be '\0'.
-  EXPECT_EQ(std::string(10, '\0'), content.substr(file_size));
-}
-
-}  // namespace file_system
-}  // namespace drive
diff --git a/components/drive/file_system_unittest.cc b/components/drive/file_system_unittest.cc
deleted file mode 100644
index c30be21..0000000
--- a/components/drive/file_system_unittest.cc
+++ /dev/null
@@ -1,1549 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "components/drive/chromeos/file_system.h"
-
-#include <stddef.h>
-#include <stdint.h>
-
-#include <memory>
-#include <string>
-#include <vector>
-
-#include "base/bind.h"
-#include "base/files/file_path.h"
-#include "base/files/file_util.h"
-#include "base/files/scoped_temp_dir.h"
-#include "base/macros.h"
-#include "base/test/test_mock_time_task_runner.h"
-#include "components/drive/chromeos/drive_change_list_loader.h"
-#include "components/drive/chromeos/drive_test_util.h"
-#include "components/drive/chromeos/fake_free_disk_space_getter.h"
-#include "components/drive/chromeos/file_system_observer.h"
-#include "components/drive/chromeos/sync_client.h"
-#include "components/drive/drive.pb.h"
-#include "components/drive/drive_api_util.h"
-#include "components/drive/event_logger.h"
-#include "components/drive/file_change.h"
-#include "components/drive/file_system_core_util.h"
-#include "components/drive/job_scheduler.h"
-#include "components/drive/service/fake_drive_service.h"
-#include "components/drive/service/test_util.h"
-#include "components/prefs/testing_pref_service.h"
-#include "content/public/test/browser_task_environment.h"
-#include "google_apis/drive/drive_api_parser.h"
-#include "google_apis/drive/test_util.h"
-#include "mojo/public/cpp/bindings/pending_remote.h"
-#include "services/network/test/test_network_connection_tracker.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace drive {
-namespace {
-
-// Counts the number of invocation, and if it increased up to |expected_counter|
-// quits the current message loop by calling |quit|.
-void AsyncInitializationCallback(int* counter,
-                                 int expected_counter,
-                                 const base::Closure& quit,
-                                 FileError error,
-                                 std::unique_ptr<ResourceEntry> entry) {
-  if (error != FILE_ERROR_OK || !entry) {
-    // If we hit an error case, quit the message loop immediately.
-    // Then the expectation in the test case can find it because the actual
-    // value of |counter| is different from the expected one.
-    quit.Run();
-    return;
-  }
-
-  (*counter)++;
-  if (*counter >= expected_counter)
-    quit.Run();
-}
-
-bool CompareHashAndFilePath(const HashAndFilePath& a,
-                            const HashAndFilePath& b) {
-  const int result = a.hash.compare(b.hash);
-  if (result < 0)
-    return true;
-  if (result > 0)
-    return false;
-  return a.path.AsUTF8Unsafe().compare(b.path.AsUTF8Unsafe()) < 0;
-}
-
-// This class is used to record directory changes and examine them later.
-class MockDirectoryChangeObserver : public FileSystemObserver {
- public:
-  MockDirectoryChangeObserver() = default;
-  ~MockDirectoryChangeObserver() override = default;
-
-  // FileSystemObserver overrides.
-  void OnDirectoryChanged(const base::FilePath& directory_path) override {
-    changed_directories_.push_back(directory_path);
-  }
-
-  void OnFileChanged(const FileChange& new_file_change) override {
-    changed_files_.Apply(new_file_change);
-  }
-
-  void OnTeamDrivesUpdated(
-      const std::set<std::string>& added_team_drive_ids,
-      const std::set<std::string>& removed_team_drive_ids) override {
-    added_team_drive_ids_ = added_team_drive_ids;
-    removed_team_drive_ids_ = removed_team_drive_ids;
-  }
-
-  const std::vector<base::FilePath>& changed_directories() const {
-    return changed_directories_;
-  }
-
-  const FileChange& changed_files() const { return changed_files_; }
-
-  const std::set<std::string>& added_team_drive_ids() const {
-    return added_team_drive_ids_;
-  }
-
-  const std::set<std::string>& removed_team_drive_ids() const {
-    return removed_team_drive_ids_;
-  }
-
- private:
-  std::vector<base::FilePath> changed_directories_;
-  FileChange changed_files_;
-  std::set<std::string> added_team_drive_ids_;
-  std::set<std::string> removed_team_drive_ids_;
-
-  DISALLOW_COPY_AND_ASSIGN(MockDirectoryChangeObserver);
-};
-
-struct DestroyHelper {
-  // FileSystemTest needs to be default constructible, so we provide a default
-  // constructor here.
-  DestroyHelper() = default;
-
-  explicit DestroyHelper(
-      scoped_refptr<base::TestMockTimeTaskRunner> task_runner)
-      : task_runner_(task_runner) {}
-
-  template <typename T>
-  void operator()(T* object) const {
-    DCHECK(task_runner_);
-    if (object) {
-      object->Destroy();
-      task_runner_->RunUntilIdle();
-    }
-  }
-
-  scoped_refptr<base::TestMockTimeTaskRunner> task_runner_;
-};
-
-}  // namespace
-
-class FileSystemTest : public testing::Test {
- protected:
-  void SetUp() override {
-    task_runner_ = base::MakeRefCounted<base::TestMockTimeTaskRunner>(
-        base::TestMockTimeTaskRunner::Type::kBoundToThread);
-
-    ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
-    pref_service_ = std::make_unique<TestingPrefServiceSimple>();
-    test_util::RegisterDrivePrefs(pref_service_->registry());
-
-    logger_ = std::make_unique<EventLogger>();
-    fake_drive_service_ = std::make_unique<FakeDriveService>();
-    test_util::SetUpTestEntries(fake_drive_service_.get());
-
-    fake_free_disk_space_getter_ = std::make_unique<FakeFreeDiskSpaceGetter>();
-
-    network::TestNetworkConnectionTracker::GetInstance()->SetConnectionType(
-        network::mojom::ConnectionType::CONNECTION_WIFI);
-    scheduler_ = std::make_unique<JobScheduler>(
-        pref_service_.get(), logger_.get(), fake_drive_service_.get(),
-        network::TestNetworkConnectionTracker::GetInstance(),
-        task_runner_.get(), mojo::NullRemote());
-
-    mock_directory_observer_ = std::make_unique<MockDirectoryChangeObserver>();
-
-    SetUpResourceMetadataAndFileSystem();
-  }
-
-  void SetUpResourceMetadataAndFileSystem() {
-    const base::FilePath metadata_dir = temp_dir_.GetPath().AppendASCII("meta");
-    ASSERT_TRUE(base::CreateDirectory(metadata_dir));
-    metadata_storage_ =
-        std::unique_ptr<internal::ResourceMetadataStorage, DestroyHelper>(
-            new internal::ResourceMetadataStorage(metadata_dir,
-                                                  task_runner_.get()),
-            DestroyHelper(task_runner_.get()));
-    ASSERT_TRUE(metadata_storage_->Initialize());
-
-    const base::FilePath cache_dir = temp_dir_.GetPath().AppendASCII("files");
-    ASSERT_TRUE(base::CreateDirectory(cache_dir));
-    cache_ = std::unique_ptr<internal::FileCache, DestroyHelper>(
-        new internal::FileCache(metadata_storage_.get(), cache_dir,
-                                task_runner_.get(),
-                                fake_free_disk_space_getter_.get()),
-        DestroyHelper(task_runner_.get()));
-    ASSERT_TRUE(cache_->Initialize());
-
-    resource_metadata_ =
-        std::unique_ptr<internal::ResourceMetadata, DestroyHelper>(
-            new internal::ResourceMetadata(metadata_storage_.get(),
-                                           cache_.get(), task_runner_.get()),
-            DestroyHelper(task_runner_.get()));
-    ASSERT_EQ(FILE_ERROR_OK, resource_metadata_->Initialize());
-
-    const base::FilePath temp_file_dir = temp_dir_.GetPath().AppendASCII("tmp");
-    ASSERT_TRUE(base::CreateDirectory(temp_file_dir));
-    file_system_ = std::make_unique<FileSystem>(
-        logger_.get(), cache_.get(), scheduler_.get(), resource_metadata_.get(),
-        task_runner_.get(), temp_file_dir, task_runner_->GetMockClock());
-    file_system_->AddObserver(mock_directory_observer_.get());
-
-    // Disable delaying so that the sync starts immediately.
-    file_system_->sync_client_for_testing()->set_delay_for_testing(
-        base::TimeDelta::FromSeconds(0));
-
-    file_system_->team_drive_operation_queue_for_testing()
-        ->DisableQueueForTesting();
-  }
-
-  // Loads the full resource list via FakeDriveService.
-  bool LoadFullResourceList() {
-    FileError error = FILE_ERROR_FAILED;
-    file_system_->change_list_loader_for_testing()->LoadIfNeeded(
-        google_apis::test_util::CreateCopyResultCallback(&error));
-    task_runner_->RunUntilIdle();
-    return error == FILE_ERROR_OK;
-  }
-
-  // Gets resource entry by path synchronously.
-  std::unique_ptr<ResourceEntry> GetResourceEntrySync(
-      const base::FilePath& file_path) {
-    FileError error = FILE_ERROR_FAILED;
-    std::unique_ptr<ResourceEntry> entry;
-    file_system_->GetResourceEntry(
-        file_path,
-        google_apis::test_util::CreateCopyResultCallback(&error, &entry));
-    task_runner_->RunUntilIdle();
-
-    return entry;
-  }
-
-  // Gets directory info by path synchronously.
-  std::unique_ptr<ResourceEntryVector> ReadDirectorySync(
-      const base::FilePath& file_path) {
-    FileError error = FILE_ERROR_FAILED;
-    std::unique_ptr<ResourceEntryVector> entries(new ResourceEntryVector);
-    file_system_->ReadDirectory(
-        file_path,
-        base::Bind(&AccumulateReadDirectoryResult, entries.get()),
-        google_apis::test_util::CreateCopyResultCallback(&error));
-    task_runner_->RunUntilIdle();
-    if (error != FILE_ERROR_OK)
-      entries.reset();
-    return entries;
-  }
-
-  // Used to implement ReadDirectorySync().
-  static void AccumulateReadDirectoryResult(
-      ResourceEntryVector* out_entries,
-      std::unique_ptr<ResourceEntryVector> entries) {
-    ASSERT_TRUE(entries);
-    out_entries->insert(out_entries->end(), entries->begin(), entries->end());
-  }
-
-  // Returns true if an entry exists at |file_path|.
-  bool EntryExists(const base::FilePath& file_path) {
-    return GetResourceEntrySync(file_path) != nullptr;
-  }
-
-  // Flag for specifying the timestamp of the test filesystem cache.
-  enum SetUpTestFileSystemParam {
-    USE_OLD_TIMESTAMP,
-    USE_SERVER_TIMESTAMP,
-  };
-
-  // Sets up a filesystem with directories: drive/root, drive/root/Dir1,
-  // drive/root/Dir1/SubDir2 and files drive/root/File1, drive/root/Dir1/File2,
-  // drive/root/Dir1/SubDir2/File3. If |use_up_to_date_timestamp| is true, sets
-  // the start_page_token to that of FakeDriveService, indicating the cache is
-  // holding the latest file system info.
-  void SetUpTestFileSystem(SetUpTestFileSystemParam param) {
-    // Destroy the existing resource metadata to close DB.
-    resource_metadata_.reset();
-
-    const base::FilePath metadata_dir = temp_dir_.GetPath().AppendASCII("meta");
-    ASSERT_TRUE(base::CreateDirectory(metadata_dir));
-    std::unique_ptr<internal::ResourceMetadataStorage, DestroyHelper>
-        metadata_storage(new internal::ResourceMetadataStorage(
-                             metadata_dir, task_runner_.get()),
-                         DestroyHelper(task_runner_.get()));
-
-    const base::FilePath cache_dir = temp_dir_.GetPath().AppendASCII("files");
-    std::unique_ptr<internal::FileCache, DestroyHelper> cache(
-        new internal::FileCache(metadata_storage.get(), cache_dir,
-                                task_runner_.get(),
-                                fake_free_disk_space_getter_.get()),
-        DestroyHelper(task_runner_.get()));
-
-    std::unique_ptr<internal::ResourceMetadata, DestroyHelper>
-        resource_metadata(
-            new internal::ResourceMetadata(metadata_storage_.get(), cache.get(),
-                                           task_runner_.get()),
-            DestroyHelper(task_runner_.get()));
-
-    ASSERT_EQ(FILE_ERROR_OK, resource_metadata->Initialize());
-
-    const std::string start_page_token =
-        param == USE_SERVER_TIMESTAMP
-            ? fake_drive_service_->start_page_token().start_page_token()
-            : "2";
-    ASSERT_EQ(FILE_ERROR_OK,
-              resource_metadata->SetStartPageToken(start_page_token));
-
-    // drive/root
-    ResourceEntry root;
-    ASSERT_EQ(FILE_ERROR_OK, resource_metadata->GetResourceEntryByPath(
-        util::GetDriveMyDriveRootPath(), &root));
-    root.set_resource_id(fake_drive_service_->GetRootResourceId());
-    ASSERT_EQ(FILE_ERROR_OK, resource_metadata->RefreshEntry(root));
-
-    std::string local_id;
-
-    // drive/root/File1
-    ResourceEntry file1;
-    file1.set_title("File1");
-    file1.set_resource_id("resource_id:File1");
-    file1.set_parent_local_id(root.local_id());
-    file1.mutable_file_specific_info()->set_md5("md5#1");
-    file1.mutable_file_info()->set_is_directory(false);
-    file1.mutable_file_info()->set_size(1048576);
-    ASSERT_EQ(FILE_ERROR_OK, resource_metadata->AddEntry(file1, &local_id));
-
-    // drive/root/Dir1
-    ResourceEntry dir1;
-    dir1.set_title("Dir1");
-    dir1.set_resource_id("resource_id:Dir1");
-    dir1.set_parent_local_id(root.local_id());
-    dir1.mutable_file_info()->set_is_directory(true);
-    ASSERT_EQ(FILE_ERROR_OK, resource_metadata->AddEntry(dir1, &local_id));
-    const std::string dir1_local_id = local_id;
-
-    // drive/root/Dir1/File2
-    ResourceEntry file2;
-    file2.set_title("File2");
-    file2.set_resource_id("resource_id:File2");
-    file2.set_parent_local_id(dir1_local_id);
-    file2.mutable_file_specific_info()->set_md5("md5#2");
-    file2.mutable_file_info()->set_is_directory(false);
-    file2.mutable_file_info()->set_size(555);
-    ASSERT_EQ(FILE_ERROR_OK, resource_metadata->AddEntry(file2, &local_id));
-
-    // drive/root/Dir1/SubDir2
-    ResourceEntry dir2;
-    dir2.set_title("SubDir2");
-    dir2.set_resource_id("resource_id:SubDir2");
-    dir2.set_parent_local_id(dir1_local_id);
-    dir2.mutable_file_info()->set_is_directory(true);
-    ASSERT_EQ(FILE_ERROR_OK, resource_metadata->AddEntry(dir2, &local_id));
-    const std::string dir2_local_id = local_id;
-
-    // drive/root/Dir1/SubDir2/File3
-    ResourceEntry file3;
-    file3.set_title("File3");
-    file3.set_resource_id("resource_id:File3");
-    file3.set_parent_local_id(dir2_local_id);
-    file3.mutable_file_specific_info()->set_md5("md5#2");
-    file3.mutable_file_info()->set_is_directory(false);
-    file3.mutable_file_info()->set_size(12345);
-    ASSERT_EQ(FILE_ERROR_OK, resource_metadata->AddEntry(file3, &local_id));
-
-    // drive/team_drive
-    ResourceEntry team_drive_root;
-    ASSERT_EQ(FILE_ERROR_OK,
-              resource_metadata->GetResourceEntryByPath(
-                  util::GetDriveTeamDrivesRootPath(), &team_drive_root));
-
-    // drive/team_drive/team_drive_1
-    ResourceEntry td_dir;
-    td_dir.set_title("team_drive_1");
-    td_dir.set_resource_id("td_id_1");
-    td_dir.set_parent_local_id(team_drive_root.local_id());
-    td_dir.mutable_file_info()->set_is_directory(true);
-    ASSERT_EQ(FILE_ERROR_OK, resource_metadata->AddEntry(td_dir, &local_id));
-
-    // Recreate resource metadata.
-    SetUpResourceMetadataAndFileSystem();
-  }
-
-  // Sets up two team drives, team_drive_a and team_drive_b and creates the
-  // following:
-  // - Directories:
-  // -- team_drive_a/dir1
-  // -- team_drive_a/dir1/nested_1
-  // -- team_drive_b/dir2
-  //
-  // - Files:
-  // -- team_drive_a/dir1/file1
-  // -- team_drive_a/dir1/nested_1/file1
-  // -- team_drive_b/dir2/file2
-  bool SetupTeamDrives() {
-    fake_drive_service_->AddTeamDrive("td_id_1", "team_drive_1", "");
-    fake_drive_service_->AddTeamDrive("td_id_2", "team_drive_2", "");
-    fake_drive_service_->AddTeamDrive("td_id_2_2", "team_drive_2", "");
-
-    google_apis::DriveApiErrorCode error = google_apis::DRIVE_OTHER_ERROR;
-    std::unique_ptr<google_apis::FileResource> entry;
-
-    fake_drive_service_->AddNewFileWithResourceId(
-        "td_1_dir_1_resource_id", util::kDriveFolderMimeType, std::string(),
-        "td_id_1", "dir1",
-        false,  // shared_with_me
-        google_apis::test_util::CreateCopyResultCallback(&error, &entry));
-    base::RunLoop().RunUntilIdle();
-    if (error != google_apis::HTTP_CREATED)
-      return false;
-
-    fake_drive_service_->AddNewFileWithResourceId(
-        "td_1_dir_nested_1_resource_id", util::kDriveFolderMimeType,
-        std::string(), "td_1_dir_1_resource_id", "nested_1",
-        false,  // shared_with_me
-        google_apis::test_util::CreateCopyResultCallback(&error, &entry));
-    base::RunLoop().RunUntilIdle();
-    if (error != google_apis::HTTP_CREATED)
-      return false;
-
-    fake_drive_service_->AddNewFileWithResourceId(
-        "td_2_dir_2_resource_id", util::kDriveFolderMimeType, std::string(),
-        "td_id_2", "dir2",
-        false,  // shared_with_me
-        google_apis::test_util::CreateCopyResultCallback(&error, &entry));
-    base::RunLoop().RunUntilIdle();
-    if (error != google_apis::HTTP_CREATED)
-      return false;
-
-    fake_drive_service_->AddNewFileWithResourceId(
-        "dir1_file_1_resource_id", "audio/mpeg", "dir 1 file 1 content.",
-        "td_1_dir_1_resource_id", "File 1.txt",
-        false,  // shared_with_me
-        google_apis::test_util::CreateCopyResultCallback(&error, &entry));
-    base::RunLoop().RunUntilIdle();
-    if (error != google_apis::HTTP_CREATED)
-      return false;
-
-    fake_drive_service_->AddNewFileWithResourceId(
-        "nested_1_file_1_resource_id", "audio/mpeg", "nested 1 file 1 content.",
-        "td_1_dir_nested_1_resource_id", "Nested File 1.txt",
-        false,  // shared_with_me
-        google_apis::test_util::CreateCopyResultCallback(&error, &entry));
-    base::RunLoop().RunUntilIdle();
-    if (error != google_apis::HTTP_CREATED)
-      return false;
-
-    fake_drive_service_->AddNewFileWithResourceId(
-        "dir_2_file_1_resource_id", "audio/mpeg", "dir2 file1 content.",
-        "td_2_dir_2_resource_id", "File 2.txt",
-        false,  // shared_with_me
-        google_apis::test_util::CreateCopyResultCallback(&error, &entry));
-    base::RunLoop().RunUntilIdle();
-    if (error != google_apis::HTTP_CREATED)
-      return false;
-
-    fake_drive_service_->AddNewFileWithResourceId(
-        "td_2_2_dir_1_resource_id", util::kDriveFolderMimeType, std::string(),
-        "td_id_2_2", "dir1",
-        false,  // shared_with_me
-        google_apis::test_util::CreateCopyResultCallback(&error, &entry));
-    base::RunLoop().RunUntilIdle();
-    if (error != google_apis::HTTP_CREATED)
-      return false;
-
-    return true;
-  }
-
-  scoped_refptr<base::TestMockTimeTaskRunner> task_runner_;
-  base::ScopedTempDir temp_dir_;
-  // We don't use TestingProfile::GetPrefs() in favor of having less
-  // dependencies to Profile in general.
-  std::unique_ptr<TestingPrefServiceSimple> pref_service_;
-
-  std::unique_ptr<EventLogger> logger_;
-  std::unique_ptr<FakeDriveService> fake_drive_service_;
-  std::unique_ptr<FakeFreeDiskSpaceGetter> fake_free_disk_space_getter_;
-  std::unique_ptr<JobScheduler> scheduler_;
-  std::unique_ptr<MockDirectoryChangeObserver> mock_directory_observer_;
-
-  std::unique_ptr<internal::ResourceMetadataStorage, DestroyHelper>
-      metadata_storage_;
-  std::unique_ptr<internal::FileCache, DestroyHelper> cache_;
-  std::unique_ptr<internal::ResourceMetadata, DestroyHelper> resource_metadata_;
-  std::unique_ptr<FileSystem> file_system_;
-};
-
-TEST_F(FileSystemTest, SearchByHashes) {
-  ASSERT_NO_FATAL_FAILURE(SetUpTestFileSystem(USE_SERVER_TIMESTAMP));
-
-  std::set<std::string> hashes;
-  FileError error;
-  std::vector<HashAndFilePath> results;
-
-  hashes.insert("md5#1");
-  file_system_->SearchByHashes(
-      hashes,
-      google_apis::test_util::CreateCopyResultCallback(&error, &results));
-  task_runner_->RunUntilIdle();
-  EXPECT_EQ(FILE_ERROR_OK, error);
-  ASSERT_EQ(1u, results.size());
-  EXPECT_EQ(FILE_PATH_LITERAL("drive/root/File1"), results[0].path.value());
-
-  hashes.clear();
-  hashes.insert("md5#2");
-  file_system_->SearchByHashes(
-      hashes,
-      google_apis::test_util::CreateCopyResultCallback(&error, &results));
-  task_runner_->RunUntilIdle();
-  EXPECT_EQ(FILE_ERROR_OK, error);
-  ASSERT_EQ(2u, results.size());
-  std::sort(results.begin(), results.end(), &CompareHashAndFilePath);
-  EXPECT_EQ(FILE_PATH_LITERAL("drive/root/Dir1/File2"),
-            results[0].path.value());
-  EXPECT_EQ(FILE_PATH_LITERAL("drive/root/Dir1/SubDir2/File3"),
-            results[1].path.value());
-
-  hashes.clear();
-  hashes.insert("md5#1");
-  hashes.insert("md5#2");
-  file_system_->SearchByHashes(
-      hashes,
-      google_apis::test_util::CreateCopyResultCallback(&error, &results));
-  task_runner_->RunUntilIdle();
-  EXPECT_EQ(FILE_ERROR_OK, error);
-  ASSERT_EQ(3u, results.size());
-  std::sort(results.begin(), results.end(), &CompareHashAndFilePath);
-  EXPECT_EQ(FILE_PATH_LITERAL("drive/root/File1"), results[0].path.value());
-  EXPECT_EQ(FILE_PATH_LITERAL("drive/root/Dir1/File2"),
-            results[1].path.value());
-  EXPECT_EQ(FILE_PATH_LITERAL("drive/root/Dir1/SubDir2/File3"),
-            results[2].path.value());
-}
-
-TEST_F(FileSystemTest, Copy) {
-  base::FilePath src_file_path(FILE_PATH_LITERAL("drive/root/File 1.txt"));
-  base::FilePath dest_file_path(FILE_PATH_LITERAL("drive/root/Copied.txt"));
-  EXPECT_TRUE(GetResourceEntrySync(src_file_path));
-  EXPECT_FALSE(GetResourceEntrySync(dest_file_path));
-
-  FileError error = FILE_ERROR_FAILED;
-  file_system_->Copy(src_file_path,
-                     dest_file_path,
-                     false,  // preserve_last_modified,
-                     google_apis::test_util::CreateCopyResultCallback(&error));
-  task_runner_->RunUntilIdle();
-  EXPECT_EQ(FILE_ERROR_OK, error);
-
-  // Entry is added on the server.
-  std::unique_ptr<ResourceEntry> entry = GetResourceEntrySync(dest_file_path);
-  ASSERT_TRUE(entry);
-
-  google_apis::DriveApiErrorCode status = google_apis::DRIVE_OTHER_ERROR;
-  std::unique_ptr<google_apis::FileResource> server_entry;
-  fake_drive_service_->GetFileResource(
-      entry->resource_id(),
-      google_apis::test_util::CreateCopyResultCallback(&status, &server_entry));
-  task_runner_->RunUntilIdle();
-  EXPECT_EQ(google_apis::HTTP_SUCCESS, status);
-  ASSERT_TRUE(server_entry);
-  EXPECT_EQ(entry->title(), server_entry->title());
-  EXPECT_FALSE(server_entry->IsDirectory());
-}
-
-TEST_F(FileSystemTest, Move) {
-  base::FilePath src_file_path(FILE_PATH_LITERAL("drive/root/File 1.txt"));
-  base::FilePath dest_file_path(
-      FILE_PATH_LITERAL("drive/root/Directory 1/Moved.txt"));
-  EXPECT_TRUE(GetResourceEntrySync(src_file_path));
-  EXPECT_FALSE(GetResourceEntrySync(dest_file_path));
-  std::unique_ptr<ResourceEntry> parent =
-      GetResourceEntrySync(dest_file_path.DirName());
-  ASSERT_TRUE(parent);
-
-  FileError error = FILE_ERROR_FAILED;
-  file_system_->Move(src_file_path,
-                     dest_file_path,
-                     google_apis::test_util::CreateCopyResultCallback(&error));
-  task_runner_->RunUntilIdle();
-  EXPECT_EQ(FILE_ERROR_OK, error);
-
-  // Entry is moved on the server.
-  std::unique_ptr<ResourceEntry> entry = GetResourceEntrySync(dest_file_path);
-  ASSERT_TRUE(entry);
-
-  google_apis::DriveApiErrorCode status = google_apis::DRIVE_OTHER_ERROR;
-  std::unique_ptr<google_apis::FileResource> server_entry;
-  fake_drive_service_->GetFileResource(
-      entry->resource_id(),
-      google_apis::test_util::CreateCopyResultCallback(&status, &server_entry));
-  task_runner_->RunUntilIdle();
-  EXPECT_EQ(google_apis::HTTP_SUCCESS, status);
-  ASSERT_TRUE(server_entry);
-  EXPECT_EQ(entry->title(), server_entry->title());
-
-  ASSERT_FALSE(server_entry->parents().empty());
-  EXPECT_EQ(parent->resource_id(), server_entry->parents()[0].file_id());
-}
-
-TEST_F(FileSystemTest, Remove) {
-  base::FilePath file_path(FILE_PATH_LITERAL("drive/root/File 1.txt"));
-  std::unique_ptr<ResourceEntry> entry = GetResourceEntrySync(file_path);
-  ASSERT_TRUE(entry);
-
-  FileError error = FILE_ERROR_FAILED;
-  file_system_->Remove(
-      file_path,
-      false,  // is_resursive
-      google_apis::test_util::CreateCopyResultCallback(&error));
-  task_runner_->RunUntilIdle();
-  EXPECT_EQ(FILE_ERROR_OK, error);
-
-  // Entry is removed on the server.
-  google_apis::DriveApiErrorCode status = google_apis::DRIVE_OTHER_ERROR;
-  std::unique_ptr<google_apis::FileResource> server_entry;
-  fake_drive_service_->GetFileResource(
-      entry->resource_id(),
-      google_apis::test_util::CreateCopyResultCallback(&status, &server_entry));
-  task_runner_->RunUntilIdle();
-  EXPECT_EQ(google_apis::HTTP_SUCCESS, status);
-  ASSERT_TRUE(server_entry);
-  EXPECT_TRUE(server_entry->labels().is_trashed());
-}
-
-TEST_F(FileSystemTest, CreateDirectory) {
-  base::FilePath directory_path(FILE_PATH_LITERAL("drive/root/New Directory"));
-  EXPECT_FALSE(GetResourceEntrySync(directory_path));
-
-  FileError error = FILE_ERROR_FAILED;
-  file_system_->CreateDirectory(
-      directory_path,
-      true,  // is_exclusive
-      false,  // is_recursive
-      google_apis::test_util::CreateCopyResultCallback(&error));
-  task_runner_->RunUntilIdle();
-  EXPECT_EQ(FILE_ERROR_OK, error);
-
-  // Directory is created on the server.
-  std::unique_ptr<ResourceEntry> entry = GetResourceEntrySync(directory_path);
-  ASSERT_TRUE(entry);
-
-  google_apis::DriveApiErrorCode status = google_apis::DRIVE_OTHER_ERROR;
-  std::unique_ptr<google_apis::FileResource> server_entry;
-  fake_drive_service_->GetFileResource(
-      entry->resource_id(),
-      google_apis::test_util::CreateCopyResultCallback(&status, &server_entry));
-  task_runner_->RunUntilIdle();
-  EXPECT_EQ(google_apis::HTTP_SUCCESS, status);
-  ASSERT_TRUE(server_entry);
-  EXPECT_EQ(entry->title(), server_entry->title());
-  EXPECT_TRUE(server_entry->IsDirectory());
-}
-
-TEST_F(FileSystemTest, CreateFile) {
-  base::FilePath file_path(FILE_PATH_LITERAL("drive/root/New File.txt"));
-  EXPECT_FALSE(GetResourceEntrySync(file_path));
-
-  FileError error = FILE_ERROR_FAILED;
-  file_system_->CreateFile(
-      file_path,
-      true,  // is_exclusive
-      "text/plain",
-      google_apis::test_util::CreateCopyResultCallback(&error));
-  task_runner_->RunUntilIdle();
-  EXPECT_EQ(FILE_ERROR_OK, error);
-
-  // File is created on the server.
-  std::unique_ptr<ResourceEntry> entry = GetResourceEntrySync(file_path);
-  ASSERT_TRUE(entry);
-
-  google_apis::DriveApiErrorCode status = google_apis::DRIVE_OTHER_ERROR;
-  std::unique_ptr<google_apis::FileResource> server_entry;
-  fake_drive_service_->GetFileResource(
-      entry->resource_id(),
-      google_apis::test_util::CreateCopyResultCallback(&status, &server_entry));
-  task_runner_->RunUntilIdle();
-  EXPECT_EQ(google_apis::HTTP_SUCCESS, status);
-  ASSERT_TRUE(server_entry);
-  EXPECT_EQ(entry->title(), server_entry->title());
-  EXPECT_FALSE(server_entry->IsDirectory());
-}
-
-TEST_F(FileSystemTest, TouchFile) {
-  base::FilePath file_path(FILE_PATH_LITERAL("drive/root/File 1.txt"));
-  std::unique_ptr<ResourceEntry> entry = GetResourceEntrySync(file_path);
-  ASSERT_TRUE(entry);
-
-  base::Time last_accessed =
-      base::Time::FromInternalValue(entry->file_info().last_accessed()) +
-      base::TimeDelta::FromSeconds(1);
-  base::Time last_modified =
-      base::Time::FromInternalValue(entry->file_info().last_modified()) +
-      base::TimeDelta::FromSeconds(1);
-
-  FileError error = FILE_ERROR_FAILED;
-  file_system_->TouchFile(
-      file_path,
-      last_accessed,
-      last_modified,
-      google_apis::test_util::CreateCopyResultCallback(&error));
-  task_runner_->RunUntilIdle();
-  EXPECT_EQ(FILE_ERROR_OK, error);
-
-  // File is touched on the server.
-  google_apis::DriveApiErrorCode status = google_apis::DRIVE_OTHER_ERROR;
-  std::unique_ptr<google_apis::FileResource> server_entry;
-  fake_drive_service_->GetFileResource(
-      entry->resource_id(),
-      google_apis::test_util::CreateCopyResultCallback(&status, &server_entry));
-  task_runner_->RunUntilIdle();
-  EXPECT_EQ(google_apis::HTTP_SUCCESS, status);
-  ASSERT_TRUE(server_entry);
-  EXPECT_EQ(last_accessed, server_entry->last_viewed_by_me_date());
-  EXPECT_EQ(last_modified, server_entry->modified_date());
-  EXPECT_EQ(last_modified, server_entry->modified_by_me_date());
-}
-
-TEST_F(FileSystemTest, TruncateFile) {
-  base::FilePath file_path(FILE_PATH_LITERAL("drive/root/File 1.txt"));
-  std::unique_ptr<ResourceEntry> entry = GetResourceEntrySync(file_path);
-  ASSERT_TRUE(entry);
-
-  const int64_t kLength = entry->file_info().size() + 100;
-
-  FileError error = FILE_ERROR_FAILED;
-  file_system_->TruncateFile(
-      file_path,
-      kLength,
-      google_apis::test_util::CreateCopyResultCallback(&error));
-  task_runner_->RunUntilIdle();
-  EXPECT_EQ(FILE_ERROR_OK, error);
-
-  // File is touched on the server.
-  google_apis::DriveApiErrorCode status = google_apis::DRIVE_OTHER_ERROR;
-  std::unique_ptr<google_apis::FileResource> server_entry;
-  fake_drive_service_->GetFileResource(
-      entry->resource_id(),
-      google_apis::test_util::CreateCopyResultCallback(&status, &server_entry));
-  task_runner_->RunUntilIdle();
-  EXPECT_EQ(google_apis::HTTP_SUCCESS, status);
-  ASSERT_TRUE(server_entry);
-  EXPECT_EQ(kLength, server_entry->file_size());
-}
-
-TEST_F(FileSystemTest, DuplicatedAsyncInitialization) {
-  base::RunLoop loop;
-
-  int counter = 0;
-
-  file_system_->GetResourceEntry(
-      base::FilePath(FILE_PATH_LITERAL("drive/root")),
-      base::BindOnce(&AsyncInitializationCallback, &counter, 2,
-                     loop.QuitClosure()));
-  file_system_->GetResourceEntry(
-      base::FilePath(FILE_PATH_LITERAL("drive/root")),
-      base::BindOnce(&AsyncInitializationCallback, &counter, 2,
-                     loop.QuitClosure()));
-  loop.Run();  // Wait to get our result
-  EXPECT_EQ(2, counter);
-
-  EXPECT_EQ(1, fake_drive_service_->file_list_load_count());
-}
-
-TEST_F(FileSystemTest, GetGrandRootEntry) {
-  const base::FilePath kFilePath(FILE_PATH_LITERAL("drive"));
-  std::unique_ptr<ResourceEntry> entry = GetResourceEntrySync(kFilePath);
-  ASSERT_TRUE(entry);
-  EXPECT_EQ(util::kDriveGrandRootLocalId, entry->local_id());
-}
-
-TEST_F(FileSystemTest, GetOtherDirEntry) {
-  const base::FilePath kFilePath(FILE_PATH_LITERAL("drive/other"));
-  std::unique_ptr<ResourceEntry> entry = GetResourceEntrySync(kFilePath);
-  ASSERT_TRUE(entry);
-  EXPECT_EQ(util::kDriveOtherDirLocalId, entry->local_id());
-}
-
-TEST_F(FileSystemTest, GetMyDriveRoot) {
-  const base::FilePath kFilePath(FILE_PATH_LITERAL("drive/root"));
-  std::unique_ptr<ResourceEntry> entry = GetResourceEntrySync(kFilePath);
-  ASSERT_TRUE(entry);
-  EXPECT_EQ(fake_drive_service_->GetRootResourceId(), entry->resource_id());
-
-  // After "fast fetch" is done, full resource list is fetched.
-  EXPECT_EQ(1, fake_drive_service_->file_list_load_count());
-}
-
-TEST_F(FileSystemTest, GetTeamDriveRoot) {
-  const base::FilePath kFilePath(FILE_PATH_LITERAL("drive/team_drives"));
-  std::unique_ptr<ResourceEntry> entry = GetResourceEntrySync(kFilePath);
-  ASSERT_TRUE(entry);
-  EXPECT_EQ(util::kDriveTeamDrivesDirLocalId, entry->local_id());
-
-  // After "fast fetch" is done, full resource list is fetched.
-  EXPECT_EQ(1, fake_drive_service_->file_list_load_count());
-}
-
-TEST_F(FileSystemTest, GetExistingFile) {
-  // Simulate the situation that full feed fetching takes very long time,
-  // to test the recursive "fast fetch" feature is properly working.
-  fake_drive_service_->set_never_return_all_file_list(true);
-
-  const base::FilePath kFilePath(
-      FILE_PATH_LITERAL("drive/root/Directory 1/SubDirectory File 1.txt"));
-  std::unique_ptr<ResourceEntry> entry = GetResourceEntrySync(kFilePath);
-  ASSERT_TRUE(entry);
-  EXPECT_EQ("subdirectory_file_1_id", entry->resource_id());
-
-  EXPECT_EQ(1, fake_drive_service_->about_resource_load_count());
-  EXPECT_EQ(2, fake_drive_service_->directory_load_count());
-  EXPECT_EQ(1, fake_drive_service_->blocked_file_list_load_count());
-}
-
-TEST_F(FileSystemTest, GetExistingDocument) {
-  const base::FilePath kFilePath(
-      FILE_PATH_LITERAL("drive/root/Document 1 excludeDir-test.gdoc"));
-  std::unique_ptr<ResourceEntry> entry = GetResourceEntrySync(kFilePath);
-  ASSERT_TRUE(entry);
-  EXPECT_EQ("5_document_resource_id", entry->resource_id());
-}
-
-TEST_F(FileSystemTest, GetNonExistingFile) {
-  const base::FilePath kFilePath(
-      FILE_PATH_LITERAL("drive/root/nonexisting.file"));
-  std::unique_ptr<ResourceEntry> entry = GetResourceEntrySync(kFilePath);
-  EXPECT_FALSE(entry);
-}
-
-TEST_F(FileSystemTest, GetInSubSubdir) {
-  const base::FilePath kFilePath(
-      FILE_PATH_LITERAL("drive/root/Directory 1/Sub Directory Folder/"
-                        "Sub Sub Directory Folder"));
-  std::unique_ptr<ResourceEntry> entry = GetResourceEntrySync(kFilePath);
-  ASSERT_TRUE(entry);
-  ASSERT_EQ("sub_sub_directory_folder_id", entry->resource_id());
-}
-
-TEST_F(FileSystemTest, GetOrphanFile) {
-  ASSERT_TRUE(LoadFullResourceList());
-
-  // Entry without parents are placed under "drive/other".
-  const base::FilePath kFilePath(
-      FILE_PATH_LITERAL("drive/other/Orphan File 1.txt"));
-  std::unique_ptr<ResourceEntry> entry = GetResourceEntrySync(kFilePath);
-  ASSERT_TRUE(entry);
-  EXPECT_EQ("1_orphanfile_resource_id", entry->resource_id());
-}
-
-TEST_F(FileSystemTest, ReadDirectory_Root) {
-  // ReadDirectory() should kick off the resource list loading.
-  std::unique_ptr<ResourceEntryVector> entries(
-      ReadDirectorySync(base::FilePath::FromUTF8Unsafe("drive")));
-  // The root directory should be read correctly.
-  ASSERT_TRUE(entries);
-  ASSERT_EQ(5U, entries->size());
-
-  // The found three directories should be /drive/root, /drive/other,
-  // /drive/trash and /drive/team_drives.
-  std::set<base::FilePath> found;
-  for (size_t i = 0; i < entries->size(); ++i)
-    found.insert(base::FilePath::FromUTF8Unsafe((*entries)[i].title()));
-  EXPECT_EQ(5U, found.size());
-  EXPECT_EQ(1U, found.count(base::FilePath::FromUTF8Unsafe(
-                    util::kDriveMyDriveRootDirName)));
-  EXPECT_EQ(1U, found.count(
-                    base::FilePath::FromUTF8Unsafe(util::kDriveOtherDirName)));
-  EXPECT_EQ(1U, found.count(
-                    base::FilePath::FromUTF8Unsafe(util::kDriveTrashDirName)));
-  EXPECT_EQ(1U, found.count(base::FilePath::FromUTF8Unsafe(
-                    util::kDriveTeamDrivesDirName)));
-  EXPECT_EQ(1U, found.count(base::FilePath::FromUTF8Unsafe(
-                    util::kDriveComputersDirName)));
-}
-
-TEST_F(FileSystemTest, ReadDirectory_TeamDrivesRoot) {
-  ASSERT_NO_FATAL_FAILURE(SetUpTestFileSystem(USE_SERVER_TIMESTAMP));
-  ASSERT_TRUE(SetupTeamDrives());
-
-  // The first load trigger the loading of team drives.
-  ReadDirectorySync(base::FilePath::FromUTF8Unsafe("."));
-
-  // After the first load team drive data should be available for reading.
-  std::unique_ptr<ResourceEntryVector> entries(
-      ReadDirectorySync(base::FilePath::FromUTF8Unsafe("drive/team_drives")));
-  // The root directory should be read correctly.
-  ASSERT_TRUE(entries);
-  ASSERT_EQ(3U, entries->size());
-
-  std::multiset<base::FilePath> found;
-  for (size_t i = 0; i < entries->size(); ++i) {
-    found.insert(base::FilePath::FromUTF8Unsafe((*entries)[i].title()));
-  }
-  EXPECT_EQ(3U, found.size());
-  EXPECT_EQ(1U, found.count(base::FilePath::FromUTF8Unsafe("team_drive_1")));
-  EXPECT_EQ(2U, found.count(base::FilePath::FromUTF8Unsafe("team_drive_2")));
-  EXPECT_EQ(1, fake_drive_service_->team_drive_list_load_count());
-  EXPECT_EQ(3, fake_drive_service_->file_list_load_count());
-
-  // We should be able to read from drive/team_drives/team_drive_1
-  std::unique_ptr<ResourceEntryVector> team_drive_1_entries(ReadDirectorySync(
-      base::FilePath::FromUTF8Unsafe("drive/team_drives/team_drive_1")));
-
-  ASSERT_TRUE(team_drive_1_entries);
-  ASSERT_EQ(1U, team_drive_1_entries->size());
-  std::set<base::FilePath> team_drive_1_found;
-  for (size_t i = 0; i < team_drive_1_entries->size(); ++i) {
-    team_drive_1_found.insert(
-        base::FilePath::FromUTF8Unsafe((*team_drive_1_entries)[i].title()));
-  }
-  EXPECT_EQ(1U, team_drive_1_found.size());
-  EXPECT_EQ(1U,
-            team_drive_1_found.count(base::FilePath::FromUTF8Unsafe("dir1")));
-}
-
-TEST_F(FileSystemTest, ReadDirectory_TeamDriveFolder) {
-  ASSERT_TRUE(SetupTeamDrives());
-
-  // The first load trigger the loading of team drives.
-  ReadDirectorySync(base::FilePath::FromUTF8Unsafe("."));
-
-  // Add a new entry to drive/team_drives/team_drive_1
-  // Create a file in the test directory.
-  std::unique_ptr<google_apis::FileResource> entry;
-  {
-    google_apis::DriveApiErrorCode error = google_apis::DRIVE_OTHER_ERROR;
-    fake_drive_service_->AddNewFile(
-        "text/plain", "(dummy data)", "td_id_1", "TestFile",
-        false,  // shared_with_me
-        google_apis::test_util::CreateCopyResultCallback(&error, &entry));
-    base::RunLoop().RunUntilIdle();
-    ASSERT_EQ(google_apis::HTTP_CREATED, error);
-  }
-
-  // Notify the update to the file system.
-  file_system_->CheckForUpdates();
-  base::RunLoop().RunUntilIdle();
-
-  std::unique_ptr<ResourceEntryVector> entries(ReadDirectorySync(
-      base::FilePath::FromUTF8Unsafe("drive/team_drives/team_drive_1")));
-  // The root directory should be read correctly.
-  ASSERT_TRUE(entries);
-
-  std::set<base::FilePath> found;
-  for (size_t i = 0; i < entries->size(); ++i) {
-    found.insert(base::FilePath::FromUTF8Unsafe((*entries)[i].title()));
-  }
-  EXPECT_EQ(2U, found.size());
-  EXPECT_EQ(1U, found.count(base::FilePath::FromUTF8Unsafe("dir1")));
-  EXPECT_EQ(1U, found.count(base::FilePath::FromUTF8Unsafe("TestFile")));
-}
-
-TEST_F(FileSystemTest, AddTeamDriveInChangeList) {
-  ASSERT_TRUE(SetupTeamDrives());
-
-  // The first load trigger the loading of team drives.
-  ReadDirectorySync(base::FilePath::FromUTF8Unsafe("."));
-
-  // Add a new team drive to the fake file system.
-  {
-    fake_drive_service_->AddTeamDrive("td_id_3", "team_drive_3");
-    base::RunLoop().RunUntilIdle();
-  }
-
-  // Notify the update to the file system, which will add the team drive
-  file_system_->CheckForUpdates();
-  base::RunLoop().RunUntilIdle();
-
-  std::unique_ptr<ResourceEntryVector> entries(
-      ReadDirectorySync(base::FilePath::FromUTF8Unsafe("drive/team_drives/")));
-  // The root directory should be read correctly.
-  ASSERT_TRUE(entries);
-  std::multiset<base::FilePath> found;
-  for (size_t i = 0; i < entries->size(); ++i) {
-    found.insert(base::FilePath::FromUTF8Unsafe((*entries)[i].title()));
-  }
-  EXPECT_EQ(4U, found.size());
-  EXPECT_EQ(1U, found.count(base::FilePath::FromUTF8Unsafe("team_drive_3")));
-
-  // Add a new entry to drive/team_drives/team_drive_3
-  // Create a file in the test directory.
-  std::unique_ptr<google_apis::FileResource> entry;
-  {
-    google_apis::DriveApiErrorCode error = google_apis::DRIVE_OTHER_ERROR;
-    fake_drive_service_->AddNewFile(
-        "text/plain", "(dummy data)", "td_id_3", "TestFile",
-        false,  // shared_with_me
-        google_apis::test_util::CreateCopyResultCallback(&error, &entry));
-    base::RunLoop().RunUntilIdle();
-    ASSERT_EQ(google_apis::HTTP_CREATED, error);
-  }
-
-  // Notify the update to the file system.
-  file_system_->CheckForUpdates();
-  base::RunLoop().RunUntilIdle();
-
-  entries = ReadDirectorySync(
-      base::FilePath::FromUTF8Unsafe("drive/team_drives/team_drive_3"));
-  // The root directory should be read correctly.
-  ASSERT_TRUE(entries);
-
-  found.clear();
-  for (size_t i = 0; i < entries->size(); ++i) {
-    found.insert(base::FilePath::FromUTF8Unsafe((*entries)[i].title()));
-  }
-  EXPECT_EQ(1U, found.size());
-  EXPECT_EQ(1U, found.count(base::FilePath::FromUTF8Unsafe("TestFile")));
-}
-
-TEST_F(FileSystemTest, ReadDirectory_NonRootDirectory) {
-  // ReadDirectory() should kick off the resource list loading.
-  std::unique_ptr<ResourceEntryVector> entries(ReadDirectorySync(
-      base::FilePath::FromUTF8Unsafe("drive/root/Directory 1")));
-  // The non root directory should also be read correctly.
-  // There was a bug (crbug.com/181487), which broke this behavior.
-  // Make sure this is fixed.
-  ASSERT_TRUE(entries);
-  EXPECT_EQ(3U, entries->size());
-}
-
-TEST_F(FileSystemTest, LoadFileSystemFromUpToDateCache) {
-  ASSERT_NO_FATAL_FAILURE(SetUpTestFileSystem(USE_SERVER_TIMESTAMP));
-
-  // Kicks loading of cached file system and query for server update.
-  EXPECT_TRUE(ReadDirectorySync(util::GetDriveMyDriveRootPath()));
-
-  // SetUpTestFileSystem and FakeDriveService have the same
-  // start_page_token (i.e. the local metadata is up to date), so no request for
-  // new resource list (i.e., call to GetResourceList) should happen.
-  EXPECT_EQ(0, fake_drive_service_->file_list_load_count());
-
-  // Since the file system has verified that it holds the latest snapshot,
-  // it should change its state to "loaded", which admits periodic refresh.
-  // To test it, call CheckForUpdates and verify it does try to check updates.
-  const int start_page_toke_load_count_before =
-      fake_drive_service_->start_page_token_load_count();
-  file_system_->CheckForUpdates();
-  task_runner_->RunUntilIdle();
-  EXPECT_LT(start_page_toke_load_count_before,
-            fake_drive_service_->start_page_token_load_count());
-}
-
-TEST_F(FileSystemTest, LoadFileSystemFromCacheWhileOffline) {
-  ASSERT_NO_FATAL_FAILURE(SetUpTestFileSystem(USE_OLD_TIMESTAMP));
-
-  // Make GetResourceList fail for simulating offline situation. This will
-  // leave the file system "loaded from cache, but not synced with server"
-  // state.
-  fake_drive_service_->set_offline(true);
-
-  // Load the root.
-  EXPECT_TRUE(ReadDirectorySync(util::GetDriveGrandRootPath()));
-  // Loading of start page token should not happen as it's offline.
-  EXPECT_EQ(0, fake_drive_service_->start_page_token_load_count());
-
-  // Load "My Drive".
-  EXPECT_TRUE(ReadDirectorySync(util::GetDriveMyDriveRootPath()));
-  EXPECT_EQ(0, fake_drive_service_->start_page_token_load_count());
-
-  // Tests that cached data can be loaded even if the server is not reachable.
-  EXPECT_TRUE(EntryExists(base::FilePath(
-      FILE_PATH_LITERAL("drive/root/File1"))));
-  EXPECT_TRUE(EntryExists(base::FilePath(
-      FILE_PATH_LITERAL("drive/root/Dir1"))));
-  EXPECT_TRUE(EntryExists(base::FilePath(
-      FILE_PATH_LITERAL("drive/root/Dir1/File2"))));
-  EXPECT_TRUE(EntryExists(base::FilePath(
-      FILE_PATH_LITERAL("drive/root/Dir1/SubDir2"))));
-  EXPECT_TRUE(EntryExists(base::FilePath(
-      FILE_PATH_LITERAL("drive/root/Dir1/SubDir2/File3"))));
-
-  // Since the file system has at least succeeded to load cached snapshot,
-  // the file system should be able to start periodic refresh.
-  // To test it, call CheckForUpdates and verify it does try to check
-  // updates, which will cause directory changes.
-  fake_drive_service_->set_offline(false);
-
-  file_system_->CheckForUpdates();
-
-  task_runner_->RunUntilIdle();
-  EXPECT_EQ(1, fake_drive_service_->start_page_token_load_count());
-  EXPECT_EQ(1, fake_drive_service_->change_list_load_count());
-
-  ASSERT_LE(0u, mock_directory_observer_->changed_directories().size());
-  ASSERT_LE(1u, mock_directory_observer_->changed_files().size());
-}
-
-TEST_F(FileSystemTest, ReadDirectoryWhileRefreshing) {
-  // Use old timestamp so the fast fetch will be performed.
-  ASSERT_NO_FATAL_FAILURE(SetUpTestFileSystem(USE_OLD_TIMESTAMP));
-
-  // The list of resources in "drive/root/Dir1" should be fetched.
-  EXPECT_TRUE(ReadDirectorySync(base::FilePath(
-      FILE_PATH_LITERAL("drive/root/Dir1"))));
-  EXPECT_EQ(1, fake_drive_service_->directory_load_count());
-
-  ASSERT_LE(1u, mock_directory_observer_->changed_directories().size());
-}
-
-TEST_F(FileSystemTest, GetResourceEntryNonExistentWhileRefreshing) {
-  // Use old timestamp so the fast fetch will be performed.
-  ASSERT_NO_FATAL_FAILURE(SetUpTestFileSystem(USE_OLD_TIMESTAMP));
-
-  // If an entry is not found, parent directory's resource list is fetched.
-  EXPECT_FALSE(GetResourceEntrySync(base::FilePath(
-      FILE_PATH_LITERAL("drive/root/Dir1/NonExistentFile"))));
-  EXPECT_EQ(1, fake_drive_service_->directory_load_count());
-
-  ASSERT_LE(1u, mock_directory_observer_->changed_directories().size());
-}
-
-TEST_F(FileSystemTest, CreateDirectoryByImplicitLoad) {
-  // Intentionally *not* calling LoadFullResourceList(), for testing that
-  // CreateDirectory ensures the resource list is loaded before it runs.
-
-  base::FilePath existing_directory(
-      FILE_PATH_LITERAL("drive/root/Directory 1"));
-  FileError error = FILE_ERROR_FAILED;
-  file_system_->CreateDirectory(
-      existing_directory,
-      true,  // is_exclusive
-      false,  // is_recursive
-      google_apis::test_util::CreateCopyResultCallback(&error));
-  task_runner_->RunUntilIdle();
-
-  // It should fail because is_exclusive is set to true.
-  EXPECT_EQ(FILE_ERROR_EXISTS, error);
-}
-
-TEST_F(FileSystemTest, CreateDirectoryRecursively) {
-  // Intentionally *not* calling LoadFullResourceList(), for testing that
-  // CreateDirectory ensures the resource list is loaded before it runs.
-
-  base::FilePath new_directory(
-      FILE_PATH_LITERAL("drive/root/Directory 1/a/b/c/d"));
-  FileError error = FILE_ERROR_FAILED;
-  file_system_->CreateDirectory(
-      new_directory,
-      true,  // is_exclusive
-      true,  // is_recursive
-      google_apis::test_util::CreateCopyResultCallback(&error));
-  task_runner_->RunUntilIdle();
-
-  EXPECT_EQ(FILE_ERROR_OK, error);
-
-  std::unique_ptr<ResourceEntry> entry(GetResourceEntrySync(new_directory));
-  ASSERT_TRUE(entry);
-  EXPECT_TRUE(entry->file_info().is_directory());
-}
-
-TEST_F(FileSystemTest, ReadDirectoryAfterUpdateWhileLoading) {
-  // Simulate the situation that full feed fetching takes very long time,
-  // to test the recursive "fast fetch" feature is properly working.
-  fake_drive_service_->set_never_return_all_file_list(true);
-
-  // On the fake server, create the test directory.
-  std::unique_ptr<google_apis::FileResource> parent;
-  {
-    google_apis::DriveApiErrorCode error = google_apis::DRIVE_OTHER_ERROR;
-    fake_drive_service_->AddNewDirectory(
-        fake_drive_service_->GetRootResourceId(), "UpdateWhileLoadingTestDir",
-        AddNewDirectoryOptions(),
-        google_apis::test_util::CreateCopyResultCallback(&error, &parent));
-    base::RunLoop().RunUntilIdle();
-    ASSERT_EQ(google_apis::HTTP_CREATED, error);
-  }
-
-  // Fetch the directory. Currently it is empty.
-  std::unique_ptr<ResourceEntryVector> before =
-      ReadDirectorySync(base::FilePath(
-          FILE_PATH_LITERAL("drive/root/UpdateWhileLoadingTestDir")));
-  ASSERT_TRUE(before);
-  EXPECT_EQ(0u, before->size());
-
-  // Create a file in the test directory.
-  std::unique_ptr<google_apis::FileResource> entry;
-  {
-    google_apis::DriveApiErrorCode error = google_apis::DRIVE_OTHER_ERROR;
-    fake_drive_service_->AddNewFile(
-        "text/plain",
-        "(dummy data)",
-        parent->file_id(),
-        "TestFile",
-        false,  // shared_with_me
-        google_apis::test_util::CreateCopyResultCallback(&error, &entry));
-    base::RunLoop().RunUntilIdle();
-    ASSERT_EQ(google_apis::HTTP_CREATED, error);
-  }
-
-  // Notify the update to the file system.
-  file_system_->CheckForUpdates();
-
-  // Fast forward the clock, so that a new read of the directory is started.
-  task_runner_->FastForwardBy(base::TimeDelta::FromMinutes(1));
-
-  // Read the directory once again. Although the full feed fetching is not yet
-  // finished, the "fast fetch" of the directory works and the refreshed content
-  // is returned.
-  std::unique_ptr<ResourceEntryVector> after = ReadDirectorySync(base::FilePath(
-      FILE_PATH_LITERAL("drive/root/UpdateWhileLoadingTestDir")));
-  ASSERT_TRUE(after);
-  EXPECT_EQ(1u, after->size());
-}
-
-TEST_F(FileSystemTest, PinAndUnpin) {
-  ASSERT_TRUE(LoadFullResourceList());
-
-  base::FilePath file_path(FILE_PATH_LITERAL("drive/root/File 1.txt"));
-
-  // Get the file info.
-  std::unique_ptr<ResourceEntry> entry(GetResourceEntrySync(file_path));
-  ASSERT_TRUE(entry);
-
-  // Pin the file.
-  FileError error = FILE_ERROR_FAILED;
-  file_system_->Pin(file_path,
-                    google_apis::test_util::CreateCopyResultCallback(&error));
-  task_runner_->RunUntilIdle();
-  EXPECT_EQ(FILE_ERROR_OK, error);
-
-  entry = GetResourceEntrySync(file_path);
-  ASSERT_TRUE(entry);
-  EXPECT_TRUE(entry->file_specific_info().cache_state().is_pinned());
-  EXPECT_TRUE(entry->file_specific_info().cache_state().is_present());
-
-  // Unpin the file.
-  error = FILE_ERROR_FAILED;
-  file_system_->Unpin(file_path,
-                      google_apis::test_util::CreateCopyResultCallback(&error));
-  task_runner_->RunUntilIdle();
-  EXPECT_EQ(FILE_ERROR_OK, error);
-
-  entry = GetResourceEntrySync(file_path);
-  ASSERT_TRUE(entry);
-  EXPECT_FALSE(entry->file_specific_info().cache_state().is_pinned());
-
-  // Pinned file gets synced and it results in entry state changes.
-  ASSERT_EQ(0u, mock_directory_observer_->changed_directories().size());
-  ASSERT_EQ(1u, mock_directory_observer_->changed_files().size());
-  EXPECT_EQ(1u,
-            mock_directory_observer_->changed_files().CountDirectory(
-                base::FilePath(FILE_PATH_LITERAL("drive/root"))));
-}
-
-TEST_F(FileSystemTest, PinAndUnpin_NotSynced) {
-  ASSERT_TRUE(LoadFullResourceList());
-
-  base::FilePath file_path(FILE_PATH_LITERAL("drive/root/File 1.txt"));
-
-  // Get the file info.
-  std::unique_ptr<ResourceEntry> entry(GetResourceEntrySync(file_path));
-  ASSERT_TRUE(entry);
-
-  // Unpin the file just after pinning. File fetch should be cancelled.
-  FileError error_pin = FILE_ERROR_FAILED;
-  file_system_->Pin(
-      file_path,
-      google_apis::test_util::CreateCopyResultCallback(&error_pin));
-
-  FileError error_unpin = FILE_ERROR_FAILED;
-  file_system_->Unpin(
-      file_path,
-      google_apis::test_util::CreateCopyResultCallback(&error_unpin));
-
-  task_runner_->RunUntilIdle();
-  EXPECT_EQ(FILE_ERROR_OK, error_pin);
-  EXPECT_EQ(FILE_ERROR_OK, error_unpin);
-
-  // No cache file available because the sync was cancelled by Unpin().
-  entry = GetResourceEntrySync(file_path);
-  ASSERT_TRUE(entry);
-  EXPECT_FALSE(entry->file_specific_info().cache_state().is_present());
-}
-
-TEST_F(FileSystemTest, GetAvailableSpace) {
-  FileError error = FILE_ERROR_OK;
-  int64_t bytes_total;
-  int64_t bytes_used;
-  file_system_->GetAvailableSpace(
-      google_apis::test_util::CreateCopyResultCallback(
-          &error, &bytes_total, &bytes_used));
-  task_runner_->RunUntilIdle();
-  EXPECT_EQ(6789012345LL, bytes_used);
-  EXPECT_EQ(9876543210LL, bytes_total);
-}
-
-TEST_F(FileSystemTest, MarkCacheFileAsMountedAndUnmounted) {
-  ASSERT_TRUE(LoadFullResourceList());
-
-  base::FilePath file_in_root(FILE_PATH_LITERAL("drive/root/File 1.txt"));
-
-  // Make the file cached.
-  FileError error = FILE_ERROR_FAILED;
-  base::FilePath file_path;
-  std::unique_ptr<ResourceEntry> entry;
-  file_system_->GetFile(
-      file_in_root,
-      google_apis::test_util::CreateCopyResultCallback(
-          &error, &file_path, &entry));
-  task_runner_->RunUntilIdle();
-  EXPECT_EQ(FILE_ERROR_OK, error);
-
-  // Test for mounting.
-  error = FILE_ERROR_FAILED;
-  file_path.clear();
-  file_system_->MarkCacheFileAsMounted(
-      file_in_root,
-      google_apis::test_util::CreateCopyResultCallback(&error, &file_path));
-  task_runner_->RunUntilIdle();
-  EXPECT_EQ(FILE_ERROR_OK, error);
-
-  error = FILE_ERROR_FAILED;
-  bool is_marked_as_mounted = false;
-  file_system_->IsCacheFileMarkedAsMounted(
-      file_in_root, google_apis::test_util::CreateCopyResultCallback(
-                        &error, &is_marked_as_mounted));
-  task_runner_->RunUntilIdle();
-  EXPECT_EQ(FILE_ERROR_OK, error);
-  EXPECT_TRUE(is_marked_as_mounted);
-
-  // Cannot remove a cache entry while it's being mounted.
-  EXPECT_EQ(FILE_ERROR_IN_USE, cache_->Remove(entry->local_id()));
-
-  // Test for unmounting.
-  error = FILE_ERROR_FAILED;
-  file_system_->MarkCacheFileAsUnmounted(
-      file_path,
-      google_apis::test_util::CreateCopyResultCallback(&error));
-  task_runner_->RunUntilIdle();
-  EXPECT_EQ(FILE_ERROR_OK, error);
-
-  error = FILE_ERROR_FAILED;
-  is_marked_as_mounted = true;
-  file_system_->IsCacheFileMarkedAsMounted(
-      file_in_root, google_apis::test_util::CreateCopyResultCallback(
-                        &error, &is_marked_as_mounted));
-  task_runner_->RunUntilIdle();
-  EXPECT_EQ(FILE_ERROR_OK, error);
-  EXPECT_FALSE(is_marked_as_mounted);
-
-  // Now able to remove the cache entry.
-  EXPECT_EQ(FILE_ERROR_OK, cache_->Remove(entry->local_id()));
-}
-
-TEST_F(FileSystemTest, FreeDiskSpaceIfNeededFor) {
-  ASSERT_TRUE(LoadFullResourceList());
-
-  base::FilePath file_in_root(FILE_PATH_LITERAL("drive/root/File 1.txt"));
-
-  // Make the file cached.
-  FileError error = FILE_ERROR_FAILED;
-  base::FilePath file_path;
-  std::unique_ptr<ResourceEntry> entry;
-  file_system_->GetFile(file_in_root,
-                        google_apis::test_util::CreateCopyResultCallback(
-                            &error, &file_path, &entry));
-  task_runner_->RunUntilIdle();
-  EXPECT_EQ(FILE_ERROR_OK, error);
-  ASSERT_TRUE(entry);
-  EXPECT_TRUE(entry->file_specific_info().cache_state().is_present());
-
-  bool available;
-  file_system_->FreeDiskSpaceIfNeededFor(
-      512LL << 40,
-      google_apis::test_util::CreateCopyResultCallback(&available));
-  task_runner_->RunUntilIdle();
-  ASSERT_FALSE(available);
-
-  entry = GetResourceEntrySync(file_in_root);
-  ASSERT_TRUE(entry);
-  EXPECT_FALSE(entry->file_specific_info().cache_state().is_present());
-}
-
-TEST_F(FileSystemTest, DebugMetadata) {
-  ASSERT_NO_FATAL_FAILURE(SetUpTestFileSystem(USE_SERVER_TIMESTAMP));
-  ASSERT_TRUE(SetupTeamDrives());
-
-  // The first load will trigger the loading of team drives.
-  ReadDirectorySync(base::FilePath::FromUTF8Unsafe("."));
-
-  base::Time now = base::Time::Now();
-
-  file_system_->CheckForUpdates();
-  base::RunLoop().RunUntilIdle();
-
-  FileSystemMetadata default_corpus_metadata;
-  std::map<std::string, FileSystemMetadata> team_drive_metadata;
-
-  file_system_->GetMetadata(google_apis::test_util::CreateCopyResultCallback(
-      &default_corpus_metadata, &team_drive_metadata));
-  base::RunLoop().RunUntilIdle();
-
-  EXPECT_LE(now, default_corpus_metadata.last_update_check_time);
-  EXPECT_FALSE(default_corpus_metadata.refreshing);
-  EXPECT_EQ(FILE_ERROR_OK, default_corpus_metadata.last_update_check_error);
-  EXPECT_EQ("654340", default_corpus_metadata.start_page_token);
-
-  EXPECT_EQ(3UL, team_drive_metadata.size());
-  EXPECT_FALSE(team_drive_metadata["td_id_1"].refreshing);
-  EXPECT_EQ(util::GetDriveTeamDrivesRootPath().Append("team_drive_1").value(),
-            team_drive_metadata["td_id_1"].path);
-  EXPECT_LE(now, team_drive_metadata["td_id_1"].last_update_check_time);
-  EXPECT_EQ("654345", team_drive_metadata["td_id_1"].start_page_token);
-  EXPECT_EQ(FILE_ERROR_OK,
-            team_drive_metadata["td_id_1"].last_update_check_error);
-
-  EXPECT_FALSE(team_drive_metadata["td_id_2"].refreshing);
-  EXPECT_EQ(util::GetDriveTeamDrivesRootPath().Append("team_drive_2").value(),
-            team_drive_metadata["td_id_2"].path);
-  EXPECT_LE(now, team_drive_metadata["td_id_2"].last_update_check_time);
-  EXPECT_EQ("654346", team_drive_metadata["td_id_2"].start_page_token);
-  EXPECT_EQ(FILE_ERROR_OK,
-            team_drive_metadata["td_id_2"].last_update_check_error);
-
-  EXPECT_FALSE(team_drive_metadata["td_id_2_2"].refreshing);
-  EXPECT_EQ(util::GetDriveTeamDrivesRootPath().Append("team_drive_2").value(),
-            team_drive_metadata["td_id_2_2"].path);
-  EXPECT_LE(now, team_drive_metadata["td_id_2_2"].last_update_check_time);
-  EXPECT_EQ("654347", team_drive_metadata["td_id_2_2"].start_page_token);
-  EXPECT_EQ(FILE_ERROR_OK,
-            team_drive_metadata["td_id_2_2"].last_update_check_error);
-}
-
-TEST_F(FileSystemTest, TeamDrivesChangesObserved) {
-  ASSERT_NO_FATAL_FAILURE(SetUpTestFileSystem(USE_SERVER_TIMESTAMP));
-  ASSERT_TRUE(SetupTeamDrives());
-
-  // The first load will trigger the loading of team drives.
-  ReadDirectorySync(base::FilePath::FromUTF8Unsafe("."));
-
-  // This is the initial set of team drives.
-  EXPECT_EQ(3UL, mock_directory_observer_->added_team_drive_ids().size());
-  EXPECT_TRUE(mock_directory_observer_->removed_team_drive_ids().empty());
-
-  fake_drive_service_->AddTeamDrive("td_id_3", "team_drive_3");
-  // TODO(slangley): Add support for removing a team drive in fake file service.
-  base::RunLoop().RunUntilIdle();
-
-  // Notify the update to the file system, which will add the team drive
-  file_system_->CheckForUpdates();
-  base::RunLoop().RunUntilIdle();
-
-  EXPECT_EQ(1UL, mock_directory_observer_->added_team_drive_ids().size());
-  EXPECT_EQ(1UL,
-            mock_directory_observer_->added_team_drive_ids().count("td_id_3"));
-  EXPECT_TRUE(mock_directory_observer_->removed_team_drive_ids().empty());
-}
-
-TEST_F(FileSystemTest, CheckUpdatesWithIds) {
-  ASSERT_NO_FATAL_FAILURE(SetUpTestFileSystem(USE_SERVER_TIMESTAMP));
-  ASSERT_TRUE(SetupTeamDrives());
-
-  // The first load will trigger the loading of team drives.
-  ReadDirectorySync(base::FilePath::FromUTF8Unsafe("."));
-
-  // Check a non existent team drive id, no other sources should be updated.
-  file_system_->CheckForUpdates({"non_existant_team_drive_id"});
-  base::RunLoop().RunUntilIdle();
-
-  FileSystemMetadata default_corpus_metadata;
-  std::map<std::string, FileSystemMetadata> team_drive_metadata;
-
-  file_system_->GetMetadata(google_apis::test_util::CreateCopyResultCallback(
-      &default_corpus_metadata, &team_drive_metadata));
-  base::RunLoop().RunUntilIdle();
-
-  const base::Time default_time;
-  EXPECT_EQ(default_time, default_corpus_metadata.last_update_check_time);
-  EXPECT_EQ(default_time,
-            team_drive_metadata["td_id_1"].last_update_check_time);
-  EXPECT_EQ(default_time,
-            team_drive_metadata["td_id_2"].last_update_check_time);
-  EXPECT_EQ(default_time,
-            team_drive_metadata["td_id_2_2"].last_update_check_time);
-
-  base::Time now = base::Time::Now();
-
-  // Update just the default corpus.
-  file_system_->CheckForUpdates({""});
-  base::RunLoop().RunUntilIdle();
-
-  file_system_->GetMetadata(google_apis::test_util::CreateCopyResultCallback(
-      &default_corpus_metadata, &team_drive_metadata));
-  base::RunLoop().RunUntilIdle();
-
-  EXPECT_LE(now, default_corpus_metadata.last_update_check_time);
-  EXPECT_EQ(default_time,
-            team_drive_metadata["td_id_1"].last_update_check_time);
-  EXPECT_EQ(default_time,
-            team_drive_metadata["td_id_2"].last_update_check_time);
-  EXPECT_EQ(default_time,
-            team_drive_metadata["td_id_2_2"].last_update_check_time);
-
-  // Update two team drives.
-  now = base::Time::Now();
-  file_system_->CheckForUpdates({"td_id_1", "td_id_2"});
-  base::RunLoop().RunUntilIdle();
-
-  file_system_->GetMetadata(google_apis::test_util::CreateCopyResultCallback(
-      &default_corpus_metadata, &team_drive_metadata));
-  base::RunLoop().RunUntilIdle();
-
-  EXPECT_GE(now, default_corpus_metadata.last_update_check_time);
-  EXPECT_LE(now, team_drive_metadata["td_id_1"].last_update_check_time);
-  EXPECT_LE(now, team_drive_metadata["td_id_2"].last_update_check_time);
-  EXPECT_EQ(default_time,
-            team_drive_metadata["td_id_2_2"].last_update_check_time);
-
-  // Update everything.
-  now = base::Time::Now();
-  file_system_->CheckForUpdates({"", "td_id_1", "td_id_2", "td_id_2_2"});
-  base::RunLoop().RunUntilIdle();
-
-  file_system_->GetMetadata(google_apis::test_util::CreateCopyResultCallback(
-      &default_corpus_metadata, &team_drive_metadata));
-  base::RunLoop().RunUntilIdle();
-
-  EXPECT_LE(now, default_corpus_metadata.last_update_check_time);
-  EXPECT_LE(now, team_drive_metadata["td_id_1"].last_update_check_time);
-  EXPECT_LE(now, team_drive_metadata["td_id_2"].last_update_check_time);
-  EXPECT_LE(now, team_drive_metadata["td_id_2_2"].last_update_check_time);
-}
-
-TEST_F(FileSystemTest, RemoveNonExistingTeamDrive) {
-  ASSERT_NO_FATAL_FAILURE(SetUpTestFileSystem(USE_SERVER_TIMESTAMP));
-  ASSERT_TRUE(SetupTeamDrives());
-
-  // The first load will trigger the loading of team drives.
-  ReadDirectorySync(base::FilePath::FromUTF8Unsafe("."));
-
-  // Create a file change with a delete team drive, ensure file_system_ does not
-  // crash.
-  const base::FilePath path =
-      util::GetDriveTeamDrivesRootPath().Append("team_drive_2");
-  std::unique_ptr<ResourceEntry> entry = GetResourceEntrySync(path);
-  ASSERT_TRUE(entry);
-
-  drive::FileChange change;
-  change.Update(path, *entry, FileChange::CHANGE_TYPE_DELETE);
-
-  // First time should be removed.
-  file_system_->OnTeamDrivesChanged(change);
-  std::set<std::string> expected_changes = {"td_id_2"};
-  EXPECT_EQ(expected_changes,
-            mock_directory_observer_->removed_team_drive_ids());
-
-  // Second time should be no changes, and no crash.
-  file_system_->OnTeamDrivesChanged(change);
-  expected_changes = {};
-  EXPECT_EQ(expected_changes,
-            mock_directory_observer_->removed_team_drive_ids());
-}
-
-}   // namespace drive
diff --git a/components/drive/start_page_token_loader_unittest.cc b/components/drive/start_page_token_loader_unittest.cc
deleted file mode 100644
index 02fab1c..0000000
--- a/components/drive/start_page_token_loader_unittest.cc
+++ /dev/null
@@ -1,165 +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/drive/chromeos/start_page_token_loader.h"
-
-#include <memory>
-
-#include "base/command_line.h"
-#include "base/files/scoped_temp_dir.h"
-#include "base/threading/thread_task_runner_handle.h"
-#include "components/drive/chromeos/drive_test_util.h"
-#include "components/drive/chromeos/file_cache.h"
-#include "components/drive/chromeos/resource_metadata.h"
-#include "components/drive/event_logger.h"
-#include "components/drive/job_scheduler.h"
-#include "components/drive/resource_metadata_storage.h"
-#include "components/drive/service/fake_drive_service.h"
-#include "components/drive/service/test_util.h"
-#include "components/prefs/testing_pref_service.h"
-#include "content/public/test/browser_task_environment.h"
-#include "mojo/public/cpp/bindings/pending_remote.h"
-#include "services/network/test/test_network_connection_tracker.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace drive {
-namespace internal {
-
-class StartPageTokenLoaderTest : public testing::Test {
- protected:
-  void SetUp() override {
-    ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
-
-    pref_service_ = std::make_unique<TestingPrefServiceSimple>();
-    test_util::RegisterDrivePrefs(pref_service_->registry());
-
-    logger_ = std::make_unique<EventLogger>();
-
-    drive_service_ = std::make_unique<FakeDriveService>();
-    ASSERT_TRUE(test_util::SetUpTestEntries(drive_service_.get()));
-
-    network::TestNetworkConnectionTracker::GetInstance()->SetConnectionType(
-        network::mojom::ConnectionType::CONNECTION_WIFI);
-    scheduler_ = std::make_unique<JobScheduler>(
-        pref_service_.get(), logger_.get(), drive_service_.get(),
-        network::TestNetworkConnectionTracker::GetInstance(),
-        base::ThreadTaskRunnerHandle::Get().get(), mojo::NullRemote());
-    metadata_storage_.reset(new ResourceMetadataStorage(
-        temp_dir_.GetPath(), base::ThreadTaskRunnerHandle::Get().get()));
-    ASSERT_TRUE(metadata_storage_->Initialize());
-
-    cache_.reset(new FileCache(metadata_storage_.get(), temp_dir_.GetPath(),
-                               base::ThreadTaskRunnerHandle::Get().get(),
-                               nullptr /* free_disk_space_getter */));
-    ASSERT_TRUE(cache_->Initialize());
-
-    metadata_.reset(
-        new ResourceMetadata(metadata_storage_.get(), cache_.get(),
-                             base::ThreadTaskRunnerHandle::Get().get()));
-    ASSERT_EQ(FILE_ERROR_OK, metadata_->Initialize());
-
-    start_page_token_loader_ = std::make_unique<StartPageTokenLoader>(
-        empty_team_drive_id_, scheduler_.get());
-  }
-
-  // Adds a new file to the root directory of the service.
-  std::unique_ptr<google_apis::FileResource> AddNewFile(
-      const std::string& title) {
-    google_apis::DriveApiErrorCode error = google_apis::DRIVE_FILE_ERROR;
-    std::unique_ptr<google_apis::FileResource> entry;
-    drive_service_->AddNewFile(
-        "text/plain", "content text", drive_service_->GetRootResourceId(),
-        title,
-        false,  // shared_with_me
-        google_apis::test_util::CreateCopyResultCallback(&error, &entry));
-    base::RunLoop().RunUntilIdle();
-    EXPECT_EQ(google_apis::HTTP_CREATED, error);
-    return entry;
-  }
-
-  // Empty team drive id equates to the users default corpus.
-  const std::string empty_team_drive_id_;
-  content::BrowserTaskEnvironment task_environment_;
-  base::ScopedTempDir temp_dir_;
-  std::unique_ptr<TestingPrefServiceSimple> pref_service_;
-  std::unique_ptr<EventLogger> logger_;
-  std::unique_ptr<FakeDriveService> drive_service_;
-  std::unique_ptr<JobScheduler> scheduler_;
-  std::unique_ptr<ResourceMetadataStorage, test_util::DestroyHelperForTests>
-      metadata_storage_;
-  std::unique_ptr<FileCache, test_util::DestroyHelperForTests> cache_;
-  std::unique_ptr<ResourceMetadata, test_util::DestroyHelperForTests> metadata_;
-  std::unique_ptr<StartPageTokenLoader> start_page_token_loader_;
-};
-
-TEST_F(StartPageTokenLoaderTest, SingleStartPageTokenLoader) {
-  google_apis::DriveApiErrorCode error[6] = {};
-  std::unique_ptr<google_apis::StartPageToken> start_page_token[6];
-
-  EXPECT_EQ(0, drive_service_->start_page_token_load_count());
-
-  ASSERT_FALSE(start_page_token_loader_->cached_start_page_token());
-
-  start_page_token_loader_->GetStartPageToken(
-      google_apis::test_util::CreateCopyResultCallback(error + 0,
-                                                       start_page_token + 0));
-  start_page_token_loader_->GetStartPageToken(
-      google_apis::test_util::CreateCopyResultCallback(error + 1,
-                                                       start_page_token + 1));
-
-  base::RunLoop().RunUntilIdle();
-  EXPECT_EQ(google_apis::HTTP_SUCCESS, error[0]);
-  EXPECT_EQ(google_apis::HTTP_SUCCESS, error[1]);
-  const std::string& first_token = start_page_token[0]->start_page_token();
-  EXPECT_EQ(first_token, start_page_token[1]->start_page_token());
-  ASSERT_TRUE(start_page_token_loader_->cached_start_page_token());
-  ASSERT_EQ(
-      first_token,
-      start_page_token_loader_->cached_start_page_token()->start_page_token());
-
-  // Create a new change, which should change the start page token.
-  AddNewFile("temp");
-
-  start_page_token_loader_->UpdateStartPageToken(
-      google_apis::test_util::CreateCopyResultCallback(error + 2,
-                                                       start_page_token + 2));
-  start_page_token_loader_->GetStartPageToken(
-      google_apis::test_util::CreateCopyResultCallback(error + 3,
-                                                       start_page_token + 3));
-  base::RunLoop().RunUntilIdle();
-  EXPECT_EQ(google_apis::HTTP_SUCCESS, error[2]);
-  EXPECT_EQ(google_apis::HTTP_SUCCESS, error[3]);
-  const std::string& second_token = start_page_token[2]->start_page_token();
-  EXPECT_NE(first_token, second_token);
-  EXPECT_EQ(second_token, start_page_token[3]->start_page_token());
-  ASSERT_EQ(
-      second_token,
-      start_page_token_loader_->cached_start_page_token()->start_page_token());
-
-  // Create a new change, which should change the start page token.
-  AddNewFile("temp2");
-
-  start_page_token_loader_->GetStartPageToken(
-      google_apis::test_util::CreateCopyResultCallback(error + 4,
-                                                       start_page_token + 4));
-  start_page_token_loader_->UpdateStartPageToken(
-      google_apis::test_util::CreateCopyResultCallback(error + 5,
-                                                       start_page_token + 5));
-
-  base::RunLoop().RunUntilIdle();
-  EXPECT_EQ(google_apis::HTTP_NO_CONTENT, error[4]);
-  EXPECT_EQ(google_apis::HTTP_SUCCESS, error[5]);
-  EXPECT_EQ(second_token, start_page_token[4]->start_page_token());
-  const std::string& third_token = start_page_token[5]->start_page_token();
-  EXPECT_NE(first_token, third_token);
-  EXPECT_NE(second_token, third_token);
-  ASSERT_EQ(
-      third_token,
-      start_page_token_loader_->cached_start_page_token()->start_page_token());
-
-  EXPECT_EQ(3, drive_service_->start_page_token_load_count());
-}
-
-}  // namespace internal
-}  // namespace drive
diff --git a/components/drive/sync/entry_revert_performer_unittest.cc b/components/drive/sync/entry_revert_performer_unittest.cc
deleted file mode 100644
index d94d944..0000000
--- a/components/drive/sync/entry_revert_performer_unittest.cc
+++ /dev/null
@@ -1,152 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "components/drive/chromeos/sync/entry_revert_performer.h"
-
-#include <memory>
-
-#include "base/bind.h"
-#include "base/task_runner_util.h"
-#include "components/drive/chromeos/resource_metadata.h"
-#include "components/drive/file_change.h"
-#include "components/drive/file_system/operation_test_base.h"
-#include "components/drive/file_system_core_util.h"
-#include "components/drive/job_scheduler.h"
-#include "components/drive/service/fake_drive_service.h"
-#include "content/public/test/test_utils.h"
-#include "google_apis/drive/test_util.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace drive {
-namespace internal {
-
-class EntryRevertPerformerTest : public file_system::OperationTestBase {
- protected:
-  void SetUp() override {
-   OperationTestBase::SetUp();
-   performer_ = std::make_unique<EntryRevertPerformer>(
-       blocking_task_runner(), delegate(), scheduler(), metadata());
-  }
-
-  std::unique_ptr<EntryRevertPerformer> performer_;
-};
-
-TEST_F(EntryRevertPerformerTest, RevertEntry) {
-  base::FilePath path(
-      FILE_PATH_LITERAL("drive/root/Directory 1/SubDirectory File 1.txt"));
-  base::FilePath updated_path(FILE_PATH_LITERAL(
-      "drive/root/Directory 1/UpdatedSubDirectory File 1.txt"));
-
-  ResourceEntry src_entry;
-  EXPECT_EQ(FILE_ERROR_OK, GetLocalResourceEntry(path, &src_entry));
-
-  // Update local entry.
-  ResourceEntry updated_entry = src_entry;
-  updated_entry.set_title("Updated" + src_entry.title());
-  updated_entry.set_metadata_edit_state(ResourceEntry::DIRTY);
-
-  FileError error = FILE_ERROR_FAILED;
-  base::PostTaskAndReplyWithResult(
-      blocking_task_runner(),
-      FROM_HERE,
-      base::Bind(&ResourceMetadata::RefreshEntry,
-                 base::Unretained(metadata()), updated_entry),
-      google_apis::test_util::CreateCopyResultCallback(&error));
-  content::RunAllTasksUntilIdle();
-  EXPECT_EQ(FILE_ERROR_OK, error);
-
-  // Revert local change.
-  error = FILE_ERROR_FAILED;
-  performer_->RevertEntry(
-      src_entry.local_id(),
-      ClientContext(USER_INITIATED),
-      google_apis::test_util::CreateCopyResultCallback(&error));
-  content::RunAllTasksUntilIdle();
-  EXPECT_EQ(FILE_ERROR_OK, error);
-
-  // Verify local change is reverted.
-  ResourceEntry result_entry;
-  EXPECT_EQ(FILE_ERROR_OK,
-            GetLocalResourceEntryById(src_entry.local_id(), &result_entry));
-  EXPECT_EQ(src_entry.title(), result_entry.title());
-  EXPECT_EQ(ResourceEntry::CLEAN, result_entry.metadata_edit_state());
-
-  EXPECT_EQ(2U, delegate()->get_changed_files().size());
-  EXPECT_TRUE(delegate()->get_changed_files().count(path));
-  EXPECT_TRUE(delegate()->get_changed_files().count(updated_path));
-}
-
-TEST_F(EntryRevertPerformerTest, RevertEntry_NotFoundOnServer) {
-  ResourceEntry my_drive;
-  EXPECT_EQ(FILE_ERROR_OK,
-            GetLocalResourceEntry(util::GetDriveMyDriveRootPath(), &my_drive));
-
-  // Add a new entry with a nonexistent resource ID.
-  ResourceEntry entry;
-  entry.set_title("New File.txt");
-  entry.set_resource_id("non-existent-resource-id");
-  entry.set_parent_local_id(my_drive.local_id());
-
-  FileError error = FILE_ERROR_FAILED;
-  std::string local_id;
-  base::PostTaskAndReplyWithResult(
-      blocking_task_runner(),
-      FROM_HERE,
-      base::Bind(&ResourceMetadata::AddEntry,
-                 base::Unretained(metadata()), entry, &local_id),
-      google_apis::test_util::CreateCopyResultCallback(&error));
-  content::RunAllTasksUntilIdle();
-  EXPECT_EQ(FILE_ERROR_OK, error);
-
-  // Revert local change. The added entry should be removed.
-  error = FILE_ERROR_FAILED;
-  performer_->RevertEntry(
-      local_id,
-      ClientContext(USER_INITIATED),
-      google_apis::test_util::CreateCopyResultCallback(&error));
-  content::RunAllTasksUntilIdle();
-  EXPECT_EQ(FILE_ERROR_OK, error);
-
-  // Verify the entry was deleted locally.
-  EXPECT_EQ(FILE_ERROR_NOT_FOUND, GetLocalResourceEntryById(local_id, &entry));
-
-  EXPECT_EQ(1U, delegate()->get_changed_files().size());
-  EXPECT_TRUE(delegate()->get_changed_files().CountDirectory(
-      util::GetDriveMyDriveRootPath()));
-}
-
-TEST_F(EntryRevertPerformerTest, RevertEntry_TrashedOnServer) {
-  base::FilePath path(
-      FILE_PATH_LITERAL("drive/root/Directory 1/SubDirectory File 1.txt"));
-
-  ResourceEntry entry;
-  EXPECT_EQ(FILE_ERROR_OK, GetLocalResourceEntry(path, &entry));
-
-  // Trash the entry on the server.
-  google_apis::DriveApiErrorCode gdata_error = google_apis::DRIVE_OTHER_ERROR;
-  fake_service()->TrashResource(
-      entry.resource_id(),
-      google_apis::test_util::CreateCopyResultCallback(&gdata_error));
-  content::RunAllTasksUntilIdle();
-  EXPECT_EQ(google_apis::HTTP_SUCCESS, gdata_error);
-
-  // Revert local change. The entry should be removed.
-  FileError error = FILE_ERROR_FAILED;
-  performer_->RevertEntry(
-      entry.local_id(),
-      ClientContext(USER_INITIATED),
-      google_apis::test_util::CreateCopyResultCallback(&error));
-  content::RunAllTasksUntilIdle();
-  EXPECT_EQ(FILE_ERROR_OK, error);
-
-  // Verify the entry was deleted locally.
-  EXPECT_EQ(FILE_ERROR_NOT_FOUND,
-            GetLocalResourceEntryById(entry.local_id(), &entry));
-
-  EXPECT_EQ(1U, delegate()->get_changed_files().size());
-  EXPECT_TRUE(delegate()->get_changed_files().count(path));
-}
-
-}  // namespace internal
-}  // namespace drive
diff --git a/components/drive/sync/entry_update_performer_unittest.cc b/components/drive/sync/entry_update_performer_unittest.cc
deleted file mode 100644
index c79fc9c..0000000
--- a/components/drive/sync/entry_update_performer_unittest.cc
+++ /dev/null
@@ -1,660 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "components/drive/chromeos/sync/entry_update_performer.h"
-
-#include <stdint.h>
-
-#include <memory>
-
-#include "base/bind.h"
-#include "base/callback_helpers.h"
-#include "base/files/file_util.h"
-#include "base/task_runner_util.h"
-#include "components/drive/chromeos/file_cache.h"
-#include "components/drive/chromeos/file_system/download_operation.h"
-#include "components/drive/chromeos/resource_metadata.h"
-#include "components/drive/drive_api_util.h"
-#include "components/drive/file_system/operation_test_base.h"
-#include "components/drive/job_scheduler.h"
-#include "components/drive/service/fake_drive_service.h"
-#include "content/public/test/test_utils.h"
-#include "google_apis/drive/drive_api_parser.h"
-#include "google_apis/drive/test_util.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace drive {
-namespace internal {
-
-class EntryUpdatePerformerTest : public file_system::OperationTestBase {
- protected:
-  void SetUp() override {
-    OperationTestBase::SetUp();
-    performer_ = std::make_unique<EntryUpdatePerformer>(
-        blocking_task_runner(), delegate(), scheduler(), metadata(), cache(),
-        loader_controller());
-  }
-
-  // Stores |content| to the cache and mark it as dirty.
-  FileError StoreAndMarkDirty(const std::string& local_id,
-                              const std::string& content) {
-    base::FilePath path;
-    if (!base::CreateTemporaryFileInDir(temp_dir(), &path) ||
-        !google_apis::test_util::WriteStringToFile(path, content))
-      return FILE_ERROR_FAILED;
-
-    // Store the file to cache.
-    FileError error = FILE_ERROR_FAILED;
-    base::PostTaskAndReplyWithResult(
-        blocking_task_runner(),
-        FROM_HERE,
-        base::Bind(&FileCache::Store,
-                   base::Unretained(cache()),
-                   local_id, std::string(), path,
-                   FileCache::FILE_OPERATION_COPY),
-        google_apis::test_util::CreateCopyResultCallback(&error));
-    content::RunAllTasksUntilIdle();
-    return error;
-  }
-
-  std::unique_ptr<EntryUpdatePerformer> performer_;
-};
-
-TEST_F(EntryUpdatePerformerTest, UpdateEntry) {
-  base::FilePath src_path(
-      FILE_PATH_LITERAL("drive/root/Directory 1/SubDirectory File 1.txt"));
-  base::FilePath dest_path(
-      FILE_PATH_LITERAL("drive/root/Directory 1/Sub Directory Folder"));
-
-  ResourceEntry src_entry, dest_entry;
-  EXPECT_EQ(FILE_ERROR_OK, GetLocalResourceEntry(src_path, &src_entry));
-  EXPECT_EQ(FILE_ERROR_OK, GetLocalResourceEntry(dest_path, &dest_entry));
-
-  // Update local entry.
-  base::Time new_last_modified = base::Time::FromInternalValue(
-      src_entry.file_info().last_modified()) + base::TimeDelta::FromSeconds(1);
-  base::Time new_last_accessed = base::Time::FromInternalValue(
-      src_entry.file_info().last_accessed()) + base::TimeDelta::FromSeconds(2);
-
-  src_entry.set_parent_local_id(dest_entry.local_id());
-  src_entry.set_title("Moved" + src_entry.title());
-  src_entry.mutable_file_info()->set_last_modified(
-      new_last_modified.ToInternalValue());
-  src_entry.mutable_file_info()->set_last_accessed(
-      new_last_accessed.ToInternalValue());
-  src_entry.set_metadata_edit_state(ResourceEntry::DIRTY);
-
-  FileError error = FILE_ERROR_FAILED;
-  base::PostTaskAndReplyWithResult(
-      blocking_task_runner(),
-      FROM_HERE,
-      base::Bind(&ResourceMetadata::RefreshEntry,
-                 base::Unretained(metadata()),
-                 src_entry),
-      google_apis::test_util::CreateCopyResultCallback(&error));
-  content::RunAllTasksUntilIdle();
-  EXPECT_EQ(FILE_ERROR_OK, error);
-
-  // Perform server side update.
-  error = FILE_ERROR_FAILED;
-  performer_->UpdateEntry(
-      src_entry.local_id(),
-      ClientContext(USER_INITIATED),
-      google_apis::test_util::CreateCopyResultCallback(&error));
-  content::RunAllTasksUntilIdle();
-  EXPECT_EQ(FILE_ERROR_OK, error);
-
-  // Verify the file is updated on the server.
-  google_apis::DriveApiErrorCode gdata_error = google_apis::DRIVE_OTHER_ERROR;
-  std::unique_ptr<google_apis::FileResource> gdata_entry;
-  fake_service()->GetFileResource(
-      src_entry.resource_id(),
-      google_apis::test_util::CreateCopyResultCallback(&gdata_error,
-                                                       &gdata_entry));
-  content::RunAllTasksUntilIdle();
-  EXPECT_EQ(google_apis::HTTP_SUCCESS, gdata_error);
-  ASSERT_TRUE(gdata_entry);
-
-  EXPECT_EQ(src_entry.title(), gdata_entry->title());
-  EXPECT_EQ(new_last_modified, gdata_entry->modified_date());
-  EXPECT_EQ(new_last_accessed, gdata_entry->last_viewed_by_me_date());
-
-  ASSERT_FALSE(gdata_entry->parents().empty());
-  EXPECT_EQ(dest_entry.resource_id(), gdata_entry->parents()[0].file_id());
-}
-
-TEST_F(EntryUpdatePerformerTest, UpdateEntry_SetProperties) {
-  base::FilePath entry_path(
-      FILE_PATH_LITERAL("drive/root/Directory 1/SubDirectory File 1.txt"));
-
-  ResourceEntry entry;
-  EXPECT_EQ(FILE_ERROR_OK, GetLocalResourceEntry(entry_path, &entry));
-
-  Property* const first_property = entry.mutable_new_properties()->Add();
-  first_property->set_key("hello");
-  first_property->set_value("world");
-  first_property->set_visibility(Property_Visibility_PUBLIC);
-
-  Property* const second_property = entry.mutable_new_properties()->Add();
-  second_property->set_key("this");
-  second_property->set_value("will-change");
-  second_property->set_visibility(Property_Visibility_PUBLIC);
-  entry.set_metadata_edit_state(ResourceEntry::DIRTY);
-
-  FileError error = FILE_ERROR_FAILED;
-  base::PostTaskAndReplyWithResult(
-      blocking_task_runner(), FROM_HERE,
-      base::Bind(&ResourceMetadata::RefreshEntry, base::Unretained(metadata()),
-                 entry),
-      google_apis::test_util::CreateCopyResultCallback(&error));
-  content::RunAllTasksUntilIdle();
-  EXPECT_EQ(FILE_ERROR_OK, error);
-
-  // Perform server side update.
-  error = FILE_ERROR_FAILED;
-  performer_->UpdateEntry(
-      entry.local_id(), ClientContext(USER_INITIATED),
-      google_apis::test_util::CreateCopyResultCallback(&error));
-
-  // Add a new property during an update.
-  Property* const property = entry.mutable_new_properties()->Add();
-  property->set_key("tokyo");
-  property->set_value("kyoto");
-  property->set_visibility(Property_Visibility_PUBLIC);
-
-  // Modify an existing property during an update.
-  second_property->set_value("changed");
-
-  // Change the resource entry during an update.
-  base::PostTaskAndReplyWithResult(
-      blocking_task_runner(), FROM_HERE,
-      base::Bind(&ResourceMetadata::RefreshEntry, base::Unretained(metadata()),
-                 entry),
-      google_apis::test_util::CreateCopyResultCallback(&error));
-
-  // Wait until the update is fully completed.
-  content::RunAllTasksUntilIdle();
-  EXPECT_EQ(FILE_ERROR_OK, error);
-
-  // List of synced properties should be removed from the proto.
-  EXPECT_EQ(FILE_ERROR_OK, GetLocalResourceEntry(entry_path, &entry));
-  ASSERT_EQ(2, entry.new_properties().size());
-  EXPECT_EQ("changed", entry.new_properties().Get(0).value());
-  EXPECT_EQ("tokyo", entry.new_properties().Get(1).key());
-}
-
-// Tests updating metadata of a file with a non-dirty cache file.
-TEST_F(EntryUpdatePerformerTest, UpdateEntry_WithNonDirtyCache) {
-  base::FilePath src_path(
-      FILE_PATH_LITERAL("drive/root/Directory 1/SubDirectory File 1.txt"));
-
-  // Download the file content to prepare a non-dirty cache file.
-  file_system::DownloadOperation download_operation(
-      blocking_task_runner(), delegate(), scheduler(), metadata(), cache(),
-      temp_dir());
-  FileError error = FILE_ERROR_FAILED;
-  base::FilePath cache_file_path;
-  std::unique_ptr<ResourceEntry> src_entry;
-  download_operation.EnsureFileDownloadedByPath(
-      src_path,
-      ClientContext(USER_INITIATED),
-      GetFileContentInitializedCallback(),
-      google_apis::GetContentCallback(),
-      google_apis::test_util::CreateCopyResultCallback(
-          &error, &cache_file_path, &src_entry));
-  content::RunAllTasksUntilIdle();
-  EXPECT_EQ(FILE_ERROR_OK, error);
-  ASSERT_TRUE(src_entry);
-
-  // Update the entry locally.
-  src_entry->set_title("Updated" + src_entry->title());
-  src_entry->set_metadata_edit_state(ResourceEntry::DIRTY);
-
-  error = FILE_ERROR_FAILED;
-  base::PostTaskAndReplyWithResult(
-      blocking_task_runner(),
-      FROM_HERE,
-      base::Bind(&ResourceMetadata::RefreshEntry,
-                 base::Unretained(metadata()),
-                 *src_entry),
-      google_apis::test_util::CreateCopyResultCallback(&error));
-  content::RunAllTasksUntilIdle();
-  EXPECT_EQ(FILE_ERROR_OK, error);
-
-  // Perform server side update. This shouldn't fail. (crbug.com/358590)
-  error = FILE_ERROR_FAILED;
-  performer_->UpdateEntry(
-      src_entry->local_id(),
-      ClientContext(USER_INITIATED),
-      google_apis::test_util::CreateCopyResultCallback(&error));
-  content::RunAllTasksUntilIdle();
-  EXPECT_EQ(FILE_ERROR_OK, error);
-
-  // Verify the file is updated on the server.
-  google_apis::DriveApiErrorCode gdata_error = google_apis::DRIVE_OTHER_ERROR;
-  std::unique_ptr<google_apis::FileResource> gdata_entry;
-  fake_service()->GetFileResource(
-      src_entry->resource_id(),
-      google_apis::test_util::CreateCopyResultCallback(&gdata_error,
-                                                       &gdata_entry));
-  content::RunAllTasksUntilIdle();
-  EXPECT_EQ(google_apis::HTTP_SUCCESS, gdata_error);
-  ASSERT_TRUE(gdata_entry);
-  EXPECT_EQ(src_entry->title(), gdata_entry->title());
-}
-
-TEST_F(EntryUpdatePerformerTest, UpdateEntry_NotFound) {
-  const std::string id = "this ID should result in NOT_FOUND";
-  FileError error = FILE_ERROR_FAILED;
-  performer_->UpdateEntry(
-      id, ClientContext(USER_INITIATED),
-      google_apis::test_util::CreateCopyResultCallback(&error));
-  content::RunAllTasksUntilIdle();
-  EXPECT_EQ(FILE_ERROR_NOT_FOUND, error);
-}
-
-TEST_F(EntryUpdatePerformerTest, UpdateEntry_ContentUpdate) {
-  const base::FilePath kFilePath(FILE_PATH_LITERAL("drive/root/File 1.txt"));
-  const std::string kResourceId("2_file_resource_id");
-
-  const std::string local_id = GetLocalId(kFilePath);
-  EXPECT_FALSE(local_id.empty());
-
-  const std::string kTestFileContent = "I'm being uploaded! Yay!";
-  EXPECT_EQ(FILE_ERROR_OK, StoreAndMarkDirty(local_id, kTestFileContent));
-
-  const std::string original_start_page_token =
-      fake_service()->start_page_token().start_page_token();
-
-  // The callback will be called upon completion of UpdateEntry().
-  FileError error = FILE_ERROR_FAILED;
-  performer_->UpdateEntry(
-      local_id,
-      ClientContext(USER_INITIATED),
-      google_apis::test_util::CreateCopyResultCallback(&error));
-  content::RunAllTasksUntilIdle();
-  EXPECT_EQ(FILE_ERROR_OK, error);
-
-  // Check that the server has received an update.
-  EXPECT_NE(original_start_page_token,
-            fake_service()->start_page_token().start_page_token());
-
-  // Check that the file size is updated to that of the updated content.
-  google_apis::DriveApiErrorCode gdata_error = google_apis::DRIVE_OTHER_ERROR;
-  std::unique_ptr<google_apis::FileResource> server_entry;
-  fake_service()->GetFileResource(
-      kResourceId,
-      google_apis::test_util::CreateCopyResultCallback(&gdata_error,
-                                                       &server_entry));
-  content::RunAllTasksUntilIdle();
-  EXPECT_EQ(google_apis::HTTP_SUCCESS, gdata_error);
-  EXPECT_EQ(static_cast<int64_t>(kTestFileContent.size()),
-            server_entry->file_size());
-
-  // Make sure that the cache is no longer dirty.
-  ResourceEntry entry;
-  EXPECT_EQ(FILE_ERROR_OK, GetLocalResourceEntry(kFilePath, &entry));
-  EXPECT_FALSE(entry.file_specific_info().cache_state().is_dirty());
-}
-
-TEST_F(EntryUpdatePerformerTest, UpdateEntry_ContentUpdateMd5Check) {
-  const base::FilePath kFilePath(FILE_PATH_LITERAL("drive/root/File 1.txt"));
-  const std::string kResourceId("2_file_resource_id");
-
-  const std::string local_id = GetLocalId(kFilePath);
-  EXPECT_FALSE(local_id.empty());
-
-  const std::string kTestFileContent = "I'm being uploaded! Yay!";
-  EXPECT_EQ(FILE_ERROR_OK, StoreAndMarkDirty(local_id, kTestFileContent));
-
-  std::string original_start_page_token =
-      fake_service()->start_page_token().start_page_token();
-
-  // The callback will be called upon completion of UpdateEntry().
-  FileError error = FILE_ERROR_FAILED;
-  performer_->UpdateEntry(
-      local_id,
-      ClientContext(USER_INITIATED),
-      google_apis::test_util::CreateCopyResultCallback(&error));
-  content::RunAllTasksUntilIdle();
-  EXPECT_EQ(FILE_ERROR_OK, error);
-
-  // Check that the server has received an update.
-  EXPECT_NE(original_start_page_token,
-            fake_service()->start_page_token().start_page_token());
-
-  // Check that the file size is updated to that of the updated content.
-  google_apis::DriveApiErrorCode gdata_error = google_apis::DRIVE_OTHER_ERROR;
-  std::unique_ptr<google_apis::FileResource> server_entry;
-  fake_service()->GetFileResource(
-      kResourceId,
-      google_apis::test_util::CreateCopyResultCallback(&gdata_error,
-                                                       &server_entry));
-  content::RunAllTasksUntilIdle();
-  EXPECT_EQ(google_apis::HTTP_SUCCESS, gdata_error);
-  EXPECT_EQ(static_cast<int64_t>(kTestFileContent.size()),
-            server_entry->file_size());
-
-  // Make sure that the cache is no longer dirty.
-  ResourceEntry entry;
-  EXPECT_EQ(FILE_ERROR_OK, GetLocalResourceEntry(kFilePath, &entry));
-  EXPECT_FALSE(entry.file_specific_info().cache_state().is_dirty());
-
-  // Again mark the cache file dirty.
-  std::unique_ptr<base::ScopedClosureRunner> file_closer;
-  error = FILE_ERROR_FAILED;
-  base::PostTaskAndReplyWithResult(
-      blocking_task_runner(),
-      FROM_HERE,
-      base::Bind(&FileCache::OpenForWrite,
-                 base::Unretained(cache()),
-                 local_id,
-                 &file_closer),
-      google_apis::test_util::CreateCopyResultCallback(&error));
-  content::RunAllTasksUntilIdle();
-  EXPECT_EQ(FILE_ERROR_OK, error);
-  file_closer.reset();
-
-  // And call UpdateEntry again.
-  // In this case, although the file is marked as dirty, but the content
-  // hasn't been changed. Thus, the actual uploading should be skipped.
-  original_start_page_token =
-      fake_service()->start_page_token().start_page_token();
-  error = FILE_ERROR_FAILED;
-  performer_->UpdateEntry(
-      local_id,
-      ClientContext(USER_INITIATED),
-      google_apis::test_util::CreateCopyResultCallback(&error));
-  content::RunAllTasksUntilIdle();
-  EXPECT_EQ(FILE_ERROR_OK, error);
-
-  EXPECT_EQ(original_start_page_token,
-            fake_service()->start_page_token().start_page_token());
-
-  // Make sure that the cache is no longer dirty.
-  EXPECT_EQ(FILE_ERROR_OK, GetLocalResourceEntry(kFilePath, &entry));
-  EXPECT_FALSE(entry.file_specific_info().cache_state().is_dirty());
-}
-
-TEST_F(EntryUpdatePerformerTest, UpdateEntry_OpenedForWrite) {
-  const base::FilePath kFilePath(FILE_PATH_LITERAL("drive/root/File 1.txt"));
-  const std::string kResourceId("2_file_resource_id");
-
-  const std::string local_id = GetLocalId(kFilePath);
-  EXPECT_FALSE(local_id.empty());
-
-  const std::string kTestFileContent = "I'm being uploaded! Yay!";
-  EXPECT_EQ(FILE_ERROR_OK, StoreAndMarkDirty(local_id, kTestFileContent));
-
-  // Emulate a situation where someone is writing to the file.
-  std::unique_ptr<base::ScopedClosureRunner> file_closer;
-  FileError error = FILE_ERROR_FAILED;
-  base::PostTaskAndReplyWithResult(
-      blocking_task_runner(),
-      FROM_HERE,
-      base::Bind(&FileCache::OpenForWrite,
-                 base::Unretained(cache()),
-                 local_id,
-                 &file_closer),
-      google_apis::test_util::CreateCopyResultCallback(&error));
-  content::RunAllTasksUntilIdle();
-  EXPECT_EQ(FILE_ERROR_OK, error);
-
-  // Update. This should not clear the dirty bit.
-  error = FILE_ERROR_FAILED;
-  performer_->UpdateEntry(
-      local_id,
-      ClientContext(USER_INITIATED),
-      google_apis::test_util::CreateCopyResultCallback(&error));
-  content::RunAllTasksUntilIdle();
-  EXPECT_EQ(FILE_ERROR_OK, error);
-
-  // Make sure that the cache is still dirty.
-  ResourceEntry entry;
-  EXPECT_EQ(FILE_ERROR_OK, GetLocalResourceEntry(kFilePath, &entry));
-  EXPECT_TRUE(entry.file_specific_info().cache_state().is_dirty());
-
-  // Close the file.
-  file_closer.reset();
-
-  // Update. This should clear the dirty bit.
-  error = FILE_ERROR_FAILED;
-  performer_->UpdateEntry(
-      local_id,
-      ClientContext(USER_INITIATED),
-      google_apis::test_util::CreateCopyResultCallback(&error));
-  content::RunAllTasksUntilIdle();
-  EXPECT_EQ(FILE_ERROR_OK, error);
-
-  // Make sure that the cache is no longer dirty.
-  EXPECT_EQ(FILE_ERROR_OK, GetLocalResourceEntry(kFilePath, &entry));
-  EXPECT_FALSE(entry.file_specific_info().cache_state().is_dirty());
-}
-
-TEST_F(EntryUpdatePerformerTest, UpdateEntry_UploadNewFile) {
-  // Create a new file locally.
-  const base::FilePath kFilePath(FILE_PATH_LITERAL("drive/root/New File.txt"));
-
-  ResourceEntry parent;
-  EXPECT_EQ(FILE_ERROR_OK, GetLocalResourceEntry(kFilePath.DirName(), &parent));
-
-  ResourceEntry entry;
-  entry.set_parent_local_id(parent.local_id());
-  entry.set_title(kFilePath.BaseName().AsUTF8Unsafe());
-  entry.mutable_file_specific_info()->set_content_mime_type("text/plain");
-  entry.set_metadata_edit_state(ResourceEntry::DIRTY);
-
-  FileError error = FILE_ERROR_FAILED;
-  std::string local_id;
-  base::PostTaskAndReplyWithResult(
-      blocking_task_runner(),
-      FROM_HERE,
-      base::Bind(&internal::ResourceMetadata::AddEntry,
-                 base::Unretained(metadata()),
-                 entry,
-                 &local_id),
-      google_apis::test_util::CreateCopyResultCallback(&error));
-  content::RunAllTasksUntilIdle();
-  EXPECT_EQ(FILE_ERROR_OK, error);
-
-  // Update. This should result in creating a new file on the server.
-  error = FILE_ERROR_FAILED;
-  performer_->UpdateEntry(
-      local_id,
-      ClientContext(USER_INITIATED),
-      google_apis::test_util::CreateCopyResultCallback(&error));
-  content::RunAllTasksUntilIdle();
-  EXPECT_EQ(FILE_ERROR_OK, error);
-
-  // The entry got a resource ID.
-  EXPECT_EQ(FILE_ERROR_OK, GetLocalResourceEntry(kFilePath, &entry));
-  EXPECT_FALSE(entry.resource_id().empty());
-  EXPECT_EQ(ResourceEntry::CLEAN, entry.metadata_edit_state());
-
-  // Make sure that the cache is no longer dirty.
-  EXPECT_FALSE(entry.file_specific_info().cache_state().is_dirty());
-
-  // Make sure that we really created a file.
-  google_apis::DriveApiErrorCode status = google_apis::DRIVE_OTHER_ERROR;
-  std::unique_ptr<google_apis::FileResource> server_entry;
-  fake_service()->GetFileResource(
-      entry.resource_id(),
-      google_apis::test_util::CreateCopyResultCallback(&status, &server_entry));
-  content::RunAllTasksUntilIdle();
-  EXPECT_EQ(google_apis::HTTP_SUCCESS, status);
-  ASSERT_TRUE(server_entry);
-  EXPECT_FALSE(server_entry->IsDirectory());
-}
-
-TEST_F(EntryUpdatePerformerTest, UpdateEntry_NewFileOpendForWrite) {
-  // Create a new file locally.
-  const base::FilePath kFilePath(FILE_PATH_LITERAL("drive/root/New File.txt"));
-
-  ResourceEntry parent;
-  EXPECT_EQ(FILE_ERROR_OK, GetLocalResourceEntry(kFilePath.DirName(), &parent));
-
-  ResourceEntry entry;
-  entry.set_parent_local_id(parent.local_id());
-  entry.set_title(kFilePath.BaseName().AsUTF8Unsafe());
-  entry.mutable_file_specific_info()->set_content_mime_type("text/plain");
-  entry.set_metadata_edit_state(ResourceEntry::DIRTY);
-
-  FileError error = FILE_ERROR_FAILED;
-  std::string local_id;
-  base::PostTaskAndReplyWithResult(
-      blocking_task_runner(),
-      FROM_HERE,
-      base::Bind(&internal::ResourceMetadata::AddEntry,
-                 base::Unretained(metadata()),
-                 entry,
-                 &local_id),
-      google_apis::test_util::CreateCopyResultCallback(&error));
-  content::RunAllTasksUntilIdle();
-  EXPECT_EQ(FILE_ERROR_OK, error);
-
-  const std::string kTestFileContent = "This is a new file.";
-  EXPECT_EQ(FILE_ERROR_OK, StoreAndMarkDirty(local_id, kTestFileContent));
-
-  // Emulate a situation where someone is writing to the file.
-  std::unique_ptr<base::ScopedClosureRunner> file_closer;
-  error = FILE_ERROR_FAILED;
-  base::PostTaskAndReplyWithResult(
-      blocking_task_runner(),
-      FROM_HERE,
-      base::Bind(&FileCache::OpenForWrite,
-                 base::Unretained(cache()),
-                 local_id,
-                 &file_closer),
-      google_apis::test_util::CreateCopyResultCallback(&error));
-  content::RunAllTasksUntilIdle();
-  EXPECT_EQ(FILE_ERROR_OK, error);
-
-  // Update, but no update is performed because the file is opened.
-  error = FILE_ERROR_FAILED;
-  performer_->UpdateEntry(
-      local_id,
-      ClientContext(USER_INITIATED),
-      google_apis::test_util::CreateCopyResultCallback(&error));
-  content::RunAllTasksUntilIdle();
-  EXPECT_EQ(FILE_ERROR_OK, error);
-
-  // The entry hasn't got a resource ID yet.
-  EXPECT_EQ(FILE_ERROR_OK, GetLocalResourceEntry(kFilePath, &entry));
-  EXPECT_TRUE(entry.resource_id().empty());
-
-  // Close the file.
-  file_closer.reset();
-
-  // Update. This should result in creating a new file on the server.
-  error = FILE_ERROR_FAILED;
-  performer_->UpdateEntry(
-      local_id,
-      ClientContext(USER_INITIATED),
-      google_apis::test_util::CreateCopyResultCallback(&error));
-  content::RunAllTasksUntilIdle();
-  EXPECT_EQ(FILE_ERROR_OK, error);
-
-  // The entry got a resource ID.
-  EXPECT_EQ(FILE_ERROR_OK, GetLocalResourceEntry(kFilePath, &entry));
-  EXPECT_FALSE(entry.resource_id().empty());
-  EXPECT_EQ(ResourceEntry::CLEAN, entry.metadata_edit_state());
-}
-
-TEST_F(EntryUpdatePerformerTest, UpdateEntry_CreateDirectory) {
-  // Create a new directory locally.
-  const base::FilePath kPath(FILE_PATH_LITERAL("drive/root/New Directory"));
-
-  ResourceEntry parent;
-  EXPECT_EQ(FILE_ERROR_OK, GetLocalResourceEntry(kPath.DirName(), &parent));
-
-  ResourceEntry entry;
-  entry.set_parent_local_id(parent.local_id());
-  entry.set_title(kPath.BaseName().AsUTF8Unsafe());
-  entry.mutable_file_info()->set_is_directory(true);
-  entry.set_metadata_edit_state(ResourceEntry::DIRTY);
-
-  FileError error = FILE_ERROR_FAILED;
-  std::string local_id;
-  base::PostTaskAndReplyWithResult(
-      blocking_task_runner(),
-      FROM_HERE,
-      base::Bind(&internal::ResourceMetadata::AddEntry,
-                 base::Unretained(metadata()),
-                 entry,
-                 &local_id),
-      google_apis::test_util::CreateCopyResultCallback(&error));
-  content::RunAllTasksUntilIdle();
-  EXPECT_EQ(FILE_ERROR_OK, error);
-
-  // Update. This should result in creating a new directory on the server.
-  error = FILE_ERROR_FAILED;
-  performer_->UpdateEntry(
-      local_id,
-      ClientContext(USER_INITIATED),
-      google_apis::test_util::CreateCopyResultCallback(&error));
-  content::RunAllTasksUntilIdle();
-  EXPECT_EQ(FILE_ERROR_OK, error);
-
-  // The entry got a resource ID.
-  EXPECT_EQ(FILE_ERROR_OK, GetLocalResourceEntry(kPath, &entry));
-  EXPECT_FALSE(entry.resource_id().empty());
-  EXPECT_EQ(ResourceEntry::CLEAN, entry.metadata_edit_state());
-
-  // Make sure that we really created a directory.
-  google_apis::DriveApiErrorCode status = google_apis::DRIVE_OTHER_ERROR;
-  std::unique_ptr<google_apis::FileResource> server_entry;
-  fake_service()->GetFileResource(
-      entry.resource_id(),
-      google_apis::test_util::CreateCopyResultCallback(&status, &server_entry));
-  content::RunAllTasksUntilIdle();
-  EXPECT_EQ(google_apis::HTTP_SUCCESS, status);
-  ASSERT_TRUE(server_entry);
-  EXPECT_TRUE(server_entry->IsDirectory());
-}
-
-TEST_F(EntryUpdatePerformerTest, UpdateEntry_InsufficientPermission) {
-  base::FilePath src_path(
-      FILE_PATH_LITERAL("drive/root/Directory 1/SubDirectory File 1.txt"));
-
-  ResourceEntry src_entry;
-  EXPECT_EQ(FILE_ERROR_OK, GetLocalResourceEntry(src_path, &src_entry));
-
-  // Update local entry.
-  ResourceEntry updated_entry(src_entry);
-  updated_entry.set_title("Moved" + src_entry.title());
-  updated_entry.set_metadata_edit_state(ResourceEntry::DIRTY);
-
-  FileError error = FILE_ERROR_FAILED;
-  base::PostTaskAndReplyWithResult(
-      blocking_task_runner(),
-      FROM_HERE,
-      base::Bind(&ResourceMetadata::RefreshEntry,
-                 base::Unretained(metadata()),
-                 updated_entry),
-      google_apis::test_util::CreateCopyResultCallback(&error));
-  content::RunAllTasksUntilIdle();
-  EXPECT_EQ(FILE_ERROR_OK, error);
-
-  // Set user permission to forbid server side update.
-  EXPECT_EQ(google_apis::HTTP_SUCCESS, fake_service()->SetUserPermission(
-      src_entry.resource_id(), google_apis::drive::PERMISSION_ROLE_READER));
-
-  // Try to perform update.
-  error = FILE_ERROR_FAILED;
-  performer_->UpdateEntry(
-      src_entry.local_id(),
-      ClientContext(USER_INITIATED),
-      google_apis::test_util::CreateCopyResultCallback(&error));
-  content::RunAllTasksUntilIdle();
-  EXPECT_EQ(FILE_ERROR_OK, error);
-
-  // This should result in reverting the local change.
-  ResourceEntry result_entry;
-  EXPECT_EQ(FILE_ERROR_OK,
-            GetLocalResourceEntryById(src_entry.local_id(), &result_entry));
-  EXPECT_EQ(src_entry.title(), result_entry.title());
-}
-
-}  // namespace internal
-}  // namespace drive
diff --git a/components/drive/sync/remove_performer_unittest.cc b/components/drive/sync/remove_performer_unittest.cc
deleted file mode 100644
index 28f99c6d..0000000
--- a/components/drive/sync/remove_performer_unittest.cc
+++ /dev/null
@@ -1,200 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "components/drive/chromeos/sync/remove_performer.h"
-
-#include "base/bind.h"
-#include "base/task_runner_util.h"
-#include "components/drive/chromeos/resource_metadata.h"
-#include "components/drive/file_system/operation_test_base.h"
-#include "components/drive/file_system_core_util.h"
-#include "components/drive/job_scheduler.h"
-#include "components/drive/service/fake_drive_service.h"
-#include "content/public/test/test_utils.h"
-#include "google_apis/drive/drive_api_parser.h"
-#include "google_apis/drive/test_util.h"
-
-namespace drive {
-namespace internal {
-
-typedef file_system::OperationTestBase RemovePerformerTest;
-
-TEST_F(RemovePerformerTest, RemoveFile) {
-  RemovePerformer performer(blocking_task_runner(), delegate(), scheduler(),
-                            metadata());
-
-  base::FilePath file_in_root(FILE_PATH_LITERAL("drive/root/File 1.txt"));
-  base::FilePath file_in_subdir(
-      FILE_PATH_LITERAL("drive/root/Directory 1/SubDirectory File 1.txt"));
-
-  // Remove a file in root.
-  ResourceEntry entry;
-  FileError error = FILE_ERROR_FAILED;
-  ASSERT_EQ(FILE_ERROR_OK, GetLocalResourceEntry(file_in_root, &entry));
-  performer.Remove(entry.local_id(),
-                   ClientContext(USER_INITIATED),
-                   google_apis::test_util::CreateCopyResultCallback(&error));
-  content::RunAllTasksUntilIdle();
-  EXPECT_EQ(FILE_ERROR_OK, error);
-
-  // Remove a file in subdirectory.
-  error = FILE_ERROR_FAILED;
-  ASSERT_EQ(FILE_ERROR_OK, GetLocalResourceEntry(file_in_subdir, &entry));
-  const std::string resource_id = entry.resource_id();
-
-  performer.Remove(entry.local_id(),
-                   ClientContext(USER_INITIATED),
-                   google_apis::test_util::CreateCopyResultCallback(&error));
-  content::RunAllTasksUntilIdle();
-  EXPECT_EQ(FILE_ERROR_OK, error);
-
-  // Verify the file is indeed removed in the server.
-  google_apis::DriveApiErrorCode gdata_error = google_apis::DRIVE_OTHER_ERROR;
-  std::unique_ptr<google_apis::FileResource> gdata_entry;
-  fake_service()->GetFileResource(
-      resource_id,
-      google_apis::test_util::CreateCopyResultCallback(&gdata_error,
-                                                       &gdata_entry));
-  content::RunAllTasksUntilIdle();
-  ASSERT_EQ(google_apis::HTTP_SUCCESS, gdata_error);
-  EXPECT_TRUE(gdata_entry->labels().is_trashed());
-
-  // Try removing non-existing file.
-  error = FILE_ERROR_FAILED;
-  performer.Remove("non-existing-id",
-                   ClientContext(USER_INITIATED),
-                   google_apis::test_util::CreateCopyResultCallback(&error));
-  content::RunAllTasksUntilIdle();
-  EXPECT_EQ(FILE_ERROR_NOT_FOUND, error);
-}
-
-TEST_F(RemovePerformerTest, RemoveShared) {
-  RemovePerformer performer(blocking_task_runner(), delegate(), scheduler(),
-                            metadata());
-
-  const base::FilePath kPathInMyDrive(FILE_PATH_LITERAL(
-      "drive/root/shared.txt"));
-  const base::FilePath kPathInOther(FILE_PATH_LITERAL(
-      "drive/other/shared.txt"));
-
-  // Prepare a shared file to the root folder.
-  google_apis::DriveApiErrorCode gdata_error = google_apis::DRIVE_OTHER_ERROR;
-  std::unique_ptr<google_apis::FileResource> gdata_entry;
-  fake_service()->AddNewFile(
-      "text/plain",
-      "dummy content",
-      fake_service()->GetRootResourceId(),
-      kPathInMyDrive.BaseName().AsUTF8Unsafe(),
-      true,  // shared_with_me,
-      google_apis::test_util::CreateCopyResultCallback(&gdata_error,
-                                                       &gdata_entry));
-  content::RunAllTasksUntilIdle();
-  ASSERT_EQ(google_apis::HTTP_CREATED, gdata_error);
-  CheckForUpdates();
-
-  // Remove it. Locally, the file should be moved to drive/other.
-  ResourceEntry entry;
-  ASSERT_EQ(FILE_ERROR_OK, GetLocalResourceEntry(kPathInMyDrive, &entry));
-  FileError error = FILE_ERROR_FAILED;
-  performer.Remove(entry.local_id(),
-                   ClientContext(USER_INITIATED),
-                   google_apis::test_util::CreateCopyResultCallback(&error));
-  content::RunAllTasksUntilIdle();
-  EXPECT_EQ(FILE_ERROR_OK, error);
-  EXPECT_EQ(FILE_ERROR_NOT_FOUND,
-            GetLocalResourceEntry(kPathInMyDrive, &entry));
-  EXPECT_EQ(FILE_ERROR_OK, GetLocalResourceEntry(kPathInOther, &entry));
-
-  // Remotely, the entry should have lost its parent.
-  gdata_error = google_apis::DRIVE_OTHER_ERROR;
-  const std::string resource_id = gdata_entry->file_id();
-  fake_service()->GetFileResource(
-      resource_id,
-      google_apis::test_util::CreateCopyResultCallback(&gdata_error,
-                                                       &gdata_entry));
-  content::RunAllTasksUntilIdle();
-  ASSERT_EQ(google_apis::HTTP_SUCCESS, gdata_error);
-  EXPECT_FALSE(gdata_entry->labels().is_trashed());  // It's not deleted.
-  EXPECT_TRUE(gdata_entry->parents().empty());
-}
-
-TEST_F(RemovePerformerTest, RemoveLocallyCreatedFile) {
-  RemovePerformer performer(blocking_task_runner(), delegate(), scheduler(),
-                            metadata());
-
-  // Add an entry without resource ID.
-  ResourceEntry entry;
-  entry.set_title("New File.txt");
-  entry.set_parent_local_id(util::kDriveTrashDirLocalId);
-
-  FileError error = FILE_ERROR_FAILED;
-  std::string local_id;
-  base::PostTaskAndReplyWithResult(
-      blocking_task_runner(),
-      FROM_HERE,
-      base::Bind(&ResourceMetadata::AddEntry,
-                 base::Unretained(metadata()),
-                 entry,
-                 &local_id),
-      google_apis::test_util::CreateCopyResultCallback(&error));
-  content::RunAllTasksUntilIdle();
-  EXPECT_EQ(FILE_ERROR_OK, error);
-
-  // Remove the entry.
-  performer.Remove(local_id, ClientContext(USER_INITIATED),
-                   google_apis::test_util::CreateCopyResultCallback(&error));
-  content::RunAllTasksUntilIdle();
-  EXPECT_EQ(FILE_ERROR_OK, error);
-  EXPECT_EQ(FILE_ERROR_NOT_FOUND, GetLocalResourceEntryById(local_id, &entry));
-}
-
-TEST_F(RemovePerformerTest, Remove_InsufficientPermission) {
-  RemovePerformer performer(blocking_task_runner(), delegate(), scheduler(),
-                            metadata());
-
-  base::FilePath file_in_root(FILE_PATH_LITERAL("drive/root/File 1.txt"));
-
-  ResourceEntry src_entry;
-  ASSERT_EQ(FILE_ERROR_OK, GetLocalResourceEntry(file_in_root, &src_entry));
-
-  // Remove locally.
-  ResourceEntry updated_entry(src_entry);
-  updated_entry.set_parent_local_id(util::kDriveTrashDirLocalId);
-
-  FileError error = FILE_ERROR_FAILED;
-  base::PostTaskAndReplyWithResult(
-      blocking_task_runner(),
-      FROM_HERE,
-      base::Bind(&ResourceMetadata::RefreshEntry,
-                 base::Unretained(metadata()),
-                 updated_entry),
-      google_apis::test_util::CreateCopyResultCallback(&error));
-  content::RunAllTasksUntilIdle();
-  EXPECT_EQ(FILE_ERROR_OK, error);
-
-  // Set user permission to forbid server side update.
-  EXPECT_EQ(google_apis::HTTP_SUCCESS, fake_service()->SetUserPermission(
-      src_entry.resource_id(), google_apis::drive::PERMISSION_ROLE_READER));
-
-  // Try to perform remove.
-  error = FILE_ERROR_FAILED;
-  performer.Remove(src_entry.local_id(),
-                   ClientContext(USER_INITIATED),
-                   google_apis::test_util::CreateCopyResultCallback(&error));
-  content::RunAllTasksUntilIdle();
-  EXPECT_EQ(FILE_ERROR_OK, error);
-
-  // This should result in reverting the local change.
-  ResourceEntry result_entry;
-  EXPECT_EQ(FILE_ERROR_OK,
-            GetLocalResourceEntryById(src_entry.local_id(), &result_entry));
-  EXPECT_EQ(src_entry.parent_local_id(), result_entry.parent_local_id());
-
-  ASSERT_EQ(1U, delegate()->drive_sync_errors().size());
-  EXPECT_EQ(file_system::DRIVE_SYNC_ERROR_DELETE_WITHOUT_PERMISSION,
-            delegate()->drive_sync_errors()[0]);
-}
-
-}  // namespace internal
-}  // namespace drive
diff --git a/components/drive/sync_client_unittest.cc b/components/drive/sync_client_unittest.cc
deleted file mode 100644
index 111378bf..0000000
--- a/components/drive/sync_client_unittest.cc
+++ /dev/null
@@ -1,530 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "components/drive/chromeos/sync_client.h"
-
-#include <memory>
-
-#include "base/bind.h"
-#include "base/files/file_path.h"
-#include "base/files/file_util.h"
-#include "base/files/scoped_temp_dir.h"
-#include "base/run_loop.h"
-#include "base/single_thread_task_runner.h"
-#include "base/test/test_timeouts.h"
-#include "base/threading/thread_task_runner_handle.h"
-#include "components/drive/chromeos/about_resource_loader.h"
-#include "components/drive/chromeos/about_resource_root_folder_id_loader.h"
-#include "components/drive/chromeos/change_list_loader.h"
-#include "components/drive/chromeos/drive_test_util.h"
-#include "components/drive/chromeos/fake_free_disk_space_getter.h"
-#include "components/drive/chromeos/file_cache.h"
-#include "components/drive/chromeos/file_system/move_operation.h"
-#include "components/drive/chromeos/file_system/operation_delegate.h"
-#include "components/drive/chromeos/file_system/remove_operation.h"
-#include "components/drive/chromeos/loader_controller.h"
-#include "components/drive/chromeos/resource_metadata.h"
-#include "components/drive/chromeos/start_page_token_loader.h"
-#include "components/drive/drive.pb.h"
-#include "components/drive/event_logger.h"
-#include "components/drive/file_change.h"
-#include "components/drive/file_system_core_util.h"
-#include "components/drive/job_scheduler.h"
-#include "components/drive/resource_entry_conversion.h"
-#include "components/drive/service/fake_drive_service.h"
-#include "components/prefs/testing_pref_service.h"
-#include "content/public/test/browser_task_environment.h"
-#include "google_apis/drive/drive_api_parser.h"
-#include "google_apis/drive/test_util.h"
-#include "mojo/public/cpp/bindings/pending_remote.h"
-#include "services/network/test/test_network_connection_tracker.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace drive {
-namespace internal {
-
-namespace {
-
-// The content of files initially stored in the cache.
-const char kLocalContent[] = "Hello!";
-
-// The content of files stored in the service.
-const char kRemoteContent[] = "World!";
-
-// SyncClientTestDriveService will return DRIVE_CANCELLED when a request is
-// made with the specified resource ID.
-class SyncClientTestDriveService : public ::drive::FakeDriveService {
- public:
-  SyncClientTestDriveService() : download_file_count_(0) {}
-
-  // FakeDriveService override:
-  google_apis::CancelCallback DownloadFile(
-      const base::FilePath& local_cache_path,
-      const std::string& resource_id,
-      const google_apis::DownloadActionCallback& download_action_callback,
-      const google_apis::GetContentCallback& get_content_callback,
-      const google_apis::ProgressCallback& progress_callback) override {
-    ++download_file_count_;
-    if (resource_id == resource_id_to_be_cancelled_) {
-      base::ThreadTaskRunnerHandle::Get()->PostTask(
-          FROM_HERE,
-          base::BindOnce(download_action_callback, google_apis::DRIVE_CANCELLED,
-                         base::FilePath()));
-      return google_apis::CancelCallback();
-    }
-    if (resource_id == resource_id_to_be_paused_) {
-      paused_action_ = base::Bind(download_action_callback,
-                                  google_apis::DRIVE_OTHER_ERROR,
-                                  base::FilePath());
-      return google_apis::CancelCallback();
-    }
-    return FakeDriveService::DownloadFile(local_cache_path,
-                                          resource_id,
-                                          download_action_callback,
-                                          get_content_callback,
-                                          progress_callback);
-  }
-
-  int download_file_count() const { return download_file_count_; }
-
-  void set_resource_id_to_be_cancelled(const std::string& resource_id) {
-    resource_id_to_be_cancelled_ = resource_id;
-  }
-
-  void set_resource_id_to_be_paused(const std::string& resource_id) {
-    resource_id_to_be_paused_ = resource_id;
-  }
-
-  const base::Closure& paused_action() const { return paused_action_; }
-
- private:
-  int download_file_count_;
-  std::string resource_id_to_be_cancelled_;
-  std::string resource_id_to_be_paused_;
-  base::Closure paused_action_;
-};
-
-}  // namespace
-
-class SyncClientTest : public testing::Test {
- public:
-  void SetUp() override {
-    ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
-
-    pref_service_ = std::make_unique<TestingPrefServiceSimple>();
-    test_util::RegisterDrivePrefs(pref_service_->registry());
-
-    logger_ = std::make_unique<EventLogger>();
-
-    drive_service_ = std::make_unique<SyncClientTestDriveService>();
-
-    network::TestNetworkConnectionTracker::GetInstance()->SetConnectionType(
-        network::mojom::ConnectionType::CONNECTION_WIFI);
-    scheduler_ = std::make_unique<JobScheduler>(
-        pref_service_.get(), logger_.get(), drive_service_.get(),
-        network::TestNetworkConnectionTracker::GetInstance(),
-        base::ThreadTaskRunnerHandle::Get().get(), mojo::NullRemote());
-
-    metadata_storage_.reset(new ResourceMetadataStorage(
-        temp_dir_.GetPath(), base::ThreadTaskRunnerHandle::Get().get()));
-    ASSERT_TRUE(metadata_storage_->Initialize());
-
-    cache_.reset(new FileCache(metadata_storage_.get(), temp_dir_.GetPath(),
-                               base::ThreadTaskRunnerHandle::Get().get(),
-                               nullptr /* free_disk_space_getter */));
-    ASSERT_TRUE(cache_->Initialize());
-
-    metadata_.reset(new internal::ResourceMetadata(
-        metadata_storage_.get(), cache_.get(),
-        base::ThreadTaskRunnerHandle::Get()));
-    ASSERT_EQ(FILE_ERROR_OK, metadata_->Initialize());
-
-    about_resource_loader_ =
-        std::make_unique<AboutResourceLoader>(scheduler_.get());
-    root_folder_id_loader_ = std::make_unique<AboutResourceRootFolderIdLoader>(
-        about_resource_loader_.get());
-
-    start_page_token_loader_ = std::make_unique<StartPageTokenLoader>(
-        drive::util::kTeamDriveIdDefaultCorpus, scheduler_.get());
-    loader_controller_ = std::make_unique<LoaderController>();
-    change_list_loader_ = std::make_unique<ChangeListLoader>(
-        logger_.get(), base::ThreadTaskRunnerHandle::Get().get(),
-        metadata_.get(), scheduler_.get(), root_folder_id_loader_.get(),
-        start_page_token_loader_.get(), loader_controller_.get(),
-        util::kTeamDriveIdDefaultCorpus, util::GetDriveMyDriveRootPath());
-    ASSERT_NO_FATAL_FAILURE(SetUpTestData());
-
-    sync_client_ = std::make_unique<SyncClient>(
-        base::ThreadTaskRunnerHandle::Get().get(), &delegate_, scheduler_.get(),
-        metadata_.get(), cache_.get(), loader_controller_.get(),
-        temp_dir_.GetPath());
-
-    // Disable delaying so that DoSyncLoop() starts immediately.
-    sync_client_->set_delay_for_testing(base::TimeDelta::FromSeconds(0));
-  }
-
-  // Adds a file to the service root and |resource_ids_|.
-  void AddFileEntry(const std::string& title) {
-    google_apis::DriveApiErrorCode error = google_apis::DRIVE_FILE_ERROR;
-    std::unique_ptr<google_apis::FileResource> entry;
-    drive_service_->AddNewFile(
-        "text/plain",
-        kRemoteContent,
-        drive_service_->GetRootResourceId(),
-        title,
-        false,  // shared_with_me
-        google_apis::test_util::CreateCopyResultCallback(&error, &entry));
-    base::RunLoop().RunUntilIdle();
-    ASSERT_EQ(google_apis::HTTP_CREATED, error);
-    ASSERT_TRUE(entry);
-    resource_ids_[title] = entry->file_id();
-  }
-
-  // Sets up data for tests.
-  void SetUpTestData() {
-    // Prepare a temp file.
-    base::FilePath temp_file;
-    EXPECT_TRUE(
-        base::CreateTemporaryFileInDir(temp_dir_.GetPath(), &temp_file));
-    ASSERT_TRUE(google_apis::test_util::WriteStringToFile(temp_file,
-                                                          kLocalContent));
-
-    // Add file entries to the service.
-    ASSERT_NO_FATAL_FAILURE(AddFileEntry("foo"));
-    ASSERT_NO_FATAL_FAILURE(AddFileEntry("bar"));
-    ASSERT_NO_FATAL_FAILURE(AddFileEntry("baz"));
-    ASSERT_NO_FATAL_FAILURE(AddFileEntry("fetched"));
-    ASSERT_NO_FATAL_FAILURE(AddFileEntry("dirty"));
-    ASSERT_NO_FATAL_FAILURE(AddFileEntry("removed"));
-    ASSERT_NO_FATAL_FAILURE(AddFileEntry("moved"));
-
-    // Load data from the service to the metadata.
-    FileError error = FILE_ERROR_FAILED;
-    change_list_loader_->LoadIfNeeded(
-        google_apis::test_util::CreateCopyResultCallback(&error));
-    base::RunLoop().RunUntilIdle();
-    EXPECT_EQ(FILE_ERROR_OK, error);
-
-    // Prepare 3 pinned-but-not-present files.
-    EXPECT_EQ(FILE_ERROR_OK, cache_->Pin(GetLocalId("foo")));
-    EXPECT_EQ(FILE_ERROR_OK, cache_->Pin(GetLocalId("bar")));
-    EXPECT_EQ(FILE_ERROR_OK, cache_->Pin(GetLocalId("baz")));
-
-    // Prepare a pinned-and-fetched file.
-    const std::string md5_fetched = "md5";
-    EXPECT_EQ(FILE_ERROR_OK,
-              cache_->Store(GetLocalId("fetched"), md5_fetched,
-                            temp_file, FileCache::FILE_OPERATION_COPY));
-    EXPECT_EQ(FILE_ERROR_OK, cache_->Pin(GetLocalId("fetched")));
-
-    // Prepare a pinned-and-fetched-and-dirty file.
-    EXPECT_EQ(FILE_ERROR_OK,
-              cache_->Store(GetLocalId("dirty"), std::string(),
-                            temp_file, FileCache::FILE_OPERATION_COPY));
-    EXPECT_EQ(FILE_ERROR_OK, cache_->Pin(GetLocalId("dirty")));
-
-    // Prepare a removed file.
-    file_system::RemoveOperation remove_operation(
-        base::ThreadTaskRunnerHandle::Get().get(), &delegate_, metadata_.get(),
-        cache_.get());
-    remove_operation.Remove(
-        util::GetDriveMyDriveRootPath().AppendASCII("removed"),
-        false,  // is_recursive
-        google_apis::test_util::CreateCopyResultCallback(&error));
-    base::RunLoop().RunUntilIdle();
-    EXPECT_EQ(FILE_ERROR_OK, error);
-
-    // Prepare a moved file.
-    file_system::MoveOperation move_operation(
-        base::ThreadTaskRunnerHandle::Get().get(), &delegate_, metadata_.get());
-    move_operation.Move(
-        util::GetDriveMyDriveRootPath().AppendASCII("moved"),
-        util::GetDriveMyDriveRootPath().AppendASCII("moved_new_title"),
-        google_apis::test_util::CreateCopyResultCallback(&error));
-    base::RunLoop().RunUntilIdle();
-    EXPECT_EQ(FILE_ERROR_OK, error);
-  }
-
- protected:
-  std::string GetLocalId(const std::string& title) {
-    EXPECT_EQ(1U, resource_ids_.count(title));
-    std::string local_id;
-    EXPECT_EQ(FILE_ERROR_OK,
-              metadata_->GetIdByResourceId(resource_ids_[title], &local_id));
-    return local_id;
-  }
-
-  content::BrowserTaskEnvironment task_environment_;
-  base::ScopedTempDir temp_dir_;
-  std::unique_ptr<TestingPrefServiceSimple> pref_service_;
-  std::unique_ptr<EventLogger> logger_;
-  std::unique_ptr<SyncClientTestDriveService> drive_service_;
-  file_system::OperationDelegate delegate_;
-  std::unique_ptr<JobScheduler> scheduler_;
-  std::unique_ptr<ResourceMetadataStorage, test_util::DestroyHelperForTests>
-      metadata_storage_;
-  std::unique_ptr<FileCache, test_util::DestroyHelperForTests> cache_;
-  std::unique_ptr<ResourceMetadata, test_util::DestroyHelperForTests> metadata_;
-  std::unique_ptr<AboutResourceLoader> about_resource_loader_;
-  std::unique_ptr<StartPageTokenLoader> start_page_token_loader_;
-  std::unique_ptr<LoaderController> loader_controller_;
-  std::unique_ptr<ChangeListLoader> change_list_loader_;
-  std::unique_ptr<SyncClient> sync_client_;
-  std::unique_ptr<AboutResourceRootFolderIdLoader> root_folder_id_loader_;
-
-  std::map<std::string, std::string> resource_ids_;  // Name-to-id map.
-};
-
-TEST_F(SyncClientTest, StartProcessingBacklog) {
-  sync_client_->StartProcessingBacklog();
-  base::RunLoop().RunUntilIdle();
-
-  ResourceEntry entry;
-  // Pinned files get downloaded.
-  EXPECT_EQ(FILE_ERROR_OK,
-            metadata_->GetResourceEntryById(GetLocalId("foo"), &entry));
-  EXPECT_TRUE(entry.file_specific_info().cache_state().is_present());
-
-  EXPECT_EQ(FILE_ERROR_OK,
-            metadata_->GetResourceEntryById(GetLocalId("bar"), &entry));
-  EXPECT_TRUE(entry.file_specific_info().cache_state().is_present());
-
-  EXPECT_EQ(FILE_ERROR_OK,
-            metadata_->GetResourceEntryById(GetLocalId("baz"), &entry));
-  EXPECT_TRUE(entry.file_specific_info().cache_state().is_present());
-
-  // Dirty file gets uploaded.
-  EXPECT_EQ(FILE_ERROR_OK,
-            metadata_->GetResourceEntryById(GetLocalId("dirty"), &entry));
-  EXPECT_FALSE(entry.file_specific_info().cache_state().is_dirty());
-
-  // Removed entry is not found.
-  google_apis::DriveApiErrorCode status = google_apis::DRIVE_OTHER_ERROR;
-  std::unique_ptr<google_apis::FileResource> server_entry;
-  drive_service_->GetFileResource(
-      resource_ids_["removed"],
-      google_apis::test_util::CreateCopyResultCallback(&status, &server_entry));
-  base::RunLoop().RunUntilIdle();
-  EXPECT_EQ(google_apis::HTTP_SUCCESS, status);
-  ASSERT_TRUE(server_entry);
-  EXPECT_TRUE(server_entry->labels().is_trashed());
-
-  // Moved entry was moved.
-  status = google_apis::DRIVE_OTHER_ERROR;
-  drive_service_->GetFileResource(
-      resource_ids_["moved"],
-      google_apis::test_util::CreateCopyResultCallback(&status, &server_entry));
-  base::RunLoop().RunUntilIdle();
-  EXPECT_EQ(google_apis::HTTP_SUCCESS, status);
-  ASSERT_TRUE(server_entry);
-  EXPECT_EQ("moved_new_title", server_entry->title());
-}
-
-TEST_F(SyncClientTest, AddFetchTask) {
-  sync_client_->AddFetchTask(GetLocalId("foo"));
-  base::RunLoop().RunUntilIdle();
-
-  ResourceEntry entry;
-  EXPECT_EQ(FILE_ERROR_OK,
-            metadata_->GetResourceEntryById(GetLocalId("foo"), &entry));
-  EXPECT_TRUE(entry.file_specific_info().cache_state().is_present());
-}
-
-TEST_F(SyncClientTest, AddFetchTaskAndCancelled) {
-  // Trigger fetching of a file which results in cancellation.
-  drive_service_->set_resource_id_to_be_cancelled(resource_ids_["foo"]);
-  sync_client_->AddFetchTask(GetLocalId("foo"));
-  base::RunLoop().RunUntilIdle();
-
-  // The file should be unpinned if the user wants the download to be cancelled.
-  ResourceEntry entry;
-  EXPECT_EQ(FILE_ERROR_OK,
-            metadata_->GetResourceEntryById(GetLocalId("foo"), &entry));
-  EXPECT_FALSE(entry.file_specific_info().cache_state().is_pinned());
-}
-
-TEST_F(SyncClientTest, RemoveFetchTask) {
-  sync_client_->AddFetchTask(GetLocalId("foo"));
-  sync_client_->AddFetchTask(GetLocalId("bar"));
-  sync_client_->AddFetchTask(GetLocalId("baz"));
-
-  sync_client_->RemoveFetchTask(GetLocalId("foo"));
-  sync_client_->RemoveFetchTask(GetLocalId("baz"));
-  base::RunLoop().RunUntilIdle();
-
-  // Only "bar" should be fetched.
-  ResourceEntry entry;
-  EXPECT_EQ(FILE_ERROR_OK,
-            metadata_->GetResourceEntryById(GetLocalId("foo"), &entry));
-  EXPECT_FALSE(entry.file_specific_info().cache_state().is_present());
-
-  EXPECT_EQ(FILE_ERROR_OK,
-            metadata_->GetResourceEntryById(GetLocalId("bar"), &entry));
-  EXPECT_TRUE(entry.file_specific_info().cache_state().is_present());
-
-  EXPECT_EQ(FILE_ERROR_OK,
-            metadata_->GetResourceEntryById(GetLocalId("baz"), &entry));
-  EXPECT_FALSE(entry.file_specific_info().cache_state().is_present());
-
-}
-
-TEST_F(SyncClientTest, ExistingPinnedFiles) {
-  // Start checking the existing pinned files. This will collect the resource
-  // IDs of pinned files, with stale local cache files.
-  sync_client_->StartCheckingExistingPinnedFiles();
-  base::RunLoop().RunUntilIdle();
-
-  // "fetched" and "dirty" are the existing pinned files.
-  // The non-dirty one should be synced, but the dirty one should not.
-  base::FilePath cache_file;
-  std::string content;
-  EXPECT_EQ(FILE_ERROR_OK, cache_->GetFile(GetLocalId("fetched"), &cache_file));
-  EXPECT_TRUE(base::ReadFileToString(cache_file, &content));
-  EXPECT_EQ(kRemoteContent, content);
-  content.clear();
-
-  EXPECT_EQ(FILE_ERROR_OK, cache_->GetFile(GetLocalId("dirty"), &cache_file));
-  EXPECT_TRUE(base::ReadFileToString(cache_file, &content));
-  EXPECT_EQ(kLocalContent, content);
-}
-
-TEST_F(SyncClientTest, RetryOnDisconnection) {
-  // Let the service go down.
-  drive_service_->set_offline(true);
-  // Change the network connection state after some delay, to test that
-  // FILE_ERROR_NO_CONNECTION is handled by SyncClient correctly.
-  // Without this delay, JobScheduler will keep the jobs unrun and SyncClient
-  // will receive no error.
-  base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
-      FROM_HERE,
-      base::BindOnce(&network::TestNetworkConnectionTracker::SetConnectionType,
-                     base::Unretained(
-                         network::TestNetworkConnectionTracker::GetInstance()),
-                     network::mojom::ConnectionType::CONNECTION_NONE),
-      TestTimeouts::tiny_timeout());
-
-  // Try fetch and upload.
-  sync_client_->AddFetchTask(GetLocalId("foo"));
-  sync_client_->AddUpdateTask(ClientContext(USER_INITIATED),
-                              GetLocalId("dirty"));
-  base::RunLoop().RunUntilIdle();
-
-  // Not yet fetched nor uploaded.
-  ResourceEntry entry;
-  EXPECT_EQ(FILE_ERROR_OK,
-            metadata_->GetResourceEntryById(GetLocalId("foo"), &entry));
-  EXPECT_FALSE(entry.file_specific_info().cache_state().is_present());
-  EXPECT_EQ(FILE_ERROR_OK,
-            metadata_->GetResourceEntryById(GetLocalId("dirty"), &entry));
-  EXPECT_TRUE(entry.file_specific_info().cache_state().is_dirty());
-
-  // Switch to online.
-  network::TestNetworkConnectionTracker::GetInstance()->SetConnectionType(
-      network::mojom::ConnectionType::CONNECTION_WIFI);
-  drive_service_->set_offline(false);
-  base::RunLoop().RunUntilIdle();
-
-  // Fetched and uploaded.
-  EXPECT_EQ(FILE_ERROR_OK,
-            metadata_->GetResourceEntryById(GetLocalId("foo"), &entry));
-  EXPECT_TRUE(entry.file_specific_info().cache_state().is_present());
-  EXPECT_EQ(FILE_ERROR_OK,
-            metadata_->GetResourceEntryById(GetLocalId("dirty"), &entry));
-  EXPECT_FALSE(entry.file_specific_info().cache_state().is_dirty());
-}
-
-TEST_F(SyncClientTest, ScheduleRerun) {
-  // Add a fetch task for "foo", this should result in being paused.
-  drive_service_->set_resource_id_to_be_paused(resource_ids_["foo"]);
-  sync_client_->AddFetchTask(GetLocalId("foo"));
-  base::RunLoop().RunUntilIdle();
-
-  // While the first task is paused, add a task again.
-  // This results in scheduling rerun of the task.
-  sync_client_->AddFetchTask(GetLocalId("foo"));
-  base::RunLoop().RunUntilIdle();
-
-  // Resume the paused task.
-  drive_service_->set_resource_id_to_be_paused(std::string());
-  ASSERT_FALSE(drive_service_->paused_action().is_null());
-  drive_service_->paused_action().Run();
-  base::RunLoop().RunUntilIdle();
-
-  // Task should be run twice.
-  EXPECT_EQ(2, drive_service_->download_file_count());
-}
-
-TEST_F(SyncClientTest, Dependencies) {
-  // Create directories locally.
-  const base::FilePath kPath1(FILE_PATH_LITERAL("drive/root/dir1"));
-  const base::FilePath kPath2 = kPath1.AppendASCII("dir2");
-
-  ResourceEntry parent;
-  EXPECT_EQ(FILE_ERROR_OK,
-            metadata_->GetResourceEntryByPath(kPath1.DirName(), &parent));
-
-  ResourceEntry entry1;
-  entry1.set_parent_local_id(parent.local_id());
-  entry1.set_title(kPath1.BaseName().AsUTF8Unsafe());
-  entry1.mutable_file_info()->set_is_directory(true);
-  entry1.set_metadata_edit_state(ResourceEntry::DIRTY);
-  std::string local_id1;
-  EXPECT_EQ(FILE_ERROR_OK, metadata_->AddEntry(entry1, &local_id1));
-
-  ResourceEntry entry2;
-  entry2.set_parent_local_id(local_id1);
-  entry2.set_title(kPath2.BaseName().AsUTF8Unsafe());
-  entry2.mutable_file_info()->set_is_directory(true);
-  entry2.set_metadata_edit_state(ResourceEntry::DIRTY);
-  std::string local_id2;
-  EXPECT_EQ(FILE_ERROR_OK, metadata_->AddEntry(entry2, &local_id2));
-
-  // Start syncing the child first.
-  sync_client_->AddUpdateTask(ClientContext(USER_INITIATED), local_id2);
-  // Start syncing the parent later.
-  sync_client_->AddUpdateTask(ClientContext(USER_INITIATED), local_id1);
-  base::RunLoop().RunUntilIdle();
-
-  // Both entries are synced.
-  EXPECT_EQ(FILE_ERROR_OK, metadata_->GetResourceEntryById(local_id1, &entry1));
-  EXPECT_EQ(ResourceEntry::CLEAN, entry1.metadata_edit_state());
-  EXPECT_EQ(FILE_ERROR_OK, metadata_->GetResourceEntryById(local_id2, &entry2));
-  EXPECT_EQ(ResourceEntry::CLEAN, entry2.metadata_edit_state());
-}
-
-TEST_F(SyncClientTest, WaitForUpdateTaskToComplete) {
-  // Create a directory locally.
-  const base::FilePath kPath(FILE_PATH_LITERAL("drive/root/dir1"));
-
-  ResourceEntry parent;
-  EXPECT_EQ(FILE_ERROR_OK,
-            metadata_->GetResourceEntryByPath(kPath.DirName(), &parent));
-
-  ResourceEntry entry;
-  entry.set_parent_local_id(parent.local_id());
-  entry.set_title(kPath.BaseName().AsUTF8Unsafe());
-  entry.mutable_file_info()->set_is_directory(true);
-  entry.set_metadata_edit_state(ResourceEntry::DIRTY);
-  std::string local_id;
-  EXPECT_EQ(FILE_ERROR_OK, metadata_->AddEntry(entry, &local_id));
-
-  // Sync task is not yet avialable.
-  FileError error = FILE_ERROR_FAILED;
-  EXPECT_FALSE(sync_client_->WaitForUpdateTaskToComplete(
-      local_id, google_apis::test_util::CreateCopyResultCallback(&error)));
-
-  // Start syncing the directory and wait for it to complete.
-  sync_client_->AddUpdateTask(ClientContext(USER_INITIATED), local_id);
-
-  EXPECT_TRUE(sync_client_->WaitForUpdateTaskToComplete(
-      local_id, google_apis::test_util::CreateCopyResultCallback(&error)));
-
-  base::RunLoop().RunUntilIdle();
-
-  // The callback is called.
-  EXPECT_EQ(FILE_ERROR_OK, error);
-}
-
-}  // namespace internal
-}  // namespace drive
diff --git a/components/drive/team_drive_change_list_loader_unittest.cc b/components/drive/team_drive_change_list_loader_unittest.cc
deleted file mode 100644
index 09faac9d..0000000
--- a/components/drive/team_drive_change_list_loader_unittest.cc
+++ /dev/null
@@ -1,312 +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 <memory>
-
-#include "base/command_line.h"
-#include "base/files/scoped_temp_dir.h"
-#include "base/threading/thread_task_runner_handle.h"
-#include "components/drive/chromeos/drive_file_util.h"
-#include "components/drive/chromeos/drive_test_util.h"
-#include "components/drive/chromeos/file_cache.h"
-#include "components/drive/chromeos/loader_controller.h"
-#include "components/drive/chromeos/resource_metadata.h"
-#include "components/drive/chromeos/team_drive_change_list_loader.h"
-#include "components/drive/event_logger.h"
-#include "components/drive/file_change.h"
-#include "components/drive/file_system_core_util.h"
-#include "components/drive/job_scheduler.h"
-#include "components/drive/resource_metadata_storage.h"
-#include "components/drive/service/fake_drive_service.h"
-#include "components/drive/service/test_util.h"
-#include "components/prefs/testing_pref_service.h"
-#include "content/public/test/browser_task_environment.h"
-#include "mojo/public/cpp/bindings/pending_remote.h"
-#include "services/network/test/test_network_connection_tracker.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace drive {
-namespace internal {
-
-namespace {
-
-constexpr char kTeamDriveId[] = "team_drive_id";
-constexpr char kTeamDriveName[] = "team_drive_name";
-constexpr char kTestStartPageToken[] = "1";
-
-class TestChangeListLoaderObserver : public ChangeListLoaderObserver {
- public:
-  TestChangeListLoaderObserver()
-      : load_from_server_complete_count_(0), initial_load_complete_count_(0) {}
-
-  ~TestChangeListLoaderObserver() override = default;
-
-  const FileChange& changed_files() const { return changed_files_; }
-  void clear_changed_files() { changed_files_.ClearForTest(); }
-
-  int load_from_server_complete_count() const {
-    return load_from_server_complete_count_;
-  }
-  int initial_load_complete_count() const {
-    return initial_load_complete_count_;
-  }
-
-  // ChageListObserver overrides:
-  void OnFileChanged(const FileChange& changed_files) override {
-    changed_files_.Apply(changed_files);
-  }
-  void OnLoadFromServerComplete() override {
-    ++load_from_server_complete_count_;
-  }
-  void OnInitialLoadComplete() override { ++initial_load_complete_count_; }
-
- private:
-  FileChange changed_files_;
-  int load_from_server_complete_count_;
-  int initial_load_complete_count_;
-
-  DISALLOW_COPY_AND_ASSIGN(TestChangeListLoaderObserver);
-};
-
-}  // namespace
-
-class TeamDriveChangeListLoaderTest : public testing::Test {
- protected:
-  void SetUp() override {
-    ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
-
-    pref_service_ = std::make_unique<TestingPrefServiceSimple>();
-    test_util::RegisterDrivePrefs(pref_service_->registry());
-
-    logger_ = std::make_unique<EventLogger>();
-
-    drive_service_ = std::make_unique<FakeDriveService>();
-    ASSERT_TRUE(test_util::SetUpTeamDriveTestEntries(
-        drive_service_.get(), kTeamDriveId, kTeamDriveName));
-
-    network::TestNetworkConnectionTracker::GetInstance()->SetConnectionType(
-        network::mojom::ConnectionType::CONNECTION_WIFI);
-    scheduler_ = std::make_unique<JobScheduler>(
-        pref_service_.get(), logger_.get(), drive_service_.get(),
-        network::TestNetworkConnectionTracker::GetInstance(),
-        base::ThreadTaskRunnerHandle::Get().get(), mojo::NullRemote());
-    metadata_storage_.reset(new ResourceMetadataStorage(
-        temp_dir_.GetPath(), base::ThreadTaskRunnerHandle::Get().get()));
-    ASSERT_TRUE(metadata_storage_->Initialize());
-
-    cache_.reset(new FileCache(metadata_storage_.get(), temp_dir_.GetPath(),
-                               base::ThreadTaskRunnerHandle::Get().get(),
-                               nullptr /* free_disk_space_getter */));
-    ASSERT_TRUE(cache_->Initialize());
-
-    metadata_.reset(
-        new ResourceMetadata(metadata_storage_.get(), cache_.get(),
-                             base::ThreadTaskRunnerHandle::Get().get()));
-    ASSERT_EQ(FILE_ERROR_OK, metadata_->Initialize());
-
-    loader_controller_ = std::make_unique<LoaderController>();
-    base::FilePath root_entry_path =
-        util::GetDriveTeamDrivesRootPath().Append(kTeamDriveName);
-
-    team_drive_change_list_loader_ =
-        std::make_unique<TeamDriveChangeListLoader>(
-            kTeamDriveId, root_entry_path, logger_.get(),
-            base::ThreadTaskRunnerHandle::Get().get(), metadata_.get(),
-            scheduler_.get(), loader_controller_.get());
-
-    change_list_loader_observer_ =
-        std::make_unique<TestChangeListLoaderObserver>();
-    team_drive_change_list_loader_->AddChangeListLoaderObserver(
-        change_list_loader_observer_.get());
-  }
-
-  // Adds a team drive entry to ResourceMetadata
-  void AddTeamDriveEntry(const std::string& id,
-                         const std::string& name,
-                         const std::string& start_page_token) {
-    std::string root_local_id;
-    ASSERT_EQ(FILE_ERROR_OK,
-              metadata_->GetIdByPath(util::GetDriveTeamDrivesRootPath(),
-                                     &root_local_id));
-
-    std::string local_id;
-    ASSERT_EQ(FILE_ERROR_OK, metadata_->AddEntry(
-                                 CreateDirectoryEntryWithResourceId(
-                                     name, id, root_local_id, start_page_token),
-                                 &local_id));
-  }
-
-  // Creates a ResourceEntry for a directory with explicitly set resource_id.
-  ResourceEntry CreateDirectoryEntryWithResourceId(
-      const std::string& title,
-      const std::string& resource_id,
-      const std::string& parent_local_id,
-      const std::string& start_page_token) {
-    ResourceEntry entry;
-    entry.set_title(title);
-    entry.set_resource_id(resource_id);
-    entry.set_parent_local_id(parent_local_id);
-    entry.mutable_file_info()->set_is_directory(true);
-    entry.mutable_directory_specific_info()->set_start_page_token(
-        start_page_token);
-    return entry;
-  }
-
-  // Adds a new file to the root directory of the service.
-  std::unique_ptr<google_apis::FileResource> AddNewFile(
-      const std::string& title,
-      const std::string& parent_resource_id) {
-    google_apis::DriveApiErrorCode error = google_apis::DRIVE_FILE_ERROR;
-    std::unique_ptr<google_apis::FileResource> entry;
-    drive_service_->AddNewFile(
-        "text/plain", "content text", parent_resource_id, title,
-        false,  // shared_with_me
-        google_apis::test_util::CreateCopyResultCallback(&error, &entry));
-    base::RunLoop().RunUntilIdle();
-    EXPECT_EQ(google_apis::HTTP_CREATED, error);
-    return entry;
-  }
-
-  content::BrowserTaskEnvironment task_environment_;
-  base::ScopedTempDir temp_dir_;
-  std::unique_ptr<TestingPrefServiceSimple> pref_service_;
-  std::unique_ptr<EventLogger> logger_;
-  std::unique_ptr<FakeDriveService> drive_service_;
-  std::unique_ptr<JobScheduler> scheduler_;
-  std::unique_ptr<ResourceMetadataStorage, test_util::DestroyHelperForTests>
-      metadata_storage_;
-  std::unique_ptr<FileCache, test_util::DestroyHelperForTests> cache_;
-  std::unique_ptr<ResourceMetadata, test_util::DestroyHelperForTests> metadata_;
-  std::unique_ptr<LoaderController> loader_controller_;
-  std::unique_ptr<TeamDriveChangeListLoader> team_drive_change_list_loader_;
-  std::unique_ptr<TestChangeListLoaderObserver> change_list_loader_observer_;
-};
-
-// When loading, if the local resource metadata contains a start page token then
-// we do not load from the server, just use local metadata.
-TEST_F(TeamDriveChangeListLoaderTest, MetadataRefresh) {
-  AddTeamDriveEntry(kTeamDriveId, kTeamDriveName, kTestStartPageToken);
-  EXPECT_FALSE(team_drive_change_list_loader_->IsRefreshing());
-
-  FileError error = FILE_ERROR_FAILED;
-  team_drive_change_list_loader_->LoadIfNeeded(
-      google_apis::test_util::CreateCopyResultCallback(&error));
-  EXPECT_TRUE(team_drive_change_list_loader_->IsRefreshing());
-  base::RunLoop().RunUntilIdle();
-  EXPECT_EQ(FILE_ERROR_OK, error);
-
-  EXPECT_FALSE(team_drive_change_list_loader_->IsRefreshing());
-  EXPECT_EQ(1, drive_service_->start_page_token_load_count());
-  EXPECT_EQ(0, drive_service_->change_list_load_count());
-}
-
-// Trigger a full load, by setting the start page token of the team drive in
-// resource metadata to an empty string.
-TEST_F(TeamDriveChangeListLoaderTest, FullLoad) {
-  AddTeamDriveEntry(kTeamDriveId, kTeamDriveName, std::string());
-  EXPECT_FALSE(team_drive_change_list_loader_->IsRefreshing());
-
-  FileError error = FILE_ERROR_FAILED;
-  team_drive_change_list_loader_->LoadIfNeeded(
-      google_apis::test_util::CreateCopyResultCallback(&error));
-  EXPECT_TRUE(team_drive_change_list_loader_->IsRefreshing());
-  base::RunLoop().RunUntilIdle();
-  EXPECT_EQ(FILE_ERROR_OK, error);
-
-  EXPECT_FALSE(team_drive_change_list_loader_->IsRefreshing());
-  EXPECT_EQ(1, drive_service_->start_page_token_load_count());
-  EXPECT_EQ(1, drive_service_->file_list_load_count());
-  EXPECT_EQ(0, drive_service_->change_list_load_count());
-  EXPECT_EQ(1, change_list_loader_observer_->initial_load_complete_count());
-  EXPECT_EQ(1, change_list_loader_observer_->load_from_server_complete_count());
-  EXPECT_TRUE(change_list_loader_observer_->changed_files().empty());
-
-  base::FilePath file_path = util::GetDriveTeamDrivesRootPath()
-                                 .AppendASCII(kTeamDriveName)
-                                 .AppendASCII("File 1.txt");
-  ResourceEntry entry;
-  EXPECT_EQ(FILE_ERROR_OK,
-            metadata_->GetResourceEntryByPath(file_path, &entry));
-}
-
-// CheckForUpdates will trigger a full and delta load from the server
-TEST_F(TeamDriveChangeListLoaderTest, CheckForUpdates) {
-  AddTeamDriveEntry(kTeamDriveId, kTeamDriveName, std::string());
-
-  // CheckForUpdates() results in no-op before load.
-  FileError error = FILE_ERROR_FAILED;
-  team_drive_change_list_loader_->CheckForUpdates(
-      google_apis::test_util::CreateCopyResultCallback(&error));
-  EXPECT_FALSE(team_drive_change_list_loader_->IsRefreshing());
-  base::RunLoop().RunUntilIdle();
-  EXPECT_EQ(FILE_ERROR_FAILED, error);
-
-  EXPECT_EQ(0, drive_service_->file_list_load_count());
-  EXPECT_EQ(0, drive_service_->start_page_token_load_count());
-
-  // Start initial load.
-  FileError load_error = FILE_ERROR_FAILED;
-  team_drive_change_list_loader_->LoadIfNeeded(
-      google_apis::test_util::CreateCopyResultCallback(&load_error));
-  EXPECT_TRUE(team_drive_change_list_loader_->IsRefreshing());
-  base::RunLoop().RunUntilIdle();
-
-  std::string start_page_token;
-  EXPECT_FALSE(team_drive_change_list_loader_->IsRefreshing());
-  EXPECT_EQ(FILE_ERROR_OK, load_error);
-  EXPECT_EQ(FILE_ERROR_OK,
-            internal::GetStartPageToken(metadata_.get(), kTeamDriveId,
-                                        &start_page_token));
-  EXPECT_FALSE(start_page_token.empty());
-  EXPECT_EQ(1, drive_service_->file_list_load_count());
-
-  std::string previous_start_page_token = start_page_token;
-  // CheckForUpdates() results in no update.
-  FileError check_for_updates_error = FILE_ERROR_FAILED;
-  team_drive_change_list_loader_->CheckForUpdates(
-      google_apis::test_util::CreateCopyResultCallback(
-          &check_for_updates_error));
-  EXPECT_TRUE(team_drive_change_list_loader_->IsRefreshing());
-  base::RunLoop().RunUntilIdle();
-  EXPECT_FALSE(team_drive_change_list_loader_->IsRefreshing());
-  EXPECT_EQ(FILE_ERROR_OK,
-            internal::GetStartPageToken(metadata_.get(), kTeamDriveId,
-                                        &start_page_token));
-  EXPECT_EQ(previous_start_page_token, start_page_token);
-
-  // Add a file to the service.
-  std::unique_ptr<google_apis::FileResource> gdata_entry =
-      AddNewFile("New File", kTeamDriveId);
-  ASSERT_TRUE(gdata_entry);
-
-  // CheckForUpdates() results in update.
-  change_list_loader_observer_->clear_changed_files();
-  team_drive_change_list_loader_->CheckForUpdates(
-      google_apis::test_util::CreateCopyResultCallback(
-          &check_for_updates_error));
-  EXPECT_TRUE(team_drive_change_list_loader_->IsRefreshing());
-  base::RunLoop().RunUntilIdle();
-
-  EXPECT_FALSE(team_drive_change_list_loader_->IsRefreshing());
-  EXPECT_EQ(FILE_ERROR_OK,
-            internal::GetStartPageToken(metadata_.get(), kTeamDriveId,
-                                        &start_page_token));
-  EXPECT_NE(previous_start_page_token, start_page_token);
-  EXPECT_EQ(2, change_list_loader_observer_->load_from_server_complete_count());
-
-  base::FilePath team_drive_path =
-      util::GetDriveTeamDrivesRootPath().AppendASCII(kTeamDriveName);
-  EXPECT_TRUE(change_list_loader_observer_->changed_files().CountDirectory(
-      team_drive_path));
-
-  // The new file is found in the local metadata.
-  base::FilePath new_file_path =
-      team_drive_path.AppendASCII(gdata_entry->title());
-  ResourceEntry entry;
-  EXPECT_EQ(FILE_ERROR_OK,
-            metadata_->GetResourceEntryByPath(new_file_path, &entry));
-}
-
-}  // namespace internal
-}  // namespace drive
diff --git a/components/drive/team_drive_list_loader_unittest.cc b/components/drive/team_drive_list_loader_unittest.cc
deleted file mode 100644
index f196d8b..0000000
--- a/components/drive/team_drive_list_loader_unittest.cc
+++ /dev/null
@@ -1,406 +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 <memory>
-
-#include "base/files/scoped_temp_dir.h"
-#include "components/drive/chromeos/change_list_loader.h"
-#include "components/drive/chromeos/drive_test_util.h"
-#include "components/drive/chromeos/loader_controller.h"
-#include "components/drive/chromeos/resource_metadata.h"
-#include "components/drive/chromeos/team_drive_list_loader.h"
-#include "components/drive/event_logger.h"
-#include "components/drive/file_system_core_util.h"
-#include "components/drive/job_scheduler.h"
-#include "components/drive/service/fake_drive_service.h"
-#include "components/drive/service/test_util.h"
-#include "components/prefs/testing_pref_service.h"
-#include "content/public/test/browser_task_environment.h"
-#include "google_apis/drive/test_util.h"
-#include "mojo/public/cpp/bindings/pending_remote.h"
-#include "services/network/test/test_network_connection_tracker.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace drive {
-namespace internal {
-
-namespace {
-
-constexpr char kTestStartPageToken[] = "123456";
-
-class TestTeamDriveListObserver : public TeamDriveListObserver {
- public:
-  ~TestTeamDriveListObserver() override = default;
-
-  void OnTeamDriveListLoaded(
-      const std::vector<TeamDrive>& team_drives_list,
-      const std::vector<TeamDrive>& added_team_drives,
-      const std::vector<TeamDrive>& removed_team_drives) override {
-    team_drives_list_ = team_drives_list;
-    added_team_drives_ = added_team_drives;
-    removed_team_drives_ = removed_team_drives;
-  }
-
-  const std::vector<TeamDrive>& team_drives_list() const {
-    return team_drives_list_;
-  }
-
-  const std::vector<TeamDrive>& added_team_drives() const {
-    return added_team_drives_;
-  }
-
-  const std::vector<TeamDrive>& removed_team_drives() const {
-    return removed_team_drives_;
-  }
-
- private:
-  std::vector<TeamDrive> team_drives_list_;
-  std::vector<TeamDrive> added_team_drives_;
-  std::vector<TeamDrive> removed_team_drives_;
-};
-
-}  // namespace
-
-class TeamDriveListLoaderTest : public testing::Test {
- protected:
-  void SetUp() override {
-    ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
-
-    pref_service_ = std::make_unique<TestingPrefServiceSimple>();
-    test_util::RegisterDrivePrefs(pref_service_->registry());
-
-    logger_ = std::make_unique<EventLogger>();
-
-    drive_service_ = std::make_unique<FakeDriveService>();
-    ASSERT_TRUE(test_util::SetUpTestEntries(drive_service_.get()));
-    drive_service_->set_default_max_results(2);
-
-    network::TestNetworkConnectionTracker::GetInstance()->SetConnectionType(
-        network::mojom::ConnectionType::CONNECTION_WIFI);
-    scheduler_ = std::make_unique<JobScheduler>(
-        pref_service_.get(), logger_.get(), drive_service_.get(),
-        network::TestNetworkConnectionTracker::GetInstance(),
-        base::ThreadTaskRunnerHandle::Get().get(), mojo::NullRemote());
-    metadata_storage_.reset(new ResourceMetadataStorage(
-        temp_dir_.GetPath(), base::ThreadTaskRunnerHandle::Get().get()));
-    ASSERT_TRUE(metadata_storage_->Initialize());
-
-    cache_.reset(new FileCache(metadata_storage_.get(), temp_dir_.GetPath(),
-                               base::ThreadTaskRunnerHandle::Get().get(),
-                               nullptr /* free_disk_space_getter */));
-    ASSERT_TRUE(cache_->Initialize());
-
-    metadata_.reset(
-        new ResourceMetadata(metadata_storage_.get(), cache_.get(),
-                             base::ThreadTaskRunnerHandle::Get().get()));
-    ASSERT_EQ(FILE_ERROR_OK, metadata_->Initialize());
-
-    loader_controller_ = std::make_unique<LoaderController>();
-    team_drive_list_loader_ = std::make_unique<TeamDriveListLoader>(
-        logger_.get(), base::ThreadTaskRunnerHandle::Get().get(),
-        metadata_.get(), scheduler_.get(), loader_controller_.get());
-
-    team_drive_list_observer_ = std::make_unique<TestTeamDriveListObserver>();
-    team_drive_list_loader_->AddObserver(team_drive_list_observer_.get());
-  }
-
-  // Creates a ResourceEntry for a directory with explicitly set resource_id.
-  ResourceEntry CreateDirectoryEntryWithResourceId(
-      const std::string& title,
-      const std::string& resource_id,
-      const std::string& parent_local_id) {
-    ResourceEntry entry;
-    entry.set_title(title);
-    entry.set_resource_id(resource_id);
-    entry.set_parent_local_id(parent_local_id);
-    entry.mutable_file_info()->set_is_directory(true);
-    entry.mutable_directory_specific_info()->set_start_page_token(
-        kTestStartPageToken);
-    return entry;
-  }
-
-  content::BrowserTaskEnvironment task_environment_;
-  base::ScopedTempDir temp_dir_;
-  std::unique_ptr<TestingPrefServiceSimple> pref_service_;
-  std::unique_ptr<EventLogger> logger_;
-  std::unique_ptr<FakeDriveService> drive_service_;
-  std::unique_ptr<JobScheduler> scheduler_;
-  std::unique_ptr<ResourceMetadataStorage, test_util::DestroyHelperForTests>
-      metadata_storage_;
-  std::unique_ptr<FileCache, test_util::DestroyHelperForTests> cache_;
-  std::unique_ptr<ResourceMetadata, test_util::DestroyHelperForTests> metadata_;
-  std::unique_ptr<LoaderController> loader_controller_;
-  std::unique_ptr<TeamDriveListLoader> team_drive_list_loader_;
-  std::unique_ptr<TestTeamDriveListObserver> team_drive_list_observer_;
-};
-
-// Tests that if there are no team drives on the server, we will not add
-// and team drives to local metadata.
-TEST_F(TeamDriveListLoaderTest, NoTeamDrives) {
-  // Tests the response if there are no team drives loaded.
-  FileError error = FILE_ERROR_FAILED;
-  team_drive_list_loader_->LoadIfNeeded(
-      google_apis::test_util::CreateCopyResultCallback(&error));
-  base::RunLoop().RunUntilIdle();
-  EXPECT_EQ(FILE_ERROR_OK, error);
-  EXPECT_EQ(1, drive_service_->team_drive_list_load_count());
-
-  EXPECT_TRUE(team_drive_list_observer_->team_drives_list().empty());
-  EXPECT_TRUE(team_drive_list_observer_->added_team_drives().empty());
-  EXPECT_TRUE(team_drive_list_observer_->removed_team_drives().empty());
-
-  ResourceEntryVector entries;
-  EXPECT_EQ(FILE_ERROR_OK, metadata_->ReadDirectoryByPath(
-                               util::GetDriveTeamDrivesRootPath(), &entries));
-  EXPECT_TRUE(entries.empty());
-}
-
-// Tests if there is one team drive on the server we will add it to the local
-// metadata.
-TEST_F(TeamDriveListLoaderTest, OneTeamDrive) {
-  constexpr char kTeamDriveId1[] = "the1stTeamDriveId";
-  constexpr char kTeamDriveName1[] = "The First Team Drive";
-  drive_service_->AddTeamDrive(kTeamDriveId1, kTeamDriveName1);
-
-  FileError error = FILE_ERROR_FAILED;
-  team_drive_list_loader_->CheckForUpdates(
-      google_apis::test_util::CreateCopyResultCallback(&error));
-  base::RunLoop().RunUntilIdle();
-  EXPECT_EQ(FILE_ERROR_OK, error);
-  EXPECT_EQ(1, drive_service_->team_drive_list_load_count());
-
-  EXPECT_EQ(1UL, team_drive_list_observer_->team_drives_list().size());
-  EXPECT_EQ(1UL, team_drive_list_observer_->added_team_drives().size());
-  EXPECT_TRUE(team_drive_list_observer_->removed_team_drives().empty());
-
-  ResourceEntryVector entries;
-  EXPECT_EQ(FILE_ERROR_OK, metadata_->ReadDirectoryByPath(
-                               util::GetDriveTeamDrivesRootPath(), &entries));
-  EXPECT_EQ(1UL, entries.size());
-
-  ResourceEntry entry;
-  EXPECT_EQ(FILE_ERROR_OK,
-            metadata_->GetResourceEntryByPath(
-                util::GetDriveTeamDrivesRootPath().AppendASCII(kTeamDriveName1),
-                &entry));
-
-  const base::FilePath& team_drive_path =
-      team_drive_list_observer_->team_drives_list().front().team_drive_path();
-  EXPECT_EQ(team_drive_path,
-            util::GetDriveTeamDrivesRootPath().AppendASCII(kTeamDriveName1));
-}
-
-TEST_F(TeamDriveListLoaderTest, NotmalizedTeamDriveName) {
-  constexpr char kTeamDriveId1[] = "the1stTeamDriveId";
-  constexpr char kTeamDriveName1[] = "A / Strange / Team / Drive / Name";
-  constexpr char kTeamDriveNormalized1[] = "A _ Strange _ Team _ Drive _ Name";
-  drive_service_->AddTeamDrive(kTeamDriveId1, kTeamDriveName1);
-
-  FileError error = FILE_ERROR_FAILED;
-  team_drive_list_loader_->CheckForUpdates(
-      google_apis::test_util::CreateCopyResultCallback(&error));
-  base::RunLoop().RunUntilIdle();
-  EXPECT_EQ(FILE_ERROR_OK, error);
-  EXPECT_EQ(1, drive_service_->team_drive_list_load_count());
-
-  EXPECT_EQ(1UL, team_drive_list_observer_->team_drives_list().size());
-  EXPECT_EQ(1UL, team_drive_list_observer_->added_team_drives().size());
-  EXPECT_TRUE(team_drive_list_observer_->removed_team_drives().empty());
-
-  ResourceEntryVector entries;
-  EXPECT_EQ(FILE_ERROR_OK, metadata_->ReadDirectoryByPath(
-                               util::GetDriveTeamDrivesRootPath(), &entries));
-  EXPECT_EQ(1UL, entries.size());
-
-  ResourceEntry entry;
-  EXPECT_EQ(
-      FILE_ERROR_OK,
-      metadata_->GetResourceEntryByPath(
-          util::GetDriveTeamDrivesRootPath().Append(kTeamDriveNormalized1),
-          &entry));
-
-  {
-    const base::FilePath& team_drive_path =
-        team_drive_list_observer_->team_drives_list().front().team_drive_path();
-    EXPECT_EQ(team_drive_path,
-              util::GetDriveTeamDrivesRootPath().Append(kTeamDriveNormalized1));
-  }
-  {
-    const base::FilePath& team_drive_path =
-        team_drive_list_observer_->added_team_drives()
-            .front()
-            .team_drive_path();
-    EXPECT_EQ(team_drive_path,
-              util::GetDriveTeamDrivesRootPath().Append(kTeamDriveNormalized1));
-  }
-}
-
-// Tests if there are multiple team drives on the server, we will add them all
-// to local metadata.
-TEST_F(TeamDriveListLoaderTest, MultipleTeamDrive) {
-  const std::vector<std::pair<std::string, std::string>> team_drives = {
-      {"the1stTeamDriveId", "The First Team Drive"},
-      {"the2ndTeamDriveId", "The Second Team Drive"},
-      {"the3rdTeamDriveId", "The Third Team Drive"},
-      {"the4thTeamDriveId", "The Forth Team Drive"},
-  };
-
-  for (const auto& drive : team_drives) {
-    drive_service_->AddTeamDrive(drive.first, drive.second);
-  }
-
-  FileError error = FILE_ERROR_FAILED;
-  team_drive_list_loader_->CheckForUpdates(
-      google_apis::test_util::CreateCopyResultCallback(&error));
-  base::RunLoop().RunUntilIdle();
-  EXPECT_EQ(FILE_ERROR_OK, error);
-  EXPECT_EQ(1, drive_service_->team_drive_list_load_count());
-
-  EXPECT_EQ(team_drives.size(),
-            team_drive_list_observer_->team_drives_list().size());
-  EXPECT_EQ(team_drives.size(),
-            team_drive_list_observer_->added_team_drives().size());
-  EXPECT_TRUE(team_drive_list_observer_->removed_team_drives().empty());
-
-  ResourceEntryVector entries;
-  EXPECT_EQ(FILE_ERROR_OK, metadata_->ReadDirectoryByPath(
-                               util::GetDriveTeamDrivesRootPath(), &entries));
-  EXPECT_EQ(team_drives.size(), entries.size());
-
-  ResourceEntry entry;
-
-  for (const auto& drive : team_drives) {
-    EXPECT_EQ(FILE_ERROR_OK,
-              metadata_->GetResourceEntryByPath(
-                  util::GetDriveTeamDrivesRootPath().AppendASCII(drive.second),
-                  &entry));
-    EXPECT_EQ(drive.first, entry.resource_id());
-    EXPECT_EQ(drive.second, entry.base_name());
-    EXPECT_TRUE(entry.file_info().is_directory());
-    EXPECT_EQ("", entry.directory_specific_info().start_page_token());
-  }
-}
-
-// Tests that is we have existing team drives in local metadata, and we add
-// new team drives from the server, that we retain the pre-existing local
-// metadata.
-TEST_F(TeamDriveListLoaderTest, RetainExistingMetadata) {
-  const std::vector<std::pair<std::string, std::string>> new_team_drives = {
-      {"the3rdTeamDriveId", "The Third Team Drive"},
-      {"the4thTeamDriveId", "The Forth Team Drive"},
-  };
-
-  const std::vector<std::pair<std::string, std::string>> old_team_drives = {
-      {"the1stTeamDriveId", "The First Team Drive"},
-      {"the2ndTeamDriveId", "The Second Team Drive"},
-  };
-
-  for (const auto& drive : old_team_drives) {
-    drive_service_->AddTeamDrive(drive.first, drive.second);
-  }
-
-  for (const auto& drive : new_team_drives) {
-    drive_service_->AddTeamDrive(drive.first, drive.second);
-  }
-
-  std::string root_local_id;
-  ASSERT_EQ(FILE_ERROR_OK,
-            metadata_->GetIdByPath(util::GetDriveTeamDrivesRootPath(),
-                                   &root_local_id));
-
-  for (const auto& drive : old_team_drives) {
-    std::string local_id;
-    ASSERT_EQ(FILE_ERROR_OK,
-              metadata_->AddEntry(CreateDirectoryEntryWithResourceId(
-                                      drive.second, drive.first, root_local_id),
-                                  &local_id));
-  }
-
-  FileError error = FILE_ERROR_FAILED;
-  team_drive_list_loader_->CheckForUpdates(
-      google_apis::test_util::CreateCopyResultCallback(&error));
-  base::RunLoop().RunUntilIdle();
-  EXPECT_EQ(FILE_ERROR_OK, error);
-  EXPECT_EQ(1, drive_service_->team_drive_list_load_count());
-
-  EXPECT_EQ(old_team_drives.size() + new_team_drives.size(),
-            team_drive_list_observer_->team_drives_list().size());
-  EXPECT_EQ(new_team_drives.size(),
-            team_drive_list_observer_->added_team_drives().size());
-  EXPECT_TRUE(team_drive_list_observer_->removed_team_drives().empty());
-
-  ResourceEntryVector entries;
-  EXPECT_EQ(FILE_ERROR_OK, metadata_->ReadDirectoryByPath(
-                               util::GetDriveTeamDrivesRootPath(), &entries));
-  EXPECT_EQ(new_team_drives.size() + old_team_drives.size(), entries.size());
-
-  ResourceEntry entry;
-  for (const auto& drive : new_team_drives) {
-    EXPECT_EQ(FILE_ERROR_OK,
-              metadata_->GetResourceEntryByPath(
-                  util::GetDriveTeamDrivesRootPath().AppendASCII(drive.second),
-                  &entry));
-    EXPECT_EQ(drive.first, entry.resource_id());
-    EXPECT_EQ(drive.second, entry.base_name());
-    EXPECT_TRUE(entry.file_info().is_directory());
-    EXPECT_EQ("", entry.directory_specific_info().start_page_token());
-  }
-
-  for (const auto& drive : old_team_drives) {
-    EXPECT_EQ(FILE_ERROR_OK,
-              metadata_->GetResourceEntryByPath(
-                  util::GetDriveTeamDrivesRootPath().AppendASCII(drive.second),
-                  &entry));
-    EXPECT_EQ(drive.first, entry.resource_id());
-    EXPECT_EQ(drive.second, entry.base_name());
-    EXPECT_TRUE(entry.file_info().is_directory());
-    EXPECT_EQ(kTestStartPageToken,
-              entry.directory_specific_info().start_page_token());
-  }
-}
-
-// Tests that if we we had team drives stored locally that are no longer on the
-// server that we deleted them correctly.
-TEST_F(TeamDriveListLoaderTest, RemoveMissingTeamDriveFromMetadata) {
-  const std::vector<std::pair<std::string, std::string>> old_team_drives = {
-      {"the1stTeamDriveId", "The First Team Drive"},
-      {"the2ndTeamDriveId", "The Second Team Drive"},
-  };
-
-  std::string root_local_id;
-  ASSERT_EQ(FILE_ERROR_OK,
-            metadata_->GetIdByPath(util::GetDriveTeamDrivesRootPath(),
-                                   &root_local_id));
-
-  for (const auto& drive : old_team_drives) {
-    std::string local_id;
-    ASSERT_EQ(FILE_ERROR_OK,
-              metadata_->AddEntry(CreateDirectoryEntryWithResourceId(
-                                      drive.second, drive.first, root_local_id),
-                                  &local_id));
-  }
-
-  FileError error = FILE_ERROR_FAILED;
-  team_drive_list_loader_->CheckForUpdates(
-      google_apis::test_util::CreateCopyResultCallback(&error));
-  base::RunLoop().RunUntilIdle();
-  EXPECT_EQ(FILE_ERROR_OK, error);
-  EXPECT_EQ(1, drive_service_->team_drive_list_load_count());
-
-  EXPECT_TRUE(team_drive_list_observer_->team_drives_list().empty());
-  EXPECT_TRUE(team_drive_list_observer_->added_team_drives().empty());
-  EXPECT_EQ(old_team_drives.size(),
-            team_drive_list_observer_->removed_team_drives().size());
-
-  ResourceEntry entry;
-  for (const auto& drive : old_team_drives) {
-    EXPECT_EQ(FILE_ERROR_NOT_FOUND,
-              metadata_->GetResourceEntryByPath(
-                  util::GetDriveTeamDrivesRootPath().AppendASCII(drive.second),
-                  &entry));
-  }
-}
-
-}  // namespace internal
-}  // namespace drive
diff --git a/components/exo/text_input.cc b/components/exo/text_input.cc
index 1ff8822..d004a1f 100644
--- a/components/exo/text_input.cc
+++ b/components/exo/text_input.cc
@@ -119,7 +119,12 @@
   delegate_->SetCompositionText(composition);
 }
 
-void TextInput::ConfirmCompositionText() {
+void TextInput::ConfirmCompositionText(bool keep_selection) {
+  // TODO(b/134473433) Modify this function so that when keep_selection is
+  // true, the selection is not changed when text committed
+  if (keep_selection) {
+    NOTIMPLEMENTED_LOG_ONCE();
+  }
   delegate_->Commit(composition_.text);
 }
 
diff --git a/components/exo/text_input.h b/components/exo/text_input.h
index 25ba6e9..cbdc7a2b 100644
--- a/components/exo/text_input.h
+++ b/components/exo/text_input.h
@@ -105,7 +105,7 @@
 
   // ui::TextInputClient:
   void SetCompositionText(const ui::CompositionText& composition) override;
-  void ConfirmCompositionText() override;
+  void ConfirmCompositionText(bool keep_selection) override;
   void ClearCompositionText() override;
   void InsertText(const base::string16& text) override;
   void InsertChar(const ui::KeyEvent& event) override;
diff --git a/components/exo/text_input_unittest.cc b/components/exo/text_input_unittest.cc
index f357f38..88f3c38 100644
--- a/components/exo/text_input_unittest.cc
+++ b/components/exo/text_input_unittest.cc
@@ -250,7 +250,7 @@
   SetCompositionText("composition");
 
   EXPECT_CALL(*delegate(), Commit(base::UTF8ToUTF16("composition"))).Times(1);
-  text_input()->ConfirmCompositionText();
+  text_input()->ConfirmCompositionText(/** keep_selection */ false);
 }
 
 TEST_F(TextInputTest, Commit) {
diff --git a/components/omnibox/browser/omnibox_edit_model.cc b/components/omnibox/browser/omnibox_edit_model.cc
index 3c965a8..88a12982 100644
--- a/components/omnibox/browser/omnibox_edit_model.cc
+++ b/components/omnibox/browser/omnibox_edit_model.cc
@@ -1475,6 +1475,10 @@
 const char OmniboxEditModel::kCutOrCopyAllTextHistogram[] =
     "Omnibox.CutOrCopyAllText";
 
+void OmniboxEditModel::SetAccessibilityLabel(const AutocompleteMatch& match) {
+  view_->SetAccessibilityLabel(view_->GetText(), match);
+}
+
 bool OmniboxEditModel::PopupIsOpen() const {
   return popup_model() && popup_model()->IsOpen();
 }
diff --git a/components/omnibox/browser/omnibox_edit_model.h b/components/omnibox/browser/omnibox_edit_model.h
index b54dc4e..65b5447 100644
--- a/components/omnibox/browser/omnibox_edit_model.h
+++ b/components/omnibox/browser/omnibox_edit_model.h
@@ -385,7 +385,8 @@
   // Name of the histogram tracking cut or copy omnibox commands.
   static const char kCutOrCopyAllTextHistogram[];
 
-  OmniboxView* view() { return view_; }
+  // Just forwards the call to the OmniboxView referred within.
+  void SetAccessibilityLabel(const AutocompleteMatch& match);
 
  private:
   friend class OmniboxControllerTest;
diff --git a/components/omnibox/browser/omnibox_popup_model.cc b/components/omnibox/browser/omnibox_popup_model.cc
index b4ee988..1acef07 100644
--- a/components/omnibox/browser/omnibox_popup_model.cc
+++ b/components/omnibox/browser/omnibox_popup_model.cc
@@ -195,8 +195,7 @@
   view_->InvalidateLine(selected_line_);
 
   if (state == BUTTON_FOCUSED) {
-    edit_model_->view()->SetAccessibilityLabel(edit_model_->view()->GetText(),
-                                               match);
+    edit_model_->SetAccessibilityLabel(match);
     view_->ProvideButtonFocusHint(selected_line_);
   }
 }
diff --git a/components/optimization_guide/optimization_guide_enums.h b/components/optimization_guide/optimization_guide_enums.h
index 89ee8e3..88d1eb73 100644
--- a/components/optimization_guide/optimization_guide_enums.h
+++ b/components/optimization_guide/optimization_guide_enums.h
@@ -40,9 +40,13 @@
   kNoHintAvailable,
   // The OptimizationGuideDecider was not initialized yet.
   kDeciderNotInitialized,
+  // A fetch to get the hint for the page load from the remote Optimization
+  // Guide Service was started, but was not available in time to make a
+  // decision.
+  kHintFetchStartedButNotAvailableInTime,
 
   // Add new values above this line.
-  kMaxValue = kDeciderNotInitialized,
+  kMaxValue = kHintFetchStartedButNotAvailableInTime,
 };
 
 // The types of decisions that can be made for an optimization target.
diff --git a/components/password_manager/core/browser/login_database.cc b/components/password_manager/core/browser/login_database.cc
index cada731..26f7f1b 100644
--- a/components/password_manager/core/browser/login_database.cc
+++ b/components/password_manager/core/browser/login_database.cc
@@ -144,6 +144,7 @@
   MIGRATION_ERROR,
   COMMIT_TRANSACTION_ERROR,
   INIT_LEAKED_CREDENTIALS_ERROR,
+  INIT_FIELD_INFO_ERROR,
 
   DATABASE_INIT_ERROR_COUNT,
 };
@@ -774,6 +775,7 @@
 
   stats_table_.Init(&db_);
   leaked_credentials_table_.Init(&db_);
+  field_info_table_.Init(&db_);
 
   int current_version = meta_table_.GetVersionNumber();
   bool migration_success = FixVersionIfNeeded(&db_, &current_version);
@@ -820,6 +822,14 @@
     return false;
   }
 
+  if (!field_info_table_.CreateTableIfNecessary()) {
+    LogDatabaseInitError(INIT_FIELD_INFO_ERROR);
+    LOG(ERROR) << "Unable to create the field info table.";
+    transaction.Rollback();
+    db_.Close();
+    return false;
+  }
+
   if (!transaction.Commit()) {
     LogDatabaseInitError(COMMIT_TRANSACTION_ERROR);
     LOG(ERROR) << "Unable to commit a transaction.";
diff --git a/components/password_manager/core/browser/login_database.h b/components/password_manager/core/browser/login_database.h
index e2c73b9..5f5065c 100644
--- a/components/password_manager/core/browser/login_database.h
+++ b/components/password_manager/core/browser/login_database.h
@@ -17,6 +17,7 @@
 #include "base/util/type_safety/strong_alias.h"
 #include "build/build_config.h"
 #include "components/password_manager/core/browser/compromised_credentials_table.h"
+#include "components/password_manager/core/browser/field_info_table.h"
 #include "components/password_manager/core/browser/password_store.h"
 #include "components/password_manager/core/browser/password_store_change.h"
 #include "components/password_manager/core/browser/password_store_sync.h"
@@ -209,6 +210,8 @@
     return leaked_credentials_table_;
   }
 
+  FieldInfoTable& field_info_table() { return field_info_table_; }
+
 #if defined(OS_POSIX) && !defined(OS_MACOSX)
   void enable_encryption() { use_encryption_ = true; }
   // This instance should not encrypt/decrypt password values using OSCrypt.
@@ -323,6 +326,7 @@
   sql::MetaTable meta_table_;
   StatisticsTable stats_table_;
   LeakedCredentialsTable leaked_credentials_table_;
+  FieldInfoTable field_info_table_;
 
   // These cached strings are used to build SQL statements.
   std::string add_statement_;
diff --git a/components/password_manager/core/browser/mock_password_store.h b/components/password_manager/core/browser/mock_password_store.h
index 7f673f05..1d86ce0 100644
--- a/components/password_manager/core/browser/mock_password_store.h
+++ b/components/password_manager/core/browser/mock_password_store.h
@@ -11,6 +11,7 @@
 
 #include "components/autofill/core/common/password_form.h"
 #include "components/password_manager/core/browser/compromised_credentials_table.h"
+#include "components/password_manager/core/browser/field_info_table.h"
 #include "components/password_manager/core/browser/password_store.h"
 #include "components/password_manager/core/browser/statistics_table.h"
 #include "testing/gmock/include/gmock/gmock.h"
@@ -80,6 +81,10 @@
                void(const base::RepeatingCallback<bool(const GURL&)>&,
                     base::Time,
                     base::Time));
+  MOCK_METHOD1(AddFieldInfoImpl, void(const FieldInfo&));
+  MOCK_METHOD0(GetAllFieldInfoImpl, std::vector<FieldInfo>());
+  MOCK_METHOD2(RemoveFieldInfoByTimeImpl, void(base::Time, base::Time));
+
   MOCK_CONST_METHOD0(IsAbleToSavePasswords, bool());
 
 #if defined(SYNC_PASSWORD_REUSE_DETECTION_ENABLED)
diff --git a/components/password_manager/core/browser/password_form_manager.cc b/components/password_manager/core/browser/password_form_manager.cc
index 82ce861..af5f94e 100644
--- a/components/password_manager/core/browser/password_form_manager.cc
+++ b/components/password_manager/core/browser/password_form_manager.cc
@@ -941,8 +941,7 @@
     is_new_login_ = true;
     // No stored credentials can be matched to the submitted form. Offer to
     // save new credentials.
-    CreatePendingCredentialsForNewCredentials(*parsed_submitted_form_,
-                                              password_to_save.second);
+    CreatePendingCredentialsForNewCredentials(password_to_save.second);
     // Generate username correction votes.
     bool username_correction_found =
         votes_uploader_.FindCorrectedUsernameElement(
@@ -989,28 +988,14 @@
 }
 
 void PasswordFormManager::CreatePendingCredentialsForNewCredentials(
-    const PasswordForm& submitted_password_form,
     const base::string16& password_element) {
   if (IsHttpAuth() || IsCredentialAPISave()) {
-    pending_credentials_ = submitted_password_form;
+    pending_credentials_ = *parsed_submitted_form_;
     return;
   }
 
-  // TODO(https://crbug.com/831123): Replace parsing of the observed form with
-  // usage of already parsed submitted form.
-  std::unique_ptr<PasswordForm> parsed_observed_form =
-      ParseFormAndMakeLogging(observed_form_, FormDataParser::Mode::kFilling);
-  if (!parsed_observed_form)
-    return;
-  pending_credentials_ = *parsed_observed_form;
-  pending_credentials_.username_element =
-      submitted_password_form.username_element;
-  pending_credentials_.username_value = submitted_password_form.username_value;
-  pending_credentials_.all_possible_usernames =
-      submitted_password_form.all_possible_usernames;
-  pending_credentials_.all_possible_passwords =
-      submitted_password_form.all_possible_passwords;
-
+  pending_credentials_ = *parsed_submitted_form_;
+  pending_credentials_.form_data = observed_form_;
   // The password value will be filled in later, remove any garbage for now.
   pending_credentials_.password_value.clear();
   // The password element should be determined earlier in |PasswordToSave|.
diff --git a/components/password_manager/core/browser/password_form_manager.h b/components/password_manager/core/browser/password_form_manager.h
index b7a64df..1522780 100644
--- a/components/password_manager/core/browser/password_form_manager.h
+++ b/components/password_manager/core/browser/password_form_manager.h
@@ -242,9 +242,8 @@
   void ReportTimeBetweenStoreAndServerUMA();
 
   // Create pending credentials from provisionally saved form when this form
-  // represents credentials that were not previosly saved.
+  // represents credentials that were not previously saved.
   void CreatePendingCredentialsForNewCredentials(
-      const autofill::PasswordForm& submitted_password_form,
       const base::string16& password_element);
 
   void SetPasswordOverridden(bool password_overridden) {
diff --git a/components/password_manager/core/browser/password_store.cc b/components/password_manager/core/browser/password_store.cc
index a6cc833..37625a2f 100644
--- a/components/password_manager/core/browser/password_store.cc
+++ b/components/password_manager/core/browser/password_store.cc
@@ -25,6 +25,7 @@
 #include "components/autofill/core/common/password_form.h"
 #include "components/password_manager/core/browser/android_affiliation/affiliated_match_helper.h"
 #include "components/password_manager/core/browser/compromised_credentials_table.h"
+#include "components/password_manager/core/browser/field_info_table.h"
 #include "components/password_manager/core/browser/password_leak_history_consumer.h"
 #include "components/password_manager/core/browser/password_manager_metrics_util.h"
 #include "components/password_manager/core/browser/password_manager_util.h"
@@ -371,6 +372,32 @@
       std::move(url_filter), remove_begin, remove_end, std::move(completion)));
 }
 
+void PasswordStore::AddFieldInfo(const FieldInfo& field_info) {
+  DCHECK(main_task_runner_->RunsTasksInCurrentSequence());
+  ScheduleTask(
+      base::BindOnce(&PasswordStore::AddFieldInfoImpl, this, field_info));
+}
+
+void PasswordStore::GetAllFieldInfo(PasswordStoreConsumer* consumer) {
+  DCHECK(main_task_runner_->RunsTasksInCurrentSequence());
+  auto get_all_field_info_task =
+      base::BindOnce(&PasswordStore::GetAllFieldInfoImpl, this);
+  consumer->cancelable_task_tracker()->PostTaskAndReplyWithResult(
+      background_task_runner_.get(), FROM_HERE,
+      std::move(get_all_field_info_task),
+      base::BindOnce(&PasswordStoreConsumer::OnGetAllFieldInfo,
+                     consumer->GetWeakPtr()));
+}
+
+void PasswordStore::RemoveFieldInfoByTime(base::Time remove_begin,
+                                          base::Time remove_end,
+                                          base::OnceClosure completion) {
+  DCHECK(main_task_runner_->RunsTasksInCurrentSequence());
+  ScheduleTask(base::BindOnce(&PasswordStore::RemoveFieldInfoByTimeInternal,
+                              this, remove_begin, remove_end,
+                              std::move(completion)));
+}
+
 void PasswordStore::AddObserver(Observer* observer) {
   observers_->AddObserver(observer);
 }
@@ -871,6 +898,15 @@
     main_task_runner_->PostTask(FROM_HERE, std::move(completion));
 }
 
+void PasswordStore::RemoveFieldInfoByTimeInternal(
+    base::Time remove_begin,
+    base::Time remove_end,
+    base::OnceClosure completion) {
+  RemoveFieldInfoByTimeImpl(remove_begin, remove_end);
+  if (!completion.is_null())
+    main_task_runner_->PostTask(FROM_HERE, std::move(completion));
+}
+
 std::vector<std::unique_ptr<autofill::PasswordForm>>
 PasswordStore::GetLoginsImpl(const FormDigest& form) {
   DCHECK(background_task_runner_->RunsTasksInCurrentSequence());
diff --git a/components/password_manager/core/browser/password_store.h b/components/password_manager/core/browser/password_store.h
index 3e1a077..639ceb1 100644
--- a/components/password_manager/core/browser/password_store.h
+++ b/components/password_manager/core/browser/password_store.h
@@ -58,6 +58,7 @@
 class PasswordStoreSigninNotifier;
 class PasswordSyncableService;
 class PasswordSyncBridge;
+struct FieldInfo;
 struct InteractionsStats;
 struct LeakedCredentials;
 
@@ -264,6 +265,21 @@
       base::Time remove_end,
       base::OnceClosure completion);
 
+  // Adds information about field. If the record for given form_signature and
+  // field_signature already exists, the new one will be ignored.
+  void AddFieldInfo(const FieldInfo& field_info);
+
+  // Retrieves all field info and notifies |consumer| on completion. The request
+  // will be cancelled if the consumer is destroyed.
+  void GetAllFieldInfo(PasswordStoreConsumer* consumer);
+
+  // Removes all leaked credentials in the given date range. If |completion| is
+  // not null, it will be posted to the |main_task_runner_| after deletions have
+  // been completed. Should be called on the UI thread.
+  void RemoveFieldInfoByTime(base::Time remove_begin,
+                             base::Time remove_end,
+                             base::OnceClosure completion);
+
   // Adds an observer to be notified when the password store data changes.
   void AddObserver(Observer* observer);
 
@@ -469,6 +485,13 @@
       base::Time remove_begin,
       base::Time remove_end) = 0;
 
+  // Synchronous implementation for manipulating with information about field
+  // info.
+  virtual void AddFieldInfoImpl(const FieldInfo& field_info) = 0;
+  virtual std::vector<FieldInfo> GetAllFieldInfoImpl() = 0;
+  virtual void RemoveFieldInfoByTimeImpl(base::Time remove_begin,
+                                         base::Time remove_end) = 0;
+
   // PasswordStoreSync:
   PasswordStoreChangeList AddLoginSync(const autofill::PasswordForm& form,
                                        AddLoginError* error) override;
@@ -613,6 +636,10 @@
       base::Time remove_end,
       base::OnceClosure completion);
 
+  void RemoveFieldInfoByTimeInternal(base::Time remove_begin,
+                                     base::Time remove_end,
+                                     base::OnceClosure completion);
+
   // Finds all PasswordForms with a signon_realm that is equal to, or is a
   // PSL-match to that of |form|, and takes care of notifying the consumer with
   // the results when done.
diff --git a/components/password_manager/core/browser/password_store_consumer.cc b/components/password_manager/core/browser/password_store_consumer.cc
index 2a9904b..e4e4d4b 100644
--- a/components/password_manager/core/browser/password_store_consumer.cc
+++ b/components/password_manager/core/browser/password_store_consumer.cc
@@ -4,18 +4,21 @@
 
 #include "components/password_manager/core/browser/password_store_consumer.h"
 
+#include "components/password_manager/core/browser/field_info_table.h"
 #include "components/password_manager/core/browser/statistics_table.h"
 
 namespace password_manager {
 
-PasswordStoreConsumer::PasswordStoreConsumer() {}
+PasswordStoreConsumer::PasswordStoreConsumer() = default;
 
-PasswordStoreConsumer::~PasswordStoreConsumer() {
-}
+PasswordStoreConsumer::~PasswordStoreConsumer() = default;
 
 void PasswordStoreConsumer::OnGetSiteStatistics(
     std::vector<InteractionsStats> stats) {}
 
+void PasswordStoreConsumer::OnGetAllFieldInfo(
+    std::vector<FieldInfo> field_info) {}
+
 void PasswordStoreConsumer::CancelAllRequests() {
   cancelable_task_tracker_.TryCancelAll();
   weak_ptr_factory_.InvalidateWeakPtrs();
diff --git a/components/password_manager/core/browser/password_store_consumer.h b/components/password_manager/core/browser/password_store_consumer.h
index 14b70dd..5e8e25d 100644
--- a/components/password_manager/core/browser/password_store_consumer.h
+++ b/components/password_manager/core/browser/password_store_consumer.h
@@ -16,6 +16,7 @@
 
 namespace password_manager {
 
+struct FieldInfo;
 struct InteractionsStats;
 
 // Reads from the PasswordStore are done asynchronously on a separate
@@ -32,10 +33,14 @@
   virtual void OnGetPasswordStoreResults(
       std::vector<std::unique_ptr<autofill::PasswordForm>> results) = 0;
 
-  // Called when the GetLogins() request is finished, with the associated site
-  // statistics.
+  // Called when the GetSiteStats() request is finished, with the associated
+  // site statistics.
   virtual void OnGetSiteStatistics(std::vector<InteractionsStats> stats);
 
+  // Called when the GetAllFieldInfo() request is finished, with the associated
+  // field info.
+  virtual void OnGetAllFieldInfo(std::vector<FieldInfo> field_info);
+
   // The base::CancelableTaskTracker can be used for cancelling the
   // tasks associated with the consumer.
   base::CancelableTaskTracker* cancelable_task_tracker() {
diff --git a/components/password_manager/core/browser/password_store_default.cc b/components/password_manager/core/browser/password_store_default.cc
index c37b5cf..369266c 100644
--- a/components/password_manager/core/browser/password_store_default.cc
+++ b/components/password_manager/core/browser/password_store_default.cc
@@ -254,6 +254,22 @@
   }
 }
 
+void PasswordStoreDefault::AddFieldInfoImpl(const FieldInfo& field_info) {
+  if (login_db_)
+    login_db_->field_info_table().AddRow(field_info);
+}
+
+std::vector<FieldInfo> PasswordStoreDefault::GetAllFieldInfoImpl() {
+  return login_db_ ? login_db_->field_info_table().GetAllRows()
+                   : std::vector<FieldInfo>();
+}
+
+void PasswordStoreDefault::RemoveFieldInfoByTimeImpl(base::Time remove_begin,
+                                                     base::Time remove_end) {
+  if (login_db_)
+    login_db_->field_info_table().RemoveRowsByTime(remove_begin, remove_end);
+}
+
 bool PasswordStoreDefault::BeginTransaction() {
   if (login_db_)
     return login_db_->BeginTransaction();
diff --git a/components/password_manager/core/browser/password_store_default.h b/components/password_manager/core/browser/password_store_default.h
index b48f8ee8..ce3b18f 100644
--- a/components/password_manager/core/browser/password_store_default.h
+++ b/components/password_manager/core/browser/password_store_default.h
@@ -82,6 +82,11 @@
       base::Time remove_begin,
       base::Time remove_end) override;
 
+  void AddFieldInfoImpl(const FieldInfo& field_info) override;
+  std::vector<FieldInfo> GetAllFieldInfoImpl() override;
+  void RemoveFieldInfoByTimeImpl(base::Time remove_begin,
+                                 base::Time remove_end) override;
+
   // Implements PasswordStoreSync interface.
   bool BeginTransaction() override;
   void RollbackTransaction() override;
diff --git a/components/password_manager/core/browser/password_store_unittest.cc b/components/password_manager/core/browser/password_store_unittest.cc
index 1326f1a..c23bdf7c 100644
--- a/components/password_manager/core/browser/password_store_unittest.cc
+++ b/components/password_manager/core/browser/password_store_unittest.cc
@@ -92,6 +92,7 @@
 
   MOCK_METHOD1(OnGetPasswordStoreResultsConstRef,
                void(const std::vector<std::unique_ptr<PasswordForm>>&));
+  MOCK_METHOD1(OnGetAllFieldInfo, void(const std::vector<FieldInfo>));
 
   // GMock cannot mock methods with move-only args.
   void OnGetPasswordStoreResults(
@@ -1246,6 +1247,7 @@
       GaiaPasswordHashChange::NOT_SYNC_PASSWORD_CHANGE, 1);
   store->ShutdownOnUIThread();
 }
+#endif
 
 TEST_F(PasswordStoreTest, GetAllLeakedCredentials) {
   LeakedCredentials leaked_credentials(GURL("https://example.com"),
@@ -1315,6 +1317,57 @@
   store->ShutdownOnUIThread();
 }
 
-#endif
+TEST_F(PasswordStoreTest, GetAllFieldInfo) {
+  FieldInfo field_info1{1001 /*form_signature*/, 1 /* field_signature */,
+                        autofill::USERNAME, base::Time::FromTimeT(1)};
+  FieldInfo field_info2{1002 /*form_signature*/, 10 /* field_signature */,
+                        autofill::PASSWORD, base::Time::FromTimeT(2)};
+  scoped_refptr<PasswordStoreDefault> store = CreatePasswordStore();
+  store->Init(syncer::SyncableService::StartSyncFlare(), nullptr);
+
+  store->AddFieldInfo(field_info1);
+  store->AddFieldInfo(field_info2);
+  MockPasswordStoreConsumer consumer;
+  EXPECT_CALL(consumer, OnGetAllFieldInfo(
+                            UnorderedElementsAre(field_info1, field_info2)));
+  store->GetAllFieldInfo(&consumer);
+  WaitForPasswordStore();
+
+  store->ShutdownOnUIThread();
+}
+
+TEST_F(PasswordStoreTest, RemoveFieldInfo) {
+  FieldInfo field_info1{1001 /*form_signature*/, 1 /* field_signature */,
+                        autofill::USERNAME, base::Time::FromTimeT(100)};
+  FieldInfo field_info2{1002 /*form_signature*/, 10 /* field_signature */,
+                        autofill::PASSWORD, base::Time::FromTimeT(200)};
+
+  FieldInfo field_info3{1003 /*form_signature*/, 11 /* field_signature */,
+                        autofill::PASSWORD, base::Time::FromTimeT(300)};
+
+  scoped_refptr<PasswordStoreDefault> store = CreatePasswordStore();
+  store->Init(syncer::SyncableService::StartSyncFlare(), nullptr);
+
+  store->AddFieldInfo(field_info1);
+  store->AddFieldInfo(field_info2);
+  store->AddFieldInfo(field_info3);
+
+  MockPasswordStoreConsumer consumer;
+  EXPECT_CALL(consumer, OnGetAllFieldInfo(UnorderedElementsAre(
+                            field_info1, field_info2, field_info3)));
+  store->GetAllFieldInfo(&consumer);
+  WaitForPasswordStore();
+  testing::Mock::VerifyAndClearExpectations(&consumer);
+
+  store->RemoveFieldInfoByTime(base::Time::FromTimeT(150),
+                               base::Time::FromTimeT(250), base::Closure());
+
+  EXPECT_CALL(consumer, OnGetAllFieldInfo(
+                            UnorderedElementsAre(field_info1, field_info3)));
+  store->GetAllFieldInfo(&consumer);
+  WaitForPasswordStore();
+
+  store->ShutdownOnUIThread();
+}
 
 }  // namespace password_manager
diff --git a/components/password_manager/core/browser/test_password_store.cc b/components/password_manager/core/browser/test_password_store.cc
index 872c8a8..3ac548e 100644
--- a/components/password_manager/core/browser/test_password_store.cc
+++ b/components/password_manager/core/browser/test_password_store.cc
@@ -249,6 +249,19 @@
   NOTIMPLEMENTED();
 }
 
+void TestPasswordStore::AddFieldInfoImpl(const FieldInfo& field_info) {
+  NOTIMPLEMENTED();
+}
+std::vector<FieldInfo> TestPasswordStore::GetAllFieldInfoImpl() {
+  NOTIMPLEMENTED();
+  return std::vector<FieldInfo>();
+}
+
+void TestPasswordStore::RemoveFieldInfoByTimeImpl(base::Time remove_begin,
+                                                  base::Time remove_end) {
+  NOTIMPLEMENTED();
+}
+
 bool TestPasswordStore::BeginTransaction() {
   return true;
 }
diff --git a/components/password_manager/core/browser/test_password_store.h b/components/password_manager/core/browser/test_password_store.h
index 53cb38e..2ec2c8c1 100644
--- a/components/password_manager/core/browser/test_password_store.h
+++ b/components/password_manager/core/browser/test_password_store.h
@@ -94,6 +94,10 @@
       const base::RepeatingCallback<bool(const GURL&)>& url_filter,
       base::Time remove_begin,
       base::Time remove_end) override;
+  void AddFieldInfoImpl(const FieldInfo& field_info) override;
+  std::vector<FieldInfo> GetAllFieldInfoImpl() override;
+  void RemoveFieldInfoByTimeImpl(base::Time remove_begin,
+                                 base::Time remove_end) override;
 
   // PasswordStoreSync interface.
   bool BeginTransaction() override;
diff --git a/components/signin/internal/identity_manager/ubertoken_fetcher_impl.cc b/components/signin/internal/identity_manager/ubertoken_fetcher_impl.cc
index bc5b9f19..3053e34b 100644
--- a/components/signin/internal/identity_manager/ubertoken_fetcher_impl.cc
+++ b/components/signin/internal/identity_manager/ubertoken_fetcher_impl.cc
@@ -34,28 +34,24 @@
     ProfileOAuth2TokenService* token_service,
     CompletionCallback ubertoken_callback,
     gaia::GaiaSource source,
-    scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
-    bool is_bound_to_channel_id)
+    scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory)
     : UbertokenFetcherImpl(account_id,
                            /*access_token=*/"",
                            token_service,
                            std::move(ubertoken_callback),
                            base::BindRepeating(CreateGaiaAuthFetcher,
                                                source,
-                                               url_loader_factory),
-                           is_bound_to_channel_id) {}
+                                               url_loader_factory)) {}
 
 UbertokenFetcherImpl::UbertokenFetcherImpl(
     const CoreAccountId& account_id,
     const std::string& access_token,
     ProfileOAuth2TokenService* token_service,
     CompletionCallback ubertoken_callback,
-    GaiaAuthFetcherFactory factory,
-    bool is_bound_to_channel_id)
+    GaiaAuthFetcherFactory factory)
     : OAuth2AccessTokenManager::Consumer("uber_token_fetcher"),
       token_service_(token_service),
       ubertoken_callback_(std::move(ubertoken_callback)),
-      is_bound_to_channel_id_(is_bound_to_channel_id),
       gaia_auth_fetcher_factory_(factory),
       account_id_(account_id),
       access_token_(access_token),
@@ -146,8 +142,7 @@
 
 void UbertokenFetcherImpl::ExchangeTokens() {
   gaia_auth_fetcher_ = gaia_auth_fetcher_factory_.Run(this);
-  gaia_auth_fetcher_->StartTokenFetchForUberAuthExchange(
-      access_token_, is_bound_to_channel_id_);
+  gaia_auth_fetcher_->StartTokenFetchForUberAuthExchange(access_token_);
 }
 
 }  // namespace signin
diff --git a/components/signin/internal/identity_manager/ubertoken_fetcher_impl.h b/components/signin/internal/identity_manager/ubertoken_fetcher_impl.h
index 8f38c5d..59247e8 100644
--- a/components/signin/internal/identity_manager/ubertoken_fetcher_impl.h
+++ b/components/signin/internal/identity_manager/ubertoken_fetcher_impl.h
@@ -55,16 +55,14 @@
       ProfileOAuth2TokenService* token_service,
       CompletionCallback ubertoken_callback,
       gaia::GaiaSource source,
-      scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
-      bool is_bound_to_channel_id = true);
+      scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory);
 
   // Constructs an instance and starts fetching the ubertoken for |account_id|.
   UbertokenFetcherImpl(const CoreAccountId& account_id,
                        const std::string& access_token,
                        ProfileOAuth2TokenService* token_service,
                        CompletionCallback ubertoken_callback,
-                       GaiaAuthFetcherFactory factory,
-                       bool is_bound_to_channel_id = true);
+                       GaiaAuthFetcherFactory factory);
   ~UbertokenFetcherImpl() override;
 
   // Overridden from GaiaAuthConsumer
@@ -87,7 +85,6 @@
 
   ProfileOAuth2TokenService* token_service_;
   CompletionCallback ubertoken_callback_;
-  bool is_bound_to_channel_id_;  // defaults to true
   GaiaAuthFetcherFactory gaia_auth_fetcher_factory_;
   std::unique_ptr<GaiaAuthFetcher> gaia_auth_fetcher_;
   std::unique_ptr<OAuth2AccessTokenManager::Request> access_token_request_;
diff --git a/components/signin/public/identity_manager/identity_manager.cc b/components/signin/public/identity_manager/identity_manager.cc
index 97612ba..8990fc2 100644
--- a/components/signin/public/identity_manager/identity_manager.cc
+++ b/components/signin/public/identity_manager/identity_manager.cc
@@ -296,11 +296,10 @@
     const CoreAccountId& account_id,
     UbertokenFetcher::CompletionCallback callback,
     gaia::GaiaSource source,
-    scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
-    bool bount_to_channel_id) {
+    scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory) {
   return std::make_unique<UbertokenFetcherImpl>(
       account_id, token_service_.get(), std::move(callback), source,
-      url_loader_factory, bount_to_channel_id);
+      url_loader_factory);
 }
 
 AccountsInCookieJarInfo IdentityManager::GetAccountsInCookieJar() const {
diff --git a/components/signin/public/identity_manager/identity_manager.h b/components/signin/public/identity_manager/identity_manager.h
index 4b30bc8..a3d9272 100644
--- a/components/signin/public/identity_manager/identity_manager.h
+++ b/components/signin/public/identity_manager/identity_manager.h
@@ -295,8 +295,7 @@
       const CoreAccountId& account_id,
       UbertokenFetcher::CompletionCallback callback,
       gaia::GaiaSource source,
-      scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
-      bool bound_to_channel_id = true);
+      scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory);
 
   // Provides the information of all accounts that are present in the Gaia
   // cookie in the cookie jar, ordered by their order in the cookie.
diff --git a/components/sync/driver/syncable_service_based_model_type_controller.cc b/components/sync/driver/syncable_service_based_model_type_controller.cc
index 4e90a70..324664d 100644
--- a/components/sync/driver/syncable_service_based_model_type_controller.cc
+++ b/components/sync/driver/syncable_service_based_model_type_controller.cc
@@ -22,14 +22,13 @@
                      base::WeakPtr<SyncableService> syncable_service,
                      const base::RepeatingClosure& dump_stack)
       : type_(type),
-        store_factory_(std::move(store_factory)),
         dump_stack_(dump_stack) {
-    DCHECK(store_factory_);
+    DCHECK(store_factory);
 
     // The |syncable_service| can be null in tests.
     if (syncable_service) {
       bridge_ = std::make_unique<SyncableServiceBasedBridge>(
-          type_, std::move(store_factory_),
+          type_, std::move(store_factory),
           std::make_unique<ClientTagBasedModelTypeProcessor>(type_,
                                                              dump_stack_),
           syncable_service.get());
@@ -66,7 +65,6 @@
   }
 
   const ModelType type_;
-  OnceModelTypeStoreFactory store_factory_;
   const base::RepeatingClosure dump_stack_;
   std::unique_ptr<ModelTypeSyncBridge> bridge_;
 
diff --git a/components/viz/host/host_gpu_memory_buffer_manager_unittest.cc b/components/viz/host/host_gpu_memory_buffer_manager_unittest.cc
index e1bd0c6..f1d7ac7 100644
--- a/components/viz/host/host_gpu_memory_buffer_manager_unittest.cc
+++ b/components/viz/host/host_gpu_memory_buffer_manager_unittest.cc
@@ -160,7 +160,7 @@
 
   void WakeUpGpu() override {}
 
-  void GpuSwitched() override {}
+  void GpuSwitched(gl::GpuPreference active_gpu_heuristic) override {}
 
   void DestroyAllChannels() override {}
 
diff --git a/components/viz/service/gl/gpu_service_impl.cc b/components/viz/service/gl/gpu_service_impl.cc
index 70b11ce..d38dfac5 100644
--- a/components/viz/service/gl/gpu_service_impl.cc
+++ b/components/viz/service/gl/gpu_service_impl.cc
@@ -813,10 +813,11 @@
 #endif
 }
 
-void GpuServiceImpl::GpuSwitched() {
+void GpuServiceImpl::GpuSwitched(gl::GpuPreference active_gpu_heuristic) {
   DVLOG(1) << "GPU: GPU has switched";
   if (!in_host_process())
-    ui::GpuSwitchingManager::GetInstance()->NotifyGpuSwitched();
+    ui::GpuSwitchingManager::GetInstance()->NotifyGpuSwitched(
+        active_gpu_heuristic);
 }
 
 void GpuServiceImpl::DestroyAllChannels() {
diff --git a/components/viz/service/gl/gpu_service_impl.h b/components/viz/service/gl/gpu_service_impl.h
index 7989adc..7919309 100644
--- a/components/viz/service/gl/gpu_service_impl.h
+++ b/components/viz/service/gl/gpu_service_impl.h
@@ -166,7 +166,7 @@
                     const std::string& key,
                     const std::string& data) override;
   void WakeUpGpu() override;
-  void GpuSwitched() override;
+  void GpuSwitched(gl::GpuPreference active_gpu_heuristic) override;
   void DestroyAllChannels() override;
   void OnBackgroundCleanup() override;
   void OnBackgrounded() override;
diff --git a/content/browser/accessibility/accessibility_win_browsertest.cc b/content/browser/accessibility/accessibility_win_browsertest.cc
index d9cc53c..cd80daa 100644
--- a/content/browser/accessibility/accessibility_win_browsertest.cc
+++ b/content/browser/accessibility/accessibility_win_browsertest.cc
@@ -3788,10 +3788,10 @@
 
     BrowserAccessibilityComWin* browser_accessibility_com_win =
         ToBrowserAccessibilityWin(browser_accessibility)->GetCOM();
-    CComPtr<IScrollProvider> scroll_provider;
+    Microsoft::WRL::ComPtr<IScrollProvider> scroll_provider;
 
     EXPECT_HRESULT_SUCCEEDED(browser_accessibility_com_win->GetPatternProvider(
-        UIA_ScrollPatternId, reinterpret_cast<IUnknown**>(&scroll_provider)));
+        UIA_ScrollPatternId, &scroll_provider));
 
     if (expected.can_scroll_vertical || expected.can_scroll_horizontal) {
       ASSERT_NE(nullptr, scroll_provider);
diff --git a/content/browser/accessibility/ax_platform_node_textprovider_win_browsertest.cc b/content/browser/accessibility/ax_platform_node_textprovider_win_browsertest.cc
index 2488119..48a76bc 100644
--- a/content/browser/accessibility/ax_platform_node_textprovider_win_browsertest.cc
+++ b/content/browser/accessibility/ax_platform_node_textprovider_win_browsertest.cc
@@ -23,19 +23,18 @@
 
 namespace content {
 
-#define ASSERT_UIA_SAFEARRAY_OF_TEXTRANGEPROVIDER(safearray, expected_size) \
-  {                                                                         \
-    EXPECT_EQ(sizeof(CComPtr<ITextRangeProvider>),                          \
-              ::SafeArrayGetElemsize(safearray));                           \
-    ASSERT_EQ(1u, SafeArrayGetDim(safearray));                              \
-    LONG array_lower_bound;                                                 \
-    ASSERT_HRESULT_SUCCEEDED(                                               \
-        SafeArrayGetLBound(safearray, 1, &array_lower_bound));              \
-    LONG array_upper_bound;                                                 \
-    ASSERT_HRESULT_SUCCEEDED(                                               \
-        SafeArrayGetUBound(safearray, 1, &array_upper_bound));              \
-    size_t count = array_upper_bound - array_lower_bound + 1;               \
-    ASSERT_EQ(expected_size, count);                                        \
+#define ASSERT_UIA_SAFEARRAY_OF_TEXTRANGEPROVIDER(safearray, expected_size)    \
+  {                                                                            \
+    EXPECT_EQ(sizeof(ITextRangeProvider*), ::SafeArrayGetElemsize(safearray)); \
+    ASSERT_EQ(1u, SafeArrayGetDim(safearray));                                 \
+    LONG array_lower_bound;                                                    \
+    ASSERT_HRESULT_SUCCEEDED(                                                  \
+        SafeArrayGetLBound(safearray, 1, &array_lower_bound));                 \
+    LONG array_upper_bound;                                                    \
+    ASSERT_HRESULT_SUCCEEDED(                                                  \
+        SafeArrayGetUBound(safearray, 1, &array_upper_bound));                 \
+    size_t count = array_upper_bound - array_lower_bound + 1;                  \
+    ASSERT_EQ(expected_size, count);                                           \
   }
 
 #define EXPECT_UIA_TEXTRANGE_EQ(provider, expected_content) \
@@ -172,11 +171,11 @@
   GetTextProviderFromTextNode(text_provider, node);
 
   base::win::ScopedSafearray text_provider_ranges;
-  CComPtr<ITextRangeProvider>* array_data;
   EXPECT_HRESULT_SUCCEEDED(
       text_provider->GetVisibleRanges(text_provider_ranges.Receive()));
   ASSERT_UIA_SAFEARRAY_OF_TEXTRANGEPROVIDER(text_provider_ranges.Get(), 2U);
 
+  ITextRangeProvider** array_data;
   ASSERT_HRESULT_SUCCEEDED(::SafeArrayAccessData(
       text_provider_ranges.Get(), reinterpret_cast<void**>(&array_data)));
 
diff --git a/content/browser/accessibility/ax_platform_node_textrangeprovider_win_browsertest.cc b/content/browser/accessibility/ax_platform_node_textrangeprovider_win_browsertest.cc
index 53a2f94..5dccd2f 100644
--- a/content/browser/accessibility/ax_platform_node_textrangeprovider_win_browsertest.cc
+++ b/content/browser/accessibility/ax_platform_node_textrangeprovider_win_browsertest.cc
@@ -260,7 +260,7 @@
         ToBrowserAccessibilityWin(browser_accessibility_start)->GetCOM();
     ASSERT_NE(nullptr, start_browser_accessibility_com_win);
 
-    CComPtr<ITextRangeProvider> text_range_provider =
+    ComPtr<ITextRangeProvider> text_range_provider =
         ui::AXPlatformNodeTextRangeProviderWin::CreateTextRangeProvider(
             start_browser_accessibility_com_win, std::move(start),
             std::move(end));
diff --git a/content/browser/accessibility/ax_platform_node_win_browsertest.cc b/content/browser/accessibility/ax_platform_node_win_browsertest.cc
index bb2d610..c3004527f 100644
--- a/content/browser/accessibility/ax_platform_node_win_browsertest.cc
+++ b/content/browser/accessibility/ax_platform_node_win_browsertest.cc
@@ -71,14 +71,15 @@
 
     std::vector<std::string> names;
     for (LONG i = 0; i < size; ++i) {
-      CComPtr<IUnknown> unknown_element = nullptr;
-      ASSERT_HRESULT_SUCCEEDED(SafeArrayGetElement(
-          V_ARRAY(flows_from_variant.ptr()), &i, &unknown_element));
+      ComPtr<IUnknown> unknown_element;
+      ASSERT_HRESULT_SUCCEEDED(
+          SafeArrayGetElement(V_ARRAY(flows_from_variant.ptr()), &i,
+                              static_cast<void**>(&unknown_element)));
       ASSERT_NE(nullptr, unknown_element);
 
-      CComPtr<IRawElementProviderSimple> raw_element_provider_simple = nullptr;
+      ComPtr<IRawElementProviderSimple> raw_element_provider_simple = nullptr;
       ASSERT_HRESULT_SUCCEEDED(
-          unknown_element->QueryInterface(&raw_element_provider_simple));
+          unknown_element.As(&raw_element_provider_simple));
       ASSERT_NE(nullptr, raw_element_provider_simple);
 
       base::win::ScopedVariant name;
diff --git a/content/browser/appcache/appcache_subresource_url_factory.cc b/content/browser/appcache/appcache_subresource_url_factory.cc
index 965f5cc..a62e806 100644
--- a/content/browser/appcache/appcache_subresource_url_factory.cc
+++ b/content/browser/appcache/appcache_subresource_url_factory.cc
@@ -64,7 +64,6 @@
         options_(options),
         traffic_annotation_(annotation),
         network_loader_factory_(std::move(network_loader_factory)),
-        local_client_binding_(this),
         host_(appcache_host) {
     DCHECK_CURRENTLY_ON(BrowserThread::UI);
     remote_receiver_.set_disconnect_handler(base::BindOnce(
@@ -111,11 +110,11 @@
     DCHECK(handler);
 
     // Disconnect from the network loader first.
-    local_client_binding_.Close();
+    local_client_receiver_.reset();
     network_loader_ = nullptr;
 
     network::mojom::URLLoaderClientPtr client_ptr;
-    local_client_binding_.Bind(mojo::MakeRequest(&client_ptr));
+    local_client_receiver_.Bind(mojo::MakeRequest(&client_ptr));
     std::move(handler).Run(request_, mojo::MakeRequest(&appcache_loader_),
                            std::move(client_ptr));
   }
@@ -123,7 +122,7 @@
   void CreateAndStartNetworkLoader() {
     DCHECK(!appcache_loader_);
     network::mojom::URLLoaderClientPtr client_ptr;
-    local_client_binding_.Bind(mojo::MakeRequest(&client_ptr));
+    local_client_receiver_.Bind(mojo::MakeRequest(&client_ptr));
     network_loader_factory_->CreateLoaderAndStart(
         mojo::MakeRequest(&network_loader_), routing_id_, request_id_, options_,
         request_, std::move(client_ptr), traffic_annotation_);
@@ -309,9 +308,9 @@
   // Core appcache logic that decides how to handle a request.
   std::unique_ptr<AppCacheRequestHandler> handler_;
 
-  // The local binding to either our network or appcache loader,
+  // The local receiver to either our network or appcache loader,
   // we only use one of them at any given time.
-  mojo::Binding<network::mojom::URLLoaderClient> local_client_binding_;
+  mojo::Receiver<network::mojom::URLLoaderClient> local_client_receiver_{this};
   network::mojom::URLLoaderPtr network_loader_;
   network::mojom::URLLoaderPtr appcache_loader_;
 
diff --git a/content/browser/appcache/appcache_update_url_loader_request.cc b/content/browser/appcache/appcache_update_url_loader_request.cc
index d4e65fa3..07657d8 100644
--- a/content/browser/appcache/appcache_update_url_loader_request.cc
+++ b/content/browser/appcache/appcache_update_url_loader_request.cc
@@ -54,7 +54,7 @@
     return;
 
   network::mojom::URLLoaderClientPtr client;
-  client_binding_.Bind(mojo::MakeRequest(&client));
+  client_receiver_.Bind(mojo::MakeRequest(&client));
 
   // The partition has shutdown, return without making the request.
   if (!partition_)
@@ -123,7 +123,7 @@
 }
 
 int AppCacheUpdateJob::UpdateURLLoaderRequest::Cancel() {
-  client_binding_.Close();
+  client_receiver_.reset();
   url_loader_ = nullptr;
   handle_watcher_.Cancel();
   handle_.reset();
@@ -208,7 +208,6 @@
     URLFetcher* fetcher)
     : fetcher_(fetcher),
       partition_(std::move(partition)),
-      client_binding_(this),
       buffer_size_(buffer_size),
       handle_watcher_(FROM_HERE,
                       mojo::SimpleWatcher::ArmingPolicy::MANUAL,
diff --git a/content/browser/appcache/appcache_update_url_loader_request.h b/content/browser/appcache/appcache_update_url_loader_request.h
index bb7fce0..1ed1cf4 100644
--- a/content/browser/appcache/appcache_update_url_loader_request.h
+++ b/content/browser/appcache/appcache_update_url_loader_request.h
@@ -12,7 +12,7 @@
 
 #include "base/macros.h"
 #include "content/browser/appcache/appcache_update_job.h"
-#include "mojo/public/cpp/bindings/binding.h"
+#include "mojo/public/cpp/bindings/receiver.h"
 #include "mojo/public/cpp/system/simple_watcher.h"
 #include "net/base/io_buffer.h"
 #include "services/network/public/cpp/net_adapters.h"
@@ -122,7 +122,7 @@
   // Response details.
   std::unique_ptr<net::HttpResponseInfo> http_response_info_;
   // Binds the URLLoaderClient interface to the channel.
-  mojo::Binding<network::mojom::URLLoaderClient> client_binding_;
+  mojo::Receiver<network::mojom::URLLoaderClient> client_receiver_{this};
   // The network URL loader.
   network::mojom::URLLoaderPtr url_loader_;
   // Caller buffer size.
diff --git a/content/browser/back_forward_cache_browsertest.cc b/content/browser/back_forward_cache_browsertest.cc
index f87e44f..adecb5d 100644
--- a/content/browser/back_forward_cache_browsertest.cc
+++ b/content/browser/back_forward_cache_browsertest.cc
@@ -38,7 +38,10 @@
 #include "net/dns/mock_host_resolver.h"
 #include "net/test/embedded_test_server/controllable_http_response.h"
 #include "net/test/embedded_test_server/embedded_test_server.h"
+#include "services/device/public/cpp/test/fake_sensor_and_provider.h"
 #include "services/device/public/cpp/test/scoped_geolocation_overrider.h"
+#include "services/device/public/mojom/constants.mojom.h"
+#include "services/service_manager/public/cpp/service_binding.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "third_party/blink/public/common/scheduler/web_scheduler_tracked_feature.h"
 
@@ -3675,4 +3678,98 @@
   EXPECT_EQ(web_contents()->GetThemeColor(), 0xFFFF0000u);
 }
 
+class SensorBackForwardCacheBrowserTest : public BackForwardCacheBrowserTest {
+ protected:
+  SensorBackForwardCacheBrowserTest() {
+    service_manager::ServiceBinding::OverrideInterfaceBinderForTesting(
+        device::mojom::kServiceName,
+        base::BindRepeating(
+            &SensorBackForwardCacheBrowserTest::BindSensorProvider,
+            base::Unretained(this)));
+  }
+
+  ~SensorBackForwardCacheBrowserTest() override {
+    service_manager::ServiceBinding::ClearInterfaceBinderOverrideForTesting<
+        device::mojom::SensorProvider>(device::mojom::kServiceName);
+  }
+
+  void SetUpOnMainThread() override {
+    provider_ = std::make_unique<device::FakeSensorProvider>();
+    provider_->SetAccelerometerData(1.0, 2.0, 3.0);
+
+    BackForwardCacheBrowserTest::SetUpOnMainThread();
+  }
+
+  std::unique_ptr<device::FakeSensorProvider> provider_;
+
+ private:
+  void BindSensorProvider(
+      mojo::PendingReceiver<device::mojom::SensorProvider> receiver) {
+    provider_->Bind(std::move(receiver));
+  }
+};
+
+IN_PROC_BROWSER_TEST_F(SensorBackForwardCacheBrowserTest,
+                       AccelerometerNotCached) {
+  ASSERT_TRUE(embedded_test_server()->Start());
+  GURL url_a(embedded_test_server()->GetURL("/title1.html"));
+  GURL url_b(embedded_test_server()->GetURL("b.com", "/title1.html"));
+
+  // 1) Navigate to A.
+  ASSERT_TRUE(NavigateToURL(shell(), url_a));
+  RenderFrameHostImpl* rfh_a = current_frame_host();
+  RenderFrameDeletedObserver delete_observer_rfh_a(rfh_a);
+
+  EXPECT_TRUE(ExecJs(rfh_a, R"(
+    new Promise(resolve => {
+      const sensor = new Accelerometer();
+      sensor.addEventListener('reading', () => { resolve(); });
+      sensor.start();
+    })
+  )"));
+
+  // 2) Navigate to B.
+  ASSERT_TRUE(NavigateToURL(shell(), url_b));
+
+  // - Page A should not be in the cache.
+  delete_observer_rfh_a.WaitUntilDeleted();
+
+  // 3) Go back.
+  web_contents()->GetController().GoBack();
+  EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
+  ExpectNotRestored(
+      {BackForwardCacheMetrics::NotRestoredReason::kBlocklistedFeatures},
+      FROM_HERE);
+}
+
+IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest, WebMidiNotCached) {
+  ASSERT_TRUE(embedded_test_server()->Start());
+  GURL url_a(embedded_test_server()->GetURL("/title1.html"));
+  GURL url_b(embedded_test_server()->GetURL("b.com", "/title1.html"));
+
+  // 1) Navigate to A.
+  ASSERT_TRUE(NavigateToURL(shell(), url_a));
+  RenderFrameHostImpl* rfh_a = current_frame_host();
+  RenderFrameDeletedObserver delete_observer_rfh_a(rfh_a);
+
+  // - Wait until requestMIDIAccess() promise is resolved.
+  EXPECT_TRUE(ExecJs(rfh_a, "navigator.requestMIDIAccess()"));
+
+  // 2) Navigate to B.
+  ASSERT_TRUE(NavigateToURL(shell(), url_b));
+
+  // - Page A should not be in the cache.
+  EXPECT_TRUE(delete_observer_rfh_a.deleted());
+
+  // 3) Go back.
+  web_contents()->GetController().GoBack();
+  EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
+  ExpectNotRestored(
+      {BackForwardCacheMetrics::NotRestoredReason::kBlocklistedFeatures},
+      FROM_HERE);
+  ExpectBlocklistedFeature(
+      blink::scheduler::WebSchedulerTrackedFeature::kRequestedMIDIPermission,
+      FROM_HERE);
+}
+
 }  // namespace content
diff --git a/content/browser/cache_storage/legacy/legacy_cache_storage_cache.cc b/content/browser/cache_storage/legacy/legacy_cache_storage_cache.cc
index 7238ee2..ba30c78 100644
--- a/content/browser/cache_storage/legacy/legacy_cache_storage_cache.cc
+++ b/content/browser/cache_storage/legacy/legacy_cache_storage_cache.cc
@@ -534,10 +534,9 @@
   }
 
   auto id = scheduler_->CreateId();
-  // TODO: use priority
   scheduler_->ScheduleOperation(
       id, CacheStorageSchedulerMode::kShared, CacheStorageSchedulerOp::kMatch,
-      CacheStorageSchedulerPriority::kNormal,
+      priority,
       base::BindOnce(
           &LegacyCacheStorageCache::MatchImpl, weak_ptr_factory_.GetWeakPtr(),
           std::move(request), std::move(match_options), trace_id,
diff --git a/content/browser/devtools/devtools_url_loader_interceptor.cc b/content/browser/devtools/devtools_url_loader_interceptor.cc
index 319246ad..e3d76f74 100644
--- a/content/browser/devtools/devtools_url_loader_interceptor.cc
+++ b/content/browser/devtools/devtools_url_loader_interceptor.cc
@@ -373,7 +373,7 @@
   std::unique_ptr<CreateLoaderParameters> create_loader_params_;
   const bool is_download_;
 
-  mojo::Binding<network::mojom::URLLoaderClient> client_binding_;
+  mojo::Receiver<network::mojom::URLLoaderClient> client_receiver_{this};
   mojo::Receiver<network::mojom::URLLoader> loader_receiver_{this};
 
   network::mojom::URLLoaderClientPtr client_;
@@ -676,7 +676,6 @@
       interceptor_(interceptor),
       create_loader_params_(std::move(create_loader_params)),
       is_download_(is_download),
-      client_binding_(this),
       client_(std::move(client)),
       target_factory_(std::move(target_factory)),
       cookie_manager_(std::move(cookie_manager)),
@@ -785,7 +784,7 @@
   if (!body_reader_) {
     body_reader_ = std::make_unique<BodyReader>(base::BindOnce(
         &InterceptionJob::ResponseBodyComplete, base::Unretained(this)));
-    client_binding_.ResumeIncomingMethodCallProcessing();
+    client_receiver_.Resume();
     loader_->ResumeReadingBodyFromNet();
   }
   body_reader_->AddCallback(std::move(callback));
@@ -804,7 +803,7 @@
   DCHECK(!!response_metadata_);
   state_ = State::kResponseTaken;
   pending_response_body_pipe_callback_ = std::move(callback);
-  client_binding_.ResumeIncomingMethodCallProcessing();
+  client_receiver_.Resume();
   loader_->ResumeReadingBodyFromNet();
 }
 
@@ -921,7 +920,7 @@
     client_->OnReceiveResponse(response_metadata_->head);
     response_metadata_.reset();
     loader_->ResumeReadingBodyFromNet();
-    client_binding_.ResumeIncomingMethodCallProcessing();
+    client_receiver_.Resume();
     return Response::OK();
   }
 
@@ -1166,8 +1165,8 @@
   state_ = State::kRequestSent;
 
   network::mojom::URLLoaderClientPtr loader_client;
-  client_binding_.Bind(MakeRequest(&loader_client));
-  client_binding_.set_connection_error_handler(
+  client_receiver_.Bind(MakeRequest(&loader_client));
+  client_receiver_.set_disconnect_handler(
       base::BindOnce(&InterceptionJob::Shutdown, base::Unretained(this)));
 
   target_factory_->CreateLoaderAndStart(
@@ -1183,7 +1182,7 @@
 void InterceptionJob::CancelRequest() {
   if (state_ == State::kNotStarted)
     return;
-  client_binding_.Close();
+  client_receiver_.reset();
   loader_.reset();
   if (body_reader_) {
     body_reader_->CancelWithError(
@@ -1348,7 +1347,7 @@
     return;
   }
   loader_->PauseReadingBodyFromNet();
-  client_binding_.PauseIncomingMethodCallProcessing();
+  client_receiver_.Pause();
 
   response_metadata_ = std::make_unique<ResponseMetadata>(head);
 
@@ -1429,9 +1428,9 @@
     return;
   }
   response_metadata_->status = status;
-  // No need to listen to the channel any more, so just close it, so if the pipe
+  // No need to listen to the channel any more, so just reset it, so if the pipe
   // is closed by the other end, |shutdown| isn't run.
-  client_binding_.Close();
+  client_receiver_.reset();
   loader_.reset();
 }
 
diff --git a/content/browser/gpu/gpu_data_manager_impl.h b/content/browser/gpu/gpu_data_manager_impl.h
index 9c20ae8..042edea 100644
--- a/content/browser/gpu/gpu_data_manager_impl.h
+++ b/content/browser/gpu/gpu_data_manager_impl.h
@@ -117,7 +117,7 @@
   // Returns a new copy of the ListValue.
   std::unique_ptr<base::ListValue> GetLogMessages() const;
 
-  // Called when switching gpu.
+  // Called when switching GPUs.
   void HandleGpuSwitch();
 
   // Maintenance of domains requiring explicit user permission before
diff --git a/content/browser/gpu/gpu_data_manager_impl_private.cc b/content/browser/gpu/gpu_data_manager_impl_private.cc
index 6101710..e85bea68 100644
--- a/content/browser/gpu/gpu_data_manager_impl_private.cc
+++ b/content/browser/gpu/gpu_data_manager_impl_private.cc
@@ -57,6 +57,7 @@
 #include "ui/gl/buildflags.h"
 #include "ui/gl/gl_implementation.h"
 #include "ui/gl/gl_switches.h"
+#include "ui/gl/gpu_preference.h"
 #include "ui/gl/gpu_switching_manager.h"
 
 #if defined(OS_ANDROID)
@@ -807,25 +808,36 @@
 void GpuDataManagerImplPrivate::HandleGpuSwitch() {
   base::AutoUnlock unlock(owner_->lock_);
   // Notify observers in the browser process.
-  ui::GpuSwitchingManager::GetInstance()->NotifyGpuSwitched();
+  ui::GpuSwitchingManager::GetInstance()->NotifyGpuSwitched(
+      active_gpu_heuristic_);
   // Pass the notification to the GPU process to notify observers there.
-  GpuProcessHost::CallOnIO(GPU_PROCESS_KIND_SANDBOXED, false /* force_create */,
-                           base::BindOnce([](GpuProcessHost* host) {
-                             if (host)
-                               host->gpu_service()->GpuSwitched();
-                           }));
+  GpuProcessHost::CallOnIO(
+      GPU_PROCESS_KIND_SANDBOXED, false /* force_create */,
+      base::BindOnce(
+          [](gl::GpuPreference active_gpu, GpuProcessHost* host) {
+            if (host)
+              host->gpu_service()->GpuSwitched(active_gpu);
+          },
+          active_gpu_heuristic_));
 }
 
 bool GpuDataManagerImplPrivate::UpdateActiveGpu(uint32_t vendor_id,
                                                 uint32_t device_id) {
+  // Heuristics for dual-GPU detection.
+  bool is_dual_gpu = gpu_info_.secondary_gpus.size() == 1;
+  const uint32_t kIntelID = 0x8086;
+  bool saw_intel_gpu = false;
+  bool saw_non_intel_gpu = false;
+
   if (gpu_info_.gpu.vendor_id == vendor_id &&
       gpu_info_.gpu.device_id == device_id) {
     // The primary GPU is active.
     if (gpu_info_.gpu.active)
       return false;
     gpu_info_.gpu.active = true;
-    for (size_t ii = 0; ii < gpu_info_.secondary_gpus.size(); ++ii)
+    for (size_t ii = 0; ii < gpu_info_.secondary_gpus.size(); ++ii) {
       gpu_info_.secondary_gpus[ii].active = false;
+    }
   } else {
     // A secondary GPU is active.
     for (size_t ii = 0; ii < gpu_info_.secondary_gpus.size(); ++ii) {
@@ -840,6 +852,26 @@
     }
     gpu_info_.gpu.active = false;
   }
+  active_gpu_heuristic_ = gl::GpuPreference::kDefault;
+  if (is_dual_gpu) {
+    if (gpu_info_.gpu.vendor_id == kIntelID) {
+      saw_intel_gpu = true;
+    } else {
+      saw_non_intel_gpu = true;
+    }
+    if (gpu_info_.secondary_gpus[0].vendor_id == kIntelID) {
+      saw_intel_gpu = true;
+    } else {
+      saw_non_intel_gpu = true;
+    }
+    if (saw_intel_gpu && saw_non_intel_gpu) {
+      if (vendor_id == kIntelID) {
+        active_gpu_heuristic_ = gl::GpuPreference::kLowPower;
+      } else {
+        active_gpu_heuristic_ = gl::GpuPreference::kHighPerformance;
+      }
+    }
+  }
   GetContentClient()->SetGpuInfo(gpu_info_);
   NotifyGpuInfoUpdate();
   return true;
diff --git a/content/browser/gpu/gpu_data_manager_impl_private.h b/content/browser/gpu/gpu_data_manager_impl_private.h
index 83fa485..3acc216b 100644
--- a/content/browser/gpu/gpu_data_manager_impl_private.h
+++ b/content/browser/gpu/gpu_data_manager_impl_private.h
@@ -23,6 +23,7 @@
 #include "base/values.h"
 #include "build/build_config.h"
 #include "content/browser/gpu/gpu_data_manager_impl.h"
+#include "ui/gl/gpu_preference.h"
 
 namespace base {
 class CommandLine;
@@ -189,6 +190,7 @@
 
   gpu::GpuFeatureInfo gpu_feature_info_;
   gpu::GPUInfo gpu_info_;
+  gl::GpuPreference active_gpu_heuristic_ = gl::GpuPreference::kDefault;
 #if defined(OS_WIN)
   bool gpu_info_dx_diag_requested_ = false;
   bool gpu_info_dx_diag_request_failed_ = false;
diff --git a/content/browser/gpu/gpu_internals_ui.cc b/content/browser/gpu/gpu_internals_ui.cc
index 96023f2..9ac4194 100644
--- a/content/browser/gpu/gpu_internals_ui.cc
+++ b/content/browser/gpu/gpu_internals_ui.cc
@@ -533,7 +533,7 @@
   void OnGpuInfoUpdate() override;
 
   // ui::GpuSwitchingObserver implementation.
-  void OnGpuSwitched() override;
+  void OnGpuSwitched(gl::GpuPreference) override;
 
   // Messages
   void OnBrowserBridgeInitialized(const base::ListValue* list);
@@ -720,7 +720,7 @@
                                          *(gpu_info_val.get()));
 }
 
-void GpuMessageHandler::OnGpuSwitched() {
+void GpuMessageHandler::OnGpuSwitched(gl::GpuPreference active_gpu_heuristic_) {
   // Currently, about:gpu page does not update GPU info after the GPU switch.
   // If there is something to be updated, the code should be added here.
 }
diff --git a/content/browser/gpu/peak_gpu_memory_tracker_impl_browsertest.cc b/content/browser/gpu/peak_gpu_memory_tracker_impl_browsertest.cc
index 3e3448e002..9a68b16 100644
--- a/content/browser/gpu/peak_gpu_memory_tracker_impl_browsertest.cc
+++ b/content/browser/gpu/peak_gpu_memory_tracker_impl_browsertest.cc
@@ -103,7 +103,7 @@
                     const std::string& key,
                     const std::string& data) override {}
   void WakeUpGpu() override {}
-  void GpuSwitched() override {}
+  void GpuSwitched(gl::GpuPreference active_gpu_heuristic) override {}
   void DestroyAllChannels() override {}
   void OnBackgroundCleanup() override {}
   void OnBackgrounded() override {}
diff --git a/content/browser/loader/prefetch_url_loader.cc b/content/browser/loader/prefetch_url_loader.cc
index e9029db..d65498c 100644
--- a/content/browser/loader/prefetch_url_loader.cc
+++ b/content/browser/loader/prefetch_url_loader.cc
@@ -49,7 +49,6 @@
     : frame_tree_node_id_(frame_tree_node_id),
       resource_request_(resource_request),
       network_loader_factory_(std::move(network_loader_factory)),
-      client_binding_(this),
       forwarding_client_(std::move(client)),
       url_loader_throttles_getter_(url_loader_throttles_getter),
       signed_exchange_prefetch_metric_recorder_(
@@ -79,8 +78,8 @@
   }
 
   network::mojom::URLLoaderClientPtr network_client;
-  client_binding_.Bind(mojo::MakeRequest(&network_client));
-  client_binding_.set_connection_error_handler(base::BindOnce(
+  client_receiver_.Bind(mojo::MakeRequest(&network_client));
+  client_receiver_.set_disconnect_handler(base::BindOnce(
       &PrefetchURLLoader::OnNetworkConnectionError, base::Unretained(this)));
   network_loader_factory_->CreateLoaderAndStart(
       mojo::MakeRequest(&loader_), routing_id, request_id, options,
@@ -112,8 +111,8 @@
     RecordPrefetchRedirectHistogram(
         PrefetchRedirect::kPrefetchRedirectedSXGHandler);
 
-    // Rebind |client_binding_| and |loader_|.
-    client_binding_.Bind(signed_exchange_prefetch_handler_->FollowRedirect(
+    // Rebind |client_receiver_| and |loader_|.
+    client_receiver_.Bind(signed_exchange_prefetch_handler_->FollowRedirect(
         mojo::MakeRequest(&loader_)));
     return;
   }
@@ -162,7 +161,7 @@
         std::make_unique<SignedExchangePrefetchHandler>(
             frame_tree_node_id_, resource_request_, response,
             mojo::ScopedDataPipeConsumerHandle(), std::move(loader_),
-            client_binding_.Unbind(), network_loader_factory_,
+            client_receiver_.Unbind(), network_loader_factory_,
             url_loader_throttles_getter_, this,
             signed_exchange_prefetch_metric_recorder_, accept_langs_);
     return;
@@ -263,7 +262,7 @@
     forwarding_client_->OnComplete(
         network::URLLoaderCompletionStatus(net::ERR_INSUFFICIENT_RESOURCES));
     forwarding_client_.reset();
-    client_binding_.Close();
+    client_receiver_.reset();
     return false;
   }
   forwarding_client_->OnStartLoadingResponseBody(std::move(consumer));
diff --git a/content/browser/loader/prefetch_url_loader.h b/content/browser/loader/prefetch_url_loader.h
index b450e29..42c1f6e 100644
--- a/content/browser/loader/prefetch_url_loader.h
+++ b/content/browser/loader/prefetch_url_loader.h
@@ -15,7 +15,7 @@
 #include "base/unguessable_token.h"
 #include "content/browser/web_package/prefetched_signed_exchange_cache.h"
 #include "content/common/content_export.h"
-#include "mojo/public/cpp/bindings/binding.h"
+#include "mojo/public/cpp/bindings/receiver.h"
 #include "mojo/public/cpp/system/data_pipe_drainer.h"
 #include "net/traffic_annotation/network_traffic_annotation.h"
 #include "services/network/public/mojom/url_loader.mojom.h"
@@ -132,7 +132,7 @@
 
   // For the actual request.
   network::mojom::URLLoaderPtr loader_;
-  mojo::Binding<network::mojom::URLLoaderClient> client_binding_;
+  mojo::Receiver<network::mojom::URLLoaderClient> client_receiver_{this};
 
   // To be a URLLoader for the client.
   network::mojom::URLLoaderClientPtr forwarding_client_;
diff --git a/content/browser/navigation_browsertest.cc b/content/browser/navigation_browsertest.cc
index 6de95bbf..2eb201dd 100644
--- a/content/browser/navigation_browsertest.cc
+++ b/content/browser/navigation_browsertest.cc
@@ -3119,10 +3119,19 @@
                          NavigationUrlRewriteBrowserTest,
                          ::testing::Bool());
 
+// TODO(1021779): Figure out why this fails on the kitkat-dbg builder
+// and re-enable for all platforms.
+#if defined(OS_ANDROID) && !defined(NDEBUG)
+#define DISABLE_ON_ANDROID_DEBUG(x) DISABLED_##x
+#else
+#define DISABLE_ON_ANDROID_DEBUG(x) x
+#endif
+
 // Tests navigating to a URL that gets rewritten to a "no access" URL. This
 // mimics the behavior of navigating to special URLs like chrome://newtab and
 // chrome://history which get rewritten to "no access" chrome-native:// URLs.
-IN_PROC_BROWSER_TEST_P(NavigationUrlRewriteBrowserTest, RewriteToNoAccess) {
+IN_PROC_BROWSER_TEST_P(NavigationUrlRewriteBrowserTest,
+                       DISABLE_ON_ANDROID_DEBUG(RewriteToNoAccess)) {
   // Perform an initial navigation.
   {
     TestNavigationObserver observer(shell()->web_contents());
diff --git a/content/browser/renderer_host/render_view_host_impl.cc b/content/browser/renderer_host/render_view_host_impl.cc
index b34aa688..2e4c2b9 100644
--- a/content/browser/renderer_host/render_view_host_impl.cc
+++ b/content/browser/renderer_host/render_view_host_impl.cc
@@ -1017,7 +1017,7 @@
       &RenderViewHostImpl::RenderViewReady, weak_factory_.GetWeakPtr()));
 }
 
-void RenderViewHostImpl::OnGpuSwitched() {
+void RenderViewHostImpl::OnGpuSwitched(gl::GpuPreference active_gpu_heuristic) {
   OnHardwareConfigurationChanged();
 }
 
diff --git a/content/browser/renderer_host/render_view_host_impl.h b/content/browser/renderer_host/render_view_host_impl.h
index 994b6142..4bdfe452 100644
--- a/content/browser/renderer_host/render_view_host_impl.h
+++ b/content/browser/renderer_host/render_view_host_impl.h
@@ -35,6 +35,7 @@
 #include "third_party/blink/public/web/web_console_message.h"
 #include "third_party/skia/include/core/SkColor.h"
 #include "ui/base/window_open_disposition.h"
+#include "ui/gl/gpu_preference.h"
 #include "ui/gl/gpu_switching_observer.h"
 
 namespace content {
@@ -111,7 +112,7 @@
                            const ChildProcessTerminationInfo& info) override;
 
   // GpuSwitchingObserver implementation.
-  void OnGpuSwitched() override;
+  void OnGpuSwitched(gl::GpuPreference active_gpu_heuristic) override;
 
   // Set up the RenderView child process. Virtual because it is overridden by
   // TestRenderViewHost.
diff --git a/content/browser/renderer_host/render_widget_host_view_aura.cc b/content/browser/renderer_host/render_widget_host_view_aura.cc
index 57f2c8f5..73e5257 100644
--- a/content/browser/renderer_host/render_widget_host_view_aura.cc
+++ b/content/browser/renderer_host/render_widget_host_view_aura.cc
@@ -1220,10 +1220,11 @@
   has_composition_text_ = !composition.text.empty();
 }
 
-void RenderWidgetHostViewAura::ConfirmCompositionText() {
+void RenderWidgetHostViewAura::ConfirmCompositionText(bool keep_selection) {
   if (text_input_manager_ && text_input_manager_->GetActiveWidget() &&
       has_composition_text_) {
-    text_input_manager_->GetActiveWidget()->ImeFinishComposingText(false);
+    text_input_manager_->GetActiveWidget()->ImeFinishComposingText(
+        keep_selection);
   }
   has_composition_text_ = false;
 }
diff --git a/content/browser/renderer_host/render_widget_host_view_aura.h b/content/browser/renderer_host/render_widget_host_view_aura.h
index 8e874e2..272be96 100644
--- a/content/browser/renderer_host/render_widget_host_view_aura.h
+++ b/content/browser/renderer_host/render_widget_host_view_aura.h
@@ -202,7 +202,7 @@
 
   // Overridden from ui::TextInputClient:
   void SetCompositionText(const ui::CompositionText& composition) override;
-  void ConfirmCompositionText() override;
+  void ConfirmCompositionText(bool keep_selection) override;
   void ClearCompositionText() override;
   void InsertText(const base::string16& text) override;
   void InsertChar(const ui::KeyEvent& event) override;
diff --git a/content/browser/renderer_host/render_widget_host_view_aura_unittest.cc b/content/browser/renderer_host/render_widget_host_view_aura_unittest.cc
index e3de2e7..52c2a120 100644
--- a/content/browser/renderer_host/render_widget_host_view_aura_unittest.cc
+++ b/content/browser/renderer_host/render_widget_host_view_aura_unittest.cc
@@ -6213,18 +6213,33 @@
 
 // This test is for ui::TextInputClient::ConfirmCompositionText.
 TEST_F(InputMethodResultAuraTest, ConfirmCompositionText) {
-  base::Closure ime_call =
-      base::Bind(&ui::TextInputClient::ConfirmCompositionText,
-                 base::Unretained(text_input_client()));
+  base::Closure ime_call = base::Bind(
+      &ui::TextInputClient::ConfirmCompositionText,
+      base::Unretained(text_input_client()), /** keep_selection */ true);
   for (auto index : active_view_sequence_) {
     ActivateViewForTextInputManager(views_[index], ui::TEXT_INPUT_TYPE_TEXT);
     SetHasCompositionTextToTrue();
+    // Due to a webkit bug. See: https://bugs.webkit.org/show_bug.cgi?id=37788
+    // RenderWidgetHostViewAura::SetCompositionText() will ignore the
+    // selection range passed into it. Hence, RWHVA::SetCompositionText()
+    // cannot be used to set the selection range.
+
+    // RenderWidgetHostViewAura::GetFocusedFrame() does not return a focused
+    // frame due to (crbug.com/689777). Hence,
+    // RWHVA::SetEditableSelectionRange(gfx::Range(0, 2)) also cannot be used
+    // to set the selection range.
+
+    // Hence, there exists no easy way to set the selection range to a specific
+    //  value and test the behaviour of keep_selection.
     ime_call.Run();
     base::RunLoop().RunUntilIdle();
     EXPECT_EQ("SetComposition FinishComposingText",
               GetMessageNames(widget_hosts_[index]
                                   ->input_handler()
                                   ->GetAndResetDispatchedMessages()));
+    // TODO(keithlee) - If either of the previous bugs get fixed, amend
+    // this unittest to check if the TIC::SelectionRange is updated to the
+    // gfx::Range(0,2) value after the IME call.
   }
 }
 
diff --git a/content/browser/renderer_host/render_widget_host_view_event_handler.cc b/content/browser/renderer_host/render_widget_host_view_event_handler.cc
index 7f5763a..d24752156 100644
--- a/content/browser/renderer_host/render_widget_host_view_event_handler.cc
+++ b/content/browser/renderer_host/render_widget_host_view_event_handler.cc
@@ -664,7 +664,8 @@
   // call to finish composition text should be made through the RWHVA itself
   // otherwise the following call to cancel composition will lead to an extra
   // IPC for finishing the ongoing composition (see https://crbug.com/723024).
-  host_view_->GetTextInputClient()->ConfirmCompositionText();
+  host_view_->GetTextInputClient()->ConfirmCompositionText(
+      /* keep_selection */ false);
   host_view_->ImeCancelComposition();
 }
 
diff --git a/content/browser/service_worker/service_worker_fetch_dispatcher.cc b/content/browser/service_worker/service_worker_fetch_dispatcher.cc
index 1681b0b4..4d0f6cf0 100644
--- a/content/browser/service_worker/service_worker_fetch_dispatcher.cc
+++ b/content/browser/service_worker/service_worker_fetch_dispatcher.cc
@@ -88,8 +88,7 @@
   using WorkerId = std::pair<int, int>;
   explicit DelegatingURLLoaderClient(network::mojom::URLLoaderClientPtr client,
                                      const network::ResourceRequest& request)
-      : binding_(this),
-        client_(std::move(client)),
+      : client_(std::move(client)),
         url_(request.url),
         devtools_enabled_(request.report_raw_headers) {
     if (!devtools_enabled_)
@@ -178,7 +177,7 @@
   }
 
   void Bind(network::mojom::URLLoaderClientPtr* ptr_info) {
-    binding_.Bind(mojo::MakeRequest(ptr_info));
+    receiver_.Bind(mojo::MakeRequest(ptr_info));
   }
 
  private:
@@ -198,7 +197,7 @@
     MaybeRunDevToolsCallbacks();
   }
 
-  mojo::Binding<network::mojom::URLLoaderClient> binding_;
+  mojo::Receiver<network::mojom::URLLoaderClient> receiver_{this};
   network::mojom::URLLoaderClientPtr client_;
   bool completed_ = false;
   const GURL url_;
diff --git a/content/browser/service_worker/service_worker_new_script_loader.cc b/content/browser/service_worker/service_worker_new_script_loader.cc
index b831990..bdd5e79e 100644
--- a/content/browser/service_worker/service_worker_new_script_loader.cc
+++ b/content/browser/service_worker/service_worker_new_script_loader.cc
@@ -75,7 +75,6 @@
       resource_type_(static_cast<ResourceType>(original_request.resource_type)),
       original_options_(options),
       version_(version),
-      network_client_binding_(this),
       network_watcher_(FROM_HERE,
                        mojo::SimpleWatcher::ArmingPolicy::MANUAL,
                        base::SequencedTaskRunnerHandle::Get()),
@@ -151,7 +150,7 @@
   options &= ~network::mojom::kURLLoadOptionSniffMimeType;
 
   network::mojom::URLLoaderClientPtr network_client;
-  network_client_binding_.Bind(mojo::MakeRequest(&network_client));
+  network_client_receiver_.Bind(mojo::MakeRequest(&network_client));
   loader_factory_->CreateLoaderAndStart(
       mojo::MakeRequest(&network_loader_), routing_id, request_id, options,
       resource_request, std::move(network_client), traffic_annotation);
@@ -559,7 +558,7 @@
   client_producer_.reset();
 
   network_loader_.reset();
-  network_client_binding_.Close();
+  network_client_receiver_.reset();
   network_consumer_.reset();
   network_watcher_.Cancel();
   cache_writer_.reset();
diff --git a/content/browser/service_worker/service_worker_new_script_loader.h b/content/browser/service_worker/service_worker_new_script_loader.h
index f54608d..2be800c 100644
--- a/content/browser/service_worker/service_worker_new_script_loader.h
+++ b/content/browser/service_worker/service_worker_new_script_loader.h
@@ -9,7 +9,7 @@
 #include "content/browser/service_worker/service_worker_cache_writer.h"
 #include "content/common/content_export.h"
 #include "content/public/common/resource_type.h"
-#include "mojo/public/cpp/bindings/binding.h"
+#include "mojo/public/cpp/bindings/receiver.h"
 #include "net/traffic_annotation/network_traffic_annotation.h"
 #include "services/network/public/cpp/net_adapters.h"
 #include "services/network/public/cpp/resource_request.h"
@@ -182,7 +182,8 @@
   // sometimes).
   network::mojom::URLLoaderPtr network_loader_;
 
-  mojo::Binding<network::mojom::URLLoaderClient> network_client_binding_;
+  mojo::Receiver<network::mojom::URLLoaderClient> network_client_receiver_{
+      this};
   mojo::ScopedDataPipeConsumerHandle network_consumer_;
   mojo::SimpleWatcher network_watcher_;
   scoped_refptr<network::SharedURLLoaderFactory> loader_factory_;
diff --git a/content/browser/utility_process_host.cc b/content/browser/utility_process_host.cc
index 7fc0e32..5df41d8 100644
--- a/content/browser/utility_process_host.cc
+++ b/content/browser/utility_process_host.cc
@@ -390,6 +390,7 @@
       network::switches::kNetLogCaptureMode,
       network::switches::kExplicitlyAllowedPorts,
       service_manager::switches::kNoSandbox,
+      service_manager::switches::kEnableAudioServiceSandbox,
 #if defined(OS_MACOSX)
       service_manager::switches::kEnableSandboxLogging,
       os_crypt::switches::kUseMockKeychain,
diff --git a/content/common/content_security_policy/csp_source_list.cc b/content/common/content_security_policy/csp_source_list.cc
index 664c2b64..0fe3e5f5 100644
--- a/content/common/content_security_policy/csp_source_list.cc
+++ b/content/common/content_security_policy/csp_source_list.cc
@@ -38,25 +38,11 @@
 
 CSPSourceList::CSPSourceList(
     const network::mojom::CSPSourceList& csp_source_list)
-    : allow_self(false), allow_star(false), allow_response_redirects(false) {
-  for (auto& source : csp_source_list.sources) {
-    // The mojo representation of the source list has 'self' as a source entry,
-    // mark this source list as accepting 'self'.
-    if (source->allow_self) {
-      allow_self = true;
-      continue;
-    }
-    // The mojo representation has a '*' (wildcard) representation as empty
-    // scheme, host and port with is_host_wildcard set to true. Mark the source
-    // list as accepting star.
-    if (source->scheme == "" && source->is_host_wildcard &&
-        source->host == "" && source->port == url::PORT_UNSPECIFIED) {
-      allow_star = true;
-      continue;
-    }
-
+    : allow_self(csp_source_list.allow_self),
+      allow_star(csp_source_list.allow_star),
+      allow_response_redirects(false) {
+  for (auto& source : csp_source_list.sources)
     sources.push_back(CSPSource(*source));
-  }
 }
 
 CSPSourceList::CSPSourceList(const CSPSourceList&) = default;
diff --git a/content/public/test/browser_test_utils.cc b/content/public/test/browser_test_utils.cc
index 93a3a8d..c244b17 100644
--- a/content/public/test/browser_test_utils.cc
+++ b/content/public/test/browser_test_utils.cc
@@ -135,7 +135,6 @@
 #if defined(OS_WIN)
 #include <uiautomation.h>
 #include <wrl/client.h>
-#include "base/win/atl.h"
 #include "base/win/scoped_safearray.h"
 #include "base/win/scoped_variant.h"
 #endif
@@ -2106,14 +2105,15 @@
 
   std::vector<std::string> names;
   for (LONG i = 0; i < size; ++i) {
-    CComPtr<IUnknown> unknown_element = nullptr;
-    ASSERT_HRESULT_SUCCEEDED(SafeArrayGetElement(V_ARRAY(result_variant.ptr()),
-                                                 &i, &unknown_element));
+    Microsoft::WRL::ComPtr<IUnknown> unknown_element;
+    ASSERT_HRESULT_SUCCEEDED(
+        SafeArrayGetElement(V_ARRAY(result_variant.ptr()), &i,
+                            static_cast<void**>(&unknown_element)));
     ASSERT_NE(nullptr, unknown_element);
 
-    CComPtr<IRawElementProviderSimple> raw_element_provider_simple = nullptr;
-    ASSERT_HRESULT_SUCCEEDED(
-        unknown_element->QueryInterface(&raw_element_provider_simple));
+    Microsoft::WRL::ComPtr<IRawElementProviderSimple>
+        raw_element_provider_simple;
+    ASSERT_HRESULT_SUCCEEDED(unknown_element.As(&raw_element_provider_simple));
     ASSERT_NE(nullptr, raw_element_provider_simple);
 
     base::win::ScopedVariant name;
diff --git a/content/public/test/url_loader_interceptor.cc b/content/public/test/url_loader_interceptor.cc
index 1ca1a94..e8f62c5 100644
--- a/content/public/test/url_loader_interceptor.cc
+++ b/content/public/test/url_loader_interceptor.cc
@@ -26,6 +26,7 @@
 #include "content/public/browser/browser_task_traits.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/test/mock_render_process_host.h"
+#include "mojo/public/cpp/bindings/receiver.h"
 #include "mojo/public/cpp/bindings/receiver_set.h"
 #include "mojo/public/cpp/bindings/remote.h"
 #include "net/http/http_util.h"
@@ -187,11 +188,10 @@
       const URLLoaderInterceptor::URLLoaderCompletionStatusCallback&
           completion_status_callback)
       : original_client_(std::move(params.client)),
-        delegating_client_binding_(this),
         completion_status_callback_(std::move(completion_status_callback)),
         request_url_(params.url_request.url) {
     network::mojom::URLLoaderClientPtr delegating_client;
-    delegating_client_binding_.Bind(mojo::MakeRequest(&delegating_client));
+    delegating_client_receiver_.Bind(mojo::MakeRequest(&delegating_client));
     factory_getter.Run()->CreateLoaderAndStart(
         std::move(params.receiver), params.routing_id, params.request_id,
         params.options, std::move(params.url_request),
@@ -235,7 +235,8 @@
 
  private:
   network::mojom::URLLoaderClientPtr original_client_;
-  mojo::Binding<network::mojom::URLLoaderClient> delegating_client_binding_;
+  mojo::Receiver<network::mojom::URLLoaderClient> delegating_client_receiver_{
+      this};
   URLLoaderInterceptor::URLLoaderCompletionStatusCallback
       completion_status_callback_;
   GURL request_url_;
diff --git a/content/renderer/loader/navigation_body_loader.cc b/content/renderer/loader/navigation_body_loader.cc
index 09762f76..918f062 100644
--- a/content/renderer/loader/navigation_body_loader.cc
+++ b/content/renderer/loader/navigation_body_loader.cc
@@ -97,7 +97,6 @@
       endpoints_(std::move(endpoints)),
       task_runner_(std::move(task_runner)),
       resource_load_info_(std::move(resource_load_info)),
-      url_loader_client_binding_(this),
       handle_watcher_(FROM_HERE,
                       mojo::SimpleWatcher::ArmingPolicy::MANUAL,
                       task_runner_) {}
@@ -220,9 +219,9 @@
 
 void NavigationBodyLoader::BindURLLoaderAndContinue() {
   url_loader_.Bind(std::move(endpoints_->url_loader), task_runner_);
-  url_loader_client_binding_.Bind(std::move(endpoints_->url_loader_client),
-                                  task_runner_);
-  url_loader_client_binding_.set_connection_error_handler(base::BindOnce(
+  url_loader_client_receiver_.Bind(std::move(endpoints_->url_loader_client),
+                                   task_runner_);
+  url_loader_client_receiver_.set_disconnect_handler(base::BindOnce(
       &NavigationBodyLoader::OnConnectionClosed, base::Unretained(this)));
 }
 
diff --git a/content/renderer/loader/navigation_body_loader.h b/content/renderer/loader/navigation_body_loader.h
index 8780320..b053a8f8 100644
--- a/content/renderer/loader/navigation_body_loader.h
+++ b/content/renderer/loader/navigation_body_loader.h
@@ -18,7 +18,7 @@
 #include "content/common/navigation_params.h"
 #include "content/public/common/resource_load_info.mojom.h"
 #include "mojo/public/cpp/base/big_buffer.h"
-#include "mojo/public/cpp/bindings/binding.h"
+#include "mojo/public/cpp/bindings/receiver.h"
 #include "mojo/public/cpp/system/data_pipe.h"
 #include "mojo/public/cpp/system/simple_watcher.h"
 #include "services/network/public/mojom/url_loader.mojom.h"
@@ -145,7 +145,8 @@
 
   // These bindings are live while loading the response.
   network::mojom::URLLoaderPtr url_loader_;
-  mojo::Binding<network::mojom::URLLoaderClient> url_loader_client_binding_;
+  mojo::Receiver<network::mojom::URLLoaderClient> url_loader_client_receiver_{
+      this};
   WebNavigationBodyLoader::Client* client_ = nullptr;
 
   // The handle and watcher are live while loading the body.
diff --git a/content/renderer/loader/url_loader_client_impl.cc b/content/renderer/loader/url_loader_client_impl.cc
index 70d6e06..44fe52b2a 100644
--- a/content/renderer/loader/url_loader_client_impl.cc
+++ b/content/renderer/loader/url_loader_client_impl.cc
@@ -152,8 +152,7 @@
       resource_dispatcher_(resource_dispatcher),
       task_runner_(std::move(task_runner)),
       bypass_redirect_checks_(bypass_redirect_checks),
-      last_loaded_url_(request_url),
-      url_loader_client_binding_(this) {}
+      last_loaded_url_(request_url) {}
 
 URLLoaderClientImpl::~URLLoaderClientImpl() = default;
 
@@ -230,9 +229,9 @@
 void URLLoaderClientImpl::Bind(
     network::mojom::URLLoaderClientEndpointsPtr endpoints) {
   url_loader_.Bind(std::move(endpoints->url_loader), task_runner_);
-  url_loader_client_binding_.Bind(std::move(endpoints->url_loader_client),
-                                  task_runner_);
-  url_loader_client_binding_.set_connection_error_handler(base::BindOnce(
+  url_loader_client_receiver_.Bind(std::move(endpoints->url_loader_client),
+                                   task_runner_);
+  url_loader_client_receiver_.set_disconnect_handler(base::BindOnce(
       &URLLoaderClientImpl::OnConnectionClosed, weak_factory_.GetWeakPtr()));
 }
 
diff --git a/content/renderer/loader/url_loader_client_impl.h b/content/renderer/loader/url_loader_client_impl.h
index a940d61..b0b5ae98 100644
--- a/content/renderer/loader/url_loader_client_impl.h
+++ b/content/renderer/loader/url_loader_client_impl.h
@@ -11,7 +11,7 @@
 #include "base/memory/ref_counted.h"
 #include "base/memory/weak_ptr.h"
 #include "content/common/content_export.h"
-#include "mojo/public/cpp/bindings/binding.h"
+#include "mojo/public/cpp/bindings/receiver.h"
 #include "mojo/public/cpp/system/data_pipe.h"
 #include "services/network/public/mojom/url_loader.mojom.h"
 
@@ -99,7 +99,8 @@
   GURL last_loaded_url_;
 
   network::mojom::URLLoaderPtr url_loader_;
-  mojo::Binding<network::mojom::URLLoaderClient> url_loader_client_binding_;
+  mojo::Receiver<network::mojom::URLLoaderClient> url_loader_client_receiver_{
+      this};
 
   base::WeakPtrFactory<URLLoaderClientImpl> weak_factory_{this};
 };
diff --git a/content/renderer/renderer_blink_platform_impl.cc b/content/renderer/renderer_blink_platform_impl.cc
index dbe2b9c..f840cfc 100644
--- a/content/renderer/renderer_blink_platform_impl.cc
+++ b/content/renderer/renderer_blink_platform_impl.cc
@@ -827,21 +827,17 @@
 
 std::unique_ptr<blink::WebGraphicsContext3DProvider>
 RendererBlinkPlatformImpl::CreateWebGPUGraphicsContext3DProvider(
-    const blink::WebURL& top_document_web_url,
-    blink::Platform::GraphicsInfo* gl_info) {
+    const blink::WebURL& top_document_web_url) {
 #if !BUILDFLAG(USE_DAWN)
   return nullptr;
 #else
   scoped_refptr<gpu::GpuChannelHost> gpu_channel_host(
       RenderThreadImpl::current()->EstablishGpuChannelSync());
   if (!gpu_channel_host) {
-    std::string error_message(
-        "WebGPUGraphicsContext3DProvider creation failed, GpuChannelHost "
-        "creation failed");
-    gl_info->error_message = WebString::FromUTF8(error_message);
+    // TODO(crbug.com/973017): Collect GPU info and surface context creation
+    // error.
     return nullptr;
   }
-  Collect3DContextInformation(gl_info, gpu_channel_host->gpu_info());
 
   gpu::ContextCreationAttribs attributes;
   // TODO(kainino): It's not clear yet how GPU preferences work for WebGPU.
diff --git a/content/renderer/renderer_blink_platform_impl.h b/content/renderer/renderer_blink_platform_impl.h
index d2d54ab..f54e6c3 100644
--- a/content/renderer/renderer_blink_platform_impl.h
+++ b/content/renderer/renderer_blink_platform_impl.h
@@ -167,8 +167,7 @@
   CreateSharedOffscreenGraphicsContext3DProvider() override;
   std::unique_ptr<blink::WebGraphicsContext3DProvider>
   CreateWebGPUGraphicsContext3DProvider(
-      const blink::WebURL& top_document_web_url,
-      blink::Platform::GraphicsInfo* gl_info) override;
+      const blink::WebURL& top_document_web_url) override;
   gpu::GpuMemoryBufferManager* GetGpuMemoryBufferManager() override;
   blink::WebString ConvertIDNToUnicode(const blink::WebString& host) override;
   void SetDisplayThreadPriority(base::PlatformThreadId thread_id) override;
diff --git a/content/test/data/gpu/functional_blank.html b/content/test/data/gpu/functional_blank.html
new file mode 100644
index 0000000..246224e
--- /dev/null
+++ b/content/test/data/gpu/functional_blank.html
@@ -0,0 +1,11 @@
+<head>
+<script>
+function main() {
+  if (window.domAutomationController) {
+    domAutomationController.send("FINISHED");
+  }
+}
+</script>
+</head>
+<body onload="main()">
+</body>
diff --git a/content/test/data/gpu/functional_files/context.js b/content/test/data/gpu/functional_files/context.js
index 9f072aa..3e96f2d 100644
--- a/content/test/data/gpu/functional_files/context.js
+++ b/content/test/data/gpu/functional_files/context.js
@@ -6,11 +6,10 @@
 var gl_context;
 var gl_renderer;
 
-initializeWebGL = function(canvas) {
+initializeWebGL = function(canvas, opt_attrs) {
   gl_context = null;
   // Try to grab the standard context.
-  gl_context = canvas.getContext("webgl") ||
-               canvas.getContext("experimental-webgl");
+  gl_context = canvas.getContext("webgl", opt_attrs);
   // If we don't have a GL context, give up now.
   if (!gl_context) {
     err = "Unable to initialize WebGL. Your browser may not support it.";
@@ -22,10 +21,10 @@
   }
 }
 
-startWebGLContext = function() {
+startWebGLContext = function(opt_attrs) {
   var canvas = document.getElementById("glcanvas");
   // Initialize the GL context.
-  initializeWebGL(canvas);
+  initializeWebGL(canvas, opt_attrs);
 
   // Only continue if WebGL is available and working.
   if (gl_context) {
diff --git a/content/test/data/gpu/functional_webgl_high_performance.html b/content/test/data/gpu/functional_webgl_high_performance.html
new file mode 100644
index 0000000..9f599a5
--- /dev/null
+++ b/content/test/data/gpu/functional_webgl_high_performance.html
@@ -0,0 +1,8 @@
+<html>
+<script type="text/javascript" src="./functional_files/context.js"></script>
+<body onload="startWebGLContext({powerPreference: 'high-performance'})">
+  <canvas id="glcanvas" width="640" height="480">
+    Your browser doesn't appear to support the HTML5 <code>&lt;canvas&gt;</code> element.
+  </canvas>
+</body>
+</html>
diff --git a/content/test/data/gpu/functional_webgl_low_power.html b/content/test/data/gpu/functional_webgl_low_power.html
new file mode 100644
index 0000000..38a1ab5
--- /dev/null
+++ b/content/test/data/gpu/functional_webgl_low_power.html
@@ -0,0 +1,8 @@
+<html>
+<script type="text/javascript" src="./functional_files/context.js"></script>
+<body onload="startWebGLContext({powerPreference: 'low-power'})">
+  <canvas id="glcanvas" width="640" height="480">
+    Your browser doesn't appear to support the HTML5 <code>&lt;canvas&gt;</code> element.
+  </canvas>
+</body>
+</html>
diff --git a/content/test/data/gpu/pixel_webgl_fullscreen_quad.js b/content/test/data/gpu/pixel_webgl_fullscreen_quad.js
new file mode 100644
index 0000000..8233144
--- /dev/null
+++ b/content/test/data/gpu/pixel_webgl_fullscreen_quad.js
@@ -0,0 +1,127 @@
+// 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.
+
+const vertexShader = [
+  "attribute vec3 pos;",
+  "void main(void)",
+  "{",
+  "  gl_Position = vec4(pos, 1.0);",
+  "}"
+].join("\n");
+
+const fragmentShader = [
+  "precision mediump float;",
+  "void main(void)",
+  "{",
+  "  gl_FragColor = vec4(0.0, 1.0, 0.0, 1.0);",
+  "}"
+].join("\n");
+
+let gl;
+
+function sendResult(status, detail) {
+  console.log(detail);
+  if (window.domAutomationController) {
+    window.domAutomationController.send(status);
+  } else {
+    console.log(status);
+  }
+}
+
+function initGL(canvas)
+{
+  try {
+    gl = canvas.getContext("webgl", { powerPreference: "low-power" });
+  } catch (e) {}
+  return gl;
+}
+
+function setupShader(source, type) {
+  var shader = gl.createShader(type);
+  gl.shaderSource(shader, source);
+  gl.compileShader(shader);
+  if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS))
+    return null;
+  return shader;
+}
+
+function setupProgram(vs_id, fs_id) {
+  var vs = setupShader(vertexShader, gl.VERTEX_SHADER);
+  var fs = setupShader(fragmentShader, gl.FRAGMENT_SHADER);
+  if (!vs || !fs)
+    return null;
+  var program = gl.createProgram();
+  gl.attachShader(program, vs);
+  gl.attachShader(program, fs);
+  gl.linkProgram(program);
+  if (!gl.getProgramParameter(program, gl.LINK_STATUS))
+    return null;
+  gl.useProgram(program);
+  return program;
+}
+
+function setupBuffer(gl) {
+  var buffer = gl.createBuffer();
+  gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
+  var vertexData = [
+    // Triangle 1
+    -1.0, -1.0, 0.0,
+    1.0, 1.0, 0.0,
+    -1.0, 1.0, 0.0,
+
+    // Triangle 2
+    -1.0, -1.0, 0.0,
+    1.0, -1.0, 0.0,
+    1.0, 1.0, 0.0
+  ];
+  gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertexData), gl.STATIC_DRAW);
+}
+
+function setupGL() {
+  var program = setupProgram("shader-vs", "shader-fs");
+  if (!program)
+    return false;
+  var posAttr = gl.getAttribLocation(program, "pos");
+  gl.enableVertexAttribArray(posAttr);
+  setupBuffer(gl);
+  var stride = 3 * Float32Array.BYTES_PER_ELEMENT;
+  gl.vertexAttribPointer(posAttr, 3, gl.FLOAT, false, stride, 0);
+  gl.clearColor(0.0, 0.0, 0.0, 0.0);
+  gl.viewport(0, 0, 300, 300);
+  gl.disable(gl.DEPTH_TEST);
+  if (gl.getError() != gl.NO_ERROR)
+    return false;
+  return true;
+}
+
+function drawQuad() {
+  gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
+  gl.drawArrays(gl.TRIANGLES, 0, 6);
+}
+
+function setup()
+{
+  let canvas = document.getElementById("c");
+  initGL(canvas);
+  if (gl && setupGL(gl))
+    return true;
+  domAutomationController.send("FAILURE");
+  return false;
+}
+
+function drawSomeFrames(callback)
+{
+  let swapsBeforeCallback = 15;
+
+  function drawSomeFramesHelper() {
+    if (--swapsBeforeCallback == 0) {
+      callback();
+    } else {
+      drawQuad();
+      window.requestAnimationFrame(drawSomeFramesHelper);
+    }
+  }
+
+  window.requestAnimationFrame(drawSomeFramesHelper);
+}
diff --git a/content/test/data/gpu/pixel_webgl_high_to_low_power.html b/content/test/data/gpu/pixel_webgl_high_to_low_power.html
new file mode 100644
index 0000000..aa6f7a0
--- /dev/null
+++ b/content/test/data/gpu/pixel_webgl_high_to_low_power.html
@@ -0,0 +1,52 @@
+<!DOCTYPE HTML>
+
+<html>
+<head>
+<meta name="viewport" content="initial-scale=1">
+<title>WebGL High to Low Power Transition Test</title>
+<style type="text/css">
+.nomargin {
+  margin: 0px auto;
+}
+</style>
+<script src="pixel_webgl_fullscreen_quad.js"></script>
+
+<script>
+function ready() {
+  sendResult("READY", "Ready for second tab to be launched");
+}
+
+function initialize() {
+  if (setup())
+    drawSomeFrames(notifyHarness);
+}
+
+function notifyHarness() {
+  sendResult("READY", "Ready for second tab to be closed");
+}
+
+function runToCompletion() {
+  drawSomeFrames(waitForFinish);
+}
+
+function waitForFinish()
+{
+  let numFramesBeforeEnd = 15;
+
+  function waitForFinishImpl() {
+    if (--numFramesBeforeEnd == 0) {
+      sendResult("SUCCESS", "Test complete");
+    } else {
+      window.requestAnimationFrame(waitForFinishImpl);
+    }
+  }
+
+  window.requestAnimationFrame(waitForFinishImpl);
+}
+</script>
+</head>
+<body onload="ready()">
+<canvas id="c" width="300" height="300" class="nomargin" style="position:absolute; top:0px; left:0px;"></canvas>
+</div>
+</body>
+</html>
diff --git a/content/test/data/gpu/pixel_webgl_low_to_high_power.html b/content/test/data/gpu/pixel_webgl_low_to_high_power.html
new file mode 100644
index 0000000..b97e4cd
--- /dev/null
+++ b/content/test/data/gpu/pixel_webgl_low_to_high_power.html
@@ -0,0 +1,46 @@
+<!DOCTYPE HTML>
+
+<html>
+<head>
+<meta name="viewport" content="initial-scale=1">
+<title>WebGL Low to High Power Transition Test</title>
+<style type="text/css">
+.nomargin {
+  margin: 0px auto;
+}
+</style>
+<script src="pixel_webgl_fullscreen_quad.js"></script>
+
+<script>
+function main() {
+  if (setup())
+    drawSomeFrames(allocateHighPowerContext);
+}
+
+function allocateHighPowerContext() {
+  c2.getContext("webgl", { powerPreference: "high-performance" });
+  setTimeout(() => { drawSomeFrames(waitForFinish) }, 1000);
+}
+
+function waitForFinish()
+{
+  let numFramesBeforeEnd = 15;
+
+  function waitForFinishImpl() {
+    if (--numFramesBeforeEnd == 0) {
+      sendResult("SUCCESS", "Test complete");
+    } else {
+      window.requestAnimationFrame(waitForFinishImpl);
+    }
+  }
+
+  window.requestAnimationFrame(waitForFinishImpl);
+}
+</script>
+</head>
+<body onload="main()">
+<canvas id="c" width="300" height="300" class="nomargin" style="position:absolute; top:0px; left:0px;"></canvas>
+<canvas id="c2" width="1" height="1" class="nomargin"></canvas>
+</div>
+</body>
+</html>
diff --git a/content/test/data/gpu/pixel_webgl_util.js b/content/test/data/gpu/pixel_webgl_util.js
index 1f084d8..8f88e2f 100644
--- a/content/test/data/gpu/pixel_webgl_util.js
+++ b/content/test/data/gpu/pixel_webgl_util.js
@@ -1,11 +1,6 @@
 // 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.
-//
-// READ BEFORE UPDATING:
-// If this file is updated, make sure to increment the "revision" value of any
-// tests that use this file in content/test/gpu/page_sets/pixel_tests.py. This
-// will ensure that the baseline images are regenerated on the next run.
 
 var vertexShader = [
   "attribute vec3 pos;",
diff --git a/content/test/data/gpu/webgl2-multisampling-high-power-switch-loses-context.html b/content/test/data/gpu/webgl2-multisampling-high-power-switch-loses-context.html
new file mode 100644
index 0000000..4b4aa98
--- /dev/null
+++ b/content/test/data/gpu/webgl2-multisampling-high-power-switch-loses-context.html
@@ -0,0 +1,62 @@
+<html>
+<head>
+<script type="text/javascript">
+let canvas;
+let gl;
+let msrb;
+let contextLost = false;
+
+function send(str) {
+  if (window.domAutomationController) {
+    window.domAutomationController.send(str);
+  } else {
+    console.log(str);
+  }
+}
+
+function animate() {
+  if (!contextLost) {
+    gl.clearColor(0, 1, 0, 1);
+    gl.clear(gl.COLOR_BUFFER_BIT);
+  }
+  requestAnimationFrame(animate);
+}
+
+function onLoad() {
+  canvas = document.getElementById("canvas1");
+  canvas.addEventListener('webglcontextlost', function(e) {
+    console.log('Context lost');
+    e.preventDefault();
+    contextLost = true;
+  }, false);
+  canvas.addEventListener('webglcontextrestored', function(e) {
+    contextLost = false;
+    send("SUCCESS");
+  }, false);
+  gl = canvas.getContext('webgl2', {powerPreference: "low-power"});
+  msrb = gl.createRenderbuffer();
+  gl.bindRenderbuffer(gl.RENDERBUFFER, msrb);
+  gl.renderbufferStorageMultisample(gl.RENDERBUFFER, 2, gl.RGBA8, 16, 16);
+  gl.bindRenderbuffer(gl.RENDERBUFFER, null);
+  let err = gl.getError();
+  if (err != 0) {
+    console.log("Error " + err + " allocating multisampled renderbuffer");
+    send("FAILED");
+    return;
+  }
+  // Must draw to the WebGL canvas in order for the GPU switch to be detected.
+  requestAnimationFrame(animate);
+  send("LOADED");
+}
+
+function runTest() {
+  let c2 = document.getElementById("canvas2");
+  let gl = c2.getContext('webgl2', {powerPreference: "high-performance"});
+}
+</script>
+</head>
+<body onload="onLoad()">
+<canvas id="canvas1" width="16px" height="16px"></canvas>
+<canvas id="canvas2" width="16px" height="16px"></canvas>
+</body>
+</html>
diff --git a/content/test/data/gpu/webgl2-preserve-db-high-power-switch-loses-context.html b/content/test/data/gpu/webgl2-preserve-db-high-power-switch-loses-context.html
new file mode 100644
index 0000000..d0d5b6b5
--- /dev/null
+++ b/content/test/data/gpu/webgl2-preserve-db-high-power-switch-loses-context.html
@@ -0,0 +1,52 @@
+<html>
+<head>
+<script type="text/javascript">
+let canvas;
+let gl;
+let msrb;
+let contextLost = false;
+
+function send(str) {
+  if (window.domAutomationController) {
+    window.domAutomationController.send(str);
+  } else {
+    console.log(str);
+  }
+}
+
+function animate() {
+  if (!contextLost) {
+    gl.clearColor(0, 1, 0, 1);
+    gl.clear(gl.COLOR_BUFFER_BIT);
+  }
+  requestAnimationFrame(animate);
+}
+
+function onLoad() {
+  canvas = document.getElementById("canvas1");
+  canvas.addEventListener('webglcontextlost', function(e) {
+    console.log('Context lost');
+    e.preventDefault();
+    contextLost = true;
+  }, false);
+  canvas.addEventListener('webglcontextrestored', function(e) {
+    contextLost = false;
+    send("SUCCESS");
+  }, false);
+  gl = canvas.getContext('webgl2', {powerPreference: "low-power", preserveDrawingBuffer:true});
+  // Must draw to the WebGL canvas in order for the GPU switch to be detected.
+  requestAnimationFrame(animate);
+  send("LOADED");
+}
+
+function runTest() {
+  let c2 = document.getElementById("canvas2");
+  let gl = c2.getContext('webgl2', {powerPreference: "high-performance"});
+}
+</script>
+</head>
+<body onload="onLoad()">
+<canvas id="canvas1" width="16px" height="16px"></canvas>
+<canvas id="canvas2" width="16px" height="16px"></canvas>
+</body>
+</html>
diff --git a/content/test/gpu/gpu_tests/context_lost_integration_test.py b/content/test/gpu/gpu_tests/context_lost_integration_test.py
index 6e3db6d..a30d380 100644
--- a/content/test/gpu/gpu_tests/context_lost_integration_test.py
+++ b/content/test/gpu/gpu_tests/context_lost_integration_test.py
@@ -2,6 +2,7 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
+import logging
 import os
 import sys
 import time
@@ -70,7 +71,13 @@
     return [
       '--disable-gpu-process-crash-limit',
       # Required to call crashGpuProcess.
-      '--enable-gpu-benchmarking'] + browser_args
+      '--enable-gpu-benchmarking',
+      # Disable:
+      #   Do you want the application "Chromium Helper.app" to accept incoming
+      #   network connections?
+      # dialogs on macOS. crbug.com/969559
+      '--disable-device-discovery-notifications',
+    ] + browser_args
 
   @classmethod
   def GenerateGpuTests(cls, options):
@@ -96,7 +103,11 @@
              ('ContextLost_WorkerRAFAfterGPUCrash_OOPD',
               'worker-raf-after-gpu-crash.html'),
              ('ContextLost_WebGL2Blocked',
-              'webgl2-context-blocked.html'))
+              'webgl2-context-blocked.html'),
+             ('ContextLost_MacWebGLMultisamplingHighPowerSwitchLosesContext',
+              'webgl2-multisampling-high-power-switch-loses-context.html'),
+             ('ContextLost_MacWebGLPreserveDBHighPowerSwitchLosesContext',
+              'webgl2-preserve-db-high-power-switch-loses-context.html'))
     for t in tests:
       yield (t[0], t[1], ('_' + t[0]))
 
@@ -214,7 +225,7 @@
     tab = self.tab
     completed = self._WaitForPageToFinish(tab)
     if not completed:
-      self.fail('Test didn\'t complete (no context restored event?)')
+      self.fail('Test didn\'t complete (no context lost / restored event?)')
     if not tab.EvaluateJavaScript('window.domAutomationController._succeeded'):
       self.fail('Test failed (context not restored properly?)')
 
@@ -357,6 +368,47 @@
     # blacklisted should not cause the GPU process to crash.
     self._CheckCrashCount(tab, 0)
 
+  def _ContextLost_MacWebGLMultisamplingHighPowerSwitchLosesContext(self, test_path):
+    # Verifies that switching from the low-power to the high-power GPU
+    # on a dual-GPU Mac, while the user has allocated multisampled
+    # renderbuffers via the WebGL 2.0 API, causes the context to be
+    # lost.
+    if not self._IsDualGPUMacLaptop():
+      logging.info('Skipping test because not running on dual-GPU Mac laptop')
+      return
+    # Start with a browser with clean GPU process state.
+    self.RestartBrowserWithArgs(self._AddDefaultArgs([]))
+    # Wait a few seconds for the system to dispatch any GPU switched
+    # notifications.
+    time.sleep(3)
+    self._NavigateAndWaitForLoad(test_path)
+    if not self._IsIntel(self.browser.GetSystemInfo().gpu.devices[0].vendor_id):
+      self.fail('Test did not start up on low-power GPU')
+    tab = self.tab
+    tab.EvaluateJavaScript('runTest()')
+    self._WaitForTabAndCheckCompletion()
+    self._CheckCrashCount(tab, 0)
+
+  def _ContextLost_MacWebGLPreserveDBHighPowerSwitchLosesContext(self, test_path):
+    # Verifies that switching from the low-power to the high-power GPU on a
+    # dual-GPU Mac, when the user specified preserveDrawingBuffer:true, causes
+    # the context to be lost.
+    if not self._IsDualGPUMacLaptop():
+      logging.info('Skipping test because not running on dual-GPU Mac laptop')
+      return
+    # Start with a browser with clean GPU process state.
+    self.RestartBrowserWithArgs(self._AddDefaultArgs([]))
+    # Wait a few seconds for the system to dispatch any GPU switched
+    # notifications.
+    time.sleep(3)
+    self._NavigateAndWaitForLoad(test_path)
+    if not self._IsIntel(self.browser.GetSystemInfo().gpu.devices[0].vendor_id):
+      self.fail('Test did not start up on low-power GPU')
+    tab = self.tab
+    tab.EvaluateJavaScript('runTest()')
+    self._WaitForTabAndCheckCompletion()
+    self._CheckCrashCount(tab, 0)
+
   @classmethod
   def GetPlatformTags(cls, browser):
     tags = super(ContextLostIntegrationTest, cls).GetPlatformTags(browser)
diff --git a/content/test/gpu/gpu_tests/gpu_integration_test.py b/content/test/gpu/gpu_tests/gpu_integration_test.py
index b6acf57c..38d2910 100644
--- a/content/test/gpu/gpu_tests/gpu_integration_test.py
+++ b/content/test/gpu/gpu_tests/gpu_integration_test.py
@@ -4,6 +4,7 @@
 
 import logging
 import re
+import sys
 
 from telemetry.core import android_platform
 from telemetry.testing import serially_executed_browser_test_case
@@ -217,6 +218,34 @@
         logging.warning(
           '%s was expected to fail, but passed.\n', test_name)
 
+  def _IsIntel(self, vendor_id):
+    return vendor_id == 0x8086
+
+  def _IsIntelGPUActive(self):
+    gpu = self.browser.GetSystemInfo().gpu
+    # The implementation of GetSystemInfo guarantees that the first entry in the
+    # GPU devices list is the active GPU.
+    return self._IsIntel(gpu.devices[0].vendor_id)
+
+  def _IsDualGPUMacLaptop(self):
+    if sys.platform != 'darwin':
+      return False
+    system_info = self.browser.GetSystemInfo()
+    if not system_info:
+      self.fail("Browser doesn't support GetSystemInfo")
+    gpu = system_info.gpu
+    if not gpu:
+      self.fail('Target machine must have a GPU')
+    if len(gpu.devices) != 2:
+      return False
+    if (self._IsIntel(gpu.devices[0].vendor_id) and not
+        self._IsIntel(gpu.devices[1].vendor_id)):
+      return True
+    if (not self._IsIntel(gpu.devices[0].vendor_id) and
+        self._IsIntel(gpu.devices[1].vendor_id)):
+      return True
+    return False
+
   @classmethod
   def GenerateGpuTests(cls, options):
     """Subclasses must implement this to yield (test_name, url, args)
diff --git a/content/test/gpu/gpu_tests/gpu_process_integration_test.py b/content/test/gpu/gpu_tests/gpu_process_integration_test.py
index a7aa064..6168ca3d 100644
--- a/content/test/gpu/gpu_tests/gpu_process_integration_test.py
+++ b/content/test/gpu/gpu_tests/gpu_process_integration_test.py
@@ -2,8 +2,10 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
+import logging
 import os
 import sys
+import time
 
 from gpu_tests import gpu_integration_test
 from gpu_tests import path_util
@@ -56,7 +58,13 @@
       # TODO(kbr): figure out why the following option seems to be
       # needed on Android for robustness.
       # https://github.com/catapult-project/catapult/issues/3122
-      '--no-first-run'] + browser_args
+      '--no-first-run',
+      # Disable:
+      #   Do you want the application "Chromium Helper.app" to accept incoming
+      #   network connections?
+      # dialogs on macOS. crbug.com/969559
+      '--disable-device-discovery-notifications',
+    ] + browser_args
 
   @classmethod
   def GenerateGpuTests(cls, options):
@@ -81,14 +89,18 @@
               'gpu/functional_webgl.html'),
              ('GpuProcess_disable_swiftshader', 'gpu/functional_webgl.html'),
              ('GpuProcess_disabling_workarounds_works', 'chrome:gpu'),
+             ('GpuProcess_mac_webgl_backgrounded_high_performance',
+              'gpu/functional_blank.html'),
+             ('GpuProcess_mac_webgl_high_performance',
+              'gpu/functional_webgl_high_performance.html'),
+             ('GpuProcess_mac_webgl_low_power',
+              'gpu/functional_webgl_low_power.html'),
+             ('GpuProcess_mac_webgl_terminated_high_performance',
+              'gpu/functional_blank.html'),
              ('GpuProcess_swiftshader_for_webgl', 'gpu/functional_webgl.html'),
              ('GpuProcess_webgl_disabled_extension',
               'gpu/functional_webgl_disabled_extension.html'))
 
-    # The earlier has_transparent_visuals_gpu_process and
-    # no_transparent_visuals_gpu_process tests became no-ops in
-    # http://crrev.com/2347383002 and were deleted.
-
     for t in tests:
       yield (t[0], t[1], ('_' + t[0]))
 
@@ -108,14 +120,16 @@
     self.tab.action_runner.Navigate(
       url, script_to_evaluate_on_commit=test_harness_script)
 
-  def _NavigateAndWait(self, test_path):
-    self._Navigate(test_path)
-    tab = self.tab
+  def _WaitForTestCompletion(self, tab):
     tab.action_runner.WaitForJavaScriptCondition(
       'window.domAutomationController._finished', timeout=10)
     if not tab.EvaluateJavaScript('window.domAutomationController._succeeded'):
       self.fail('Test reported that it failed')
 
+  def _NavigateAndWait(self, test_path):
+    self._Navigate(test_path)
+    self._WaitForTestCompletion(self.tab)
+
   def _VerifyGpuProcessPresent(self):
     tab = self.tab
     if not tab.EvaluateJavaScript('chrome.gpuBenchmarking.hasGpuChannel()'):
@@ -219,28 +233,28 @@
   # The actual tests
 
   def _GpuProcess_canvas2d(self, test_path):
-    self.RestartBrowserIfNecessaryWithArgs([])
+    self.RestartBrowserIfNecessaryWithArgs(self._AddDefaultArgs([]))
     self._NavigateAndWait(test_path)
     self._VerifyGpuProcessPresent()
 
   def _GpuProcess_css3d(self, test_path):
-    self.RestartBrowserIfNecessaryWithArgs([])
+    self.RestartBrowserIfNecessaryWithArgs(self._AddDefaultArgs([]))
     self._NavigateAndWait(test_path)
     self._VerifyGpuProcessPresent()
 
   def _GpuProcess_webgl(self, test_path):
-    self.RestartBrowserIfNecessaryWithArgs([])
+    self.RestartBrowserIfNecessaryWithArgs(self._AddDefaultArgs([]))
     self._NavigateAndWait(test_path)
     self._VerifyGpuProcessPresent()
 
   def _GpuProcess_video(self, test_path):
-    self.RestartBrowserIfNecessaryWithArgs([])
+    self.RestartBrowserIfNecessaryWithArgs(self._AddDefaultArgs([]))
     self._NavigateAndWait(test_path)
     self._VerifyGpuProcessPresent()
 
   def _GpuProcess_gpu_info_complete(self, test_path):
     # Regression test for crbug.com/454906
-    self.RestartBrowserIfNecessaryWithArgs([])
+    self.RestartBrowserIfNecessaryWithArgs(self._AddDefaultArgs([]))
     self._NavigateAndWait(test_path)
     tab = self.tab
     system_info = tab.browser.GetSystemInfo()
@@ -258,16 +272,16 @@
       self.fail('Must have a non-empty gl_renderer string')
 
   def _GpuProcess_driver_bug_workarounds_in_gpu_process(self, test_path):
-    self.RestartBrowserIfNecessaryWithArgs([
-      '--use_gpu_driver_workaround_for_testing'])
+    self.RestartBrowserIfNecessaryWithArgs(self._AddDefaultArgs([
+      '--use_gpu_driver_workaround_for_testing']))
     self._Navigate(test_path)
     self._ValidateDriverBugWorkarounds(
       'use_gpu_driver_workaround_for_testing', None)
 
   def _GpuProcess_readback_webgl_gpu_process(self, test_path):
     # Hit test group 1 with entry 152 from kSoftwareRenderingListEntries.
-    self.RestartBrowserIfNecessaryWithArgs([
-      '--gpu-blacklist-test-group=1'])
+    self.RestartBrowserIfNecessaryWithArgs(self._AddDefaultArgs([
+      '--gpu-blacklist-test-group=1']))
     self._Navigate(test_path)
     feature_status_list = self.tab.EvaluateJavaScript(
         'browserBridge.gpuInfo.featureStatus.featureStatus')
@@ -286,8 +300,8 @@
     if not self._SupportsSwiftShader():
       return
     # Hit test group 2 with entry 153 from kSoftwareRenderingListEntries.
-    self.RestartBrowserIfNecessaryWithArgs([
-      '--gpu-blacklist-test-group=2'])
+    self.RestartBrowserIfNecessaryWithArgs(self._AddDefaultArgs([
+      '--gpu-blacklist-test-group=2']))
     self._Navigate(test_path)
     feature_status_list = self.tab.EvaluateJavaScript(
         'browserBridge.gpuInfo.featureStatus.featureStatus')
@@ -322,7 +336,7 @@
   def _GpuProcess_one_extra_workaround(self, test_path):
     # Start this test by launching the browser with no command line
     # arguments.
-    self.RestartBrowserIfNecessaryWithArgs([])
+    self.RestartBrowserIfNecessaryWithArgs(self._AddDefaultArgs([]))
     self._Navigate(test_path)
     self._VerifyGpuProcessPresent()
     recorded_workarounds, recorded_disabled_gl_extensions = (
@@ -334,7 +348,7 @@
     recorded_workarounds.append('use_gpu_driver_workaround_for_testing')
     browser_args.append('--disable-gl-extensions=' +
                         recorded_disabled_gl_extensions)
-    self.RestartBrowserIfNecessaryWithArgs(browser_args)
+    self.RestartBrowserIfNecessaryWithArgs(self._AddDefaultArgs(browser_args))
     self._Navigate(test_path)
     self._VerifyGpuProcessPresent()
     new_workarounds, new_disabled_gl_extensions = (
@@ -364,7 +378,8 @@
       # Chrome on Android doesn't support software fallback, skip it.
       # TODO(zmo): If this test runs on ChromeOS, we also need to skip it.
       return
-    self.RestartBrowserIfNecessaryWithArgs(['--disable-gpu'])
+    self.RestartBrowserIfNecessaryWithArgs(self._AddDefaultArgs(
+      ['--disable-gpu']))
     self._NavigateAndWait(test_path)
     # On Windows, Linux or MacOS, SwiftShader is enabled, so GPU process
     # will still launch with SwiftShader.
@@ -387,16 +402,17 @@
       # The current configuration will always launch a GPU process, skip test.
       return
 
-    self.RestartBrowserIfNecessaryWithArgs([
+    self.RestartBrowserIfNecessaryWithArgs(self._AddDefaultArgs([
       '--disable-gpu',
-      '--disable-software-rasterizer'])
+      '--disable-software-rasterizer']))
     self._NavigateAndWait(test_path)
     if self.tab.EvaluateJavaScript('chrome.gpuBenchmarking.hasGpuProcess()'):
       self.fail('GPU process detected')
 
   def _GpuProcess_disable_swiftshader(self, test_path):
     # Disable SwiftShader, GPU process should be able to launch.
-    self.RestartBrowserIfNecessaryWithArgs(['--disable-software-rasterizer'])
+    self.RestartBrowserIfNecessaryWithArgs(self._AddDefaultArgs(
+      ['--disable-software-rasterizer']))
     self._NavigateAndWait(test_path)
     if not self.tab.EvaluateJavaScript(
         'chrome.gpuBenchmarking.hasGpuProcess()'):
@@ -404,9 +420,9 @@
 
   def _GpuProcess_disabling_workarounds_works(self, test_path):
     # Hit exception from id 215 from kGpuDriverBugListEntries.
-    self.RestartBrowserIfNecessaryWithArgs([
+    self.RestartBrowserIfNecessaryWithArgs(self._AddDefaultArgs([
       '--gpu-driver-bug-list-test-group=1',
-      '--use_gpu_driver_workaround_for_testing=0'])
+      '--use_gpu_driver_workaround_for_testing=0']))
     self._Navigate(test_path)
     workarounds, _ = (
       self._CompareAndCaptureDriverBugWorkarounds())
@@ -425,7 +441,7 @@
       # Explicitly disable GPU access.
       ['--disable-gpu'])
     for args in args_list:
-      self.RestartBrowserIfNecessaryWithArgs(args)
+      self.RestartBrowserIfNecessaryWithArgs(self._AddDefaultArgs(args))
       self._NavigateAndWait(test_path)
       # Validate the WebGL unmasked renderer string.
       renderer = self.tab.EvaluateJavaScript('gl_renderer')
@@ -480,11 +496,124 @@
 
   def _GpuProcess_webgl_disabled_extension(self, test_path):
     # Hit exception from id 257 from kGpuDriverBugListEntries.
-    self.RestartBrowserIfNecessaryWithArgs([
+    self.RestartBrowserIfNecessaryWithArgs(self._AddDefaultArgs([
       '--gpu-driver-bug-list-test-group=2',
-    ])
+    ]))
     self._NavigateAndWait(test_path)
 
+
+  def _GpuProcess_mac_webgl_low_power(self, test_path):
+    # Ensures that low-power WebGL content stays on the low-power GPU.
+    if not self._IsDualGPUMacLaptop():
+      logging.info('Skipping test because not running on dual-GPU Mac laptop')
+      return
+    # Start with a clean browser instance to ensure the GPU process is in a
+    # clean state.
+    self.RestartBrowserWithArgs(self._AddDefaultArgs([]))
+    # Wait a few seconds for the system to dispatch any GPU switched
+    # notifications.
+    time.sleep(3)
+    self._NavigateAndWait(test_path)
+    # Sleep for several seconds to ensure that any GPU switch is detected.
+    time.sleep(6)
+    if not self._IsIntelGPUActive():
+      self.fail(
+        'Low-power WebGL context incorrectly activated the high-performance '
+        'GPU')
+
+  def _GpuProcess_mac_webgl_high_performance(self, test_path):
+    # Ensures that high-performance WebGL content activates the high-performance
+    # GPU.
+    if not self._IsDualGPUMacLaptop():
+      logging.info('Skipping test because not running on dual-GPU Mac laptop')
+      return
+    # Start with a clean browser instance to ensure the GPU process is in a
+    # clean state.
+    self.RestartBrowserWithArgs(self._AddDefaultArgs([]))
+    # Wait a few seconds for the system to dispatch any GPU switched
+    # notifications.
+    time.sleep(3)
+    self._NavigateAndWait(test_path)
+    # Sleep for several seconds to ensure that any GPU switch is detected.
+    time.sleep(6)
+    if self._IsIntelGPUActive():
+      self.fail(
+        'High-performance WebGL context did not activate the high-performance '
+        'GPU')
+
+  def _GpuProcess_mac_webgl_backgrounded_high_performance(self, test_path):
+    # Ensures that high-performance WebGL content in a background tab releases
+    # the hold on the discrete GPU after 10 seconds.
+    if not self._IsDualGPUMacLaptop():
+      logging.info('Skipping test because not running on dual-GPU Mac laptop')
+      return
+    # Start with a clean browser instance to ensure the GPU process is in a
+    # clean state.
+    self.RestartBrowserWithArgs(self._AddDefaultArgs([]))
+    # Wait a few seconds for the system to dispatch any GPU switched
+    # notifications.
+    time.sleep(3)
+    self._NavigateAndWait(test_path)
+    blank_tab = self.tab
+    # Create a new tab and navigate it to the high-power WebGL test.
+    webgl_tab = self.browser.tabs.New()
+    webgl_tab.Activate()
+    webgl_url = self.UrlOfStaticFilePath(
+      'gpu/functional_webgl_high_performance.html')
+    webgl_tab.action_runner.Navigate(
+      webgl_url, script_to_evaluate_on_commit=test_harness_script)
+    self._WaitForTestCompletion(webgl_tab)
+    # Verify that the high-performance GPU is active.
+    if self._IsIntelGPUActive():
+      self.fail(
+        'High-performance WebGL context did not activate the high-performance '
+        'GPU')
+    # Now activate the original tab.
+    blank_tab.Activate()
+    # Sleep for >10 seconds in order to wait for the hold on the
+    # high-performance GPU to be released.
+    time.sleep(15)
+    if not self._IsIntelGPUActive():
+      self.fail(
+        'Backgrounded high-performance WebGL context did not release the hold '
+        'on the high-performance GPU')
+
+  def _GpuProcess_mac_webgl_terminated_high_performance(self, test_path):
+    # Ensures that high-performance WebGL content in a background tab releases
+    # the hold on the discrete GPU after 10 seconds.
+    if not self._IsDualGPUMacLaptop():
+      logging.info('Skipping test because not running on dual-GPU Mac laptop')
+      return
+    # Start with a clean browser instance to ensure the GPU process is in a
+    # clean state.
+    self.RestartBrowserWithArgs(self._AddDefaultArgs([]))
+    # Wait a few seconds for the system to dispatch any GPU switched
+    # notifications.
+    time.sleep(3)
+    self._NavigateAndWait(test_path)
+    # Create a new tab and navigate it to the high-power WebGL test.
+    webgl_tab = self.browser.tabs.New()
+    webgl_tab.Activate()
+    webgl_url = self.UrlOfStaticFilePath(
+      'gpu/functional_webgl_high_performance.html')
+    webgl_tab.action_runner.Navigate(
+      webgl_url, script_to_evaluate_on_commit=test_harness_script)
+    self._WaitForTestCompletion(webgl_tab)
+    # Verify that the high-performance GPU is active.
+    if self._IsIntelGPUActive():
+      self.fail(
+        'High-performance WebGL context did not activate the high-performance '
+        'GPU')
+    # Close the high-performance WebGL tab.
+    webgl_tab.Close()
+    # Sleep for >10 seconds in order to wait for the hold on the
+    # high-performance GPU to be released.
+    time.sleep(15)
+    if not self._IsIntelGPUActive():
+      self.fail(
+        'Backgrounded high-performance WebGL context did not release the hold '
+        'on the high-performance GPU')
+
   @classmethod
   def ExpectationsFiles(cls):
     return [
diff --git a/content/test/gpu/gpu_tests/pixel_integration_test.py b/content/test/gpu/gpu_tests/pixel_integration_test.py
index e5119d2..d8bc6959 100644
--- a/content/test/gpu/gpu_tests/pixel_integration_test.py
+++ b/content/test/gpu/gpu_tests/pixel_integration_test.py
@@ -2,8 +2,10 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
+import logging
 import os
 import sys
+import time
 
 from gpu_tests import gpu_integration_test
 from gpu_tests import pixel_test_pages
@@ -62,6 +64,10 @@
     # pages += namespace.SwiftShaderPages(cls.test_base_name)
     if sys.platform.startswith('darwin'):
       pages += namespace.MacSpecificPages(cls.test_base_name)
+      # Unfortunately we don't have a browser instance here so can't tell
+      # whether we should really run these tests. They're short-circuited to a
+      # certain degree on the other platforms.
+      pages += namespace.DualGPUMacSpecificPages(cls.test_base_name)
     if sys.platform.startswith('win'):
       pages += namespace.DirectCompositionPages(cls.test_base_name)
       pages += namespace.LowLatencySwapChainPages(cls.test_base_name)
@@ -165,6 +171,42 @@
     dummy_tab.action_runner.Wait(2)
     tab.Activate()
 
+  def _RunTestWithHighPerformanceTab(self, tab, page):
+    if not self._IsDualGPUMacLaptop():
+      # Short-circuit this test.
+      logging.info('Short-circuiting test because not running on dual-GPU Mac '
+                   'laptop')
+      tab.EvaluateJavaScript('initialize()')
+      tab.action_runner.WaitForJavaScriptCondition(
+        'domAutomationController._readyForActions', timeout=30)
+      tab.EvaluateJavaScript('runToCompletion()')
+      return
+    # Reset the ready state of the harness.
+    tab.EvaluateJavaScript('domAutomationController._readyForActions = false')
+    high_performance_tab = tab.browser.tabs.New()
+    high_performance_tab.Navigate(self.UrlOfStaticFilePath(
+      skia_gold_integration_test_base.GPU_RELATIVE_PATH +
+      'functional_webgl_high_performance.html'),
+      script_to_evaluate_on_commit=test_harness_script)
+    high_performance_tab.action_runner.WaitForJavaScriptCondition(
+      'domAutomationController._finished', timeout=30)
+    # Wait a few seconds for the GPU switched notification to propagate
+    # throughout the system.
+    time.sleep(5)
+    # Switch back to the main tab and quickly start its rendering, while the
+    # high-power GPU is still active.
+    tab.Activate()
+    tab.EvaluateJavaScript('initialize()')
+    tab.action_runner.WaitForJavaScriptCondition(
+      'domAutomationController._readyForActions', timeout=30)
+    # Close the high-performance tab.
+    high_performance_tab.Close()
+    # Wait for ~15 seconds for the system to switch back to the
+    # integrated GPU.
+    time.sleep(15)
+    # Run the page to completion.
+    tab.EvaluateJavaScript('runToCompletion()')
+
   @classmethod
   def ExpectationsFiles(cls):
     return [
diff --git a/content/test/gpu/gpu_tests/pixel_test_pages.py b/content/test/gpu/gpu_tests/pixel_test_pages.py
index 244466c..c7a89f95 100644
--- a/content/test/gpu/gpu_tests/pixel_test_pages.py
+++ b/content/test/gpu/gpu_tests/pixel_test_pages.py
@@ -1169,6 +1169,41 @@
         ]),
     ]
 
+  # Pages that should be run only on dual-GPU MacBook Pros (at the
+  # present time, anyway).
+  @staticmethod
+  def DualGPUMacSpecificPages(base_name):
+    return [
+      PixelTestPage(
+        'pixel_webgl_high_to_low_power.html',
+        base_name + '_WebGLHighToLowPower',
+        test_rect=[0, 0, 300, 300],
+        tolerance=3,
+        expected_colors=[
+          {
+            'comment': 'solid green',
+            'location': [100, 100],
+            'size': [100, 100],
+            'color': [0, 255, 0],
+          }
+        ],
+        optional_action='RunTestWithHighPerformanceTab'),
+
+      PixelTestPage(
+        'pixel_webgl_low_to_high_power.html',
+        base_name + '_WebGLLowToHighPower',
+        test_rect=[0, 0, 300, 300],
+        tolerance=3,
+        expected_colors=[
+          {
+            'comment': 'solid green',
+            'location': [100, 100],
+            'size': [100, 100],
+            'color': [0, 255, 0],
+          }
+        ]),
+    ]
+
   @staticmethod
   def DirectCompositionPages(base_name):
     browser_args = [
diff --git a/content/test/gpu/gpu_tests/test_expectations/context_lost_expectations.txt b/content/test/gpu/gpu_tests/test_expectations/context_lost_expectations.txt
index bc9154b..85cdbd9 100644
--- a/content/test/gpu/gpu_tests/test_expectations/context_lost_expectations.txt
+++ b/content/test/gpu/gpu_tests/test_expectations/context_lost_expectations.txt
@@ -45,3 +45,9 @@
 crbug.com/609629 [ android qualcomm-adreno-(tm)-420 ] GpuCrash_GPUProcessCrashesExactlyOncePerVisitToAboutGpuCrash [ Skip ]
 crbug.com/609629 [ android qualcomm-adreno-(tm)-420 ] ContextLost_WebGLContextLostFromGPUProcessExit [ Skip ]
 crbug.com/609629 [ android qualcomm-adreno-(tm)-420 ] ContextLost_WebGLContextLostInHiddenTab [ Skip ]
+
+# TODO(crbug.com/681341): enable these new tests immediately after they land.
+# Disabled upon landing only to avoid having the entire CL reverted if the new
+# tests turn out to be flaky.
+crbug.com/681341 ContextLost_MacWebGLMultisamplingHighPowerSwitchLosesContext [ Skip ]
+crbug.com/681341 ContextLost_MacWebGLPreserveDBHighPowerSwitchLosesContext [ Skip ]
diff --git a/content/test/gpu/gpu_tests/test_expectations/gpu_process_expectations.txt b/content/test/gpu/gpu_tests/test_expectations/gpu_process_expectations.txt
index 71e3a1b..f4f7d48 100644
--- a/content/test/gpu/gpu_tests/test_expectations/gpu_process_expectations.txt
+++ b/content/test/gpu/gpu_tests/test_expectations/gpu_process_expectations.txt
@@ -6,3 +6,10 @@
 # Seems to have become flaky on Windows recently.
 crbug.com/700522 [ win ] GpuProcess_one_extra_workaround [ RetryOnFailure ]
 
+# TODO(crbug.com/681341): enable these new tests immediately after they land.
+# Disabled upon landing only to avoid having the entire CL reverted if the new
+# tests turn out to be flaky.
+crbug.com/681341 GpuProcess_mac_webgl_backgrounded_high_performance [ Skip ]
+crbug.com/681341 GpuProcess_mac_webgl_high_performance [ Skip ]
+crbug.com/681341 GpuProcess_mac_webgl_low_power [ Skip ]
+crbug.com/681341 GpuProcess_mac_webgl_terminated_high_performance [ Skip ]
diff --git a/content/test/gpu/gpu_tests/test_expectations/pixel_expectations.txt b/content/test/gpu/gpu_tests/test_expectations/pixel_expectations.txt
index fe863b3c..21297a3 100644
--- a/content/test/gpu/gpu_tests/test_expectations/pixel_expectations.txt
+++ b/content/test/gpu/gpu_tests/test_expectations/pixel_expectations.txt
@@ -262,3 +262,9 @@
 crbug.com/1019462 [ android nvidia no-skia-renderer ] Pixel_Video_MP4_Rounded_Corner [ RetryOnFailure ]
 crbug.com/1019462 [ android nvidia no-skia-renderer ] Pixel_Video_Context_Loss_VP9 [ RetryOnFailure ]
 crbug.com/1019462 [ android nvidia no-skia-renderer ] Pixel_WebGL2_BlitFramebuffer_Result_Displayed [ RetryOnFailure ]
+
+# TODO(crbug.com/681341): enable these new tests immediately after they land.
+# Disabled upon landing only to avoid having the entire CL reverted if the new
+# tests turn out to be flaky.
+crbug.com/681341 [ mac ] Pixel_WebGLHighToLowPower [ Skip ]
+crbug.com/681341 [ mac ] Pixel_WebGLLowToHighPower [ Skip ]
diff --git a/device/vr/BUILD.gn b/device/vr/BUILD.gn
index 2670b19..e47ed6b 100644
--- a/device/vr/BUILD.gn
+++ b/device/vr/BUILD.gn
@@ -249,8 +249,6 @@
       "test/fake_vr_device.h",
       "test/fake_vr_device_provider.cc",
       "test/fake_vr_device_provider.h",
-      "test/fake_vr_display_impl_client.cc",
-      "test/fake_vr_display_impl_client.h",
       "test/fake_vr_service_client.cc",
       "test/fake_vr_service_client.h",
       "vr_export.h",
diff --git a/device/vr/android/gvr/gvr_delegate_provider.h b/device/vr/android/gvr/gvr_delegate_provider.h
index 17625ee..a7391d2 100644
--- a/device/vr/android/gvr/gvr_delegate_provider.h
+++ b/device/vr/android/gvr/gvr_delegate_provider.h
@@ -24,7 +24,6 @@
       mojom::XRRuntimeSessionOptionsPtr options,
       base::OnceCallback<void(device::mojom::XRSessionPtr)> callback) = 0;
   virtual void ExitWebVRPresent() = 0;
-  virtual void OnListeningForActivateChanged(bool listening) = 0;
 
  protected:
   virtual ~GvrDelegateProvider() = default;
diff --git a/device/vr/android/gvr/gvr_device.cc b/device/vr/android/gvr/gvr_device.cc
index 7a56b30..c1c7e59 100644
--- a/device/vr/android/gvr/gvr_device.cc
+++ b/device/vr/android/gvr/gvr_device.cc
@@ -254,13 +254,6 @@
   exclusive_controller_receiver_.reset();
 }
 
-void GvrDevice::OnListeningForActivate(bool listening) {
-  GvrDelegateProvider* delegate_provider = GetGvrDelegateProvider();
-  if (!delegate_provider)
-    return;
-  delegate_provider->OnListeningForActivateChanged(listening);
-}
-
 void GvrDevice::PauseTracking() {
   paused_ = true;
   if (gvr_api_ && non_presenting_context_.obj()) {
@@ -297,11 +290,6 @@
   SetVRDisplayInfo(CreateVRDisplayInfo(gvr_api_.get(), GetId()));
 }
 
-void GvrDevice::Activate(mojom::VRDisplayEventReason reason,
-                         base::Callback<void(bool)> on_handled) {
-  OnActivate(reason, std::move(on_handled));
-}
-
 void GvrDevice::Init(base::OnceCallback<void(bool)> on_finished) {
   GvrDelegateProvider* delegate_provider = GetGvrDelegateProvider();
   if (!delegate_provider || delegate_provider->ShouldDisableGvrDevice()) {
diff --git a/device/vr/android/gvr/gvr_device.h b/device/vr/android/gvr/gvr_device.h
index 22aebae0..e44b9cb 100644
--- a/device/vr/android/gvr/gvr_device.h
+++ b/device/vr/android/gvr/gvr_device.h
@@ -38,13 +38,7 @@
       JNIEnv* env,
       const base::android::JavaRef<jobject>& obj);
 
-  void Activate(mojom::VRDisplayEventReason reason,
-                base::Callback<void(bool)> on_handled);
-
  private:
-  // VRDeviceBase
-  void OnListeningForActivate(bool listening) override;
-
   void OnStartPresentResult(mojom::XRSessionPtr session);
 
   // XRSessionController
diff --git a/device/vr/public/mojom/isolated_xr_service.mojom b/device/vr/public/mojom/isolated_xr_service.mojom
index 07234ee6..163c9b4 100644
--- a/device/vr/public/mojom/isolated_xr_service.mojom
+++ b/device/vr/public/mojom/isolated_xr_service.mojom
@@ -27,13 +27,6 @@
   // A device has changed its display information.
   OnDisplayInfoChanged(device.mojom.VRDisplayInfo display_info);
 
-  // A device has indicated that it is in use.
-  OnDeviceActivated(device.mojom.VRDisplayEventReason reason) =>
-      (bool will_not_present);
-
-  // A device has indicated that it is idle.
-  OnDeviceIdle(device.mojom.VRDisplayEventReason reason);
-
   // A device has indicated that the visibility of the content it's displaying
   // has changed.
   OnVisibilityStateChanged(device.mojom.XRVisibilityState visibility_state);
@@ -88,8 +81,6 @@
   // GvrDevice::RequestSession().
   EnsureInitialized() => ();
 
-  SetListeningForActivate(bool listen_for_activation);
-
   SetInlinePosesEnabled(bool enable);
 };
 
diff --git a/device/vr/public/mojom/vr_service.mojom b/device/vr/public/mojom/vr_service.mojom
index b4c7045..f8c86aa 100644
--- a/device/vr/public/mojom/vr_service.mojom
+++ b/device/vr/public/mojom/vr_service.mojom
@@ -465,13 +465,6 @@
   XRHitTestSubscriptionResultsData? hit_test_subscription_results;
 };
 
-enum VRDisplayEventReason {
-  NONE = 0,
-  NAVIGATION = 1,
-  MOUNTED = 2,
-  UNMOUNTED = 3
-};
-
 enum RequestSessionError {
   ORIGIN_NOT_SECURE = 1,
   EXISTING_IMMERSIVE_SESSION = 2,
@@ -502,10 +495,6 @@
   // A bad message will be reported if this is called multiple times.
   SetClient(pending_remote<VRServiceClient> client);
 
-  // WebVR 1.1 functionality compatibility method. To stop listening pass a null
-  // client.
-  SetListeningForActivate(pending_remote<VRDisplayClient>? client);
-
   // Request to initialize a session in the browser process. If successful, the
   // XRSession struct with the requisite interfaces will be returned.
   RequestSession(XRSessionOptions options) => (RequestSessionResult result);
@@ -724,15 +713,3 @@
   // Indicates a change in the visibility of the WebXR content.
   OnVisibilityStateChanged(XRVisibilityState visibility_state);
 };
-
-// Backwards compatibility events for WebVR 1.1. These are expected to not be
-// used for WebXR.
-interface VRDisplayClient {
-  // Inform the renderer that a headset has sent a signal indicating that the
-  // user has put it on. Returns an indicator of whether or not the page
-  // actually started a WebVR 1.1 presentation.
-  OnActivate(VRDisplayEventReason reason) => (bool will_not_present);
-  // Inform the renderer that a headset has sent a signal indicating that the
-  // user stopped using a headset.
-  OnDeactivate(VRDisplayEventReason reason);
-};
diff --git a/device/vr/test/fake_vr_display_impl_client.cc b/device/vr/test/fake_vr_display_impl_client.cc
deleted file mode 100644
index 09f64c69..0000000
--- a/device/vr/test/fake_vr_display_impl_client.cc
+++ /dev/null
@@ -1,25 +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 "device/vr/test/fake_vr_display_impl_client.h"
-#include "device/vr/test/fake_vr_service_client.h"
-
-namespace device {
-
-FakeVRDisplayImplClient::FakeVRDisplayImplClient(
-    mojo::PendingReceiver<mojom::VRDisplayClient> receiver)
-    : receiver_(this, std::move(receiver)) {}
-
-FakeVRDisplayImplClient::~FakeVRDisplayImplClient() {}
-
-void FakeVRDisplayImplClient::SetServiceClient(
-    FakeVRServiceClient* service_client) {
-  service_client_ = service_client;
-}
-
-void FakeVRDisplayImplClient::OnChanged(mojom::VRDisplayInfoPtr display) {
-  service_client_->SetLastDeviceId(display->id);
-}
-
-}  // namespace device
diff --git a/device/vr/test/fake_vr_display_impl_client.h b/device/vr/test/fake_vr_display_impl_client.h
deleted file mode 100644
index 836ff308..0000000
--- a/device/vr/test/fake_vr_display_impl_client.h
+++ /dev/null
@@ -1,43 +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 DEVICE_VR_TEST_FAKE_VR_DISPLAY_IMPL_CLIENT_H_
-#define DEVICE_VR_TEST_FAKE_VR_DISPLAY_IMPL_CLIENT_H_
-
-#include "device/vr/public/mojom/vr_service.mojom.h"
-#include "mojo/public/cpp/bindings/pending_receiver.h"
-#include "mojo/public/cpp/bindings/receiver.h"
-
-namespace device {
-class FakeVRServiceClient;
-
-class FakeVRDisplayImplClient : public mojom::VRDisplayClient,
-                                public mojom::XRSessionClient {
- public:
-  explicit FakeVRDisplayImplClient(
-      mojo::PendingReceiver<mojom::VRDisplayClient> receiver);
-  ~FakeVRDisplayImplClient() override;
-
-  void SetServiceClient(FakeVRServiceClient* service_client);
-  // mojom::XRSessionClient overrides
-  void OnChanged(mojom::VRDisplayInfoPtr display) override;
-  void OnExitPresent() override {}
-  void OnVisibilityStateChanged(
-      mojom::XRVisibilityState visibility_state) override {}
-  // mojom::VRDisplayClient overrides
-  void OnActivate(mojom::VRDisplayEventReason reason,
-                  OnActivateCallback callback) override {}
-  void OnDeactivate(mojom::VRDisplayEventReason reason) override {}
-
- private:
-  FakeVRServiceClient* service_client_;
-  mojom::VRDisplayInfoPtr last_display_;
-  mojo::Receiver<mojom::VRDisplayClient> receiver_;
-
-  DISALLOW_COPY_AND_ASSIGN(FakeVRDisplayImplClient);
-};
-
-}  // namespace device
-
-#endif  // DEVICE_VR_TEST_FAKE_VR_DISPLAY_IMPL_CLIENT_H_
diff --git a/device/vr/test/fake_vr_service_client.cc b/device/vr/test/fake_vr_service_client.cc
index 62e99f7e..c569673 100644
--- a/device/vr/test/fake_vr_service_client.cc
+++ b/device/vr/test/fake_vr_service_client.cc
@@ -3,7 +3,6 @@
 // found in the LICENSE file.
 
 #include "device/vr/test/fake_vr_service_client.h"
-#include "device/vr/test/fake_vr_display_impl_client.h"
 
 namespace device {
 
diff --git a/device/vr/test/fake_vr_service_client.h b/device/vr/test/fake_vr_service_client.h
index f52e660..68d8311 100644
--- a/device/vr/test/fake_vr_service_client.h
+++ b/device/vr/test/fake_vr_service_client.h
@@ -11,8 +11,6 @@
 #include "mojo/public/cpp/bindings/receiver.h"
 
 namespace device {
-class FakeVRDisplayImplClient;
-
 // TODO(mthiesse, crbug.com/769373): Remove DEVICE_VR_EXPORT.
 class DEVICE_VR_EXPORT FakeVRServiceClient : public mojom::VRServiceClient {
  public:
@@ -25,8 +23,6 @@
   bool CheckDeviceId(mojom::XRDeviceId id);
 
  private:
-  std::vector<mojom::VRDisplayInfoPtr> displays_;
-  std::vector<std::unique_ptr<FakeVRDisplayImplClient>> display_clients_;
   mojom::XRDeviceId last_device_id_ = static_cast<mojom::XRDeviceId>(0);
   mojo::Receiver<mojom::VRServiceClient> receiver_;
 
diff --git a/device/vr/vr_device_base.cc b/device/vr/vr_device_base.cc
index dc5aa21..dabda27 100644
--- a/device/vr/vr_device_base.cc
+++ b/device/vr/vr_device_base.cc
@@ -69,12 +69,6 @@
     listener_->OnDisplayInfoChanged(display_info_.Clone());
 }
 
-void VRDeviceBase::OnActivate(mojom::VRDisplayEventReason reason,
-                              base::Callback<void(bool)> on_handled) {
-  if (listener_)
-    listener_->OnDeviceActivated(reason, std::move(on_handled));
-}
-
 void VRDeviceBase::OnVisibilityStateChanged(
     mojom::XRVisibilityState visibility_state) {
   if (listener_)
@@ -86,12 +80,6 @@
   return runtime_receiver_.BindNewPipeAndPassRemote();
 }
 
-void VRDeviceBase::OnListeningForActivate(bool listening) {}
-
-void VRDeviceBase::SetListeningForActivate(bool is_listening) {
-  OnListeningForActivate(is_listening);
-}
-
 void VRDeviceBase::EnsureInitialized(EnsureInitializedCallback callback) {
   std::move(callback).Run();
 }
diff --git a/device/vr/vr_device_base.h b/device/vr/vr_device_base.h
index 325981f..feffa80b 100644
--- a/device/vr/vr_device_base.h
+++ b/device/vr/vr_device_base.h
@@ -33,7 +33,6 @@
   void ListenToDeviceChanges(
       mojo::PendingAssociatedRemote<mojom::XRRuntimeEventListener> listener,
       mojom::XRRuntime::ListenToDeviceChangesCallback callback) final;
-  void SetListeningForActivate(bool is_listening) override;
   void EnsureInitialized(EnsureInitializedCallback callback) override;
   void SetInlinePosesEnabled(bool enable) override;
   void ShutdownSession(mojom::XRRuntime::ShutdownSessionCallback) override;
@@ -67,8 +66,6 @@
   void OnStartPresenting();
   bool IsPresenting() { return presenting_; }  // Exposed for test.
   void SetVRDisplayInfo(mojom::VRDisplayInfoPtr display_info);
-  void OnActivate(mojom::VRDisplayEventReason reason,
-                  base::Callback<void(bool)> on_handled);
   void OnVisibilityStateChanged(mojom::XRVisibilityState visibility_state);
 
   mojom::VRDisplayInfoPtr display_info_;
@@ -76,8 +73,6 @@
   bool inline_poses_enabled_ = true;
 
  private:
-  // TODO(https://crbug.com/842227): Rename methods to HandleOnXXX
-  virtual void OnListeningForActivate(bool listening);
 
   mojo::AssociatedRemote<mojom::XRRuntimeEventListener> listener_;
 
diff --git a/device/vr/vr_device_base_unittest.cc b/device/vr/vr_device_base_unittest.cc
index e3cc3978..b1dde911 100644
--- a/device/vr/vr_device_base_unittest.cc
+++ b/device/vr/vr_device_base_unittest.cc
@@ -31,22 +31,11 @@
     SetVRDisplayInfo(std::move(display_info));
   }
 
-  void FireDisplayActivate() {
-    OnActivate(device::mojom::VRDisplayEventReason::MOUNTED, base::DoNothing());
-  }
-
-  bool ListeningForActivate() { return listening_for_activate; }
-
   void RequestSession(
       mojom::XRRuntimeSessionOptionsPtr options,
       mojom::XRRuntime::RequestSessionCallback callback) override {}
 
  private:
-  void OnListeningForActivate(bool listening) override {
-    listening_for_activate = listening;
-  }
-
-  bool listening_for_activate = false;
 
   DISALLOW_COPY_AND_ASSIGN(VRDeviceBaseForTesting);
 };
@@ -61,20 +50,8 @@
     DoOnChanged(vr_device_info.get());
   }
 
-  MOCK_METHOD2(DoOnDeviceActivated,
-               void(mojom::VRDisplayEventReason,
-                    base::OnceCallback<void(bool)>));
-  void OnDeviceActivated(mojom::VRDisplayEventReason reason,
-                         base::OnceCallback<void(bool)> callback) override {
-    DoOnDeviceActivated(reason, base::DoNothing());
-    // For now keep the test simple, and just call the callback:
-    std::move(callback).Run(true);
-  }
-
   MOCK_METHOD0(OnExitPresent, void());
   MOCK_METHOD1(OnVisibilityStateChanged, void(mojom::XRVisibilityState));
-  MOCK_METHOD1(OnDeviceIdle, void(mojom::VRDisplayEventReason));
-  MOCK_METHOD0(OnInitialized, void());
 
   mojo::PendingAssociatedRemote<mojom::XRRuntimeEventListener>
   BindPendingRemote() {
@@ -127,24 +104,4 @@
   base::RunLoop().RunUntilIdle();
 }
 
-TEST_F(VRDeviceTest, DisplayActivateRegsitered) {
-  device::mojom::VRDisplayEventReason mounted =
-      device::mojom::VRDisplayEventReason::MOUNTED;
-  auto device = MakeVRDevice();
-  mojo::Remote<mojom::XRRuntime> device_remote(device->BindXRRuntime());
-  StubVRDeviceEventListener listener;
-  device_remote->ListenToDeviceChanges(
-      listener.BindPendingRemote(),
-      base::DoNothing());  // TODO: consider getting initial data
-  base::RunLoop().RunUntilIdle();
-
-  EXPECT_FALSE(device->ListeningForActivate());
-  device->SetListeningForActivate(true);
-  EXPECT_TRUE(device->ListeningForActivate());
-
-  EXPECT_CALL(listener, DoOnDeviceActivated(mounted, testing::_)).Times(1);
-  device->FireDisplayActivate();
-  base::RunLoop().RunUntilIdle();
-}
-
 }  // namespace device
diff --git a/extensions/browser/api/web_request/web_request_proxying_url_loader_factory.cc b/extensions/browser/api/web_request/web_request_proxying_url_loader_factory.cc
index c02807b..20724d5 100644
--- a/extensions/browser/api/web_request/web_request_proxying_url_loader_factory.cc
+++ b/extensions/browser/api/web_request/web_request_proxying_url_loader_factory.cc
@@ -82,7 +82,6 @@
       traffic_annotation_(traffic_annotation),
       proxied_loader_receiver_(this, std::move(loader_receiver)),
       target_client_(std::move(client)),
-      proxied_client_binding_(this),
       current_response_(network::mojom::URLResponseHead::New()),
       has_any_extra_headers_listeners_(
           network_service_request_id_ != 0 &&
@@ -108,7 +107,6 @@
       original_initiator_(request.request_initiator),
       request_id_(request_id),
       proxied_loader_receiver_(this),
-      proxied_client_binding_(this),
       for_cors_preflight_(true),
       has_any_extra_headers_listeners_(
           ExtensionWebRequestEventRouter::GetInstance()
@@ -204,9 +202,9 @@
     // they respond. |continuation| above will be invoked asynchronously to
     // continue or cancel the request.
     //
-    // We pause the binding here to prevent further client message processing.
-    if (proxied_client_binding_.is_bound())
-      proxied_client_binding_.PauseIncomingMethodCallProcessing();
+    // We pause the receiver here to prevent further client message processing.
+    if (proxied_client_receiver_.is_bound())
+      proxied_client_receiver_.Pause();
 
     // Pause the header client, since we want to wait until OnBeforeRequest has
     // finished before processing any future events.
@@ -395,7 +393,7 @@
   header_client_receiver_.Bind(std::move(receiver));
   if (for_cors_preflight_) {
     // In this case we don't have |target_loader_| and
-    // |proxied_client_binding_|, and |receiver| is the only connection to the
+    // |proxied_client_receiver_|, and |receiver| is the only connection to the
     // network service, so we observe mojo connection errors.
     header_client_receiver_.set_disconnect_handler(base::BindOnce(
         &WebRequestProxyingURLLoaderFactory::InProgressRequest::OnRequestError,
@@ -453,7 +451,7 @@
   // bugs. The latter doesn't know anything about the redirect. Continuing
   // the load with it gives unexpected results. See
   // https://crbug.com/882661#c72.
-  proxied_client_binding_.Close();
+  proxied_client_receiver_.reset();
   header_client_receiver_.reset();
   target_loader_.reset();
 
@@ -523,8 +521,8 @@
     return;
   }
 
-  if (proxied_client_binding_.is_bound())
-    proxied_client_binding_.ResumeIncomingMethodCallProcessing();
+  if (proxied_client_receiver_.is_bound())
+    proxied_client_receiver_.Resume();
 
   if (request_.url.SchemeIsHTTPOrHTTPS()) {
     // NOTE: While it does not appear to be documented (and in fact it may be
@@ -551,8 +549,8 @@
       // continue or cancel the request.
       //
       // We pause the binding here to prevent further client message processing.
-      if (proxied_client_binding_.is_bound())
-        proxied_client_binding_.PauseIncomingMethodCallProcessing();
+      if (proxied_client_receiver_.is_bound())
+        proxied_client_receiver_.Pause();
       return;
     }
     DCHECK_EQ(net::OK, result);
@@ -579,8 +577,8 @@
     return;
   }
 
-  if (proxied_client_binding_.is_bound())
-    proxied_client_binding_.ResumeIncomingMethodCallProcessing();
+  if (proxied_client_receiver_.is_bound())
+    proxied_client_receiver_.Resume();
 
   if (header_client_receiver_.is_bound())
     header_client_receiver_.Resume();
@@ -596,7 +594,7 @@
     // No extensions have cancelled us up to this point, so it's now OK to
     // initiate the real network request.
     network::mojom::URLLoaderClientPtr proxied_client;
-    proxied_client_binding_.Bind(mojo::MakeRequest(&proxied_client));
+    proxied_client_receiver_.Bind(mojo::MakeRequest(&proxied_client));
     uint32_t options = options_;
     // Even if this request does not use the header client, future redirects
     // might, so we need to set the option on the loader.
@@ -651,8 +649,8 @@
     pending_follow_redirect_params_.reset();
   }
 
-  if (proxied_client_binding_.is_bound())
-    proxied_client_binding_.ResumeIncomingMethodCallProcessing();
+  if (proxied_client_receiver_.is_bound())
+    proxied_client_receiver_.Resume();
 
   if (request_.url.SchemeIsHTTPOrHTTPS()) {
     // NOTE: While it does not appear to be documented (and in fact it may be
@@ -707,8 +705,8 @@
     OnAuthRequestHandled(
         WebRequestAPI::AuthRequestCallback callback,
         ExtensionWebRequestEventRouter::AuthRequiredResponse response) {
-  if (proxied_client_binding_.is_bound())
-    proxied_client_binding_.ResumeIncomingMethodCallProcessing();
+  if (proxied_client_receiver_.is_bound())
+    proxied_client_receiver_.Resume();
 
   base::OnceClosure completion;
   switch (response) {
@@ -781,8 +779,8 @@
     return;
   }
 
-  if (proxied_client_binding_)
-    proxied_client_binding_.ResumeIncomingMethodCallProcessing();
+  if (proxied_client_receiver_.is_bound())
+    proxied_client_receiver_.Resume();
 }
 
 void WebRequestProxyingURLLoaderFactory::InProgressRequest::
@@ -817,7 +815,7 @@
 
     // These will get re-bound if a new request is initiated by
     // |FollowRedirect()|.
-    proxied_client_binding_.Close();
+    proxied_client_receiver_.reset();
     header_client_receiver_.reset();
     target_loader_.reset();
 
@@ -827,7 +825,7 @@
 
   info_->AddResponseInfoFromResourceResponse(*current_response_);
 
-  proxied_client_binding_.ResumeIncomingMethodCallProcessing();
+  proxied_client_receiver_.Resume();
 
   ExtensionWebRequestEventRouter::GetInstance()->OnResponseStarted(
       factory_->browser_context_, &info_.value(), net::OK);
@@ -844,8 +842,8 @@
 
   info_->AddResponseInfoFromResourceResponse(*current_response_);
 
-  if (proxied_client_binding_.is_bound())
-    proxied_client_binding_.ResumeIncomingMethodCallProcessing();
+  if (proxied_client_receiver_.is_bound())
+    proxied_client_receiver_.Resume();
 
   ExtensionWebRequestEventRouter::GetInstance()->OnBeforeRedirect(
       factory_->browser_context_, &info_.value(), redirect_info.new_url);
@@ -884,14 +882,14 @@
     }
 
     if (result == net::ERR_IO_PENDING) {
-      if (proxied_client_binding_.is_bound()) {
+      if (proxied_client_receiver_.is_bound()) {
         // One or more listeners is blocking, so the request must be paused
         // until they respond. |continuation| above will be invoked
         // asynchronously to continue or cancel the request.
         //
-        // We pause the binding here to prevent further client message
+        // We pause the receiver here to prevent further client message
         // processing.
-        proxied_client_binding_.PauseIncomingMethodCallProcessing();
+        proxied_client_receiver_.Pause();
       }
       return;
     }
diff --git a/extensions/browser/api/web_request/web_request_proxying_url_loader_factory.h b/extensions/browser/api/web_request/web_request_proxying_url_loader_factory.h
index 6d539b45..2b3eae7 100644
--- a/extensions/browser/api/web_request/web_request_proxying_url_loader_factory.h
+++ b/extensions/browser/api/web_request/web_request_proxying_url_loader_factory.h
@@ -145,7 +145,8 @@
 
     base::Optional<WebRequestInfo> info_;
 
-    mojo::Binding<network::mojom::URLLoaderClient> proxied_client_binding_;
+    mojo::Receiver<network::mojom::URLLoaderClient> proxied_client_receiver_{
+        this};
     network::mojom::URLLoaderPtr target_loader_;
 
     // NOTE: This is state which ExtensionWebRequestEventRouter needs to have
diff --git a/extensions/browser/extension_function_histogram_value.h b/extensions/browser/extension_function_histogram_value.h
index 6eee8b7..5906339 100644
--- a/extensions/browser/extension_function_histogram_value.h
+++ b/extensions/browser/extension_function_histogram_value.h
@@ -1466,6 +1466,7 @@
   AUTOTESTPRIVATE_REMOVEACTIVEDESK = 1403,
   TERMINALPRIVATE_GETCROSHSETTINGS = 1404,
   AUTOTESTPRIVATE_ENABLEASSISTANTANDWAITFORREADY = 1405,
+  INPUTMETHODPRIVATE_FINISHCOMPOSINGTEXT = 1406,
   // Last entry: Add new entries above, then run:
   // python tools/metrics/histograms/update_extension_histograms.py
   ENUM_BOUNDARY
diff --git a/google_apis/gaia/gaia_auth_fetcher.cc b/google_apis/gaia/gaia_auth_fetcher.cc
index 257e5dd..fb3a1c8 100644
--- a/google_apis/gaia/gaia_auth_fetcher.cc
+++ b/google_apis/gaia/gaia_auth_fetcher.cc
@@ -620,16 +620,13 @@
 }
 
 void GaiaAuthFetcher::StartTokenFetchForUberAuthExchange(
-    const std::string& access_token,
-    bool is_bound_to_channel_id) {
+    const std::string& access_token) {
   DCHECK(!fetch_pending_) << "Tried to fetch two things at once!";
 
   VLOG(1) << "Starting StartTokenFetchForUberAuthExchange with access_token="
            << access_token;
   std::string authentication_header =
       base::StringPrintf(kOAuthHeaderFormat, access_token.c_str());
-  int load_flags =
-      is_bound_to_channel_id ? net::LOAD_NORMAL : kLoadFlagsIgnoreCookies;
   net::NetworkTrafficAnnotationTag traffic_annotation =
       net::DefineNetworkTrafficAnnotation("gaia_auth_fetch_for_uber", R"(
         semantics {
@@ -658,7 +655,7 @@
           }
         })");
   CreateAndStartGaiaFetcher(std::string(), authentication_header,
-                            uberauth_token_gurl_, load_flags,
+                            uberauth_token_gurl_, kLoadFlagsIgnoreCookies,
                             traffic_annotation);
 }
 
diff --git a/google_apis/gaia/gaia_auth_fetcher.h b/google_apis/gaia/gaia_auth_fetcher.h
index 68cf5f3..bb7e3021 100644
--- a/google_apis/gaia/gaia_auth_fetcher.h
+++ b/google_apis/gaia/gaia_auth_fetcher.h
@@ -143,13 +143,10 @@
   // Start a request to exchange an OAuthLogin-scoped oauth2 access token for an
   // uber-auth token.  The returned token can be used with the method
   // StartMergeSession().
-  // If |is_bound_to_channel_id| is true, then the generated UberToken will
-  // be bound to the channel ID of the network context of |getter_|.
   //
   // Either OnUberAuthTokenSuccess or OnUberAuthTokenFailure will be
   // called on the consumer on the original thread.
-  void StartTokenFetchForUberAuthExchange(const std::string& access_token,
-                                          bool is_bound_to_channel_id);
+  void StartTokenFetchForUberAuthExchange(const std::string& access_token);
 
   // Start a request to exchange an OAuthLogin-scoped oauth2 access token for a
   // ClientLogin-style service tokens.  The response to this request is the
diff --git a/google_apis/gaia/gaia_auth_fetcher_unittest.cc b/google_apis/gaia/gaia_auth_fetcher_unittest.cc
index 018d8b8..86840c0 100644
--- a/google_apis/gaia/gaia_auth_fetcher_unittest.cc
+++ b/google_apis/gaia/gaia_auth_fetcher_unittest.cc
@@ -464,8 +464,7 @@
   EXPECT_CALL(consumer, OnUberAuthTokenSuccess("uberToken")).Times(1);
 
   TestGaiaAuthFetcher auth(&consumer, GetURLLoaderFactory());
-  auth.StartTokenFetchForUberAuthExchange("myAccessToken",
-                                          true /* is_bound_to_channel_id */);
+  auth.StartTokenFetchForUberAuthExchange("myAccessToken");
 
   EXPECT_TRUE(auth.HasPendingFetch());
   auth.TestOnURLLoadCompleteInternal(net::OK, net::HTTP_OK, "uberToken");
diff --git a/gpu/command_buffer/client/gles2_implementation.cc b/gpu/command_buffer/client/gles2_implementation.cc
index 914d6f12..3d6312a 100644
--- a/gpu/command_buffer/client/gles2_implementation.cc
+++ b/gpu/command_buffer/client/gles2_implementation.cc
@@ -53,6 +53,7 @@
 #include "gpu/command_buffer/common/sync_token.h"
 #include "ui/gfx/geometry/rect.h"
 #include "ui/gfx/geometry/rect_f.h"
+#include "ui/gl/gpu_preference.h"
 
 #if !defined(__native_client__)
 #include "ui/gfx/color_space.h"
@@ -386,17 +387,19 @@
   std::move(callback).Run(params);
 }
 
-void GLES2Implementation::OnGpuSwitched() {
-  share_group_->SetGpuSwitched(true);
+void GLES2Implementation::OnGpuSwitched(
+    gl::GpuPreference active_gpu_heuristic) {
+  gpu_switched_ = true;
+  active_gpu_heuristic_ = active_gpu_heuristic;
 }
 
-GLboolean GLES2Implementation::DidGpuSwitch() {
-  // TODO(zmo): Redesign this code; it works for now because the share group
-  // only contains one context but in the future only the first OpenGL context
-  // in the share group will receive GL_TRUE as the return value.
-  bool gpu_changed = share_group_->GetGpuSwitched();
-  share_group_->SetGpuSwitched(false);
-  return gpu_changed ? GL_TRUE : GL_FALSE;
+GLboolean GLES2Implementation::DidGpuSwitch(gl::GpuPreference* active_gpu) {
+  if (gpu_switched_) {
+    *active_gpu = active_gpu_heuristic_;
+  }
+  GLboolean result = gpu_switched_ ? GL_TRUE : GL_FALSE;
+  gpu_switched_ = false;
+  return result;
 }
 
 void GLES2Implementation::SendErrorMessage(std::string message, int32_t id) {
diff --git a/gpu/command_buffer/client/gles2_implementation.h b/gpu/command_buffer/client/gles2_implementation.h
index 9f3d8b2b..0baea84 100644
--- a/gpu/command_buffer/client/gles2_implementation.h
+++ b/gpu/command_buffer/client/gles2_implementation.h
@@ -99,7 +99,7 @@
 
   // GLES2Interface implementation
   void FreeSharedMemory(void*) override;
-  GLboolean DidGpuSwitch() final;
+  GLboolean DidGpuSwitch(gl::GpuPreference* active_gpu) final;
 
   // Include the auto-generated part of this class. We split this because
   // it means we can easily edit the non-auto generated parts right here in
@@ -400,7 +400,7 @@
   void OnGpuControlErrorMessage(const char* message, int32_t id) final;
   void OnGpuControlSwapBuffersCompleted(
       const SwapBuffersCompleteParams& params) final;
-  void OnGpuSwitched() final;
+  void OnGpuSwitched(gl::GpuPreference active_gpu_heuristic) final;
   void OnSwapBufferPresented(uint64_t swap_id,
                              const gfx::PresentationFeedback& feedback) final;
   void OnGpuControlReturnData(base::span<const uint8_t> data) final;
@@ -860,6 +860,9 @@
 
   std::string last_active_url_;
 
+  bool gpu_switched_ = false;
+  gl::GpuPreference active_gpu_heuristic_ = gl::GpuPreference::kDefault;
+
   base::WeakPtrFactory<GLES2Implementation> weak_ptr_factory_{this};
 
   DISALLOW_COPY_AND_ASSIGN(GLES2Implementation);
diff --git a/gpu/command_buffer/client/gles2_interface.cc b/gpu/command_buffer/client/gles2_interface.cc
index 722a39b..6b345766 100644
--- a/gpu/command_buffer/client/gles2_interface.cc
+++ b/gpu/command_buffer/client/gles2_interface.cc
@@ -9,7 +9,7 @@
 namespace gpu {
 namespace gles2 {
 
-GLboolean GLES2Interface::DidGpuSwitch() {
+GLboolean GLES2Interface::DidGpuSwitch(gl::GpuPreference* active_gpu) {
   return GL_FALSE;
 }
 
diff --git a/gpu/command_buffer/client/gles2_interface.h b/gpu/command_buffer/client/gles2_interface.h
index 1a6e382..ec6728c 100644
--- a/gpu/command_buffer/client/gles2_interface.h
+++ b/gpu/command_buffer/client/gles2_interface.h
@@ -22,6 +22,10 @@
 class Vector2dF;
 }  // namespace gfx
 
+namespace gl {
+enum class GpuPreference;
+}
+
 extern "C" typedef struct _ClientBuffer* ClientBuffer;
 extern "C" typedef struct _GLColorSpace* GLColorSpace;
 extern "C" typedef struct _ClientGpuFence* ClientGpuFence;
@@ -37,7 +41,11 @@
 
   virtual void FreeSharedMemory(void*) {}
 
-  virtual GLboolean DidGpuSwitch();
+  // Returns true if the active GPU switched since the last time this
+  // method was called. If so, |active_gpu| will be written with the
+  // results of the heuristic indicating which GPU is active;
+  // kDefault if "unknown", or kLowPower or kHighPerformance if known.
+  virtual GLboolean DidGpuSwitch(gl::GpuPreference* active_gpu);
 
   // Include the auto-generated part of this class. We split this because
   // it means we can easily edit the non-auto generated parts right here in
diff --git a/gpu/command_buffer/client/gpu_control_client.h b/gpu/command_buffer/client/gpu_control_client.h
index a2bbec2..c88be16c0 100644
--- a/gpu/command_buffer/client/gpu_control_client.h
+++ b/gpu/command_buffer/client/gpu_control_client.h
@@ -9,6 +9,7 @@
 
 #include "base/containers/span.h"
 #include "ui/gfx/presentation_feedback.h"
+#include "ui/gl/gpu_preference.h"
 
 namespace gpu {
 struct SwapBuffersCompleteParams;
@@ -28,7 +29,7 @@
   virtual void OnGpuControlErrorMessage(const char* message, int32_t id) = 0;
   virtual void OnGpuControlSwapBuffersCompleted(
       const SwapBuffersCompleteParams& params) = 0;
-  virtual void OnGpuSwitched() {}
+  virtual void OnGpuSwitched(gl::GpuPreference active_gpu_heuristic) {}
   virtual void OnSwapBufferPresented(
       uint64_t swap_id,
       const gfx::PresentationFeedback& feedback) = 0;
diff --git a/gpu/command_buffer/client/share_group.cc b/gpu/command_buffer/client/share_group.cc
index ceb61d8..a923387 100644
--- a/gpu/command_buffer/client/share_group.cc
+++ b/gpu/command_buffer/client/share_group.cc
@@ -401,16 +401,6 @@
   return lost_;
 }
 
-void ShareGroup::SetGpuSwitched(bool gpu_switched) {
-  base::AutoLock hold(gpu_switched_lock_);
-  gpu_switched_ = gpu_switched;
-}
-
-bool ShareGroup::GetGpuSwitched() const {
-  base::AutoLock hold(gpu_switched_lock_);
-  return gpu_switched_;
-}
-
 void ShareGroup::SetProgramInfoManagerForTesting(ProgramInfoManager* manager) {
   program_info_manager_.reset(manager);
 }
diff --git a/gpu/command_buffer/client/share_group.h b/gpu/command_buffer/client/share_group.h
index a1b6f74..7d074d1a 100644
--- a/gpu/command_buffer/client/share_group.h
+++ b/gpu/command_buffer/client/share_group.h
@@ -165,9 +165,6 @@
   // thread safe as contexts may be on different threads.
   bool IsLost() const;
 
-  void SetGpuSwitched(bool gpu_switched);
-  bool GetGpuSwitched() const;
-
  private:
   friend class gpu::RefCountedThreadSafe<ShareGroup>;
   friend class gpu::gles2::GLES2ImplementationTest;
@@ -189,9 +186,6 @@
   mutable base::Lock lost_lock_;
   bool lost_ = false;
 
-  mutable base::Lock gpu_switched_lock_;
-  bool gpu_switched_ = false;
-
   DISALLOW_COPY_AND_ASSIGN(ShareGroup);
 };
 
diff --git a/gpu/command_buffer/service/decoder_client.h b/gpu/command_buffer/service/decoder_client.h
index 1583419..85ebf14c 100644
--- a/gpu/command_buffer/service/decoder_client.h
+++ b/gpu/command_buffer/service/decoder_client.h
@@ -11,6 +11,7 @@
 
 #include "base/containers/span.h"
 #include "gpu/gpu_export.h"
+#include "ui/gl/gpu_preference.h"
 #include "url/gurl.h"
 
 namespace gpu {
@@ -23,7 +24,7 @@
   virtual void OnConsoleMessage(int32_t id, const std::string& message) = 0;
 
   // Notifies the renderer process that the active GPU changed.
-  virtual void OnGpuSwitched() {}
+  virtual void OnGpuSwitched(gl::GpuPreference active_gpu_heuristic) {}
 
   // Cache a newly linked shader.
   virtual void CacheShader(const std::string& key,
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder.cc b/gpu/command_buffer/service/gles2_cmd_decoder.cc
index 1e64f1a5..1b24f828 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder.cc
+++ b/gpu/command_buffer/service/gles2_cmd_decoder.cc
@@ -107,6 +107,7 @@
 #include "ui/gl/gl_implementation.h"
 #include "ui/gl/gl_surface.h"
 #include "ui/gl/gl_version_info.h"
+#include "ui/gl/gpu_preference.h"
 #include "ui/gl/gpu_switching_manager.h"
 #include "ui/gl/gpu_switching_observer.h"
 #include "ui/gl/gpu_timing.h"
@@ -755,7 +756,7 @@
                     const gfx::Rect& cleared_rect) override;
 
   // Implements GpuSwitchingObserver.
-  void OnGpuSwitched() override;
+  void OnGpuSwitched(gl::GpuPreference active_gpu_heuristic) override;
 
   // Restores the current state to the user's settings.
   void RestoreCurrentFramebufferBindings();
@@ -5291,9 +5292,9 @@
                                   0 /* border */, format, type, cleared_rect);
 }
 
-void GLES2DecoderImpl::OnGpuSwitched() {
+void GLES2DecoderImpl::OnGpuSwitched(gl::GpuPreference active_gpu_heuristic) {
   // Send OnGpuSwitched notification to renderer process via decoder client.
-  client()->OnGpuSwitched();
+  client()->OnGpuSwitched(active_gpu_heuristic);
 }
 
 void GLES2DecoderImpl::Destroy(bool have_context) {
diff --git a/gpu/ipc/client/command_buffer_proxy_impl.cc b/gpu/ipc/client/command_buffer_proxy_impl.cc
index 1ea1ee14..2ba4395e 100644
--- a/gpu/ipc/client/command_buffer_proxy_impl.cc
+++ b/gpu/ipc/client/command_buffer_proxy_impl.cc
@@ -38,6 +38,7 @@
 #include "ui/gfx/geometry/size.h"
 #include "ui/gfx/gpu_fence.h"
 #include "ui/gl/gl_bindings.h"
+#include "ui/gl/gpu_preference.h"
 
 namespace gpu {
 
@@ -190,9 +191,10 @@
                                                   message.id);
 }
 
-void CommandBufferProxyImpl::OnGpuSwitched() {
+void CommandBufferProxyImpl::OnGpuSwitched(
+    gl::GpuPreference active_gpu_heuristic) {
   if (gpu_control_client_)
-    gpu_control_client_->OnGpuSwitched();
+    gpu_control_client_->OnGpuSwitched(active_gpu_heuristic);
 }
 
 void CommandBufferProxyImpl::AddDeletionObserver(DeletionObserver* observer) {
diff --git a/gpu/ipc/client/command_buffer_proxy_impl.h b/gpu/ipc/client/command_buffer_proxy_impl.h
index 67cecbdf..b2be647ee 100644
--- a/gpu/ipc/client/command_buffer_proxy_impl.h
+++ b/gpu/ipc/client/command_buffer_proxy_impl.h
@@ -178,7 +178,7 @@
   void OnDestroyed(gpu::error::ContextLostReason reason,
                    gpu::error::Error error);
   void OnConsoleMessage(const GPUCommandBufferConsoleMessage& message);
-  void OnGpuSwitched();
+  void OnGpuSwitched(gl::GpuPreference active_gpu_heuristic);
   void OnSignalAck(uint32_t id, const CommandBuffer::State& state);
   void OnSwapBuffersCompleted(const SwapBuffersCompleteParams& params);
   void OnBufferPresented(uint64_t swap_id,
diff --git a/gpu/ipc/common/gpu_messages.h b/gpu/ipc/common/gpu_messages.h
index 2b8e00f1..37d9bee 100644
--- a/gpu/ipc/common/gpu_messages.h
+++ b/gpu/ipc/common/gpu_messages.h
@@ -42,6 +42,7 @@
 #include "ui/gfx/native_widget_types.h"
 #include "ui/gfx/presentation_feedback.h"
 #include "ui/gfx/swap_result.h"
+#include "ui/gl/gpu_preference.h"
 #include "url/ipc/url_param_traits.h"
 
 #if defined(OS_MACOSX)
@@ -296,7 +297,8 @@
                     GPUCommandBufferConsoleMessage /* msg */)
 
 // Sent by the GPU process to notify the renderer process of a GPU switch.
-IPC_MESSAGE_ROUTED0(GpuCommandBufferMsg_GpuSwitched)
+IPC_MESSAGE_ROUTED1(GpuCommandBufferMsg_GpuSwitched,
+                    gl::GpuPreference /* active_gpu_heuristic */)
 
 // Register an existing shared memory transfer buffer. The id that can be
 // used to identify the transfer buffer from a command buffer.
diff --git a/gpu/ipc/service/gles2_command_buffer_stub.cc b/gpu/ipc/service/gles2_command_buffer_stub.cc
index d13ef5e..34928936 100644
--- a/gpu/ipc/service/gles2_command_buffer_stub.cc
+++ b/gpu/ipc/service/gles2_command_buffer_stub.cc
@@ -432,8 +432,9 @@
   return context_group_->memory_tracker();
 }
 
-void GLES2CommandBufferStub::OnGpuSwitched() {
-  Send(new GpuCommandBufferMsg_GpuSwitched(route_id_));
+void GLES2CommandBufferStub::OnGpuSwitched(
+    gl::GpuPreference active_gpu_heuristic) {
+  Send(new GpuCommandBufferMsg_GpuSwitched(route_id_, active_gpu_heuristic));
 }
 
 bool GLES2CommandBufferStub::HandleMessage(const IPC::Message& message) {
diff --git a/gpu/ipc/service/gles2_command_buffer_stub.h b/gpu/ipc/service/gles2_command_buffer_stub.h
index 4625837..953919d 100644
--- a/gpu/ipc/service/gles2_command_buffer_stub.h
+++ b/gpu/ipc/service/gles2_command_buffer_stub.h
@@ -40,7 +40,7 @@
   MemoryTracker* GetMemoryTracker() const override;
 
   // DecoderClient implementation.
-  void OnGpuSwitched() override;
+  void OnGpuSwitched(gl::GpuPreference active_gpu_heuristic) override;
 
 // ImageTransportSurfaceDelegate implementation:
 #if defined(OS_WIN)
diff --git a/gpu/ipc/service/image_transport_surface_overlay_mac.h b/gpu/ipc/service/image_transport_surface_overlay_mac.h
index f343b7e0..f65ad035 100644
--- a/gpu/ipc/service/image_transport_surface_overlay_mac.h
+++ b/gpu/ipc/service/image_transport_surface_overlay_mac.h
@@ -82,7 +82,7 @@
   bool IsSurfaceless() const override;
 
   // ui::GpuSwitchingObserver implementation.
-  void OnGpuSwitched() override;
+  void OnGpuSwitched(gl::GpuPreference active_gpu_heuristic) override;
 
  private:
   ~ImageTransportSurfaceOverlayMacBase() override;
diff --git a/gpu/ipc/service/image_transport_surface_overlay_mac.mm b/gpu/ipc/service/image_transport_surface_overlay_mac.mm
index fa1ef9c9..c1af03a 100644
--- a/gpu/ipc/service/image_transport_surface_overlay_mac.mm
+++ b/gpu/ipc/service/image_transport_surface_overlay_mac.mm
@@ -316,7 +316,8 @@
 }
 
 template <typename BaseClass>
-void ImageTransportSurfaceOverlayMacBase<BaseClass>::OnGpuSwitched() {
+void ImageTransportSurfaceOverlayMacBase<BaseClass>::OnGpuSwitched(
+    gl::GpuPreference active_gpu_heuristic) {
   // Create a new context, and use the GL renderer ID that the new context gets.
   scoped_refptr<ui::IOSurfaceContext> context_on_new_gpu =
       ui::IOSurfaceContext::Get(ui::IOSurfaceContext::kCALayerContext);
diff --git a/ios/chrome/browser/infobars/confirm_infobar_metrics_recorder.h b/ios/chrome/browser/infobars/confirm_infobar_metrics_recorder.h
index 2abd607..84d063a 100644
--- a/ios/chrome/browser/infobars/confirm_infobar_metrics_recorder.h
+++ b/ios/chrome/browser/infobars/confirm_infobar_metrics_recorder.h
@@ -9,6 +9,12 @@
 
 #import "ios/chrome/browser/infobars/infobar_type.h"
 
+// Histogram names for InfobarConfirmTypeRestore.
+extern const char kInfobarTypeRestoreEventHistogram[];
+
+// Histogram names for ConfirmInfobarTypeBlockPopups.
+extern const char kInfobarTypeBlockPopupsEventHistogram[];
+
 // Values for the UMA Mobile.Messages.Confirm.Event histogram. These values
 // are persisted to logs. Entries should not be renumbered and numeric values
 // should never be reused.
diff --git a/ios/chrome/browser/infobars/confirm_infobar_metrics_recorder.mm b/ios/chrome/browser/infobars/confirm_infobar_metrics_recorder.mm
index 7db2a09..b02bd6a 100644
--- a/ios/chrome/browser/infobars/confirm_infobar_metrics_recorder.mm
+++ b/ios/chrome/browser/infobars/confirm_infobar_metrics_recorder.mm
@@ -10,11 +10,11 @@
 #error "This file requires ARC support."
 #endif
 
-namespace {
-// Histogram names for InfobarConfirmTypeRestore.
 const char kInfobarTypeRestoreEventHistogram[] =
     "Mobile.Messages.Confirm.Event.ConfirmInfobarTypeRestore";
-}  // namespace
+
+const char kInfobarTypeBlockPopupsEventHistogram[] =
+    "Mobile.Messages.Confirm.Event.ConfirmInfobarTypeBlockPopups";
 
 @implementation ConfirmInfobarMetricsRecorder
 
@@ -24,6 +24,9 @@
     case InfobarConfirmType::kInfobarConfirmTypeRestore:
       UMA_HISTOGRAM_ENUMERATION(kInfobarTypeRestoreEventHistogram, event);
       break;
+    case InfobarConfirmType::kInfobarConfirmTypeBlockPopups:
+      UMA_HISTOGRAM_ENUMERATION(kInfobarTypeBlockPopupsEventHistogram, event);
+      break;
   }
 }
 
diff --git a/ios/chrome/browser/infobars/infobar_type.h b/ios/chrome/browser/infobars/infobar_type.h
index 6edda28..5273c55 100644
--- a/ios/chrome/browser/infobars/infobar_type.h
+++ b/ios/chrome/browser/infobars/infobar_type.h
@@ -27,6 +27,8 @@
 enum class InfobarConfirmType {
   // Confirm Infobar for enabling to "Restore Tabs" after a crash.
   kInfobarConfirmTypeRestore = 0,
+  // Confirm Infobar for blocking popups.
+  kInfobarConfirmTypeBlockPopups = 1,
 };
 
 #endif  // IOS_CHROME_BROWSER_INFOBARS_INFOBAR_TYPE_H_
diff --git a/ios/chrome/browser/web/BUILD.gn b/ios/chrome/browser/web/BUILD.gn
index 3f1b4883..bb7cd64 100644
--- a/ios/chrome/browser/web/BUILD.gn
+++ b/ios/chrome/browser/web/BUILD.gn
@@ -234,6 +234,7 @@
     "//ios/chrome/browser/browser_state",
     "//ios/chrome/browser/content_settings",
     "//ios/chrome/browser/infobars",
+    "//ios/chrome/browser/infobars:public",
     "//ios/chrome/browser/passwords",
     "//ios/chrome/browser/reading_list",
     "//ios/chrome/browser/ssl",
@@ -297,6 +298,7 @@
     "//ios/chrome/browser/content_settings:content_settings",
     "//ios/chrome/browser/find_in_page",
     "//ios/chrome/browser/infobars",
+    "//ios/chrome/browser/infobars:public",
     "//ios/chrome/browser/passwords",
     "//ios/chrome/browser/web",
     "//ios/chrome/test/fakes",
diff --git a/ios/chrome/browser/web/blocked_popup_tab_helper.mm b/ios/chrome/browser/web/blocked_popup_tab_helper.mm
index c2e770a..3f19a86 100644
--- a/ios/chrome/browser/web/blocked_popup_tab_helper.mm
+++ b/ios/chrome/browser/web/blocked_popup_tab_helper.mm
@@ -19,6 +19,7 @@
 #include "components/infobars/core/infobar.h"
 #include "ios/chrome/browser/browser_state/chrome_browser_state.h"
 #include "ios/chrome/browser/content_settings/host_content_settings_map_factory.h"
+#include "ios/chrome/browser/infobars/confirm_infobar_metrics_recorder.h"
 #include "ios/chrome/browser/infobars/infobar_manager_impl.h"
 #include "ios/chrome/grit/ios_strings.h"
 #include "ios/web/public/navigation/referrer.h"
@@ -65,6 +66,10 @@
   }
 
   bool Accept() override {
+    [ConfirmInfobarMetricsRecorder
+        recordConfirmInfobarEvent:MobileMessagesConfirmInfobarEvents::Accepted
+            forInfobarConfirmType:InfobarConfirmType::
+                                      kInfobarConfirmTypeBlockPopups];
     scoped_refptr<HostContentSettingsMap> host_content_map_settings(
         ios::HostContentSettingsMapFactory::GetForBrowserState(browser_state_));
     for (auto& popup : popups_) {
@@ -80,6 +85,13 @@
     return true;
   }
 
+  void InfoBarDismissed() override {
+    [ConfirmInfobarMetricsRecorder
+        recordConfirmInfobarEvent:MobileMessagesConfirmInfobarEvents::Dismissed
+            forInfobarConfirmType:InfobarConfirmType::
+                                      kInfobarConfirmTypeBlockPopups];
+  }
+
   int GetButtons() const override { return BUTTON_OK; }
 
  private:
@@ -144,6 +156,10 @@
   } else {
     infobar_ = infobar_manager->AddInfoBar(std::move(infobar));
   }
+  [ConfirmInfobarMetricsRecorder
+      recordConfirmInfobarEvent:MobileMessagesConfirmInfobarEvents::Presented
+          forInfobarConfirmType:InfobarConfirmType::
+                                    kInfobarConfirmTypeBlockPopups];
 }
 
 ios::ChromeBrowserState* BlockedPopupTabHelper::GetBrowserState() const {
diff --git a/ios/chrome/browser/web/blocked_popup_tab_helper_unittest.mm b/ios/chrome/browser/web/blocked_popup_tab_helper_unittest.mm
index 5da71578..315f123 100644
--- a/ios/chrome/browser/web/blocked_popup_tab_helper_unittest.mm
+++ b/ios/chrome/browser/web/blocked_popup_tab_helper_unittest.mm
@@ -5,12 +5,14 @@
 #import "ios/chrome/browser/web/blocked_popup_tab_helper.h"
 
 #include "base/memory/ptr_util.h"
+#include "base/test/metrics/histogram_tester.h"
 #include "components/content_settings/core/browser/host_content_settings_map.h"
 #include "components/infobars/core/confirm_infobar_delegate.h"
 #include "components/infobars/core/infobar.h"
 #include "components/infobars/core/infobar_manager.h"
 #include "ios/chrome/browser/browser_state/test_chrome_browser_state.h"
 #include "ios/chrome/browser/content_settings/host_content_settings_map_factory.h"
+#include "ios/chrome/browser/infobars/confirm_infobar_metrics_recorder.h"
 #include "ios/chrome/browser/infobars/infobar_manager_impl.h"
 #import "ios/chrome/browser/web/chrome_web_test.h"
 #import "ios/web/public/test/fakes/test_navigation_manager.h"
@@ -150,3 +152,55 @@
   EXPECT_EQ(0U, GetInfobarManager()->infobar_count());
   EXPECT_FALSE(IsObservingSources());
 }
+
+// Tests that the Infobar presentation and dismissal histograms are recorded
+// correctly.
+TEST_F(BlockedPopupTabHelperTest, RecordDismissMetrics) {
+  base::HistogramTester histogram_tester;
+
+  // Call |HandlePopup| to show an infobar and check that the Presented
+  // histogram was recorded correctly.
+  const GURL test_url("https://popups.example.com");
+  GetBlockedPopupTabHelper()->HandlePopup(test_url, web::Referrer());
+  ASSERT_EQ(1U, GetInfobarManager()->infobar_count());
+  histogram_tester.ExpectUniqueSample(
+      "Mobile.Messages.Confirm.Event.ConfirmInfobarTypeBlockPopups",
+      static_cast<base::HistogramBase::Sample>(
+          MobileMessagesConfirmInfobarEvents::Presented),
+      1);
+
+  // Dismiss the infobar and check that the Dismiss histogram was recorded
+  // correctly.
+  GetInfobarManager()->infobar_at(0)->delegate()->InfoBarDismissed();
+  histogram_tester.ExpectBucketCount(
+      kInfobarTypeBlockPopupsEventHistogram,
+      static_cast<base::HistogramBase::Sample>(
+          MobileMessagesConfirmInfobarEvents::Dismissed),
+      1);
+}
+
+// Tests that the Infobar accept histogram is recorded correctly.
+TEST_F(BlockedPopupTabHelperTest, RecordAcceptMetrics) {
+  base::HistogramTester histogram_tester;
+  const GURL source_url("https://source-url");
+  ASSERT_TRUE(GetBlockedPopupTabHelper()->ShouldBlockPopup(source_url));
+
+  // Block popup.
+  const GURL target_url("https://target-url");
+  web::Referrer referrer(source_url, web::ReferrerPolicyDefault);
+  GetBlockedPopupTabHelper()->HandlePopup(target_url, referrer);
+
+  // Accept the infobar and check that the Accepted histogram was recorded
+  // correctly.
+  ASSERT_EQ(1U, GetInfobarManager()->infobar_count());
+  auto* delegate = GetInfobarManager()
+                       ->infobar_at(0)
+                       ->delegate()
+                       ->AsConfirmInfoBarDelegate();
+  delegate->Accept();
+  histogram_tester.ExpectBucketCount(
+      kInfobarTypeBlockPopupsEventHistogram,
+      static_cast<base::HistogramBase::Sample>(
+          MobileMessagesConfirmInfobarEvents::Accepted),
+      1);
+}
diff --git a/media/filters/fuchsia/fuchsia_video_decoder.cc b/media/filters/fuchsia/fuchsia_video_decoder.cc
index 870ef425..60fa9e72 100644
--- a/media/filters/fuchsia/fuchsia_video_decoder.cc
+++ b/media/filters/fuchsia/fuchsia_video_decoder.cc
@@ -96,11 +96,16 @@
     mailboxes[0].mailbox = mailbox_;
     mailboxes[0].sync_token = shared_image_interface_->GenUnverifiedSyncToken();
 
-    return VideoFrame::WrapNativeTextures(
+    auto frame = VideoFrame::WrapNativeTextures(
         pixel_format, mailboxes,
         BindToCurrentLoop(base::BindOnce(&OutputMailbox::OnFrameDestroyed,
                                          base::Unretained(this))),
         coded_size, visible_rect, natural_size, timestamp);
+
+    // Request a fence we'll wait on before reusing the buffer.
+    frame->metadata()->SetBoolean(VideoFrameMetadata::READ_LOCK_FENCES_ENABLED,
+                                  true);
+    return frame;
   }
 
   // Called by FuchsiaVideoDecoder when it no longer needs this mailbox.
diff --git a/media/gpu/test/video_decode_accelerator_unittest_helpers.cc b/media/gpu/test/video_decode_accelerator_unittest_helpers.cc
index 3253c8ae..e1f1cdc 100644
--- a/media/gpu/test/video_decode_accelerator_unittest_helpers.cc
+++ b/media/gpu/test/video_decode_accelerator_unittest_helpers.cc
@@ -73,7 +73,10 @@
   size_t pos = start_pos;
   if (pos + 4 > data_.size())
     return pos;
-  LOG_ASSERT(IsNALHeader(data_, pos));
+  if (!IsNALHeader(data_, pos)) {
+    ADD_FAILURE();
+    return std::numeric_limits<std::size_t>::max();
+  }
   pos += 4;
   while (pos + 4 <= data_.size() && !IsNALHeader(data_, pos)) {
     ++pos;
diff --git a/media/gpu/test/video_frame_file_writer.cc b/media/gpu/test/video_frame_file_writer.cc
index a88ddb43..5e46a79 100644
--- a/media/gpu/test/video_frame_file_writer.cc
+++ b/media/gpu/test/video_frame_file_writer.cc
@@ -14,6 +14,7 @@
 #include "build/build_config.h"
 #include "media/gpu/video_frame_mapper.h"
 #include "media/gpu/video_frame_mapper_factory.h"
+#include "testing/gtest/include/gtest/gtest.h"
 #include "ui/gfx/codec/png_codec.h"
 
 namespace media {
@@ -127,7 +128,7 @@
       !video_frame_mapper_) {
     video_frame_mapper_ = VideoFrameMapperFactory::CreateMapper(
         video_frame->format(), video_frame->storage_type());
-    LOG_ASSERT(video_frame_mapper_) << "Failed to create VideoFrameMapper";
+    ASSERT_TRUE(video_frame_mapper_) << "Failed to create VideoFrameMapper";
   }
 #endif
 
@@ -180,7 +181,7 @@
       argb_out_frame->stride(VideoFrame::kARGBPlane),
       true, /* discard_transparency */
       std::vector<gfx::PNGCodec::Comment>(), &png_output);
-  LOG_ASSERT(png_encode_status);
+  ASSERT_TRUE(png_encode_status);
 
   // Write the PNG data to file.
   base::FilePath file_path(
@@ -188,7 +189,7 @@
   const int size = base::checked_cast<int>(png_output.size());
   const int bytes_written = base::WriteFile(
       file_path, reinterpret_cast<char*>(png_output.data()), size);
-  LOG_ASSERT(bytes_written == size);
+  ASSERT_TRUE(bytes_written == size);
 }
 
 void VideoFrameFileWriter::WriteVideoFrameYUV(
@@ -235,7 +236,7 @@
         VideoFrame::Rows(i, pixel_format, visible_size.height());
     const int row_bytes =
         VideoFrame::RowBytes(i, pixel_format, visible_size.width());
-    LOG_ASSERT(stride > 0);
+    ASSERT_TRUE(stride > 0);
     for (size_t row = 0; row < rows; ++row) {
       if (yuv_file.WriteAtCurrentPos(
               reinterpret_cast<const char*>(data + (stride * row)),
diff --git a/media/gpu/test/video_player/test_vda_video_decoder.cc b/media/gpu/test/video_player/test_vda_video_decoder.cc
index fc65575..99cf150 100644
--- a/media/gpu/test/video_player/test_vda_video_decoder.cc
+++ b/media/gpu/test/video_player/test_vda_video_decoder.cc
@@ -107,7 +107,7 @@
   }
 
   if (!decoder_factory) {
-    LOG_ASSERT(decoder_) << "Failed to create VideoDecodeAccelerator factory";
+    ASSERT_TRUE(decoder_) << "Failed to create VideoDecodeAccelerator factory";
     std::move(init_cb).Run(false);
     return;
   }
@@ -128,7 +128,7 @@
       this, vda_config, gpu_driver_bug_workarounds, gpu_preferences);
 
   if (!decoder_) {
-    LOG_ASSERT(decoder_) << "Failed to create VideoDecodeAccelerator factory";
+    ASSERT_TRUE(decoder_) << "Failed to create VideoDecodeAccelerator factory";
     std::move(init_cb).Run(false);
     return;
   }
@@ -229,7 +229,7 @@
             gfx::BufferUsage::SCANOUT_VDA_WRITE);
 #endif  // BUILDFLAG(USE_CHROMEOS_MEDIA_ACCELERATION)
 
-        LOG_ASSERT(video_frame) << "Failed to create video frame";
+        ASSERT_TRUE(video_frame) << "Failed to create video frame";
         video_frames_.emplace(picture_buffer.id(), video_frame);
         gfx::GpuMemoryBufferHandle handle;
 
@@ -240,7 +240,7 @@
         NOTREACHED();
 #endif  // BUILDFLAG(USE_CHROMEOS_MEDIA_ACCELERATION)
 
-        LOG_ASSERT(!handle.is_null()) << "Failed to create GPU memory handle";
+        ASSERT_TRUE(!handle.is_null()) << "Failed to create GPU memory handle";
         decoder_->ImportBufferForPicture(picture_buffer.id(), format,
                                          std::move(handle));
       }
@@ -252,7 +252,7 @@
         uint32_t texture_id;
         auto video_frame = frame_renderer_->CreateVideoFrame(
             format, dimensions, texture_target, &texture_id);
-        LOG_ASSERT(video_frame) << "Failed to create video frame";
+        ASSERT_TRUE(video_frame) << "Failed to create video frame";
         int32_t picture_buffer_id = GetNextPictureBufferId();
         PictureBuffer::TextureIds texture_ids(1, texture_id);
         picture_buffers.emplace_back(picture_buffer_id, dimensions, texture_ids,
@@ -282,7 +282,7 @@
   DVLOGF(4) << "Picture buffer ID: " << picture.picture_buffer_id();
 
   auto it = video_frames_.find(picture.picture_buffer_id());
-  LOG_ASSERT(it != video_frames_.end());
+  ASSERT_TRUE(it != video_frames_.end());
   scoped_refptr<VideoFrame> video_frame = it->second;
 
   // Look up the time at which the decode started.
@@ -359,7 +359,7 @@
   DCHECK_CALLED_ON_VALID_SEQUENCE(vda_wrapper_sequence_checker_);
 
   auto it = decode_cbs_.find(bitstream_buffer_id);
-  LOG_ASSERT(it != decode_cbs_.end())
+  ASSERT_TRUE(it != decode_cbs_.end())
       << "Couldn't find decode callback for picture buffer with id "
       << bitstream_buffer_id;
 
diff --git a/media/gpu/test/video_test_environment.cc b/media/gpu/test/video_test_environment.cc
index 773f51c..1533829 100644
--- a/media/gpu/test/video_test_environment.cc
+++ b/media/gpu/test/video_test_environment.cc
@@ -32,7 +32,8 @@
   logging::LoggingSettings settings;
   settings.logging_dest =
       logging::LOG_TO_SYSTEM_DEBUG_LOG | logging::LOG_TO_STDERR;
-  LOG_ASSERT(logging::InitLogging(settings));
+  if (!logging::InitLogging(settings))
+    ADD_FAILURE();
 
   // Setting up a task environment will create a task runner for the current
   // thread and allow posting tasks to other threads. This is required for video
diff --git a/mojo/public/cpp/bindings/README.md b/mojo/public/cpp/bindings/README.md
index 9403a416..19cbf66 100644
--- a/mojo/public/cpp/bindings/README.md
+++ b/mojo/public/cpp/bindings/README.md
@@ -384,7 +384,7 @@
 
 Regardless of the underlying cause, when a connection error is encountered on
 a receiver endpoint, that endpoint's **disconnect handler** (if set) is
-invoked. This handler is a simple `base::Closure` and may only be invoked
+invoked. This handler is a simple `base::OnceClosure` and may only be invoked
 *once* as long as the endpoint is bound to the same pipe. Typically clients and
 implementations use this handler to do some kind of cleanup or -- particuarly if
 the error was unexpected -- create a new pipe and attempt to establish a new
@@ -1733,7 +1733,7 @@
 version:
 
 ```cpp
-void QueryVersion(const base::Callback<void(uint32_t)>& callback);
+void QueryVersion(base::OnceCallback<void(uint32_t)> callback);
 ```
 
 This queries the remote endpoint for the version number of its binding. When a
diff --git a/mojo/public/cpp/bindings/associated_group.h b/mojo/public/cpp/bindings/associated_group.h
index 1a31f904..bae09eed 100644
--- a/mojo/public/cpp/bindings/associated_group.h
+++ b/mojo/public/cpp/bindings/associated_group.h
@@ -42,7 +42,7 @@
   AssociatedGroupController* GetController();
 
  private:
-  base::Callback<AssociatedGroupController*()> controller_getter_;
+  base::RepeatingCallback<AssociatedGroupController*()> controller_getter_;
   scoped_refptr<AssociatedGroupController> controller_;
 };
 
diff --git a/mojo/public/cpp/bindings/associated_interface_ptr.h b/mojo/public/cpp/bindings/associated_interface_ptr.h
index ab77a77f..95def73 100644
--- a/mojo/public/cpp/bindings/associated_interface_ptr.h
+++ b/mojo/public/cpp/bindings/associated_interface_ptr.h
@@ -95,8 +95,8 @@
   // Queries the max version that the remote side supports. On completion, the
   // result will be returned as the input of |callback|. The version number of
   // this object will also be updated.
-  void QueryVersion(const base::Callback<void(uint32_t)>& callback) {
-    internal_state_.QueryVersion(callback);
+  void QueryVersion(base::OnceCallback<void(uint32_t)> callback) {
+    internal_state_.QueryVersion(std::move(callback));
   }
 
   // If the remote side doesn't support the specified version, it will close the
diff --git a/mojo/public/cpp/bindings/interface_ptr.h b/mojo/public/cpp/bindings/interface_ptr.h
index af383ed1..9032c2c 100644
--- a/mojo/public/cpp/bindings/interface_ptr.h
+++ b/mojo/public/cpp/bindings/interface_ptr.h
@@ -111,8 +111,8 @@
   // Queries the max version that the remote side supports. On completion, the
   // result will be returned as the input of |callback|. The version number of
   // this interface pointer will also be updated.
-  void QueryVersion(const base::Callback<void(uint32_t)>& callback) {
-    internal_state_.QueryVersionDeprecated(callback);
+  void QueryVersion(base::OnceCallback<void(uint32_t)> callback) {
+    internal_state_.QueryVersion(std::move(callback));
   }
 
   // If the remote side doesn't support the specified version, it will close its
diff --git a/mojo/public/cpp/bindings/interface_ptr_set.h b/mojo/public/cpp/bindings/interface_ptr_set.h
index c782e15..616f594a 100644
--- a/mojo/public/cpp/bindings/interface_ptr_set.h
+++ b/mojo/public/cpp/bindings/interface_ptr_set.h
@@ -90,7 +90,7 @@
   class Element {
    public:
     explicit Element(Ptr<Interface> ptr) : ptr_(std::move(ptr)) {
-      ptr_.set_connection_error_handler(base::Bind(&DeleteElement, this));
+      ptr_.set_connection_error_handler(base::BindOnce(&DeleteElement, this));
     }
 
     ~Element() {}
diff --git a/mojo/public/cpp/bindings/lib/associated_interface_ptr_state.cc b/mojo/public/cpp/bindings/lib/associated_interface_ptr_state.cc
index fa8c7d0..6f6d4abc 100644
--- a/mojo/public/cpp/bindings/lib/associated_interface_ptr_state.cc
+++ b/mojo/public/cpp/bindings/lib/associated_interface_ptr_state.cc
@@ -14,12 +14,12 @@
 AssociatedInterfacePtrStateBase::~AssociatedInterfacePtrStateBase() = default;
 
 void AssociatedInterfacePtrStateBase::QueryVersion(
-    const base::Callback<void(uint32_t)>& callback) {
+    base::OnceCallback<void(uint32_t)> callback) {
   // It is safe to capture |this| because the callback won't be run after this
   // object goes away.
   endpoint_client_->QueryVersion(
-      base::Bind(&AssociatedInterfacePtrStateBase::OnQueryVersion,
-                 base::Unretained(this), callback));
+      base::BindOnce(&AssociatedInterfacePtrStateBase::OnQueryVersion,
+                     base::Unretained(this), std::move(callback)));
 }
 
 void AssociatedInterfacePtrStateBase::RequireVersion(uint32_t version) {
@@ -31,10 +31,10 @@
 }
 
 void AssociatedInterfacePtrStateBase::OnQueryVersion(
-    const base::Callback<void(uint32_t)>& callback,
+    base::OnceCallback<void(uint32_t)> callback,
     uint32_t version) {
   version_ = version;
-  callback.Run(version);
+  std::move(callback).Run(version);
 }
 
 void AssociatedInterfacePtrStateBase::FlushForTesting() {
diff --git a/mojo/public/cpp/bindings/lib/associated_interface_ptr_state.h b/mojo/public/cpp/bindings/lib/associated_interface_ptr_state.h
index f8dea18..23fc89f 100644
--- a/mojo/public/cpp/bindings/lib/associated_interface_ptr_state.h
+++ b/mojo/public/cpp/bindings/lib/associated_interface_ptr_state.h
@@ -37,7 +37,7 @@
 
   uint32_t version() const { return version_; }
 
-  void QueryVersion(const base::Callback<void(uint32_t)>& callback);
+  void QueryVersion(base::OnceCallback<void(uint32_t)> callback);
   void RequireVersion(uint32_t version);
   void FlushForTesting();
   void CloseWithReason(uint32_t custom_reason, const std::string& description);
@@ -93,7 +93,7 @@
   InterfaceEndpointClient* endpoint_client() { return endpoint_client_.get(); }
 
  private:
-  void OnQueryVersion(const base::Callback<void(uint32_t)>& callback,
+  void OnQueryVersion(base::OnceCallback<void(uint32_t)> callback,
                       uint32_t version);
 
   std::unique_ptr<InterfaceEndpointClient> endpoint_client_;
diff --git a/mojo/public/cpp/bindings/lib/connector.cc b/mojo/public/cpp/bindings/lib/connector.cc
index f29ee91..5f77d2d 100644
--- a/mojo/public/cpp/bindings/lib/connector.cc
+++ b/mojo/public/cpp/bindings/lib/connector.cc
@@ -520,7 +520,8 @@
   handle_watcher_->set_heap_profiler_tag(heap_profiler_tag_);
   MojoResult rv = handle_watcher_->Watch(
       message_pipe_.get(), MOJO_HANDLE_SIGNAL_READABLE,
-      base::Bind(&Connector::OnWatcherHandleReady, base::Unretained(this)));
+      base::BindRepeating(&Connector::OnWatcherHandleReady,
+                          base::Unretained(this)));
 
   if (message_pipe_.is_valid()) {
     peer_remoteness_tracker_.emplace(
diff --git a/mojo/public/cpp/bindings/lib/interface_endpoint_client.cc b/mojo/public/cpp/bindings/lib/interface_endpoint_client.cc
index f4bb42d..ad1d872 100644
--- a/mojo/public/cpp/bindings/lib/interface_endpoint_client.cc
+++ b/mojo/public/cpp/bindings/lib/interface_endpoint_client.cc
@@ -165,7 +165,7 @@
     dispatcher_.SetValidator(std::move(payload_validator));
 
   if (handle_.pending_association()) {
-    handle_.SetAssociationEventHandler(base::Bind(
+    handle_.SetAssociationEventHandler(base::BindOnce(
         &InterfaceEndpointClient::OnAssociationEvent, base::Unretained(this)));
   } else {
     InitControllerIfNecessary();
diff --git a/mojo/public/cpp/bindings/lib/interface_ptr_state.h b/mojo/public/cpp/bindings/lib/interface_ptr_state.h
index 31b71f83..f3f64fe 100644
--- a/mojo/public/cpp/bindings/lib/interface_ptr_state.h
+++ b/mojo/public/cpp/bindings/lib/interface_ptr_state.h
@@ -136,10 +136,6 @@
 #endif
   }
 
-  void QueryVersionDeprecated(const base::Callback<void(uint32_t)>& callback) {
-    QueryVersion(base::BindOnce(callback));
-  }
-
   void QueryVersion(base::OnceCallback<void(uint32_t)> callback) {
     ConfigureProxyIfNecessary();
     InterfacePtrStateBase::QueryVersion(std::move(callback));
diff --git a/mojo/public/cpp/bindings/lib/scoped_interface_endpoint_handle.cc b/mojo/public/cpp/bindings/lib/scoped_interface_endpoint_handle.cc
index 9ccae37b22..bcddf8b 100644
--- a/mojo/public/cpp/bindings/lib/scoped_interface_endpoint_handle.cc
+++ b/mojo/public/cpp/bindings/lib/scoped_interface_endpoint_handle.cc
@@ -372,12 +372,12 @@
   state_.swap(new_state);
 }
 
-base::Callback<AssociatedGroupController*()>
+base::RepeatingCallback<AssociatedGroupController*()>
 ScopedInterfaceEndpointHandle::CreateGroupControllerGetter() const {
   // We allow this callback to be run on any sequence. If this handle is created
   // in non-pending state, we don't have a lock but it should still be safe
   // because the group controller never changes.
-  return base::Bind(&State::group_controller, state_);
+  return base::BindRepeating(&State::group_controller, state_);
 }
 
 }  // namespace mojo
diff --git a/mojo/public/cpp/bindings/lib/sync_event_watcher.cc b/mojo/public/cpp/bindings/lib/sync_event_watcher.cc
index 1716591..98ccf45 100644
--- a/mojo/public/cpp/bindings/lib/sync_event_watcher.cc
+++ b/mojo/public/cpp/bindings/lib/sync_event_watcher.cc
@@ -12,9 +12,9 @@
 namespace mojo {
 
 SyncEventWatcher::SyncEventWatcher(base::WaitableEvent* event,
-                                   const base::Closure& callback)
+                                   base::RepeatingClosure callback)
     : event_(event),
-      callback_(callback),
+      callback_(std::move(callback)),
       registry_(SyncHandleRegistry::current()),
       destroyed_(new base::RefCountedData<bool>(false)) {}
 
diff --git a/mojo/public/cpp/bindings/lib/sync_handle_registry.cc b/mojo/public/cpp/bindings/lib/sync_handle_registry.cc
index b91d5f9..5a349aa 100644
--- a/mojo/public/cpp/bindings/lib/sync_handle_registry.cc
+++ b/mojo/public/cpp/bindings/lib/sync_handle_registry.cc
@@ -33,7 +33,7 @@
 
 bool SyncHandleRegistry::RegisterHandle(const Handle& handle,
                                         MojoHandleSignals handle_signals,
-                                        const HandleCallback& callback) {
+                                        HandleCallback callback) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
 
   if (base::Contains(handles_, handle))
@@ -43,7 +43,7 @@
   if (result != MOJO_RESULT_OK)
     return false;
 
-  handles_[handle] = callback;
+  handles_[handle] = std::move(callback);
   return true;
 }
 
@@ -58,7 +58,7 @@
 }
 
 void SyncHandleRegistry::RegisterEvent(base::WaitableEvent* event,
-                                       const base::Closure& callback) {
+                                       base::RepeatingClosure callback) {
   auto it = events_.find(event);
   if (it == events_.end()) {
     auto result = events_.emplace(event, EventCallbackList{});
@@ -70,11 +70,11 @@
   // callbacks to see if any are valid.
   wait_set_.AddEvent(event);
 
-  it->second.container().push_back(callback);
+  it->second.container().push_back(std::move(callback));
 }
 
 void SyncHandleRegistry::UnregisterEvent(base::WaitableEvent* event,
-                                         const base::Closure& callback) {
+                                         base::RepeatingClosure callback) {
   auto it = events_.find(event);
   if (it == events_.end())
     return;
@@ -174,10 +174,11 @@
 void SyncHandleRegistry::RemoveInvalidEventCallbacks() {
   for (auto it = events_.begin(); it != events_.end();) {
     auto& callbacks = it->second.container();
-    callbacks.erase(
-        std::remove_if(callbacks.begin(), callbacks.end(),
-                       [](const base::Closure& callback) { return !callback; }),
-        callbacks.end());
+    callbacks.erase(std::remove_if(callbacks.begin(), callbacks.end(),
+                                   [](const base::RepeatingClosure& callback) {
+                                     return !callback;
+                                   }),
+                    callbacks.end());
     if (callbacks.empty())
       events_.erase(it++);
     else
diff --git a/mojo/public/cpp/bindings/lib/validation_errors.cc b/mojo/public/cpp/bindings/lib/validation_errors.cc
index 472e8661..477eb35 100644
--- a/mojo/public/cpp/bindings/lib/validation_errors.cc
+++ b/mojo/public/cpp/bindings/lib/validation_errors.cc
@@ -119,8 +119,8 @@
 }
 
 ValidationErrorObserverForTesting::ValidationErrorObserverForTesting(
-    const base::Closure& callback)
-    : last_error_(VALIDATION_ERROR_NONE), callback_(callback) {
+    base::RepeatingClosure callback)
+    : last_error_(VALIDATION_ERROR_NONE), callback_(std::move(callback)) {
   DCHECK(!g_validation_error_observer);
   g_validation_error_observer = this;
 }
diff --git a/mojo/public/cpp/bindings/lib/validation_errors.h b/mojo/public/cpp/bindings/lib/validation_errors.h
index ddb9872..d8916aca 100644
--- a/mojo/public/cpp/bindings/lib/validation_errors.h
+++ b/mojo/public/cpp/bindings/lib/validation_errors.h
@@ -111,7 +111,7 @@
 class COMPONENT_EXPORT(MOJO_CPP_BINDINGS_BASE)
     ValidationErrorObserverForTesting {
  public:
-  explicit ValidationErrorObserverForTesting(const base::Closure& callback);
+  explicit ValidationErrorObserverForTesting(base::RepeatingClosure callback);
   ~ValidationErrorObserverForTesting();
 
   ValidationError last_error() const { return last_error_; }
@@ -122,7 +122,7 @@
 
  private:
   ValidationError last_error_;
-  base::Closure callback_;
+  base::RepeatingClosure callback_;
 
   DISALLOW_COPY_AND_ASSIGN(ValidationErrorObserverForTesting);
 };
diff --git a/mojo/public/cpp/bindings/scoped_interface_endpoint_handle.h b/mojo/public/cpp/bindings/scoped_interface_endpoint_handle.h
index 6b77758..aa406f9 100644
--- a/mojo/public/cpp/bindings/scoped_interface_endpoint_handle.h
+++ b/mojo/public/cpp/bindings/scoped_interface_endpoint_handle.h
@@ -109,8 +109,8 @@
   //     asssociation, the return value of the getter will initially be null,
   //     change to non-null when the handle is associated, and remain unchanged
   //     ever since.
-  base::Callback<AssociatedGroupController*()> CreateGroupControllerGetter()
-      const;
+  base::RepeatingCallback<AssociatedGroupController*()>
+  CreateGroupControllerGetter() const;
 
   scoped_refptr<State> state_;
 
diff --git a/mojo/public/cpp/bindings/strong_associated_binding.h b/mojo/public/cpp/bindings/strong_associated_binding.h
index f734772..9c552ee 100644
--- a/mojo/public/cpp/bindings/strong_associated_binding.h
+++ b/mojo/public/cpp/bindings/strong_associated_binding.h
@@ -97,7 +97,7 @@
                           scoped_refptr<base::SequencedTaskRunner> task_runner)
       : impl_(std::move(impl)),
         binding_(impl_.get(), std::move(request), std::move(task_runner)) {
-    binding_.set_connection_error_with_reason_handler(base::Bind(
+    binding_.set_connection_error_with_reason_handler(base::BindOnce(
         &StrongAssociatedBinding::OnConnectionError, base::Unretained(this)));
   }
 
diff --git a/mojo/public/cpp/bindings/strong_binding.h b/mojo/public/cpp/bindings/strong_binding.h
index d9ebbb80..315ad0f0 100644
--- a/mojo/public/cpp/bindings/strong_binding.h
+++ b/mojo/public/cpp/bindings/strong_binding.h
@@ -104,8 +104,8 @@
                 scoped_refptr<base::SequencedTaskRunner> task_runner)
       : impl_(std::move(impl)),
         binding_(impl_.get(), std::move(request), std::move(task_runner)) {
-    binding_.set_connection_error_with_reason_handler(
-        base::Bind(&StrongBinding::OnConnectionError, base::Unretained(this)));
+    binding_.set_connection_error_with_reason_handler(base::BindOnce(
+        &StrongBinding::OnConnectionError, base::Unretained(this)));
   }
 
   ~StrongBinding() {}
diff --git a/mojo/public/cpp/bindings/sync_event_watcher.h b/mojo/public/cpp/bindings/sync_event_watcher.h
index 2f33681..139c383 100644
--- a/mojo/public/cpp/bindings/sync_event_watcher.h
+++ b/mojo/public/cpp/bindings/sync_event_watcher.h
@@ -24,7 +24,7 @@
 // This class is not thread safe.
 class COMPONENT_EXPORT(MOJO_CPP_BINDINGS) SyncEventWatcher {
  public:
-  SyncEventWatcher(base::WaitableEvent* event, const base::Closure& callback);
+  SyncEventWatcher(base::WaitableEvent* event, base::RepeatingClosure callback);
 
   ~SyncEventWatcher();
 
@@ -51,7 +51,7 @@
   void DecrementRegisterCount();
 
   base::WaitableEvent* const event_;
-  const base::Closure callback_;
+  const base::RepeatingClosure callback_;
 
   // Whether |event_| has been registered with SyncHandleRegistry.
   bool registered_ = false;
diff --git a/mojo/public/cpp/bindings/sync_handle_registry.h b/mojo/public/cpp/bindings/sync_handle_registry.h
index b3daf8e..f3dc89c 100644
--- a/mojo/public/cpp/bindings/sync_handle_registry.h
+++ b/mojo/public/cpp/bindings/sync_handle_registry.h
@@ -29,14 +29,14 @@
   // Returns a sequence-local object.
   static scoped_refptr<SyncHandleRegistry> current();
 
-  using HandleCallback = base::Callback<void(MojoResult)>;
+  using HandleCallback = base::RepeatingCallback<void(MojoResult)>;
 
   // Registers a |Handle| to be watched for |handle_signals|. If any such
   // signals are satisfied during a Wait(), the Wait() is woken up and
   // |callback| is run.
   bool RegisterHandle(const Handle& handle,
                       MojoHandleSignals handle_signals,
-                      const HandleCallback& callback);
+                      HandleCallback callback);
 
   void UnregisterHandle(const Handle& handle);
 
@@ -44,11 +44,12 @@
   // Wait() before any handle signals. |event| is not owned, and if it signals
   // during Wait(), |callback| is invoked.  Note that |event| may be registered
   // multiple times with different callbacks.
-  void RegisterEvent(base::WaitableEvent* event, const base::Closure& callback);
+  void RegisterEvent(base::WaitableEvent* event,
+                     base::RepeatingClosure callback);
 
   // Unregisters a specific |event|+|callback| pair.
   void UnregisterEvent(base::WaitableEvent* event,
-                       const base::Closure& callback);
+                       base::RepeatingClosure callback);
 
   // Waits on all the registered handles and events and runs callbacks
   // synchronously for any that become ready.
@@ -60,7 +61,7 @@
  private:
   friend class base::RefCounted<SyncHandleRegistry>;
 
-  using EventCallbackList = base::StackVector<base::Closure, 1>;
+  using EventCallbackList = base::StackVector<base::RepeatingClosure, 1>;
   using EventMap = std::map<base::WaitableEvent*, EventCallbackList>;
 
   SyncHandleRegistry();
diff --git a/mojo/public/cpp/bindings/tests/associated_interface_unittest.cc b/mojo/public/cpp/bindings/tests/associated_interface_unittest.cc
index 864a9da..227bf227 100644
--- a/mojo/public/cpp/bindings/tests/associated_interface_unittest.cc
+++ b/mojo/public/cpp/bindings/tests/associated_interface_unittest.cc
@@ -267,11 +267,11 @@
     CHECK(task_runner()->RunsTasksInCurrentSequence());
 
     impl0_.reset(new IntegerSenderImpl(std::move(receiver0)));
-    impl0_->set_notify_send_method_called(
-        base::Bind(&TestReceiver::SendMethodCalled, base::Unretained(this)));
+    impl0_->set_notify_send_method_called(base::BindRepeating(
+        &TestReceiver::SendMethodCalled, base::Unretained(this)));
     impl1_.reset(new IntegerSenderImpl(std::move(receiver1)));
-    impl1_->set_notify_send_method_called(
-        base::Bind(&TestReceiver::SendMethodCalled, base::Unretained(this)));
+    impl1_->set_notify_send_method_called(base::BindRepeating(
+        &TestReceiver::SendMethodCalled, base::Unretained(this)));
 
     expected_calls_ = expected_calls;
     notify_finish_ = std::move(notify_finish);
diff --git a/mojo/public/cpp/bindings/tests/bindings_perftest.cc b/mojo/public/cpp/bindings/tests/bindings_perftest.cc
index 283a2b2c..4c0ecd19 100644
--- a/mojo/public/cpp/bindings/tests/bindings_perftest.cc
+++ b/mojo/public/cpp/bindings/tests/bindings_perftest.cc
@@ -63,7 +63,7 @@
   void OnPingDone() {
     current_iterations_++;
     if (current_iterations_ >= iterations_to_run_) {
-      quit_closure_.Run();
+      std::move(quit_closure_).Run();
       return;
     }
 
@@ -75,7 +75,7 @@
   unsigned int iterations_to_run_;
   unsigned int current_iterations_;
 
-  base::Closure quit_closure_;
+  base::OnceClosure quit_closure_;
 
   DISALLOW_COPY_AND_ASSIGN(PingPongTest);
 };
@@ -183,7 +183,7 @@
   base::TimeTicks end_time_;
   uint32_t expected_count_ = 0;
   MessageReceiver* sender_;
-  base::Closure quit_closure_;
+  base::RepeatingClosure quit_closure_;
 };
 
 TEST_F(MojoBindingsPerftest, MultiplexRouterPingPong) {
diff --git a/mojo/public/cpp/bindings/tests/connector_unittest.cc b/mojo/public/cpp/bindings/tests/connector_unittest.cc
index e16cf5c..ddd70b2 100644
--- a/mojo/public/cpp/bindings/tests/connector_unittest.cc
+++ b/mojo/public/cpp/bindings/tests/connector_unittest.cc
@@ -27,12 +27,12 @@
 class MessageAccumulator : public MessageReceiver {
  public:
   MessageAccumulator() {}
-  explicit MessageAccumulator(const base::Closure& closure)
-      : closure_(closure) {}
+  explicit MessageAccumulator(base::OnceClosure closure)
+      : closure_(std::move(closure)) {}
 
   bool Accept(Message* message) override {
     queue_.Push(message);
-    if (!closure_.is_null())
+    if (closure_)
       std::move(closure_).Run();
     return true;
   }
@@ -41,13 +41,13 @@
 
   void Pop(Message* message) { queue_.Pop(message); }
 
-  void set_closure(const base::Closure& closure) { closure_ = closure; }
+  void set_closure(base::OnceClosure closure) { closure_ = std::move(closure); }
 
   size_t size() const { return queue_.size(); }
 
  private:
   MessageQueue queue_;
-  base::Closure closure_;
+  base::OnceClosure closure_;
 };
 
 class ConnectorDeletingMessageAccumulator : public MessageAccumulator {
@@ -405,9 +405,9 @@
   ASSERT_EQ(2, accumulator.number_of_calls());
 }
 
-void ForwardErrorHandler(bool* called, const base::Closure& callback) {
+void ForwardErrorHandler(bool* called, base::OnceClosure callback) {
   *called = true;
-  callback.Run();
+  std::move(callback).Run();
 }
 
 TEST_F(ConnectorTest, RaiseError) {
@@ -415,13 +415,13 @@
   Connector connector0(std::move(handle0_), Connector::SINGLE_THREADED_SEND,
                        base::ThreadTaskRunnerHandle::Get());
   bool error_handler_called0 = false;
-  connector0.set_connection_error_handler(base::Bind(
+  connector0.set_connection_error_handler(base::BindOnce(
       &ForwardErrorHandler, &error_handler_called0, run_loop.QuitClosure()));
 
   Connector connector1(std::move(handle1_), Connector::SINGLE_THREADED_SEND,
                        base::ThreadTaskRunnerHandle::Get());
   bool error_handler_called1 = false;
-  connector1.set_connection_error_handler(base::Bind(
+  connector1.set_connection_error_handler(base::BindOnce(
       &ForwardErrorHandler, &error_handler_called1, run_loop2.QuitClosure()));
 
   const char kText[] = "hello world";
@@ -462,9 +462,9 @@
 }
 
 void PauseConnectorAndRunClosure(Connector* connector,
-                                 const base::Closure& closure) {
+                                 base::OnceClosure closure) {
   connector->PauseIncomingMethodCallProcessing();
-  closure.Run();
+  std::move(closure).Run();
 }
 
 TEST_F(ConnectorTest, PauseWithQueuedMessages) {
@@ -484,7 +484,7 @@
   base::RunLoop run_loop;
   // Configure the accumulator such that it pauses after the first message is
   // received.
-  MessageAccumulator accumulator(base::Bind(
+  MessageAccumulator accumulator(base::BindOnce(
       &PauseConnectorAndRunClosure, &connector1, run_loop.QuitClosure()));
   connector1.set_incoming_receiver(&accumulator);
 
@@ -496,11 +496,11 @@
 }
 
 void AccumulateWithNestedLoop(MessageAccumulator* accumulator,
-                              const base::Closure& closure) {
+                              base::OnceClosure closure) {
   base::RunLoop nested_run_loop(base::RunLoop::Type::kNestableTasksAllowed);
   accumulator->set_closure(nested_run_loop.QuitClosure());
   nested_run_loop.Run();
-  closure.Run();
+  std::move(closure).Run();
 }
 
 TEST_F(ConnectorTest, ProcessWhenNested) {
@@ -521,8 +521,8 @@
   MessageAccumulator accumulator;
   // When the accumulator gets the first message it spins a nested message
   // loop. The loop is quit when another message is received.
-  accumulator.set_closure(base::Bind(&AccumulateWithNestedLoop, &accumulator,
-                                     run_loop.QuitClosure()));
+  accumulator.set_closure(base::BindOnce(&AccumulateWithNestedLoop,
+                                         &accumulator, run_loop.QuitClosure()));
   connector1.set_incoming_receiver(&accumulator);
 
   run_loop.Run();
diff --git a/mojo/public/cpp/bindings/tests/e2e_perftest.cc b/mojo/public/cpp/bindings/tests/e2e_perftest.cc
index e0c6b68..e11be65 100644
--- a/mojo/public/cpp/bindings/tests/e2e_perftest.cc
+++ b/mojo/public/cpp/bindings/tests/e2e_perftest.cc
@@ -122,8 +122,8 @@
       base::RunLoop run_loop;
       runner->PostTaskAndReply(
           FROM_HERE,
-          base::Bind(&MojoE2EPerftest::RunTests, base::Unretained(this),
-                     client_mp, test_name),
+          base::BindOnce(&MojoE2EPerftest::RunTests, base::Unretained(this),
+                         client_mp, test_name),
           run_loop.QuitClosure());
       run_loop.Run();
     }
diff --git a/mojo/public/cpp/bindings/tests/handle_passing_unittest.cc b/mojo/public/cpp/bindings/tests/handle_passing_unittest.cc
index 4d5210d..8f79c1f 100644
--- a/mojo/public/cpp/bindings/tests/handle_passing_unittest.cc
+++ b/mojo/public/cpp/bindings/tests/handle_passing_unittest.cc
@@ -24,16 +24,16 @@
 const char kText2[] = "world";
 
 void RecordString(std::string* storage,
-                  const base::Closure& closure,
+                  base::OnceClosure closure,
                   const std::string& str) {
   *storage = str;
-  closure.Run();
+  std::move(closure).Run();
 }
 
-base::Callback<void(const std::string&)> MakeStringRecorder(
+base::OnceCallback<void(const std::string&)> MakeStringRecorder(
     std::string* storage,
-    const base::Closure& closure) {
-  return base::Bind(&RecordString, storage, closure);
+    base::OnceClosure closure) {
+  return base::BindOnce(&RecordString, storage, std::move(closure));
 }
 
 class ImportedInterfaceImpl : public imported::ImportedInterface {
@@ -162,7 +162,7 @@
 
 void DoStuff(bool* got_response,
              std::string* got_text_reply,
-             const base::Closure& closure,
+             base::OnceClosure closure,
              sample::ResponsePtr response,
              const std::string& text_reply) {
   *got_text_reply = text_reply;
@@ -183,16 +183,16 @@
   }
 
   *got_response = true;
-  closure.Run();
+  std::move(closure).Run();
 }
 
 void DoStuff2(bool* got_response,
               std::string* got_text_reply,
-              const base::Closure& closure,
+              base::OnceClosure closure,
               const std::string& text_reply) {
   *got_response = true;
   *got_text_reply = text_reply;
-  closure.Run();
+  std::move(closure).Run();
 }
 
 TEST_P(HandlePassingTest, Basic) {
@@ -216,8 +216,8 @@
   std::string got_text_reply;
   base::RunLoop run_loop2;
   factory->DoStuff(std::move(request), std::move(pipe0.handle0),
-                   base::Bind(&DoStuff, &got_response, &got_text_reply,
-                              run_loop2.QuitClosure()));
+                   base::BindOnce(&DoStuff, &got_response, &got_text_reply,
+                                  run_loop2.QuitClosure()));
 
   EXPECT_FALSE(got_response);
   int count_before = ImportedInterfaceImpl::do_something_count();
@@ -241,8 +241,8 @@
   std::string got_text_reply;
   base::RunLoop run_loop;
   factory->DoStuff(std::move(request), ScopedMessagePipeHandle(),
-                   base::Bind(&DoStuff, &got_response, &got_text_reply,
-                              run_loop.QuitClosure()));
+                   base::BindOnce(&DoStuff, &got_response, &got_text_reply,
+                                  run_loop.QuitClosure()));
 
   EXPECT_FALSE(got_response);
 
@@ -276,8 +276,8 @@
   std::string got_text_reply;
   base::RunLoop run_loop;
   factory->DoStuff2(std::move(consumer_handle),
-                    base::Bind(&DoStuff2, &got_response, &got_text_reply,
-                               run_loop.QuitClosure()));
+                    base::BindOnce(&DoStuff2, &got_response, &got_text_reply,
+                                   run_loop.QuitClosure()));
 
   EXPECT_FALSE(got_response);
 
diff --git a/mojo/public/cpp/bindings/tests/multiplex_router_unittest.cc b/mojo/public/cpp/bindings/tests/multiplex_router_unittest.cc
index c18e806..d845c97 100644
--- a/mojo/public/cpp/bindings/tests/multiplex_router_unittest.cc
+++ b/mojo/public/cpp/bindings/tests/multiplex_router_unittest.cc
@@ -221,9 +221,9 @@
             std::string(reinterpret_cast<const char*>(response.payload())));
 }
 
-void ForwardErrorHandler(bool* called, const base::Closure& callback) {
+void ForwardErrorHandler(bool* called, base::OnceClosure callback) {
   *called = true;
-  callback.Run();
+  std::move(callback).Run();
 }
 
 // Tests that if the receiving application destroys the responder_ without
@@ -235,9 +235,8 @@
       std::move(endpoint0_), nullptr, base::WrapUnique(new PassThroughFilter()),
       false, base::ThreadTaskRunnerHandle::Get(), 0u, kTestInterfaceName);
   bool error_handler_called0 = false;
-  client0.set_connection_error_handler(
-      base::Bind(&ForwardErrorHandler, &error_handler_called0,
-                 run_loop0.QuitClosure()));
+  client0.set_connection_error_handler(base::BindOnce(
+      &ForwardErrorHandler, &error_handler_called0, run_loop0.QuitClosure()));
 
   base::RunLoop run_loop3;
   LazyResponseGenerator generator(run_loop3.QuitClosure());
@@ -246,9 +245,8 @@
                                   false, base::ThreadTaskRunnerHandle::Get(),
                                   0u, kTestInterfaceName);
   bool error_handler_called1 = false;
-  client1.set_connection_error_handler(
-      base::Bind(&ForwardErrorHandler, &error_handler_called1,
-                 run_loop1.QuitClosure()));
+  client1.set_connection_error_handler(base::BindOnce(
+      &ForwardErrorHandler, &error_handler_called1, run_loop1.QuitClosure()));
 
   Message request;
   AllocRequestMessage(1, "hello", &request);
diff --git a/mojo/public/cpp/bindings/tests/pickle_unittest.cc b/mojo/public/cpp/bindings/tests/pickle_unittest.cc
index e233a2506f..959c7bf 100644
--- a/mojo/public/cpp/bindings/tests/pickle_unittest.cc
+++ b/mojo/public/cpp/bindings/tests/pickle_unittest.cc
@@ -25,16 +25,17 @@
 namespace {
 
 template <typename T>
-void DoExpectResult(int foo, int bar, const base::Closure& callback, T actual) {
+void DoExpectResult(int foo, int bar, base::OnceClosure callback, T actual) {
   EXPECT_EQ(foo, actual.foo());
   EXPECT_EQ(bar, actual.bar());
-  callback.Run();
+  std::move(callback).Run();
 }
 
 template <typename T>
-base::Callback<void(T)> ExpectResult(const T& t,
-                                     const base::Closure& callback) {
-  return base::Bind(&DoExpectResult<T>, t.foo(), t.bar(), callback);
+base::OnceCallback<void(T)> ExpectResult(const T& t,
+                                         base::OnceClosure callback) {
+  return base::BindOnce(&DoExpectResult<T>, t.foo(), t.bar(),
+                        std::move(callback));
 }
 
 template <typename T>
@@ -43,19 +44,19 @@
 }
 
 template <typename T>
-base::Callback<void(T)> Fail(const std::string& reason) {
-  return base::Bind(&DoFail<T>, reason);
+base::OnceCallback<void(T)> Fail(const std::string& reason) {
+  return base::BindOnce(&DoFail<T>, reason);
 }
 
 template <typename T>
-void DoExpectEnumResult(T expected, const base::Closure& callback, T actual) {
+void DoExpectEnumResult(T expected, base::OnceClosure callback, T actual) {
   EXPECT_EQ(expected, actual);
-  callback.Run();
+  std::move(callback).Run();
 }
 
 template <typename T>
-base::Callback<void(T)> ExpectEnumResult(T t, const base::Closure& callback) {
-  return base::Bind(&DoExpectEnumResult<T>, t, callback);
+base::OnceCallback<void(T)> ExpectEnumResult(T t, base::OnceClosure callback) {
+  return base::BindOnce(&DoExpectEnumResult<T>, t, std::move(callback));
 }
 
 template <typename T>
@@ -64,8 +65,8 @@
 }
 
 template <typename T>
-base::Callback<void(T)> EnumFail(const std::string& reason) {
-  return base::Bind(&DoEnumFail<T>, reason);
+base::OnceCallback<void(T)> EnumFail(const std::string& reason) {
+  return base::BindOnce(&DoEnumFail<T>, reason);
 }
 
 template <typename T>
@@ -77,8 +78,8 @@
 void RunSimpleLambda(Func func, Arg arg) { func(std::move(arg)); }
 
 template <typename Arg, typename Func>
-base::Callback<void(Arg)> BindSimpleLambda(Func func) {
-  return base::Bind(&RunSimpleLambda<Func, Arg>, func);
+base::OnceCallback<void(Arg)> BindSimpleLambda(Func func) {
+  return base::BindOnce(&RunSimpleLambda<Func, Arg>, func);
 }
 
 // This implements the generated Chromium variant of PicklePasser.
diff --git a/mojo/public/cpp/bindings/tests/receiver_set_unittest.cc b/mojo/public/cpp/bindings/tests/receiver_set_unittest.cc
index b88d676..e2ed86e9 100644
--- a/mojo/public/cpp/bindings/tests/receiver_set_unittest.cc
+++ b/mojo/public/cpp/bindings/tests/receiver_set_unittest.cc
@@ -212,9 +212,9 @@
 
   std::string last_received_error;
   core::SetDefaultProcessErrorCallback(
-      base::Bind([](std::string* out_error,
-                    const std::string& error) { *out_error = error; },
-                 &last_received_error));
+      base::BindRepeating([](std::string* out_error,
+                             const std::string& error) { *out_error = error; },
+                          &last_received_error));
 
   ReceiverSet<PingService, int> receivers;
   Remote<PingService> ping_a, ping_b;
@@ -225,7 +225,7 @@
     impl.set_ping_handler(ReportBadMessage(&receivers, "message 1"));
     base::RunLoop loop;
     ping_a.set_disconnect_handler(loop.QuitClosure());
-    ping_a->Ping(base::Bind([] {}));
+    ping_a->Ping(base::BindOnce([] {}));
     loop.Run();
     EXPECT_EQ("message 1", last_received_error);
   }
@@ -234,7 +234,7 @@
     impl.set_ping_handler(ReportBadMessage(&receivers, "message 2"));
     base::RunLoop loop;
     ping_b.set_disconnect_handler(loop.QuitClosure());
-    ping_b->Ping(base::Bind([] {}));
+    ping_b->Ping(base::BindOnce([] {}));
     loop.Run();
     EXPECT_EQ("message 2", last_received_error);
   }
@@ -249,9 +249,9 @@
 
   std::string last_received_error;
   core::SetDefaultProcessErrorCallback(
-      base::Bind([](std::string* out_error,
-                    const std::string& error) { *out_error = error; },
-                 &last_received_error));
+      base::BindRepeating([](std::string* out_error,
+                             const std::string& error) { *out_error = error; },
+                          &last_received_error));
 
   ReceiverSet<PingService, int> receivers;
   Remote<PingService> ping_a, ping_b;
@@ -299,9 +299,9 @@
 
   std::string last_received_error;
   core::SetDefaultProcessErrorCallback(
-      base::Bind([](std::string* out_error,
-                    const std::string& error) { *out_error = error; },
-                 &last_received_error));
+      base::BindRepeating([](std::string* out_error,
+                             const std::string& error) { *out_error = error; },
+                          &last_received_error));
 
   ReportBadMessageCallback bad_message_callback;
   {
@@ -329,12 +329,12 @@
 
   void set_new_ping_context(int context) { new_ping_context_ = context; }
 
-  void set_new_ping_handler(const base::RepeatingClosure& handler) {
-    new_ping_handler_ = handler;
+  void set_new_ping_handler(base::RepeatingClosure handler) {
+    new_ping_handler_ = std::move(handler);
   }
 
-  void set_ping_handler(const base::RepeatingClosure& handler) {
-    ping_handler_ = handler;
+  void set_ping_handler(base::RepeatingClosure handler) {
+    ping_handler_ = std::move(handler);
   }
 
   AssociatedReceiverSet<PingService, int>& ping_receivers() {
@@ -358,8 +358,8 @@
 
   AssociatedReceiverSet<PingService, int> ping_receivers_;
   int new_ping_context_ = -1;
-  base::Closure ping_handler_;
-  base::Closure new_ping_handler_;
+  base::RepeatingClosure ping_handler_;
+  base::RepeatingClosure new_ping_handler_;
 };
 
 TEST_P(ReceiverSetTest, AssociatedReceiverSetContext) {
diff --git a/mojo/public/cpp/bindings/tests/remote_unittest.cc b/mojo/public/cpp/bindings/tests/remote_unittest.cc
index e56a31e..36f7b3d 100644
--- a/mojo/public/cpp/bindings/tests/remote_unittest.cc
+++ b/mojo/public/cpp/bindings/tests/remote_unittest.cc
@@ -322,7 +322,7 @@
   EXPECT_EQ(2.0, calculator_ui.GetOutput());
   EXPECT_TRUE(calculator_ui.is_connected());
 
-  calculator_ui.Multiply(5.0, base::Closure());
+  calculator_ui.Multiply(5.0, base::OnceClosure());
   EXPECT_TRUE(calculator_ui.is_connected());
 
   calc_impl.receiver().reset();
@@ -358,7 +358,7 @@
   EXPECT_EQ(2.0, calculator_ui.GetOutput());
   EXPECT_TRUE(calculator_ui.is_connected());
 
-  calculator_ui.Multiply(5.0, base::Closure());
+  calculator_ui.Multiply(5.0, base::OnceClosure());
   EXPECT_TRUE(calculator_ui.is_connected());
 
   calc_impl.receiver().reset();
diff --git a/mojo/public/cpp/bindings/tests/report_bad_message_unittest.cc b/mojo/public/cpp/bindings/tests/report_bad_message_unittest.cc
index 1394c86..f468325 100644
--- a/mojo/public/cpp/bindings/tests/report_bad_message_unittest.cc
+++ b/mojo/public/cpp/bindings/tests/report_bad_message_unittest.cc
@@ -63,7 +63,7 @@
   ReportBadMessageTest() = default;
 
   void SetUp() override {
-    mojo::core::SetDefaultProcessErrorCallback(base::Bind(
+    mojo::core::SetDefaultProcessErrorCallback(base::BindRepeating(
         &ReportBadMessageTest::OnProcessError, base::Unretained(this)));
 
     impl_.Bind(remote_.BindNewPipeAndPassReceiver());
diff --git a/mojo/public/cpp/bindings/tests/router_test_util.cc b/mojo/public/cpp/bindings/tests/router_test_util.cc
index b36de55..48539dca 100644
--- a/mojo/public/cpp/bindings/tests/router_test_util.cc
+++ b/mojo/public/cpp/bindings/tests/router_test_util.cc
@@ -35,16 +35,15 @@
 }
 
 MessageAccumulator::MessageAccumulator(MessageQueue* queue,
-                                       const base::Closure& closure)
-    : queue_(queue), closure_(closure) {}
+                                       base::OnceClosure closure)
+    : queue_(queue), closure_(std::move(closure)) {}
 
 MessageAccumulator::~MessageAccumulator() {}
 
 bool MessageAccumulator::Accept(Message* message) {
   queue_->Push(message);
-  if (!closure_.is_null()) {
-    closure_.Run();
-    closure_.Reset();
+  if (closure_) {
+    std::move(closure_).Run();
   }
   return true;
 }
@@ -79,8 +78,11 @@
   return responder->Accept(&response);
 }
 
-LazyResponseGenerator::LazyResponseGenerator(const base::Closure& closure)
-    : responder_(nullptr), name_(0), request_id_(0), closure_(closure) {}
+LazyResponseGenerator::LazyResponseGenerator(base::OnceClosure closure)
+    : responder_(nullptr),
+      name_(0),
+      request_id_(0),
+      closure_(std::move(closure)) {}
 
 LazyResponseGenerator::~LazyResponseGenerator() = default;
 
@@ -92,9 +94,8 @@
   request_string_ =
       std::string(reinterpret_cast<const char*>(message->payload()));
   responder_ = std::move(responder);
-  if (!closure_.is_null()) {
-    closure_.Run();
-    closure_.Reset();
+  if (closure_) {
+    std::move(closure_).Run();
   }
   return true;
 }
diff --git a/mojo/public/cpp/bindings/tests/router_test_util.h b/mojo/public/cpp/bindings/tests/router_test_util.h
index 6d18a03..946f5f7 100644
--- a/mojo/public/cpp/bindings/tests/router_test_util.h
+++ b/mojo/public/cpp/bindings/tests/router_test_util.h
@@ -8,6 +8,7 @@
 #include <stdint.h>
 
 #include <string>
+#include <utility>
 
 #include "base/callback.h"
 #include "mojo/public/cpp/bindings/message.h"
@@ -26,14 +27,14 @@
 class MessageAccumulator : public MessageReceiver {
  public:
   MessageAccumulator(MessageQueue* queue,
-                     const base::Closure& closure = base::Closure());
+                     base::OnceClosure closure = base::OnceClosure());
   ~MessageAccumulator() override;
 
   bool Accept(Message* message) override;
 
  private:
   MessageQueue* queue_;
-  base::Closure closure_;
+  base::OnceClosure closure_;
 };
 
 class ResponseGenerator : public MessageReceiverWithResponderStatus {
@@ -54,7 +55,7 @@
 class LazyResponseGenerator : public ResponseGenerator {
  public:
   explicit LazyResponseGenerator(
-      const base::Closure& closure = base::Closure());
+      base::OnceClosure closure = base::OnceClosure());
 
   ~LazyResponseGenerator() override;
 
@@ -66,7 +67,7 @@
 
   bool responder_is_valid() const { return responder_->IsConnected(); }
 
-  void set_closure(const base::Closure& closure) { closure_ = closure; }
+  void set_closure(base::OnceClosure closure) { closure_ = std::move(closure); }
 
   // Sends the response and delete the responder.
   void CompleteWithResponse() { Complete(true); }
@@ -83,7 +84,7 @@
   uint32_t name_;
   uint64_t request_id_;
   std::string request_string_;
-  base::Closure closure_;
+  base::OnceClosure closure_;
 };
 
 }  // namespace test
diff --git a/mojo/public/cpp/bindings/tests/struct_traits_unittest.cc b/mojo/public/cpp/bindings/tests/struct_traits_unittest.cc
index 76e1702..b251b04 100644
--- a/mojo/public/cpp/bindings/tests/struct_traits_unittest.cc
+++ b/mojo/public/cpp/bindings/tests/struct_traits_unittest.cc
@@ -28,19 +28,19 @@
 
 template <typename T>
 void DoExpectResult(const T& expected,
-                    const base::Closure& callback,
+                    base::OnceClosure callback,
                     const T& actual) {
   EXPECT_EQ(expected.x(), actual.x());
   EXPECT_EQ(expected.y(), actual.y());
   EXPECT_EQ(expected.width(), actual.width());
   EXPECT_EQ(expected.height(), actual.height());
-  callback.Run();
+  std::move(callback).Run();
 }
 
 template <typename T>
-base::Callback<void(const T&)> ExpectResult(const T& r,
-                                            const base::Closure& callback) {
-  return base::Bind(&DoExpectResult<T>, r, callback);
+base::OnceCallback<void(const T&)> ExpectResult(const T& r,
+                                                base::OnceClosure callback) {
+  return base::BindOnce(&DoExpectResult<T>, r, std::move(callback));
 }
 
 template <typename T>
@@ -49,8 +49,8 @@
 }
 
 template <typename T>
-base::Callback<void(const T&)> Fail(const std::string& reason) {
-  return base::Bind(&DoFail<T>, reason);
+base::OnceCallback<void(const T&)> Fail(const std::string& reason) {
+  return base::BindOnce(&DoFail<T>, reason);
 }
 
 template <typename T>
@@ -292,7 +292,7 @@
 }
 
 void ExpectStructWithTraits(const StructWithTraitsImpl& expected,
-                            const base::Closure& closure,
+                            base::OnceClosure closure,
                             const StructWithTraitsImpl& passed) {
   EXPECT_EQ(expected.get_enum(), passed.get_enum());
   EXPECT_EQ(expected.get_bool(), passed.get_bool());
@@ -303,7 +303,7 @@
   EXPECT_EQ(expected.get_struct(), passed.get_struct());
   EXPECT_EQ(expected.get_struct_array(), passed.get_struct_array());
   EXPECT_EQ(expected.get_struct_map(), passed.get_struct_map());
-  closure.Run();
+  std::move(closure).Run();
 }
 
 TEST_F(StructTraitsTest, EchoStructWithTraits) {
@@ -341,10 +341,10 @@
 }
 
 void ExpectTrivialStructWithTraits(TrivialStructWithTraitsImpl expected,
-                                   const base::Closure& closure,
+                                   base::OnceClosure closure,
                                    TrivialStructWithTraitsImpl passed) {
   EXPECT_EQ(expected.value, passed.value);
-  closure.Run();
+  std::move(closure).Run();
 }
 
 TEST_F(StructTraitsTest, EchoTrivialStructWithTraits) {
@@ -361,11 +361,11 @@
 }
 
 void CaptureMessagePipe(ScopedMessagePipeHandle* storage,
-                        const base::Closure& closure,
+                        base::OnceClosure closure,
                         MoveOnlyStructWithTraitsImpl passed) {
   storage->reset(MessagePipeHandle(
       passed.get_mutable_handle().release().value()));
-  closure.Run();
+  std::move(closure).Run();
 }
 
 TEST_F(StructTraitsTest, EchoMoveOnlyStructWithTraits) {
@@ -403,10 +403,10 @@
 
 void CaptureNullableMoveOnlyStructWithTraitsImpl(
     base::Optional<MoveOnlyStructWithTraitsImpl>* storage,
-    const base::Closure& closure,
+    base::OnceClosure closure,
     base::Optional<MoveOnlyStructWithTraitsImpl> passed) {
   *storage = std::move(passed);
-  closure.Run();
+  std::move(closure).Run();
 }
 
 TEST_F(StructTraitsTest, EchoNullableMoveOnlyStructWithTraits) {
@@ -424,10 +424,10 @@
 }
 
 void ExpectEnumWithTraits(EnumWithTraitsImpl expected_value,
-                          const base::Closure& closure,
+                          base::OnceClosure closure,
                           EnumWithTraitsImpl value) {
   EXPECT_EQ(expected_value, value);
-  closure.Run();
+  std::move(closure).Run();
 }
 
 TEST_F(StructTraitsTest, EchoEnumWithTraits) {
@@ -475,12 +475,12 @@
 }
 
 void ExpectUniquePtr(std::unique_ptr<int> expected,
-                     const base::Closure& closure,
+                     base::OnceClosure closure,
                      std::unique_ptr<int> value) {
   ASSERT_EQ(!expected, !value);
   if (expected)
     EXPECT_EQ(*expected, *value);
-  closure.Run();
+  std::move(closure).Run();
 }
 
 TEST_F(StructTraitsTest, TypemapUniquePtr) {
@@ -512,13 +512,13 @@
     proxy->EchoUnionWithTraits(
         std::move(input),
         base::BindOnce(
-            [](const base::Closure& quit_closure,
+            [](base::OnceClosure quit_closure,
                std::unique_ptr<test::UnionWithTraitsBase> passed) {
               ASSERT_EQ(test::UnionWithTraitsBase::Type::INT32, passed->type());
               EXPECT_EQ(1234,
                         static_cast<test::UnionWithTraitsInt32*>(passed.get())
                             ->value());
-              quit_closure.Run();
+              std::move(quit_closure).Run();
             },
             loop.QuitClosure()));
     loop.Run();
@@ -531,7 +531,7 @@
     proxy->EchoUnionWithTraits(
         std::move(input),
         base::BindOnce(
-            [](const base::Closure& quit_closure,
+            [](base::OnceClosure quit_closure,
                std::unique_ptr<test::UnionWithTraitsBase> passed) {
               ASSERT_EQ(test::UnionWithTraitsBase::Type::STRUCT,
                         passed->type());
@@ -539,7 +539,7 @@
                         static_cast<test::UnionWithTraitsStruct*>(passed.get())
                             ->get_struct()
                             .value);
-              quit_closure.Run();
+              std::move(quit_closure).Run();
             },
             loop.QuitClosure()));
     loop.Run();
diff --git a/mojo/public/cpp/bindings/tests/sync_handle_registry_unittest.cc b/mojo/public/cpp/bindings/tests/sync_handle_registry_unittest.cc
index 2f17fc7..89bd80d 100644
--- a/mojo/public/cpp/bindings/tests/sync_handle_registry_unittest.cc
+++ b/mojo/public/cpp/bindings/tests/sync_handle_registry_unittest.cc
@@ -28,8 +28,8 @@
   bool called1 = false;
   bool called2 = false;
   auto callback = [](bool* called) { *called = true; };
-  auto callback1 = base::Bind(callback, &called1);
-  auto callback2 = base::Bind(callback, &called2);
+  auto callback1 = base::BindRepeating(callback, &called1);
+  auto callback2 = base::BindRepeating(callback, &called2);
 
   base::WaitableEvent e(base::WaitableEvent::ResetPolicy::MANUAL,
                         base::WaitableEvent::InitialState::SIGNALED);
@@ -60,15 +60,17 @@
   bool called1 = false;
   bool called2 = false;
   bool called3 = false;
-  auto callback1 = base::Bind([](bool* called) { *called = true; }, &called1);
-  auto callback2 = base::Bind(
-      [](base::WaitableEvent* e, const base::Closure& other_callback,
+  auto callback1 =
+      base::BindRepeating([](bool* called) { *called = true; }, &called1);
+  auto callback2 = base::BindRepeating(
+      [](base::WaitableEvent* e, base::RepeatingClosure other_callback,
          scoped_refptr<SyncHandleRegistry> registry, bool* called) {
         registry->UnregisterEvent(e, other_callback);
         *called = true;
       },
       &e, callback1, registry(), &called2);
-  auto callback3 = base::Bind([](bool* called) { *called = true; }, &called3);
+  auto callback3 =
+      base::BindRepeating([](bool* called) { *called = true; }, &called3);
 
   registry()->RegisterEvent(&e, callback1);
   registry()->RegisterEvent(&e, callback2);
@@ -101,10 +103,10 @@
       base::WaitableEvent::ResetPolicy::MANUAL,
       base::WaitableEvent::InitialState::SIGNALED);
   bool called = false;
-  base::Closure callback_holder;
-  auto callback = base::Bind(
+  base::RepeatingClosure callback_holder;
+  auto callback = base::BindRepeating(
       [](std::unique_ptr<base::WaitableEvent>* e,
-         base::Closure* callback_holder,
+         base::RepeatingClosure* callback_holder,
          scoped_refptr<SyncHandleRegistry> registry, bool* called) {
         EXPECT_FALSE(*called);
 
@@ -116,8 +118,8 @@
             base::WaitableEvent::ResetPolicy::MANUAL,
             base::WaitableEvent::InitialState::SIGNALED);
         bool nested_called = false;
-        auto nested_callback =
-            base::Bind([](bool* called) { *called = true; }, &nested_called);
+        auto nested_callback = base::BindRepeating(
+            [](bool* called) { *called = true; }, &nested_called);
         registry->RegisterEvent(&nested_event, nested_callback);
         const bool* stop_flag = &nested_called;
         registry->Wait(&stop_flag, 1);
@@ -137,9 +139,9 @@
   base::WaitableEvent e(base::WaitableEvent::ResetPolicy::MANUAL,
                         base::WaitableEvent::InitialState::SIGNALED);
   bool called = false;
-  base::Closure callback_holder;
-  auto callback = base::Bind(
-      [](base::WaitableEvent* e, base::Closure* callback_holder,
+  base::RepeatingClosure callback_holder;
+  auto callback = base::BindRepeating(
+      [](base::WaitableEvent* e, base::RepeatingClosure* callback_holder,
          scoped_refptr<SyncHandleRegistry> registry, bool* called) {
         EXPECT_FALSE(*called);
 
@@ -147,8 +149,8 @@
         *called = true;
 
         bool nested_called = false;
-        auto nested_callback =
-            base::Bind([](bool* called) { *called = true; }, &nested_called);
+        auto nested_callback = base::BindRepeating(
+            [](bool* called) { *called = true; }, &nested_called);
         registry->RegisterEvent(e, nested_callback);
         const bool* stop_flag = &nested_called;
         registry->Wait(&stop_flag, 1);
@@ -171,7 +173,7 @@
                         base::WaitableEvent::InitialState::SIGNALED);
   bool called = false;
   int call_count = 0;
-  auto callback = base::Bind(
+  auto callback = base::BindRepeating(
       [](base::WaitableEvent* e, scoped_refptr<SyncHandleRegistry> registry,
          bool* called, int* call_count) {
         // Don't re-enter.
@@ -183,7 +185,7 @@
 
         bool called2 = false;
         auto callback2 =
-            base::Bind([](bool* called) { *called = true; }, &called2);
+            base::BindRepeating([](bool* called) { *called = true; }, &called2);
         registry->RegisterEvent(e, callback2);
 
         const bool* stop_flag = &called2;
@@ -212,10 +214,11 @@
                          base::WaitableEvent::InitialState::SIGNALED);
   bool called1 = false;
   bool called2 = false;
-  auto callback1 = base::Bind([](bool* called) { *called = true; }, &called1);
-  auto callback2 = base::Bind(
+  auto callback1 =
+      base::BindRepeating([](bool* called) { *called = true; }, &called1);
+  auto callback2 = base::BindRepeating(
       [](std::unique_ptr<base::WaitableEvent>* e1,
-         const base::Closure& other_callback,
+         base::RepeatingClosure other_callback,
          scoped_refptr<SyncHandleRegistry> registry, bool* called) {
         // Prevent re-entrancy.
         if (*called)
@@ -228,7 +231,7 @@
         // Nest another wait.
         bool called3 = false;
         auto callback3 =
-            base::Bind([](bool* called) { *called = true; }, &called3);
+            base::BindRepeating([](bool* called) { *called = true; }, &called3);
         base::WaitableEvent e3(base::WaitableEvent::ResetPolicy::MANUAL,
                                base::WaitableEvent::InitialState::SIGNALED);
         registry->RegisterEvent(&e3, callback3);
diff --git a/mojo/public/cpp/bindings/tests/wtf_types_unittest.cc b/mojo/public/cpp/bindings/tests/wtf_types_unittest.cc
index d25238ba..15059e2 100644
--- a/mojo/public/cpp/bindings/tests/wtf_types_unittest.cc
+++ b/mojo/public/cpp/bindings/tests/wtf_types_unittest.cc
@@ -84,25 +84,25 @@
 }
 
 void ExpectString(const WTF::String& expected_string,
-                  const base::Closure& closure,
+                  base::OnceClosure closure,
                   const WTF::String& string) {
   EXPECT_EQ(expected_string, string);
-  closure.Run();
+  std::move(closure).Run();
 }
 
 void ExpectStringArray(base::Optional<WTF::Vector<WTF::String>>* expected_arr,
-                       const base::Closure& closure,
+                       base::OnceClosure closure,
                        const base::Optional<WTF::Vector<WTF::String>>& arr) {
   EXPECT_EQ(*expected_arr, arr);
-  closure.Run();
+  std::move(closure).Run();
 }
 
 void ExpectStringMap(
     base::Optional<WTF::HashMap<WTF::String, WTF::String>>* expected_map,
-    const base::Closure& closure,
+    base::OnceClosure closure,
     const base::Optional<WTF::HashMap<WTF::String, WTF::String>>& map) {
   EXPECT_EQ(*expected_map, map);
-  closure.Run();
+  std::move(closure).Run();
 }
 
 }  // namespace
diff --git a/mojo/public/cpp/bindings/thread_safe_forwarder_base.cc b/mojo/public/cpp/bindings/thread_safe_forwarder_base.cc
index 2d8fbdd..56239ff 100644
--- a/mojo/public/cpp/bindings/thread_safe_forwarder_base.cc
+++ b/mojo/public/cpp/bindings/thread_safe_forwarder_base.cc
@@ -15,12 +15,12 @@
 
 ThreadSafeForwarderBase::ThreadSafeForwarderBase(
     scoped_refptr<base::SequencedTaskRunner> task_runner,
-    const ForwardMessageCallback& forward,
-    const ForwardMessageWithResponderCallback& forward_with_responder,
+    ForwardMessageCallback forward,
+    ForwardMessageWithResponderCallback forward_with_responder,
     const AssociatedGroup& associated_group)
     : task_runner_(std::move(task_runner)),
-      forward_(forward),
-      forward_with_responder_(forward_with_responder),
+      forward_(std::move(forward)),
+      forward_with_responder_(std::move(forward_with_responder)),
       associated_group_(associated_group),
       sync_calls_(new InProgressSyncCalls()) {}
 
@@ -52,7 +52,7 @@
         associated_group_.GetController());
   }
   task_runner_->PostTask(FROM_HERE,
-                         base::BindOnce(forward_, base::Passed(message)));
+                         base::BindOnce(forward_, std::move(*message)));
   return true;
 }
 
@@ -72,9 +72,8 @@
     auto reply_forwarder =
         std::make_unique<ForwardToCallingThread>(std::move(responder));
     task_runner_->PostTask(
-        FROM_HERE,
-        base::BindOnce(forward_with_responder_, base::Passed(message),
-                       std::move(reply_forwarder)));
+        FROM_HERE, base::BindOnce(forward_with_responder_, std::move(*message),
+                                  std::move(reply_forwarder)));
     return true;
   }
 
@@ -90,7 +89,7 @@
   auto response = base::MakeRefCounted<SyncResponseInfo>();
   auto response_signaler = std::make_unique<SyncResponseSignaler>(response);
   task_runner_->PostTask(
-      FROM_HERE, base::BindOnce(forward_with_responder_, base::Passed(message),
+      FROM_HERE, base::BindOnce(forward_with_responder_, std::move(*message),
                                 std::move(response_signaler)));
 
   // Save the pending SyncResponseInfo so that if the sync call deletes
@@ -105,7 +104,7 @@
   auto assign_true = [](bool* b) { *b = true; };
   bool event_signaled = false;
   SyncEventWatcher watcher(&response->event,
-                           base::Bind(assign_true, &event_signaled));
+                           base::BindRepeating(assign_true, &event_signaled));
   const bool* stop_flags[] = {&event_signaled};
   watcher.SyncWatch(stop_flags, 1);
 
diff --git a/mojo/public/cpp/bindings/thread_safe_forwarder_base.h b/mojo/public/cpp/bindings/thread_safe_forwarder_base.h
index b1c3f8e..cf11165 100644
--- a/mojo/public/cpp/bindings/thread_safe_forwarder_base.h
+++ b/mojo/public/cpp/bindings/thread_safe_forwarder_base.h
@@ -24,14 +24,14 @@
 class COMPONENT_EXPORT(MOJO_CPP_BINDINGS) ThreadSafeForwarderBase
     : public MessageReceiverWithResponder {
  public:
-  using ForwardMessageCallback = base::Callback<void(Message)>;
+  using ForwardMessageCallback = base::RepeatingCallback<void(Message)>;
   using ForwardMessageWithResponderCallback =
-      base::Callback<void(Message, std::unique_ptr<MessageReceiver>)>;
+      base::RepeatingCallback<void(Message, std::unique_ptr<MessageReceiver>)>;
 
   ThreadSafeForwarderBase(
       scoped_refptr<base::SequencedTaskRunner> task_runner,
-      const ForwardMessageCallback& forward,
-      const ForwardMessageWithResponderCallback& forward_with_responder,
+      ForwardMessageCallback forward,
+      ForwardMessageWithResponderCallback forward_with_responder,
       const AssociatedGroup& associated_group);
 
   ~ThreadSafeForwarderBase() override;
diff --git a/mojo/public/cpp/bindings/thread_safe_interface_ptr.h b/mojo/public/cpp/bindings/thread_safe_interface_ptr.h
index 4f347bc0..bba6d3b 100644
--- a/mojo/public/cpp/bindings/thread_safe_interface_ptr.h
+++ b/mojo/public/cpp/bindings/thread_safe_interface_ptr.h
@@ -51,12 +51,12 @@
   // method.
   ThreadSafeForwarder(
       scoped_refptr<base::SequencedTaskRunner> task_runner,
-      const ForwardMessageCallback& forward,
-      const ForwardMessageWithResponderCallback& forward_with_responder,
+      ForwardMessageCallback forward,
+      ForwardMessageWithResponderCallback forward_with_responder,
       const AssociatedGroup& associated_group)
       : ThreadSafeForwarderBase(std::move(task_runner),
-                                forward,
-                                forward_with_responder,
+                                std::move(forward),
+                                std::move(forward_with_responder),
                                 associated_group),
         proxy_(this) {}
 
@@ -151,8 +151,8 @@
 
     std::unique_ptr<ThreadSafeForwarder<InterfaceType>> CreateForwarder() {
       return std::make_unique<ThreadSafeForwarder<InterfaceType>>(
-          task_runner_, base::Bind(&PtrWrapper::Accept, this),
-          base::Bind(&PtrWrapper::AcceptWithResponder, this),
+          task_runner_, base::BindRepeating(&PtrWrapper::Accept, this),
+          base::BindRepeating(&PtrWrapper::AcceptWithResponder, this),
           associated_group_);
     }
 
diff --git a/mojo/public/tools/bindings/chromium_bindings_configuration.gni b/mojo/public/tools/bindings/chromium_bindings_configuration.gni
index 1e19276..ef2d02a0 100644
--- a/mojo/public/tools/bindings/chromium_bindings_configuration.gni
+++ b/mojo/public/tools/bindings/chromium_bindings_configuration.gni
@@ -58,6 +58,7 @@
   "//ui/display/mojom/typemaps.gni",
   "//ui/events/mojom/typemaps.gni",
   "//ui/gfx/typemaps.gni",
+  "//ui/gl/typemaps.gni",
   "//ui/latency/mojom/typemaps.gni",
   "//ui/ozone/public/mojom/typemaps.gni",
   "//url/mojom/typemaps.gni",
diff --git a/mojo/public/tools/fuzzers/fuzz_impl.cc b/mojo/public/tools/fuzzers/fuzz_impl.cc
index 23816fd..9fbecda 100644
--- a/mojo/public/tools/fuzzers/fuzz_impl.cc
+++ b/mojo/public/tools/fuzzers/fuzz_impl.cc
@@ -4,11 +4,12 @@
 
 #include <utility>
 
+#include "mojo/public/cpp/bindings/pending_receiver.h"
 #include "mojo/public/tools/fuzzers/fuzz.mojom.h"
 #include "mojo/public/tools/fuzzers/fuzz_impl.h"
 
-FuzzImpl::FuzzImpl(fuzz::mojom::FuzzInterfaceRequest request)
-    : binding_(this, std::move(request)) {}
+FuzzImpl::FuzzImpl(mojo::PendingReceiver<fuzz::mojom::FuzzInterface> receiver)
+    : receiver_(this, std::move(receiver)) {}
 
 FuzzImpl::~FuzzImpl() {}
 
diff --git a/mojo/public/tools/fuzzers/fuzz_impl.h b/mojo/public/tools/fuzzers/fuzz_impl.h
index d8f7f566..77f882db 100644
--- a/mojo/public/tools/fuzzers/fuzz_impl.h
+++ b/mojo/public/tools/fuzzers/fuzz_impl.h
@@ -6,14 +6,15 @@
 #define MOJO_PUBLIC_TOOLS_FUZZERS_FUZZ_IMPL_H_
 
 #include "mojo/public/cpp/bindings/associated_receiver_set.h"
-#include "mojo/public/cpp/bindings/binding.h"
 #include "mojo/public/cpp/bindings/pending_associated_receiver.h"
+#include "mojo/public/cpp/bindings/pending_receiver.h"
+#include "mojo/public/cpp/bindings/receiver.h"
 #include "mojo/public/tools/fuzzers/fuzz.mojom.h"
 
 class FuzzImpl : public fuzz::mojom::FuzzInterface,
                  public fuzz::mojom::FuzzDummyInterface {
  public:
-  explicit FuzzImpl(fuzz::mojom::FuzzInterfaceRequest request);
+  explicit FuzzImpl(mojo::PendingReceiver<fuzz::mojom::FuzzInterface> receiver);
   ~FuzzImpl() override;
 
   // fuzz::mojom::FuzzInterface:
@@ -38,7 +39,7 @@
   void Ping() override;
 
   /* Expose the binding to the fuzz harness. */
-  mojo::Binding<FuzzInterface> binding_;
+  mojo::Receiver<FuzzInterface> receiver_;
 
  private:
   mojo::AssociatedReceiverSet<FuzzDummyInterface> associated_receivers_;
diff --git a/mojo/public/tools/fuzzers/mojo_fuzzer_message_dump.cc b/mojo/public/tools/fuzzers/mojo_fuzzer_message_dump.cc
index b81f8c4..32ea91d 100644
--- a/mojo/public/tools/fuzzers/mojo_fuzzer_message_dump.cc
+++ b/mojo/public/tools/fuzzers/mojo_fuzzer_message_dump.cc
@@ -14,6 +14,7 @@
 #include "base/task/thread_pool/thread_pool_instance.h"
 #include "mojo/core/embedder/embedder.h"
 #include "mojo/public/cpp/bindings/associated_remote.h"
+#include "mojo/public/cpp/bindings/pending_remote.h"
 #include "mojo/public/tools/fuzzers/fuzz.mojom.h"
 #include "mojo/public/tools/fuzzers/fuzz_impl.h"
 
@@ -227,13 +228,15 @@
 /* Invokes each method in the FuzzInterface and dumps the messages to the
  * supplied directory. */
 void DumpMessages(std::string output_directory) {
-  fuzz::mojom::FuzzInterfacePtr fuzz;
+  mojo::Remote<fuzz::mojom::FuzzInterface> fuzz;
   mojo::AssociatedRemote<fuzz::mojom::FuzzDummyInterface> dummy;
 
   /* Create the impl and add a MessageDumper to the filter chain. */
-  env->impl = std::make_unique<FuzzImpl>(MakeRequest(&fuzz));
-  env->impl->binding_.RouterForTesting()->SetIncomingMessageFilter(
-      std::make_unique<MessageDumper>(output_directory));
+  env->impl = std::make_unique<FuzzImpl>(fuzz.BindNewPipeAndPassReceiver());
+  env->impl->receiver_.internal_state()
+      ->RouterForTesting()
+      ->SetIncomingMessageFilter(
+          std::make_unique<MessageDumper>(output_directory));
 
   /* Call methods in various ways to generate interesting messages. */
   fuzz->FuzzBasic();
diff --git a/mojo/public/tools/fuzzers/mojo_parse_message_fuzzer.cc b/mojo/public/tools/fuzzers/mojo_parse_message_fuzzer.cc
index b145959..74691fa 100644
--- a/mojo/public/tools/fuzzers/mojo_parse_message_fuzzer.cc
+++ b/mojo/public/tools/fuzzers/mojo_parse_message_fuzzer.cc
@@ -8,13 +8,13 @@
 #include "base/task/single_thread_task_executor.h"
 #include "base/task/thread_pool/thread_pool_instance.h"
 #include "mojo/core/embedder/embedder.h"
-#include "mojo/public/cpp/bindings/binding.h"
+#include "mojo/public/cpp/bindings/pending_remote.h"
 #include "mojo/public/tools/fuzzers/fuzz_impl.h"
 
 void FuzzMessage(const uint8_t* data, size_t size, base::RunLoop* run) {
-  fuzz::mojom::FuzzInterfacePtr fuzz;
-  auto impl = std::make_unique<FuzzImpl>(MakeRequest(&fuzz));
-  auto router = impl->binding_.RouterForTesting();
+  mojo::PendingRemote<fuzz::mojom::FuzzInterface> fuzz;
+  auto impl = std::make_unique<FuzzImpl>(fuzz.InitWithNewPipeAndPassReceiver());
+  auto router = impl->receiver_.internal_state()->RouterForTesting();
 
   /* Create a mojo message with the appropriate payload size. */
   mojo::Message message(0, 0, size, 0, nullptr);
diff --git a/mojo/public/tools/fuzzers/mojo_parse_message_proto_fuzzer.cc b/mojo/public/tools/fuzzers/mojo_parse_message_proto_fuzzer.cc
index ec76724..303e62a 100644
--- a/mojo/public/tools/fuzzers/mojo_parse_message_proto_fuzzer.cc
+++ b/mojo/public/tools/fuzzers/mojo_parse_message_proto_fuzzer.cc
@@ -11,7 +11,7 @@
 #include "base/task/single_thread_task_executor.h"
 #include "base/task/thread_pool/thread_pool_instance.h"
 #include "mojo/core/embedder/embedder.h"
-#include "mojo/public/cpp/bindings/binding.h"
+#include "mojo/public/cpp/bindings/pending_remote.h"
 #include "mojo/public/tools/fuzzers/fuzz_impl.h"
 #include "mojo/public/tools/fuzzers/mojo_fuzzer.pb.h"
 #include "testing/libfuzzer/proto/lpm_interface.h"
@@ -20,9 +20,9 @@
 
 void FuzzMessage(const MojoFuzzerMessages& mojo_fuzzer_messages,
                  base::RunLoop* run) {
-  fuzz::mojom::FuzzInterfacePtr fuzz;
-  auto impl = std::make_unique<FuzzImpl>(MakeRequest(&fuzz));
-  auto router = impl->binding_.RouterForTesting();
+  mojo::PendingRemote<fuzz::mojom::FuzzInterface> fuzz;
+  auto impl = std::make_unique<FuzzImpl>(fuzz.InitWithNewPipeAndPassReceiver());
+  auto router = impl->receiver_.internal_state()->RouterForTesting();
 
   for (auto& message_str : mojo_fuzzer_messages.messages()) {
     // Create a mojo message with the appropriate payload size.
diff --git a/net/base/features.cc b/net/base/features.cc
index 1224a854..f94fe645 100644
--- a/net/base/features.cc
+++ b/net/base/features.cc
@@ -42,6 +42,9 @@
 const base::Feature kTLS13KeyUpdate{"TLS13KeyUpdate",
                                     base::FEATURE_DISABLED_BY_DEFAULT};
 
+const base::Feature kPostQuantumCECPQ2{"PostQuantumCECPQ2",
+                                       base::FEATURE_DISABLED_BY_DEFAULT};
+
 const base::Feature kNetUnusedIdleSocketTimeout{
     "NetUnusedIdleSocketTimeout", base::FEATURE_DISABLED_BY_DEFAULT};
 
diff --git a/net/base/features.h b/net/base/features.h
index 1e68a63..f0b10453 100644
--- a/net/base/features.h
+++ b/net/base/features.h
@@ -62,6 +62,9 @@
 // servers.
 NET_EXPORT extern const base::Feature kTLS13KeyUpdate;
 
+// Enables CECPQ2, a post-quantum key-agreement, in TLS 1.3 connections.
+NET_EXPORT extern const base::Feature kPostQuantumCECPQ2;
+
 // Changes the timeout after which unused sockets idle sockets are cleaned up.
 NET_EXPORT extern const base::Feature kNetUnusedIdleSocketTimeout;
 
diff --git a/net/socket/ssl_client_socket_impl.cc b/net/socket/ssl_client_socket_impl.cc
index dbb7f97..48af2a1 100644
--- a/net/socket/ssl_client_socket_impl.cc
+++ b/net/socket/ssl_client_socket_impl.cc
@@ -323,6 +323,12 @@
         ssl_ctx_.get(), TLSEXT_cert_compression_brotli,
         nullptr /* compression not supported */, DecompressBrotliCert);
 #endif
+
+    if (base::FeatureList::IsEnabled(features::kPostQuantumCECPQ2)) {
+      static const int kCurves[] = {NID_CECPQ2, NID_X25519,
+                                    NID_X9_62_prime256v1, NID_secp384r1};
+      SSL_CTX_set1_curves(ssl_ctx_.get(), kCurves, base::size(kCurves));
+    }
   }
 
   static int ClientCertRequestCallback(SSL* ssl, void* arg) {
diff --git a/services/device/generic_sensor/platform_sensor_reader_winrt.cc b/services/device/generic_sensor/platform_sensor_reader_winrt.cc
index e568c1a3..94aa8702 100644
--- a/services/device/generic_sensor/platform_sensor_reader_winrt.cc
+++ b/services/device/generic_sensor/platform_sensor_reader_winrt.cc
@@ -126,35 +126,6 @@
   client_ = client;
 }
 
-// static
-template <wchar_t const* runtime_class_id,
-          class ISensorWinrtStatics,
-          class ISensorWinrtClass,
-          class ISensorReadingChangedHandler,
-          class ISensorReadingChangedEventArgs>
-bool PlatformSensorReaderWinrtBase<runtime_class_id,
-                                   ISensorWinrtStatics,
-                                   ISensorWinrtClass,
-                                   ISensorReadingChangedHandler,
-                                   ISensorReadingChangedEventArgs>::
-    IsSensorCreateSuccess(SensorWinrtCreateFailure create_return_code) {
-  switch (create_return_code) {
-    case SensorWinrtCreateFailure::kErrorISensorWinrtStaticsActivationFailed:
-      // Failing to query the default report interval is not a fatal error. The
-      // consumer (PlatformSensorWin) should be able to handle this and return a
-      // default report interval instead.
-      FALLTHROUGH;
-    case SensorWinrtCreateFailure::kOk:
-      return true;
-    case SensorWinrtCreateFailure::kErrorGetDefaultSensorFailed:
-      FALLTHROUGH;
-    case SensorWinrtCreateFailure::kErrorDefaultSensorNull:
-      FALLTHROUGH;
-    case SensorWinrtCreateFailure::kErrorGetMinReportIntervalFailed:
-      return false;
-  }
-}
-
 template <wchar_t const* runtime_class_id,
           class ISensorWinrtStatics,
           class ISensorWinrtClass,
@@ -183,35 +154,42 @@
           class ISensorWinrtClass,
           class ISensorReadingChangedHandler,
           class ISensorReadingChangedEventArgs>
-SensorWinrtCreateFailure
-PlatformSensorReaderWinrtBase<runtime_class_id,
-                              ISensorWinrtStatics,
-                              ISensorWinrtClass,
-                              ISensorReadingChangedHandler,
-                              ISensorReadingChangedEventArgs>::Initialize() {
+bool PlatformSensorReaderWinrtBase<
+    runtime_class_id,
+    ISensorWinrtStatics,
+    ISensorWinrtClass,
+    ISensorReadingChangedHandler,
+    ISensorReadingChangedEventArgs>::Initialize() {
   ComPtr<ISensorWinrtStatics> sensor_statics;
 
   HRESULT hr = get_sensor_factory_callback_.Run(&sensor_statics);
 
-  if (FAILED(hr))
-    return SensorWinrtCreateFailure::kErrorISensorWinrtStaticsActivationFailed;
+  if (FAILED(hr)) {
+    DLOG(ERROR) << "Failed to get sensor activation factory: "
+                << logging::SystemErrorCodeToString(hr);
+    return false;
+  }
 
   hr = sensor_statics->GetDefault(&sensor_);
   base::UmaHistogramSparse("Sensors.Windows.WinRT.Activation.Result", hr);
   if (FAILED(hr)) {
-    return SensorWinrtCreateFailure::kErrorGetDefaultSensorFailed;
+    DLOG(ERROR) << "Failed to query default sensor: "
+                << logging::SystemErrorCodeToString(hr);
+    return false;
   }
 
   // GetDefault() returns null if the sensor does not exist
-  if (!sensor_)
-    return SensorWinrtCreateFailure::kErrorDefaultSensorNull;
+  if (!sensor_) {
+    VLOG(1) << "Sensor does not exist on system";
+    return false;
+  }
 
   minimum_report_interval_ = GetMinimumReportIntervalFromSensor();
 
   if (minimum_report_interval_.is_zero())
-    return SensorWinrtCreateFailure::kErrorGetMinReportIntervalFailed;
+    DLOG(WARNING) << "Failed to get sensor minimum report interval";
 
-  return SensorWinrtCreateFailure::kOk;
+  return true;
 }
 
 template <wchar_t const* runtime_class_id,
@@ -348,7 +326,7 @@
 std::unique_ptr<PlatformSensorReaderWinBase>
 PlatformSensorReaderWinrtLightSensor::Create() {
   auto light_sensor = std::make_unique<PlatformSensorReaderWinrtLightSensor>();
-  if (IsSensorCreateSuccess(light_sensor->Initialize())) {
+  if (light_sensor->Initialize()) {
     return light_sensor;
   }
   return nullptr;
@@ -406,7 +384,7 @@
 PlatformSensorReaderWinrtAccelerometer::Create() {
   auto accelerometer =
       std::make_unique<PlatformSensorReaderWinrtAccelerometer>();
-  if (IsSensorCreateSuccess(accelerometer->Initialize())) {
+  if (accelerometer->Initialize()) {
     return accelerometer;
   }
   return nullptr;
@@ -486,7 +464,7 @@
 std::unique_ptr<PlatformSensorReaderWinBase>
 PlatformSensorReaderWinrtGyrometer::Create() {
   auto gyrometer = std::make_unique<PlatformSensorReaderWinrtGyrometer>();
-  if (IsSensorCreateSuccess(gyrometer->Initialize())) {
+  if (gyrometer->Initialize()) {
     return gyrometer;
   }
   return nullptr;
@@ -565,7 +543,7 @@
 std::unique_ptr<PlatformSensorReaderWinBase>
 PlatformSensorReaderWinrtMagnetometer::Create() {
   auto magnetometer = std::make_unique<PlatformSensorReaderWinrtMagnetometer>();
-  if (IsSensorCreateSuccess(magnetometer->Initialize())) {
+  if (magnetometer->Initialize()) {
     return magnetometer;
   }
   return nullptr;
@@ -642,7 +620,7 @@
 PlatformSensorReaderWinrtAbsOrientationEulerAngles::Create() {
   auto inclinometer =
       std::make_unique<PlatformSensorReaderWinrtAbsOrientationEulerAngles>();
-  if (IsSensorCreateSuccess(inclinometer->Initialize())) {
+  if (inclinometer->Initialize()) {
     return inclinometer;
   }
   return nullptr;
@@ -720,7 +698,7 @@
 PlatformSensorReaderWinrtAbsOrientationQuaternion::Create() {
   auto orientation =
       std::make_unique<PlatformSensorReaderWinrtAbsOrientationQuaternion>();
-  if (IsSensorCreateSuccess(orientation->Initialize())) {
+  if (orientation->Initialize()) {
     return orientation;
   }
   return nullptr;
diff --git a/services/device/generic_sensor/platform_sensor_reader_winrt.h b/services/device/generic_sensor/platform_sensor_reader_winrt.h
index 7736a3d..84c0b85 100644
--- a/services/device/generic_sensor/platform_sensor_reader_winrt.h
+++ b/services/device/generic_sensor/platform_sensor_reader_winrt.h
@@ -32,14 +32,6 @@
       mojom::SensorType type);
 };
 
-enum SensorWinrtCreateFailure {
-  kOk = 0,
-  kErrorISensorWinrtStaticsActivationFailed = 1,
-  kErrorGetDefaultSensorFailed = 2,
-  kErrorDefaultSensorNull = 3,
-  kErrorGetMinReportIntervalFailed = 4
-};
-
 // Base class that contains common helper functions used between all low
 // level sensor types based on the Windows.Devices.Sensors API. Derived
 // classes will specialize the template into a specific sensor. See
@@ -65,11 +57,15 @@
 
   // Allows tests to specify their own implementation of the underlying sensor.
   // This function should be called before Initialize().
-  void InitForTests(GetSensorFactoryFunctor get_sensor_factory_callback) {
+  void InitForTesting(GetSensorFactoryFunctor get_sensor_factory_callback) {
     get_sensor_factory_callback_ = get_sensor_factory_callback;
   }
 
-  SensorWinrtCreateFailure Initialize() WARN_UNUSED_RESULT;
+  // Returns true if the underlying WinRT sensor object is valid, meant
+  // for testing purposes.
+  bool IsUnderlyingWinrtObjectValidForTesting() { return sensor_; }
+
+  bool Initialize() WARN_UNUSED_RESULT;
 
   bool StartSensor(const PlatformSensorConfiguration& configuration) override
       WARN_UNUSED_RESULT;
@@ -80,11 +76,6 @@
   PlatformSensorReaderWinrtBase();
   virtual ~PlatformSensorReaderWinrtBase();
 
-  // Determines if the SensorWinrtCreateFailure code means a WinRT sensor
-  // was successfully created or not.
-  static bool IsSensorCreateSuccess(
-      SensorWinrtCreateFailure create_return_code);
-
   // Derived classes should implement this function to handle sensor specific
   // parsing of the sensor reading.
   virtual HRESULT OnReadingChangedCallback(
diff --git a/services/device/generic_sensor/platform_sensor_reader_winrt_unittests.cc b/services/device/generic_sensor/platform_sensor_reader_winrt_unittests.cc
index de39df4..ac140e1 100644
--- a/services/device/generic_sensor/platform_sensor_reader_winrt_unittests.cc
+++ b/services/device/generic_sensor/platform_sensor_reader_winrt_unittests.cc
@@ -558,23 +558,31 @@
       ABI::Windows::Devices::Sensors::ILightSensorReadingChangedEventArgs,
       ABI::Windows::Devices::Sensors::LightSensorReadingChangedEventArgs>>();
 
+  // Case: sensor was created successfully
   auto sensor = std::make_unique<PlatformSensorReaderWinrtLightSensor>();
-  sensor->InitForTests(base::BindLambdaForTesting(
+  sensor->InitForTesting(base::BindLambdaForTesting(
       [&](ABI::Windows::Devices::Sensors::ILightSensorStatics** sensor_factory)
           -> HRESULT { return fake_sensor_factory.CopyTo(sensor_factory); }));
+  EXPECT_TRUE(sensor->Initialize());
+  EXPECT_TRUE(sensor->IsUnderlyingWinrtObjectValidForTesting());
 
-  EXPECT_EQ(sensor->Initialize(), SensorWinrtCreateFailure::kOk);
-
+  // Case: failed to query sensor
   fake_sensor_factory->SetGetDefaultReturnCode(E_FAIL);
-  EXPECT_EQ(sensor->Initialize(),
-            SensorWinrtCreateFailure::kErrorGetDefaultSensorFailed);
+  EXPECT_FALSE(sensor->Initialize());
+  EXPECT_FALSE(sensor->IsUnderlyingWinrtObjectValidForTesting());
+  fake_sensor_factory->SetGetDefaultReturnCode(S_OK);
 
-  sensor->InitForTests(base::BindLambdaForTesting(
+  // Case: Sensor does not exist on system
+  fake_sensor_factory->fake_sensor_ = nullptr;
+  EXPECT_FALSE(sensor->Initialize());
+  EXPECT_FALSE(sensor->IsUnderlyingWinrtObjectValidForTesting());
+
+  // Case:: failed to activate sensor factory
+  sensor->InitForTesting(base::BindLambdaForTesting(
       [&](ABI::Windows::Devices::Sensors::ILightSensorStatics** sensor_factory)
           -> HRESULT { return E_FAIL; }));
-  EXPECT_EQ(
-      sensor->Initialize(),
-      SensorWinrtCreateFailure::kErrorISensorWinrtStaticsActivationFailed);
+  EXPECT_FALSE(sensor->Initialize());
+  EXPECT_FALSE(sensor->IsUnderlyingWinrtObjectValidForTesting());
 }
 
 // Tests that PlatformSensorReaderWinrtBase returns the right
@@ -590,10 +598,10 @@
   auto fake_sensor = fake_sensor_factory->fake_sensor_;
 
   auto sensor = std::make_unique<PlatformSensorReaderWinrtLightSensor>();
-  sensor->InitForTests(base::BindLambdaForTesting(
+  sensor->InitForTesting(base::BindLambdaForTesting(
       [&](ABI::Windows::Devices::Sensors::ILightSensorStatics** sensor_factory)
           -> HRESULT { return fake_sensor_factory.CopyTo(sensor_factory); }));
-  EXPECT_EQ(sensor->Initialize(), SensorWinrtCreateFailure::kOk);
+  EXPECT_TRUE(sensor->Initialize());
 
   EXPECT_EQ(sensor->GetMinimalReportingInterval().InMilliseconds(),
             kExpectedMinimumReportInterval);
@@ -613,11 +621,10 @@
 
   auto sensor = std::make_unique<PlatformSensorReaderWinrtLightSensor>();
   fake_sensor->SetGetMinimumReportIntervalReturnCode(E_FAIL);
-  sensor->InitForTests(base::BindLambdaForTesting(
+  sensor->InitForTesting(base::BindLambdaForTesting(
       [&](ABI::Windows::Devices::Sensors::ILightSensorStatics** sensor_factory)
           -> HRESULT { return fake_sensor_factory.CopyTo(sensor_factory); }));
-  EXPECT_EQ(sensor->Initialize(),
-            SensorWinrtCreateFailure::kErrorGetMinReportIntervalFailed);
+  EXPECT_TRUE(sensor->Initialize());
 
   EXPECT_EQ(sensor->GetMinimalReportingInterval().InMilliseconds(), 0);
 }
@@ -636,10 +643,10 @@
   auto fake_sensor = fake_sensor_factory->fake_sensor_;
 
   auto sensor = std::make_unique<PlatformSensorReaderWinrtLightSensor>();
-  sensor->InitForTests(base::BindLambdaForTesting(
+  sensor->InitForTesting(base::BindLambdaForTesting(
       [&](ABI::Windows::Devices::Sensors::ILightSensorStatics** sensor_factory)
           -> HRESULT { return fake_sensor_factory.CopyTo(sensor_factory); }));
-  EXPECT_EQ(sensor->Initialize(), SensorWinrtCreateFailure::kOk);
+  EXPECT_TRUE(sensor->Initialize());
 
   auto mock_client = std::make_unique<testing::NiceMock<MockClient>>();
 
@@ -688,10 +695,10 @@
   auto fake_sensor = fake_sensor_factory->fake_sensor_;
 
   auto sensor = std::make_unique<PlatformSensorReaderWinrtLightSensor>();
-  sensor->InitForTests(base::BindLambdaForTesting(
+  sensor->InitForTesting(base::BindLambdaForTesting(
       [&](ABI::Windows::Devices::Sensors::ILightSensorStatics** sensor_factory)
           -> HRESULT { return fake_sensor_factory.CopyTo(sensor_factory); }));
-  EXPECT_EQ(sensor->Initialize(), SensorWinrtCreateFailure::kOk);
+  EXPECT_TRUE(sensor->Initialize());
 
   PlatformSensorConfiguration sensor_config(kExpectedReportFrequencySet);
   EXPECT_TRUE(sensor->StartSensor(sensor_config));
@@ -722,10 +729,10 @@
   auto fake_sensor = fake_sensor_factory->fake_sensor_;
 
   auto sensor = std::make_unique<PlatformSensorReaderWinrtLightSensor>();
-  sensor->InitForTests(base::BindLambdaForTesting(
+  sensor->InitForTesting(base::BindLambdaForTesting(
       [&](ABI::Windows::Devices::Sensors::ILightSensorStatics** sensor_factory)
           -> HRESULT { return fake_sensor_factory.CopyTo(sensor_factory); }));
-  EXPECT_EQ(sensor->Initialize(), SensorWinrtCreateFailure::kOk);
+  EXPECT_TRUE(sensor->Initialize());
 
   PlatformSensorConfiguration sensor_config(kExpectedReportFrequencySet);
   EXPECT_TRUE(sensor->StartSensor(sensor_config));
@@ -748,10 +755,10 @@
   auto fake_sensor = fake_sensor_factory->fake_sensor_;
 
   auto sensor = std::make_unique<PlatformSensorReaderWinrtLightSensor>();
-  sensor->InitForTests(base::BindLambdaForTesting(
+  sensor->InitForTesting(base::BindLambdaForTesting(
       [&](ABI::Windows::Devices::Sensors::ILightSensorStatics** sensor_factory)
           -> HRESULT { return fake_sensor_factory.CopyTo(sensor_factory); }));
-  EXPECT_EQ(sensor->Initialize(), SensorWinrtCreateFailure::kOk);
+  EXPECT_TRUE(sensor->Initialize());
 
   fake_sensor->SetPutReportIntervalReturnCode(E_FAIL);
 
@@ -777,10 +784,10 @@
   auto fake_sensor = fake_sensor_factory->fake_sensor_;
 
   auto sensor = std::make_unique<PlatformSensorReaderWinrtLightSensor>();
-  sensor->InitForTests(base::BindLambdaForTesting(
+  sensor->InitForTesting(base::BindLambdaForTesting(
       [&](ABI::Windows::Devices::Sensors::ILightSensorStatics** sensor_factory)
           -> HRESULT { return fake_sensor_factory.CopyTo(sensor_factory); }));
-  EXPECT_EQ(sensor->Initialize(), SensorWinrtCreateFailure::kOk);
+  EXPECT_TRUE(sensor->Initialize());
 
   PlatformSensorConfiguration sensor_config(kExpectedReportFrequencySet);
   EXPECT_TRUE(sensor->StartSensor(sensor_config));
@@ -803,10 +810,10 @@
   auto fake_sensor = fake_sensor_factory->fake_sensor_;
 
   auto sensor = std::make_unique<PlatformSensorReaderWinrtLightSensor>();
-  sensor->InitForTests(base::BindLambdaForTesting(
+  sensor->InitForTesting(base::BindLambdaForTesting(
       [&](ABI::Windows::Devices::Sensors::ILightSensorStatics** sensor_factory)
           -> HRESULT { return fake_sensor_factory.CopyTo(sensor_factory); }));
-  EXPECT_EQ(sensor->Initialize(), SensorWinrtCreateFailure::kOk);
+  EXPECT_TRUE(sensor->Initialize());
 
   auto mock_client = std::make_unique<testing::NiceMock<MockClient>>();
 
@@ -844,10 +851,10 @@
   auto fake_sensor = fake_sensor_factory->fake_sensor_;
 
   auto sensor = std::make_unique<PlatformSensorReaderWinrtLightSensor>();
-  sensor->InitForTests(base::BindLambdaForTesting(
+  sensor->InitForTesting(base::BindLambdaForTesting(
       [&](ABI::Windows::Devices::Sensors::ILightSensorStatics** sensor_factory)
           -> HRESULT { return fake_sensor_factory.CopyTo(sensor_factory); }));
-  EXPECT_EQ(sensor->Initialize(), SensorWinrtCreateFailure::kOk);
+  EXPECT_TRUE(sensor->Initialize());
 
   auto mock_client = std::make_unique<testing::NiceMock<MockClient>>();
 
@@ -886,12 +893,12 @@
   auto fake_sensor = fake_sensor_factory->fake_sensor_;
 
   auto sensor = std::make_unique<PlatformSensorReaderWinrtAccelerometer>();
-  sensor->InitForTests(base::BindLambdaForTesting(
+  sensor->InitForTesting(base::BindLambdaForTesting(
       [&](ABI::Windows::Devices::Sensors::IAccelerometerStatics**
               sensor_factory) -> HRESULT {
         return fake_sensor_factory.CopyTo(sensor_factory);
       }));
-  EXPECT_EQ(sensor->Initialize(), SensorWinrtCreateFailure::kOk);
+  EXPECT_TRUE(sensor->Initialize());
 
   auto mock_client = std::make_unique<testing::NiceMock<MockClient>>();
   EXPECT_CALL(*mock_client, OnReadingUpdated(::testing::_))
@@ -927,12 +934,12 @@
   auto fake_sensor = fake_sensor_factory->fake_sensor_;
 
   auto sensor = std::make_unique<PlatformSensorReaderWinrtAccelerometer>();
-  sensor->InitForTests(base::BindLambdaForTesting(
+  sensor->InitForTesting(base::BindLambdaForTesting(
       [&](ABI::Windows::Devices::Sensors::IAccelerometerStatics**
               sensor_factory) -> HRESULT {
         return fake_sensor_factory.CopyTo(sensor_factory);
       }));
-  EXPECT_EQ(sensor->Initialize(), SensorWinrtCreateFailure::kOk);
+  EXPECT_TRUE(sensor->Initialize());
 
   auto mock_client = std::make_unique<testing::NiceMock<MockClient>>();
   sensor->SetClient(mock_client.get());
@@ -976,10 +983,10 @@
   auto fake_sensor = fake_sensor_factory->fake_sensor_;
 
   auto sensor = std::make_unique<PlatformSensorReaderWinrtGyrometer>();
-  sensor->InitForTests(base::BindLambdaForTesting(
+  sensor->InitForTesting(base::BindLambdaForTesting(
       [&](ABI::Windows::Devices::Sensors::IGyrometerStatics** sensor_factory)
           -> HRESULT { return fake_sensor_factory.CopyTo(sensor_factory); }));
-  EXPECT_EQ(sensor->Initialize(), SensorWinrtCreateFailure::kOk);
+  EXPECT_TRUE(sensor->Initialize());
 
   auto mock_client = std::make_unique<testing::NiceMock<MockClient>>();
   EXPECT_CALL(*mock_client, OnReadingUpdated(::testing::_))
@@ -1013,10 +1020,10 @@
   auto fake_sensor = fake_sensor_factory->fake_sensor_;
 
   auto sensor = std::make_unique<PlatformSensorReaderWinrtGyrometer>();
-  sensor->InitForTests(base::BindLambdaForTesting(
+  sensor->InitForTesting(base::BindLambdaForTesting(
       [&](ABI::Windows::Devices::Sensors::IGyrometerStatics** sensor_factory)
           -> HRESULT { return fake_sensor_factory.CopyTo(sensor_factory); }));
-  EXPECT_EQ(sensor->Initialize(), SensorWinrtCreateFailure::kOk);
+  EXPECT_TRUE(sensor->Initialize());
 
   auto mock_client = std::make_unique<testing::NiceMock<MockClient>>();
   sensor->SetClient(mock_client.get());
@@ -1060,10 +1067,10 @@
   auto fake_sensor = fake_sensor_factory->fake_sensor_;
 
   auto sensor = std::make_unique<PlatformSensorReaderWinrtMagnetometer>();
-  sensor->InitForTests(base::BindLambdaForTesting(
+  sensor->InitForTesting(base::BindLambdaForTesting(
       [&](ABI::Windows::Devices::Sensors::IMagnetometerStatics** sensor_factory)
           -> HRESULT { return fake_sensor_factory.CopyTo(sensor_factory); }));
-  EXPECT_EQ(sensor->Initialize(), SensorWinrtCreateFailure::kOk);
+  EXPECT_TRUE(sensor->Initialize());
 
   auto mock_client = std::make_unique<testing::NiceMock<MockClient>>();
   EXPECT_CALL(*mock_client, OnReadingUpdated(::testing::_))
@@ -1097,10 +1104,10 @@
   auto fake_sensor = fake_sensor_factory->fake_sensor_;
 
   auto sensor = std::make_unique<PlatformSensorReaderWinrtMagnetometer>();
-  sensor->InitForTests(base::BindLambdaForTesting(
+  sensor->InitForTesting(base::BindLambdaForTesting(
       [&](ABI::Windows::Devices::Sensors::IMagnetometerStatics** sensor_factory)
           -> HRESULT { return fake_sensor_factory.CopyTo(sensor_factory); }));
-  EXPECT_EQ(sensor->Initialize(), SensorWinrtCreateFailure::kOk);
+  EXPECT_TRUE(sensor->Initialize());
 
   auto mock_client = std::make_unique<testing::NiceMock<MockClient>>();
   sensor->SetClient(mock_client.get());
@@ -1145,10 +1152,10 @@
 
   auto sensor =
       std::make_unique<PlatformSensorReaderWinrtAbsOrientationEulerAngles>();
-  sensor->InitForTests(base::BindLambdaForTesting(
+  sensor->InitForTesting(base::BindLambdaForTesting(
       [&](ABI::Windows::Devices::Sensors::IInclinometerStatics** sensor_factory)
           -> HRESULT { return fake_sensor_factory.CopyTo(sensor_factory); }));
-  EXPECT_EQ(sensor->Initialize(), SensorWinrtCreateFailure::kOk);
+  EXPECT_TRUE(sensor->Initialize());
 
   auto mock_client = std::make_unique<testing::NiceMock<MockClient>>();
   EXPECT_CALL(*mock_client, OnReadingUpdated(::testing::_))
@@ -1183,10 +1190,10 @@
 
   auto sensor =
       std::make_unique<PlatformSensorReaderWinrtAbsOrientationEulerAngles>();
-  sensor->InitForTests(base::BindLambdaForTesting(
+  sensor->InitForTesting(base::BindLambdaForTesting(
       [&](ABI::Windows::Devices::Sensors::IInclinometerStatics** sensor_factory)
           -> HRESULT { return fake_sensor_factory.CopyTo(sensor_factory); }));
-  EXPECT_EQ(sensor->Initialize(), SensorWinrtCreateFailure::kOk);
+  EXPECT_TRUE(sensor->Initialize());
 
   auto mock_client = std::make_unique<testing::NiceMock<MockClient>>();
   sensor->SetClient(mock_client.get());
@@ -1233,12 +1240,12 @@
 
   auto sensor =
       std::make_unique<PlatformSensorReaderWinrtAbsOrientationQuaternion>();
-  sensor->InitForTests(base::BindLambdaForTesting(
+  sensor->InitForTesting(base::BindLambdaForTesting(
       [&](ABI::Windows::Devices::Sensors::IOrientationSensorStatics**
               sensor_factory) -> HRESULT {
         return fake_sensor_factory.CopyTo(sensor_factory);
       }));
-  EXPECT_EQ(sensor->Initialize(), SensorWinrtCreateFailure::kOk);
+  EXPECT_TRUE(sensor->Initialize());
 
   auto mock_client = std::make_unique<testing::NiceMock<MockClient>>();
   EXPECT_CALL(*mock_client, OnReadingUpdated(::testing::_))
@@ -1276,12 +1283,12 @@
 
   auto sensor =
       std::make_unique<PlatformSensorReaderWinrtAbsOrientationQuaternion>();
-  sensor->InitForTests(base::BindLambdaForTesting(
+  sensor->InitForTesting(base::BindLambdaForTesting(
       [&](ABI::Windows::Devices::Sensors::IOrientationSensorStatics**
               sensor_factory) -> HRESULT {
         return fake_sensor_factory.CopyTo(sensor_factory);
       }));
-  EXPECT_EQ(sensor->Initialize(), SensorWinrtCreateFailure::kOk);
+  EXPECT_TRUE(sensor->Initialize());
 
   auto mock_client = std::make_unique<testing::NiceMock<MockClient>>();
   sensor->SetClient(mock_client.get());
@@ -1311,10 +1318,10 @@
   auto fake_sensor = fake_sensor_factory->fake_sensor_;
 
   auto sensor = std::make_unique<PlatformSensorReaderWinrtLightSensor>();
-  sensor->InitForTests(base::BindLambdaForTesting(
+  sensor->InitForTesting(base::BindLambdaForTesting(
       [&](ABI::Windows::Devices::Sensors::ILightSensorStatics** sensor_factory)
           -> HRESULT { return fake_sensor_factory.CopyTo(sensor_factory); }));
-  EXPECT_EQ(sensor->Initialize(), SensorWinrtCreateFailure::kOk);
+  EXPECT_TRUE(sensor->Initialize());
 
   auto mock_client = std::make_unique<testing::NiceMock<MockClient>>();
 
@@ -1367,12 +1374,12 @@
   auto fake_sensor = fake_sensor_factory->fake_sensor_;
 
   auto sensor = std::make_unique<PlatformSensorReaderWinrtAccelerometer>();
-  sensor->InitForTests(base::BindLambdaForTesting(
+  sensor->InitForTesting(base::BindLambdaForTesting(
       [&](ABI::Windows::Devices::Sensors::IAccelerometerStatics**
               sensor_factory) -> HRESULT {
         return fake_sensor_factory.CopyTo(sensor_factory);
       }));
-  EXPECT_EQ(sensor->Initialize(), SensorWinrtCreateFailure::kOk);
+  EXPECT_TRUE(sensor->Initialize());
 
   auto mock_client = std::make_unique<testing::NiceMock<MockClient>>();
 
@@ -1437,10 +1444,10 @@
   auto fake_sensor = fake_sensor_factory->fake_sensor_;
 
   auto sensor = std::make_unique<PlatformSensorReaderWinrtGyrometer>();
-  sensor->InitForTests(base::BindLambdaForTesting(
+  sensor->InitForTesting(base::BindLambdaForTesting(
       [&](ABI::Windows::Devices::Sensors::IGyrometerStatics** sensor_factory)
           -> HRESULT { return fake_sensor_factory.CopyTo(sensor_factory); }));
-  EXPECT_EQ(sensor->Initialize(), SensorWinrtCreateFailure::kOk);
+  EXPECT_TRUE(sensor->Initialize());
 
   auto mock_client = std::make_unique<testing::NiceMock<MockClient>>();
 
@@ -1505,10 +1512,10 @@
   auto fake_sensor = fake_sensor_factory->fake_sensor_;
 
   auto sensor = std::make_unique<PlatformSensorReaderWinrtMagnetometer>();
-  sensor->InitForTests(base::BindLambdaForTesting(
+  sensor->InitForTesting(base::BindLambdaForTesting(
       [&](ABI::Windows::Devices::Sensors::IMagnetometerStatics** sensor_factory)
           -> HRESULT { return fake_sensor_factory.CopyTo(sensor_factory); }));
-  EXPECT_EQ(sensor->Initialize(), SensorWinrtCreateFailure::kOk);
+  EXPECT_TRUE(sensor->Initialize());
 
   auto mock_client = std::make_unique<testing::NiceMock<MockClient>>();
 
@@ -1580,10 +1587,10 @@
 
   auto sensor =
       std::make_unique<PlatformSensorReaderWinrtAbsOrientationEulerAngles>();
-  sensor->InitForTests(base::BindLambdaForTesting(
+  sensor->InitForTesting(base::BindLambdaForTesting(
       [&](ABI::Windows::Devices::Sensors::IInclinometerStatics** sensor_factory)
           -> HRESULT { return fake_sensor_factory.CopyTo(sensor_factory); }));
-  EXPECT_EQ(sensor->Initialize(), SensorWinrtCreateFailure::kOk);
+  EXPECT_TRUE(sensor->Initialize());
 
   auto mock_client = std::make_unique<testing::NiceMock<MockClient>>();
 
@@ -1665,12 +1672,12 @@
 
   auto sensor =
       std::make_unique<PlatformSensorReaderWinrtAbsOrientationQuaternion>();
-  sensor->InitForTests(base::BindLambdaForTesting(
+  sensor->InitForTesting(base::BindLambdaForTesting(
       [&](ABI::Windows::Devices::Sensors::IOrientationSensorStatics**
               sensor_factory) -> HRESULT {
         return fake_sensor_factory.CopyTo(sensor_factory);
       }));
-  EXPECT_EQ(sensor->Initialize(), SensorWinrtCreateFailure::kOk);
+  EXPECT_TRUE(sensor->Initialize());
 
   auto mock_client = std::make_unique<testing::NiceMock<MockClient>>();
 
@@ -1728,13 +1735,13 @@
       ABI::Windows::Devices::Sensors::LightSensorReadingChangedEventArgs>>();
 
   auto sensor = std::make_unique<PlatformSensorReaderWinrtLightSensor>();
-  sensor->InitForTests(base::BindLambdaForTesting(
+  sensor->InitForTesting(base::BindLambdaForTesting(
       [&](ABI::Windows::Devices::Sensors::ILightSensorStatics** sensor_factory)
           -> HRESULT { return fake_sensor_factory.CopyTo(sensor_factory); }));
   base::HistogramTester histogram_tester;
 
   // Trigger S_OK
-  EXPECT_EQ(sensor->Initialize(), SensorWinrtCreateFailure::kOk);
+  EXPECT_TRUE(sensor->Initialize());
 
   EXPECT_EQ(histogram_tester.GetBucketCount(
                 "Sensors.Windows.WinRT.Activation.Result", S_OK),
@@ -1742,15 +1749,13 @@
 
   // Trigger E_ACCESSDENIED twice
   fake_sensor_factory->SetGetDefaultReturnCode(E_ACCESSDENIED);
-  EXPECT_EQ(sensor->Initialize(),
-            SensorWinrtCreateFailure::kErrorGetDefaultSensorFailed);
+  EXPECT_FALSE(sensor->Initialize());
 
   EXPECT_EQ(histogram_tester.GetBucketCount(
                 "Sensors.Windows.WinRT.Activation.Result", E_ACCESSDENIED),
             1);
 
-  EXPECT_EQ(sensor->Initialize(),
-            SensorWinrtCreateFailure::kErrorGetDefaultSensorFailed);
+  EXPECT_FALSE(sensor->Initialize());
 
   EXPECT_EQ(histogram_tester.GetBucketCount(
                 "Sensors.Windows.WinRT.Activation.Result", E_ACCESSDENIED),
@@ -1773,10 +1778,10 @@
   auto fake_sensor = fake_sensor_factory->fake_sensor_;
 
   auto sensor = std::make_unique<PlatformSensorReaderWinrtLightSensor>();
-  sensor->InitForTests(base::BindLambdaForTesting(
+  sensor->InitForTesting(base::BindLambdaForTesting(
       [&](ABI::Windows::Devices::Sensors::ILightSensorStatics** sensor_factory)
           -> HRESULT { return fake_sensor_factory.CopyTo(sensor_factory); }));
-  EXPECT_EQ(sensor->Initialize(), SensorWinrtCreateFailure::kOk);
+  EXPECT_TRUE(sensor->Initialize());
   base::HistogramTester histogram_tester;
 
   // Trigger S_OK
@@ -1823,10 +1828,10 @@
   auto fake_sensor = fake_sensor_factory->fake_sensor_;
 
   auto sensor = std::make_unique<PlatformSensorReaderWinrtLightSensor>();
-  sensor->InitForTests(base::BindLambdaForTesting(
+  sensor->InitForTesting(base::BindLambdaForTesting(
       [&](ABI::Windows::Devices::Sensors::ILightSensorStatics** sensor_factory)
           -> HRESULT { return fake_sensor_factory.CopyTo(sensor_factory); }));
-  EXPECT_EQ(sensor->Initialize(), SensorWinrtCreateFailure::kOk);
+  EXPECT_TRUE(sensor->Initialize());
   base::HistogramTester histogram_tester;
 
   // Trigger E_UNEXPECTED
diff --git a/services/network/cors/cors_url_loader.cc b/services/network/cors/cors_url_loader.cc
index 1d8339b..53e8891 100644
--- a/services/network/cors/cors_url_loader.cc
+++ b/services/network/cors/cors_url_loader.cc
@@ -98,7 +98,6 @@
       options_(options),
       delete_callback_(std::move(delete_callback)),
       network_loader_factory_(network_loader_factory),
-      network_client_binding_(this),
       request_(resource_request),
       forwarding_client_(std::move(client)),
       traffic_annotation_(traffic_annotation),
@@ -114,9 +113,9 @@
 }
 
 CorsURLLoader::~CorsURLLoader() {
-  // Close pipes first to ignore possible subsequent callback invocations
-  // cased by |network_loader_|
-  network_client_binding_.Close();
+  // Reset pipes first to ignore possible subsequent callback invocations
+  // caused by |network_loader_|
+  network_client_receiver_.reset();
 }
 
 void CorsURLLoader::Start() {
@@ -217,7 +216,7 @@
       (!original_fetch_cors_flag && fetch_cors_flag_) ||
       (fetch_cors_flag_ && original_method != request_.method)) {
     DCHECK_NE(request_.mode, mojom::RequestMode::kNoCors);
-    network_client_binding_.Unbind();
+    network_client_receiver_.reset();
     StartRequest();
     return;
   }
@@ -491,10 +490,10 @@
           : mojom::CredentialsMode::kOmit;
 
   mojom::URLLoaderClientPtr network_client;
-  network_client_binding_.Bind(mojo::MakeRequest(&network_client));
+  network_client_receiver_.Bind(mojo::MakeRequest(&network_client));
   // Binding |this| as an unretained pointer is safe because
-  // |network_client_binding_| shares this object's lifetime.
-  network_client_binding_.set_connection_error_handler(
+  // |network_client_receiver_| shares this object's lifetime.
+  network_client_receiver_.set_disconnect_handler(
       base::BindOnce(&CorsURLLoader::OnMojoDisconnect, base::Unretained(this)));
   network_loader_factory_->CreateLoaderAndStart(
       mojo::MakeRequest(&network_loader_), routing_id_, request_id_, options_,
diff --git a/services/network/cors/cors_url_loader.h b/services/network/cors/cors_url_loader.h
index e3da283..8299d05d 100644
--- a/services/network/cors/cors_url_loader.h
+++ b/services/network/cors/cors_url_loader.h
@@ -128,7 +128,7 @@
 
   // For the actual request.
   mojom::URLLoaderPtr network_loader_;
-  mojo::Binding<mojom::URLLoaderClient> network_client_binding_;
+  mojo::Receiver<mojom::URLLoaderClient> network_client_receiver_{this};
   ResourceRequest request_;
 
   // To be a URLLoader for the client.
diff --git a/services/network/public/cpp/content_security_policy.cc b/services/network/public/cpp/content_security_policy.cc
index 0181a63d..b86517e 100644
--- a/services/network/public/cpp/content_security_policy.cc
+++ b/services/network/public/cpp/content_security_policy.cc
@@ -155,81 +155,67 @@
 
 // Parses an ancestor source expression.
 // https://www.w3.org/TR/CSP3/#grammardef-ancestor-source
-base::Optional<mojom::CSPSourcePtr> ParseAncestorSource(
-    base::StringPiece source) {
-  if (base::EqualsCaseInsensitiveASCII(source, "'none'"))
-    return base::nullopt;
+//
+// Return false on errors.
+bool ParseAncestorSource(base::StringPiece expression,
+                         mojom::CSPSource* csp_source) {
+  // TODO(arthursonzogni): Blink reports an invalid source expression when
+  // 'none' is parsed here.
+  if (base::EqualsCaseInsensitiveASCII(expression, "'none'"))
+    return false;
 
-  mojom::CSPSource csp_source;
-
-  if (base::EqualsCaseInsensitiveASCII(source, "*")) {
-    csp_source.is_host_wildcard = true;
-    return csp_source.Clone();
-  }
-
-  if (base::EqualsCaseInsensitiveASCII(source, "'self'")) {
-    csp_source.allow_self = true;
-    return csp_source.Clone();
-  }
-
-  size_t position = source.find_first_of(":/");
-  if (position != std::string::npos && source[position] == ':') {
+  size_t position = expression.find_first_of(":/");
+  if (position != std::string::npos && expression[position] == ':') {
     // scheme:
     //       ^
-    if (position + 1 == source.size()) {
-      if (ParseScheme(source.substr(0, position), &csp_source))
-        return csp_source.Clone();
-      return base::nullopt;
-    }
+    if (position + 1 == expression.size())
+      return ParseScheme(expression.substr(0, position), csp_source);
 
-    if (source[position + 1] == '/') {
+    if (expression[position + 1] == '/') {
       // scheme://
       //       ^
-      if (position + 2 >= source.size() || source[position + 2] != '/')
-        return base::nullopt;
-      if (!ParseScheme(source.substr(0, position), &csp_source))
-        return base::nullopt;
-      source = source.substr(position + 3);
-      position = source.find_first_of(":/");
+      if (position + 2 >= expression.size() || expression[position + 2] != '/')
+        return false;
+      if (!ParseScheme(expression.substr(0, position), csp_source))
+        return false;
+      expression = expression.substr(position + 3);
+      position = expression.find_first_of(":/");
     }
   }
 
   // host
   //     ^
-  if (!ParseHost(source.substr(0, position), &csp_source))
-    return base::nullopt;
+  if (!ParseHost(expression.substr(0, position), csp_source))
+    return false;
 
   // If there's nothing more to parse (no port or path specified), return.
   if (position == std::string::npos)
-    return csp_source.Clone();
+    return true;
 
-  source = source.substr(position);
+  expression = expression.substr(position);
 
   // :\d*
   // ^
-  if (source[0] == ':') {
-    size_t port_end = source.find_first_of("/");
-    base::StringPiece port = source.substr(
+  if (expression[0] == ':') {
+    size_t port_end = expression.find_first_of("/");
+    base::StringPiece port = expression.substr(
         1, port_end == std::string::npos ? std::string::npos : port_end - 1);
-    if (!ParsePort(port, &csp_source))
-      return base::nullopt;
+    if (!ParsePort(port, csp_source))
+      return false;
     if (port_end == std::string::npos)
-      return csp_source.Clone();
+      return true;
 
-    source = source.substr(port_end);
+    expression = expression.substr(port_end);
   }
 
   // /
   // ^
-  if (!source.empty() && !ParsePath(source, &csp_source))
-    return base::nullopt;
-
-  return csp_source.Clone();
+  return expression.empty() || ParsePath(expression, csp_source);
 }
 
 // Parse ancestor-source-list grammar.
 // https://www.w3.org/TR/CSP3/#directive-frame-ancestors
-base::Optional<mojom::CSPSourceListPtr> ParseFrameAncestorsDirective(
+mojom::CSPSourceListPtr ParseFrameAncestorsDirective(
     base::StringPiece frame_ancestors_value) {
   base::StringPiece value = base::TrimString(
       frame_ancestors_value, base::kWhitespaceASCII, base::TRIM_ALL);
@@ -237,20 +223,36 @@
   std::vector<mojom::CSPSourcePtr> sources;
 
   if (frame_ancestors_value.empty())
-    return base::nullopt;
+    return {};
+
+  auto directive = mojom::CSPSourceList::New();
 
   if (base::EqualsCaseInsensitiveASCII(value, "'none'"))
-    return mojom::CSPSourceList::New(std::move(sources));
+    return directive;
 
-  for (const auto& source : base::SplitStringPiece(
+  for (const auto& expression : base::SplitStringPiece(
            value, " ", base::TRIM_WHITESPACE, base::SPLIT_WANT_NONEMPTY)) {
-    if (auto csp_source = ParseAncestorSource(source))
-      sources.push_back(std::move(*csp_source));
-    else
-      return base::nullopt;
+    if (base::EqualsCaseInsensitiveASCII(expression, "'self'")) {
+      directive->allow_self = true;
+      continue;
+    }
+
+    if (base::EqualsCaseInsensitiveASCII(expression, "*")) {
+      directive->allow_star = true;
+      continue;
+    }
+
+    auto csp_source = mojom::CSPSource::New();
+    if (ParseAncestorSource(expression, csp_source.get())) {
+      directive->sources.push_back(std::move(csp_source));
+      continue;
+    }
+
+    // Parsing error.
+    return {};
   }
 
-  return mojom::CSPSourceList::New(std::move(sources));
+  return directive;
 }
 
 // Parses a reporting directive.
@@ -361,10 +363,8 @@
   if (content_security_policy_ptr_->frame_ancestors)
     return true;
 
-  if (auto parsed_frame_ancestors =
-          ParseFrameAncestorsDirective(frame_ancestors_value)) {
-    content_security_policy_ptr_->frame_ancestors =
-        std::move(*parsed_frame_ancestors);
+  if (auto directive = ParseFrameAncestorsDirective(frame_ancestors_value)) {
+    content_security_policy_ptr_->frame_ancestors = std::move(directive);
     return true;
   }
 
diff --git a/services/network/public/cpp/content_security_policy_unittest.cc b/services/network/public/cpp/content_security_policy_unittest.cc
index d11a3d1..a759cf5 100644
--- a/services/network/public/cpp/content_security_policy_unittest.cc
+++ b/services/network/public/cpp/content_security_policy_unittest.cc
@@ -12,17 +12,17 @@
 namespace {
 
 struct ExpectedResult {
-  size_t size;
   struct ParsedSource {
     std::string scheme;
     std::string host;
-    int port;
-    std::string path;
-    bool is_host_wildcard;
-    bool is_port_wildcard;
-    bool allow_self;
+    int port = url::PORT_UNSPECIFIED;
+    std::string path = "";
+    bool is_host_wildcard = false;
+    bool is_port_wildcard = false;
   };
   std::vector<ParsedSource> parsed_sources;
+  bool allow_self = false;
+  bool allow_star = false;
 };
 
 struct TestData {
@@ -48,7 +48,8 @@
     return;
   }
   auto& frame_ancestors = policy.content_security_policy_ptr()->frame_ancestors;
-  EXPECT_EQ(frame_ancestors->sources.size(), expected_result->size);
+  EXPECT_EQ(frame_ancestors->sources.size(),
+            expected_result->parsed_sources.size());
   for (size_t i = 0; i < expected_result->parsed_sources.size(); i++) {
     EXPECT_EQ(frame_ancestors->sources[i]->scheme,
               expected_result->parsed_sources[i].scheme);
@@ -62,9 +63,9 @@
               expected_result->parsed_sources[i].is_host_wildcard);
     EXPECT_EQ(frame_ancestors->sources[i]->is_port_wildcard,
               expected_result->parsed_sources[i].is_port_wildcard);
-    EXPECT_EQ(frame_ancestors->sources[i]->allow_self,
-              expected_result->parsed_sources[i].allow_self);
   }
+  EXPECT_EQ(frame_ancestors->allow_self, expected_result->allow_self);
+  EXPECT_EQ(frame_ancestors->allow_star, expected_result->allow_star);
 }
 
 }  // namespace
@@ -76,62 +77,54 @@
       {":"},
 
       // First character is alpha/non-alpha.
-      {"a:", {1, {{"a", "", url::PORT_UNSPECIFIED, "", false, false, false}}}},
+      {"a:", {{{"a", ""}}}},
       {"1ba:"},
       {"-:"},
 
       // Remaining characters.
-      {"abcd:",
-       {1, {{"abcd", "", url::PORT_UNSPECIFIED, "", false, false, false}}}},
-      {"a123:",
-       {1, {{"a123", "", url::PORT_UNSPECIFIED, "", false, false, false}}}},
-      {"a+-:",
-       {1, {{"a+-", "", url::PORT_UNSPECIFIED, "", false, false, false}}}},
-      {"a1+-:",
-       {1, {{"a1+-", "", url::PORT_UNSPECIFIED, "", false, false, false}}}},
+      {"abcd:", {{{"abcd", ""}}}},
+      {"a123:", {{{"a123", ""}}}},
+      {"a+-:", {{{"a+-", ""}}}},
+      {"a1+-:", {{{"a1+-", ""}}}},
 
       // Invalid character.
       {"wrong_scheme"},
+      {"wrong_scheme://"},
 
       // Parse host.
-      // Wildcards.
-      {"*", {1, {{"", "", url::PORT_UNSPECIFIED, "", true, false, false}}}},
       {"*."},
-      {"*.a", {1, {{"", "a", url::PORT_UNSPECIFIED, "", true, false, false}}}},
+      {"*.a", {{{"", "a", url::PORT_UNSPECIFIED, "", true, false}}}},
       {"a.*"},
       {"a.*.b"},
       {"*a"},
 
       // Dot separation.
-      {"a", {1, {{"", "a", url::PORT_UNSPECIFIED, "", false, false, false}}}},
-      {"a.b.c",
-       {1, {{"", "a.b.c", url::PORT_UNSPECIFIED, "", false, false, false}}}},
+      {"a", {{{"", "a"}}}},
+      {"a.b.c", {{{"", "a.b.c"}}}},
       {"a.b."},
       {".b.c"},
       {"a..c"},
 
       // Valid/Invalid characters.
-      {"az09-",
-       {1, {{"", "az09-", url::PORT_UNSPECIFIED, "", false, false, false}}}},
+      {"az09-", {{{"", "az09-"}}}},
       {"+"},
 
       // Strange host.
-      {"---.com",
-       {1, {{"", "---.com", url::PORT_UNSPECIFIED, "", false, false, false}}}},
+      {"---.com", {{{"", "---.com"}}}},
 
       // Parse port.
       // Empty port.
       {"scheme://host:"},
 
       // Common case.
-      {"a:80", {1, {{"", "a", 80, "", false, false, false}}}},
+      {"a:80", {{{"", "a", 80, ""}}}},
 
       // Wildcard port.
-      {"a:*", {1, {{"", "a", url::PORT_UNSPECIFIED, "", false, true, false}}}},
+      {"a:*", {{{"", "a", url::PORT_UNSPECIFIED, "", false, true}}}},
 
       // Leading zeroes.
-      {"a:000", {1, {{"", "a", 0, "", false, false, false}}}},
-      {"a:0", {1, {{"", "a", 0, "", false, false, false}}}},
+      {"a:000", {{{"", "a", 0, ""}}}},
+      {"a:0", {{{"", "a", 0, ""}}}},
 
       // Invalid chars.
       {"a:-1"},
@@ -140,47 +133,33 @@
       // Parse path.
       // Encoded.
       {"example.com/%48%65%6c%6c%6f%20%57%6f%72%6c%64",
-       {1,
-        {{"", "example.com", url::PORT_UNSPECIFIED, "/Hello World", false,
-          false, false}}}},
+       {{{"", "example.com", url::PORT_UNSPECIFIED, "/Hello World"}}}},
+
+      // Special keyword.
+      {"'none'", {{}, false, false}},
+      {"'self'", {{}, true, false}},
+      {"*", {{}, false, true}},
+
+      // Invalid 'none'
+      {"example.com 'none'"},
 
       // Other.
-      {"*:*", {1, {{"", "", url::PORT_UNSPECIFIED, "", true, true, false}}}},
-      {"http:",
-       {1, {{"http", "", url::PORT_UNSPECIFIED, "", false, false, false}}}},
-      {"https://*",
-       {1, {{"https", "", url::PORT_UNSPECIFIED, "", true, false, false}}}},
+      {"*:*", {{{"", "", url::PORT_UNSPECIFIED, "", true, true}}}},
+      {"http:", {{{"http", ""}}}},
+      {"https://*", {{{"https", "", url::PORT_UNSPECIFIED, "", true}}}},
       {"http:/example.com"},
       {"http://"},
-      {"example.com",
-       {1,
-        {{"", "example.com", url::PORT_UNSPECIFIED, "", false, false, false}}}},
+      {"example.com", {{{"", "example.com"}}}},
       {"example.com/path",
-       {1,
-        {{"", "example.com", url::PORT_UNSPECIFIED, "/path", false, false,
-          false}}}},
-      {"https://example.com",
-       {1,
-        {{"https", "example.com", url::PORT_UNSPECIFIED, "", false, false,
-          false}}}},
+       {{{"", "example.com", url::PORT_UNSPECIFIED, "/path"}}}},
+      {"https://example.com", {{{"https", "example.com"}}}},
       {"https://example.com/path",
-       {1,
-        {{"https", "example.com", url::PORT_UNSPECIFIED, "/path", false, false,
-          false}}}},
-      {"https://example.com:1234",
-       {1, {{"https", "example.com", 1234, "", false, false, false}}}},
+       {{{"https", "example.com", url::PORT_UNSPECIFIED, "/path"}}}},
+      {"https://example.com:1234", {{{"https", "example.com", 1234, ""}}}},
       {"https://example.com:2345/some/path",
-       {1,
-        {{"https", "example.com", 2345, "/some/path", false, false, false}}}},
-      {"example.com example.org",
-       {2,
-        {{"", "example.com", url::PORT_UNSPECIFIED, "", false, false, false},
-         {"", "example.org", url::PORT_UNSPECIFIED, "", false, false, false}}}},
+       {{{"https", "example.com", 2345, "/some/path"}}}},
+      {"example.com example.org", {{{"", "example.com"}, {"", "example.org"}}}},
       {"about:blank"},
-      {"'none'", {0, {}}},
-      {"'self'",
-       {1, {{"", "", url::PORT_UNSPECIFIED, "", false, false, true}}}},
-      {"example.com 'none'"},
       {""},
   };
 
@@ -208,7 +187,7 @@
     EXPECT_EQ(frame_ancestors->sources[0]->path, "");
     EXPECT_EQ(frame_ancestors->sources[0]->is_host_wildcard, false);
     EXPECT_EQ(frame_ancestors->sources[0]->is_port_wildcard, false);
-    EXPECT_EQ(frame_ancestors->sources[0]->allow_self, false);
+    EXPECT_EQ(frame_ancestors->allow_self, false);
   }
 
   // Skip the first directive, which is not frame-ancestors.
@@ -230,7 +209,8 @@
     EXPECT_EQ(frame_ancestors->sources[0]->path, "");
     EXPECT_EQ(frame_ancestors->sources[0]->is_host_wildcard, false);
     EXPECT_EQ(frame_ancestors->sources[0]->is_port_wildcard, false);
-    EXPECT_EQ(frame_ancestors->sources[0]->allow_self, false);
+    EXPECT_EQ(frame_ancestors->allow_self, false);
+    EXPECT_EQ(frame_ancestors->allow_star, false);
   }
 
   // Multiple CSP headers with multiple frame-ancestors directives present. Only
@@ -252,7 +232,8 @@
     EXPECT_EQ(frame_ancestors->sources[0]->path, "");
     EXPECT_EQ(frame_ancestors->sources[0]->is_host_wildcard, false);
     EXPECT_EQ(frame_ancestors->sources[0]->is_port_wildcard, false);
-    EXPECT_EQ(frame_ancestors->sources[0]->allow_self, false);
+    EXPECT_EQ(frame_ancestors->allow_self, false);
+    EXPECT_EQ(frame_ancestors->allow_star, false);
   }
 
   // Multiple CSP headers separated by ',' (RFC2616 section 4.2).
@@ -274,7 +255,8 @@
     EXPECT_EQ(frame_ancestors->sources[0]->path, "");
     EXPECT_EQ(frame_ancestors->sources[0]->is_host_wildcard, false);
     EXPECT_EQ(frame_ancestors->sources[0]->is_port_wildcard, false);
-    EXPECT_EQ(frame_ancestors->sources[0]->allow_self, false);
+    EXPECT_EQ(frame_ancestors->allow_self, false);
+    EXPECT_EQ(frame_ancestors->allow_star, false);
   }
 
   // Multiple CSP headers separated by ',', with multiple frame-ancestors
@@ -297,7 +279,8 @@
     EXPECT_EQ(frame_ancestors->sources[0]->path, "");
     EXPECT_EQ(frame_ancestors->sources[0]->is_host_wildcard, false);
     EXPECT_EQ(frame_ancestors->sources[0]->is_port_wildcard, false);
-    EXPECT_EQ(frame_ancestors->sources[0]->allow_self, false);
+    EXPECT_EQ(frame_ancestors->allow_self, false);
+    EXPECT_EQ(frame_ancestors->allow_star, false);
   }
 
   // Both frame-ancestors and report-to directives present.
@@ -325,7 +308,8 @@
     EXPECT_EQ(frame_ancestors->sources[0]->path, "");
     EXPECT_EQ(frame_ancestors->sources[0]->is_host_wildcard, false);
     EXPECT_EQ(frame_ancestors->sources[0]->is_port_wildcard, false);
-    EXPECT_EQ(frame_ancestors->sources[0]->allow_self, false);
+    EXPECT_EQ(frame_ancestors->allow_self, false);
+    EXPECT_EQ(frame_ancestors->allow_star, false);
   }
 }
 
diff --git a/services/network/public/cpp/simple_url_loader.cc b/services/network/public/cpp/simple_url_loader.cc
index 1cc4198..cd555af 100644
--- a/services/network/public/cpp/simple_url_loader.cc
+++ b/services/network/public/cpp/simple_url_loader.cc
@@ -26,8 +26,8 @@
 #include "base/threading/sequenced_task_runner_handle.h"
 #include "base/time/time.h"
 #include "base/timer/timer.h"
-#include "mojo/public/cpp/bindings/binding.h"
 #include "mojo/public/cpp/bindings/pending_remote.h"
+#include "mojo/public/cpp/bindings/receiver.h"
 #include "mojo/public/cpp/bindings/receiver_set.h"
 #include "mojo/public/cpp/bindings/remote.h"
 #include "mojo/public/cpp/system/data_pipe.h"
@@ -324,9 +324,9 @@
     return task_priority;
   }
 
-  // Bound to the URLLoaderClient message pipe (|client_binding_|) via
-  // set_connection_error_handler.
-  void OnConnectionError();
+  // Bound to the URLLoaderClient message pipe (|client_receiver_|) via
+  // set_disconnect_handler.
+  void OnMojoDisconnect();
 
   // Completes the request by calling FinishWithResult() if OnComplete() was
   // called and either no body pipe was ever received, or the body pipe was
@@ -357,7 +357,7 @@
   mojo::Remote<mojom::URLLoaderFactory> url_loader_factory_remote_;
   std::unique_ptr<BodyHandler> body_handler_;
 
-  mojo::Binding<mojom::URLLoaderClient> client_binding_;
+  mojo::Receiver<mojom::URLLoaderClient> client_receiver_{this};
   mojom::URLLoaderPtr url_loader_;
 
   std::unique_ptr<StringUploadDataPipeGetter> string_upload_data_pipe_getter_;
@@ -1150,7 +1150,6 @@
     const net::NetworkTrafficAnnotationTag& annotation_tag)
     : resource_request_(std::move(resource_request)),
       annotation_tag_(annotation_tag),
-      client_binding_(this),
       request_state_(std::make_unique<RequestState>()),
       final_url_(resource_request_->url),
       timeout_timer_(timeout_tick_clock_) {
@@ -1457,7 +1456,7 @@
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   DCHECK(!request_state_->finished);
 
-  client_binding_.Close();
+  client_receiver_.reset();
   url_loader_.reset();
   timeout_timer_.Stop();
 
@@ -1509,9 +1508,9 @@
     resource_request_->enable_upload_progress = true;
 
   mojom::URLLoaderClientPtr client_ptr;
-  client_binding_.Bind(mojo::MakeRequest(&client_ptr));
-  client_binding_.set_connection_error_handler(base::BindOnce(
-      &SimpleURLLoaderImpl::OnConnectionError, base::Unretained(this)));
+  client_receiver_.Bind(mojo::MakeRequest(&client_ptr));
+  client_receiver_.set_disconnect_handler(base::BindOnce(
+      &SimpleURLLoaderImpl::OnMojoDisconnect, base::Unretained(this)));
   // Data elements that use pipes aren't reuseable, currently (Since the IPC
   // code doesn't call the Clone() method), so need to create another one, if
   // uploading a string via a data pipe.
@@ -1546,7 +1545,7 @@
   DCHECK_GT(remaining_retries_, 0);
   --remaining_retries_;
 
-  client_binding_.Close();
+  client_receiver_.reset();
   url_loader_.reset();
 
   request_state_ = std::make_unique<RequestState>();
@@ -1659,8 +1658,8 @@
   DCHECK(!request_state_->finished);
   DCHECK(!request_state_->request_completed);
 
-  // Close pipes to ignore any subsequent close notification.
-  client_binding_.Close();
+  // Reset pipes to ignore any subsequent close notification.
+  client_receiver_.reset();
   url_loader_.reset();
 
   request_state_->request_completed = true;
@@ -1675,7 +1674,7 @@
   MaybeComplete();
 }
 
-void SimpleURLLoaderImpl::OnConnectionError() {
+void SimpleURLLoaderImpl::OnMojoDisconnect() {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   // |this| closes the pipe to the URLLoader in OnComplete(), so this method
   // being called indicates the pipe was closed before completion, most likely
diff --git a/services/network/public/mojom/content_security_policy.mojom b/services/network/public/mojom/content_security_policy.mojom
index 99fcf2d..6685a7d 100644
--- a/services/network/public/mojom/content_security_policy.mojom
+++ b/services/network/public/mojom/content_security_policy.mojom
@@ -6,6 +6,15 @@
 
 import "url/mojom/url.mojom";
 
+// A CSPSource represents an expression that matches a set of urls.
+// Examples of CSPSource:
+// - domain.example.com
+// - *.example.com
+// - https://cdn.com
+// - data:
+// - 'none'
+// - 'self'
+// - *
 struct CSPSource {
   string scheme;
   string host;
@@ -13,11 +22,15 @@
   string path;
   bool is_host_wildcard = false;
   bool is_port_wildcard = false;
-  bool allow_self = false;
 };
 
 struct CSPSourceList {
   array<CSPSource> sources;
+
+  // Wildcard hosts and 'self' aren't stored in |sources|, but as attributes
+  // on the source list itself.
+  bool allow_self = false;
+  bool allow_star = false;
 };
 
 struct ContentSecurityPolicy {
diff --git a/services/network/websocket.cc b/services/network/websocket.cc
index 9e39295..ea5e5391 100644
--- a/services/network/websocket.cc
+++ b/services/network/websocket.cc
@@ -205,7 +205,6 @@
   DVLOG(3) << "WebSocketEventHandler::OnDataFrame @"
            << reinterpret_cast<void*>(this) << " fin=" << fin
            << " type=" << type << " data is " << payload.size() << " bytes";
-  // TODO(yoichio): Merge OnDataFrame mojo channel into data pipe.
   impl_->client_->OnDataFrame(fin, OpCodeToMessageType(type), payload.size());
   if (payload.size() > 0) {
     impl_->pending_data_frames_.push(payload);
diff --git a/services/service_manager/sandbox/sandbox_type.cc b/services/service_manager/sandbox/sandbox_type.cc
index 2655d1f..fe4bcf3d 100644
--- a/services/service_manager/sandbox/sandbox_type.cc
+++ b/services/service_manager/sandbox/sandbox_type.cc
@@ -193,14 +193,16 @@
   return SANDBOX_TYPE_UTILITY;
 }
 
-static bool g_audio_sandbox_enabled = true;
-
-SERVICE_MANAGER_SANDBOX_EXPORT void EnableAudioSandbox(bool enable) {
-  g_audio_sandbox_enabled = enable;
+void EnableAudioSandbox(bool enable) {
+  if (enable) {
+    base::CommandLine::ForCurrentProcess()->AppendSwitch(
+        switches::kEnableAudioServiceSandbox);
+  }
 }
 
 bool IsAudioSandboxEnabled() {
-  return g_audio_sandbox_enabled;
+  return base::CommandLine::ForCurrentProcess()->HasSwitch(
+      switches::kEnableAudioServiceSandbox);
 }
 
 }  // namespace service_manager
diff --git a/services/service_manager/sandbox/switches.cc b/services/service_manager/sandbox/switches.cc
index 6e2f2f6b..b17da8f 100644
--- a/services/service_manager/sandbox/switches.cc
+++ b/services/service_manager/sandbox/switches.cc
@@ -62,6 +62,9 @@
 // Disables the Win32K process mitigation policy for child processes.
 const char kDisableWin32kLockDown[] = "disable-win32k-lockdown";
 
+// Command line flag to enable the audio service sandbox.
+const char kEnableAudioServiceSandbox[] = "enable-audio-service-sandbox";
+
 // Allows shmat() system call in the GPU sandbox.
 const char kGpuSandboxAllowSysVShm[] = "gpu-sandbox-allow-sysv-shm";
 
diff --git a/services/service_manager/sandbox/switches.h b/services/service_manager/sandbox/switches.h
index 2281bb3..e27f58ae 100644
--- a/services/service_manager/sandbox/switches.h
+++ b/services/service_manager/sandbox/switches.h
@@ -41,6 +41,7 @@
 SERVICE_MANAGER_SANDBOX_EXPORT extern const char kDisableSeccompFilterSandbox[];
 SERVICE_MANAGER_SANDBOX_EXPORT extern const char kDisableSetuidSandbox[];
 SERVICE_MANAGER_SANDBOX_EXPORT extern const char kDisableWin32kLockDown[];
+SERVICE_MANAGER_SANDBOX_EXPORT extern const char kEnableAudioServiceSandbox[];
 SERVICE_MANAGER_SANDBOX_EXPORT extern const char kGpuSandboxAllowSysVShm[];
 SERVICE_MANAGER_SANDBOX_EXPORT extern const char kGpuSandboxFailuresFatal[];
 SERVICE_MANAGER_SANDBOX_EXPORT extern const char kNoSandbox[];
diff --git a/services/viz/privileged/mojom/gl/BUILD.gn b/services/viz/privileged/mojom/gl/BUILD.gn
index cea0dd64..8aab87a4 100644
--- a/services/viz/privileged/mojom/gl/BUILD.gn
+++ b/services/viz/privileged/mojom/gl/BUILD.gn
@@ -16,6 +16,7 @@
     "//media/mojo/mojom",
     "//ui/gfx/geometry/mojom",
     "//ui/gfx/mojom",
+    "//ui/gl/mojom",
     "//url/mojom:url_mojom_gurl",
   ]
   if (is_chromeos) {
diff --git a/services/viz/privileged/mojom/gl/gpu_service.mojom b/services/viz/privileged/mojom/gl/gpu_service.mojom
index c4da750..e1156e1 100644
--- a/services/viz/privileged/mojom/gl/gpu_service.mojom
+++ b/services/viz/privileged/mojom/gl/gpu_service.mojom
@@ -24,6 +24,7 @@
 import "media/mojo/mojom/video_encode_accelerator.mojom";
 import "ui/gfx/geometry/mojom/geometry.mojom";
 import "ui/gfx/mojom/buffer_types.mojom";
+import "ui/gl/mojom/gpu_preference.mojom";
 
 interface GpuService {
   // Tells the GPU service to create a new channel for communication with a
@@ -116,7 +117,7 @@
 
   // Tells GPU that host has seen a GPU switch. This can happen when the display
   // is reconfigured, for example.
-  GpuSwitched();
+  GpuSwitched(gl.mojom.GpuPreference active_gpu_heuristic);
 
   DestroyAllChannels();
 
diff --git a/skia/BUILD.gn b/skia/BUILD.gn
index dd36d2a..99da57ad 100644
--- a/skia/BUILD.gn
+++ b/skia/BUILD.gn
@@ -190,11 +190,7 @@
                   # assembly code contains flow control(jmp or jcc) statements.
 
       "/wd4800",  # forcing value to bool 'true/false'(assigning int to bool).
-      "/wd5041",  # out-of-line definition for constexpr static data member is not needed and is deprecated in C++17
     ]
-    cflags_cc = [ "/std:c++17" ]
-  } else {
-    cflags_cc = [ "-std=c++17" ]
   }
 }
 
diff --git a/testing/variations/fieldtrial_testing_config.json b/testing/variations/fieldtrial_testing_config.json
index 9485104c..969b9c1 100644
--- a/testing/variations/fieldtrial_testing_config.json
+++ b/testing/variations/fieldtrial_testing_config.json
@@ -546,6 +546,9 @@
             "experiments": [
                 {
                     "name": "Enabled",
+                    "params": {
+                        "show_confirmation_button": "false"
+                    },
                     "enable_features": [
                         "TouchToFillAndroid"
                     ]
diff --git a/third_party/blink/public/platform/platform.h b/third_party/blink/public/platform/platform.h
index a363c7f..e2cc612 100644
--- a/third_party/blink/public/platform/platform.h
+++ b/third_party/blink/public/platform/platform.h
@@ -516,8 +516,7 @@
   // backed by an independent context. Returns null if the context cannot be
   // created or initialized.
   virtual std::unique_ptr<WebGraphicsContext3DProvider>
-  CreateWebGPUGraphicsContext3DProvider(const WebURL& top_document_url,
-                                        GraphicsInfo*);
+  CreateWebGPUGraphicsContext3DProvider(const WebURL& top_document_url);
 
   virtual gpu::GpuMemoryBufferManager* GetGpuMemoryBufferManager() {
     return nullptr;
diff --git a/third_party/blink/renderer/bindings/core/v8/v8_binding_for_core.cc b/third_party/blink/renderer/bindings/core/v8/v8_binding_for_core.cc
index 22f10d1..955e03e 100644
--- a/third_party/blink/renderer/bindings/core/v8/v8_binding_for_core.cc
+++ b/third_party/blink/renderer/bindings/core/v8/v8_binding_for_core.cc
@@ -80,13 +80,25 @@
                       const v8::PropertyDescriptor& descriptor) {
   DCHECK(descriptor.has_configurable());
   DCHECK(descriptor.has_enumerable());
-  DCHECK(descriptor.has_value());
-  DCHECK(descriptor.has_writable());
+  if (descriptor.has_value()) {
+    // Data property
+    DCHECK(descriptor.has_writable());
+    info.GetReturnValue().Set(
+        V8ObjectBuilder(ScriptState::ForCurrentRealm(info))
+            .Add("configurable", descriptor.configurable())
+            .Add("enumerable", descriptor.enumerable())
+            .Add("value", descriptor.value())
+            .Add("writable", descriptor.writable())
+            .V8Value());
+    return;
+  }
+  // Accessor property
+  DCHECK(descriptor.has_get() || descriptor.has_set());
   info.GetReturnValue().Set(V8ObjectBuilder(ScriptState::ForCurrentRealm(info))
                                 .Add("configurable", descriptor.configurable())
                                 .Add("enumerable", descriptor.enumerable())
-                                .Add("value", descriptor.value())
-                                .Add("writable", descriptor.writable())
+                                .Add("get", descriptor.get())
+                                .Add("set", descriptor.set())
                                 .V8Value());
 }
 
diff --git a/third_party/blink/renderer/bindings/scripts/bind_gen/__init__.py b/third_party/blink/renderer/bindings/scripts/bind_gen/__init__.py
index 8109fdb8..10a4b43c 100644
--- a/third_party/blink/renderer/bindings/scripts/bind_gen/__init__.py
+++ b/third_party/blink/renderer/bindings/scripts/bind_gen/__init__.py
@@ -29,7 +29,11 @@
 
 _setup_sys_path()
 
-from .clang_format import init_clang_format
+
+from . import clang_format
+from .example import run_example
+from .interface import generate_interfaces
+from .path_manager import PathManager
 
 
 def _setup_clang_format():
@@ -44,10 +48,13 @@
     command_path = os.path.abspath(
         os.path.join(root_dir, 'third_party', 'depot_tools', command_name))
 
-    init_clang_format(command_path=command_path)
+    clang_format.init(command_path=command_path)
 
 
-_setup_clang_format()
-
-from .example import run_example
-from .interface import generate_interfaces
+def init(output_dirs):
+    """
+    Args:
+        output_dirs: Pairs of component and output directory.
+    """
+    _setup_clang_format()
+    PathManager.init(output_dirs)
diff --git a/third_party/blink/renderer/bindings/scripts/bind_gen/blink_v8_bridge.py b/third_party/blink/renderer/bindings/scripts/bind_gen/blink_v8_bridge.py
index e60e363..954d786 100644
--- a/third_party/blink/renderer/bindings/scripts/bind_gen/blink_v8_bridge.py
+++ b/third_party/blink/renderer/bindings/scripts/bind_gen/blink_v8_bridge.py
@@ -15,6 +15,23 @@
 _format = CodeNode.format_template
 
 
+def blink_class_name(idl_definition):
+    """
+    Returns the class name of Blink implementation.
+    """
+    try:
+        class_name = idl_definition.extended_attributes.get(
+            "ImplementedAs").value
+    except:
+        class_name = idl_definition.identifier
+
+    if isinstance(idl_definition,
+                  (web_idl.CallbackFunction, web_idl.CallbackInterface)):
+        return name_style.class_("v8", class_name)
+    else:
+        return name_style.class_(class_name)
+
+
 def blink_type_info(idl_type):
     """
     Returns the types of Blink implementation corresponding to the given IDL
diff --git a/third_party/blink/renderer/bindings/scripts/bind_gen/clang_format.py b/third_party/blink/renderer/bindings/scripts/bind_gen/clang_format.py
index 3f41f65..ac060bc8 100644
--- a/third_party/blink/renderer/bindings/scripts/bind_gen/clang_format.py
+++ b/third_party/blink/renderer/bindings/scripts/bind_gen/clang_format.py
@@ -8,7 +8,11 @@
 _clang_format_command_path = None
 
 
-def init_clang_format(command_path):
+def init(command_path):
+    """
+    Args:
+        command_path: Path to the clang_format command.
+    """
     assert isinstance(command_path, str)
     assert os.path.exists(command_path)
 
diff --git a/third_party/blink/renderer/bindings/scripts/bind_gen/code_generation_accumulator.py b/third_party/blink/renderer/bindings/scripts/bind_gen/code_generation_accumulator.py
new file mode 100644
index 0000000..9da5dc9
--- /dev/null
+++ b/third_party/blink/renderer/bindings/scripts/bind_gen/code_generation_accumulator.py
@@ -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.
+
+
+class CodeGenerationAccumulator(object):
+    """
+    Accumulates a variety of information and helps generate code based on the
+    information.
+    """
+
+    def __init__(self):
+        # Headers to be included
+        self._include_headers = set()
+        # Forward declarations of C++ class
+        self._class_decls = set()
+
+    @property
+    def include_headers(self):
+        return self._include_headers
+
+    def add_include_header(self, header):
+        self._include_headers.add(header)
+
+    def add_include_headers(self, headers):
+        self._include_headers.update(headers)
+
+    @property
+    def class_decls(self):
+        return self._class_decls
+
+    def add_class_decl(self, class_name):
+        self._class_decls.add(class_name)
+
+    def add_class_decls(self, class_names):
+        self._class_decls.update(class_names)
diff --git a/third_party/blink/renderer/bindings/scripts/bind_gen/code_node.py b/third_party/blink/renderer/bindings/scripts/bind_gen/code_node.py
index 049fea09..88a6800 100644
--- a/third_party/blink/renderer/bindings/scripts/bind_gen/code_node.py
+++ b/third_party/blink/renderer/bindings/scripts/bind_gen/code_node.py
@@ -11,6 +11,7 @@
 import copy
 import string
 
+from .code_generation_accumulator import CodeGenerationAccumulator
 from .mako_renderer import MakoRenderer
 
 
@@ -145,6 +146,9 @@
         # Mako's template text, bindings dict, and the renderer object
         self._template_text = template_text
         self._template_vars = {}
+
+        self._accumulator = None
+
         self._renderer = renderer
 
         self._render_state = CodeNode._RenderState()
@@ -275,6 +279,18 @@
             self.add_template_var(name, value)
 
     @property
+    def accumulator(self):
+        # Always consistently use the accumulator of the root node.
+        if self.outer is not None:
+            return self.outer.accumulator
+        return self._accumulator
+
+    def set_accumulator(self, accumulator):
+        assert isinstance(accumulator, CodeGenerationAccumulator)
+        assert self._accumulator is None
+        self._accumulator = accumulator
+
+    @property
     def renderer(self):
         # Always use the renderer of the root node in order not to mix renderers
         # during rendering of a single code node tree.
@@ -282,6 +298,11 @@
             return self.outer.renderer
         return self._renderer
 
+    def set_renderer(self, renderer):
+        assert isinstance(renderer, MakoRenderer)
+        assert self._renderer is None
+        self._renderer = renderer
+
     @property
     def current_render_state(self):
         assert self._is_rendering
@@ -337,8 +358,6 @@
     """
 
     def __init__(self, literal_text, renderer=None):
-        assert isinstance(literal_text, str)
-
         literal_text_gensym = CodeNode.gensym()
         template_text = CodeNode.format_template(
             "${{{literal_text}}}", literal_text=literal_text_gensym)
diff --git a/third_party/blink/renderer/bindings/scripts/bind_gen/codegen_utils.py b/third_party/blink/renderer/bindings/scripts/bind_gen/codegen_utils.py
index 75e3394..c9c71e2 100644
--- a/third_party/blink/renderer/bindings/scripts/bind_gen/codegen_utils.py
+++ b/third_party/blink/renderer/bindings/scripts/bind_gen/codegen_utils.py
@@ -2,10 +2,14 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
+import web_idl
+
 from .clang_format import clang_format
+from .code_generation_accumulator import CodeGenerationAccumulator
 from .code_node import CodeNode
 from .code_node import LiteralNode
 from .code_node import SymbolScopeNode
+from .path_manager import PathManager
 
 
 def make_copyright_header():
@@ -16,6 +20,22 @@
 """)
 
 
+def make_header_include_directives(accumulator):
+    assert isinstance(accumulator, CodeGenerationAccumulator)
+
+    class HeaderIncludeDirectives(object):
+        def __init__(self, accumulator):
+            self._accumulator = accumulator
+
+        def __str__(self):
+            return "\n".join([
+                "#include \"{}\"".format(header)
+                for header in sorted(self._accumulator.include_headers)
+            ])
+
+    return LiteralNode(HeaderIncludeDirectives(accumulator))
+
+
 def enclose_with_header_guard(code_node, header_guard):
     assert isinstance(code_node, CodeNode)
     assert isinstance(header_guard, str)
@@ -43,6 +63,62 @@
     ])
 
 
+def traverse_idl_types(idl_definition, callback):
+    """
+    Traverses in the given |idl_definition| to find all the web_idl.IdlType used
+    in the IDL definition.  Invokes |callback| with each web_idl.IdlType.
+    """
+    assert callable(callback)
+
+    def get(obj, attr):
+        try:
+            return getattr(obj, attr)
+        except:
+            return ()
+
+    xs = (get(idl_definition, "attributes") + get(idl_definition, "constants")
+          + get(idl_definition, "own_members") + (idl_definition, ))
+    for x in xs:
+        idl_type = get(x, "idl_type")
+        if idl_type:
+            callback(idl_type)
+
+    xs = (get(idl_definition, "constructors") + get(idl_definition,
+                                                    "operations"))
+    for x in xs:
+        for argument in x.arguments:
+            callback(argument.idl_type)
+        if x.return_type is not None:
+            callback(x.return_type)
+
+    xs = get(idl_definition, "flattened_member_types")
+    for x in xs:
+        callback(x)
+
+
+def collect_include_headers(idl_definition):
+    """
+    Returns a list of include headers that are required by generated bindings of
+    |idl_definition|.
+    """
+    type_def_objs = set()
+
+    def collect_type_def_obj(idl_type):
+        type_def_obj = idl_type.unwrap().type_definition_object
+        if type_def_obj is not None:
+            type_def_objs.add(type_def_obj)
+
+    traverse_idl_types(idl_definition, collect_type_def_obj)
+
+    header_paths = set()
+    for type_def_obj in type_def_objs:
+        if isinstance(type_def_obj, web_idl.Enumeration):
+            continue
+        header_paths.add(PathManager(type_def_obj).blink_path(ext="h"))
+
+    return header_paths
+
+
 def render_code_node(code_node):
     """
     Renders |code_node| and turns it into text letting |code_node| apply all
diff --git a/third_party/blink/renderer/bindings/scripts/bind_gen/interface.py b/third_party/blink/renderer/bindings/scripts/bind_gen/interface.py
index 78075e5..2eca39ab5 100644
--- a/third_party/blink/renderer/bindings/scripts/bind_gen/interface.py
+++ b/third_party/blink/renderer/bindings/scripts/bind_gen/interface.py
@@ -7,6 +7,7 @@
 from . import name_style
 from .blink_v8_bridge import blink_type_info
 from .blink_v8_bridge import make_v8_to_blink_value
+from .code_generation_accumulator import CodeGenerationAccumulator
 from .code_generation_context import CodeGenerationContext
 from .code_node import CodeNode
 from .code_node import FunctionDefinitionNode
@@ -16,8 +17,10 @@
 from .code_node import SymbolScopeNode
 from .code_node import TextNode
 from .code_node import UnlikelyExitNode
+from .codegen_utils import collect_include_headers
 from .codegen_utils import enclose_with_namespace
 from .codegen_utils import make_copyright_header
+from .codegen_utils import make_header_include_directives
 from .codegen_utils import write_code_node_to_file
 from .mako_renderer import MakoRenderer
 
@@ -382,10 +385,17 @@
     filename = "v8_example_interface.cc"
     filepath = os.path.join(output_dirs['core'], filename)
 
-    interface = web_idl_database.find("TestNamespace")
+    interface = web_idl_database.find("Node")
 
     cg_context = CodeGenerationContext(interface=interface)
 
+    root_node = SymbolScopeNode(separator_last="\n")
+    root_node.set_accumulator(CodeGenerationAccumulator())
+    root_node.set_renderer(MakoRenderer())
+
+    root_node.accumulator.add_include_headers(
+        collect_include_headers(interface))
+
     code_node = SymbolScopeNode()
 
     for attribute in interface.attributes:
@@ -401,10 +411,11 @@
 
     code_node.append(make_install_interface_template_def(cg_context))
 
-    root_node = SymbolScopeNode(separator_last="\n", renderer=MakoRenderer())
     root_node.extend([
         make_copyright_header(),
         LiteralNode(""),
+        make_header_include_directives(root_node.accumulator),
+        LiteralNode(""),
         enclose_with_namespace(code_node, name_style.namespace("blink")),
     ])
 
diff --git a/third_party/blink/renderer/bindings/scripts/bind_gen/path_manager.py b/third_party/blink/renderer/bindings/scripts/bind_gen/path_manager.py
index e939165d..b8243b6 100644
--- a/third_party/blink/renderer/bindings/scripts/bind_gen/path_manager.py
+++ b/third_party/blink/renderer/bindings/scripts/bind_gen/path_manager.py
@@ -4,7 +4,10 @@
 
 import os.path
 
+import web_idl
+
 from . import name_style
+from .blink_v8_bridge import blink_class_name
 
 
 class PathManager(object):
@@ -19,41 +22,71 @@
         Everything is generated in a single component.
     """
 
-    def __init__(self, idl_definition, output_dirs):
+    _REQUIRE_INIT_MESSAGE = ("PathManager.init must be called in advance.")
+    _is_initialized = False
+
+    @classmethod
+    def init(cls, output_dirs):
+        """
+        Args:
+            output_dirs: Pairs of component and output directory.
+        """
+        assert not cls._is_initialized
+        assert isinstance(output_dirs, dict)
+        cls._output_dirs = output_dirs
+        cls._blink_path_prefix = os.path.sep + os.path.join(
+            "third_party", "blink", "renderer", "")
+        cls._is_initialized = True
+
+    def __init__(self, idl_definition):
+        assert self._is_initialized, self._REQUIRE_INIT_MESSAGE
+
         idl_path = idl_definition.debug_info.location.filepath
         self._idl_basepath, _ = os.path.splitext(idl_path)
         self._idl_dir, self._idl_basename = os.path.split(self._idl_basepath)
 
-        components = idl_definition.components
-        assert 0 < len(components)
+        components = sorted(idl_definition.components)
 
         if len(components) == 1:
             component = components[0]
             self._is_cross_components = False
             self._api_component = component
             self._impl_component = component
-        else:
-            assert ("core", "modules") == sorted(components)
+        elif len(components) == 2:
+            assert components[0] == "core"
+            assert components[1] == "modules"
             self._is_cross_components = True
             self._api_component = "core"
             self._impl_component = "modules"
+        else:
+            assert False
 
-        self._api_dir = output_dirs[self._api_component]
-        self._impl_dir = output_dirs[self._impl_component]
-
+        self._api_dir = self._output_dirs[self._api_component]
+        self._impl_dir = self._output_dirs[self._impl_component]
         self._out_basename = name_style.file("v8", idl_definition.identifier)
 
+        if isinstance(idl_definition,
+                      (web_idl.CallbackFunction, web_idl.CallbackInterface)):
+            self._blink_dir = self._api_dir
+        else:
+            self._blink_dir = self._idl_dir
+        self._blink_basename = name_style.file(
+            blink_class_name(idl_definition))
+
     @property
     def idl_dir(self):
         return self._idl_dir
 
     def blink_path(self, filename=None, ext=None):
-        # The IDL file and Blink headers are supposed to exist in the same
-        # directory.
-        return self._join(
-            dirpath=self.idl_dir,
-            filename=(filename or self._idl_basename),
-            ext=ext)
+        """
+        Returns a path to a Blink implementation file relative to the project
+        root directory, e.g. "third_party/blink/renderer/..."
+        """
+        return self._rel_to_root(
+            self._join(
+                dirpath=self._blink_dir,
+                filename=(filename or self._blink_basename),
+                ext=ext))
 
     @property
     def is_cross_components(self):
@@ -87,7 +120,14 @@
             filename=(filename or self._out_basename),
             ext=ext)
 
+    def _rel_to_root(self, path):
+        index = path.find(self._blink_path_prefix)
+        if index < 0:
+            assert path.startswith(self._blink_path_prefix[1:])
+            return path
+        return path[index + 1:]
+
     def _join(self, dirpath, filename, ext=None):
         if ext is not None:
-            filename = "{}.{}".format(filename, ext)
+            filename = os.path.extsep.join([filename, ext])
         return os.path.join(dirpath, filename)
diff --git a/third_party/blink/renderer/bindings/scripts/generate_bindings.py b/third_party/blink/renderer/bindings/scripts/generate_bindings.py
index e8f122ce..cdce8ee 100644
--- a/third_party/blink/renderer/bindings/scripts/generate_bindings.py
+++ b/third_party/blink/renderer/bindings/scripts/generate_bindings.py
@@ -53,6 +53,8 @@
         web_idl.Component('modules'): options.output_dir_modules,
     }
 
+    bind_gen.init(output_dirs)
+
     for task in tasks:
         dispatch_table[task](web_idl_database=web_idl_database,
                              output_dirs=output_dirs)
diff --git a/third_party/blink/renderer/bindings/scripts/generate_bindings.pydeps b/third_party/blink/renderer/bindings/scripts/generate_bindings.pydeps
index c329ec7..442951c8 100644
--- a/third_party/blink/renderer/bindings/scripts/generate_bindings.pydeps
+++ b/third_party/blink/renderer/bindings/scripts/generate_bindings.pydeps
@@ -29,6 +29,7 @@
 bind_gen/__init__.py
 bind_gen/blink_v8_bridge.py
 bind_gen/clang_format.py
+bind_gen/code_generation_accumulator.py
 bind_gen/code_generation_context.py
 bind_gen/code_node.py
 bind_gen/codegen_utils.py
@@ -36,6 +37,7 @@
 bind_gen/interface.py
 bind_gen/mako_renderer.py
 bind_gen/name_style.py
+bind_gen/path_manager.py
 generate_bindings.py
 web_idl/__init__.py
 web_idl/argument.py
diff --git a/third_party/blink/renderer/bindings/scripts/web_idl/runtime_enabled_features.py b/third_party/blink/renderer/bindings/scripts/web_idl/runtime_enabled_features.py
index 57ece2b..7421e6f 100644
--- a/third_party/blink/renderer/bindings/scripts/web_idl/runtime_enabled_features.py
+++ b/third_party/blink/renderer/bindings/scripts/web_idl/runtime_enabled_features.py
@@ -10,6 +10,7 @@
 
     _REQUIRE_INIT_MESSAGE = (
         "RuntimeEnabledFeatures.init must be called in advance.")
+    _is_initialized = False
 
     @classmethod
     def init(cls, filepaths):
@@ -18,6 +19,7 @@
             filepaths: Paths to the definition files of runtime-enabled features
                 ("runtime_enabled_features.json5").
         """
+        assert not cls._is_initialized
         assert isinstance(filepaths, list)
         assert all(isinstance(filepath, str) for filepath in filepaths)
 
@@ -36,7 +38,7 @@
     @classmethod
     def is_context_dependent(cls, feature_name):
         """Returns True if the feature may be enabled per-context."""
-        assert cls._is_initialized, _REQUIRE_INIT_MESSAGE
+        assert cls._is_initialized, cls._REQUIRE_INIT_MESSAGE
         assert isinstance(feature_name, str)
         assert feature_name in cls._features, (
             "Unknown runtime-enabled feature: {}".format(feature_name))
diff --git a/third_party/blink/renderer/core/css/resolver/style_adjuster.cc b/third_party/blink/renderer/core/css/resolver/style_adjuster.cc
index c424eee..30053d7 100644
--- a/third_party/blink/renderer/core/css/resolver/style_adjuster.cc
+++ b/third_party/blink/renderer/core/css/resolver/style_adjuster.cc
@@ -654,6 +654,11 @@
     // Columns don't apply to svg text elements.
     if (IsSVGTextElement(*element))
       style.ClearMultiCol();
+  } else if (element && element->IsMathMLElement()) {
+    if (style.Display() == EDisplay::kContents) {
+      // https://drafts.csswg.org/css-display/#unbox-mathml
+      style.SetDisplay(EDisplay::kNone);
+    }
   }
 
   // If this node is sticky it marks the creation of a sticky subtree, which we
diff --git a/third_party/blink/renderer/core/display_lock/display_lock_context_test.cc b/third_party/blink/renderer/core/display_lock/display_lock_context_test.cc
index 9194196..4a82fa0b 100644
--- a/third_party/blink/renderer/core/display_lock/display_lock_context_test.cc
+++ b/third_party/blink/renderer/core/display_lock/display_lock_context_test.cc
@@ -961,7 +961,7 @@
   EXPECT_EQ(GetDocument().ActivationBlockingDisplayLockCount(), 0);
 
   auto* template_el =
-      ToHTMLTemplateElement(GetDocument().getElementById("template"));
+      To<HTMLTemplateElement>(GetDocument().getElementById("template"));
   auto* child = To<Element>(template_el->content()->firstChild());
   EXPECT_FALSE(child->isConnected());
 
diff --git a/third_party/blink/renderer/core/dom/element.cc b/third_party/blink/renderer/core/dom/element.cc
index a7a291b..0483a982 100644
--- a/third_party/blink/renderer/core/dom/element.cc
+++ b/third_party/blink/renderer/core/dom/element.cc
@@ -4395,11 +4395,12 @@
 
 void Element::ForceLegacyLayoutInFormattingContext(
     const ComputedStyle& new_style) {
-  if (DefinitelyNewFormattingContext(*this, new_style))
-    return;
-
-  bool found_bfc = false;
-  for (Element* ancestor = this; !found_bfc;) {
+  // TableNG requires that table elements are either all NG, or all Legacy.
+  bool needs_traverse_to_table =
+      RuntimeEnabledFeatures::LayoutNGTableEnabled() &&
+      new_style.IsDisplayTableType();
+  bool found_bfc = DefinitelyNewFormattingContext(*this, new_style);
+  for (Element* ancestor = this; !found_bfc || needs_traverse_to_table;) {
     ancestor =
         DynamicTo<Element>(LayoutTreeBuilderTraversal::Parent(*ancestor));
     if (!ancestor || ancestor->ShouldForceLegacyLayout())
@@ -4407,7 +4408,17 @@
     const ComputedStyle* style = ancestor->GetComputedStyle();
     if (style->Display() == EDisplay::kNone)
       break;
-    found_bfc = DefinitelyNewFormattingContext(*ancestor, *style);
+    found_bfc = found_bfc || DefinitelyNewFormattingContext(*ancestor, *style);
+    if (found_bfc && !needs_traverse_to_table) {
+      needs_traverse_to_table =
+          RuntimeEnabledFeatures::LayoutNGTableEnabled() &&
+          style->IsDisplayTableType();
+    }
+    if (needs_traverse_to_table) {
+      EDisplay display = style->Display();
+      if (display == EDisplay::kTable || display == EDisplay::kInlineTable)
+        needs_traverse_to_table = false;
+    }
     ancestor->SetShouldForceLegacyLayoutForChild(true);
     ancestor->SetNeedsReattachLayoutTree();
   }
diff --git a/third_party/blink/renderer/core/editing/testing/selection_sample.cc b/third_party/blink/renderer/core/editing/testing/selection_sample.cc
index 0d1b3a50..9ae865e 100644
--- a/third_party/blink/renderer/core/editing/testing/selection_sample.cc
+++ b/third_party/blink/renderer/core/editing/testing/selection_sample.cc
@@ -41,9 +41,9 @@
     Document* const document = element.ownerDocument();
     ShadowRoot& shadow_root =
         parent->AttachShadowRootInternal(ShadowRootType::kOpen);
-    Node* const fragment =
-        document->importNode(ToHTMLTemplateElement(template_element)->content(),
-                             true, ASSERT_NO_EXCEPTION);
+    Node* const fragment = document->importNode(
+        To<HTMLTemplateElement>(template_element)->content(), true,
+        ASSERT_NO_EXCEPTION);
     shadow_root.AppendChild(fragment);
   }
 }
diff --git a/third_party/blink/renderer/core/fetch/fetch_response_data.cc b/third_party/blink/renderer/core/fetch/fetch_response_data.cc
index 9d096bb..11a632a 100644
--- a/third_party/blink/renderer/core/fetch/fetch_response_data.cc
+++ b/third_party/blink/renderer/core/fetch/fetch_response_data.cc
@@ -293,9 +293,13 @@
                     String::FromUTF8(csp_source->scheme),
                     String::FromUTF8(csp_source->host), csp_source->port,
                     String::FromUTF8(csp_source->path),
-                    csp_source->is_host_wildcard, csp_source->is_port_wildcard,
-                    csp_source->allow_self));
+                    csp_source->is_host_wildcard,
+                    csp_source->is_port_wildcard));
           }
+          blink_frame_ancestors->allow_self =
+              frame_ancestors_directive->allow_self;
+          blink_frame_ancestors->allow_star =
+              frame_ancestors_directive->allow_star;
         }
 
         for (auto& endpoints :
diff --git a/third_party/blink/renderer/core/html/html_template_element.cc b/third_party/blink/renderer/core/html/html_template_element.cc
index 8787c5d..56bb1f30 100644
--- a/third_party/blink/renderer/core/html/html_template_element.cc
+++ b/third_party/blink/renderer/core/html/html_template_element.cc
@@ -60,8 +60,10 @@
     CloneChildrenFlag flag) {
   if (flag == CloneChildrenFlag::kSkip)
     return;
-  if (ToHTMLTemplateElement(source).content_)
-    content()->CloneChildNodesFrom(*ToHTMLTemplateElement(source).content());
+
+  auto& html_template_element = To<HTMLTemplateElement>(source);
+  if (html_template_element.content_)
+    content()->CloneChildNodesFrom(*html_template_element.content());
 }
 
 void HTMLTemplateElement::DidMoveToNewDocument(Document& old_document) {
diff --git a/third_party/blink/renderer/core/layout/flexible_box_algorithm.cc b/third_party/blink/renderer/core/layout/flexible_box_algorithm.cc
index a995ac65..ca06e24b 100644
--- a/third_party/blink/renderer/core/layout/flexible_box_algorithm.cc
+++ b/third_party/blink/renderer/core/layout/flexible_box_algorithm.cc
@@ -958,6 +958,10 @@
     LayoutUnit border_scrollbar_padding_before) {
   DCHECK(IsColumnFlow());
   DCHECK(Style()->ResolvedIsColumnReverseFlexDirection());
+  DCHECK(all_items_.IsEmpty() || IsNGFlexBox())
+      << "This method relies on NG having passed in 0 for initial main axis "
+         "offset for column-reverse flex boxes. That needs to be fixed if this "
+         "method is to be used in legacy.";
   for (FlexLine& line_context : FlexLines()) {
     for (wtf_size_t child_number = 0;
          child_number < line_context.line_items.size(); ++child_number) {
@@ -966,12 +970,11 @@
       // We passed 0 as the initial main_axis offset to ComputeLineItemsPosition
       // for ColumnReverse containers so here we have to add the
       // border_scrollbar_padding of the container.
-      // TODO(dgrogan): I think
-      // wpt/css/css-flexbox/flex-lines/multi-line-wrap-with-column-reverse.html
-      // fails because this totally ignores margins.
       flex_item.desired_location.SetX(
           main_axis_content_size + border_scrollbar_padding_before -
-          flex_item.desired_location.X() - item_main_size);
+          flex_item.desired_location.X() - item_main_size -
+          flex_item.box->MarginAfter(Style()) +
+          flex_item.box->MarginBefore(Style()));
     }
   }
 }
diff --git a/third_party/blink/renderer/core/layout/layout_inline.cc b/third_party/blink/renderer/core/layout/layout_inline.cc
index 5eee459..bd469763 100644
--- a/third_party/blink/renderer/core/layout/layout_inline.cc
+++ b/third_party/blink/renderer/core/layout/layout_inline.cc
@@ -1070,14 +1070,9 @@
         *ContainingNGBlockFlow()->PaintFragment()));
     DCHECK(container_fragment->PhysicalFragment().IsInline() ||
            container_fragment->PhysicalFragment().IsLineBox());
-    NGInlineCursor cursor;
-    cursor.MoveTo(*this);
-    for (; cursor; cursor.MoveToNextForSameLayoutObject()) {
-      if (!cursor.CurrentPaintFragment()->IsDescendantOfNotSelf(
-              *container_fragment))
-        continue;
+    NGInlineCursor cursor(*container_fragment);
+    for (cursor.MoveTo(*this); cursor; cursor.MoveToNextForSameLayoutObject())
       yield(cursor.CurrentRect());
-    }
   } else {
     DCHECK(!ContainingNGBlockFlow());
     CollectCulledLineBoxRects(yield);
diff --git a/third_party/blink/renderer/core/layout/ng/inline/ng_caret_position.h b/third_party/blink/renderer/core/layout/ng/inline/ng_caret_position.h
index 6d0d0720..cd9d204 100644
--- a/third_party/blink/renderer/core/layout/ng/inline/ng_caret_position.h
+++ b/third_party/blink/renderer/core/layout/ng/inline/ng_caret_position.h
@@ -32,12 +32,6 @@
  public:
   bool IsNull() const { return cursor.IsNull(); }
 
-  // TODO(yosin): We'll remove |NGCaretPosition::PaintFragment()|, once all
-  // clients work with |NGInlineCursor|.
-  const NGPaintFragment* PaintFragment() const {
-    return cursor.CurrentPaintFragment();
-  }
-
   Position ToPositionInDOMTree() const;
   PositionWithAffinity ToPositionInDOMTreeWithAffinity() const;
 
diff --git a/third_party/blink/renderer/modules/mediastream/media_stream_device_observer.cc b/third_party/blink/renderer/modules/mediastream/media_stream_device_observer.cc
index 0ff66af2..b4563f7e 100644
--- a/third_party/blink/renderer/modules/mediastream/media_stream_device_observer.cc
+++ b/third_party/blink/renderer/modules/mediastream/media_stream_device_observer.cc
@@ -135,6 +135,9 @@
 
 void MediaStreamDeviceObserver::BindMediaStreamDeviceObserverReceiver(
     mojo::PendingReceiver<mojom::blink::MediaStreamDeviceObserver> receiver) {
+  if (receiver_.is_bound())
+    return;
+
   receiver_.Bind(std::move(receiver));
 }
 
diff --git a/third_party/blink/renderer/modules/modules_idl_files.gni b/third_party/blink/renderer/modules/modules_idl_files.gni
index 3371822..9cb9f43 100644
--- a/third_party/blink/renderer/modules/modules_idl_files.gni
+++ b/third_party/blink/renderer/modules/modules_idl_files.gni
@@ -867,8 +867,8 @@
           "webgpu/gpu_texture_view_descriptor.idl",
           "webgpu/gpu_uncaptured_error_event_init.idl",
           "webgpu/gpu_vertex_attribute_descriptor.idl",
-          "webgpu/gpu_vertex_buffer_descriptor.idl",
-          "webgpu/gpu_vertex_input_descriptor.idl",
+          "webgpu/gpu_vertex_buffer_layout_descriptor.idl",
+          "webgpu/gpu_vertex_state_descriptor.idl",
           "webmidi/midi_connection_event_init.idl",
           "webmidi/midi_message_event_init.idl",
           "webmidi/midi_options.idl",
@@ -1011,6 +1011,7 @@
           "webgpu/gpu_programmable_pass_encoder.idl",
           "webgpu/gpu_render_encoder_base.idl",
           "webgpu/navigator_gpu.idl",
+          "webgpu/worker_navigator_gpu.idl",
           "webmidi/navigator_web_midi.idl",
           "webshare/navigator_share.idl",
           "webusb/navigator_usb.idl",
diff --git a/third_party/blink/renderer/modules/webgl/DEPS b/third_party/blink/renderer/modules/webgl/DEPS
index fd5693a..7f39fad4 100644
--- a/third_party/blink/renderer/modules/webgl/DEPS
+++ b/third_party/blink/renderer/modules/webgl/DEPS
@@ -5,4 +5,5 @@
     "+gpu/command_buffer/common/capabilities.h",
     "+gpu/config/gpu_feature_info.h",
     "+skia/ext",
+    "+ui/gl/gpu_preference.h",
 ]
diff --git a/third_party/blink/renderer/modules/webgl/webgl2_rendering_context_base.cc b/third_party/blink/renderer/modules/webgl/webgl2_rendering_context_base.cc
index b61e9566..5c05aa57 100644
--- a/third_party/blink/renderer/modules/webgl/webgl2_rendering_context_base.cc
+++ b/third_party/blink/renderer/modules/webgl/webgl2_rendering_context_base.cc
@@ -931,6 +931,8 @@
   }
   renderbuffer_binding_->SetInternalFormat(internalformat);
   renderbuffer_binding_->SetSize(width, height);
+  UpdateNumberOfUserAllocatedMultisampledRenderbuffers(
+      renderbuffer_binding_->UpdateMultisampleState(samples > 0));
 }
 
 void WebGL2RenderingContextBase::renderbufferStorageMultisample(
diff --git a/third_party/blink/renderer/modules/webgl/webgl_context_attribute_helpers.cc b/third_party/blink/renderer/modules/webgl/webgl_context_attribute_helpers.cc
index 4e3e5be0..810e91b 100644
--- a/third_party/blink/renderer/modules/webgl/webgl_context_attribute_helpers.cc
+++ b/third_party/blink/renderer/modules/webgl/webgl_context_attribute_helpers.cc
@@ -5,6 +5,7 @@
 #include "third_party/blink/renderer/modules/webgl/webgl_context_attribute_helpers.h"
 
 #include "third_party/blink/renderer/core/frame/settings.h"
+#include "ui/gl/gpu_preference.h"
 
 namespace blink {
 
@@ -30,6 +31,8 @@
     Platform::ContextType context_type,
     bool support_own_offscreen_surface) {
   Platform::ContextAttributes result;
+  // Must keep the meaning of the "default" GPU choice in sync with the code
+  // below, in PowerPreferenceToGpuPreference.
   result.prefer_low_power_gpu = attrs.power_preference == "low-power";
   result.fail_if_major_performance_caveat =
       attrs.fail_if_major_performance_caveat;
@@ -45,4 +48,12 @@
   return result;
 }
 
+gl::GpuPreference PowerPreferenceToGpuPreference(String power_preference) {
+  // Must keep the interpretation of the "default" GPU in sync with the code
+  // above which sets the prefer_low_power_gpu attribute.
+  if (power_preference == "low-power")
+    return gl::GpuPreference::kLowPower;
+  return gl::GpuPreference::kHighPerformance;
+}
+
 }  // namespace blink
diff --git a/third_party/blink/renderer/modules/webgl/webgl_context_attribute_helpers.h b/third_party/blink/renderer/modules/webgl/webgl_context_attribute_helpers.h
index ea8c979..61988273 100644
--- a/third_party/blink/renderer/modules/webgl/webgl_context_attribute_helpers.h
+++ b/third_party/blink/renderer/modules/webgl/webgl_context_attribute_helpers.h
@@ -8,6 +8,11 @@
 #include "third_party/blink/public/platform/platform.h"
 #include "third_party/blink/renderer/core/html/canvas/canvas_context_creation_attributes_core.h"
 #include "third_party/blink/renderer/modules/webgl/webgl_context_attributes.h"
+#include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
+
+namespace gl {
+enum class GpuPreference;
+}
 
 namespace blink {
 
@@ -21,6 +26,12 @@
     Platform::ContextType context_type,
     bool support_own_offscreen_surface);
 
+// Turns the powerPreference context creation attribute into the
+// gl::GpuPreference enum which is sent along with GPU switching
+// notifications. This must not return the kDefault constant, but
+// choose either the low-power or high-performance GPU.
+gl::GpuPreference PowerPreferenceToGpuPreference(String power_preference);
+
 }  // namespace blink
 
 #endif  // THIRD_PARTY_BLINK_RENDERER_MODULES_WEBGL_WEBGL_CONTEXT_ATTRIBUTE_HELPERS_H_
diff --git a/third_party/blink/renderer/modules/webgl/webgl_renderbuffer.cc b/third_party/blink/renderer/modules/webgl/webgl_renderbuffer.cc
index cecfa2b..34255af 100644
--- a/third_party/blink/renderer/modules/webgl/webgl_renderbuffer.cc
+++ b/third_party/blink/renderer/modules/webgl/webgl_renderbuffer.cc
@@ -39,6 +39,7 @@
       internal_format_(GL_RGBA4),
       width_(0),
       height_(0),
+      is_multisampled_(false),
       has_ever_been_bound_(false) {
   GLuint rbo;
   ctx->ContextGL()->GenRenderbuffers(1, &rbo);
@@ -52,6 +53,16 @@
   object_ = 0;
 }
 
+int WebGLRenderbuffer::UpdateMultisampleState(bool multisampled) {
+  int result = 0;
+  if (!is_multisampled_ && multisampled)
+    result = 1;
+  if (is_multisampled_ && !multisampled)
+    result = -1;
+  is_multisampled_ = multisampled;
+  return result;
+}
+
 void WebGLRenderbuffer::Trace(blink::Visitor* visitor) {
   WebGLSharedPlatform3DObject::Trace(visitor);
 }
diff --git a/third_party/blink/renderer/modules/webgl/webgl_renderbuffer.h b/third_party/blink/renderer/modules/webgl/webgl_renderbuffer.h
index 7ce5daaf..dd1897f 100644
--- a/third_party/blink/renderer/modules/webgl/webgl_renderbuffer.h
+++ b/third_party/blink/renderer/modules/webgl/webgl_renderbuffer.h
@@ -52,8 +52,15 @@
   GLsizei Width() const { return width_; }
   GLsizei Height() const { return height_; }
 
-  bool HasEverBeenBound() const { return Object() && has_ever_been_bound_; }
+  // Returns:
+  //   -1 if the renderbuffer *used to be* multisampled and *is now*
+  //     single-sampled
+  //   0 if the renderbuffer's multisample state hasn't changed
+  //   1 if the renderbuffer *used to be* single-sampled and *is now*
+  //     multisampled
+  int UpdateMultisampleState(bool multisampled);
 
+  bool HasEverBeenBound() const { return Object() && has_ever_been_bound_; }
   void SetHasEverBeenBound() { has_ever_been_bound_ = true; }
 
   void Trace(blink::Visitor*) override;
@@ -66,6 +73,7 @@
 
   GLenum internal_format_;
   GLsizei width_, height_;
+  bool is_multisampled_;
 
   bool has_ever_been_bound_;
 };
diff --git a/third_party/blink/renderer/modules/webgl/webgl_rendering_context_base.cc b/third_party/blink/renderer/modules/webgl/webgl_rendering_context_base.cc
index 65d7ab0..a3420be 100644
--- a/third_party/blink/renderer/modules/webgl/webgl_rendering_context_base.cc
+++ b/third_party/blink/renderer/modules/webgl/webgl_rendering_context_base.cc
@@ -837,6 +837,12 @@
   return xr_compatible_;
 }
 
+void WebGLRenderingContextBase::
+    UpdateNumberOfUserAllocatedMultisampledRenderbuffers(int delta) {
+  DCHECK(delta >= -1 && delta <= 1);
+  number_of_user_allocated_multisampled_renderbuffers_ += delta;
+}
+
 namespace {
 
 // Exposed by GL_ANGLE_depth_texture
@@ -1010,7 +1016,8 @@
       feature_handle_for_scheduler_(
           host->GetTopExecutionContext()->GetScheduler()->RegisterFeature(
               SchedulingPolicy::Feature::kWebGL,
-              {SchedulingPolicy::RecordMetricsForBackForwardCache()})) {
+              {SchedulingPolicy::RecordMetricsForBackForwardCache()})),
+      number_of_user_allocated_multisampled_renderbuffers_(0) {
   DCHECK(context_provider);
 
   // TODO(http://crbug.com/876140) Make sure this is being created on a
@@ -1065,14 +1072,15 @@
 scoped_refptr<DrawingBuffer> WebGLRenderingContextBase::CreateDrawingBuffer(
     std::unique_ptr<WebGraphicsContext3DProvider> context_provider,
     bool using_gpu_compositing) {
-  bool premultiplied_alpha = CreationAttributes().premultiplied_alpha;
-  bool want_alpha_channel = CreationAttributes().alpha;
-  bool want_depth_buffer = CreationAttributes().depth;
-  bool want_stencil_buffer = CreationAttributes().stencil;
-  bool want_antialiasing = CreationAttributes().antialias;
-  DrawingBuffer::PreserveDrawingBuffer preserve =
-      CreationAttributes().preserve_drawing_buffer ? DrawingBuffer::kPreserve
-                                                   : DrawingBuffer::kDiscard;
+  const CanvasContextCreationAttributesCore& attrs = CreationAttributes();
+  bool premultiplied_alpha = attrs.premultiplied_alpha;
+  bool want_alpha_channel = attrs.alpha;
+  bool want_depth_buffer = attrs.depth;
+  bool want_stencil_buffer = attrs.stencil;
+  bool want_antialiasing = attrs.antialias;
+  DrawingBuffer::PreserveDrawingBuffer preserve = attrs.preserve_drawing_buffer
+                                                      ? DrawingBuffer::kPreserve
+                                                      : DrawingBuffer::kDiscard;
   DrawingBuffer::WebGLVersion web_gl_version = DrawingBuffer::kWebGL1;
   if (context_type_ == Platform::kWebGL1ContextType) {
     web_gl_version = DrawingBuffer::kWebGL1;
@@ -1099,13 +1107,14 @@
   bool using_swap_chain =
       base::FeatureList::IsEnabled(kLowLatencyWebGLSwapChain) &&
       context_provider->GetCapabilities().shared_image_swap_chain &&
-      CreationAttributes().desynchronized;
+      attrs.desynchronized;
 
   return DrawingBuffer::Create(
       std::move(context_provider), using_gpu_compositing, using_swap_chain,
       this, ClampedCanvasSize(), premultiplied_alpha, want_alpha_channel,
       want_depth_buffer, want_stencil_buffer, want_antialiasing, preserve,
-      web_gl_version, chromium_image_usage, ColorParams());
+      web_gl_version, chromium_image_usage, ColorParams(),
+      PowerPreferenceToGpuPreference(attrs.power_preference));
 }
 
 void WebGLRenderingContextBase::InitializeNewContext() {
@@ -1257,6 +1266,8 @@
   supported_tex_image_source_types_.clear();
   ADD_VALUES_TO_SET(supported_tex_image_source_types_, kSupportedTypesES2);
 
+  number_of_user_allocated_multisampled_renderbuffers_ = 0;
+
   // The DrawingBuffer was unable to store the state that dirtied when it was
   // initialized. Restore it now.
   GetDrawingBuffer()->RestoreAllState();
@@ -4508,6 +4519,8 @@
                         "invalid internalformat");
       break;
   }
+  UpdateNumberOfUserAllocatedMultisampledRenderbuffers(
+      renderbuffer_binding_->UpdateMultisampleState(false));
 }
 
 void WebGLRenderingContextBase::renderbufferStorage(GLenum target,
@@ -6783,6 +6796,17 @@
 void WebGLRenderingContextBase::
     DrawingBufferClientRestorePixelPackBufferBinding() {}
 
+bool WebGLRenderingContextBase::
+    DrawingBufferClientUserAllocatedMultisampledRenderbuffers() {
+  return number_of_user_allocated_multisampled_renderbuffers_ > 0;
+}
+
+void WebGLRenderingContextBase::
+    DrawingBufferClientForceLostContextWithAutoRecovery() {
+  ForceLostContext(WebGLRenderingContextBase::kSyntheticLostContext,
+                   WebGLRenderingContextBase::kAuto);
+}
+
 ScriptValue WebGLRenderingContextBase::GetBooleanParameter(
     ScriptState* script_state,
     GLenum pname) {
diff --git a/third_party/blink/renderer/modules/webgl/webgl_rendering_context_base.h b/third_party/blink/renderer/modules/webgl/webgl_rendering_context_base.h
index 8368b276..9549f51 100644
--- a/third_party/blink/renderer/modules/webgl/webgl_rendering_context_base.h
+++ b/third_party/blink/renderer/modules/webgl/webgl_rendering_context_base.h
@@ -619,6 +619,8 @@
   ScriptPromise makeXRCompatible(ScriptState*);
   bool IsXRCompatible();
 
+  void UpdateNumberOfUserAllocatedMultisampledRenderbuffers(int delta);
+
  protected:
   friend class EXTDisjointTimerQuery;
   friend class EXTDisjointTimerQueryWebGL2;
@@ -681,6 +683,8 @@
   void DrawingBufferClientRestoreFramebufferBinding() override;
   void DrawingBufferClientRestorePixelUnpackBufferBinding() override;
   void DrawingBufferClientRestorePixelPackBufferBinding() override;
+  bool DrawingBufferClientUserAllocatedMultisampledRenderbuffers() override;
+  void DrawingBufferClientForceLostContextWithAutoRecovery() override;
 
   virtual void DestroyContext();
   void MarkContextChanged(ContentChangeType);
@@ -1761,6 +1765,8 @@
   FrameOrWorkerScheduler::SchedulingAffectingFeatureHandle
       feature_handle_for_scheduler_;
 
+  int number_of_user_allocated_multisampled_renderbuffers_;
+
   DISALLOW_COPY_AND_ASSIGN(WebGLRenderingContextBase);
 };
 
diff --git a/third_party/blink/renderer/modules/webgpu/BUILD.gn b/third_party/blink/renderer/modules/webgpu/BUILD.gn
index ef46d40..4f2d528 100644
--- a/third_party/blink/renderer/modules/webgpu/BUILD.gn
+++ b/third_party/blink/renderer/modules/webgpu/BUILD.gn
@@ -71,6 +71,8 @@
     "gpu_validation_error.h",
     "navigator_gpu.cc",
     "navigator_gpu.h",
+    "worker_navigator_gpu.cc",
+    "worker_navigator_gpu.h",
   ]
   deps = [
     "//third_party/dawn/src/dawn:dawn_headers",
diff --git a/third_party/blink/renderer/modules/webgpu/gpu.cc b/third_party/blink/renderer/modules/webgpu/gpu.cc
index 75c6433..30f7ef5 100644
--- a/third_party/blink/renderer/modules/webgpu/gpu.cc
+++ b/third_party/blink/renderer/modules/webgpu/gpu.cc
@@ -15,27 +15,67 @@
 #include "third_party/blink/renderer/modules/webgpu/gpu_adapter.h"
 #include "third_party/blink/renderer/modules/webgpu/gpu_request_adapter_options.h"
 #include "third_party/blink/renderer/platform/graphics/gpu/dawn_control_client_holder.h"
+#include "third_party/blink/renderer/platform/scheduler/public/post_cross_thread_task.h"
+#include "third_party/blink/renderer/platform/scheduler/public/thread.h"
+#include "third_party/blink/renderer/platform/weborigin/kurl.h"
+#include "third_party/blink/renderer/platform/wtf/cross_thread_functional.h"
 
 namespace blink {
 
+namespace {
+
+void CreateContextProvider(
+    const KURL& url,
+    base::WaitableEvent* waitable_event,
+    std::unique_ptr<WebGraphicsContext3DProvider>* created_context_provider) {
+  DCHECK(IsMainThread());
+  *created_context_provider =
+      Platform::Current()->CreateWebGPUGraphicsContext3DProvider(url);
+  waitable_event->Signal();
+}
+
+std::unique_ptr<WebGraphicsContext3DProvider> CreateContextProviderOnMainThread(
+    const KURL& url) {
+  scoped_refptr<base::SingleThreadTaskRunner> task_runner =
+      Thread::MainThread()->GetTaskRunner();
+
+  base::WaitableEvent waitable_event;
+  std::unique_ptr<WebGraphicsContext3DProvider> created_context_provider;
+  PostCrossThreadTask(
+      *task_runner, FROM_HERE,
+      CrossThreadBindOnce(&CreateContextProvider, url,
+                          CrossThreadUnretained(&waitable_event),
+                          CrossThreadUnretained(&created_context_provider)));
+
+  waitable_event.Wait();
+  return created_context_provider;
+}
+
+}  // anonymous namespace
+
 // static
 GPU* GPU::Create(ExecutionContext& execution_context) {
-  const auto& url = execution_context.Url();
-  Platform::GraphicsInfo info;
+  const KURL& url = execution_context.Url();
 
-  std::unique_ptr<WebGraphicsContext3DProvider> context_provider =
-      Platform::Current()->CreateWebGPUGraphicsContext3DProvider(url, &info);
+  std::unique_ptr<WebGraphicsContext3DProvider> context_provider;
+  if (IsMainThread()) {
+    context_provider =
+        Platform::Current()->CreateWebGPUGraphicsContext3DProvider(url);
+  } else {
+    context_provider = CreateContextProviderOnMainThread(url);
+  }
 
   // TODO(kainino): we will need a better way of accessing the GPU interface
   // from multiple threads than BindToCurrentThread et al.
-  if (context_provider && context_provider->BindToCurrentThread()) {
-    info.error_message =
-        String("bindToCurrentThread failed: " + String(info.error_message));
+  if (context_provider && !context_provider->BindToCurrentThread()) {
+    // TODO(crbug.com/973017): Collect GPU info and surface context creation
+    // error.
+    return nullptr;
   }
 
   if (!context_provider) {
-    // TODO(kainino): send the error message somewhere
-    // (see ExtractWebGLContextCreationError).
+    // TODO(crbug.com/973017): Collect GPU info and surface context creation
+    // error.
     return nullptr;
   }
 
diff --git a/third_party/blink/renderer/modules/webgpu/gpu.idl b/third_party/blink/renderer/modules/webgpu/gpu.idl
index 393ae11..44736c7 100644
--- a/third_party/blink/renderer/modules/webgpu/gpu.idl
+++ b/third_party/blink/renderer/modules/webgpu/gpu.idl
@@ -10,7 +10,7 @@
 typedef (sequence<unsigned long> or GPUOrigin3DDict) GPUOrigin3D;
 
 [
-    RuntimeEnabled=WebGPU
+    Exposed(Window WebGPU, Worker WebGPU)
 ] interface GPU {
     [
       RuntimeEnabled=WebGPU,
diff --git a/third_party/blink/renderer/modules/webgpu/gpu_adapter.idl b/third_party/blink/renderer/modules/webgpu/gpu_adapter.idl
index 0c14346..a5d12ecc 100644
--- a/third_party/blink/renderer/modules/webgpu/gpu_adapter.idl
+++ b/third_party/blink/renderer/modules/webgpu/gpu_adapter.idl
@@ -5,7 +5,7 @@
 // https://gpuweb.github.io/gpuweb/
 
 [
-    RuntimeEnabled=WebGPU
+    Exposed(Window WebGPU, Worker WebGPU)
 ] interface GPUAdapter {
     readonly attribute DOMString name;
 
diff --git a/third_party/blink/renderer/modules/webgpu/gpu_bind_group.idl b/third_party/blink/renderer/modules/webgpu/gpu_bind_group.idl
index 7affa268..dbb19a65 100644
--- a/third_party/blink/renderer/modules/webgpu/gpu_bind_group.idl
+++ b/third_party/blink/renderer/modules/webgpu/gpu_bind_group.idl
@@ -5,6 +5,6 @@
 // https://gpuweb.github.io/gpuweb/
 
 [
-    RuntimeEnabled=WebGPU
+    Exposed(Window WebGPU, Worker WebGPU)
 ] interface GPUBindGroup {
 };
diff --git a/third_party/blink/renderer/modules/webgpu/gpu_bind_group_layout.idl b/third_party/blink/renderer/modules/webgpu/gpu_bind_group_layout.idl
index 00c5707..20dafb87 100644
--- a/third_party/blink/renderer/modules/webgpu/gpu_bind_group_layout.idl
+++ b/third_party/blink/renderer/modules/webgpu/gpu_bind_group_layout.idl
@@ -5,6 +5,6 @@
 // https://gpuweb.github.io/gpuweb/
 
 [
-    RuntimeEnabled=WebGPU
+    Exposed(Window WebGPU, Worker WebGPU)
 ] interface GPUBindGroupLayout {
 };
diff --git a/third_party/blink/renderer/modules/webgpu/gpu_buffer.idl b/third_party/blink/renderer/modules/webgpu/gpu_buffer.idl
index 1728f46..2db4c05 100644
--- a/third_party/blink/renderer/modules/webgpu/gpu_buffer.idl
+++ b/third_party/blink/renderer/modules/webgpu/gpu_buffer.idl
@@ -5,7 +5,7 @@
 // https://gpuweb.github.io/gpuweb/
 
 [
-    RuntimeEnabled=WebGPU
+    Exposed(Window WebGPU, Worker WebGPU)
 ] interface GPUBuffer {
     [RaisesException] void setSubData(
         unsigned long long dstOffset,
diff --git a/third_party/blink/renderer/modules/webgpu/gpu_buffer_usage.idl b/third_party/blink/renderer/modules/webgpu/gpu_buffer_usage.idl
index b49cc104..a1706b7 100644
--- a/third_party/blink/renderer/modules/webgpu/gpu_buffer_usage.idl
+++ b/third_party/blink/renderer/modules/webgpu/gpu_buffer_usage.idl
@@ -6,7 +6,7 @@
 
 typedef unsigned long GPUBufferUsageFlags;
 [
-    RuntimeEnabled=WebGPU
+    Exposed(Window WebGPU, Worker WebGPU)
 ] interface GPUBufferUsage {
     const GPUBufferUsageFlags MAP_READ = 1;
     const GPUBufferUsageFlags MAP_WRITE = 2;
diff --git a/third_party/blink/renderer/modules/webgpu/gpu_canvas_context.idl b/third_party/blink/renderer/modules/webgpu/gpu_canvas_context.idl
index feb476c..d5eb80d 100644
--- a/third_party/blink/renderer/modules/webgpu/gpu_canvas_context.idl
+++ b/third_party/blink/renderer/modules/webgpu/gpu_canvas_context.idl
@@ -5,7 +5,7 @@
 // https://gpuweb.github.io/gpuweb/
 
 [
-    RuntimeEnabled=WebGPU
+    Exposed(Window WebGPU, Worker WebGPU)
 ] interface GPUCanvasContext {
     GPUSwapChain configureSwapChain(GPUSwapChainDescriptor descriptor);
 
diff --git a/third_party/blink/renderer/modules/webgpu/gpu_color_write.idl b/third_party/blink/renderer/modules/webgpu/gpu_color_write.idl
index a71fbafd..69bdf6e 100644
--- a/third_party/blink/renderer/modules/webgpu/gpu_color_write.idl
+++ b/third_party/blink/renderer/modules/webgpu/gpu_color_write.idl
@@ -6,7 +6,7 @@
 
 typedef unsigned long GPUColorWriteFlags;
 [
-    RuntimeEnabled=WebGPU
+    Exposed(Window WebGPU, Worker WebGPU)
 ] interface GPUColorWrite {
     const GPUColorWriteFlags RED = 1;
     const GPUColorWriteFlags GREEN = 2;
diff --git a/third_party/blink/renderer/modules/webgpu/gpu_command_buffer.idl b/third_party/blink/renderer/modules/webgpu/gpu_command_buffer.idl
index 6c6af47..75b5b25 100644
--- a/third_party/blink/renderer/modules/webgpu/gpu_command_buffer.idl
+++ b/third_party/blink/renderer/modules/webgpu/gpu_command_buffer.idl
@@ -5,6 +5,6 @@
 // https://gpuweb.github.io/gpuweb/
 
 [
-    RuntimeEnabled=WebGPU
+    Exposed(Window WebGPU, Worker WebGPU)
 ] interface GPUCommandBuffer {
 };
diff --git a/third_party/blink/renderer/modules/webgpu/gpu_command_encoder.idl b/third_party/blink/renderer/modules/webgpu/gpu_command_encoder.idl
index 574ec01e..e93ef35 100644
--- a/third_party/blink/renderer/modules/webgpu/gpu_command_encoder.idl
+++ b/third_party/blink/renderer/modules/webgpu/gpu_command_encoder.idl
@@ -5,7 +5,7 @@
 // https://gpuweb.github.io/gpuweb/
 
 [
-    RuntimeEnabled=WebGPU
+    Exposed(Window WebGPU, Worker WebGPU)
 ] interface GPUCommandEncoder {
     [RaisesException] GPURenderPassEncoder beginRenderPass(GPURenderPassDescriptor descriptor);
     GPUComputePassEncoder beginComputePass(optional GPUComputePassDescriptor descriptor = {});
diff --git a/third_party/blink/renderer/modules/webgpu/gpu_compute_pass_encoder.idl b/third_party/blink/renderer/modules/webgpu/gpu_compute_pass_encoder.idl
index dd75cea..dec314d 100644
--- a/third_party/blink/renderer/modules/webgpu/gpu_compute_pass_encoder.idl
+++ b/third_party/blink/renderer/modules/webgpu/gpu_compute_pass_encoder.idl
@@ -5,7 +5,7 @@
 // https://gpuweb.github.io/gpuweb/
 
 [
-    RuntimeEnabled=WebGPU
+    Exposed(Window WebGPU, Worker WebGPU)
 ] interface GPUComputePassEncoder {
     void setPipeline(GPUComputePipeline pipeline);
     void dispatch(unsigned long x,
diff --git a/third_party/blink/renderer/modules/webgpu/gpu_compute_pipeline.idl b/third_party/blink/renderer/modules/webgpu/gpu_compute_pipeline.idl
index 9fb2b5c..49ac61d 100644
--- a/third_party/blink/renderer/modules/webgpu/gpu_compute_pipeline.idl
+++ b/third_party/blink/renderer/modules/webgpu/gpu_compute_pipeline.idl
@@ -5,6 +5,6 @@
 // https://gpuweb.github.io/gpuweb/
 
 [
-    RuntimeEnabled=WebGPU
+    Exposed(Window WebGPU, Worker WebGPU)
 ] interface GPUComputePipeline {
 };
diff --git a/third_party/blink/renderer/modules/webgpu/gpu_device.idl b/third_party/blink/renderer/modules/webgpu/gpu_device.idl
index 56e9b38..f245caf5 100644
--- a/third_party/blink/renderer/modules/webgpu/gpu_device.idl
+++ b/third_party/blink/renderer/modules/webgpu/gpu_device.idl
@@ -5,7 +5,7 @@
 // https://gpuweb.github.io/gpuweb/
 
 [
-    RuntimeEnabled=WebGPU
+    Exposed(Window WebGPU, Worker WebGPU)
 ] interface GPUDevice : EventTarget {
     readonly attribute GPUAdapter adapter;
     [CallWith=ScriptState] readonly attribute Promise<GPUDeviceLostInfo> lost;
diff --git a/third_party/blink/renderer/modules/webgpu/gpu_fence.idl b/third_party/blink/renderer/modules/webgpu/gpu_fence.idl
index df7c035..51633406 100644
--- a/third_party/blink/renderer/modules/webgpu/gpu_fence.idl
+++ b/third_party/blink/renderer/modules/webgpu/gpu_fence.idl
@@ -5,7 +5,7 @@
 // https://gpuweb.github.io/gpuweb/
 
 [
-    RuntimeEnabled=WebGPU
+    Exposed(Window WebGPU, Worker WebGPU)
 ] interface GPUFence {
     unsigned long long getCompletedValue();
     [CallWith=ScriptState] Promise<void> onCompletion(unsigned long long completionValue);
diff --git a/third_party/blink/renderer/modules/webgpu/gpu_out_of_memory_error.idl b/third_party/blink/renderer/modules/webgpu/gpu_out_of_memory_error.idl
index 83002f7..bd16e3b0e 100644
--- a/third_party/blink/renderer/modules/webgpu/gpu_out_of_memory_error.idl
+++ b/third_party/blink/renderer/modules/webgpu/gpu_out_of_memory_error.idl
@@ -6,6 +6,6 @@
 
 [
     Constructor(),
-    RuntimeEnabled=WebGPU
+    Exposed(Window WebGPU, Worker WebGPU)
 ] interface GPUOutOfMemoryError {
 };
diff --git a/third_party/blink/renderer/modules/webgpu/gpu_pipeline_layout.idl b/third_party/blink/renderer/modules/webgpu/gpu_pipeline_layout.idl
index 3fbf4922..f192dea 100644
--- a/third_party/blink/renderer/modules/webgpu/gpu_pipeline_layout.idl
+++ b/third_party/blink/renderer/modules/webgpu/gpu_pipeline_layout.idl
@@ -5,6 +5,6 @@
 // https://gpuweb.github.io/gpuweb/
 
 [
-    RuntimeEnabled=WebGPU
+    Exposed(Window WebGPU, Worker WebGPU)
 ] interface GPUPipelineLayout {
 };
diff --git a/third_party/blink/renderer/modules/webgpu/gpu_queue.idl b/third_party/blink/renderer/modules/webgpu/gpu_queue.idl
index 2cb3f9c..fd6251e 100644
--- a/third_party/blink/renderer/modules/webgpu/gpu_queue.idl
+++ b/third_party/blink/renderer/modules/webgpu/gpu_queue.idl
@@ -5,7 +5,7 @@
 // https://gpuweb.github.io/gpuweb/
 
 [
-    RuntimeEnabled=WebGPU
+    Exposed(Window WebGPU, Worker WebGPU)
 ] interface GPUQueue {
     void submit(sequence<GPUCommandBuffer> buffers);
 
diff --git a/third_party/blink/renderer/modules/webgpu/gpu_render_bundle.idl b/third_party/blink/renderer/modules/webgpu/gpu_render_bundle.idl
index c6f5c5ec..ba301eb 100644
--- a/third_party/blink/renderer/modules/webgpu/gpu_render_bundle.idl
+++ b/third_party/blink/renderer/modules/webgpu/gpu_render_bundle.idl
@@ -5,6 +5,6 @@
 // https://gpuweb.github.io/gpuweb/
 
 [
-    RuntimeEnabled=WebGPU
+    Exposed(Window WebGPU, Worker WebGPU)
 ] interface GPURenderBundle {
 };
diff --git a/third_party/blink/renderer/modules/webgpu/gpu_render_bundle_encoder.idl b/third_party/blink/renderer/modules/webgpu/gpu_render_bundle_encoder.idl
index 1ee00378..98355ab 100644
--- a/third_party/blink/renderer/modules/webgpu/gpu_render_bundle_encoder.idl
+++ b/third_party/blink/renderer/modules/webgpu/gpu_render_bundle_encoder.idl
@@ -5,7 +5,7 @@
 // https://gpuweb.github.io/gpuweb/
 
 [
-    RuntimeEnabled=WebGPU
+    Exposed(Window WebGPU, Worker WebGPU)
 ] interface GPURenderBundleEncoder {
     GPURenderBundle finish(optional GPURenderBundleDescriptor descriptor = {});
 };
diff --git a/third_party/blink/renderer/modules/webgpu/gpu_render_pass_encoder.idl b/third_party/blink/renderer/modules/webgpu/gpu_render_pass_encoder.idl
index 524f750..867958c 100644
--- a/third_party/blink/renderer/modules/webgpu/gpu_render_pass_encoder.idl
+++ b/third_party/blink/renderer/modules/webgpu/gpu_render_pass_encoder.idl
@@ -5,7 +5,7 @@
 // https://gpuweb.github.io/gpuweb/
 
 [
-    RuntimeEnabled=WebGPU
+    Exposed(Window WebGPU, Worker WebGPU)
 ] interface GPURenderPassEncoder {
     void setViewport(float x, float y,
                      float width, float height,
diff --git a/third_party/blink/renderer/modules/webgpu/gpu_render_pipeline.cc b/third_party/blink/renderer/modules/webgpu/gpu_render_pipeline.cc
index 56fc21a3..afb92057 100644
--- a/third_party/blink/renderer/modules/webgpu/gpu_render_pipeline.cc
+++ b/third_party/blink/renderer/modules/webgpu/gpu_render_pipeline.cc
@@ -4,7 +4,7 @@
 
 #include "third_party/blink/renderer/modules/webgpu/gpu_render_pipeline.h"
 
-#include "third_party/blink/renderer/bindings/modules/v8/v8_gpu_vertex_buffer_descriptor.h"
+#include "third_party/blink/renderer/bindings/modules/v8/v8_gpu_vertex_buffer_layout_descriptor.h"
 #include "third_party/blink/renderer/modules/webgpu/dawn_conversions.h"
 #include "third_party/blink/renderer/modules/webgpu/gpu_blend_descriptor.h"
 #include "third_party/blink/renderer/modules/webgpu/gpu_color_state_descriptor.h"
@@ -12,8 +12,8 @@
 #include "third_party/blink/renderer/modules/webgpu/gpu_device.h"
 #include "third_party/blink/renderer/modules/webgpu/gpu_pipeline_layout.h"
 #include "third_party/blink/renderer/modules/webgpu/gpu_render_pipeline_descriptor.h"
-#include "third_party/blink/renderer/modules/webgpu/gpu_vertex_buffer_descriptor.h"
-#include "third_party/blink/renderer/modules/webgpu/gpu_vertex_input_descriptor.h"
+#include "third_party/blink/renderer/modules/webgpu/gpu_vertex_buffer_layout_descriptor.h"
+#include "third_party/blink/renderer/modules/webgpu/gpu_vertex_state_descriptor.h"
 #include "third_party/blink/renderer/platform/bindings/exception_state.h"
 #include "third_party/blink/renderer/platform/bindings/script_state.h"
 
@@ -84,21 +84,21 @@
   return dawn_desc;
 }
 
-using WGPUVertexInputInfo = std::tuple<WGPUVertexInputDescriptor,
-                                       Vector<WGPUVertexBufferDescriptor>,
+using WGPUVertexStateInfo = std::tuple<WGPUVertexStateDescriptor,
+                                       Vector<WGPUVertexBufferLayoutDescriptor>,
                                        Vector<WGPUVertexAttributeDescriptor>>;
 
-WGPUVertexInputInfo GPUVertexInputAsWGPUInputState(
+WGPUVertexStateInfo GPUVertexStateAsWGPUVertexState(
     v8::Isolate* isolate,
-    const GPUVertexInputDescriptor* descriptor,
+    const GPUVertexStateDescriptor* descriptor,
     ExceptionState& exception_state) {
-  WGPUVertexInputDescriptor dawn_desc = {};
+  WGPUVertexStateDescriptor dawn_desc = {};
   dawn_desc.indexFormat =
       AsDawnEnum<WGPUIndexFormat>(descriptor->indexFormat());
-  dawn_desc.bufferCount = 0;
-  dawn_desc.buffers = nullptr;
+  dawn_desc.vertexBufferCount = 0;
+  dawn_desc.vertexBuffers = nullptr;
 
-  Vector<WGPUVertexBufferDescriptor> dawn_vertex_buffers;
+  Vector<WGPUVertexBufferLayoutDescriptor> dawn_vertex_buffers;
   Vector<WGPUVertexAttributeDescriptor> dawn_vertex_attributes;
 
   if (descriptor->hasVertexBuffers()) {
@@ -116,18 +116,18 @@
     v8::Local<v8::Array> vertex_buffers = vertex_buffers_value.As<v8::Array>();
 
     // First we collect all the descriptors but we don't set
-    // WGPUVertexBufferDescriptor::attributes
+    // WGPUVertexBufferLayoutDescriptor::attributes
     // TODO(cwallez@chromium.org): Should we validate the Length() first so we
-    // don't risk creating HUGE vectors of WGPUVertexBufferDescriptor from the
-    // sparse array?
+    // don't risk creating HUGE vectors of WGPUVertexBufferLayoutDescriptor from
+    // the sparse array?
     for (uint32_t i = 0; i < vertex_buffers->Length(); ++i) {
       // This array can be sparse. Skip empty slots.
       v8::MaybeLocal<v8::Value> maybe_value = vertex_buffers->Get(context, i);
       v8::Local<v8::Value> value;
       if (!maybe_value.ToLocal(&value) || value.IsEmpty() ||
           value->IsNullOrUndefined()) {
-        WGPUVertexBufferDescriptor dawn_vertex_buffer = {};
-        dawn_vertex_buffer.stride = 0;
+        WGPUVertexBufferLayoutDescriptor dawn_vertex_buffer = {};
+        dawn_vertex_buffer.arrayStride = 0;
         dawn_vertex_buffer.stepMode = WGPUInputStepMode_Vertex;
         dawn_vertex_buffer.attributeCount = 0;
         dawn_vertex_buffer.attributes = nullptr;
@@ -135,26 +135,26 @@
         continue;
       }
 
-      GPUVertexBufferDescriptor vertex_buffer;
-      V8GPUVertexBufferDescriptor::ToImpl(isolate, value, &vertex_buffer,
-                                          exception_state);
+      GPUVertexBufferLayoutDescriptor vertex_buffer;
+      V8GPUVertexBufferLayoutDescriptor::ToImpl(isolate, value, &vertex_buffer,
+                                                exception_state);
       if (exception_state.HadException()) {
         return std::make_tuple(dawn_desc, std::move(dawn_vertex_buffers),
                                std::move(dawn_vertex_attributes));
       }
 
-      WGPUVertexBufferDescriptor dawn_vertex_buffer = {};
-      dawn_vertex_buffer.stride = vertex_buffer.stride();
+      WGPUVertexBufferLayoutDescriptor dawn_vertex_buffer = {};
+      dawn_vertex_buffer.arrayStride = vertex_buffer.arrayStride();
       dawn_vertex_buffer.stepMode =
           AsDawnEnum<WGPUInputStepMode>(vertex_buffer.stepMode());
       dawn_vertex_buffer.attributeCount =
-          static_cast<uint32_t>(vertex_buffer.attributeSet().size());
+          static_cast<uint32_t>(vertex_buffer.attributes().size());
       dawn_vertex_buffer.attributes = nullptr;
       dawn_vertex_buffers.push_back(dawn_vertex_buffer);
 
-      for (wtf_size_t j = 0; j < vertex_buffer.attributeSet().size(); ++j) {
+      for (wtf_size_t j = 0; j < vertex_buffer.attributes().size(); ++j) {
         const GPUVertexAttributeDescriptor* attribute =
-            vertex_buffer.attributeSet()[j];
+            vertex_buffer.attributes()[j];
         WGPUVertexAttributeDescriptor dawn_vertex_attribute = {};
         dawn_vertex_attribute.shaderLocation = attribute->shaderLocation();
         dawn_vertex_attribute.offset = attribute->offset();
@@ -164,10 +164,11 @@
       }
     }
 
-    // Set up pointers in DawnVertexBufferDescriptor::attributes only after we
-    // stopped appending to the vector so the pointers aren't invalidated.
+    // Set up pointers in DawnVertexBufferLayoutDescriptor::attributes only
+    // after we stopped appending to the vector so the pointers aren't
+    // invalidated.
     uint32_t attributeIndex = 0;
-    for (WGPUVertexBufferDescriptor& buffer : dawn_vertex_buffers) {
+    for (WGPUVertexBufferLayoutDescriptor& buffer : dawn_vertex_buffers) {
       if (buffer.attributeCount == 0) {
         continue;
       }
@@ -176,8 +177,9 @@
     }
   }
 
-  dawn_desc.bufferCount = static_cast<uint32_t>(dawn_vertex_buffers.size());
-  dawn_desc.buffers = dawn_vertex_buffers.data();
+  dawn_desc.vertexBufferCount =
+      static_cast<uint32_t>(dawn_vertex_buffers.size());
+  dawn_desc.vertexBuffers = dawn_vertex_buffers.data();
 
   return std::make_tuple(dawn_desc, std::move(dawn_vertex_buffers),
                          std::move(dawn_vertex_attributes));
@@ -226,13 +228,12 @@
     dawn_desc.fragmentStage = nullptr;
   }
 
-  // TODO(crbug.com/dawn/131): Update Dawn to match WebGPU vertex input
   v8::Isolate* isolate = script_state->GetIsolate();
   ExceptionState exception_state(isolate, ExceptionState::kConstructionContext,
-                                 "GPUVertexInputDescriptor");
-  WGPUVertexInputInfo vertex_input_info = GPUVertexInputAsWGPUInputState(
-      isolate, webgpu_desc->vertexInput(), exception_state);
-  dawn_desc.vertexInput = &std::get<0>(vertex_input_info);
+                                 "GPUVertexStateDescriptor");
+  WGPUVertexStateInfo vertex_state_info = GPUVertexStateAsWGPUVertexState(
+      isolate, webgpu_desc->vertexState(), exception_state);
+  dawn_desc.vertexState = &std::get<0>(vertex_state_info);
 
   if (exception_state.HadException()) {
     return nullptr;
diff --git a/third_party/blink/renderer/modules/webgpu/gpu_render_pipeline.idl b/third_party/blink/renderer/modules/webgpu/gpu_render_pipeline.idl
index a4a1c7f1..deeddd5c 100644
--- a/third_party/blink/renderer/modules/webgpu/gpu_render_pipeline.idl
+++ b/third_party/blink/renderer/modules/webgpu/gpu_render_pipeline.idl
@@ -5,6 +5,6 @@
 // https://gpuweb.github.io/gpuweb/
 
 [
-    RuntimeEnabled=WebGPU
+    Exposed(Window WebGPU, Worker WebGPU)
 ] interface GPURenderPipeline {
 };
diff --git a/third_party/blink/renderer/modules/webgpu/gpu_render_pipeline_descriptor.idl b/third_party/blink/renderer/modules/webgpu/gpu_render_pipeline_descriptor.idl
index 0017094..79572d9 100644
--- a/third_party/blink/renderer/modules/webgpu/gpu_render_pipeline_descriptor.idl
+++ b/third_party/blink/renderer/modules/webgpu/gpu_render_pipeline_descriptor.idl
@@ -12,7 +12,7 @@
     GPURasterizationStateDescriptor rasterizationState = {};
     required sequence<GPUColorStateDescriptor> colorStates;
     GPUDepthStencilStateDescriptor depthStencilState;
-    GPUVertexInputDescriptor vertexInput = {};
+    GPUVertexStateDescriptor vertexState = {};
 
     unsigned long sampleCount = 1;
 
diff --git a/third_party/blink/renderer/modules/webgpu/gpu_sampler.idl b/third_party/blink/renderer/modules/webgpu/gpu_sampler.idl
index 96599ce..afb0b4e 100644
--- a/third_party/blink/renderer/modules/webgpu/gpu_sampler.idl
+++ b/third_party/blink/renderer/modules/webgpu/gpu_sampler.idl
@@ -5,6 +5,6 @@
 // https://gpuweb.github.io/gpuweb/
 
 [
-    RuntimeEnabled=WebGPU
+    Exposed(Window WebGPU, Worker WebGPU)
 ] interface GPUSampler {
 };
diff --git a/third_party/blink/renderer/modules/webgpu/gpu_shader_module.idl b/third_party/blink/renderer/modules/webgpu/gpu_shader_module.idl
index dd63cdf2..e8d42b9 100644
--- a/third_party/blink/renderer/modules/webgpu/gpu_shader_module.idl
+++ b/third_party/blink/renderer/modules/webgpu/gpu_shader_module.idl
@@ -5,6 +5,6 @@
 // https://gpuweb.github.io/gpuweb/
 
 [
-    RuntimeEnabled=WebGPU
+    Exposed(Window WebGPU, Worker WebGPU)
 ] interface GPUShaderModule {
 };
diff --git a/third_party/blink/renderer/modules/webgpu/gpu_shader_stage.idl b/third_party/blink/renderer/modules/webgpu/gpu_shader_stage.idl
index 546221e2..341d97054 100644
--- a/third_party/blink/renderer/modules/webgpu/gpu_shader_stage.idl
+++ b/third_party/blink/renderer/modules/webgpu/gpu_shader_stage.idl
@@ -6,7 +6,7 @@
 
 typedef unsigned long GPUShaderStageFlags;
 [
-    RuntimeEnabled=WebGPU
+    Exposed(Window WebGPU, Worker WebGPU)
 ] interface GPUShaderStage {
     const GPUShaderStageFlags VERTEX = 1;
     const GPUShaderStageFlags FRAGMENT = 2;
diff --git a/third_party/blink/renderer/modules/webgpu/gpu_swap_chain.idl b/third_party/blink/renderer/modules/webgpu/gpu_swap_chain.idl
index f89aead..d69ae91c 100644
--- a/third_party/blink/renderer/modules/webgpu/gpu_swap_chain.idl
+++ b/third_party/blink/renderer/modules/webgpu/gpu_swap_chain.idl
@@ -5,7 +5,7 @@
 // https://gpuweb.github.io/gpuweb/
 
 [
-    RuntimeEnabled=WebGPU
+    Exposed(Window WebGPU, Worker WebGPU)
 ] interface GPUSwapChain {
     GPUTexture getCurrentTexture();
 };
diff --git a/third_party/blink/renderer/modules/webgpu/gpu_texture.idl b/third_party/blink/renderer/modules/webgpu/gpu_texture.idl
index 67904ef..868ea15 100644
--- a/third_party/blink/renderer/modules/webgpu/gpu_texture.idl
+++ b/third_party/blink/renderer/modules/webgpu/gpu_texture.idl
@@ -5,7 +5,7 @@
 // https://gpuweb.github.io/gpuweb/
 
 [
-    RuntimeEnabled=WebGPU
+    Exposed(Window WebGPU, Worker WebGPU)
 ] interface GPUTexture {
     GPUTextureView createView(optional GPUTextureViewDescriptor descriptor = {});
     void destroy();
diff --git a/third_party/blink/renderer/modules/webgpu/gpu_texture_usage.idl b/third_party/blink/renderer/modules/webgpu/gpu_texture_usage.idl
index d8139ba..50775c3 100644
--- a/third_party/blink/renderer/modules/webgpu/gpu_texture_usage.idl
+++ b/third_party/blink/renderer/modules/webgpu/gpu_texture_usage.idl
@@ -6,7 +6,7 @@
 
 typedef unsigned long GPUTextureUsageFlags;
 [
-    RuntimeEnabled=WebGPU
+    Exposed(Window WebGPU, Worker WebGPU)
 ] interface GPUTextureUsage {
     const GPUTextureUsageFlags COPY_SRC = 1;
     const GPUTextureUsageFlags COPY_DST = 2;
diff --git a/third_party/blink/renderer/modules/webgpu/gpu_texture_view.idl b/third_party/blink/renderer/modules/webgpu/gpu_texture_view.idl
index db31277..03d3626 100644
--- a/third_party/blink/renderer/modules/webgpu/gpu_texture_view.idl
+++ b/third_party/blink/renderer/modules/webgpu/gpu_texture_view.idl
@@ -5,6 +5,6 @@
 // https://gpuweb.github.io/gpuweb/
 
 [
-    RuntimeEnabled=WebGPU
+    Exposed(Window WebGPU, Worker WebGPU)
 ] interface GPUTextureView {
 };
diff --git a/third_party/blink/renderer/modules/webgpu/gpu_uncaptured_error_event.idl b/third_party/blink/renderer/modules/webgpu/gpu_uncaptured_error_event.idl
index 80bed55..a45cdd5 100644
--- a/third_party/blink/renderer/modules/webgpu/gpu_uncaptured_error_event.idl
+++ b/third_party/blink/renderer/modules/webgpu/gpu_uncaptured_error_event.idl
@@ -6,7 +6,7 @@
 
 [
     Constructor(DOMString type, GPUUncapturedErrorEventInit gpuUncapturedErrorEventInitDict),
-    RuntimeEnabled=WebGPU
+    Exposed(Window WebGPU, Worker WebGPU)
 ] interface GPUUncapturedErrorEvent : Event {
     readonly attribute GPUError error;
 };
diff --git a/third_party/blink/renderer/modules/webgpu/gpu_validation_error.idl b/third_party/blink/renderer/modules/webgpu/gpu_validation_error.idl
index 0b93ed1b..d372e5f 100644
--- a/third_party/blink/renderer/modules/webgpu/gpu_validation_error.idl
+++ b/third_party/blink/renderer/modules/webgpu/gpu_validation_error.idl
@@ -6,7 +6,7 @@
 
 [
     Constructor(DOMString message),
-    RuntimeEnabled=WebGPU
+    Exposed(Window WebGPU, Worker WebGPU)
 ] interface GPUValidationError {
     readonly attribute DOMString message;
 };
diff --git a/third_party/blink/renderer/modules/webgpu/gpu_vertex_buffer_descriptor.idl b/third_party/blink/renderer/modules/webgpu/gpu_vertex_buffer_layout_descriptor.idl
similarity index 67%
rename from third_party/blink/renderer/modules/webgpu/gpu_vertex_buffer_descriptor.idl
rename to third_party/blink/renderer/modules/webgpu/gpu_vertex_buffer_layout_descriptor.idl
index a696790..437fd68 100644
--- a/third_party/blink/renderer/modules/webgpu/gpu_vertex_buffer_descriptor.idl
+++ b/third_party/blink/renderer/modules/webgpu/gpu_vertex_buffer_layout_descriptor.idl
@@ -4,10 +4,10 @@
 
 // https://gpuweb.github.io/gpuweb/
 
-dictionary GPUVertexBufferDescriptor {
-    required GPUBufferSize stride;
+dictionary GPUVertexBufferLayoutDescriptor {
+    required GPUBufferSize arrayStride;
     GPUInputStepMode stepMode = "vertex";
-    required sequence<GPUVertexAttributeDescriptor> attributeSet;
+    required sequence<GPUVertexAttributeDescriptor> attributes;
 };
 
 enum GPUInputStepMode {
diff --git a/third_party/blink/renderer/modules/webgpu/gpu_vertex_input_descriptor.idl b/third_party/blink/renderer/modules/webgpu/gpu_vertex_state_descriptor.idl
similarity index 84%
rename from third_party/blink/renderer/modules/webgpu/gpu_vertex_input_descriptor.idl
rename to third_party/blink/renderer/modules/webgpu/gpu_vertex_state_descriptor.idl
index dc30a7c..7a991d1 100644
--- a/third_party/blink/renderer/modules/webgpu/gpu_vertex_input_descriptor.idl
+++ b/third_party/blink/renderer/modules/webgpu/gpu_vertex_state_descriptor.idl
@@ -4,10 +4,10 @@
 
 // https://gpuweb.github.io/gpuweb/
 
-dictionary GPUVertexInputDescriptor {
+dictionary GPUVertexStateDescriptor {
     GPUIndexFormat indexFormat = "uint32";
     // TODO(crbug.com/951629): Make this a sequence of nullables.
-    object vertexBuffers; // We validate this is an array of nullable GPUVertexBufferDescriptor
+    object vertexBuffers; // We validate this is an array of nullable GPUVertexBufferLayoutDescriptor
 };
 
 enum GPUIndexFormat {
diff --git a/third_party/blink/renderer/modules/webgpu/navigator_gpu.cc b/third_party/blink/renderer/modules/webgpu/navigator_gpu.cc
index 1a08230..a221d48 100644
--- a/third_party/blink/renderer/modules/webgpu/navigator_gpu.cc
+++ b/third_party/blink/renderer/modules/webgpu/navigator_gpu.cc
@@ -11,6 +11,7 @@
 
 namespace blink {
 
+// static
 NavigatorGPU& NavigatorGPU::From(Navigator& navigator) {
   NavigatorGPU* supplement =
       Supplement<Navigator>::From<NavigatorGPU>(navigator);
diff --git a/third_party/blink/renderer/modules/webgpu/worker_navigator_gpu.cc b/third_party/blink/renderer/modules/webgpu/worker_navigator_gpu.cc
new file mode 100644
index 0000000..8f5e7cb
--- /dev/null
+++ b/third_party/blink/renderer/modules/webgpu/worker_navigator_gpu.cc
@@ -0,0 +1,49 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "third_party/blink/renderer/modules/webgpu/worker_navigator_gpu.h"
+
+#include "third_party/blink/renderer/core/workers/worker_navigator.h"
+#include "third_party/blink/renderer/modules/webgpu/gpu.h"
+
+namespace blink {
+
+// static
+WorkerNavigatorGPU& WorkerNavigatorGPU::From(WorkerNavigator& navigator) {
+  WorkerNavigatorGPU* supplement =
+      Supplement<WorkerNavigator>::From<WorkerNavigatorGPU>(navigator);
+  if (!supplement) {
+    supplement = MakeGarbageCollected<WorkerNavigatorGPU>(navigator);
+    ProvideTo(navigator, supplement);
+  }
+  return *supplement;
+}
+
+// static
+GPU* WorkerNavigatorGPU::gpu(ScriptState* script_state,
+                             WorkerNavigator& navigator) {
+  return WorkerNavigatorGPU::From(navigator).gpu(script_state);
+}
+
+GPU* WorkerNavigatorGPU::gpu(ScriptState* script_state) {
+  if (!gpu_) {
+    ExecutionContext* context = ExecutionContext::From(script_state);
+    DCHECK(context);
+
+    gpu_ = GPU::Create(*context);
+  }
+  return gpu_;
+}
+
+void WorkerNavigatorGPU::Trace(blink::Visitor* visitor) {
+  visitor->Trace(gpu_);
+  Supplement<WorkerNavigator>::Trace(visitor);
+}
+
+WorkerNavigatorGPU::WorkerNavigatorGPU(WorkerNavigator& navigator)
+    : Supplement<WorkerNavigator>(navigator) {}
+
+const char WorkerNavigatorGPU::kSupplementName[] = "WorkerNavigatorGPU";
+
+}  // namespace blink
diff --git a/third_party/blink/renderer/modules/webgpu/worker_navigator_gpu.h b/third_party/blink/renderer/modules/webgpu/worker_navigator_gpu.h
new file mode 100644
index 0000000..0f8eabe1
--- /dev/null
+++ b/third_party/blink/renderer/modules/webgpu/worker_navigator_gpu.h
@@ -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.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_WEBGPU_WORKER_NAVIGATOR_GPU_H_
+#define THIRD_PARTY_BLINK_RENDERER_MODULES_WEBGPU_WORKER_NAVIGATOR_GPU_H_
+
+#include "third_party/blink/renderer/core/workers/worker_navigator.h"
+#include "third_party/blink/renderer/platform/heap/handle.h"
+#include "third_party/blink/renderer/platform/supplementable.h"
+
+namespace blink {
+
+class GPU;
+class WorkerNavigator;
+
+class WorkerNavigatorGPU final : public GarbageCollected<WorkerNavigatorGPU>,
+                                 public Supplement<WorkerNavigator> {
+  USING_GARBAGE_COLLECTED_MIXIN(WorkerNavigatorGPU);
+
+ public:
+  static const char kSupplementName[];
+
+  // Gets, or creates, WorkerNavigatorGPU supplement on WorkerNavigator.
+  // See platform/Supplementable.h
+  static WorkerNavigatorGPU& From(WorkerNavigator&);
+
+  static GPU* gpu(ScriptState* script_state, WorkerNavigator&);
+  GPU* gpu(ScriptState* script_state);
+
+  explicit WorkerNavigatorGPU(WorkerNavigator&);
+
+  void Trace(blink::Visitor*) override;
+
+ private:
+  Member<GPU> gpu_;
+
+  DISALLOW_COPY_AND_ASSIGN(WorkerNavigatorGPU);
+};
+
+}  // namespace blink
+
+#endif  // THIRD_PARTY_BLINK_RENDERER_MODULES_WEBGPU_WORKER_NAVIGATOR_GPU_H_
diff --git a/third_party/blink/renderer/modules/webgpu/worker_navigator_gpu.idl b/third_party/blink/renderer/modules/webgpu/worker_navigator_gpu.idl
new file mode 100644
index 0000000..e69ee47
--- /dev/null
+++ b/third_party/blink/renderer/modules/webgpu/worker_navigator_gpu.idl
@@ -0,0 +1,12 @@
+// 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.
+
+// https://gpuweb.github.io/gpuweb/
+
+[
+    Exposed=Worker,
+    ImplementedAs=WorkerNavigatorGPU
+] partial interface WorkerNavigator {
+    [SameObject, RuntimeEnabled=WebGPU, CallWith=ScriptState] readonly attribute GPU gpu;
+};
diff --git a/third_party/blink/renderer/platform/bindings/v8_private_property.h b/third_party/blink/renderer/platform/bindings/v8_private_property.h
index 8201c9a..864454f1 100644
--- a/third_party/blink/renderer/platform/bindings/v8_private_property.h
+++ b/third_party/blink/renderer/platform/bindings/v8_private_property.h
@@ -76,7 +76,6 @@
     friend class V8PrivateProperty;
     // The following classes are exceptionally allowed to call to
     // getFromMainWorld.
-    friend class V8CustomEvent;
     friend class V8ExtendableMessageEvent;
 
     Symbol(v8::Isolate* isolate, v8::Local<v8::Private> private_symbol)
diff --git a/third_party/blink/renderer/platform/exported/platform.cc b/third_party/blink/renderer/platform/exported/platform.cc
index c56556b..46ae6ea 100644
--- a/third_party/blink/renderer/platform/exported/platform.cc
+++ b/third_party/blink/renderer/platform/exported/platform.cc
@@ -328,8 +328,8 @@
 }
 
 std::unique_ptr<WebGraphicsContext3DProvider>
-Platform::CreateWebGPUGraphicsContext3DProvider(const WebURL& top_document_url,
-                                                GraphicsInfo*) {
+Platform::CreateWebGPUGraphicsContext3DProvider(
+    const WebURL& top_document_url) {
   return nullptr;
 }
 
diff --git a/third_party/blink/renderer/platform/graphics/gpu/DEPS b/third_party/blink/renderer/platform/graphics/gpu/DEPS
index b7824e6..aa252c3 100644
--- a/third_party/blink/renderer/platform/graphics/gpu/DEPS
+++ b/third_party/blink/renderer/platform/graphics/gpu/DEPS
@@ -15,4 +15,5 @@
     "+gpu/config/gpu_driver_bug_workaround_type.h",
     "+gpu/config/gpu_feature_info.h",
     "+ui/gfx/gpu_fence.h",
+    "+ui/gl/gpu_preference.h",
 ]
diff --git a/third_party/blink/renderer/platform/graphics/gpu/drawing_buffer.cc b/third_party/blink/renderer/platform/graphics/gpu/drawing_buffer.cc
index f5fab0d..b3e1aee 100644
--- a/third_party/blink/renderer/platform/graphics/gpu/drawing_buffer.cc
+++ b/third_party/blink/renderer/platform/graphics/gpu/drawing_buffer.cc
@@ -64,6 +64,7 @@
 #include "third_party/skia/include/core/SkSurface.h"
 #include "third_party/skia/include/gpu/GrContext.h"
 #include "third_party/skia/include/gpu/gl/GrGLTypes.h"
+#include "ui/gl/gpu_preference.h"
 #include "v8/include/v8.h"
 
 namespace blink {
@@ -90,7 +91,8 @@
     PreserveDrawingBuffer preserve,
     WebGLVersion webgl_version,
     ChromiumImageUsage chromium_image_usage,
-    const CanvasColorParams& color_params) {
+    const CanvasColorParams& color_params,
+    gl::GpuPreference gpu_preference) {
   if (g_should_fail_drawing_buffer_creation_for_testing) {
     g_should_fail_drawing_buffer_creation_for_testing = false;
     return nullptr;
@@ -141,7 +143,7 @@
           std::move(extensions_util), client, discard_framebuffer_supported,
           want_alpha_channel, premultiplied_alpha, preserve, webgl_version,
           want_depth_buffer, want_stencil_buffer, chromium_image_usage,
-          color_params));
+          color_params, gpu_preference));
   if (!drawing_buffer->Initialize(size, multisample_supported)) {
     drawing_buffer->BeginDestruction();
     return scoped_refptr<DrawingBuffer>();
@@ -167,7 +169,8 @@
     bool want_depth,
     bool want_stencil,
     ChromiumImageUsage chromium_image_usage,
-    const CanvasColorParams& color_params)
+    const CanvasColorParams& color_params,
+    gl::GpuPreference gpu_preference)
     : client_(client),
       preserve_drawing_buffer_(preserve),
       webgl_version_(webgl_version),
@@ -188,10 +191,15 @@
                               kF16CanvasPixelFormat),
       chromium_image_usage_(chromium_image_usage),
       opengl_flip_y_extension_(
-          ContextProvider()->GetCapabilities().mesa_framebuffer_flip_y) {
+          ContextProvider()->GetCapabilities().mesa_framebuffer_flip_y),
+      initial_gpu_(gpu_preference),
+      current_active_gpu_(gpu_preference) {
   // Used by browser tests to detect the use of a DrawingBuffer.
   TRACE_EVENT_INSTANT0("test_gpu", "DrawingBufferCreation",
                        TRACE_EVENT_SCOPE_GLOBAL);
+  // PowerPreferenceToGpuPreference should have resolved the meaning
+  // of the "default" GPU already.
+  DCHECK(gpu_preference != gl::GpuPreference::kDefault);
 }
 
 DrawingBuffer::~DrawingBuffer() {
@@ -345,15 +353,15 @@
   ResolveIfNeeded();
 
   if (!using_gpu_compositing_ && !force_gpu_result) {
-    FinishPrepareTransferableResourceSoftware(bitmap_registrar, out_resource,
-                                              out_release_callback);
-  } else {
-    FinishPrepareTransferableResourceGpu(out_resource, out_release_callback);
+    return FinishPrepareTransferableResourceSoftware(
+        bitmap_registrar, out_resource, out_release_callback);
   }
-  return true;
+
+  return FinishPrepareTransferableResourceGpu(out_resource,
+                                              out_release_callback);
 }
 
-void DrawingBuffer::FinishPrepareTransferableResourceSoftware(
+bool DrawingBuffer::FinishPrepareTransferableResourceSoftware(
     cc::SharedBitmapIdRegistrar* bitmap_registrar,
     viz::TransferableResource* out_resource,
     std::unique_ptr<viz::SingleReleaseCallback>* out_release_callback) {
@@ -391,9 +399,10 @@
   *out_release_callback = viz::SingleReleaseCallback::Create(std::move(func));
 
   ResetBuffersToAutoClear();
+  return true;
 }
 
-void DrawingBuffer::FinishPrepareTransferableResourceGpu(
+bool DrawingBuffer::FinishPrepareTransferableResourceGpu(
     viz::TransferableResource* out_resource,
     std::unique_ptr<viz::SingleReleaseCallback>* out_release_callback) {
   DCHECK(state_restorer_);
@@ -419,6 +428,10 @@
     // into the mailbox, and allocate (or recycle) a new backbuffer.
     color_buffer_for_mailbox = back_color_buffer_;
     back_color_buffer_ = CreateOrRecycleColorBuffer();
+    if (!back_color_buffer_) {
+      // Context is likely lost.
+      return false;
+    }
     AttachColorBufferToReadFramebuffer();
 
     // Explicitly specify that m_fbo (which is now bound to the just-allocated
@@ -437,6 +450,10 @@
     // TODO(sunnyps): We can skip this test if explicit resolve is used since
     // we'll render to the multisample fbo which will be preserved.
     color_buffer_for_mailbox = CreateOrRecycleColorBuffer();
+    if (!color_buffer_for_mailbox) {
+      // Context is likely lost.
+      return false;
+    }
     gl_->CopySubTextureCHROMIUM(
         back_color_buffer_->texture_id, 0, texture_target_,
         color_buffer_for_mailbox->texture_id, 0, 0, 0, 0, 0, size_.Width(),
@@ -498,6 +515,7 @@
 
   contents_changed_ = false;
   ResetBuffersToAutoClear();
+  return true;
 }
 
 void DrawingBuffer::MailboxReleasedGpu(scoped_refptr<ColorBuffer> color_buffer,
@@ -1223,13 +1241,45 @@
   contents_change_resolved_ = true;
 
   auto* gl = ContextProvider()->ContextGL();
-  if (gl->DidGpuSwitch() == GL_TRUE) {
-    // TODO(crbug.com/681341): handle preserveDrawingBuffer:true, and
-    // user-allocated multisampled renderbuffers, by dispatching a context lost
-    // event.
-    if (WantExplicitResolve()) {
-      ReallocateMultisampleRenderbuffer(size_);
+  gl::GpuPreference active_gpu = gl::GpuPreference::kDefault;
+  if (gl->DidGpuSwitch(&active_gpu) == GL_TRUE) {
+    // This code path is mainly taken on macOS (the only platform which, as of
+    // this writing, dispatches the GPU-switched notifications), and the
+    // comments below focus only on macOS.
+    //
+    // The code below attempts to deduce whether, if a GPU switch occurred,
+    // it's really necessary to lose the context because certain GPU resources
+    // are no longer accessible. Resources only become inaccessible if
+    // CGLSetVirtualScreen is explicitly called against a GL context to change
+    // its renderer ID. GPU switching notifications are highly asynchronous.
+    //
+    // The tests below, of the initial and currently active GPU, replicate
+    // some logic in GLContextCGL::ForceGpuSwitchIfNeeded. Basically, if a
+    // context requests the high-performance GPU, then CGLSetVirtualScreen
+    // will never be called to migrate that context to the low-power
+    // GPU. However, contexts that were allocated on the integrated GPU will
+    // be migrated to the discrete GPU, and back, when the discrete GPU is
+    // activated and deactivated. Also, if the high-performance GPU was
+    // requested, then that request took effect during context bringup, even
+    // though the GPU switching notification is generally dispatched a couple
+    // of seconds after that, so it's not necessary to either lose the context
+    // or reallocate the multisampled renderbuffers when that initial
+    // notification is received.
+    if (initial_gpu_ == gl::GpuPreference::kLowPower &&
+        current_active_gpu_ != active_gpu) {
+      if ((WantExplicitResolve() && preserve_drawing_buffer_ == kPreserve) ||
+          client_
+              ->DrawingBufferClientUserAllocatedMultisampledRenderbuffers()) {
+        // In these situations there are multisampled renderbuffers whose
+        // content the application expects to be preserved, but which can not
+        // be. Forcing a lost context is the only option to keep applications
+        // rendering correctly.
+        client_->DrawingBufferClientForceLostContextWithAutoRecovery();
+      } else if (WantExplicitResolve()) {
+        ReallocateMultisampleRenderbuffer(size_);
+      }
     }
+    current_active_gpu_ = active_gpu;
   }
 }
 
@@ -1457,6 +1507,11 @@
 
 scoped_refptr<DrawingBuffer::ColorBuffer> DrawingBuffer::CreateColorBuffer(
     const IntSize& size) {
+  if (size.IsEmpty()) {
+    // Context is likely lost.
+    return nullptr;
+  }
+
   DCHECK(state_restorer_);
   state_restorer_->SetFramebufferBindingDirty();
   state_restorer_->SetTextureBindingDirty();
diff --git a/third_party/blink/renderer/platform/graphics/gpu/drawing_buffer.h b/third_party/blink/renderer/platform/graphics/gpu/drawing_buffer.h
index 28908a7..7b4807a0 100644
--- a/third_party/blink/renderer/platform/graphics/gpu/drawing_buffer.h
+++ b/third_party/blink/renderer/platform/graphics/gpu/drawing_buffer.h
@@ -52,6 +52,7 @@
 #include "third_party/khronos/GLES2/gl2.h"
 #include "third_party/skia/include/core/SkBitmap.h"
 #include "ui/gfx/color_space.h"
+#include "ui/gl/gpu_preference.h"
 
 namespace cc {
 class Layer;
@@ -98,6 +99,9 @@
     virtual void DrawingBufferClientRestoreFramebufferBinding() = 0;
     virtual void DrawingBufferClientRestorePixelUnpackBufferBinding() = 0;
     virtual void DrawingBufferClientRestorePixelPackBufferBinding() = 0;
+    virtual bool
+    DrawingBufferClientUserAllocatedMultisampledRenderbuffers() = 0;
+    virtual void DrawingBufferClientForceLostContextWithAutoRecovery() = 0;
   };
 
   enum PreserveDrawingBuffer {
@@ -129,7 +133,8 @@
       PreserveDrawingBuffer,
       WebGLVersion,
       ChromiumImageUsage,
-      const CanvasColorParams&);
+      const CanvasColorParams&,
+      gl::GpuPreference);
   static void ForceNextDrawingBufferCreationToFail();
 
   ~DrawingBuffer() override;
@@ -284,7 +289,8 @@
                 bool wants_depth,
                 bool wants_stencil,
                 ChromiumImageUsage,
-                const CanvasColorParams&);
+                const CanvasColorParams&,
+                gl::GpuPreference gpu_preference);
 
   bool Initialize(const IntSize&, bool use_multisampling);
 
@@ -399,10 +405,10 @@
       bool force_gpu_result);
 
   // Helper functions to be called only by PrepareTransferableResourceInternal.
-  void FinishPrepareTransferableResourceGpu(
+  bool FinishPrepareTransferableResourceGpu(
       viz::TransferableResource* out_resource,
       std::unique_ptr<viz::SingleReleaseCallback>* out_release_callback);
-  void FinishPrepareTransferableResourceSoftware(
+  bool FinishPrepareTransferableResourceSoftware(
       cc::SharedBitmapIdRegistrar* bitmap_registrar,
       viz::TransferableResource* out_resource,
       std::unique_ptr<viz::SingleReleaseCallback>* out_release_callback);
@@ -603,6 +609,9 @@
 
   bool opengl_flip_y_extension_;
 
+  gl::GpuPreference initial_gpu_;
+  gl::GpuPreference current_active_gpu_;
+
   DISALLOW_COPY_AND_ASSIGN(DrawingBuffer);
 };
 
diff --git a/third_party/blink/renderer/platform/graphics/gpu/drawing_buffer_test.cc b/third_party/blink/renderer/platform/graphics/gpu/drawing_buffer_test.cc
index f3919c90..d721d47 100644
--- a/third_party/blink/renderer/platform/graphics/gpu/drawing_buffer_test.cc
+++ b/third_party/blink/renderer/platform/graphics/gpu/drawing_buffer_test.cc
@@ -46,6 +46,7 @@
 #include "third_party/blink/renderer/platform/graphics/gpu/drawing_buffer_test_helpers.h"
 #include "third_party/blink/renderer/platform/graphics/test/gpu_memory_buffer_test_platform.h"
 #include "third_party/blink/renderer/platform/testing/runtime_enabled_features_test_helpers.h"
+#include "ui/gl/gpu_preference.h"
 #include "v8/include/v8.h"
 
 using testing::Test;
@@ -726,7 +727,7 @@
         IntSize(10, 10), premultiplied_alpha, want_alpha_channel,
         want_depth_buffer, want_stencil_buffer, want_antialiasing, preserve,
         DrawingBuffer::kWebGL1, DrawingBuffer::kAllowChromiumImage,
-        CanvasColorParams());
+        CanvasColorParams(), gl::GpuPreference::kHighPerformance);
 
     // When we request a depth or a stencil buffer, we will get both.
     EXPECT_EQ(cases[i].request_depth || cases[i].request_stencil,
@@ -796,7 +797,7 @@
       nullptr, gpu_compositing, false /* using_swap_chain */, nullptr,
       too_big_size, false, false, false, false, false, DrawingBuffer::kDiscard,
       DrawingBuffer::kWebGL1, DrawingBuffer::kAllowChromiumImage,
-      CanvasColorParams());
+      CanvasColorParams(), gl::GpuPreference::kHighPerformance);
   EXPECT_EQ(too_big_drawing_buffer, nullptr);
   drawing_buffer_->BeginDestruction();
 }
diff --git a/third_party/blink/renderer/platform/graphics/gpu/drawing_buffer_test_helpers.h b/third_party/blink/renderer/platform/graphics/gpu/drawing_buffer_test_helpers.h
index 2ef0b27f..8c4ad4b 100644
--- a/third_party/blink/renderer/platform/graphics/gpu/drawing_buffer_test_helpers.h
+++ b/third_party/blink/renderer/platform/graphics/gpu/drawing_buffer_test_helpers.h
@@ -18,6 +18,7 @@
 #include "third_party/blink/renderer/platform/graphics/gpu/drawing_buffer.h"
 #include "third_party/blink/renderer/platform/graphics/gpu/extensions_3d_util.h"
 #include "third_party/blink/renderer/platform/runtime_enabled_features.h"
+#include "ui/gl/gpu_preference.h"
 
 namespace blink {
 
@@ -329,6 +330,13 @@
   void DrawingBufferClientRestorePixelPackBufferBinding() override {
     state_.pixel_pack_buffer_binding = saved_state_.pixel_pack_buffer_binding;
   }
+  bool DrawingBufferClientUserAllocatedMultisampledRenderbuffers() override {
+    // Not unit tested yet. Tested with end-to-end tests.
+    return false;
+  }
+  void DrawingBufferClientForceLostContextWithAutoRecovery() override {
+    // Not unit tested yet. Tested with end-to-end tests.
+  }
 
   // Testing methods.
   gpu::SyncToken MostRecentlyWaitedSyncToken() const {
@@ -461,7 +469,8 @@
             false /* wantDepth */,
             false /* wantStencil */,
             DrawingBuffer::kAllowChromiumImage /* ChromiumImageUsage */,
-            CanvasColorParams()),
+            CanvasColorParams(),
+            gl::GpuPreference::kHighPerformance),
         live_(nullptr) {}
 
   ~DrawingBufferForTests() override {
diff --git a/third_party/blink/renderer/platform/heap/unified_heap_controller.cc b/third_party/blink/renderer/platform/heap/unified_heap_controller.cc
index 708d7c9..d618263 100644
--- a/third_party/blink/renderer/platform/heap/unified_heap_controller.cc
+++ b/third_party/blink/renderer/platform/heap/unified_heap_controller.cc
@@ -146,7 +146,7 @@
 
 bool UnifiedHeapController::IsRootForNonTracingGC(
     const v8::TracedReference<v8::Value>& handle) {
-  if (!IsTracingDone()) {
+  if (thread_state()->IsIncrementalMarking()) {
     // We have a non-tracing GC while unified GC is in progress. Treat all
     // objects as roots to avoid stale pointers in the marking worklists.
     return true;
@@ -186,7 +186,7 @@
   // potential in place rehashing. Both operations may trigger write barriers by
   // moving references. Such references may already be dead but not yet cleared
   // which would result in reporting dead objects to V8.
-  DCHECK(IsTracingDone());
+  DCHECK(!thread_state()->IsIncrementalMarking());
   // Clearing the wrapper below adjusts the DOM wrapper store which may
   // re-allocate its backing. We have to avoid report memory to V8 as that may
   // trigger GC during GC.
diff --git a/third_party/blink/renderer/platform/runtime_enabled_features.json5 b/third_party/blink/renderer/platform/runtime_enabled_features.json5
index 865ae4ed..893757d 100644
--- a/third_party/blink/renderer/platform/runtime_enabled_features.json5
+++ b/third_party/blink/renderer/platform/runtime_enabled_features.json5
@@ -1044,7 +1044,7 @@
     },
     {
       name: "ModuleDedicatedWorker",
-      status: "experimental",
+      status: "stable",
     },
     {
       name: "ModuleServiceWorker",
diff --git a/third_party/blink/tools/blinkpy/presubmit/audit_non_blink_usage.py b/third_party/blink/tools/blinkpy/presubmit/audit_non_blink_usage.py
index 85739ca4..8ec5aef 100755
--- a/third_party/blink/tools/blinkpy/presubmit/audit_non_blink_usage.py
+++ b/third_party/blink/tools/blinkpy/presubmit/audit_non_blink_usage.py
@@ -614,6 +614,7 @@
         # display-related types.
         'allowed': [
             'base::MRUCache',
+            'gl::GpuPreference',
             'gpu::gles2::GLES2Interface',
             'gpu::MailboxHolder',
             'display::Display',
diff --git a/third_party/blink/tools/blinkpy/web_tests/port/base.py b/third_party/blink/tools/blinkpy/web_tests/port/base.py
index 573a573..8879f61f 100644
--- a/third_party/blink/tools/blinkpy/web_tests/port/base.py
+++ b/third_party/blink/tools/blinkpy/web_tests/port/base.py
@@ -253,6 +253,12 @@
         return 'Port{name=%s, version=%s, architecture=%s, test_configuration=%s}' % (
             self._name, self._version, self._architecture, self._test_configuration)
 
+    def get_platform_tags(self):
+        """Returns system condition tags that are used to find active expectations
+           for a test run on a specific system"""
+        return frozenset([self._options.configuration.lower(), self._version,
+                          self.port_name, self._architecture])
+
     @memoized
     def _flag_specific_config_name(self):
         """Returns the name of the flag-specific configuration which best matches
diff --git a/third_party/blink/tools/blinkpy/web_tests/port/linux_unittest.py b/third_party/blink/tools/blinkpy/web_tests/port/linux_unittest.py
index ad851beb..b23920cf 100644
--- a/third_party/blink/tools/blinkpy/web_tests/port/linux_unittest.py
+++ b/third_party/blink/tools/blinkpy/web_tests/port/linux_unittest.py
@@ -72,6 +72,10 @@
         for i, path in enumerate(expected_paths):
             self.assertTrue(port.baseline_search_path()[i].endswith(path))
 
+    def test_get_platform_tags(self):
+        port = self.make_port()
+        self.assertEqual(port.get_platform_tags(), {'linux', 'trusty', 'x86_64', 'release'})
+
     def test_baseline_paths(self):
         self.assert_baseline_paths('linux', 'trusty', 'linux', '/win')
         self.assert_baseline_paths('linux-trusty', None, 'linux', '/win')
diff --git a/third_party/blink/tools/blinkpy/web_tests/port/mac_unittest.py b/third_party/blink/tools/blinkpy/web_tests/port/mac_unittest.py
index 670dbfe..ed4d465 100644
--- a/third_party/blink/tools/blinkpy/web_tests/port/mac_unittest.py
+++ b/third_party/blink/tools/blinkpy/web_tests/port/mac_unittest.py
@@ -46,6 +46,10 @@
     def test_operating_system(self):
         self.assertEqual('mac', self.make_port().operating_system())
 
+    def test_get_platform_tags(self):
+        port = self.make_port()
+        self.assertEqual(port.get_platform_tags(), {'mac', 'mac10.12', 'x86', 'release'})
+
     def test_driver_name_option(self):
         self.assertTrue(self.make_port()._path_to_driver().endswith('Content Shell'))
         port = self.make_port(options=optparse.Values(dict(driver_name='OtherDriver')))
diff --git a/third_party/blink/tools/blinkpy/web_tests/port/win_unittest.py b/third_party/blink/tools/blinkpy/web_tests/port/win_unittest.py
index 5c73f13..bee0d49c 100644
--- a/third_party/blink/tools/blinkpy/web_tests/port/win_unittest.py
+++ b/third_party/blink/tools/blinkpy/web_tests/port/win_unittest.py
@@ -53,6 +53,10 @@
         port = self.make_port(port_name=port_name, os_version=os_version_string)
         self.assertEqual(expected, port.name())
 
+    def test_get_platform_tags(self):
+        port = self.make_port()
+        self.assertEqual(port.get_platform_tags(), {'win', 'win7', 'x86', 'release'})
+
     def test_versions(self):
         port = self.make_port()
         self.assertIn(port.name(), ('win-win7', 'win-win10'))
diff --git a/third_party/blink/web_tests/TestExpectations b/third_party/blink/web_tests/TestExpectations
index dcb0aa6..78529ae44 100644
--- a/third_party/blink/web_tests/TestExpectations
+++ b/third_party/blink/web_tests/TestExpectations
@@ -1386,7 +1386,6 @@
 crbug.com/591099 virtual/layout_ng_flex_box/css3/flexbox/flex-align-vertical-writing-mode.html [ Failure ]
 crbug.com/591099 virtual/layout_ng_flex_box/css3/flexbox/flex-align.html [ Failure ]
 crbug.com/591099 virtual/layout_ng_flex_box/css3/flexbox/flex-flow-2.html [ Failure ]
-crbug.com/591099 virtual/layout_ng_flex_box/css3/flexbox/flex-flow-auto-margins.html [ Failure ]
 crbug.com/591099 virtual/layout_ng_flex_box/css3/flexbox/flex-flow-border.html [ Failure ]
 crbug.com/591099 virtual/layout_ng_flex_box/css3/flexbox/flex-flow-margins-auto-size.html [ Failure ]
 crbug.com/591099 virtual/layout_ng_flex_box/css3/flexbox/flex-flow-padding.html [ Failure ]
@@ -1448,10 +1447,6 @@
 crbug.com/591099 virtual/layout_ng_flex_box/external/wpt/css/css-flexbox/hittest-overlapping-margin.html [ Failure ]
 crbug.com/591099 virtual/layout_ng_flex_box/external/wpt/css/css-flexbox/hittest-overlapping-order.html [ Failure ]
 
-### virtual/layout_ng_flex_box/external/wpt/css/css-flexbox/flex-lines/
-crbug.com/591099 virtual/layout_ng_flex_box/external/wpt/css/css-flexbox/flex-lines/multi-line-wrap-reverse-column-reverse.html [ Failure ]
-crbug.com/591099 virtual/layout_ng_flex_box/external/wpt/css/css-flexbox/flex-lines/multi-line-wrap-with-column-reverse.html [ Failure ]
-
 ### virtual/layout_ng_flex_box/external/wpt/css/css-flexbox/getcomputedstyle/
 crbug.com/467127 virtual/layout_ng_flex_box/external/wpt/css/css-flexbox/getcomputedstyle/flexbox_computedstyle_flex-basis-0percent.html [ Failure ]
 crbug.com/467127 virtual/layout_ng_flex_box/external/wpt/css/css-flexbox/getcomputedstyle/flexbox_computedstyle_flex-shorthand-number.html [ Failure ]
@@ -1581,7 +1576,6 @@
 crbug.com/6606 external/wpt/mathml/relations/css-styling/color-003.html [ Failure ]
 crbug.com/6606 external/wpt/mathml/relations/css-styling/color-004.html [ Failure ]
 crbug.com/6606 external/wpt/mathml/relations/css-styling/display-1.html [ Failure ]
-crbug.com/6606 external/wpt/mathml/relations/css-styling/display-contents.html [ Failure ]
 crbug.com/6606 external/wpt/mathml/relations/css-styling/displaystyle-011.html [ Failure ]
 crbug.com/6606 external/wpt/mathml/relations/css-styling/displaystyle-012.html [ Failure ]
 crbug.com/6606 external/wpt/mathml/relations/css-styling/displaystyle-013.html [ Failure ]
diff --git a/third_party/blink/web_tests/WebGPUExpectations b/third_party/blink/web_tests/WebGPUExpectations
index 2a204f1a..d397c72 100644
--- a/third_party/blink/web_tests/WebGPUExpectations
+++ b/third_party/blink/web_tests/WebGPUExpectations
@@ -9,38 +9,53 @@
 #
 
 crbug.com/1014734 wpt_internal/webgpu/cts.html?q=cts:validation/createBindGroup:buffer_binding_must_contain_exactly_one_buffer_of_its_type~{"bindingType":"readonly-storage-buffer"} [ Failure ]
+crbug.com/1014734 wpt_internal/webgpu/cts.html?worker=1&q=cts:validation/createBindGroup:buffer_binding_must_contain_exactly_one_buffer_of_its_type~{"bindingType":"readonly-storage-buffer"} [ Failure ]
 
 crbug.com/1014735 wpt_internal/webgpu/cts.html?q=cts:validation/createBindGroup:buffer_binding_must_contain_exactly_one_buffer_of_its_type~{"bindingType":"storage-texture"} [ Failure ]
+crbug.com/1014735 wpt_internal/webgpu/cts.html?worker=1&q=cts:validation/createBindGroup:buffer_binding_must_contain_exactly_one_buffer_of_its_type~{"bindingType":"storage-texture"} [ Failure ]
 
 crbug.com/1014735 wpt_internal/webgpu/cts.html?q=cts:validation/createBindGroup:buffer_binding_must_contain_exactly_one_buffer_of_its_type={"bindingType":"uniform-buffer","resourceType":"storage-texture"} [ Failure ]
+crbug.com/1014735 wpt_internal/webgpu/cts.html?worker=1&q=cts:validation/createBindGroup:buffer_binding_must_contain_exactly_one_buffer_of_its_type={"bindingType":"uniform-buffer","resourceType":"storage-texture"} [ Failure ]
 crbug.com/1014735 wpt_internal/webgpu/cts.html?q=cts:validation/createBindGroup:buffer_binding_must_contain_exactly_one_buffer_of_its_type={"bindingType":"storage-buffer","resourceType":"storage-texture"} [ Failure ]
+crbug.com/1014735 wpt_internal/webgpu/cts.html?worker=1&q=cts:validation/createBindGroup:buffer_binding_must_contain_exactly_one_buffer_of_its_type={"bindingType":"storage-buffer","resourceType":"storage-texture"} [ Failure ]
 crbug.com/1014735 wpt_internal/webgpu/cts.html?q=cts:validation/createBindGroup:buffer_binding_must_contain_exactly_one_buffer_of_its_type={"bindingType":"sampler","resourceType":"storage-texture"} [ Failure ]
+crbug.com/1014735 wpt_internal/webgpu/cts.html?worker=1&q=cts:validation/createBindGroup:buffer_binding_must_contain_exactly_one_buffer_of_its_type={"bindingType":"sampler","resourceType":"storage-texture"} [ Failure ]
 crbug.com/1014735 wpt_internal/webgpu/cts.html?q=cts:validation/createBindGroup:buffer_binding_must_contain_exactly_one_buffer_of_its_type={"bindingType":"sampled-texture","resourceType":"storage-texture"} [ Failure ]
+crbug.com/1014735 wpt_internal/webgpu/cts.html?worker=1&q=cts:validation/createBindGroup:buffer_binding_must_contain_exactly_one_buffer_of_its_type={"bindingType":"sampled-texture","resourceType":"storage-texture"} [ Failure ]
 
 crbug.com/1014735 wpt_internal/webgpu/cts.html?q=cts:validation/createBindGroup:texture_binding_must_have_correct_usage={"type":"storage-texture"} [ Failure ]
+crbug.com/1014735 wpt_internal/webgpu/cts.html?worker=1&q=cts:validation/createBindGroup:texture_binding_must_have_correct_usage={"type":"storage-texture"} [ Failure ]
 
 crbug.com/1014734 wpt_internal/webgpu/cts.html?q=cts:validation/createBindGroupLayout:dynamic_set_to_true_is_allowed_only_for_buffers={"type":"readonly-storage-buffer"} [ Failure ]
+crbug.com/1014734 wpt_internal/webgpu/cts.html?worker=1&q=cts:validation/createBindGroupLayout:dynamic_set_to_true_is_allowed_only_for_buffers={"type":"readonly-storage-buffer"} [ Failure ]
 
 crbug.com/dawn/243 wpt_internal/webgpu/cts.html?q=cts:validation/createTexture:validation_of_sampleCount={"sampleCount":4,"arrayLayerCount":2} [ Failure ]
+crbug.com/dawn/243 wpt_internal/webgpu/cts.html?worker=1&q=cts:validation/createTexture:validation_of_sampleCount={"sampleCount":4,"arrayLayerCount":2} [ Failure ]
 
 crbug.com/1014750 wpt_internal/webgpu/cts.html?q=cts:validation/createView:it_is_invalid_to_use_a_texture_view_created_from_a_destroyed_texture= [ Failure ]
+crbug.com/1014750 wpt_internal/webgpu/cts.html?worker=1&q=cts:validation/createView:it_is_invalid_to_use_a_texture_view_created_from_a_destroyed_texture= [ Failure ]
 
 #
 # Mac (Metal) specific
 #
 
 crbug.com/1014744 [ Mac ] wpt_internal/webgpu/cts.html?q=cts:command_buffer/render/storeop:storeOp_controls_whether_1x1_drawn_quad_is_stored={"storeOp":"clear"} [ Failure ]
+crbug.com/1014744 [ Mac ] wpt_internal/webgpu/cts.html?worker=1&q=cts:command_buffer/render/storeop:storeOp_controls_whether_1x1_drawn_quad_is_stored={"storeOp":"clear"} [ Failure ]
 
 #
 # Linux (Vulkan) specific
 #
 
 crbug.com/1014740 [ Linux ] wpt_internal/webgpu/cts.html?q=cts:buffers/map_oom:mapWriteAsync= [ Failure ]
+crbug.com/1014740 [ Linux ] wpt_internal/webgpu/cts.html?worker=1&q=cts:buffers/map_oom:mapWriteAsync= [ Failure ]
 crbug.com/1014740 [ Linux ] wpt_internal/webgpu/cts.html?q=cts:buffers/map_oom:mapReadAsync= [ Failure ]
+crbug.com/1014740 [ Linux ] wpt_internal/webgpu/cts.html?worker=1&q=cts:buffers/map_oom:mapReadAsync= [ Failure ]
 
 #
 # Windows (D3D12) specific
 #
 
 crbug.com/1014738 [ Win ] wpt_internal/webgpu/cts.html?q=cts:buffers/map_oom:mapWriteAsync= [ Failure ]
+crbug.com/1014738 [ Win ] wpt_internal/webgpu/cts.html?worker=1&q=cts:buffers/map_oom:mapWriteAsync= [ Failure ]
 crbug.com/1014738 [ Win ] wpt_internal/webgpu/cts.html?q=cts:buffers/map_oom:mapReadAsync= [ Failure ]
+crbug.com/1014738 [ Win ] wpt_internal/webgpu/cts.html?worker=1&q=cts:buffers/map_oom:mapReadAsync= [ Failure ]
diff --git a/third_party/blink/web_tests/external/wpt/webgpu/cts.html b/third_party/blink/web_tests/external/wpt/webgpu/cts.html
index b66553d..13d8b7c8 100644
--- a/third_party/blink/web_tests/external/wpt/webgpu/cts.html
+++ b/third_party/blink/web_tests/external/wpt/webgpu/cts.html
@@ -39,6 +39,17 @@
     width: 100%;
     height: 15em;
 }
+
+/* Test Name column */
+#results > tbody > tr > td:nth-child(2) {
+    word-break: break-word;
+}
+
+/* Message column */
+#results > tbody > tr > td:nth-child(3) {
+    white-space: pre-wrap;
+    word-break: break-word;
+}
 </style>
 
 <textarea id=results></textarea>
@@ -74,4 +85,4 @@
 <meta name=variant content='?q=cts:validation/setStencilReference:'>
 <meta name=variant content='?q=cts:validation/setVertexBuffer:'>
 <meta name=variant content='?q=cts:validation/setViewport:'>
-<meta name=variant content='?q=cts:validation/vertex_input:'>
+<meta name=variant content='?q=cts:validation/vertex_state:'>
diff --git a/third_party/blink/web_tests/external/wpt/webgpu/framework/fixture.js b/third_party/blink/web_tests/external/wpt/webgpu/framework/fixture.js
index 12793122..d976fa46 100644
--- a/third_party/blink/web_tests/external/wpt/webgpu/framework/fixture.js
+++ b/third_party/blink/web_tests/external/wpt/webgpu/framework/fixture.js
@@ -27,11 +27,7 @@
   async init() {}
 
   debug(msg) {
-    this.rec.debug(msg);
-  }
-
-  log(msg) {
-    this.rec.log(msg);
+    this.rec.debug(new Error(msg));
   }
 
   skip(msg) {
@@ -47,11 +43,11 @@
   }
 
   warn(msg) {
-    this.rec.warn(msg);
+    this.rec.warn(new Error(msg));
   }
 
   fail(msg) {
-    this.rec.fail(msg);
+    this.rec.fail(new Error(msg));
   }
 
   async immediateAsyncExpectation(fn) {
@@ -62,35 +58,40 @@
   }
 
   eventualAsyncExpectation(fn) {
-    const promise = fn();
+    const promise = fn(new Error());
     this.eventualExpectations.push(promise);
     return promise;
   }
 
-  expectErrorValue(expectedName, ex, m) {
+  expectErrorValue(expectedName, ex, niceStack) {
     if (!(ex instanceof Error)) {
-      this.fail('THREW non-error value, of type ' + typeof ex);
+      niceStack.message = 'THREW non-error value, of type ' + typeof ex + niceStack.message;
+      this.rec.fail(niceStack);
       return;
     }
 
     const actualName = ex.name;
 
     if (actualName !== expectedName) {
-      this.fail(`THREW ${actualName}, instead of ${expectedName}${m}`);
+      niceStack.message = `THREW ${actualName}, instead of ${expectedName}` + niceStack.message;
+      this.rec.fail(niceStack);
     } else {
-      this.debug(`OK: threw ${actualName}${m}`);
+      niceStack.message = 'OK: threw ' + actualName + niceStack.message;
+      this.rec.debug(niceStack);
     }
   }
 
   shouldReject(expectedName, p, msg) {
-    this.eventualAsyncExpectation(async () => {
+    this.eventualAsyncExpectation(async niceStack => {
       const m = msg ? ': ' + msg : '';
 
       try {
         await p;
-        this.fail('DID NOT THROW' + m);
+        niceStack.message = 'DID NOT THROW' + m;
+        this.rec.fail(niceStack);
       } catch (ex) {
-        this.expectErrorValue(expectedName, ex, m);
+        niceStack.message = m;
+        this.expectErrorValue(expectedName, ex, niceStack);
       }
     });
   }
@@ -100,18 +101,18 @@
 
     try {
       fn();
-      this.fail('DID NOT THROW' + m);
+      this.rec.fail(new Error('DID NOT THROW' + m));
     } catch (ex) {
-      this.expectErrorValue(expectedName, ex, m);
+      this.expectErrorValue(expectedName, ex, new Error(m));
     }
   }
 
   expect(cond, msg) {
     if (cond) {
       const m = msg ? ': ' + msg : '';
-      this.debug('expect OK' + m);
+      this.rec.debug(new Error('expect OK' + m));
     } else {
-      this.rec.fail(msg);
+      this.rec.fail(new Error(msg));
     }
 
     return cond;
diff --git a/third_party/blink/web_tests/external/wpt/webgpu/framework/logger.js b/third_party/blink/web_tests/external/wpt/webgpu/framework/logger.js
index ee869196..5536e736 100644
--- a/third_party/blink/web_tests/external/wpt/webgpu/framework/logger.js
+++ b/third_party/blink/web_tests/external/wpt/webgpu/framework/logger.js
@@ -9,6 +9,34 @@
 import { extractPublicParams } from './url_query.js';
 import { getStackTrace, now } from './util/index.js';
 import { version } from './version.js';
+
+class LogMessageWithStack extends Error {
+  constructor(name, ex) {
+    super(ex.message);
+    this.name = name;
+    this.stack = ex.stack;
+  }
+
+  toJSON() {
+    let m = this.name;
+
+    if (this.message) {
+      m += ': ' + this.message;
+    }
+
+    m += '\n' + getStackTrace(this);
+    return m;
+  }
+
+}
+
+class LogMessageWithoutStack extends LogMessageWithStack {
+  toJSON() {
+    return this.message;
+  }
+
+}
+
 export class Logger {
   constructor() {
     _defineProperty(this, "results", []);
@@ -94,46 +122,27 @@
     this.debugging = false;
   }
 
-  debug(msg) {
+  debug(ex) {
     if (!this.debugging) {
       return;
     }
 
-    this.log('DEBUG: ' + msg);
+    this.logs.push(new LogMessageWithoutStack('DEBUG', ex));
   }
 
-  log(msg) {
-    this.logs.push(msg);
-  }
-
-  warn(msg) {
+  warn(ex) {
     this.setState(PassState.warn);
-    let m = 'WARN';
-
-    if (msg) {
-      m += ': ' + msg;
-    }
-
-    m += ' ' + getStackTrace(new Error());
-    this.log(m);
+    this.logs.push(new LogMessageWithStack('WARN', ex));
   }
 
-  fail(msg) {
+  fail(ex) {
     this.setState(PassState.fail);
-    let m = 'FAIL';
-
-    if (msg) {
-      m += ': ' + msg;
-    }
-
-    m += '\n' + getStackTrace(new Error());
-    this.log(m);
+    this.logs.push(new LogMessageWithStack('FAIL', ex));
   }
 
   skipped(ex) {
     this.setState(PassState.skip);
-    const m = 'SKIPPED: ' + getStackTrace(ex);
-    this.log(m);
+    this.logs.push(new LogMessageWithStack('SKIP', ex));
   }
 
   threw(ex) {
@@ -143,7 +152,7 @@
     }
 
     this.setState(PassState.fail);
-    this.log('EXCEPTION: ' + ex.name + ':\n' + ex.message + '\n' + getStackTrace(ex));
+    this.logs.push(new LogMessageWithStack('EXCEPTION', ex));
   }
 
   setState(state) {
diff --git a/third_party/blink/web_tests/external/wpt/webgpu/framework/version.js b/third_party/blink/web_tests/external/wpt/webgpu/framework/version.js
index 154f062..e2c91190 100644
--- a/third_party/blink/web_tests/external/wpt/webgpu/framework/version.js
+++ b/third_party/blink/web_tests/external/wpt/webgpu/framework/version.js
@@ -1,3 +1,3 @@
 // AUTO-GENERATED - DO NOT EDIT. See tools/gen_version.
 
-export const version = '3dc37c83a70667e9a92df773f34d154ec600d203';
+export const version = 'e114192747a54f34157eb65754e037701fbdf98b';
diff --git a/third_party/blink/web_tests/external/wpt/webgpu/runtime/wpt.js b/third_party/blink/web_tests/external/wpt/webgpu/runtime/wpt.js
index e078f67..fd02f09 100644
--- a/third_party/blink/web_tests/external/wpt/webgpu/runtime/wpt.js
+++ b/third_party/blink/web_tests/external/wpt/webgpu/runtime/wpt.js
@@ -41,7 +41,7 @@
           this.step(() => {
             // Unfortunately, it seems not possible to surface any logs for warn/skip.
             if (r.status === 'fail') {
-              throw (r.logs || []).join('\n');
+              throw (r.logs || []).map(s => s.toJSON()).join('\n\n');
             }
           });
           this.done();
diff --git a/third_party/blink/web_tests/external/wpt/webgpu/suites/cts/command_buffer/render/rendering.spec.js b/third_party/blink/web_tests/external/wpt/webgpu/suites/cts/command_buffer/render/rendering.spec.js
index 43c4566..54c627d 100644
--- a/third_party/blink/web_tests/external/wpt/webgpu/suites/cts/command_buffer/render/rendering.spec.js
+++ b/third_party/blink/web_tests/external/wpt/webgpu/suites/cts/command_buffer/render/rendering.spec.js
@@ -73,7 +73,7 @@
       alphaBlend: {},
       colorBlend: {}
     }],
-    vertexInput: {
+    vertexState: {
       indexFormat: 'uint16',
       vertexBuffers: []
     }
diff --git a/third_party/blink/web_tests/external/wpt/webgpu/suites/cts/gpu_test.js b/third_party/blink/web_tests/external/wpt/webgpu/suites/cts/gpu_test.js
index 272b1b8..a324e88 100644
--- a/third_party/blink/web_tests/external/wpt/webgpu/suites/cts/gpu_test.js
+++ b/third_party/blink/web_tests/external/wpt/webgpu/suites/cts/gpu_test.js
@@ -112,41 +112,61 @@
     const c = this.device.createCommandEncoder();
     c.copyBufferToBuffer(src, 0, dst, 0, size);
     this.queue.submit([c.finish()]);
-    this.eventualAsyncExpectation(async () => {
+    this.eventualAsyncExpectation(async niceStack => {
       const actual = new Uint8Array((await dst.mapReadAsync()));
-      this.expectBuffer(actual, exp);
+      const check = this.checkBuffer(actual, exp);
+
+      if (check !== undefined) {
+        niceStack.message = check;
+        this.rec.fail(niceStack);
+      }
+
       dst.destroy();
     });
   }
 
   expectBuffer(actual, exp) {
+    const check = this.checkBuffer(actual, exp);
+
+    if (check !== undefined) {
+      this.rec.fail(new Error(check));
+    }
+  }
+
+  checkBuffer(actual, exp) {
     const size = exp.byteLength;
 
     if (actual.byteLength !== size) {
-      this.rec.fail('size mismatch');
-      return;
+      return 'size mismatch';
     }
 
+    const lines = [];
     let failedPixels = 0;
 
     for (let i = 0; i < size; ++i) {
       if (actual[i] !== exp[i]) {
         if (failedPixels > 4) {
-          this.rec.fail('... and more');
+          lines.push('... and more');
           break;
         }
 
         failedPixels++;
-        this.rec.fail(`at [${i}], expected ${exp[i]}, got ${actual[i]}`);
+        lines.push(`at [${i}], expected ${exp[i]}, got ${actual[i]}`);
       }
     }
 
     if (size <= 256 && failedPixels > 0) {
       const expHex = Array.from(exp).map(x => x.toString(16).padStart(2, '0')).join('');
       const actHex = Array.from(actual).map(x => x.toString(16).padStart(2, '0')).join('');
-      this.rec.log('EXPECT: ' + expHex);
-      this.rec.log('ACTUAL: ' + actHex);
+      lines.push('EXPECT: ' + expHex);
+      lines.push('ACTUAL: ' + actHex);
     }
+
+    if (failedPixels) {
+      return lines.join('\n');
+    }
+
+    return undefined;
   }
 
 }
diff --git a/third_party/blink/web_tests/external/wpt/webgpu/suites/cts/index.js b/third_party/blink/web_tests/external/wpt/webgpu/suites/cts/index.js
index 33934cdd..d38bcc5 100644
--- a/third_party/blink/web_tests/external/wpt/webgpu/suites/cts/index.js
+++ b/third_party/blink/web_tests/external/wpt/webgpu/suites/cts/index.js
@@ -130,7 +130,7 @@
     "description": "setViewport validation tests."
   },
   {
-    "path": "validation/vertex_input",
-    "description": "vertexInput validation tests."
+    "path": "validation/vertex_state",
+    "description": "vertexState validation tests."
   }
 ];
diff --git a/third_party/blink/web_tests/external/wpt/webgpu/suites/cts/validation/setVertexBuffer.spec.js b/third_party/blink/web_tests/external/wpt/webgpu/suites/cts/validation/setVertexBuffer.spec.js
index 0f47e73..ba22ee2d 100644
--- a/third_party/blink/web_tests/external/wpt/webgpu/suites/cts/validation/setVertexBuffer.spec.js
+++ b/third_party/blink/web_tests/external/wpt/webgpu/suites/cts/validation/setVertexBuffer.spec.js
@@ -29,11 +29,12 @@
       colorStates: [{
         format: 'rgba8unorm'
       }],
-      vertexInput: {
+      vertexState: {
         vertexBuffers: [{
-          stride: 3 * 4,
-          attributeSet: range(bufferCount, i => ({
+          arrayStride: 3 * 4,
+          attributes: range(bufferCount, i => ({
             format: 'float3',
+            offset: 0,
             shaderLocation: i
           }))
         }]
diff --git a/third_party/blink/web_tests/external/wpt/webgpu/suites/cts/validation/validation_test.js b/third_party/blink/web_tests/external/wpt/webgpu/suites/cts/validation/validation_test.js
index 099b820..dc5488e 100644
--- a/third_party/blink/web_tests/external/wpt/webgpu/suites/cts/validation/validation_test.js
+++ b/third_party/blink/web_tests/external/wpt/webgpu/suites/cts/validation/validation_test.js
@@ -25,13 +25,15 @@
     this.device.pushErrorScope('validation');
     fn();
     const promise = this.device.popErrorScope();
-    this.eventualAsyncExpectation(async () => {
+    this.eventualAsyncExpectation(async niceStack => {
       const gpuValidationError = await promise;
 
       if (!gpuValidationError) {
-        this.fail('Validation error was expected.');
+        niceStack.message = 'Validation error was expected.';
+        this.rec.fail(niceStack);
       } else if (gpuValidationError instanceof GPUValidationError) {
-        this.debug(`Captured validation error - ${gpuValidationError.message}`);
+        niceStack.message = `Captured validation error - ${gpuValidationError.message}`;
+        this.rec.debug(niceStack);
       }
     });
   }
diff --git a/third_party/blink/web_tests/external/wpt/webgpu/suites/cts/validation/vertex_input.spec.js b/third_party/blink/web_tests/external/wpt/webgpu/suites/cts/validation/vertex_input.spec.js
deleted file mode 100644
index c5978025..0000000
--- a/third_party/blink/web_tests/external/wpt/webgpu/suites/cts/validation/vertex_input.spec.js
+++ /dev/null
@@ -1,623 +0,0 @@
-/**
-* AUTO-GENERATED - DO NOT EDIT. Source: https://github.com/gpuweb/cts
-**/
-
-export const description = `
-vertexInput validation tests.
-`;
-import { TestGroup } from '../../../framework/index.js';
-import { ValidationTest } from './validation_test.js';
-const MAX_VERTEX_ATTRIBUTES = 16;
-const MAX_VERTEX_BUFFER_END = 2048;
-const MAX_VERTEX_BUFFER_STRIDE = 2048;
-const MAX_VERTEX_BUFFERS = 16;
-const VERTEX_SHADER_CODE_WITH_NO_INPUT = `
-  #version 450
-  void main() {
-    gl_Position = vec4(0.0);
-  }
-`;
-
-function clone(descriptor) {
-  return JSON.parse(JSON.stringify(descriptor));
-}
-
-class F extends ValidationTest {
-  async init() {
-    await Promise.all([super.init(), this.initGLSL()]);
-  }
-
-  getDescriptor(vertexInput, vertexShaderCode) {
-    const descriptor = {
-      vertexStage: this.getVertexStage(vertexShaderCode),
-      fragmentStage: this.getFragmentStage(),
-      layout: this.getPipelineLayout(),
-      primitiveTopology: 'triangle-list',
-      colorStates: [{
-        format: 'rgba8unorm'
-      }],
-      vertexInput
-    };
-    return descriptor;
-  }
-
-  getVertexStage(code) {
-    return {
-      module: this.makeShaderModuleFromGLSL('vertex', code),
-      entryPoint: 'main'
-    };
-  }
-
-  getFragmentStage() {
-    const code = `
-      #version 450
-      layout(location = 0) out vec4 fragColor;
-      void main() {
-        fragColor = vec4(0.0, 1.0, 0.0, 1.0);
-      }
-    `;
-    return {
-      module: this.makeShaderModuleFromGLSL('fragment', code),
-      entryPoint: 'main'
-    };
-  }
-
-  getPipelineLayout() {
-    return this.device.createPipelineLayout({
-      bindGroupLayouts: []
-    });
-  }
-
-}
-
-export const g = new TestGroup(F);
-g.test('an empty vertex input is valid', t => {
-  const vertexInput = {};
-  const descriptor = t.getDescriptor(vertexInput, VERTEX_SHADER_CODE_WITH_NO_INPUT);
-  t.device.createRenderPipeline(descriptor);
-});
-g.test('a null buffer is valid', t => {
-  {
-    // One null buffer is OK
-    const vertexInput = {
-      vertexBuffers: [{
-        stride: 0,
-        attributeSet: []
-      }]
-    };
-    const descriptor = t.getDescriptor(vertexInput, VERTEX_SHADER_CODE_WITH_NO_INPUT);
-    t.device.createRenderPipeline(descriptor);
-  }
-  {
-    //  One null buffer followed by a buffer is OK
-    const vertexInput = {
-      vertexBuffers: [{
-        stride: 0,
-        attributeSet: []
-      }, {
-        stride: 0,
-        attributeSet: [{
-          shaderLocation: 0,
-          format: 'float'
-        }]
-      }]
-    };
-    const descriptor = t.getDescriptor(vertexInput, VERTEX_SHADER_CODE_WITH_NO_INPUT);
-    t.device.createRenderPipeline(descriptor);
-  }
-  {
-    //  One null buffer sitting between buffers is OK
-    const vertexInput = {
-      vertexBuffers: [{
-        stride: 0,
-        attributeSet: [{
-          shaderLocation: 0,
-          format: 'float'
-        }]
-      }, {
-        stride: 0,
-        attributeSet: []
-      }, {
-        stride: 0,
-        attributeSet: [{
-          shaderLocation: 1,
-          format: 'float'
-        }]
-      }]
-    };
-    const descriptor = t.getDescriptor(vertexInput, VERTEX_SHADER_CODE_WITH_NO_INPUT);
-    t.device.createRenderPipeline(descriptor);
-  }
-});
-g.test('pipeline vertex buffers are backed by attributes in vertex input', async t => {
-  const vertexInput = {
-    vertexBuffers: [{
-      stride: 2 * Float32Array.BYTES_PER_ELEMENT,
-      attributeSet: [{
-        shaderLocation: 0,
-        format: 'float'
-      }, {
-        shaderLocation: 1,
-        format: 'float'
-      }]
-    }]
-  };
-  {
-    // Control case: pipeline with one input per attribute
-    const code = `
-      #version 450
-      layout(location = 0) in vec4 a;
-      layout(location = 1) in vec4 b;
-      void main() {
-          gl_Position = vec4(0.0);
-      }
-    `;
-    const descriptor = t.getDescriptor(vertexInput, code);
-    t.device.createRenderPipeline(descriptor);
-  }
-  {
-    // Check it is valid for the pipeline to use a subset of the VertexInput
-    const code = `
-      #version 450
-      layout(location = 0) in vec4 a;
-      void main() {
-          gl_Position = vec4(0.0);
-      }
-    `;
-    const descriptor = t.getDescriptor(vertexInput, code);
-    t.device.createRenderPipeline(descriptor);
-  }
-  {
-    // Check for an error when the pipeline uses an attribute not in the vertex input
-    const code = `
-      #version 450
-      layout(location = 2) in vec4 a;
-      void main() {
-          gl_Position = vec4(0.0);
-      }
-    `;
-    const descriptor = t.getDescriptor(vertexInput, code);
-    t.expectValidationError(() => {
-      t.device.createRenderPipeline(descriptor);
-    });
-  }
-});
-g.test('a stride of 0 is valid', t => {
-  const vertexInput = {
-    vertexBuffers: [{
-      stride: 0,
-      attributeSet: [{
-        shaderLocation: 0,
-        format: 'float'
-      }]
-    }]
-  };
-  {
-    // Works ok without attributes
-    const descriptor = t.getDescriptor(vertexInput, VERTEX_SHADER_CODE_WITH_NO_INPUT);
-    t.device.createRenderPipeline(descriptor);
-  }
-  {
-    // Works ok with attributes at a large-ish offset
-    vertexInput.vertexBuffers[0].attributeSet[0].offset = 128;
-    const descriptor = t.getDescriptor(vertexInput, VERTEX_SHADER_CODE_WITH_NO_INPUT);
-    t.device.createRenderPipeline(descriptor);
-  }
-});
-g.test('offset should be within vertex buffer stride if stride is not zero', async t => {
-  const vertexInput = {
-    vertexBuffers: [{
-      stride: 2 * Float32Array.BYTES_PER_ELEMENT,
-      attributeSet: [{
-        shaderLocation: 0,
-        format: 'float'
-      }, {
-        offset: Float32Array.BYTES_PER_ELEMENT,
-        shaderLocation: 1,
-        format: 'float'
-      }]
-    }]
-  };
-  {
-    // Control case, setting correct stride and offset
-    const descriptor = t.getDescriptor(vertexInput, VERTEX_SHADER_CODE_WITH_NO_INPUT);
-    t.device.createRenderPipeline(descriptor);
-  }
-  {
-    // Test vertex attribute offset exceed vertex buffer stride range
-    const badVertexInput = clone(vertexInput);
-    badVertexInput.vertexBuffers[0].attributeSet[1].format = 'float2';
-    const descriptor = t.getDescriptor(badVertexInput, VERTEX_SHADER_CODE_WITH_NO_INPUT);
-    t.expectValidationError(() => {
-      t.device.createRenderPipeline(descriptor);
-    });
-  }
-  {
-    // Test vertex attribute offset exceed vertex buffer stride range
-    const badVertexInput = clone(vertexInput);
-    badVertexInput.vertexBuffers[0].stride = Float32Array.BYTES_PER_ELEMENT;
-    const descriptor = t.getDescriptor(badVertexInput, VERTEX_SHADER_CODE_WITH_NO_INPUT);
-    t.expectValidationError(() => {
-      t.device.createRenderPipeline(descriptor);
-    });
-  }
-  {
-    // It's OK if stride is zero
-    const goodVertexInput = clone(vertexInput);
-    goodVertexInput.vertexBuffers[0].stride = 0;
-    const descriptor = t.getDescriptor(goodVertexInput, VERTEX_SHADER_CODE_WITH_NO_INPUT);
-    t.device.createRenderPipeline(descriptor);
-  }
-});
-g.test('check two attributes overlapping', async t => {
-  const vertexInput = {
-    vertexBuffers: [{
-      stride: 2 * Float32Array.BYTES_PER_ELEMENT,
-      attributeSet: [{
-        shaderLocation: 0,
-        format: 'float'
-      }, {
-        offset: Float32Array.BYTES_PER_ELEMENT,
-        shaderLocation: 1,
-        format: 'float'
-      }]
-    }]
-  };
-  {
-    // Control case, setting correct stride and offset
-    const descriptor = t.getDescriptor(vertexInput, VERTEX_SHADER_CODE_WITH_NO_INPUT);
-    t.device.createRenderPipeline(descriptor);
-  }
-  {
-    // Test two attributes overlapping
-    const badVertexInput = clone(vertexInput);
-    badVertexInput.vertexBuffers[0].attributeSet[0].format = 'int2';
-    const descriptor = t.getDescriptor(badVertexInput, VERTEX_SHADER_CODE_WITH_NO_INPUT);
-    t.expectValidationError(() => {
-      t.device.createRenderPipeline(descriptor);
-    });
-  }
-});
-g.test('check out of bounds condition on total number of vertex buffers', async t => {
-  const vertexBuffers = [];
-
-  for (let i = 0; i < MAX_VERTEX_BUFFERS; i++) {
-    vertexBuffers.push({
-      stride: 0,
-      attributeSet: [{
-        shaderLocation: i,
-        format: 'float'
-      }]
-    });
-  }
-
-  {
-    // Control case, setting max vertex buffer number
-    const vertexInput = {
-      vertexBuffers
-    };
-    const descriptor = t.getDescriptor(vertexInput, VERTEX_SHADER_CODE_WITH_NO_INPUT);
-    t.device.createRenderPipeline(descriptor);
-  }
-  {
-    // Test vertex buffer number exceed the limit
-    const vertexInput = {
-      vertexBuffers: [...vertexBuffers, {
-        stride: 0,
-        attributeSet: [{
-          shaderLocation: MAX_VERTEX_BUFFERS,
-          format: 'float'
-        }]
-      }]
-    };
-    const descriptor = t.getDescriptor(vertexInput, VERTEX_SHADER_CODE_WITH_NO_INPUT);
-    t.expectValidationError(() => {
-      t.device.createRenderPipeline(descriptor);
-    });
-  }
-});
-g.test('check out of bounds on number of vertex attributes on a single vertex buffer', async t => {
-  const vertexAttributes = [];
-
-  for (let i = 0; i < MAX_VERTEX_ATTRIBUTES; i++) {
-    vertexAttributes.push({
-      shaderLocation: i,
-      format: 'float'
-    });
-  }
-
-  {
-    // Control case, setting max vertex buffer number
-    const vertexInput = {
-      vertexBuffers: [{
-        stride: 0,
-        attributeSet: vertexAttributes
-      }]
-    };
-    const descriptor = t.getDescriptor(vertexInput, VERTEX_SHADER_CODE_WITH_NO_INPUT);
-    t.device.createRenderPipeline(descriptor);
-  }
-  {
-    // Test vertex attribute number exceed the limit
-    const vertexInput = {
-      vertexBuffers: [{
-        stride: 0,
-        attributeSet: [...vertexAttributes, {
-          shaderLocation: MAX_VERTEX_ATTRIBUTES,
-          format: 'float'
-        }]
-      }]
-    };
-    const descriptor = t.getDescriptor(vertexInput, VERTEX_SHADER_CODE_WITH_NO_INPUT);
-    t.expectValidationError(() => {
-      t.device.createRenderPipeline(descriptor);
-    });
-  }
-});
-g.test('check out of bounds on number of vertex attributes across vertex buffers', async t => {
-  const vertexBuffers = [];
-
-  for (let i = 0; i < MAX_VERTEX_ATTRIBUTES; i++) {
-    vertexBuffers.push({
-      stride: 0,
-      attributeSet: [{
-        shaderLocation: i,
-        format: 'float'
-      }]
-    });
-  }
-
-  {
-    // Control case, setting max vertex buffer number
-    const vertexInput = {
-      vertexBuffers
-    };
-    const descriptor = t.getDescriptor(vertexInput, VERTEX_SHADER_CODE_WITH_NO_INPUT);
-    t.device.createRenderPipeline(descriptor);
-  }
-  {
-    // Test vertex attribute number exceed the limit
-    vertexBuffers[MAX_VERTEX_ATTRIBUTES - 1].attributeSet.push({
-      shaderLocation: MAX_VERTEX_ATTRIBUTES,
-      format: 'float'
-    });
-    const vertexInput = {
-      vertexBuffers
-    };
-    const descriptor = t.getDescriptor(vertexInput, VERTEX_SHADER_CODE_WITH_NO_INPUT);
-    t.expectValidationError(() => {
-      t.device.createRenderPipeline(descriptor);
-    });
-  }
-});
-g.test('check out of bounds condition on input strides', async t => {
-  const vertexInput = {
-    vertexBuffers: [{
-      stride: MAX_VERTEX_BUFFER_STRIDE,
-      attributeSet: []
-    }]
-  };
-  {
-    // Control case, setting max input stride
-    const descriptor = t.getDescriptor(vertexInput, VERTEX_SHADER_CODE_WITH_NO_INPUT);
-    t.device.createRenderPipeline(descriptor);
-  }
-  {
-    // Test input stride OOB
-    vertexInput.vertexBuffers[0].stride = MAX_VERTEX_BUFFER_STRIDE + 4;
-    const descriptor = t.getDescriptor(vertexInput, VERTEX_SHADER_CODE_WITH_NO_INPUT);
-    t.expectValidationError(() => {
-      t.device.createRenderPipeline(descriptor);
-    });
-  }
-});
-g.test('check multiple of 4 bytes constraint on input stride', async t => {
-  const vertexInput = {
-    vertexBuffers: [{
-      stride: 4,
-      attributeSet: [{
-        shaderLocation: 0,
-        format: 'uchar2'
-      }]
-    }]
-  };
-  {
-    // Control case, setting input stride 4 bytes
-    const descriptor = t.getDescriptor(vertexInput, VERTEX_SHADER_CODE_WITH_NO_INPUT);
-    t.device.createRenderPipeline(descriptor);
-  }
-  {
-    // Test input stride not multiple of 4 bytes
-    vertexInput.vertexBuffers[0].stride = 2;
-    const descriptor = t.getDescriptor(vertexInput, VERTEX_SHADER_CODE_WITH_NO_INPUT);
-    t.expectValidationError(() => {
-      t.device.createRenderPipeline(descriptor);
-    });
-  }
-});
-g.test('identical duplicate attributes are invalid', async t => {
-  const vertexInput = {
-    vertexBuffers: [{
-      stride: 0,
-      attributeSet: [{
-        shaderLocation: 0,
-        format: 'float'
-      }]
-    }]
-  };
-  {
-    // Control case, setting attribute 0
-    const descriptor = t.getDescriptor(vertexInput, VERTEX_SHADER_CODE_WITH_NO_INPUT);
-    t.device.createRenderPipeline(descriptor);
-  }
-  {
-    // Oh no, attribute 0 is set twice
-    vertexInput.vertexBuffers[0].attributeSet.push({
-      shaderLocation: 0,
-      format: 'float'
-    });
-    const descriptor = t.getDescriptor(vertexInput, VERTEX_SHADER_CODE_WITH_NO_INPUT);
-    t.expectValidationError(() => {
-      t.device.createRenderPipeline(descriptor);
-    });
-  }
-});
-g.test('we cannot set same shader location', async t => {
-  {
-    const vertexInput = {
-      vertexBuffers: [{
-        stride: 0,
-        attributeSet: [{
-          shaderLocation: 0,
-          format: 'float'
-        }, {
-          offset: Float32Array.BYTES_PER_ELEMENT,
-          shaderLocation: 1,
-          format: 'float'
-        }]
-      }]
-    };
-    {
-      // Control case, setting different shader locations in two attributes
-      const descriptor = t.getDescriptor(vertexInput, VERTEX_SHADER_CODE_WITH_NO_INPUT);
-      t.device.createRenderPipeline(descriptor);
-    }
-    {
-      // Test same shader location in two attributes in the same buffer
-      vertexInput.vertexBuffers[0].attributeSet[1].shaderLocation = 0;
-      const descriptor = t.getDescriptor(vertexInput, VERTEX_SHADER_CODE_WITH_NO_INPUT);
-      t.expectValidationError(() => {
-        t.device.createRenderPipeline(descriptor);
-      });
-    }
-  }
-  {
-    const vertexInput = {
-      vertexBuffers: [{
-        stride: 0,
-        attributeSet: [{
-          shaderLocation: 0,
-          format: 'float'
-        }]
-      }, {
-        stride: 0,
-        attributeSet: [{
-          shaderLocation: 0,
-          format: 'float'
-        }]
-      }]
-    }; // Test same shader location in two attributes in different buffers
-
-    const descriptor = t.getDescriptor(vertexInput, VERTEX_SHADER_CODE_WITH_NO_INPUT);
-    t.expectValidationError(() => {
-      t.device.createRenderPipeline(descriptor);
-    });
-  }
-});
-g.test('check out of bounds condition on attribute shader location', async t => {
-  const vertexInput = {
-    vertexBuffers: [{
-      stride: 0,
-      attributeSet: [{
-        shaderLocation: MAX_VERTEX_ATTRIBUTES - 1,
-        format: 'float'
-      }]
-    }]
-  };
-  {
-    // Control case, setting last attribute shader location
-    const descriptor = t.getDescriptor(vertexInput, VERTEX_SHADER_CODE_WITH_NO_INPUT);
-    t.device.createRenderPipeline(descriptor);
-  }
-  {
-    // Test attribute location OOB
-    vertexInput.vertexBuffers[0].attributeSet[0].shaderLocation = MAX_VERTEX_ATTRIBUTES;
-    const descriptor = t.getDescriptor(vertexInput, VERTEX_SHADER_CODE_WITH_NO_INPUT);
-    t.expectValidationError(() => {
-      t.device.createRenderPipeline(descriptor);
-    });
-  }
-});
-g.test('check attribute offset out of bounds', async t => {
-  const vertexInput = {
-    vertexBuffers: [{
-      stride: 0,
-      attributeSet: [{
-        offset: MAX_VERTEX_BUFFER_END - 2 * Float32Array.BYTES_PER_ELEMENT,
-        shaderLocation: 0,
-        format: 'float2'
-      }]
-    }]
-  };
-  {
-    // Control case, setting max attribute offset to MAX_VERTEX_BUFFER_END - 8
-    const descriptor = t.getDescriptor(vertexInput, VERTEX_SHADER_CODE_WITH_NO_INPUT);
-    t.device.createRenderPipeline(descriptor);
-  }
-  {
-    // Control case, setting attribute offset to 8
-    vertexInput.vertexBuffers[0].attributeSet[0].offset = 8;
-    const descriptor = t.getDescriptor(vertexInput, VERTEX_SHADER_CODE_WITH_NO_INPUT);
-    t.device.createRenderPipeline(descriptor);
-  }
-  {
-    // Test attribute offset out of bounds
-    vertexInput.vertexBuffers[0].attributeSet[0].offset = MAX_VERTEX_BUFFER_END - 4;
-    const descriptor = t.getDescriptor(vertexInput, VERTEX_SHADER_CODE_WITH_NO_INPUT);
-    t.expectValidationError(() => {
-      t.device.createRenderPipeline(descriptor);
-    });
-  }
-});
-g.test('check multiple of 4 bytes constraint on offset', async t => {
-  const vertexInput = {
-    vertexBuffers: [{
-      stride: 0,
-      attributeSet: [{
-        offset: Float32Array.BYTES_PER_ELEMENT,
-        shaderLocation: 0,
-        format: 'float'
-      }]
-    }]
-  };
-  {
-    // Control case, setting offset 4 bytes
-    const descriptor = t.getDescriptor(vertexInput, VERTEX_SHADER_CODE_WITH_NO_INPUT);
-    t.device.createRenderPipeline(descriptor);
-  }
-  {
-    // Test offset of 2 bytes with uchar2 format
-    vertexInput.vertexBuffers[0].attributeSet[0].offset = 2;
-    vertexInput.vertexBuffers[0].attributeSet[0].format = 'uchar2';
-    const descriptor = t.getDescriptor(vertexInput, VERTEX_SHADER_CODE_WITH_NO_INPUT);
-    t.expectValidationError(() => {
-      t.device.createRenderPipeline(descriptor);
-    });
-  }
-  {
-    // Test offset of 2 bytes with float format
-    vertexInput.vertexBuffers[0].attributeSet[0].offset = 2;
-    vertexInput.vertexBuffers[0].attributeSet[0].format = 'float';
-    const descriptor = t.getDescriptor(vertexInput, VERTEX_SHADER_CODE_WITH_NO_INPUT);
-    t.expectValidationError(() => {
-      t.device.createRenderPipeline(descriptor);
-    });
-  }
-});
-g.test('check attribute offset overflow', async t => {
-  const vertexInput = {
-    vertexBuffers: [{
-      stride: 0,
-      attributeSet: [{
-        offset: Number.MAX_SAFE_INTEGER,
-        shaderLocation: 0,
-        format: 'float'
-      }]
-    }]
-  };
-  const descriptor = t.getDescriptor(vertexInput, VERTEX_SHADER_CODE_WITH_NO_INPUT);
-  t.expectValidationError(() => {
-    t.device.createRenderPipeline(descriptor);
-  });
-});
-//# sourceMappingURL=vertex_input.spec.js.map
\ No newline at end of file
diff --git a/third_party/blink/web_tests/external/wpt/webgpu/suites/cts/validation/vertex_state.spec.js b/third_party/blink/web_tests/external/wpt/webgpu/suites/cts/validation/vertex_state.spec.js
new file mode 100644
index 0000000..da619181
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/webgpu/suites/cts/validation/vertex_state.spec.js
@@ -0,0 +1,644 @@
+/**
+* AUTO-GENERATED - DO NOT EDIT. Source: https://github.com/gpuweb/cts
+**/
+
+export const description = `
+vertexState validation tests.
+`;
+import { TestGroup } from '../../../framework/index.js';
+import { ValidationTest } from './validation_test.js';
+const MAX_VERTEX_ATTRIBUTES = 16;
+const MAX_VERTEX_BUFFER_END = 2048;
+const MAX_VERTEX_BUFFER_ARRAY_STRIDE = 2048;
+const MAX_VERTEX_BUFFERS = 16;
+const VERTEX_SHADER_CODE_WITH_NO_INPUT = `
+  #version 450
+  void main() {
+    gl_Position = vec4(0.0);
+  }
+`;
+
+function clone(descriptor) {
+  return JSON.parse(JSON.stringify(descriptor));
+}
+
+class F extends ValidationTest {
+  async init() {
+    await Promise.all([super.init(), this.initGLSL()]);
+  }
+
+  getDescriptor(vertexState, vertexShaderCode) {
+    const descriptor = {
+      vertexStage: this.getVertexStage(vertexShaderCode),
+      fragmentStage: this.getFragmentStage(),
+      layout: this.getPipelineLayout(),
+      primitiveTopology: 'triangle-list',
+      colorStates: [{
+        format: 'rgba8unorm'
+      }],
+      vertexState
+    };
+    return descriptor;
+  }
+
+  getVertexStage(code) {
+    return {
+      module: this.makeShaderModuleFromGLSL('vertex', code),
+      entryPoint: 'main'
+    };
+  }
+
+  getFragmentStage() {
+    const code = `
+      #version 450
+      layout(location = 0) out vec4 fragColor;
+      void main() {
+        fragColor = vec4(0.0, 1.0, 0.0, 1.0);
+      }
+    `;
+    return {
+      module: this.makeShaderModuleFromGLSL('fragment', code),
+      entryPoint: 'main'
+    };
+  }
+
+  getPipelineLayout() {
+    return this.device.createPipelineLayout({
+      bindGroupLayouts: []
+    });
+  }
+
+}
+
+export const g = new TestGroup(F);
+g.test('an empty vertex input is valid', t => {
+  const vertexState = {};
+  const descriptor = t.getDescriptor(vertexState, VERTEX_SHADER_CODE_WITH_NO_INPUT);
+  t.device.createRenderPipeline(descriptor);
+});
+g.test('a null buffer is valid', t => {
+  {
+    // One null buffer is OK
+    const vertexState = {
+      vertexBuffers: [{
+        arrayStride: 0,
+        attributes: []
+      }]
+    };
+    const descriptor = t.getDescriptor(vertexState, VERTEX_SHADER_CODE_WITH_NO_INPUT);
+    t.device.createRenderPipeline(descriptor);
+  }
+  {
+    //  One null buffer followed by a buffer is OK
+    const vertexState = {
+      vertexBuffers: [{
+        arrayStride: 0,
+        attributes: []
+      }, {
+        arrayStride: 0,
+        attributes: [{
+          format: 'float',
+          offset: 0,
+          shaderLocation: 0
+        }]
+      }]
+    };
+    const descriptor = t.getDescriptor(vertexState, VERTEX_SHADER_CODE_WITH_NO_INPUT);
+    t.device.createRenderPipeline(descriptor);
+  }
+  {
+    //  One null buffer sitting between buffers is OK
+    const vertexState = {
+      vertexBuffers: [{
+        arrayStride: 0,
+        attributes: [{
+          format: 'float',
+          offset: 0,
+          shaderLocation: 0
+        }]
+      }, {
+        arrayStride: 0,
+        attributes: []
+      }, {
+        arrayStride: 0,
+        attributes: [{
+          format: 'float',
+          offset: 0,
+          shaderLocation: 1
+        }]
+      }]
+    };
+    const descriptor = t.getDescriptor(vertexState, VERTEX_SHADER_CODE_WITH_NO_INPUT);
+    t.device.createRenderPipeline(descriptor);
+  }
+});
+g.test('pipeline vertex buffers are backed by attributes in vertex input', async t => {
+  const vertexState = {
+    vertexBuffers: [{
+      arrayStride: 2 * Float32Array.BYTES_PER_ELEMENT,
+      attributes: [{
+        format: 'float',
+        offset: 0,
+        shaderLocation: 0
+      }, {
+        format: 'float',
+        offset: 0,
+        shaderLocation: 1
+      }]
+    }]
+  };
+  {
+    // Control case: pipeline with one input per attribute
+    const code = `
+      #version 450
+      layout(location = 0) in vec4 a;
+      layout(location = 1) in vec4 b;
+      void main() {
+          gl_Position = vec4(0.0);
+      }
+    `;
+    const descriptor = t.getDescriptor(vertexState, code);
+    t.device.createRenderPipeline(descriptor);
+  }
+  {
+    // Check it is valid for the pipeline to use a subset of the VertexState
+    const code = `
+      #version 450
+      layout(location = 0) in vec4 a;
+      void main() {
+          gl_Position = vec4(0.0);
+      }
+    `;
+    const descriptor = t.getDescriptor(vertexState, code);
+    t.device.createRenderPipeline(descriptor);
+  }
+  {
+    // Check for an error when the pipeline uses an attribute not in the vertex input
+    const code = `
+      #version 450
+      layout(location = 2) in vec4 a;
+      void main() {
+          gl_Position = vec4(0.0);
+      }
+    `;
+    const descriptor = t.getDescriptor(vertexState, code);
+    t.expectValidationError(() => {
+      t.device.createRenderPipeline(descriptor);
+    });
+  }
+});
+g.test('an arrayStride of 0 is valid', t => {
+  const vertexState = {
+    vertexBuffers: [{
+      arrayStride: 0,
+      attributes: [{
+        format: 'float',
+        offset: 0,
+        shaderLocation: 0
+      }]
+    }]
+  };
+  {
+    // Works ok without attributes
+    const descriptor = t.getDescriptor(vertexState, VERTEX_SHADER_CODE_WITH_NO_INPUT);
+    t.device.createRenderPipeline(descriptor);
+  }
+  {
+    // Works ok with attributes at a large-ish offset
+    vertexState.vertexBuffers[0].attributes[0].offset = 128;
+    const descriptor = t.getDescriptor(vertexState, VERTEX_SHADER_CODE_WITH_NO_INPUT);
+    t.device.createRenderPipeline(descriptor);
+  }
+});
+g.test('offset should be within vertex buffer arrayStride if arrayStride is not zero', async t => {
+  const vertexState = {
+    vertexBuffers: [{
+      arrayStride: 2 * Float32Array.BYTES_PER_ELEMENT,
+      attributes: [{
+        format: 'float',
+        offset: 0,
+        shaderLocation: 0
+      }, {
+        format: 'float',
+        offset: Float32Array.BYTES_PER_ELEMENT,
+        shaderLocation: 1
+      }]
+    }]
+  };
+  {
+    // Control case, setting correct arrayStride and offset
+    const descriptor = t.getDescriptor(vertexState, VERTEX_SHADER_CODE_WITH_NO_INPUT);
+    t.device.createRenderPipeline(descriptor);
+  }
+  {
+    // Test vertex attribute offset exceed vertex buffer arrayStride range
+    const badVertexState = clone(vertexState);
+    badVertexState.vertexBuffers[0].attributes[1].format = 'float2';
+    const descriptor = t.getDescriptor(badVertexState, VERTEX_SHADER_CODE_WITH_NO_INPUT);
+    t.expectValidationError(() => {
+      t.device.createRenderPipeline(descriptor);
+    });
+  }
+  {
+    // Test vertex attribute offset exceed vertex buffer arrayStride range
+    const badVertexState = clone(vertexState);
+    badVertexState.vertexBuffers[0].arrayStride = Float32Array.BYTES_PER_ELEMENT;
+    const descriptor = t.getDescriptor(badVertexState, VERTEX_SHADER_CODE_WITH_NO_INPUT);
+    t.expectValidationError(() => {
+      t.device.createRenderPipeline(descriptor);
+    });
+  }
+  {
+    // It's OK if arrayStride is zero
+    const goodVertexState = clone(vertexState);
+    goodVertexState.vertexBuffers[0].arrayStride = 0;
+    const descriptor = t.getDescriptor(goodVertexState, VERTEX_SHADER_CODE_WITH_NO_INPUT);
+    t.device.createRenderPipeline(descriptor);
+  }
+});
+g.test('check two attributes overlapping', async t => {
+  const vertexState = {
+    vertexBuffers: [{
+      arrayStride: 2 * Float32Array.BYTES_PER_ELEMENT,
+      attributes: [{
+        format: 'float',
+        offset: 0,
+        shaderLocation: 0
+      }, {
+        format: 'float',
+        offset: Float32Array.BYTES_PER_ELEMENT,
+        shaderLocation: 1
+      }]
+    }]
+  };
+  {
+    // Control case, setting correct arrayStride and offset
+    const descriptor = t.getDescriptor(vertexState, VERTEX_SHADER_CODE_WITH_NO_INPUT);
+    t.device.createRenderPipeline(descriptor);
+  }
+  {
+    // Test two attributes overlapping
+    const badVertexState = clone(vertexState);
+    badVertexState.vertexBuffers[0].attributes[0].format = 'int2';
+    const descriptor = t.getDescriptor(badVertexState, VERTEX_SHADER_CODE_WITH_NO_INPUT);
+    t.expectValidationError(() => {
+      t.device.createRenderPipeline(descriptor);
+    });
+  }
+});
+g.test('check out of bounds condition on total number of vertex buffers', async t => {
+  const vertexBuffers = [];
+
+  for (let i = 0; i < MAX_VERTEX_BUFFERS; i++) {
+    vertexBuffers.push({
+      arrayStride: 0,
+      attributes: [{
+        format: 'float',
+        offset: 0,
+        shaderLocation: i
+      }]
+    });
+  }
+
+  {
+    // Control case, setting max vertex buffer number
+    const vertexState = {
+      vertexBuffers
+    };
+    const descriptor = t.getDescriptor(vertexState, VERTEX_SHADER_CODE_WITH_NO_INPUT);
+    t.device.createRenderPipeline(descriptor);
+  }
+  {
+    // Test vertex buffer number exceed the limit
+    const vertexState = {
+      vertexBuffers: [...vertexBuffers, {
+        arrayStride: 0,
+        attributes: [{
+          format: 'float',
+          offset: 0,
+          shaderLocation: MAX_VERTEX_BUFFERS
+        }]
+      }]
+    };
+    const descriptor = t.getDescriptor(vertexState, VERTEX_SHADER_CODE_WITH_NO_INPUT);
+    t.expectValidationError(() => {
+      t.device.createRenderPipeline(descriptor);
+    });
+  }
+});
+g.test('check out of bounds on number of vertex attributes on a single vertex buffer', async t => {
+  const vertexAttributes = [];
+
+  for (let i = 0; i < MAX_VERTEX_ATTRIBUTES; i++) {
+    vertexAttributes.push({
+      format: 'float',
+      offset: 0,
+      shaderLocation: i
+    });
+  }
+
+  {
+    // Control case, setting max vertex buffer number
+    const vertexState = {
+      vertexBuffers: [{
+        arrayStride: 0,
+        attributes: vertexAttributes
+      }]
+    };
+    const descriptor = t.getDescriptor(vertexState, VERTEX_SHADER_CODE_WITH_NO_INPUT);
+    t.device.createRenderPipeline(descriptor);
+  }
+  {
+    // Test vertex attribute number exceed the limit
+    const vertexState = {
+      vertexBuffers: [{
+        arrayStride: 0,
+        attributes: [...vertexAttributes, {
+          format: 'float',
+          offset: 0,
+          shaderLocation: MAX_VERTEX_ATTRIBUTES
+        }]
+      }]
+    };
+    const descriptor = t.getDescriptor(vertexState, VERTEX_SHADER_CODE_WITH_NO_INPUT);
+    t.expectValidationError(() => {
+      t.device.createRenderPipeline(descriptor);
+    });
+  }
+});
+g.test('check out of bounds on number of vertex attributes across vertex buffers', async t => {
+  const vertexBuffers = [];
+
+  for (let i = 0; i < MAX_VERTEX_ATTRIBUTES; i++) {
+    vertexBuffers.push({
+      arrayStride: 0,
+      attributes: [{
+        format: 'float',
+        offset: 0,
+        shaderLocation: i
+      }]
+    });
+  }
+
+  {
+    // Control case, setting max vertex buffer number
+    const vertexState = {
+      vertexBuffers
+    };
+    const descriptor = t.getDescriptor(vertexState, VERTEX_SHADER_CODE_WITH_NO_INPUT);
+    t.device.createRenderPipeline(descriptor);
+  }
+  {
+    // Test vertex attribute number exceed the limit
+    vertexBuffers[MAX_VERTEX_ATTRIBUTES - 1].attributes.push({
+      format: 'float',
+      offset: 0,
+      shaderLocation: MAX_VERTEX_ATTRIBUTES
+    });
+    const vertexState = {
+      vertexBuffers
+    };
+    const descriptor = t.getDescriptor(vertexState, VERTEX_SHADER_CODE_WITH_NO_INPUT);
+    t.expectValidationError(() => {
+      t.device.createRenderPipeline(descriptor);
+    });
+  }
+});
+g.test('check out of bounds condition on input strides', async t => {
+  const vertexState = {
+    vertexBuffers: [{
+      arrayStride: MAX_VERTEX_BUFFER_ARRAY_STRIDE,
+      attributes: []
+    }]
+  };
+  {
+    // Control case, setting max input arrayStride
+    const descriptor = t.getDescriptor(vertexState, VERTEX_SHADER_CODE_WITH_NO_INPUT);
+    t.device.createRenderPipeline(descriptor);
+  }
+  {
+    // Test input arrayStride OOB
+    vertexState.vertexBuffers[0].arrayStride = MAX_VERTEX_BUFFER_ARRAY_STRIDE + 4;
+    const descriptor = t.getDescriptor(vertexState, VERTEX_SHADER_CODE_WITH_NO_INPUT);
+    t.expectValidationError(() => {
+      t.device.createRenderPipeline(descriptor);
+    });
+  }
+});
+g.test('check multiple of 4 bytes constraint on input arrayStride', async t => {
+  const vertexState = {
+    vertexBuffers: [{
+      arrayStride: 4,
+      attributes: [{
+        format: 'uchar2',
+        offset: 0,
+        shaderLocation: 0
+      }]
+    }]
+  };
+  {
+    // Control case, setting input arrayStride 4 bytes
+    const descriptor = t.getDescriptor(vertexState, VERTEX_SHADER_CODE_WITH_NO_INPUT);
+    t.device.createRenderPipeline(descriptor);
+  }
+  {
+    // Test input arrayStride not multiple of 4 bytes
+    vertexState.vertexBuffers[0].arrayStride = 2;
+    const descriptor = t.getDescriptor(vertexState, VERTEX_SHADER_CODE_WITH_NO_INPUT);
+    t.expectValidationError(() => {
+      t.device.createRenderPipeline(descriptor);
+    });
+  }
+});
+g.test('identical duplicate attributes are invalid', async t => {
+  const vertexState = {
+    vertexBuffers: [{
+      arrayStride: 0,
+      attributes: [{
+        format: 'float',
+        offset: 0,
+        shaderLocation: 0
+      }]
+    }]
+  };
+  {
+    // Control case, setting attribute 0
+    const descriptor = t.getDescriptor(vertexState, VERTEX_SHADER_CODE_WITH_NO_INPUT);
+    t.device.createRenderPipeline(descriptor);
+  }
+  {
+    // Oh no, attribute 0 is set twice
+    vertexState.vertexBuffers[0].attributes.push({
+      format: 'float',
+      offset: 0,
+      shaderLocation: 0
+    });
+    const descriptor = t.getDescriptor(vertexState, VERTEX_SHADER_CODE_WITH_NO_INPUT);
+    t.expectValidationError(() => {
+      t.device.createRenderPipeline(descriptor);
+    });
+  }
+});
+g.test('we cannot set same shader location', async t => {
+  {
+    const vertexState = {
+      vertexBuffers: [{
+        arrayStride: 0,
+        attributes: [{
+          format: 'float',
+          offset: 0,
+          shaderLocation: 0
+        }, {
+          format: 'float',
+          offset: Float32Array.BYTES_PER_ELEMENT,
+          shaderLocation: 1
+        }]
+      }]
+    };
+    {
+      // Control case, setting different shader locations in two attributes
+      const descriptor = t.getDescriptor(vertexState, VERTEX_SHADER_CODE_WITH_NO_INPUT);
+      t.device.createRenderPipeline(descriptor);
+    }
+    {
+      // Test same shader location in two attributes in the same buffer
+      vertexState.vertexBuffers[0].attributes[1].shaderLocation = 0;
+      const descriptor = t.getDescriptor(vertexState, VERTEX_SHADER_CODE_WITH_NO_INPUT);
+      t.expectValidationError(() => {
+        t.device.createRenderPipeline(descriptor);
+      });
+    }
+  }
+  {
+    const vertexState = {
+      vertexBuffers: [{
+        arrayStride: 0,
+        attributes: [{
+          format: 'float',
+          offset: 0,
+          shaderLocation: 0
+        }]
+      }, {
+        arrayStride: 0,
+        attributes: [{
+          format: 'float',
+          offset: 0,
+          shaderLocation: 0
+        }]
+      }]
+    }; // Test same shader location in two attributes in different buffers
+
+    const descriptor = t.getDescriptor(vertexState, VERTEX_SHADER_CODE_WITH_NO_INPUT);
+    t.expectValidationError(() => {
+      t.device.createRenderPipeline(descriptor);
+    });
+  }
+});
+g.test('check out of bounds condition on attribute shader location', async t => {
+  const vertexState = {
+    vertexBuffers: [{
+      arrayStride: 0,
+      attributes: [{
+        format: 'float',
+        offset: 0,
+        shaderLocation: MAX_VERTEX_ATTRIBUTES - 1
+      }]
+    }]
+  };
+  {
+    // Control case, setting last attribute shader location
+    const descriptor = t.getDescriptor(vertexState, VERTEX_SHADER_CODE_WITH_NO_INPUT);
+    t.device.createRenderPipeline(descriptor);
+  }
+  {
+    // Test attribute location OOB
+    vertexState.vertexBuffers[0].attributes[0].shaderLocation = MAX_VERTEX_ATTRIBUTES;
+    const descriptor = t.getDescriptor(vertexState, VERTEX_SHADER_CODE_WITH_NO_INPUT);
+    t.expectValidationError(() => {
+      t.device.createRenderPipeline(descriptor);
+    });
+  }
+});
+g.test('check attribute offset out of bounds', async t => {
+  const vertexState = {
+    vertexBuffers: [{
+      arrayStride: 0,
+      attributes: [{
+        format: 'float2',
+        offset: MAX_VERTEX_BUFFER_END - 2 * Float32Array.BYTES_PER_ELEMENT,
+        shaderLocation: 0
+      }]
+    }]
+  };
+  {
+    // Control case, setting max attribute offset to MAX_VERTEX_BUFFER_END - 8
+    const descriptor = t.getDescriptor(vertexState, VERTEX_SHADER_CODE_WITH_NO_INPUT);
+    t.device.createRenderPipeline(descriptor);
+  }
+  {
+    // Control case, setting attribute offset to 8
+    vertexState.vertexBuffers[0].attributes[0].offset = 8;
+    const descriptor = t.getDescriptor(vertexState, VERTEX_SHADER_CODE_WITH_NO_INPUT);
+    t.device.createRenderPipeline(descriptor);
+  }
+  {
+    // Test attribute offset out of bounds
+    vertexState.vertexBuffers[0].attributes[0].offset = MAX_VERTEX_BUFFER_END - 4;
+    const descriptor = t.getDescriptor(vertexState, VERTEX_SHADER_CODE_WITH_NO_INPUT);
+    t.expectValidationError(() => {
+      t.device.createRenderPipeline(descriptor);
+    });
+  }
+});
+g.test('check multiple of 4 bytes constraint on offset', async t => {
+  const vertexState = {
+    vertexBuffers: [{
+      arrayStride: 0,
+      attributes: [{
+        format: 'float',
+        offset: Float32Array.BYTES_PER_ELEMENT,
+        shaderLocation: 0
+      }]
+    }]
+  };
+  {
+    // Control case, setting offset 4 bytes
+    const descriptor = t.getDescriptor(vertexState, VERTEX_SHADER_CODE_WITH_NO_INPUT);
+    t.device.createRenderPipeline(descriptor);
+  }
+  {
+    // Test offset of 2 bytes with uchar2 format
+    vertexState.vertexBuffers[0].attributes[0].offset = 2;
+    vertexState.vertexBuffers[0].attributes[0].format = 'uchar2';
+    const descriptor = t.getDescriptor(vertexState, VERTEX_SHADER_CODE_WITH_NO_INPUT);
+    t.expectValidationError(() => {
+      t.device.createRenderPipeline(descriptor);
+    });
+  }
+  {
+    // Test offset of 2 bytes with float format
+    vertexState.vertexBuffers[0].attributes[0].offset = 2;
+    vertexState.vertexBuffers[0].attributes[0].format = 'float';
+    const descriptor = t.getDescriptor(vertexState, VERTEX_SHADER_CODE_WITH_NO_INPUT);
+    t.expectValidationError(() => {
+      t.device.createRenderPipeline(descriptor);
+    });
+  }
+});
+g.test('check attribute offset overflow', async t => {
+  const vertexState = {
+    vertexBuffers: [{
+      arrayStride: 0,
+      attributes: [{
+        format: 'float',
+        offset: Number.MAX_SAFE_INTEGER,
+        shaderLocation: 0
+      }]
+    }]
+  };
+  const descriptor = t.getDescriptor(vertexState, VERTEX_SHADER_CODE_WITH_NO_INPUT);
+  t.expectValidationError(() => {
+    t.device.createRenderPipeline(descriptor);
+  });
+});
+//# sourceMappingURL=vertex_state.spec.js.map
\ No newline at end of file
diff --git a/third_party/blink/web_tests/wpt_internal/webgpu/cts.html b/third_party/blink/web_tests/wpt_internal/webgpu/cts.html
index 95880efd..c67c0c8 100644
--- a/third_party/blink/web_tests/wpt_internal/webgpu/cts.html
+++ b/third_party/blink/web_tests/wpt_internal/webgpu/cts.html
@@ -216,3 +216,198 @@
 <meta name=variant content='?q=cts:validation/setScissorRect:'>
 <meta name=variant content='?q=cts:validation/setStencilReference:'>
 <meta name=variant content='?q=cts:validation/setViewport:'>
+
+<!-- Workers -->
+
+<meta name=variant content='?worker=1&q=cts:buffers/create_mapped:'>
+<meta name=variant content='?worker=1&q=cts:buffers/map:'>
+<meta name=variant content='?worker=1&q=cts:buffers/map_detach:'>
+
+<meta name=variant content='?worker=1&q=cts:buffers/map_oom:mapWriteAsync='>
+<meta name=variant content='?worker=1&q=cts:buffers/map_oom:mapReadAsync='>
+<meta name=variant content='?worker=1&q=cts:buffers/map_oom:createBufferMapped='>
+<meta name=variant content='?worker=1&q=cts:buffers/map_oom:createBufferAsync='>
+
+<meta name=variant content='?worker=1&q=cts:canvas/context_creation:'>
+<meta name=variant content='?worker=1&q=cts:command_buffer/basic:'>
+<meta name=variant content='?worker=1&q=cts:command_buffer/compute/basic:'>
+<meta name=variant content='?worker=1&q=cts:command_buffer/copies:'>
+<meta name=variant content='?worker=1&q=cts:command_buffer/render/basic:'>
+<meta name=variant content='?worker=1&q=cts:command_buffer/render/rendering:'>
+
+<meta name=variant content='?worker=1&q=cts:command_buffer/render/storeop:storeOp_controls_whether_1x1_drawn_quad_is_stored={"storeOp":"clear"}'>
+<meta name=variant content='?worker=1&q=cts:command_buffer/render/storeop:storeOp_controls_whether_1x1_drawn_quad_is_stored={"storeOp":"store"}'>
+
+<meta name=variant content='?worker=1&q=cts:examples:'>
+<meta name=variant content='?worker=1&q=cts:fences:'>
+
+<meta name=variant content='?worker=1&q=cts:validation/createBindGroup:binding_count_mismatch='>
+<meta name=variant content='?worker=1&q=cts:validation/createBindGroup:binding_must_be_present_in_layout='>
+<meta name=variant content='?worker=1&q=cts:validation/createBindGroup:buffer_binding_must_contain_exactly_one_buffer_of_its_type={"bindingType":"uniform-buffer","resourceType":"error"}'>
+<meta name=variant content='?worker=1&q=cts:validation/createBindGroup:buffer_binding_must_contain_exactly_one_buffer_of_its_type={"bindingType":"uniform-buffer","resourceType":"uniform-buffer"}'>
+<meta name=variant content='?worker=1&q=cts:validation/createBindGroup:buffer_binding_must_contain_exactly_one_buffer_of_its_type={"bindingType":"uniform-buffer","resourceType":"storage-buffer"}'>
+<meta name=variant content='?worker=1&q=cts:validation/createBindGroup:buffer_binding_must_contain_exactly_one_buffer_of_its_type={"bindingType":"uniform-buffer","resourceType":"sampler"}'>
+<meta name=variant content='?worker=1&q=cts:validation/createBindGroup:buffer_binding_must_contain_exactly_one_buffer_of_its_type={"bindingType":"uniform-buffer","resourceType":"sampled-texture"}'>
+<meta name=variant content='?worker=1&q=cts:validation/createBindGroup:buffer_binding_must_contain_exactly_one_buffer_of_its_type={"bindingType":"uniform-buffer","resourceType":"storage-texture"}'>
+<meta name=variant content='?worker=1&q=cts:validation/createBindGroup:buffer_binding_must_contain_exactly_one_buffer_of_its_type={"bindingType":"storage-buffer","resourceType":"error"}'>
+<meta name=variant content='?worker=1&q=cts:validation/createBindGroup:buffer_binding_must_contain_exactly_one_buffer_of_its_type={"bindingType":"storage-buffer","resourceType":"uniform-buffer"}'>
+<meta name=variant content='?worker=1&q=cts:validation/createBindGroup:buffer_binding_must_contain_exactly_one_buffer_of_its_type={"bindingType":"storage-buffer","resourceType":"storage-buffer"}'>
+<meta name=variant content='?worker=1&q=cts:validation/createBindGroup:buffer_binding_must_contain_exactly_one_buffer_of_its_type={"bindingType":"storage-buffer","resourceType":"sampler"}'>
+<meta name=variant content='?worker=1&q=cts:validation/createBindGroup:buffer_binding_must_contain_exactly_one_buffer_of_its_type={"bindingType":"storage-buffer","resourceType":"sampled-texture"}'>
+<meta name=variant content='?worker=1&q=cts:validation/createBindGroup:buffer_binding_must_contain_exactly_one_buffer_of_its_type={"bindingType":"storage-buffer","resourceType":"storage-texture"}'>
+<meta name=variant content='?worker=1&q=cts:validation/createBindGroup:buffer_binding_must_contain_exactly_one_buffer_of_its_type~{"bindingType":"readonly-storage-buffer"}'>
+<meta name=variant content='?worker=1&q=cts:validation/createBindGroup:buffer_binding_must_contain_exactly_one_buffer_of_its_type={"bindingType":"sampler","resourceType":"error"}'>
+<meta name=variant content='?worker=1&q=cts:validation/createBindGroup:buffer_binding_must_contain_exactly_one_buffer_of_its_type={"bindingType":"sampler","resourceType":"uniform-buffer"}'>
+<meta name=variant content='?worker=1&q=cts:validation/createBindGroup:buffer_binding_must_contain_exactly_one_buffer_of_its_type={"bindingType":"sampler","resourceType":"storage-buffer"}'>
+<meta name=variant content='?worker=1&q=cts:validation/createBindGroup:buffer_binding_must_contain_exactly_one_buffer_of_its_type={"bindingType":"sampler","resourceType":"sampler"}'>
+<meta name=variant content='?worker=1&q=cts:validation/createBindGroup:buffer_binding_must_contain_exactly_one_buffer_of_its_type={"bindingType":"sampler","resourceType":"sampled-texture"}'>
+<meta name=variant content='?worker=1&q=cts:validation/createBindGroup:buffer_binding_must_contain_exactly_one_buffer_of_its_type={"bindingType":"sampler","resourceType":"storage-texture"}'>
+<meta name=variant content='?worker=1&q=cts:validation/createBindGroup:buffer_binding_must_contain_exactly_one_buffer_of_its_type={"bindingType":"sampled-texture","resourceType":"error"}'>
+<meta name=variant content='?worker=1&q=cts:validation/createBindGroup:buffer_binding_must_contain_exactly_one_buffer_of_its_type={"bindingType":"sampled-texture","resourceType":"uniform-buffer"}'>
+<meta name=variant content='?worker=1&q=cts:validation/createBindGroup:buffer_binding_must_contain_exactly_one_buffer_of_its_type={"bindingType":"sampled-texture","resourceType":"storage-buffer"}'>
+<meta name=variant content='?worker=1&q=cts:validation/createBindGroup:buffer_binding_must_contain_exactly_one_buffer_of_its_type={"bindingType":"sampled-texture","resourceType":"sampler"}'>
+<meta name=variant content='?worker=1&q=cts:validation/createBindGroup:buffer_binding_must_contain_exactly_one_buffer_of_its_type={"bindingType":"sampled-texture","resourceType":"sampled-texture"}'>
+<meta name=variant content='?worker=1&q=cts:validation/createBindGroup:buffer_binding_must_contain_exactly_one_buffer_of_its_type={"bindingType":"sampled-texture","resourceType":"storage-texture"}'>
+<meta name=variant content='?worker=1&q=cts:validation/createBindGroup:buffer_binding_must_contain_exactly_one_buffer_of_its_type~{"bindingType":"storage-texture"}'>
+<meta name=variant content='?worker=1&q=cts:validation/createBindGroup:texture_binding_must_have_correct_usage={"type":"sampled-texture"}'>
+<meta name=variant content='?worker=1&q=cts:validation/createBindGroup:texture_binding_must_have_correct_usage={"type":"storage-texture"}'>
+<meta name=variant content='?worker=1&q=cts:validation/createBindGroup:texture_must_have_correct_component_type~'>
+<meta name=variant content='?worker=1&q=cts:validation/createBindGroup:texture_must_have_correct_dimension='>
+<meta name=variant content='?worker=1&q=cts:validation/createBindGroup:buffer_offset_and_size_for_bind_groups_match~'>
+
+<meta name=variant content='?worker=1&q=cts:validation/createBindGroupLayout:some_binding_index_was_specified_more_than_once='>
+<meta name=variant content='?worker=1&q=cts:validation/createBindGroupLayout:negative_binding_index='>
+<meta name=variant content='?worker=1&q=cts:validation/createBindGroupLayout:Visibility_of_bindings_can_be_0='>
+<meta name=variant content='?worker=1&q=cts:validation/createBindGroupLayout:number_of_dynamic_buffers_exceeds_the_maximum_value~'>
+<meta name=variant content='?worker=1&q=cts:validation/createBindGroupLayout:dynamic_set_to_true_is_allowed_only_for_buffers={"type":"uniform-buffer"}'>
+<meta name=variant content='?worker=1&q=cts:validation/createBindGroupLayout:dynamic_set_to_true_is_allowed_only_for_buffers={"type":"storage-buffer"}'>
+<meta name=variant content='?worker=1&q=cts:validation/createBindGroupLayout:dynamic_set_to_true_is_allowed_only_for_buffers={"type":"readonly-storage-buffer"}'>
+<meta name=variant content='?worker=1&q=cts:validation/createBindGroupLayout:dynamic_set_to_true_is_allowed_only_for_buffers={"type":"sampler"}'>
+<meta name=variant content='?worker=1&q=cts:validation/createBindGroupLayout:dynamic_set_to_true_is_allowed_only_for_buffers={"type":"sampled-texture"}'>
+<meta name=variant content='?worker=1&q=cts:validation/createBindGroupLayout:dynamic_set_to_true_is_allowed_only_for_buffers={"type":"storage-texture"}'>
+
+<meta name=variant content='?worker=1&q=cts:validation/createPipelineLayout:'>
+
+<meta name=variant content='?worker=1&q=cts:validation/createTexture:validation_of_sampleCount={"sampleCount":0}'>
+<meta name=variant content='?worker=1&q=cts:validation/createTexture:validation_of_sampleCount={"sampleCount":1}'>
+<meta name=variant content='?worker=1&q=cts:validation/createTexture:validation_of_sampleCount={"sampleCount":2}'>
+<meta name=variant content='?worker=1&q=cts:validation/createTexture:validation_of_sampleCount={"sampleCount":3}'>
+<meta name=variant content='?worker=1&q=cts:validation/createTexture:validation_of_sampleCount={"sampleCount":4}'>
+<meta name=variant content='?worker=1&q=cts:validation/createTexture:validation_of_sampleCount={"sampleCount":8}'>
+<meta name=variant content='?worker=1&q=cts:validation/createTexture:validation_of_sampleCount={"sampleCount":16}'>
+<meta name=variant content='?worker=1&q=cts:validation/createTexture:validation_of_sampleCount={"sampleCount":4,"mipLevelCount":2}'>
+<meta name=variant content='?worker=1&q=cts:validation/createTexture:validation_of_sampleCount={"sampleCount":4,"arrayLayerCount":2}'>
+<meta name=variant content='?worker=1&q=cts:validation/createTexture:validation_of_mipLevelCount={"width":32,"height":32,"mipLevelCount":1}'>
+<meta name=variant content='?worker=1&q=cts:validation/createTexture:validation_of_mipLevelCount={"width":32,"height":32,"mipLevelCount":0}'>
+<meta name=variant content='?worker=1&q=cts:validation/createTexture:validation_of_mipLevelCount={"width":32,"height":32,"mipLevelCount":6}'>
+<meta name=variant content='?worker=1&q=cts:validation/createTexture:validation_of_mipLevelCount={"width":31,"height":32,"mipLevelCount":7}'>
+<meta name=variant content='?worker=1&q=cts:validation/createTexture:validation_of_mipLevelCount={"width":32,"height":31,"mipLevelCount":7}'>
+<meta name=variant content='?worker=1&q=cts:validation/createTexture:validation_of_mipLevelCount={"width":32,"height":32,"mipLevelCount":100}'>
+<meta name=variant content='?worker=1&q=cts:validation/createTexture:validation_of_mipLevelCount={"width":32,"height":8,"mipLevelCount":6}'>
+<meta name=variant content='?worker=1&q=cts:validation/createTexture:it_is_valid_to_destroy_a_texture='>
+<meta name=variant content='?worker=1&q=cts:validation/createTexture:it_is_valid_to_destroy_a_destroyed_texture='>
+<meta name=variant content='?worker=1&q=cts:validation/createTexture:it_is_invalid_to_submit_a_destroyed_texture_before_and_after_encode={"destroyBeforeEncode":false,"destroyAfterEncode":false}'>
+<meta name=variant content='?worker=1&q=cts:validation/createTexture:it_is_invalid_to_submit_a_destroyed_texture_before_and_after_encode={"destroyBeforeEncode":true,"destroyAfterEncode":false}'>
+<meta name=variant content='?worker=1&q=cts:validation/createTexture:it_is_invalid_to_submit_a_destroyed_texture_before_and_after_encode={"destroyBeforeEncode":false,"destroyAfterEncode":true}'>
+<meta name=variant content='?worker=1&q=cts:validation/createTexture:it_is_invalid_to_have_an_output_attachment_texture_with_non_renderable_format={"format":"r8unorm"}'>
+<meta name=variant content='?worker=1&q=cts:validation/createTexture:it_is_invalid_to_have_an_output_attachment_texture_with_non_renderable_format={"format":"r8snorm"}'>
+<meta name=variant content='?worker=1&q=cts:validation/createTexture:it_is_invalid_to_have_an_output_attachment_texture_with_non_renderable_format={"format":"r8uint"}'>
+<meta name=variant content='?worker=1&q=cts:validation/createTexture:it_is_invalid_to_have_an_output_attachment_texture_with_non_renderable_format={"format":"r8sint"}'>
+<meta name=variant content='?worker=1&q=cts:validation/createTexture:it_is_invalid_to_have_an_output_attachment_texture_with_non_renderable_format={"format":"r16uint"}'>
+<meta name=variant content='?worker=1&q=cts:validation/createTexture:it_is_invalid_to_have_an_output_attachment_texture_with_non_renderable_format={"format":"r16sint"}'>
+<meta name=variant content='?worker=1&q=cts:validation/createTexture:it_is_invalid_to_have_an_output_attachment_texture_with_non_renderable_format={"format":"r16float"}'>
+<meta name=variant content='?worker=1&q=cts:validation/createTexture:it_is_invalid_to_have_an_output_attachment_texture_with_non_renderable_format={"format":"rg8unorm"}'>
+<meta name=variant content='?worker=1&q=cts:validation/createTexture:it_is_invalid_to_have_an_output_attachment_texture_with_non_renderable_format={"format":"rg8snorm"}'>
+<meta name=variant content='?worker=1&q=cts:validation/createTexture:it_is_invalid_to_have_an_output_attachment_texture_with_non_renderable_format={"format":"rg8uint"}'>
+<meta name=variant content='?worker=1&q=cts:validation/createTexture:it_is_invalid_to_have_an_output_attachment_texture_with_non_renderable_format={"format":"rg8sint"}'>
+<meta name=variant content='?worker=1&q=cts:validation/createTexture:it_is_invalid_to_have_an_output_attachment_texture_with_non_renderable_format={"format":"r32uint"}'>
+<meta name=variant content='?worker=1&q=cts:validation/createTexture:it_is_invalid_to_have_an_output_attachment_texture_with_non_renderable_format={"format":"r32sint"}'>
+<meta name=variant content='?worker=1&q=cts:validation/createTexture:it_is_invalid_to_have_an_output_attachment_texture_with_non_renderable_format={"format":"r32float"}'>
+<meta name=variant content='?worker=1&q=cts:validation/createTexture:it_is_invalid_to_have_an_output_attachment_texture_with_non_renderable_format={"format":"rg16uint"}'>
+<meta name=variant content='?worker=1&q=cts:validation/createTexture:it_is_invalid_to_have_an_output_attachment_texture_with_non_renderable_format={"format":"rg16sint"}'>
+<meta name=variant content='?worker=1&q=cts:validation/createTexture:it_is_invalid_to_have_an_output_attachment_texture_with_non_renderable_format={"format":"rg16float"}'>
+<meta name=variant content='?worker=1&q=cts:validation/createTexture:it_is_invalid_to_have_an_output_attachment_texture_with_non_renderable_format={"format":"rgba8unorm"}'>
+<meta name=variant content='?worker=1&q=cts:validation/createTexture:it_is_invalid_to_have_an_output_attachment_texture_with_non_renderable_format={"format":"rgba8unorm-srgb"}'>
+<meta name=variant content='?worker=1&q=cts:validation/createTexture:it_is_invalid_to_have_an_output_attachment_texture_with_non_renderable_format={"format":"rgba8snorm"}'>
+<meta name=variant content='?worker=1&q=cts:validation/createTexture:it_is_invalid_to_have_an_output_attachment_texture_with_non_renderable_format={"format":"rgba8uint"}'>
+<meta name=variant content='?worker=1&q=cts:validation/createTexture:it_is_invalid_to_have_an_output_attachment_texture_with_non_renderable_format={"format":"rgba8sint"}'>
+<meta name=variant content='?worker=1&q=cts:validation/createTexture:it_is_invalid_to_have_an_output_attachment_texture_with_non_renderable_format={"format":"bgra8unorm"}'>
+<meta name=variant content='?worker=1&q=cts:validation/createTexture:it_is_invalid_to_have_an_output_attachment_texture_with_non_renderable_format={"format":"bgra8unorm-srgb"}'>
+<meta name=variant content='?worker=1&q=cts:validation/createTexture:it_is_invalid_to_have_an_output_attachment_texture_with_non_renderable_format={"format":"rgb10a2unorm"}'>
+<meta name=variant content='?worker=1&q=cts:validation/createTexture:it_is_invalid_to_have_an_output_attachment_texture_with_non_renderable_format={"format":"rg11b10float"}'>
+<meta name=variant content='?worker=1&q=cts:validation/createTexture:it_is_invalid_to_have_an_output_attachment_texture_with_non_renderable_format={"format":"rg32uint"}'>
+<meta name=variant content='?worker=1&q=cts:validation/createTexture:it_is_invalid_to_have_an_output_attachment_texture_with_non_renderable_format={"format":"rg32sint"}'>
+<meta name=variant content='?worker=1&q=cts:validation/createTexture:it_is_invalid_to_have_an_output_attachment_texture_with_non_renderable_format={"format":"rg32float"}'>
+<meta name=variant content='?worker=1&q=cts:validation/createTexture:it_is_invalid_to_have_an_output_attachment_texture_with_non_renderable_format={"format":"rgba16uint"}'>
+<meta name=variant content='?worker=1&q=cts:validation/createTexture:it_is_invalid_to_have_an_output_attachment_texture_with_non_renderable_format={"format":"rgba16sint"}'>
+<meta name=variant content='?worker=1&q=cts:validation/createTexture:it_is_invalid_to_have_an_output_attachment_texture_with_non_renderable_format={"format":"rgba16float"}'>
+<meta name=variant content='?worker=1&q=cts:validation/createTexture:it_is_invalid_to_have_an_output_attachment_texture_with_non_renderable_format={"format":"rgba32uint"}'>
+<meta name=variant content='?worker=1&q=cts:validation/createTexture:it_is_invalid_to_have_an_output_attachment_texture_with_non_renderable_format={"format":"rgba32sint"}'>
+<meta name=variant content='?worker=1&q=cts:validation/createTexture:it_is_invalid_to_have_an_output_attachment_texture_with_non_renderable_format={"format":"rgba32float"}'>
+
+<meta name=variant content='?worker=1&q=cts:validation/createView:creating_texture_view_on_a_2D_non_array_texture={}'>
+<meta name=variant content='?worker=1&q=cts:validation/createView:creating_texture_view_on_a_2D_non_array_texture={"arrayLayerCount":1}'>
+<meta name=variant content='?worker=1&q=cts:validation/createView:creating_texture_view_on_a_2D_non_array_texture={"arrayLayerCount":2}'>
+<meta name=variant content='?worker=1&q=cts:validation/createView:creating_texture_view_on_a_2D_non_array_texture={"dimension":"2d-array","arrayLayerCount":1}'>
+<meta name=variant content='?worker=1&q=cts:validation/createView:creating_texture_view_on_a_2D_non_array_texture={"mipLevelCount":1,"baseMipLevel":5}'>
+<meta name=variant content='?worker=1&q=cts:validation/createView:creating_texture_view_on_a_2D_non_array_texture={"mipLevelCount":2,"baseMipLevel":4}'>
+<meta name=variant content='?worker=1&q=cts:validation/createView:creating_texture_view_on_a_2D_non_array_texture={"mipLevelCount":0,"baseMipLevel":0}'>
+<meta name=variant content='?worker=1&q=cts:validation/createView:creating_texture_view_on_a_2D_non_array_texture={"mipLevelCount":0,"baseMipLevel":1}'>
+<meta name=variant content='?worker=1&q=cts:validation/createView:creating_texture_view_on_a_2D_non_array_texture={"mipLevelCount":0,"baseMipLevel":5}'>
+<meta name=variant content='?worker=1&q=cts:validation/createView:creating_texture_view_on_a_2D_non_array_texture={"mipLevelCount":0,"baseMipLevel":6}'>
+<meta name=variant content='?worker=1&q=cts:validation/createView:creating_texture_view_on_a_2D_non_array_texture={"mipLevelCount":7,"baseMipLevel":0}'>
+<meta name=variant content='?worker=1&q=cts:validation/createView:creating_texture_view_on_a_2D_non_array_texture={"mipLevelCount":6,"baseMipLevel":1}'>
+<meta name=variant content='?worker=1&q=cts:validation/createView:creating_texture_view_on_a_2D_non_array_texture={"mipLevelCount":2,"baseMipLevel":5}'>
+<meta name=variant content='?worker=1&q=cts:validation/createView:creating_texture_view_on_a_2D_non_array_texture={"mipLevelCount":1,"baseMipLevel":6}'>
+<meta name=variant content='?worker=1&q=cts:validation/createView:creating_texture_view_on_a_2D_array_texture={}'>
+<meta name=variant content='?worker=1&q=cts:validation/createView:creating_texture_view_on_a_2D_array_texture={"dimension":"2d","arrayLayerCount":1}'>
+<meta name=variant content='?worker=1&q=cts:validation/createView:creating_texture_view_on_a_2D_array_texture={"arrayLayerCount":6}'>
+<meta name=variant content='?worker=1&q=cts:validation/createView:creating_texture_view_on_a_2D_array_texture={"arrayLayerCount":0,"baseArrayLayer":0}'>
+<meta name=variant content='?worker=1&q=cts:validation/createView:creating_texture_view_on_a_2D_array_texture={"arrayLayerCount":0,"baseArrayLayer":1}'>
+<meta name=variant content='?worker=1&q=cts:validation/createView:creating_texture_view_on_a_2D_array_texture={"arrayLayerCount":0,"baseArrayLayer":5}'>
+<meta name=variant content='?worker=1&q=cts:validation/createView:creating_texture_view_on_a_2D_array_texture={"arrayLayerCount":0,"baseArrayLayer":6}'>
+<meta name=variant content='?worker=1&q=cts:validation/createView:creating_texture_view_on_a_2D_array_texture={"arrayLayerCount":7,"baseArrayLayer":0}'>
+<meta name=variant content='?worker=1&q=cts:validation/createView:creating_texture_view_on_a_2D_array_texture={"arrayLayerCount":6,"baseArrayLayer":1}'>
+<meta name=variant content='?worker=1&q=cts:validation/createView:creating_texture_view_on_a_2D_array_texture={"arrayLayerCount":2,"baseArrayLayer":5}'>
+<meta name=variant content='?worker=1&q=cts:validation/createView:creating_texture_view_on_a_2D_array_texture={"arrayLayerCount":1,"baseArrayLayer":6}'>
+<meta name=variant content='?worker=1&q=cts:validation/createView:Using_defaults_validates_the_same_as_setting_values_for_more_than_1_array_layer={}'>
+<meta name=variant content='?worker=1&q=cts:validation/createView:Using_defaults_validates_the_same_as_setting_values_for_more_than_1_array_layer={"format":"rgba8unorm"}'>
+<meta name=variant content='?worker=1&q=cts:validation/createView:Using_defaults_validates_the_same_as_setting_values_for_more_than_1_array_layer={"format":"r8unorm"}'>
+<meta name=variant content='?worker=1&q=cts:validation/createView:Using_defaults_validates_the_same_as_setting_values_for_more_than_1_array_layer={"dimension":"2d-array"}'>
+<meta name=variant content='?worker=1&q=cts:validation/createView:Using_defaults_validates_the_same_as_setting_values_for_more_than_1_array_layer={"dimension":"2d"}'>
+<meta name=variant content='?worker=1&q=cts:validation/createView:Using_defaults_validates_the_same_as_setting_values_for_more_than_1_array_layer={"arrayLayerCount":6}'>
+<meta name=variant content='?worker=1&q=cts:validation/createView:Using_defaults_validates_the_same_as_setting_values_for_more_than_1_array_layer={"arrayLayerCount":6,"dimension":"2d-array"}'>
+<meta name=variant content='?worker=1&q=cts:validation/createView:Using_defaults_validates_the_same_as_setting_values_for_more_than_1_array_layer={"arrayLayerCount":6,"dimension":"2d-array","mipLevelCount":6}'>
+<meta name=variant content='?worker=1&q=cts:validation/createView:Using_defaults_validates_the_same_as_setting_values_for_only_1_array_layer={}'>
+<meta name=variant content='?worker=1&q=cts:validation/createView:Using_defaults_validates_the_same_as_setting_values_for_only_1_array_layer={"format":"rgba8unorm"}'>
+<meta name=variant content='?worker=1&q=cts:validation/createView:Using_defaults_validates_the_same_as_setting_values_for_only_1_array_layer={"format":"r8unorm"}'>
+<meta name=variant content='?worker=1&q=cts:validation/createView:Using_defaults_validates_the_same_as_setting_values_for_only_1_array_layer={"dimension":"2d-array"}'>
+<meta name=variant content='?worker=1&q=cts:validation/createView:Using_defaults_validates_the_same_as_setting_values_for_only_1_array_layer={"dimension":"2d"}'>
+<meta name=variant content='?worker=1&q=cts:validation/createView:Using_defaults_validates_the_same_as_setting_values_for_only_1_array_layer={"arrayLayerCount":0}'>
+<meta name=variant content='?worker=1&q=cts:validation/createView:Using_defaults_validates_the_same_as_setting_values_for_only_1_array_layer={"arrayLayerCount":1}'>
+<meta name=variant content='?worker=1&q=cts:validation/createView:Using_defaults_validates_the_same_as_setting_values_for_only_1_array_layer={"arrayLayerCount":2}'>
+<meta name=variant content='?worker=1&q=cts:validation/createView:Using_defaults_validates_the_same_as_setting_values_for_only_1_array_layer={"mipLevelCount":6}'>
+<meta name=variant content='?worker=1&q=cts:validation/createView:Using_defaults_validates_the_same_as_setting_values_for_only_1_array_layer={"mipLevelCount":1}'>
+<meta name=variant content='?worker=1&q=cts:validation/createView:creating_cube_map_texture_view={"dimension":"cube","arrayLayerCount":6}'>
+<meta name=variant content='?worker=1&q=cts:validation/createView:creating_cube_map_texture_view={"dimension":"cube","arrayLayerCount":3}'>
+<meta name=variant content='?worker=1&q=cts:validation/createView:creating_cube_map_texture_view={"dimension":"cube","arrayLayerCount":7}'>
+<meta name=variant content='?worker=1&q=cts:validation/createView:creating_cube_map_texture_view={"dimension":"cube","arrayLayerCount":12}'>
+<meta name=variant content='?worker=1&q=cts:validation/createView:creating_cube_map_texture_view={"dimension":"cube"}'>
+<meta name=variant content='?worker=1&q=cts:validation/createView:creating_cube_map_texture_view={"dimension":"cube-array","arrayLayerCount":12}'>
+<meta name=variant content='?worker=1&q=cts:validation/createView:creating_cube_map_texture_view={"dimension":"cube-array","arrayLayerCount":11}'>
+<meta name=variant content='?worker=1&q=cts:validation/createView:creating_cube_map_texture_view={"dimension":"cube-array","arrayLayerCount":13}'>
+<meta name=variant content='?worker=1&q=cts:validation/createView:creating_cube_map_texture_view_with_a_non_square_texture={"dimension":"cube","arrayLayerCount":6}'>
+<meta name=variant content='?worker=1&q=cts:validation/createView:creating_cube_map_texture_view_with_a_non_square_texture={"dimension":"cube-array","arrayLayerCount":12}'>
+<meta name=variant content='?worker=1&q=cts:validation/createView:test_the_format_compatibility_rules_when_creating_a_texture_view='>
+<meta name=variant content='?worker=1&q=cts:validation/createView:it_is_invalid_to_use_a_texture_view_created_from_a_destroyed_texture='>
+
+<meta name=variant content='?worker=1&q=cts:validation/error_scope:'>
+<meta name=variant content='?worker=1&q=cts:validation/fences:'>
+<meta name=variant content='?worker=1&q=cts:validation/queue_submit:'>
+<meta name=variant content='?worker=1&q=cts:validation/render_pass:'>
+<meta name=variant content='?worker=1&q=cts:validation/render_pass_descriptor:'>
+<meta name=variant content='?worker=1&q=cts:validation/setBindGroup:'>
+<meta name=variant content='?worker=1&q=cts:validation/setBlendColor:'>
+<meta name=variant content='?worker=1&q=cts:validation/setScissorRect:'>
+<meta name=variant content='?worker=1&q=cts:validation/setStencilReference:'>
+<meta name=variant content='?worker=1&q=cts:validation/setViewport:'>
diff --git a/third_party/closure_compiler/externs/input_method_private.js b/third_party/closure_compiler/externs/input_method_private.js
index e290c81..43461a9 100644
--- a/third_party/closure_compiler/externs/input_method_private.js
+++ b/third_party/closure_compiler/externs/input_method_private.js
@@ -162,6 +162,13 @@
 chrome.inputMethodPrivate.setXkbLayout = function(xkb_name, callback) {};
 
 /**
+ * Commits the text currently being composed without moving the selected text
+ * range
+ * @param {function():void=} callback Called when the operation completes.
+ */
+chrome.inputMethodPrivate.finishComposingText = function(callback) {};
+
+/**
  * Fires the input.ime.onMenuItemActivated event.
  * @param {string} engineID ID of the engine to use.
  * @param {string} name Name of the MenuItem which was activated
diff --git a/third_party/webxr_test_pages/webxr-samples/proposals/phone-ar-plane-detection-anchors.html b/third_party/webxr_test_pages/webxr-samples/proposals/phone-ar-plane-detection-anchors.html
index b0fc160..c54c5a2 100644
--- a/third_party/webxr_test_pages/webxr-samples/proposals/phone-ar-plane-detection-anchors.html
+++ b/third_party/webxr_test_pages/webxr-samples/proposals/phone-ar-plane-detection-anchors.html
@@ -388,8 +388,8 @@
               addARObjectAt(event.frame.session,
                             event.frame,
                             hitResult.plane,
-                            new XRRigidTransform(hitResult.hitMatrix),
-                            hitResult.plane.plane_space);
+                            new XRRigidTransform(hitResult.point_on_plane),
+                            hitResult.plane.planeSpace);
             } else {
               console.log("Missed everything, placing an anchor at origin.");
               addARObjectAt(event.frame.session,
@@ -474,8 +474,10 @@
 
       // Called every time a XRSession requests that a new frame be drawn.
       async function onXRFrame(t, frame) {
-
         let session = frame.session;
+
+        session.requestAnimationFrame(onXRFrame);
+
         let pose = frame.getViewerPose(xrRefSpace);
 
         let detected_planes = frame.worldInformation.detectedPlanes;
@@ -581,8 +583,6 @@
         scene.startFrame();
         scene.drawXRFrame(frame, pose);
         scene.endFrame();
-
-        session.requestAnimationFrame(onXRFrame);
       }
 
       // Start the XR application.
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml
index 2afc6959..bcb50d6 100644
--- a/tools/metrics/histograms/enums.xml
+++ b/tools/metrics/histograms/enums.xml
@@ -7914,6 +7914,7 @@
   <int value="30" label="kTpmAttestationKeys"/>
   <int value="31" label="kStrikes"/>
   <int value="32" label="kLeakedCredentials"/>
+  <int value="33" label="kFieldInfo"/>
 </enum>
 
 <enum name="ChromeChannelForHistogram">
@@ -21264,6 +21265,7 @@
   <int value="1403" label="AUTOTESTPRIVATE_REMOVEACTIVEDESK"/>
   <int value="1404" label="TERMINALPRIVATE_GETCROSHSETTINGS"/>
   <int value="1405" label="AUTOTESTPRIVATE_ENABLEASSISTANTANDWAITFORREADY"/>
+  <int value="1406" label="INPUTMETHODPRIVATE_FINISHCOMPOSINGTEXT"/>
 </enum>
 
 <enum name="ExtensionIconState">
@@ -37110,6 +37112,7 @@
   <int value="-169745744" label="SyncPseudoUSSPreferences:enabled"/>
   <int value="-167744090" label="EnableHomeLauncher:enabled"/>
   <int value="-165756594" label="enable-touch-feedback"/>
+  <int value="-165006916" label="EnableNeuralPalmDetectionFilter:enabled"/>
   <int value="-164539906"
       label="OmniboxPreserveDefaultMatchAgainstAsyncUpdate:disabled"/>
   <int value="-161782023" label="AndroidMessagesProdEndpoint:enabled"/>
@@ -37853,6 +37856,7 @@
   <int value="787385958" label="RegionalLocalesAsDisplayUI:enabled"/>
   <int value="799680074" label="ContextualSearchTranslationModel:enabled"/>
   <int value="803282885" label="PreferHtmlOverPlugins:disabled"/>
+  <int value="806035639" label="EnableNeuralPalmDetectionFilter:disabled"/>
   <int value="806334184" label="AndroidSpellChecker:enabled"/>
   <int value="807447752" label="ChromeMemex:disabled"/>
   <int value="807734471" label="tab-management-experiment-type-disabled"/>
@@ -38899,6 +38903,8 @@
   <int value="6" label="Stats table failed initialization"/>
   <int value="7" label="Migration error"/>
   <int value="8" label="Commit transaction error"/>
+  <int value="9" label="Init leaked table error"/>
+  <int value="10" label="Init field info table error"/>
 </enum>
 
 <enum name="LoginFailureReason">
@@ -46575,6 +46581,12 @@
   <int value="9" label="Optimization Guide Decider not initialized">
     The OptimizationGuideDecider was not initialized yet.
   </int>
+  <int value="10" label="Hint was being fetched but was not available yet">
+    A fetch for a hint that matches the page load from the remote Optimization
+    Guide Service was started but was not available in time to make a decision.
+    (Added in M80, Previously, this was combined with &quot;No hint available
+    for page load&quot;.)
+  </int>
 </enum>
 
 <enum name="OptimizationGuideProcessHintsResult">
diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml
index 43d7229..04333c0f 100644
--- a/tools/metrics/histograms/histograms.xml
+++ b/tools/metrics/histograms/histograms.xml
@@ -56323,6 +56323,17 @@
   </summary>
 </histogram>
 
+<histogram name="InputMethod.VirtualKeyboard.KeyboardShownLongTail" units="ms"
+    expires_after="2020-11-08">
+  <owner>jopalmer@chromium.org</owner>
+  <owner>essential-inputs-team@google.com</owner>
+  <summary>
+    Time to show the on-screen keyboard in milliseconds. Similar to
+    InputMethod.VirtualKeyboard.KeyboardShown but with a larger maximum to
+    capture more of the distribution.
+  </summary>
+</histogram>
+
 <histogram name="InputMethod.VirtualKeyboard.Layout" enum="IMEVKLayout">
   <owner>essential-inputs-team@google.com</owner>
   <summary>
@@ -126214,7 +126225,7 @@
 </histogram>
 
 <histogram name="SBClientDownload.ZipFileSuccess" enum="BooleanSuccess"
-    expires_after="M80">
+    expires_after="M83">
   <owner>drubery@chromium.org</owner>
   <owner>chrome-safebrowsing-alerts@google.com</owner>
   <summary>
@@ -143103,7 +143114,7 @@
 </histogram>
 
 <histogram name="Startup.WebFooterExperiment.DidFirstVisuallyNonEmptyPaint"
-    units="ms" expires_after="M80">
+    units="ms" expires_after="M84">
   <owner>pbos@chromium.org</owner>
   <owner>robliao@chromium.org</owner>
   <summary>
@@ -143112,7 +143123,7 @@
 </histogram>
 
 <histogram name="Startup.WebFooterExperiment.WebFooterCreation" units="ms"
-    expires_after="M80">
+    expires_after="M84">
   <owner>pbos@chromium.org</owner>
   <owner>robliao@chromium.org</owner>
   <summary>
@@ -173924,6 +173935,8 @@
 </histogram_suffixes>
 
 <histogram_suffixes name="Mobile.Messages.Confirm.Type" separator=".">
+  <suffix name="ConfirmInfobarTypeBlockPopups"
+      label="Recorded for Block Popups Confirm Messages."/>
   <suffix name="ConfirmInfobarTypeRestore"
       label="Recorded for Restore Tabs Confirm Messages."/>
   <affected-histogram name="Mobile.Messages.Confirm.Event"/>
diff --git a/ui/accelerated_widget_mac/io_surface_context.h b/ui/accelerated_widget_mac/io_surface_context.h
index cf7770d..504a52b 100644
--- a/ui/accelerated_widget_mac/io_surface_context.h
+++ b/ui/accelerated_widget_mac/io_surface_context.h
@@ -46,7 +46,7 @@
   CGLContextObj cgl_context() const { return cgl_context_; }
 
   // ui::GpuSwitchingObserver implementation.
-  void OnGpuSwitched() override;
+  void OnGpuSwitched(gl::GpuPreference active_gpu_heuristic) override;
 
  private:
   friend class base::RefCounted<IOSurfaceContext>;
diff --git a/ui/accelerated_widget_mac/io_surface_context.mm b/ui/accelerated_widget_mac/io_surface_context.mm
index bbfcb25d..50a7b9c1 100644
--- a/ui/accelerated_widget_mac/io_surface_context.mm
+++ b/ui/accelerated_widget_mac/io_surface_context.mm
@@ -113,7 +113,7 @@
   }
 }
 
-void IOSurfaceContext::OnGpuSwitched() {
+void IOSurfaceContext::OnGpuSwitched(gl::GpuPreference active_gpu_heuristic) {
   // Recreate all browser-side GL contexts whenever the GPU switches. If this
   // is not done, performance will suffer.
   // http://crbug.com/361493
diff --git a/ui/accessibility/ax_action_data.h b/ui/accessibility/ax_action_data.h
index 519fcc20..2b5529b 100644
--- a/ui/accessibility/ax_action_data.h
+++ b/ui/accessibility/ax_action_data.h
@@ -19,9 +19,6 @@
   AXActionData(const AXActionData& other);
   ~AXActionData();
 
-  // Return a string representation of this data, for debugging.
-  std::string ToString() const;
-
   // This is a simple serializable struct. All member variables should be
   // public and copyable.
 
diff --git a/ui/base/ime/chromeos/input_method_chromeos.cc b/ui/base/ime/chromeos/input_method_chromeos.cc
index 05beda6..5864c7b 100644
--- a/ui/base/ime/chromeos/input_method_chromeos.cc
+++ b/ui/base/ime/chromeos/input_method_chromeos.cc
@@ -42,7 +42,7 @@
 }
 
 InputMethodChromeOS::~InputMethodChromeOS() {
-  ConfirmCompositionText(/* reset_engine */ true);
+  ConfirmCompositionText(/* reset_engine */ true, /* keep_selection */ false);
   // We are dead, so we need to ask the client to stop relying on us.
   OnInputMethodChanged();
 
@@ -284,7 +284,7 @@
 void InputMethodChromeOS::OnWillChangeFocusedClient(
     TextInputClient* focused_before,
     TextInputClient* focused) {
-  ConfirmCompositionText(/* reset_engine */ true);
+  ConfirmCompositionText(/* reset_engine */ true, /* keep_selection */ false);
 
   if (GetEngine())
     GetEngine()->FocusOut();
@@ -344,8 +344,9 @@
   }
 }
 
-void InputMethodChromeOS::ConfirmCompositionText(bool reset_engine) {
-  InputMethodBase::ConfirmCompositionText(reset_engine);
+void InputMethodChromeOS::ConfirmCompositionText(bool reset_engine,
+                                                 bool keep_selection) {
+  InputMethodBase::ConfirmCompositionText(reset_engine, keep_selection);
 
   // See https://crbug.com/984472.
   ResetContext(reset_engine);
diff --git a/ui/base/ime/chromeos/input_method_chromeos.h b/ui/base/ime/chromeos/input_method_chromeos.h
index 0c40e72..7955f75 100644
--- a/ui/base/ime/chromeos/input_method_chromeos.h
+++ b/ui/base/ime/chromeos/input_method_chromeos.h
@@ -52,7 +52,7 @@
       uint32_t before,
       uint32_t after,
       const std::vector<ui::ImeTextSpan>& text_spans) override;
-  void ConfirmCompositionText(bool reset_engine) override;
+  void ConfirmCompositionText(bool reset_engine, bool keep_selection) override;
 
  protected:
   // Converts |text| into CompositionText.
diff --git a/ui/base/ime/chromeos/input_method_chromeos_unittest.cc b/ui/base/ime/chromeos/input_method_chromeos_unittest.cc
index 16e0be7c..d2fe588 100644
--- a/ui/base/ime/chromeos/input_method_chromeos_unittest.cc
+++ b/ui/base/ime/chromeos/input_method_chromeos_unittest.cc
@@ -268,7 +268,12 @@
   void SetCompositionText(const CompositionText& composition) override {
     composition_text_ = composition;
   }
-  void ConfirmCompositionText() override {
+  void ConfirmCompositionText(bool keep_selection) override {
+    // TODO(b/134473433) Modify this function so that when keep_selection is
+    // true, the selection is not changed when text committed
+    if (keep_selection) {
+      NOTIMPLEMENTED_LOG_ONCE();
+    }
     confirmed_text_ = composition_text_;
     composition_text_ = CompositionText();
   }
@@ -910,7 +915,8 @@
   input_type_ = TEXT_INPUT_TYPE_TEXT;
   ime_->OnTextInputTypeChanged(this);
 
-  ime_->ConfirmCompositionText(/* reset_engine */ true);
+  ime_->ConfirmCompositionText(/* reset_engine */ true,
+                               /* keep_selection */ false);
 
   EXPECT_TRUE(confirmed_text_.text.empty());
   EXPECT_TRUE(composition_text_.text.empty());
@@ -924,7 +930,8 @@
   CompositionText composition_text;
   composition_text.text = base::UTF8ToUTF16("hello");
   SetCompositionText(composition_text);
-  ime_->ConfirmCompositionText(/* reset_engine */ true);
+  ime_->ConfirmCompositionText(/* reset_engine */ true,
+                               /* keep_selection */ false);
 
   EXPECT_EQ(base::ASCIIToUTF16("hello"), confirmed_text_.text);
   EXPECT_TRUE(composition_text_.text.empty());
@@ -941,7 +948,8 @@
 
   // "abc" is in composition. Put the two characters in composition.
   ime_->SetCompositionRange(0, 2, {});
-  ime_->ConfirmCompositionText(/* reset_engine */ true);
+  ime_->ConfirmCompositionText(/* reset_engine */ true,
+                               /* keep_selection */ false);
 
   EXPECT_EQ(base::ASCIIToUTF16("ab"), confirmed_text_.text);
   EXPECT_TRUE(composition_text_.text.empty());
diff --git a/ui/base/ime/dummy_text_input_client.cc b/ui/base/ime/dummy_text_input_client.cc
index da3fc28..0cd06f6 100644
--- a/ui/base/ime/dummy_text_input_client.cc
+++ b/ui/base/ime/dummy_text_input_client.cc
@@ -35,8 +35,7 @@
   composition_history_.push_back(composition);
 }
 
-void DummyTextInputClient::ConfirmCompositionText() {
-}
+void DummyTextInputClient::ConfirmCompositionText(bool keep_selection) {}
 
 void DummyTextInputClient::ClearCompositionText() {
   SetCompositionText(CompositionText());
diff --git a/ui/base/ime/dummy_text_input_client.h b/ui/base/ime/dummy_text_input_client.h
index 0d9f5053..b4bbc8be 100644
--- a/ui/base/ime/dummy_text_input_client.h
+++ b/ui/base/ime/dummy_text_input_client.h
@@ -25,7 +25,7 @@
 
   // Overriden from TextInputClient.
   void SetCompositionText(const CompositionText& composition) override;
-  void ConfirmCompositionText() override;
+  void ConfirmCompositionText(bool) override;
   void ClearCompositionText() override;
   void InsertText(const base::string16& text) override;
   void InsertChar(const KeyEvent& event) override;
diff --git a/ui/base/ime/ime_input_context_handler_interface.h b/ui/base/ime/ime_input_context_handler_interface.h
index a62302c5..76c4496b 100644
--- a/ui/base/ime/ime_input_context_handler_interface.h
+++ b/ui/base/ime/ime_input_context_handler_interface.h
@@ -53,7 +53,8 @@
 
   // Commits any composition text.
   // Set |reset_engine| to false if this was triggered from the extension.
-  virtual void ConfirmCompositionText(bool reset_engine) = 0;
+  virtual void ConfirmCompositionText(bool reset_engine,
+                                      bool keep_selection) = 0;
 
   // Returns true if there is any composition text.
   virtual bool HasCompositionText() = 0;
diff --git a/ui/base/ime/input_method_base.cc b/ui/base/ime/input_method_base.cc
index 7cebca9..fdecc84 100644
--- a/ui/base/ime/input_method_base.cc
+++ b/ui/base/ime/input_method_base.cc
@@ -282,10 +282,11 @@
   return this;
 }
 
-void InputMethodBase::ConfirmCompositionText(bool reset_engine) {
+void InputMethodBase::ConfirmCompositionText(bool reset_engine,
+                                             bool keep_selection) {
   TextInputClient* client = GetTextInputClient();
   if (client && client->HasCompositionText())
-    client->ConfirmCompositionText();
+    client->ConfirmCompositionText(keep_selection);
 }
 
 bool InputMethodBase::HasCompositionText() {
diff --git a/ui/base/ime/input_method_base.h b/ui/base/ime/input_method_base.h
index 914c4bd..2d63937f 100644
--- a/ui/base/ime/input_method_base.h
+++ b/ui/base/ime/input_method_base.h
@@ -98,7 +98,7 @@
   SurroundingTextInfo GetSurroundingTextInfo() override;
   void SendKeyEvent(KeyEvent* event) override;
   InputMethod* GetInputMethod() override;
-  void ConfirmCompositionText(bool reset_engine) override;
+  void ConfirmCompositionText(bool reset_engine, bool keep_selection) override;
   bool HasCompositionText() override;
 
   // Sends a fake key event for IME composing without physical key events.
diff --git a/ui/base/ime/linux/input_method_auralinux.cc b/ui/base/ime/linux/input_method_auralinux.cc
index d14e686e..3f3663c3 100644
--- a/ui/base/ime/linux/input_method_auralinux.cc
+++ b/ui/base/ime/linux/input_method_auralinux.cc
@@ -414,7 +414,7 @@
 void InputMethodAuraLinux::OnWillChangeFocusedClient(
     TextInputClient* focused_before,
     TextInputClient* focused) {
-  ConfirmCompositionText(/* reset_engine */ true);
+  ConfirmCompositionText(/* reset_engine */ true, /* keep_selection */ false);
 }
 
 void InputMethodAuraLinux::OnDidChangeFocusedClient(
@@ -451,8 +451,12 @@
   return details;
 }
 
-void InputMethodAuraLinux::ConfirmCompositionText(bool reset_engine) {
-  InputMethodBase::ConfirmCompositionText(reset_engine);
+void InputMethodAuraLinux::ConfirmCompositionText(bool reset_engine,
+                                                  bool keep_selection) {
+  if (keep_selection) {
+    NOTIMPLEMENTED_LOG_ONCE();
+  }
+  InputMethodBase::ConfirmCompositionText(reset_engine, keep_selection);
   if (reset_engine && GetEngine())
     GetEngine()->Reset();
   ResetContext();
diff --git a/ui/base/ime/linux/input_method_auralinux.h b/ui/base/ime/linux/input_method_auralinux.h
index fffef79..294979d 100644
--- a/ui/base/ime/linux/input_method_auralinux.h
+++ b/ui/base/ime/linux/input_method_auralinux.h
@@ -47,7 +47,7 @@
                                  TextInputClient* focused) override;
   void OnDidChangeFocusedClient(TextInputClient* focused_before,
                                 TextInputClient* focused) override;
-  void ConfirmCompositionText(bool reset_engine) override;
+  void ConfirmCompositionText(bool reset_engine, bool keep_selection) override;
 
  private:
   bool HasInputMethodResult();
diff --git a/ui/base/ime/linux/input_method_auralinux_unittest.cc b/ui/base/ime/linux/input_method_auralinux_unittest.cc
index 9305047..02819b9 100644
--- a/ui/base/ime/linux/input_method_auralinux_unittest.cc
+++ b/ui/base/ime/linux/input_method_auralinux_unittest.cc
@@ -215,7 +215,12 @@
 
   bool HasCompositionText() const override { return !composition_text.empty(); }
 
-  void ConfirmCompositionText() override {
+  void ConfirmCompositionText(bool keep_selection) override {
+    // TODO(b/134473433) Modify this function so that when keep_selection is
+    // true, the selection is not changed when text committed
+    if (keep_selection) {
+      NOTIMPLEMENTED_LOG_ONCE();
+    }
     TestResult::GetInstance()->RecordAction(
         base::ASCIIToUTF16("compositionend"));
     TestResult::GetInstance()->RecordAction(base::ASCIIToUTF16("textinput:") +
diff --git a/ui/base/ime/mock_ime_input_context_handler.cc b/ui/base/ime/mock_ime_input_context_handler.cc
index bed1795..01e25ef6 100644
--- a/ui/base/ime/mock_ime_input_context_handler.cc
+++ b/ui/base/ime/mock_ime_input_context_handler.cc
@@ -72,7 +72,13 @@
   return nullptr;
 }
 
-void MockIMEInputContextHandler::ConfirmCompositionText(bool reset_engine) {
+void MockIMEInputContextHandler::ConfirmCompositionText(bool reset_engine,
+                                                        bool keep_selection) {
+  // TODO(b/134473433) Modify this function so that when keep_selection is
+  // true, the selection is not changed when text committed
+  if (keep_selection) {
+    NOTIMPLEMENTED_LOG_ONCE();
+  }
   if (!HasCompositionText())
     return;
 
diff --git a/ui/base/ime/mock_ime_input_context_handler.h b/ui/base/ime/mock_ime_input_context_handler.h
index d75e38b..fb0b849 100644
--- a/ui/base/ime/mock_ime_input_context_handler.h
+++ b/ui/base/ime/mock_ime_input_context_handler.h
@@ -48,7 +48,7 @@
   SurroundingTextInfo GetSurroundingTextInfo() override;
   void SendKeyEvent(KeyEvent* event) override;
   InputMethod* GetInputMethod() override;
-  void ConfirmCompositionText(bool reset_engine) override;
+  void ConfirmCompositionText(bool reset_engine, bool keep_selection) override;
   bool HasCompositionText() override;
 
   int commit_text_call_count() const { return commit_text_call_count_; }
diff --git a/ui/base/ime/text_input_client.h b/ui/base/ime/text_input_client.h
index 24371492..ae47101 100644
--- a/ui/base/ime/text_input_client.h
+++ b/ui/base/ime/text_input_client.h
@@ -61,7 +61,9 @@
   virtual void SetCompositionText(const ui::CompositionText& composition) = 0;
 
   // Converts current composition text into final content.
-  virtual void ConfirmCompositionText() = 0;
+  // If keep_selection is true, keep the selected range unchanged
+  // otherwise, set it to be after the newly committed text.
+  virtual void ConfirmCompositionText(bool keep_selection) = 0;
 
   // Removes current composition text.
   virtual void ClearCompositionText() = 0;
diff --git a/ui/base/ime/win/input_method_win_imm32.cc b/ui/base/ime/win/input_method_win_imm32.cc
index 2cc52439..7c0ee3e 100644
--- a/ui/base/ime/win/input_method_win_imm32.cc
+++ b/ui/base/ime/win/input_method_win_imm32.cc
@@ -159,7 +159,8 @@
     TextInputClient* focused_before,
     TextInputClient* focused) {
   if (IsWindowFocused(focused_before))
-    ConfirmCompositionText(/* reset_engine */ true);
+    ConfirmCompositionText(/* reset_engine */ true,
+                           /* keep_selection */ false);
 }
 
 void InputMethodWinImm32::OnDidChangeFocusedClient(
@@ -322,8 +323,9 @@
   }
 }
 
-void InputMethodWinImm32::ConfirmCompositionText(bool reset_engine) {
-  InputMethodBase::ConfirmCompositionText(reset_engine);
+void InputMethodWinImm32::ConfirmCompositionText(bool reset_engine,
+                                                 bool keep_selection) {
+  InputMethodBase::ConfirmCompositionText(reset_engine, keep_selection);
   if (reset_engine)
     InputMethodWinBase::ResetEngine();
 
diff --git a/ui/base/ime/win/input_method_win_imm32.h b/ui/base/ime/win/input_method_win_imm32.h
index 25922ff..c95a8ae7 100644
--- a/ui/base/ime/win/input_method_win_imm32.h
+++ b/ui/base/ime/win/input_method_win_imm32.h
@@ -27,7 +27,7 @@
 
   // Overridden from InputMethodBase:
   void OnFocus() override;
-  void ConfirmCompositionText(bool reset_engine) override;
+  void ConfirmCompositionText(bool reset_engine, bool keep_selection) override;
 
   // Overridden from InputMethod:
   bool OnUntranslatedIMEMessage(const MSG event,
diff --git a/ui/base/ime/win/input_method_win_tsf.cc b/ui/base/ime/win/input_method_win_tsf.cc
index 37d2888..e0b9a87 100644
--- a/ui/base/ime/win/input_method_win_tsf.cc
+++ b/ui/base/ime/win/input_method_win_tsf.cc
@@ -151,7 +151,8 @@
     TextInputClient* focused_before,
     TextInputClient* focused) {
   if (IsWindowFocused(focused_before)) {
-    ConfirmCompositionText(/* reset_engine */ true);
+    ConfirmCompositionText(/* reset_engine */ true,
+                           /* keep_selection */ false);
     ui::TSFBridge::GetInstance()->RemoveFocusedClient(focused_before);
   }
 }
@@ -176,7 +177,13 @@
   InputMethodWinBase::OnDidChangeFocusedClient(focused_before, focused);
 }
 
-void InputMethodWinTSF::ConfirmCompositionText(bool reset_engine) {
+void InputMethodWinTSF::ConfirmCompositionText(bool reset_engine,
+                                               bool keep_selection) {
+  // TODO(b/134473433) Modify this function so that when keep_selection is
+  // true, the selection is not changed when text committed
+  if (keep_selection) {
+    NOTIMPLEMENTED_LOG_ONCE();
+  }
   if (IsTextInputTypeNone())
     return;
 
diff --git a/ui/base/ime/win/input_method_win_tsf.h b/ui/base/ime/win/input_method_win_tsf.h
index 58d7855..58e0cfe 100644
--- a/ui/base/ime/win/input_method_win_tsf.h
+++ b/ui/base/ime/win/input_method_win_tsf.h
@@ -41,7 +41,7 @@
                                  TextInputClient* focused) override;
   void OnDidChangeFocusedClient(TextInputClient* focused_before,
                                 TextInputClient* focused) override;
-  void ConfirmCompositionText(bool reset_engine) override;
+  void ConfirmCompositionText(bool reset_engine, bool keep_selection) override;
 
   void ShowVirtualKeyboardIfEnabled() override;
 
diff --git a/ui/base/ime/win/tsf_input_policy_unittest.cc b/ui/base/ime/win/tsf_input_policy_unittest.cc
index 620f7df..3e31e57 100644
--- a/ui/base/ime/win/tsf_input_policy_unittest.cc
+++ b/ui/base/ime/win/tsf_input_policy_unittest.cc
@@ -39,7 +39,7 @@
  public:
   ~MockTextInputClient() {}
   MOCK_METHOD1(SetCompositionText, void(const ui::CompositionText&));
-  MOCK_METHOD0(ConfirmCompositionText, void());
+  MOCK_METHOD1(ConfirmCompositionText, void(bool));
   MOCK_METHOD0(ClearCompositionText, void());
   MOCK_METHOD1(InsertText, void(const base::string16&));
   MOCK_METHOD1(InsertChar, void(const ui::KeyEvent&));
diff --git a/ui/base/ime/win/tsf_text_store_unittest.cc b/ui/base/ime/win/tsf_text_store_unittest.cc
index fe4fdf1c..7909ade 100644
--- a/ui/base/ime/win/tsf_text_store_unittest.cc
+++ b/ui/base/ime/win/tsf_text_store_unittest.cc
@@ -37,7 +37,7 @@
  public:
   ~MockTextInputClient() {}
   MOCK_METHOD1(SetCompositionText, void(const ui::CompositionText&));
-  MOCK_METHOD0(ConfirmCompositionText, void());
+  MOCK_METHOD1(ConfirmCompositionText, void(bool));
   MOCK_METHOD0(ClearCompositionText, void());
   MOCK_METHOD1(InsertText, void(const base::string16&));
   MOCK_METHOD1(InsertChar, void(const ui::KeyEvent&));
diff --git a/ui/file_manager/file_manager/foreground/elements/files_xf_elements_unittest.js b/ui/file_manager/file_manager/foreground/elements/files_xf_elements_unittest.js
index 39bde07..f911e20 100644
--- a/ui/file_manager/file_manager/foreground/elements/files_xf_elements_unittest.js
+++ b/ui/file_manager/file_manager/foreground/elements/files_xf_elements_unittest.js
@@ -134,6 +134,33 @@
   done();
 }
 
+function testFilesDisplayPanelErrorText() {
+  // Get the host display panel container element.
+  /** @type {!DisplayPanel|!Element} */
+  const displayPanel = assert(document.querySelector('#test-xf-display-panel'));
+
+  // Add a panel item to the display panel container.
+  const panelItem = displayPanel.addPanelItem('testpanel');
+
+  // Change the primary and secondary text on the panel item.
+  panelItem.primaryText = 'foo';
+  panelItem.secondaryText = 'bar';
+
+  // Check the primary and secondary text has been set on the panel.
+  assertEquals('foo', panelItem.primaryText);
+  assertEquals('bar', panelItem.secondaryText);
+
+  // Change the panel item type to an error panel.
+  panelItem.panelType = panelItem.panelTypeError;
+
+  // Check the default primary text displays a generic error message.
+  // Note, the i18n message gets smooshed into 'An error occurred.' in the app.
+  assertEquals('$i18n{FILE_ERROR_GENERIC}', panelItem.primaryText);
+
+  // Check the secondary text is empty.
+  assertEquals('', panelItem.secondaryText);
+}
+
 // Override the formatting function for unit testing.
 util.strf = (end, option) => {
   return option + end;
diff --git a/ui/file_manager/file_manager/foreground/elements/xf_panel_item.js b/ui/file_manager/file_manager/foreground/elements/xf_panel_item.js
index 2e01600..17b465c 100644
--- a/ui/file_manager/file_manager/foreground/elements/xf_panel_item.js
+++ b/ui/file_manager/file_manager/foreground/elements/xf_panel_item.js
@@ -241,6 +241,8 @@
       case this.panelTypeError:
         this.setAttribute('indicator', 'status');
         this.setAttribute('status', 'failure');
+        this.primaryText = '$i18n{FILE_ERROR_GENERIC}';
+        this.secondaryText = '';
         secondaryButton = document.createElement('xf-button');
         secondaryButton.id = 'secondary-action';
         secondaryButton.onclick = assert(this.onclick);
@@ -516,6 +518,14 @@
   }
 
   /**
+   * Getter for the primary text on the panel.
+   * @return {string}
+   */
+  get primaryText() {
+    return this.getAttribute('primary-text');
+  }
+
+  /**
    * Setter to set the secondary text on the panel.
    * @param {string} text Text to be shown.
    */
@@ -524,6 +534,14 @@
   }
 
   /**
+   * Getter for the secondary text on the panel.
+   * @return {string}
+   */
+  get secondaryText() {
+    return this.getAttribute('secondary-text');
+  }
+
+  /**
    * Setter to set the panel type.
    * @param {number} type Enum value for the panel type.
    */
diff --git a/ui/file_manager/file_manager/foreground/js/file_manager_commands.js b/ui/file_manager/file_manager/foreground/js/file_manager_commands.js
index e965c23..fd690fba 100644
--- a/ui/file_manager/file_manager/foreground/js/file_manager_commands.js
+++ b/ui/file_manager/file_manager/foreground/js/file_manager_commands.js
@@ -164,7 +164,7 @@
 CommandUtil.forceDefaultHandler = (node, commandId) => {
   const doc = node.ownerDocument;
   const command = /** @type {!cr.ui.Command} */ (
-      doc.querySelector('command[id="' + commandId + '"]'));
+      doc.body.querySelector('command[id="' + commandId + '"]'));
   node.addEventListener('keydown', e => {
     if (command.matchesEvent(e)) {
       // Prevent cr.ui.CommandManager of handling it and leave it
diff --git a/ui/file_manager/file_manager/foreground/js/file_transfer_controller.js b/ui/file_manager/file_manager/foreground/js/file_transfer_controller.js
index bb3da3e..abc227c 100644
--- a/ui/file_manager/file_manager/foreground/js/file_transfer_controller.js
+++ b/ui/file_manager/file_manager/foreground/js/file_transfer_controller.js
@@ -141,14 +141,14 @@
      * @const
      */
     this.copyCommand_ = /** @type {!cr.ui.Command} */ (
-        queryRequiredElement('command#copy', this.document_));
+        queryRequiredElement('command#copy', assert(this.document_.body)));
 
     /**
      * @private {!cr.ui.Command}
      * @const
      */
     this.cutCommand_ = /** @type {!cr.ui.Command} */ (
-        queryRequiredElement('command#cut', this.document_));
+        queryRequiredElement('command#cut', assert(this.document_.body)));
 
     /**
      * @private {DirectoryEntry|FilesAppDirEntry}
@@ -616,7 +616,7 @@
   renderThumbnail_() {
     const length = this.selectionHandler_.selection.entries.length;
     const container = /** @type {HTMLElement} */ (
-        this.document_.querySelector('#drag-container'));
+        this.document_.body.querySelector('#drag-container'));
     const contents = this.document_.createElement('div');
     contents.className = 'drag-contents';
     container.appendChild(contents);
@@ -758,7 +758,7 @@
     // This should be removed after the bug is fixed.
     this.touching_ = false;
 
-    const container = this.document_.querySelector('#drag-container');
+    const container = this.document_.body.querySelector('#drag-container');
     container.textContent = '';
     this.clearDropTarget_();
     delete window[DRAG_AND_DROP_GLOBAL_DATA];
@@ -1280,7 +1280,7 @@
    * @private
    */
   simulateCommand_(command, handler) {
-    const iframe = this.document_.querySelector('#command-dispatcher');
+    const iframe = this.document_.body.querySelector('#command-dispatcher');
     const doc = iframe.contentDocument;
     doc.addEventListener(command, handler);
     doc.execCommand(command);
diff --git a/ui/file_manager/file_manager/foreground/js/ui/commandbutton.js b/ui/file_manager/file_manager/foreground/js/ui/commandbutton.js
index 6fed6ef..4170c12 100644
--- a/ui/file_manager/file_manager/foreground/js/ui/commandbutton.js
+++ b/ui/file_manager/file_manager/foreground/js/ui/commandbutton.js
@@ -72,7 +72,7 @@
     if (typeof command == 'string') {
       assert(command[0] == '#');
       command = /** @type {!cr.ui.Command} */
-          (this.ownerDocument.getElementById(command.slice(1)));
+          (this.ownerDocument.body.querySelector(command));
       cr.ui.decorate(command, cr.ui.Command);
     }
 
diff --git a/ui/file_manager/file_manager/foreground/js/ui/multi_menu.js b/ui/file_manager/file_manager/foreground/js/ui/multi_menu.js
index e06d978..36de11e 100644
--- a/ui/file_manager/file_manager/foreground/js/ui/multi_menu.js
+++ b/ui/file_manager/file_manager/foreground/js/ui/multi_menu.js
@@ -119,7 +119,7 @@
     }
     set menu(menu) {
       if (typeof menu == 'string' && menu[0] == '#') {
-        menu = assert(this.ownerDocument.getElementById(menu.slice(1)));
+        menu = assert(this.ownerDocument.body.querySelector(menu));
         cr.ui.decorate(menu, cr.ui.Menu);
       }
 
diff --git a/ui/gl/gpu_switching_manager.cc b/ui/gl/gpu_switching_manager.cc
index be715646..76a7821d 100644
--- a/ui/gl/gpu_switching_manager.cc
+++ b/ui/gl/gpu_switching_manager.cc
@@ -23,9 +23,10 @@
   observer_list_.RemoveObserver(observer);
 }
 
-void GpuSwitchingManager::NotifyGpuSwitched() {
+void GpuSwitchingManager::NotifyGpuSwitched(
+    gl::GpuPreference active_gpu_heuristic) {
   for (GpuSwitchingObserver& observer : observer_list_)
-    observer.OnGpuSwitched();
+    observer.OnGpuSwitched(active_gpu_heuristic);
 }
 
 }  // namespace ui
diff --git a/ui/gl/gpu_switching_manager.h b/ui/gl/gpu_switching_manager.h
index eb7e480..fde5eafe 100644
--- a/ui/gl/gpu_switching_manager.h
+++ b/ui/gl/gpu_switching_manager.h
@@ -9,6 +9,7 @@
 #include "base/observer_list.h"
 #include "build/build_config.h"
 #include "ui/gl/gl_export.h"
+#include "ui/gl/gpu_preference.h"
 #include "ui/gl/gpu_switching_observer.h"
 
 namespace ui {
@@ -26,7 +27,11 @@
   // occurs as a result of an IPC from the browser. The system observer is kept
   // in the browser process only so that any workarounds or blacklisting can
   // be applied there.
-  void NotifyGpuSwitched();
+  //
+  // The GpuPreference argument is a heuristic indicating whether the
+  // system is known to be on the low-power or high-performance GPU.
+  // If this heuristic fails, then kDefault is passed as argument.
+  void NotifyGpuSwitched(gl::GpuPreference active_gpu_heuristic);
 
  private:
   friend struct base::DefaultSingletonTraits<GpuSwitchingManager>;
diff --git a/ui/gl/gpu_switching_observer.h b/ui/gl/gpu_switching_observer.h
index 56f00db..b4e628c 100644
--- a/ui/gl/gpu_switching_observer.h
+++ b/ui/gl/gpu_switching_observer.h
@@ -6,13 +6,14 @@
 #define UI_GL_GPU_SWITCHING_OBSERVER_H_
 
 #include "ui/gl/gl_export.h"
+#include "ui/gl/gpu_preference.h"
 
 namespace ui {
 
 class GL_EXPORT GpuSwitchingObserver {
  public:
   // Called for any observer when the system switches to a different GPU.
-  virtual void OnGpuSwitched() {}
+  virtual void OnGpuSwitched(gl::GpuPreference active_gpu_heuristic) {}
 };
 
 }  // namespace ui
diff --git a/ui/gl/mojom/BUILD.gn b/ui/gl/mojom/BUILD.gn
new file mode 100644
index 0000000..648b511
--- /dev/null
+++ b/ui/gl/mojom/BUILD.gn
@@ -0,0 +1,25 @@
+# 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("//mojo/public/tools/bindings/mojom.gni")
+
+mojom("mojom") {
+  sources = [
+    "gpu_preference.mojom",
+  ]
+
+  public_deps = [
+    "//mojo/public/mojom/base",
+  ]
+}
+
+mojom("test_interfaces") {
+  sources = [
+    "traits_test_service.mojom",
+  ]
+
+  public_deps = [
+    ":mojom",
+  ]
+}
diff --git a/ui/gl/mojom/OWNERS b/ui/gl/mojom/OWNERS
new file mode 100644
index 0000000..ae29a36aa
--- /dev/null
+++ b/ui/gl/mojom/OWNERS
@@ -0,0 +1,6 @@
+per-file *.mojom=set noparent
+per-file *.mojom=file://ipc/SECURITY_OWNERS
+per-file *_mojom_traits*.*=set noparent
+per-file *_mojom_traits*.*=file://ipc/SECURITY_OWNERS
+per-file *.typemap=set noparent
+per-file *.typemap=file://ipc/SECURITY_OWNERS
diff --git a/ui/gl/mojom/gpu_preference.mojom b/ui/gl/mojom/gpu_preference.mojom
new file mode 100644
index 0000000..645f6fb
--- /dev/null
+++ b/ui/gl/mojom/gpu_preference.mojom
@@ -0,0 +1,12 @@
+// 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.
+
+module gl.mojom;
+
+// gl::GpuPreference
+enum GpuPreference {
+  kDefault,
+  kLowPower,
+  kHighPerformance,
+};
diff --git a/ui/gl/mojom/gpu_preference.typemap b/ui/gl/mojom/gpu_preference.typemap
new file mode 100644
index 0000000..ec7a154
--- /dev/null
+++ b/ui/gl/mojom/gpu_preference.typemap
@@ -0,0 +1,12 @@
+# 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.
+
+mojom = "//ui/gl/mojom/gpu_preference.mojom"
+public_headers = [ "//ui/gl/gpu_preference.h" ]
+traits_headers = [ "//ui/gl/mojom/gpu_preference_mojom_traits.h" ]
+sources = []
+public_deps = [
+  "//ui/gl",
+]
+type_mappings = [ "gl.mojom.GpuPreference=::gl::GpuPreference" ]
diff --git a/ui/gl/mojom/gpu_preference_mojom_traits.h b/ui/gl/mojom/gpu_preference_mojom_traits.h
new file mode 100644
index 0000000..09deab4
--- /dev/null
+++ b/ui/gl/mojom/gpu_preference_mojom_traits.h
@@ -0,0 +1,48 @@
+// 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 UI_GL_MOJOM_GPU_PREFERENCE_MOJOM_TRAITS_H_
+#define UI_GL_MOJOM_GPU_PREFERENCE_MOJOM_TRAITS_H_
+
+#include "ui/gl/gpu_preference.h"
+#include "ui/gl/mojom/gpu_preference.mojom.h"
+
+namespace mojo {
+
+template <>
+struct EnumTraits<gl::mojom::GpuPreference, gl::GpuPreference> {
+  static gl::mojom::GpuPreference ToMojom(gl::GpuPreference preference) {
+    switch (preference) {
+      case gl::GpuPreference::kDefault:
+        return gl::mojom::GpuPreference::kDefault;
+      case gl::GpuPreference::kLowPower:
+        return gl::mojom::GpuPreference::kLowPower;
+      case gl::GpuPreference::kHighPerformance:
+        return gl::mojom::GpuPreference::kHighPerformance;
+    }
+    NOTREACHED();
+    return gl::mojom::GpuPreference::kDefault;
+  }
+
+  static bool FromMojom(gl::mojom::GpuPreference input,
+                        gl::GpuPreference* out) {
+    switch (input) {
+      case gl::mojom::GpuPreference::kDefault:
+        *out = gl::GpuPreference::kDefault;
+        return true;
+      case gl::mojom::GpuPreference::kLowPower:
+        *out = gl::GpuPreference::kLowPower;
+        return true;
+      case gl::mojom::GpuPreference::kHighPerformance:
+        *out = gl::GpuPreference::kHighPerformance;
+        return true;
+    }
+    NOTREACHED();
+    return false;
+  }
+};
+
+}  // namespace mojo
+
+#endif  // UI_GL_MOJOM_GPU_PREFERENCE_MOJOM_TRAITS_H_
diff --git a/ui/gl/mojom/traits_test_service.mojom b/ui/gl/mojom/traits_test_service.mojom
new file mode 100644
index 0000000..84bbddf
--- /dev/null
+++ b/ui/gl/mojom/traits_test_service.mojom
@@ -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.
+
+module gl.mojom;
+
+import "ui/gl/mojom/gpu_preference.mojom";
+
+// All functions on this interface echo their arguments to test StructTraits
+// serialization and deserialization.
+interface TraitsTestService {
+  [Sync]
+  EchoGpuPreference(GpuPreference g) => (GpuPreference pass);
+};
diff --git a/ui/gl/typemaps.gni b/ui/gl/typemaps.gni
new file mode 100644
index 0000000..f831c21b
--- /dev/null
+++ b/ui/gl/typemaps.gni
@@ -0,0 +1,5 @@
+# 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.
+
+typemaps = [ "//ui/gl/mojom/gpu_preference.typemap" ]
diff --git a/ui/ozone/platform/scenic/scenic_window.cc b/ui/ozone/platform/scenic/scenic_window.cc
index 1133178..5ce4cd7 100644
--- a/ui/ozone/platform/scenic/scenic_window.cc
+++ b/ui/ozone/platform/scenic/scenic_window.cc
@@ -63,19 +63,20 @@
 
 void ScenicWindow::AttachSurfaceView(
     fuchsia::ui::views::ViewHolderToken token) {
-  scenic::ViewHolder surface_view_holder(&scenic_session_, std::move(token),
-                                         "chromium window surface");
+  surface_view_holder_ = std::make_unique<scenic::ViewHolder>(
+      &scenic_session_, std::move(token), "chromium window surface");
 
   // Configure the ViewHolder not to be focusable, or hit-testable, to ensure
   // that it cannot receive input.
   fuchsia::ui::gfx::ViewProperties view_properties;
+  view_properties.bounding_box = {{-0.5f, -0.5f, -0.5f}, {0.5f, 0.5f, 0.5f}};
   view_properties.focus_change = false;
-  surface_view_holder.SetViewProperties(std::move(view_properties));
-  surface_view_holder.SetHitTestBehavior(
+  surface_view_holder_->SetViewProperties(std::move(view_properties));
+  surface_view_holder_->SetHitTestBehavior(
       fuchsia::ui::gfx::HitTestBehavior::kSuppress);
 
   render_node_.DetachChildren();
-  render_node_.Attach(surface_view_holder);
+  render_node_.AddChild(*surface_view_holder_);
 
   scenic_session_.Present(
       /*presentation_time=*/0, [](fuchsia::images::PresentationInfo info) {});
diff --git a/ui/ozone/platform/scenic/scenic_window.h b/ui/ozone/platform/scenic/scenic_window.h
index 2b6197b8..7277075 100644
--- a/ui/ozone/platform/scenic/scenic_window.h
+++ b/ui/ozone/platform/scenic/scenic_window.h
@@ -116,6 +116,7 @@
 
   // Node in |scenic_session_| for rendering (hit testing disabled).
   scenic::EntityNode render_node_;
+  std::unique_ptr<scenic::ViewHolder> surface_view_holder_;
 
   // The ratio used for translating device-independent coordinates to absolute
   // pixel coordinates.
diff --git a/ui/views/cocoa/text_input_host.mm b/ui/views/cocoa/text_input_host.mm
index 9607e56..ddeba0c4 100644
--- a/ui/views/cocoa/text_input_host.mm
+++ b/ui/views/cocoa/text_input_host.mm
@@ -301,7 +301,7 @@
 void TextInputHost::ConfirmCompositionText() {
   if (!text_input_client_)
     return;
-  text_input_client_->ConfirmCompositionText();
+  text_input_client_->ConfirmCompositionText(/* keep_selection */ false);
 }
 
 bool TextInputHost::HasCompositionText(bool* out_has_composition_text) {
diff --git a/ui/views/controls/prefix_selector.cc b/ui/views/controls/prefix_selector.cc
index ceab3ca..4d9cde2 100644
--- a/ui/views/controls/prefix_selector.cc
+++ b/ui/views/controls/prefix_selector.cc
@@ -41,8 +41,7 @@
     const ui::CompositionText& composition) {
 }
 
-void PrefixSelector::ConfirmCompositionText() {
-}
+void PrefixSelector::ConfirmCompositionText(bool keep_selection) {}
 
 void PrefixSelector::ClearCompositionText() {
 }
diff --git a/ui/views/controls/prefix_selector.h b/ui/views/controls/prefix_selector.h
index 84a9657..9f08b202 100644
--- a/ui/views/controls/prefix_selector.h
+++ b/ui/views/controls/prefix_selector.h
@@ -44,7 +44,7 @@
 
   // ui::TextInputClient:
   void SetCompositionText(const ui::CompositionText& composition) override;
-  void ConfirmCompositionText() override;
+  void ConfirmCompositionText(bool keep_selection) override;
   void ClearCompositionText() override;
   void InsertText(const base::string16& text) override;
   void InsertChar(const ui::KeyEvent& event) override;
diff --git a/ui/views/controls/textfield/textfield.cc b/ui/views/controls/textfield/textfield.cc
index 31985ec07..9e85918 100644
--- a/ui/views/controls/textfield/textfield.cc
+++ b/ui/views/controls/textfield/textfield.cc
@@ -1462,7 +1462,12 @@
   OnAfterUserAction();
 }
 
-void Textfield::ConfirmCompositionText() {
+void Textfield::ConfirmCompositionText(bool keep_selection) {
+  // TODO(b/134473433) Modify this function so that when keep_selection is
+  // true, the selection is not changed when text committed
+  if (keep_selection) {
+    NOTIMPLEMENTED_LOG_ONCE();
+  }
   if (!model_->HasCompositionText())
     return;
 
diff --git a/ui/views/controls/textfield/textfield.h b/ui/views/controls/textfield/textfield.h
index 9d31ab8..8357ff7 100644
--- a/ui/views/controls/textfield/textfield.h
+++ b/ui/views/controls/textfield/textfield.h
@@ -339,7 +339,7 @@
 
   // ui::TextInputClient overrides:
   void SetCompositionText(const ui::CompositionText& composition) override;
-  void ConfirmCompositionText() override;
+  void ConfirmCompositionText(bool keep_selection) override;
   void ClearCompositionText() override;
   void InsertText(const base::string16& text) override;
   void InsertChar(const ui::KeyEvent& event) override;
diff --git a/ui/views/controls/textfield/textfield_unittest.cc b/ui/views/controls/textfield/textfield_unittest.cc
index 85bd50c..5ec471c 100644
--- a/ui/views/controls/textfield/textfield_unittest.cc
+++ b/ui/views/controls/textfield/textfield_unittest.cc
@@ -222,7 +222,7 @@
     ui::TextInputClient* focused) {
   ui::TextInputClient* client = GetTextInputClient();
   if (client && client->HasCompositionText())
-    client->ConfirmCompositionText();
+    client->ConfirmCompositionText(/* keep_selection */ false);
   ClearComposition();
 }
 
diff --git a/ui/views/controls/webview/web_dialog_view.cc b/ui/views/controls/webview/web_dialog_view.cc
index fc3bb0b..f4a07f2 100644
--- a/ui/views/controls/webview/web_dialog_view.cc
+++ b/ui/views/controls/webview/web_dialog_view.cc
@@ -268,10 +268,9 @@
   return std::string();
 }
 
-void WebDialogView::OnDialogShown(content::WebUI* webui,
-                                  content::RenderViewHost* render_view_host) {
+void WebDialogView::OnDialogShown(content::WebUI* webui) {
   if (delegate_)
-    delegate_->OnDialogShown(webui, render_view_host);
+    delegate_->OnDialogShown(webui);
 }
 
 void WebDialogView::OnDialogClosed(const std::string& json_retval) {
diff --git a/ui/views/controls/webview/web_dialog_view.h b/ui/views/controls/webview/web_dialog_view.h
index e395998..50a6290 100644
--- a/ui/views/controls/webview/web_dialog_view.h
+++ b/ui/views/controls/webview/web_dialog_view.h
@@ -114,8 +114,7 @@
   void GetDialogSize(gfx::Size* size) const override;
   void GetMinimumDialogSize(gfx::Size* size) const override;
   std::string GetDialogArgs() const override;
-  void OnDialogShown(content::WebUI* webui,
-                     content::RenderViewHost* render_view_host) override;
+  void OnDialogShown(content::WebUI* webui) override;
   void OnDialogClosed(const std::string& json_retval) override;
   void OnDialogCloseFromWebUI(const std::string& json_retval) override;
   void OnCloseContents(content::WebContents* source,
diff --git a/ui/web_dialogs/web_dialog_delegate.h b/ui/web_dialogs/web_dialog_delegate.h
index 08a4dd5..9aa90df 100644
--- a/ui/web_dialogs/web_dialog_delegate.h
+++ b/ui/web_dialogs/web_dialog_delegate.h
@@ -19,7 +19,6 @@
 
 namespace content {
 class RenderFrameHost;
-class RenderViewHost;
 class WebContents;
 class WebUI;
 class WebUIMessageHandler;
@@ -88,9 +87,7 @@
 
   // A callback to notify the delegate that a web dialog has been shown.
   // |webui| is the WebUI with which the dialog is associated.
-  // |render_view_host| is the RenderViewHost for the shown dialog.
-  virtual void OnDialogShown(content::WebUI* webui,
-                             content::RenderViewHost* render_view_host) {}
+  virtual void OnDialogShown(content::WebUI* webui) {}
 
   // A callback to notify the delegate that the window is requesting to be
   // closed.  If this returns true, the dialog is closed, otherwise the
diff --git a/ui/web_dialogs/web_dialog_ui.cc b/ui/web_dialogs/web_dialog_ui.cc
index 15f230d..ca118e3 100644
--- a/ui/web_dialogs/web_dialog_ui.cc
+++ b/ui/web_dialogs/web_dialog_ui.cc
@@ -10,7 +10,6 @@
 #include "base/memory/ptr_util.h"
 #include "base/values.h"
 #include "content/public/browser/render_frame_host.h"
-#include "content/public/browser/render_view_host.h"
 #include "content/public/browser/web_contents.h"
 #include "content/public/browser/web_ui.h"
 #include "content/public/browser/web_ui_message_handler.h"
@@ -95,7 +94,7 @@
     web_ui_->AddMessageHandler(base::WrapUnique(handler));
 
   if (delegate)
-    delegate->OnDialogShown(web_ui_, render_frame_host->GetRenderViewHost());
+    delegate->OnDialogShown(web_ui_);
 }
 
 void WebDialogUIBase::OnDialogClosed(const base::ListValue* args) {
diff --git a/weblayer/public/java/org/chromium/weblayer/Browser.java b/weblayer/public/java/org/chromium/weblayer/Browser.java
index deca88bc..5d59a4f 100644
--- a/weblayer/public/java/org/chromium/weblayer/Browser.java
+++ b/weblayer/public/java/org/chromium/weblayer/Browser.java
@@ -162,7 +162,7 @@
      *
      * @param callback The TabListCallback.
      */
-    public void addTabListCallback(@NonNull TabListCallback callback) {
+    public void registerTabListCallback(@NonNull TabListCallback callback) {
         ThreadCheck.ensureOnUiThread();
         mTabListCallbacks.addObserver(callback);
     }
@@ -172,7 +172,7 @@
      *
      * @param callback The TabListCallback.
      */
-    public void removeTabListCallback(@NonNull TabListCallback callback) {
+    public void unregisterTabListCallback(@NonNull TabListCallback callback) {
         ThreadCheck.ensureOnUiThread();
         mTabListCallbacks.removeObserver(callback);
     }
diff --git a/weblayer/public/java/org/chromium/weblayer/BrowsingDataType.java b/weblayer/public/java/org/chromium/weblayer/BrowsingDataType.java
index 668ab96..2522c7f 100644
--- a/weblayer/public/java/org/chromium/weblayer/BrowsingDataType.java
+++ b/weblayer/public/java/org/chromium/weblayer/BrowsingDataType.java
@@ -9,6 +9,9 @@
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 
+/**
+ * @hide
+ */
 @IntDef({BrowsingDataType.COOKIES_AND_SITE_DATA, BrowsingDataType.CACHE})
 @Retention(RetentionPolicy.SOURCE)
 public @interface BrowsingDataType {
diff --git a/weblayer/public/java/org/chromium/weblayer/DownloadCallback.java b/weblayer/public/java/org/chromium/weblayer/DownloadCallback.java
index 79cc7a55..37d8b8e 100644
--- a/weblayer/public/java/org/chromium/weblayer/DownloadCallback.java
+++ b/weblayer/public/java/org/chromium/weblayer/DownloadCallback.java
@@ -19,6 +19,6 @@
      * @param mimetype the mimetype of the content reported by the server
      * @param contentLength the file size reported by the server
      */
-    public abstract void downloadRequested(@NonNull String url, @NonNull String userAgent,
+    public abstract void onDownloadRequested(@NonNull String url, @NonNull String userAgent,
             @NonNull String contentDisposition, @NonNull String mimetype, long contentLength);
 }
diff --git a/weblayer/public/java/org/chromium/weblayer/FullscreenCallback.java b/weblayer/public/java/org/chromium/weblayer/FullscreenCallback.java
index 2ae2bc8..e66c989f 100644
--- a/weblayer/public/java/org/chromium/weblayer/FullscreenCallback.java
+++ b/weblayer/public/java/org/chromium/weblayer/FullscreenCallback.java
@@ -19,10 +19,10 @@
      *
      * NOTE: the Runnable must not be used synchronously.
      */
-    public abstract void enterFullscreen(@NonNull Runnable exitFullscreenRunner);
+    public abstract void onEnterFullscreen(@NonNull Runnable exitFullscreenRunner);
 
     /**
      * The page has exited fullscreen mode and the system should be moved out of fullscreen mode.
      */
-    public abstract void exitFullscreen();
+    public abstract void onExitFullscreen();
 }
diff --git a/weblayer/public/java/org/chromium/weblayer/NavigationCallback.java b/weblayer/public/java/org/chromium/weblayer/NavigationCallback.java
index 543df4c5..d996b19 100644
--- a/weblayer/public/java/org/chromium/weblayer/NavigationCallback.java
+++ b/weblayer/public/java/org/chromium/weblayer/NavigationCallback.java
@@ -39,14 +39,14 @@
      *
      * @param navigation the unique object for this navigation.
      */
-    public void navigationStarted(@NonNull Navigation navigation) {}
+    public void onNavigationStarted(@NonNull Navigation navigation) {}
 
     /**
      * Called when a navigation encountered a server redirect.
      *
      * @param navigation the unique object for this navigation.
      */
-    public void navigationRedirected(@NonNull Navigation navigation) {}
+    public void onNavigationRedirected(@NonNull Navigation navigation) {}
 
     /**
      * Called when the navigation is ready to be committed in a renderer. This occurs when the
@@ -61,7 +61,7 @@
      *
      * @param navigation the unique object for this navigation.
      */
-    public void readyToCommitNavigation(@NonNull Navigation navigation) {}
+    public void onReadyToCommitNavigation(@NonNull Navigation navigation) {}
 
     /**
      * Called when a navigation completes successfully in the Tab.
@@ -79,7 +79,7 @@
      *
      * @param navigation the unique object for this navigation.
      */
-    public void navigationCompleted(@NonNull Navigation navigation) {}
+    public void onNavigationCompleted(@NonNull Navigation navigation) {}
 
     /**
      * Called when a navigation aborts in the Tab.
@@ -89,7 +89,7 @@
      *
      * @param navigation the unique object for this navigation.
      */
-    public void navigationFailed(@NonNull Navigation navigation) {}
+    public void onNavigationFailed(@NonNull Navigation navigation) {}
 
     /**
      * The load state of the document has changed.
@@ -98,14 +98,14 @@
      * @param toDifferentDocument True if the main frame is loading a different document. Only valid
      *        when |isLoading| is true.
      */
-    public void loadStateChanged(boolean isLoading, boolean toDifferentDocument) {}
+    public void onLoadStateChanged(boolean isLoading, boolean toDifferentDocument) {}
 
     /**
      * The progress of loading the main frame in the document has changed.
      *
      * @param progress A value in the range of 0.0-1.0.
      */
-    public void loadProgressChanged(double progress) {}
+    public void onLoadProgressChanged(double progress) {}
 
     /**
      * This is fired after each navigation has completed to indicate that the first paint after a
diff --git a/weblayer/public/java/org/chromium/weblayer/NavigationController.java b/weblayer/public/java/org/chromium/weblayer/NavigationController.java
index 9273ee8..2879e86 100644
--- a/weblayer/public/java/org/chromium/weblayer/NavigationController.java
+++ b/weblayer/public/java/org/chromium/weblayer/NavigationController.java
@@ -148,49 +148,49 @@
         @Override
         public void navigationStarted(IClientNavigation navigation) {
             for (NavigationCallback callback : mCallbacks) {
-                callback.navigationStarted((Navigation) navigation);
+                callback.onNavigationStarted((Navigation) navigation);
             }
         }
 
         @Override
         public void navigationRedirected(IClientNavigation navigation) {
             for (NavigationCallback callback : mCallbacks) {
-                callback.navigationRedirected((Navigation) navigation);
+                callback.onNavigationRedirected((Navigation) navigation);
             }
         }
 
         @Override
         public void readyToCommitNavigation(IClientNavigation navigation) {
             for (NavigationCallback callback : mCallbacks) {
-                callback.readyToCommitNavigation((Navigation) navigation);
+                callback.onReadyToCommitNavigation((Navigation) navigation);
             }
         }
 
         @Override
         public void navigationCompleted(IClientNavigation navigation) {
             for (NavigationCallback callback : mCallbacks) {
-                callback.navigationCompleted((Navigation) navigation);
+                callback.onNavigationCompleted((Navigation) navigation);
             }
         }
 
         @Override
         public void navigationFailed(IClientNavigation navigation) {
             for (NavigationCallback callback : mCallbacks) {
-                callback.navigationFailed((Navigation) navigation);
+                callback.onNavigationFailed((Navigation) navigation);
             }
         }
 
         @Override
         public void loadStateChanged(boolean isLoading, boolean toDifferentDocument) {
             for (NavigationCallback callback : mCallbacks) {
-                callback.loadStateChanged(isLoading, toDifferentDocument);
+                callback.onLoadStateChanged(isLoading, toDifferentDocument);
             }
         }
 
         @Override
         public void loadProgressChanged(double progress) {
             for (NavigationCallback callback : mCallbacks) {
-                callback.loadProgressChanged(progress);
+                callback.onLoadProgressChanged(progress);
             }
         }
 
diff --git a/weblayer/public/java/org/chromium/weblayer/NewTabType.java b/weblayer/public/java/org/chromium/weblayer/NewTabType.java
index 37aa62dd..9a87d28 100644
--- a/weblayer/public/java/org/chromium/weblayer/NewTabType.java
+++ b/weblayer/public/java/org/chromium/weblayer/NewTabType.java
@@ -9,6 +9,9 @@
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 
+/**
+ * @hide
+ */
 @IntDef({NewTabType.FOREGROUND_TAB, NewTabType.BACKGROUND_TAB, NewTabType.NEW_POPUP,
         NewTabType.NEW_WINDOW})
 @Retention(RetentionPolicy.SOURCE)
diff --git a/weblayer/public/java/org/chromium/weblayer/Tab.java b/weblayer/public/java/org/chromium/weblayer/Tab.java
index 60b6055..f9f5a0c 100644
--- a/weblayer/public/java/org/chromium/weblayer/Tab.java
+++ b/weblayer/public/java/org/chromium/weblayer/Tab.java
@@ -93,6 +93,7 @@
         mBrowser = browser;
     }
 
+    @NonNull
     public Browser getBrowser() {
         ThreadCheck.ensureOnUiThread();
         return mBrowser;
@@ -128,6 +129,7 @@
         }
     }
 
+    @Nullable
     public DownloadCallback getDownloadCallback() {
         ThreadCheck.ensureOnUiThread();
         return mDownloadCallbackClient != null ? mDownloadCallbackClient.getCallback() : null;
@@ -207,7 +209,7 @@
         public void visibleUrlChanged(String url) {
             Uri uri = Uri.parse(url);
             for (TabCallback callback : mCallbacks) {
-                callback.visibleUrlChanged(uri);
+                callback.onVisibleUrlChanged(uri);
             }
         }
 
@@ -238,7 +240,7 @@
         @Override
         public void downloadRequested(String url, String userAgent, String contentDisposition,
                 String mimetype, long contentLength) {
-            mCallback.downloadRequested(
+            mCallback.onDownloadRequested(
                     url, userAgent, contentDisposition, mimetype, contentLength);
         }
     }
@@ -258,12 +260,12 @@
         public void enterFullscreen(IObjectWrapper exitFullscreenWrapper) {
             ValueCallback<Void> exitFullscreenCallback = (ValueCallback<Void>) ObjectWrapper.unwrap(
                     exitFullscreenWrapper, ValueCallback.class);
-            mCallback.enterFullscreen(() -> exitFullscreenCallback.onReceiveValue(null));
+            mCallback.onEnterFullscreen(() -> exitFullscreenCallback.onReceiveValue(null));
         }
 
         @Override
         public void exitFullscreen() {
-            mCallback.exitFullscreen();
+            mCallback.onExitFullscreen();
         }
     }
 }
diff --git a/weblayer/public/java/org/chromium/weblayer/TabCallback.java b/weblayer/public/java/org/chromium/weblayer/TabCallback.java
index 7d139ce..045b9e3 100644
--- a/weblayer/public/java/org/chromium/weblayer/TabCallback.java
+++ b/weblayer/public/java/org/chromium/weblayer/TabCallback.java
@@ -17,5 +17,5 @@
      *
      * @param url The new user-visible url.
      */
-    public void visibleUrlChanged(@NonNull Uri url) {}
+    public void onVisibleUrlChanged(@NonNull Uri url) {}
 }
diff --git a/weblayer/public/java/org/chromium/weblayer/WebLayer.java b/weblayer/public/java/org/chromium/weblayer/WebLayer.java
index 84f60d2ad..ff289db0 100644
--- a/weblayer/public/java/org/chromium/weblayer/WebLayer.java
+++ b/weblayer/public/java/org/chromium/weblayer/WebLayer.java
@@ -81,7 +81,7 @@
      * completes
      */
     @NonNull
-    public static ListenableFuture<WebLayer> create(Context appContext)
+    public static ListenableFuture<WebLayer> create(@NonNull Context appContext)
             throws UnsupportedVersionException {
         ThreadCheck.ensureOnUiThread();
         if (sFuture == null) {
diff --git a/weblayer/shell/android/browsertests_apk/src/org/chromium/weblayer_browsertests_apk/WebLayerBrowserTestsActivity.java b/weblayer/shell/android/browsertests_apk/src/org/chromium/weblayer_browsertests_apk/WebLayerBrowserTestsActivity.java
index c844ebb..062ba3c 100644
--- a/weblayer/shell/android/browsertests_apk/src/org/chromium/weblayer_browsertests_apk/WebLayerBrowserTestsActivity.java
+++ b/weblayer/shell/android/browsertests_apk/src/org/chromium/weblayer_browsertests_apk/WebLayerBrowserTestsActivity.java
@@ -90,7 +90,7 @@
         mTab = mBrowser.getActiveTab();
         mTab.registerTabCallback(new TabCallback() {
             @Override
-            public void visibleUrlChanged(Uri uri) {
+            public void onVisibleUrlChanged(Uri uri) {
                 mUrlView.setText(uri.toString());
             }
         });
diff --git a/weblayer/shell/android/javatests/src/org/chromium/weblayer/test/BrowserFragmentLifecycleTest.java b/weblayer/shell/android/javatests/src/org/chromium/weblayer/test/BrowserFragmentLifecycleTest.java
index 7a24248..4a734bfa 100644
--- a/weblayer/shell/android/javatests/src/org/chromium/weblayer/test/BrowserFragmentLifecycleTest.java
+++ b/weblayer/shell/android/javatests/src/org/chromium/weblayer/test/BrowserFragmentLifecycleTest.java
@@ -57,7 +57,7 @@
             NavigationController navigationController = activity.getTab().getNavigationController();
             navigationController.registerNavigationCallback(new NavigationCallback() {
                 @Override
-                public void readyToCommitNavigation(@NonNull Navigation navigation) {
+                public void onReadyToCommitNavigation(@NonNull Navigation navigation) {
                     FragmentManager fm = activity.getSupportFragmentManager();
                     fm.beginTransaction()
                             .remove(fm.getFragments().get(0))
diff --git a/weblayer/shell/android/javatests/src/org/chromium/weblayer/test/DownloadCallbackTest.java b/weblayer/shell/android/javatests/src/org/chromium/weblayer/test/DownloadCallbackTest.java
index 3b8212d..33910bc 100644
--- a/weblayer/shell/android/javatests/src/org/chromium/weblayer/test/DownloadCallbackTest.java
+++ b/weblayer/shell/android/javatests/src/org/chromium/weblayer/test/DownloadCallbackTest.java
@@ -5,7 +5,6 @@
 package org.chromium.weblayer.test;
 
 import android.net.Uri;
-import android.support.test.InstrumentationRegistry;
 import android.support.test.filters.SmallTest;
 import android.util.Pair;
 
@@ -19,7 +18,6 @@
 import org.chromium.content_public.browser.test.util.Criteria;
 import org.chromium.content_public.browser.test.util.CriteriaHelper;
 import org.chromium.content_public.browser.test.util.TestThreadUtils;
-import org.chromium.net.test.EmbeddedTestServer;
 import org.chromium.net.test.util.TestWebServer;
 import org.chromium.weblayer.DownloadCallback;
 import org.chromium.weblayer.shell.InstrumentationActivity;
@@ -47,7 +45,7 @@
         public long mContentLength;
 
         @Override
-        public void downloadRequested(String url, String userAgent, String contentDisposition,
+        public void onDownloadRequested(String url, String userAgent, String contentDisposition,
                 String mimetype, long contentLength) {
             mUrl = url;
             mUserAgent = userAgent;
@@ -117,20 +115,11 @@
     @Test
     @SmallTest
     public void testDownloadByLinkAttribute() {
-        EmbeddedTestServer testServer = new EmbeddedTestServer();
-
-        testServer.initializeNative(InstrumentationRegistry.getInstrumentation().getContext(),
-                EmbeddedTestServer.ServerHTTPSSetting.USE_HTTP);
-        testServer.addDefaultHandlers("weblayer/test/data");
-        Assert.assertTrue(testServer.start(0));
-
-        String pageUrl = testServer.getURL("/download.html");
+        String pageUrl = mActivityTestRule.getTestDataURL("download.html");
         mActivityTestRule.navigateAndWait(pageUrl);
 
         EventUtils.simulateTouchCenterOfView(mActivity.getWindow().getDecorView());
         mCallback.waitForDownload();
-        Assert.assertEquals(testServer.getURL("/lorem_ipsum.txt"), mCallback.mUrl);
-
-        testServer.stopAndDestroyServer();
+        Assert.assertEquals(mActivityTestRule.getTestDataURL("lorem_ipsum.txt"), mCallback.mUrl);
     }
 }
diff --git a/weblayer/shell/android/javatests/src/org/chromium/weblayer/test/FullscreenCallbackTest.java b/weblayer/shell/android/javatests/src/org/chromium/weblayer/test/FullscreenCallbackTest.java
index a74838e70..ba346b9 100644
--- a/weblayer/shell/android/javatests/src/org/chromium/weblayer/test/FullscreenCallbackTest.java
+++ b/weblayer/shell/android/javatests/src/org/chromium/weblayer/test/FullscreenCallbackTest.java
@@ -4,10 +4,8 @@
 
 package org.chromium.weblayer.test;
 
-import android.support.test.InstrumentationRegistry;
 import android.support.test.filters.SmallTest;
 
-import org.junit.After;
 import org.junit.Assert;
 import org.junit.Before;
 import org.junit.Rule;
@@ -18,7 +16,6 @@
 import org.chromium.content_public.browser.test.util.Criteria;
 import org.chromium.content_public.browser.test.util.CriteriaHelper;
 import org.chromium.content_public.browser.test.util.TestThreadUtils;
-import org.chromium.net.test.EmbeddedTestServer;
 import org.chromium.weblayer.FullscreenCallback;
 import org.chromium.weblayer.shell.InstrumentationActivity;
 
@@ -31,7 +28,6 @@
     public InstrumentationActivityTestRule mActivityTestRule =
             new InstrumentationActivityTestRule();
 
-    private EmbeddedTestServer mTestServer;
     private InstrumentationActivity mActivity;
     private Delegate mDelegate;
 
@@ -41,13 +37,13 @@
         public Runnable mExitFullscreenRunnable;
 
         @Override
-        public void enterFullscreen(Runnable exitFullscreenRunner) {
+        public void onEnterFullscreen(Runnable exitFullscreenRunner) {
             mEnterFullscreenCount++;
             mExitFullscreenRunnable = exitFullscreenRunner;
         }
 
         @Override
-        public void exitFullscreen() {
+        public void onExitFullscreen() {
             mExitFullscreenCount++;
         }
 
@@ -72,13 +68,7 @@
 
     @Before
     public void setUp() {
-        mTestServer = new EmbeddedTestServer();
-        mTestServer.initializeNative(InstrumentationRegistry.getInstrumentation().getContext(),
-                EmbeddedTestServer.ServerHTTPSSetting.USE_HTTP);
-        mTestServer.addDefaultHandlers("weblayer/test/data");
-        Assert.assertTrue(mTestServer.start(0));
-
-        String url = mTestServer.getURL("/fullscreen.html");
+        String url = mActivityTestRule.getTestDataURL("fullscreen.html");
         mActivity = mActivityTestRule.launchShellWithUrl(url);
         Assert.assertNotNull(mActivity);
         mDelegate = new Delegate();
@@ -91,11 +81,6 @@
         Assert.assertEquals(1, mDelegate.mEnterFullscreenCount);
     }
 
-    @After
-    public void tearDown() {
-        mTestServer.stopAndDestroyServer();
-    }
-
     @Test
     @SmallTest
     public void testFullscreen() {
diff --git a/weblayer/shell/android/javatests/src/org/chromium/weblayer/test/InputTypesTest.java b/weblayer/shell/android/javatests/src/org/chromium/weblayer/test/InputTypesTest.java
index 0a1a6cc..63587e9 100644
--- a/weblayer/shell/android/javatests/src/org/chromium/weblayer/test/InputTypesTest.java
+++ b/weblayer/shell/android/javatests/src/org/chromium/weblayer/test/InputTypesTest.java
@@ -16,7 +16,6 @@
 import android.os.Handler;
 import android.os.Parcelable;
 import android.provider.MediaStore;
-import android.support.test.InstrumentationRegistry;
 import android.support.test.filters.SmallTest;
 import android.support.v4.app.ActivityCompat;
 import android.support.v4.app.Fragment;
@@ -34,7 +33,6 @@
 import org.chromium.base.test.util.MinAndroidSdkLevel;
 import org.chromium.content_public.browser.test.util.CriteriaHelper;
 import org.chromium.content_public.browser.test.util.TestThreadUtils;
-import org.chromium.net.test.EmbeddedTestServer;
 import org.chromium.weblayer.shell.InstrumentationActivity;
 
 import java.io.File;
@@ -49,7 +47,6 @@
     public InstrumentationActivityTestRule mActivityTestRule =
             new InstrumentationActivityTestRule();
 
-    private EmbeddedTestServer mTestServer;
     private File mTempFile;
     private int mCameraPermission = PackageManager.PERMISSION_GRANTED;
 
@@ -127,12 +124,6 @@
 
     @Before
     public void setUp() throws Exception {
-        mTestServer = new EmbeddedTestServer();
-        mTestServer.initializeNative(InstrumentationRegistry.getInstrumentation().getContext(),
-                EmbeddedTestServer.ServerHTTPSSetting.USE_HTTP);
-        mTestServer.addDefaultHandlers("weblayer/test/data");
-        Assert.assertTrue(mTestServer.start(0));
-
         InstrumentationActivity activity = mActivityTestRule.launchShell(new Bundle());
         TestThreadUtils.runOnUiThreadBlocking(() -> {
             activity.createWebLayer(
@@ -148,7 +139,7 @@
                             null)
                     .get();
         });
-        mActivityTestRule.navigateAndWait(mTestServer.getURL("/input_types.html"));
+        mActivityTestRule.navigateAndWait(mActivityTestRule.getTestDataURL("input_types.html"));
         mTempFile = File.createTempFile("file", null);
         activity.setIntentInterceptor(mIntentInterceptor);
         ActivityCompat.setPermissionCompatDelegate(mPermissionCompatDelegate);
diff --git a/weblayer/shell/android/javatests/src/org/chromium/weblayer/test/InstrumentationActivityTestRule.java b/weblayer/shell/android/javatests/src/org/chromium/weblayer/test/InstrumentationActivityTestRule.java
index 0a796b53..83d3377 100644
--- a/weblayer/shell/android/javatests/src/org/chromium/weblayer/test/InstrumentationActivityTestRule.java
+++ b/weblayer/shell/android/javatests/src/org/chromium/weblayer/test/InstrumentationActivityTestRule.java
@@ -16,10 +16,15 @@
 import org.json.JSONException;
 import org.json.JSONObject;
 import org.junit.Assert;
+import org.junit.Rule;
+import org.junit.runner.Description;
+import org.junit.runners.model.Statement;
 
 import org.chromium.base.test.util.CallbackHelper;
 import org.chromium.content_public.browser.test.util.CriteriaHelper;
 import org.chromium.content_public.browser.test.util.TestThreadUtils;
+import org.chromium.net.test.EmbeddedTestServer;
+import org.chromium.net.test.EmbeddedTestServerRule;
 import org.chromium.weblayer.Navigation;
 import org.chromium.weblayer.NavigationCallback;
 import org.chromium.weblayer.Tab;
@@ -36,6 +41,9 @@
  * Test can use this ActivityTestRule to launch or get InstrumentationActivity.
  */
 public class InstrumentationActivityTestRule extends ActivityTestRule<InstrumentationActivity> {
+    @Rule
+    private EmbeddedTestServerRule mTestServerRule = new EmbeddedTestServerRule();
+
     private static final class NavigationWaiter {
         private String mUrl;
         private Tab mTab;
@@ -46,7 +54,7 @@
 
         private NavigationCallback mNavigationCallback = new NavigationCallback() {
             @Override
-            public void navigationCompleted(Navigation navigation) {
+            public void onNavigationCompleted(Navigation navigation) {
                 if (navigation.getUri().toString().equals(mUrl)) {
                     mNavigationComplete = true;
                     checkComplete();
@@ -54,7 +62,7 @@
             }
 
             @Override
-            public void loadStateChanged(boolean isLoading, boolean toDifferentDocument) {
+            public void onLoadStateChanged(boolean isLoading, boolean toDifferentDocument) {
                 mDoneLoading = !isLoading;
                 checkComplete();
             }
@@ -114,6 +122,11 @@
         super(InstrumentationActivity.class, false, false);
     }
 
+    @Override
+    public Statement apply(final Statement base, Description description) {
+        return super.apply(mTestServerRule.apply(base, description), description);
+    }
+
     public WebLayer getWebLayer() {
         return TestThreadUtils.runOnUiThreadBlockingNoException(() -> {
             return WebLayer
@@ -249,4 +262,12 @@
         String url = "data:text,foo";
         return launchShellWithUrl(url, extras);
     }
+
+    public EmbeddedTestServer getTestServer() {
+        return mTestServerRule.getServer();
+    }
+
+    public String getTestDataURL(String path) {
+        return getTestServer().getURL("/weblayer/test/data/" + path);
+    }
 }
diff --git a/weblayer/shell/android/javatests/src/org/chromium/weblayer/test/NavigationTest.java b/weblayer/shell/android/javatests/src/org/chromium/weblayer/test/NavigationTest.java
index 64c0ac80..622c1e6 100644
--- a/weblayer/shell/android/javatests/src/org/chromium/weblayer/test/NavigationTest.java
+++ b/weblayer/shell/android/javatests/src/org/chromium/weblayer/test/NavigationTest.java
@@ -110,17 +110,17 @@
         public CallbackHelper onFirstContentfulPaintCallback = new CallbackHelper();
 
         @Override
-        public void navigationStarted(Navigation navigation) {
+        public void onNavigationStarted(Navigation navigation) {
             onStartedCallback.notifyCalled(navigation.getUri());
         }
 
         @Override
-        public void readyToCommitNavigation(Navigation navigation) {
+        public void onReadyToCommitNavigation(Navigation navigation) {
             onReadyToCommitCallback.notifyCalled(navigation.getUri());
         }
 
         @Override
-        public void navigationCompleted(Navigation navigation) {
+        public void onNavigationCompleted(Navigation navigation) {
             onCompletedCallback.notifyCalled(navigation.getUri(), navigation.isSameDocument());
         }
 
@@ -130,13 +130,13 @@
         }
 
         @Override
-        public void loadStateChanged(boolean isLoading, boolean toDifferentDocument) {
+        public void onLoadStateChanged(boolean isLoading, boolean toDifferentDocument) {
             loadStateChangedCallback.recordValue(
                     Boolean.toString(isLoading) + " " + Boolean.toString(toDifferentDocument));
         }
 
         @Override
-        public void loadProgressChanged(double progress) {
+        public void onLoadProgressChanged(double progress) {
             loadProgressChangedCallback.recordValue(
                     progress == 1 ? "load complete" : "load started");
         }
diff --git a/weblayer/shell/android/javatests/src/org/chromium/weblayer/test/NewTabCallbackTest.java b/weblayer/shell/android/javatests/src/org/chromium/weblayer/test/NewTabCallbackTest.java
index 76fdeb8..ad9085b6 100644
--- a/weblayer/shell/android/javatests/src/org/chromium/weblayer/test/NewTabCallbackTest.java
+++ b/weblayer/shell/android/javatests/src/org/chromium/weblayer/test/NewTabCallbackTest.java
@@ -4,19 +4,15 @@
 
 package org.chromium.weblayer.test;
 
-import android.support.test.InstrumentationRegistry;
 import android.support.test.filters.SmallTest;
 
-import org.junit.After;
 import org.junit.Assert;
-import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
 import org.chromium.base.test.BaseJUnit4ClassRunner;
 import org.chromium.content_public.browser.test.util.TestThreadUtils;
-import org.chromium.net.test.EmbeddedTestServer;
 import org.chromium.weblayer.Tab;
 import org.chromium.weblayer.shell.InstrumentationActivity;
 
@@ -29,27 +25,12 @@
     public InstrumentationActivityTestRule mActivityTestRule =
             new InstrumentationActivityTestRule();
 
-    private EmbeddedTestServer mTestServer;
     private InstrumentationActivity mActivity;
 
-    @Before
-    public void setUp() {
-        mTestServer = new EmbeddedTestServer();
-        mTestServer.initializeNative(InstrumentationRegistry.getInstrumentation().getContext(),
-                EmbeddedTestServer.ServerHTTPSSetting.USE_HTTP);
-        mTestServer.addDefaultHandlers("weblayer/test/data");
-        Assert.assertTrue(mTestServer.start(0));
-    }
-
-    @After
-    public void tearDown() {
-        mTestServer.stopAndDestroyServer();
-    }
-
     @Test
     @SmallTest
     public void testNewBrowser() {
-        String url = mTestServer.getURL("/new_browser.html");
+        String url = mActivityTestRule.getTestDataURL("new_browser.html");
         mActivity = mActivityTestRule.launchShellWithUrl(url);
         Assert.assertNotNull(mActivity);
         NewTabCallbackImpl callback = new NewTabCallbackImpl();
diff --git a/weblayer/shell/android/javatests/src/org/chromium/weblayer/test/TabCallbackTest.java b/weblayer/shell/android/javatests/src/org/chromium/weblayer/test/TabCallbackTest.java
index 7358a992..411e266d 100644
--- a/weblayer/shell/android/javatests/src/org/chromium/weblayer/test/TabCallbackTest.java
+++ b/weblayer/shell/android/javatests/src/org/chromium/weblayer/test/TabCallbackTest.java
@@ -60,7 +60,7 @@
         public TabCallbackValueRecorder visibleUrlChangedCallback = new TabCallbackValueRecorder();
 
         @Override
-        public void visibleUrlChanged(Uri url) {
+        public void onVisibleUrlChanged(Uri url) {
             visibleUrlChangedCallback.recordValue(url.toString());
         }
     }
diff --git a/weblayer/shell/android/javatests/src/org/chromium/weblayer/test/TabListCallbackTest.java b/weblayer/shell/android/javatests/src/org/chromium/weblayer/test/TabListCallbackTest.java
index 7355230b..a38fbf66 100644
--- a/weblayer/shell/android/javatests/src/org/chromium/weblayer/test/TabListCallbackTest.java
+++ b/weblayer/shell/android/javatests/src/org/chromium/weblayer/test/TabListCallbackTest.java
@@ -5,10 +5,8 @@
 package org.chromium.weblayer.test;
 
 import android.os.Bundle;
-import android.support.test.InstrumentationRegistry;
 import android.support.test.filters.SmallTest;
 
-import org.junit.After;
 import org.junit.Assert;
 import org.junit.Before;
 import org.junit.Rule;
@@ -17,7 +15,6 @@
 
 import org.chromium.base.test.BaseJUnit4ClassRunner;
 import org.chromium.content_public.browser.test.util.TestThreadUtils;
-import org.chromium.net.test.EmbeddedTestServer;
 import org.chromium.weblayer.Browser;
 import org.chromium.weblayer.Tab;
 import org.chromium.weblayer.TabListCallback;
@@ -36,7 +33,6 @@
     public InstrumentationActivityTestRule mActivityTestRule =
             new InstrumentationActivityTestRule();
 
-    private EmbeddedTestServer mTestServer;
     private InstrumentationActivity mActivity;
     private Tab mFirstTab;
     private Tab mSecondTab;
@@ -75,13 +71,7 @@
 
     @Before
     public void setUp() {
-        mTestServer = new EmbeddedTestServer();
-        mTestServer.initializeNative(InstrumentationRegistry.getInstrumentation().getContext(),
-                EmbeddedTestServer.ServerHTTPSSetting.USE_HTTP);
-        mTestServer.addDefaultHandlers("weblayer/test/data");
-        Assert.assertTrue(mTestServer.start(0));
-
-        String url = mTestServer.getURL("/new_browser.html");
+        String url = mActivityTestRule.getTestDataURL("new_browser.html");
         mActivity = mActivityTestRule.launchShellWithUrl(url);
         Assert.assertNotNull(mActivity);
         NewTabCallbackImpl callback = new NewTabCallbackImpl();
@@ -100,17 +90,12 @@
         });
     }
 
-    @After
-    public void tearDown() {
-        mTestServer.stopAndDestroyServer();
-    }
-
     @Test
     @SmallTest
     public void testActiveTabChanged() {
         TestThreadUtils.runOnUiThreadBlocking(() -> {
             TabListCallbackImpl callback = new TabListCallbackImpl();
-            mActivity.getBrowser().addTabListCallback(callback);
+            mActivity.getBrowser().registerTabListCallback(callback);
             mActivity.getBrowser().setActiveTab(mFirstTab);
             Assert.assertTrue(callback.getObservedValues().contains(TabListCallbackImpl.ACTIVE));
         });
@@ -124,10 +109,10 @@
                     Browser.fromFragment(mActivity.createBrowserFragment(0, new Bundle()));
             Browser browser1 = mActivity.getBrowser();
             TabListCallbackImpl callback1 = new TabListCallbackImpl();
-            browser1.addTabListCallback(callback1);
+            browser1.registerTabListCallback(callback1);
 
             TabListCallbackImpl callback2 = new TabListCallbackImpl();
-            browser2.addTabListCallback(callback2);
+            browser2.registerTabListCallback(callback2);
 
             // Move the active tab from browser1 to browser2.
             Tab tabToMove = browser1.getActiveTab();
@@ -157,7 +142,7 @@
         TestThreadUtils.runOnUiThreadBlocking(() -> {
             TabListCallbackImpl callback = new TabListCallbackImpl();
             Browser browser = mActivity.getBrowser();
-            browser.addTabListCallback(callback);
+            browser.registerTabListCallback(callback);
             browser.destroyTab(mActivity.getBrowser().getActiveTab());
             Assert.assertTrue(callback.getObservedValues().contains(TabListCallbackImpl.ACTIVE));
             Assert.assertEquals(1, browser.getTabs().size());
diff --git a/weblayer/shell/android/shell_apk/src/org/chromium/weblayer/shell/InstrumentationActivity.java b/weblayer/shell/android/shell_apk/src/org/chromium/weblayer/shell/InstrumentationActivity.java
index d427b53..5445c689 100644
--- a/weblayer/shell/android/shell_apk/src/org/chromium/weblayer/shell/InstrumentationActivity.java
+++ b/weblayer/shell/android/shell_apk/src/org/chromium/weblayer/shell/InstrumentationActivity.java
@@ -135,7 +135,7 @@
         mTab = mBrowser.getActiveTab();
         mTab.registerTabCallback(new TabCallback() {
             @Override
-            public void visibleUrlChanged(Uri uri) {
+            public void onVisibleUrlChanged(Uri uri) {
                 mUrlView.setText(uri.toString());
             }
         });
diff --git a/weblayer/shell/android/shell_apk/src/org/chromium/weblayer/shell/WebLayerShellActivity.java b/weblayer/shell/android/shell_apk/src/org/chromium/weblayer/shell/WebLayerShellActivity.java
index 5ba865b..f2a32bb9 100644
--- a/weblayer/shell/android/shell_apk/src/org/chromium/weblayer/shell/WebLayerShellActivity.java
+++ b/weblayer/shell/android/shell_apk/src/org/chromium/weblayer/shell/WebLayerShellActivity.java
@@ -130,7 +130,7 @@
                     private int mSystemVisibilityToRestore;
 
                     @Override
-                    public void enterFullscreen(Runnable exitFullscreenRunnable) {
+                    public void onEnterFullscreen(Runnable exitFullscreenRunnable) {
                         // This comes from Chrome code to avoid an extra resize.
                         final WindowManager.LayoutParams attrs = getWindow().getAttributes();
                         attrs.flags |= WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS;
@@ -150,7 +150,7 @@
                     }
 
                     @Override
-                    public void exitFullscreen() {
+                    public void onExitFullscreen() {
                         View decorView = getWindow().getDecorView();
                         decorView.setSystemUiVisibility(mSystemVisibilityToRestore);
 
@@ -174,26 +174,25 @@
         loadUrl(startupUrl);
         mTab.registerTabCallback(new TabCallback() {
             @Override
-            public void visibleUrlChanged(Uri uri) {
+            public void onVisibleUrlChanged(Uri uri) {
                 mUrlView.setText(uri.toString());
             }
         });
-        mTab.getNavigationController().registerNavigationCallback(
-                new NavigationCallback() {
-                    @Override
-                    public void loadStateChanged(boolean isLoading, boolean toDifferentDocument) {
-                        mLoadProgressBar.setVisibility(
-                                isLoading && toDifferentDocument ? View.VISIBLE : View.INVISIBLE);
-                    }
+        mTab.getNavigationController().registerNavigationCallback(new NavigationCallback() {
+            @Override
+            public void onLoadStateChanged(boolean isLoading, boolean toDifferentDocument) {
+                mLoadProgressBar.setVisibility(
+                        isLoading && toDifferentDocument ? View.VISIBLE : View.INVISIBLE);
+            }
 
-                    @Override
-                    public void loadProgressChanged(double progress) {
-                        mLoadProgressBar.setProgress((int) Math.round(100 * progress));
-                    }
-                });
+            @Override
+            public void onLoadProgressChanged(double progress) {
+                mLoadProgressBar.setProgress((int) Math.round(100 * progress));
+            }
+        });
         mTab.setDownloadCallback(new DownloadCallback() {
             @Override
-            public void downloadRequested(String url, String userAgent, String contentDisposition,
+            public void onDownloadRequested(String url, String userAgent, String contentDisposition,
                     String mimetype, long contentLength) {
                 DownloadManager.Request request = new DownloadManager.Request(Uri.parse(url));
                 request.setNotificationVisibility(