diff --git a/BUILD.gn b/BUILD.gn
index 18b2a49..a36e366 100644
--- a/BUILD.gn
+++ b/BUILD.gn
@@ -464,7 +464,6 @@
         "//media/cast:generate_barcode_video",
         "//media/cast:generate_timecode_audio",
         "//net:crash_cache",
-        "//net:crl_set_dump",
         "//net:dns_fuzz_stub",
         "//net:gdig",
         "//net:get_server_time",
diff --git a/DEPS b/DEPS
index d8fda5d..f7d1ee0d 100644
--- a/DEPS
+++ b/DEPS
@@ -79,7 +79,7 @@
   # 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': 'aefcccb5d84fb0e0cb8161d4021e8fbd724e2d9e',
+  'skia_revision': '835e26526f27a2cb6a408fd556edcaee9a2cf138',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling V8
   # and whatever else without interference from each other.
@@ -91,7 +91,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': '1f46bc12005ae18a5e3f821174eff3188dd4a27c',
+  'angle_revision': '8d986bf24128b2eb05b1e14dfdea42d05225ccd1',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling build tools
   # and whatever else without interference from each other.
@@ -103,7 +103,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling PDFium
   # and whatever else without interference from each other.
-  'pdfium_revision': '451c9b4f5d52079f05d26f91497f91ebafa6cd77',
+  'pdfium_revision': '8df7805e66d3b32513b05554aacd5959a5e5928f',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling openmax_dl
   # and whatever else without interference from each other.
@@ -135,7 +135,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': '6a7c1ed24c1a750c1dc34546e00b7d83f261df72',
+  'catapult_revision': '3994526859f1e56267ce0c669c928968fa53078e',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling libFuzzer
   # and whatever else without interference from each other.
@@ -856,7 +856,7 @@
     Var('chromium_git') + '/external/khronosgroup/webgl.git' + '@' + 'a182a9ad3078aca566d8355eabf2d9f56f70ee82',
 
   'src/third_party/webrtc':
-    Var('webrtc_git') + '/src.git' + '@' + 'f90637887c95bdbec4c35e312056f1eb1708e74b', # commit position 21742
+    Var('webrtc_git') + '/src.git' + '@' + 'fc8d26bd8ad627a4469bbe2ca6e343ae9fe4e537', # commit position 21742
 
   'src/third_party/xdg-utils': {
       'url': Var('chromium_git') + '/chromium/deps/xdg-utils.git' + '@' + 'd80274d5869b17b8c9067a1022e4416ee7ed5e0d',
diff --git a/android_webview/browser/gl_view_renderer_manager.cc b/android_webview/browser/gl_view_renderer_manager.cc
index 204239c..750846a4 100644
--- a/android_webview/browser/gl_view_renderer_manager.cc
+++ b/android_webview/browser/gl_view_renderer_manager.cc
@@ -5,6 +5,7 @@
 #include "android_webview/browser/gl_view_renderer_manager.h"
 
 #include "base/logging.h"
+#include "base/stl_util.h"
 #include "base/threading/platform_thread.h"
 
 namespace android_webview {
@@ -32,8 +33,7 @@
 
 GLViewRendererManager::Key GLViewRendererManager::PushBack(RendererType view) {
   AutoLock auto_lock(lock_);
-  DCHECK(mru_list_.end() ==
-         std::find(mru_list_.begin(), mru_list_.end(), view));
+  DCHECK(!base::ContainsValue(mru_list_, view));
   mru_list_.push_back(view);
   Key back = mru_list_.end();
   back--;
diff --git a/android_webview/browser/surfaces_instance.cc b/android_webview/browser/surfaces_instance.cc
index 15db7d5..2414208 100644
--- a/android_webview/browser/surfaces_instance.cc
+++ b/android_webview/browser/surfaces_instance.cc
@@ -12,6 +12,7 @@
 #include "android_webview/browser/aw_render_thread_context_provider.h"
 #include "android_webview/browser/deferred_gpu_command_service.h"
 #include "android_webview/browser/parent_output_surface.h"
+#include "base/stl_util.h"
 #include "components/viz/common/display/renderer_settings.h"
 #include "components/viz/common/frame_sinks/begin_frame_source.h"
 #include "components/viz/common/quads/solid_color_draw_quad.h"
@@ -118,8 +119,7 @@
                                    const gfx::Size& frame_size,
                                    const viz::SurfaceId& child_id,
                                    float device_scale_factor) {
-  DCHECK(std::find(child_ids_.begin(), child_ids_.end(), child_id) !=
-         child_ids_.end());
+  DCHECK(base::ContainsValue(child_ids_, child_id));
 
   // Create a frame with a single SurfaceDrawQuad referencing the child
   // Surface and transformed using the given transform.
@@ -165,8 +165,7 @@
 }
 
 void SurfacesInstance::AddChildId(const viz::SurfaceId& child_id) {
-  DCHECK(std::find(child_ids_.begin(), child_ids_.end(), child_id) ==
-         child_ids_.end());
+  DCHECK(!base::ContainsValue(child_ids_, child_id));
   child_ids_.push_back(child_id);
   if (root_id_.is_valid())
     SetSolidColorRootFrame();
diff --git a/android_webview/test/shell/src/org/chromium/android_webview/shell/AwShellApplication.java b/android_webview/test/shell/src/org/chromium/android_webview/shell/AwShellApplication.java
index ab0f33e..d31e658 100644
--- a/android_webview/test/shell/src/org/chromium/android_webview/shell/AwShellApplication.java
+++ b/android_webview/test/shell/src/org/chromium/android_webview/shell/AwShellApplication.java
@@ -4,13 +4,14 @@
 
 package org.chromium.android_webview.shell;
 
-import org.chromium.base.BaseChromiumApplication;
+import android.app.Application;
+
 import org.chromium.base.CommandLine;
 
 /**
  * The android_webview shell Application subclass.
  */
-public class AwShellApplication extends BaseChromiumApplication {
+public class AwShellApplication extends Application {
     public void initCommandLine() {
         if (!CommandLine.isInitialized()) {
             CommandLine.initFromFile("/data/local/tmp/android-webview-command-line");
diff --git a/ash/display/display_manager_unittest.cc b/ash/display/display_manager_unittest.cc
index 24660a37..25c97d07 100644
--- a/ash/display/display_manager_unittest.cc
+++ b/ash/display/display_manager_unittest.cc
@@ -1041,7 +1041,7 @@
                                        gfx::Insets(13, 12, 11, 10));
 
   std::vector<display::Display> changed_displays = changed();
-  EXPECT_EQ(1u, changed_displays.size());
+  ASSERT_EQ(1u, changed_displays.size());
   EXPECT_EQ(display_info2.id(), changed_displays[0].id());
   EXPECT_EQ("0,0 500x500", GetDisplayInfoAt(0).bounds_in_native().ToString());
   display::ManagedDisplayInfo updated_display_info2 = GetDisplayInfoAt(1);
@@ -1164,12 +1164,12 @@
 
   reset();
   display_manager()->SetOverscanInsets(display2_id, gfx::Insets(1, 0, 0, 0));
-  EXPECT_EQ(1u, changed().size());
+  ASSERT_EQ(1u, changed().size());
   EXPECT_EQ(display2_id, changed()[0].id());
 
   reset();
   display_manager()->SetOverscanInsets(display2_id, gfx::Insets(0, 0, 0, 0));
-  EXPECT_EQ(1u, changed().size());
+  ASSERT_EQ(1u, changed().size());
   EXPECT_EQ(display2_id, changed()[0].id());
 }
 
@@ -2343,7 +2343,7 @@
       "0,0 300x400",
       display::Screen::GetScreen()->GetPrimaryDisplay().bounds().ToString());
   std::vector<aura::WindowTreeHost*> hosts = test_api.GetHosts();
-  EXPECT_EQ(1U, hosts.size());
+  ASSERT_EQ(1U, hosts.size());
   EXPECT_EQ("400x500", hosts[0]->GetBoundsInPixels().size().ToString());
   EXPECT_EQ("300x400", hosts[0]->window()->bounds().size().ToString());
   EXPECT_TRUE(display_manager()->IsInMirrorMode());
@@ -2691,7 +2691,7 @@
   UpdateDisplay("400x500,1000x800*2");
   display::ManagedDisplayInfo info =
       display_manager()->GetDisplayInfo(screen->GetPrimaryDisplay().id());
-  EXPECT_EQ(2u, info.display_modes().size());
+  ASSERT_EQ(2u, info.display_modes().size());
   EXPECT_EQ("1640x800", info.display_modes()[0].size().ToString());
   EXPECT_EQ(2.0f, info.display_modes()[0].device_scale_factor());
   EXPECT_EQ("1025x500", info.display_modes()[1].size().ToString());
@@ -2710,7 +2710,7 @@
   // 1st display is 2x.
   UpdateDisplay("1200x800*2,1000x1000");
   info = display_manager()->GetDisplayInfo(screen->GetPrimaryDisplay().id());
-  EXPECT_EQ(2u, info.display_modes().size());
+  ASSERT_EQ(2u, info.display_modes().size());
   EXPECT_EQ("2000x800", info.display_modes()[0].size().ToString());
   EXPECT_EQ(2.0f, info.display_modes()[0].device_scale_factor());
   EXPECT_EQ("2500x1000", info.display_modes()[1].size().ToString());
@@ -2730,7 +2730,7 @@
   // 1st display is 2x.
   UpdateDisplay("1200x800*2,1000x1000*2");
   info = display_manager()->GetDisplayInfo(screen->GetPrimaryDisplay().id());
-  EXPECT_EQ(2u, info.display_modes().size());
+  ASSERT_EQ(2u, info.display_modes().size());
   EXPECT_EQ("2000x800", info.display_modes()[0].size().ToString());
   EXPECT_EQ(2.0f, info.display_modes()[0].device_scale_factor());
   EXPECT_EQ("2500x1000", info.display_modes()[1].size().ToString());
@@ -2748,7 +2748,7 @@
   // being 2x.
   UpdateDisplay("1000x800*2,300x800");
   info = display_manager()->GetDisplayInfo(screen->GetPrimaryDisplay().id());
-  EXPECT_EQ(2u, info.display_modes().size());
+  ASSERT_EQ(2u, info.display_modes().size());
   EXPECT_EQ("1300x800", info.display_modes()[0].size().ToString());
   EXPECT_EQ(2.0f, info.display_modes()[0].device_scale_factor());
   EXPECT_EQ("1300x800", info.display_modes()[1].size().ToString());
@@ -2765,7 +2765,7 @@
   // Both displays have the same physical height, with the second display
   // being 2x.
   UpdateDisplay("1000x800,300x800*2");
-  EXPECT_EQ(2u, info.display_modes().size());
+  ASSERT_EQ(2u, info.display_modes().size());
   EXPECT_EQ("1300x800", info.display_modes()[0].size().ToString());
   EXPECT_EQ(2.0f, info.display_modes()[0].device_scale_factor());
   EXPECT_EQ("1300x800", info.display_modes()[1].size().ToString());
@@ -3929,7 +3929,7 @@
 
   const display::DisplayIdList id_list =
       display_manager()->GetMirroringDestinationDisplayIdList();
-  EXPECT_EQ(2U, id_list.size());
+  ASSERT_EQ(2U, id_list.size());
   EXPECT_EQ(11U, id_list[0]);
   EXPECT_EQ(12U, id_list[1]);
 
@@ -3955,7 +3955,7 @@
             display::Screen::GetScreen()->GetPrimaryDisplay().bounds());
 
   std::vector<aura::WindowTreeHost*> host_list = test_api.GetHosts();
-  EXPECT_EQ(2U, host_list.size());
+  ASSERT_EQ(2U, host_list.size());
   EXPECT_EQ(gfx::Size(400, 500), host_list[0]->GetBoundsInPixels().size());
   EXPECT_EQ(gfx::Size(300, 400), host_list[0]->window()->bounds().size());
   EXPECT_EQ(gfx::Size(500, 600), host_list[1]->GetBoundsInPixels().size());
diff --git a/ash/login/ui/login_password_view_test.cc b/ash/login/ui/login_password_view_test.cc
index 0598a06..a743bbd7 100644
--- a/ash/login/ui/login_password_view_test.cc
+++ b/ash/login/ui/login_password_view_test.cc
@@ -105,7 +105,7 @@
   generator.PressKey(ui::KeyboardCode::VKEY_1, 0);
   generator.PressKey(ui::KeyboardCode::VKEY_RETURN, 0);
 
-  EXPECT_TRUE(password_.has_value());
+  ASSERT_TRUE(password_.has_value());
   EXPECT_EQ(base::ASCIIToUTF16("abc1"), *password_);
 }
 
@@ -122,7 +122,7 @@
       test_api.submit_button()->GetBoundsInScreen().CenterPoint());
   generator.ClickLeftButton();
 
-  EXPECT_TRUE(password_.has_value());
+  ASSERT_TRUE(password_.has_value());
   EXPECT_EQ(base::ASCIIToUTF16("abc1"), *password_);
 }
 
@@ -137,7 +137,7 @@
   EXPECT_FALSE(is_password_field_empty_);
   generator.PressKey(ui::KeyboardCode::VKEY_RETURN, 0);
   EXPECT_FALSE(is_password_field_empty_);
-  EXPECT_TRUE(password_.has_value());
+  ASSERT_TRUE(password_.has_value());
   EXPECT_EQ(base::ASCIIToUTF16("a"), *password_);
 
   // Clear password.
@@ -150,7 +150,7 @@
   EXPECT_FALSE(is_password_field_empty_);
   generator.PressKey(ui::KeyboardCode::VKEY_RETURN, 0);
   EXPECT_FALSE(is_password_field_empty_);
-  EXPECT_TRUE(password_.has_value());
+  ASSERT_TRUE(password_.has_value());
   // The submitted password is 'b' instead of "ab".
   EXPECT_EQ(base::ASCIIToUTF16("b"), *password_);
 }
@@ -204,4 +204,5 @@
   // Icon was not tapped.
   EXPECT_FALSE(easy_unlock_icon_tapped_called_);
 }
+
 }  // namespace ash
diff --git a/ash/wm/overview/window_selector.cc b/ash/wm/overview/window_selector.cc
index 63ebdb65..4c9c9a2 100644
--- a/ash/wm/overview/window_selector.cc
+++ b/ash/wm/overview/window_selector.cc
@@ -746,7 +746,8 @@
 
   // Don't restore focus on exit if a window was just activated.
   ResetFocusRestoreWindow(false);
-  selected_item_ = iter->get();
+  if (iter != windows.end())
+    selected_item_ = iter->get();
   CancelSelection();
 }
 
diff --git a/ash/wm/overview/window_selector_unittest.cc b/ash/wm/overview/window_selector_unittest.cc
index 72ff4e6c..b76f5ab 100644
--- a/ash/wm/overview/window_selector_unittest.cc
+++ b/ash/wm/overview/window_selector_unittest.cc
@@ -2304,6 +2304,47 @@
   EXPECT_FALSE(window3->layer()->GetAnimator()->is_animating());
 }
 
+// Tests can handle |gained_active| window is not in the |window_grid| when
+// OnWindowActivated.
+TEST_F(WindowSelectorTest, HandleActiveWindowNotInWindowGrid) {
+  base::CommandLine::ForCurrentProcess()->AppendSwitch(
+      switches::kAshEnableNewOverviewAnimations);
+
+  gfx::Rect bounds(0, 0, 400, 400);
+  std::unique_ptr<aura::Window> window1(CreateWindow(bounds));
+  std::unique_ptr<aura::Window> window2(CreateWindow(bounds));
+  std::unique_ptr<aura::Window> window3(CreateWindow(bounds));
+  wm::ActivateWindow(window3.get());
+  wm::ActivateWindow(window2.get());
+  wm::ActivateWindow(window1.get());
+
+  EXPECT_FALSE(wm::GetWindowState(window1.get())->IsFullscreen());
+  EXPECT_FALSE(wm::GetWindowState(window2.get())->IsFullscreen());
+  EXPECT_FALSE(wm::GetWindowState(window3.get())->IsFullscreen());
+
+  const wm::WMEvent toggle_fullscreen_event(wm::WM_EVENT_TOGGLE_FULLSCREEN);
+  wm::GetWindowState(window2.get())->OnWMEvent(&toggle_fullscreen_event);
+  wm::GetWindowState(window3.get())->OnWMEvent(&toggle_fullscreen_event);
+  EXPECT_FALSE(wm::GetWindowState(window1.get())->IsFullscreen());
+  EXPECT_TRUE(wm::GetWindowState(window2.get())->IsFullscreen());
+  EXPECT_TRUE(wm::GetWindowState(window3.get())->IsFullscreen());
+
+  // Enter overview.
+  ToggleOverview();
+
+  ui::ScopedAnimationDurationScaleMode test_duration_mode(
+      ui::ScopedAnimationDurationScaleMode::NON_ZERO_DURATION);
+  // Create and active a new window should exit overview without error.
+  auto widget =
+      CreateTestWidget(nullptr, kShellWindowId_StatusContainer, bounds);
+  ClickWindow(widget->GetNativeWindow());
+
+  // |window1| and |window2| should animate.
+  EXPECT_TRUE(window1->layer()->GetAnimator()->is_animating());
+  EXPECT_TRUE(window2->layer()->GetAnimator()->is_animating());
+  EXPECT_FALSE(window3->layer()->GetAnimator()->is_animating());
+}
+
 // Verify that the window selector items titlebar and close button change
 // visibility when a item is being dragged.
 TEST_F(WindowSelectorTest, WindowItemTitleCloseVisibilityOnDrag) {
diff --git a/ash/wm/window_manager_unittest.cc b/ash/wm/window_manager_unittest.cc
index e9942c1..2be40f9 100644
--- a/ash/wm/window_manager_unittest.cc
+++ b/ash/wm/window_manager_unittest.cc
@@ -81,6 +81,7 @@
 class WindowManagerTest : public AshTestBase {
  public:
   WindowManagerTest() = default;
+  ~WindowManagerTest() override = default;
 
   void SetUp() override {
     AshTestBase::SetUp();
diff --git a/base/BUILD.gn b/base/BUILD.gn
index 99ee76af..821464b3 100644
--- a/base/BUILD.gn
+++ b/base/BUILD.gn
@@ -2669,7 +2669,6 @@
       "android/java/src/org/chromium/base/ApiCompatibilityUtils.java",
       "android/java/src/org/chromium/base/ApkAssets.java",
       "android/java/src/org/chromium/base/ApplicationStatus.java",
-      "android/java/src/org/chromium/base/BaseChromiumApplication.java",
       "android/java/src/org/chromium/base/BaseSwitches.java",
       "android/java/src/org/chromium/base/BuildInfo.java",
       "android/java/src/org/chromium/base/Callback.java",
diff --git a/base/allocator/partition_allocator/partition_alloc_unittest.cc b/base/allocator/partition_allocator/partition_alloc_unittest.cc
index 05347b7..a419b1e 100644
--- a/base/allocator/partition_allocator/partition_alloc_unittest.cc
+++ b/base/allocator/partition_allocator/partition_alloc_unittest.cc
@@ -21,7 +21,6 @@
 #include <sys/mman.h>
 #include <sys/resource.h>
 #include <sys/time.h>
-
 #endif  // defined(OS_POSIX)
 
 #if !defined(MEMORY_TOOL_REPLACES_ALLOCATOR)
@@ -248,13 +247,34 @@
 }
 
 #if defined(OS_LINUX)
-bool IsPageInCore(void* ptr) {
-  unsigned char ret = 0;
-  EXPECT_EQ(0, mincore(ptr, kSystemPageSize, &ret));
-  return (ret & 1) != 0;
+bool KernelSupportsMadvFree() {
+  int32_t major_version;
+  int32_t minor_version;
+  int32_t bugfix_version;
+  SysInfo::OperatingSystemVersionNumbers(&major_version, &minor_version,
+                                         &bugfix_version);
+  return std::vector<int32_t>{major_version, minor_version, bugfix_version} >=
+         std::vector<int32_t>{4, 5};
 }
 
-#define CHECK_PAGE_IN_CORE(ptr, in_core) EXPECT_EQ(IsPageInCore(ptr), in_core);
+bool CheckPageInCore(void* ptr, bool in_core) {
+  // If the kernel supports MADV_FREE, then pages may still be in core to be
+  // reclaimed by the OS later.  This is a cool optimization that prevents the
+  // kernel from freeing and allocating memory in case the app needs more memory
+  // soon -- it can just reuse the memory already allocated.  Unfortunately,
+  // there's no way to test if a page is in core because it needs to be, or if
+  // it just hasn't been reclaimed yet.
+  static bool kernel_supports_madv_free = KernelSupportsMadvFree();
+  if (kernel_supports_madv_free)
+    return true;
+
+  unsigned char ret = 0;
+  EXPECT_EQ(0, mincore(ptr, kSystemPageSize, &ret));
+  return in_core == (ret & 1);
+}
+
+#define CHECK_PAGE_IN_CORE(ptr, in_core) \
+  EXPECT_TRUE(CheckPageInCore(ptr, in_core))
 #else
 #define CHECK_PAGE_IN_CORE(ptr, in_core) (void)(0)
 #endif  // defined(OS_LINUX)
diff --git a/base/android/java/src/org/chromium/base/BaseChromiumApplication.java b/base/android/java/src/org/chromium/base/BaseChromiumApplication.java
deleted file mode 100644
index 649090b1e..0000000
--- a/base/android/java/src/org/chromium/base/BaseChromiumApplication.java
+++ /dev/null
@@ -1,39 +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.
-
-package org.chromium.base;
-
-import android.app.Application;
-import android.content.Context;
-
-import org.chromium.base.multidex.ChromiumMultiDexInstaller;
-
-/**
- * Basic application functionality that should be shared among all browser applications.
- */
-public class BaseChromiumApplication extends Application {
-    private static final String TAG = "base";
-
-    @Override
-    protected void attachBaseContext(Context base) {
-        super.attachBaseContext(base);
-        assert getBaseContext() != null;
-        checkAppBeingReplaced();
-        if (BuildConfig.isMultidexEnabled()) {
-            ChromiumMultiDexInstaller.install(this);
-        }
-    }
-
-    /** Ensure this application object is not out-of-date. */
-    private void checkAppBeingReplaced() {
-        // During app update the old apk can still be triggered by broadcasts and spin up an
-        // out-of-date application. Kill old applications in this bad state. See
-        // http://crbug.com/658130 for more context and http://b.android.com/56296 for the bug.
-        if (getResources() == null) {
-            Log.e(TAG, "getResources() null, closing app.");
-            System.exit(0);
-        }
-    }
-
-}
diff --git a/base/android/jni_generator/jni_generator.py b/base/android/jni_generator/jni_generator.py
index 0e2b73d..90d0c1c 100755
--- a/base/android/jni_generator/jni_generator.py
+++ b/base/android/jni_generator/jni_generator.py
@@ -600,15 +600,15 @@
 
 # Regex to match a string like "@CalledByNative public void foo(int bar)".
 RE_CALLED_BY_NATIVE = re.compile(
-    '@CalledByNative(?P<Unchecked>(Unchecked)*?)(?:\("(?P<annotation>.*)"\))?'
-    '\s+(?P<prefix>('
-    '(private|protected|public|static|abstract|final|default|synchronized)'
-    '\s*)*)'
-    '(:?\s*@\w+)?'  # Ignore annotations in return types.
-    '\s*(?P<return_type>\S*?)'
-    '\s*(?P<name>\w+)'
-    '\s*\((?P<params>[^\)]*)\)')
-
+    r'@CalledByNative(?P<Unchecked>(?:Unchecked)?)(?:\("(?P<annotation>.*)"\))?'
+    r'(?:\s+@\w+(?:\(.*\))?)*'  # Ignore any other annotations.
+    r'\s+(?P<prefix>('
+    r'(private|protected|public|static|abstract|final|default|synchronized)'
+    r'\s*)*)'
+    r'(?:\s*@\w+)?'  # Ignore annotations in return types.
+    r'\s*(?P<return_type>\S*?)'
+    r'\s*(?P<name>\w+)'
+    r'\s*\((?P<params>[^\)]*)\)')
 
 # Removes empty lines that are indented (i.e. start with 2x spaces).
 def RemoveIndentedEmptyLines(string):
diff --git a/base/android/jni_generator/jni_generator_tests.py b/base/android/jni_generator/jni_generator_tests.py
index 0e9d363..b5d4c37 100755
--- a/base/android/jni_generator/jni_generator_tests.py
+++ b/base/android/jni_generator/jni_generator_tests.py
@@ -393,7 +393,9 @@
     class InnerClass {}
 
     @CalledByNative
-    InnerClass showConfirmInfoBar(int nativeInfoBar,
+    @SomeOtherA
+    @SomeOtherB
+    public InnerClass showConfirmInfoBar(int nativeInfoBar,
             String buttonOk, String buttonCancel, String title, Bitmap icon) {
         InfoBar infobar = new ConfirmInfoBar(nativeInfoBar, mContext,
                                              buttonOk, buttonCancel,
diff --git a/base/android/junit/src/org/chromium/base/ApplicationStatusTest.java b/base/android/junit/src/org/chromium/base/ApplicationStatusTest.java
index 07118bf..eb182953 100644
--- a/base/android/junit/src/org/chromium/base/ApplicationStatusTest.java
+++ b/base/android/junit/src/org/chromium/base/ApplicationStatusTest.java
@@ -27,7 +27,7 @@
 
 /** Unit tests for {@link ApplicationStatus}. */
 @RunWith(BaseRobolectricTestRunner.class)
-@Config(manifest = Config.NONE, application = BaseChromiumApplication.class,
+@Config(manifest = Config.NONE,
         shadows = {ApplicationStatusTest.TrackingShadowActivity.class, ShadowMultiDex.class})
 public class ApplicationStatusTest {
     /** Shadow that tracks calls to onWindowFocusChanged and dispatchKeyEvent. */
diff --git a/base/debug/activity_tracker.cc b/base/debug/activity_tracker.cc
index 99dcdb8..20c56480 100644
--- a/base/debug/activity_tracker.cc
+++ b/base/debug/activity_tracker.cc
@@ -1496,7 +1496,7 @@
     task_runner->PostTask(
         FROM_HERE,
         BindOnce(&GlobalActivityTracker::CleanupAfterProcess, Unretained(this),
-                 pid, now_stamp, exit_code, Passed(&command_line)));
+                 pid, now_stamp, exit_code, std::move(command_line)));
     return;
   }
 
diff --git a/base/files/file_proxy.cc b/base/files/file_proxy.cc
index 26a49e1..9f5d2efb 100644
--- a/base/files/file_proxy.cc
+++ b/base/files/file_proxy.cc
@@ -38,7 +38,7 @@
        proxy_->SetFile(std::move(file_));
      else if (file_.IsValid())
        task_runner_->PostTask(FROM_HERE,
-                              BindOnce(&FileDeleter, Passed(&file_)));
+                              BindOnce(&FileDeleter, std::move(file_)));
    }
 
  protected:
@@ -236,7 +236,7 @@
 
 FileProxy::~FileProxy() {
   if (file_.IsValid())
-    task_runner_->PostTask(FROM_HERE, BindOnce(&FileDeleter, Passed(&file_)));
+    task_runner_->PostTask(FROM_HERE, BindOnce(&FileDeleter, std::move(file_)));
 }
 
 bool FileProxy::CreateOrOpen(const FilePath& file_path,
diff --git a/base/message_loop/message_loop.cc b/base/message_loop/message_loop.cc
index 285028dd..028cf9f 100644
--- a/base/message_loop/message_loop.cc
+++ b/base/message_loop/message_loop.cc
@@ -85,7 +85,7 @@
 }
 
 MessageLoop::MessageLoop(std::unique_ptr<MessagePump> pump)
-    : MessageLoop(TYPE_CUSTOM, BindOnce(&ReturnPump, Passed(&pump))) {
+    : MessageLoop(TYPE_CUSTOM, BindOnce(&ReturnPump, std::move(pump))) {
   BindToCurrentThread();
 }
 
diff --git a/base/process/kill_win.cc b/base/process/kill_win.cc
index d7b6db6..fee61c1e 100644
--- a/base/process/kill_win.cc
+++ b/base/process/kill_win.cc
@@ -144,13 +144,13 @@
   PostDelayedTaskWithTraits(
       FROM_HERE,
       {TaskPriority::BACKGROUND, TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN},
-      Bind(
+      BindOnce(
           [](Process process) {
             if (CheckForProcessExitAndReport(process))
               return;
             process.Terminate(win::kProcessKilledExitCode, false);
           },
-          Passed(&process)),
+          std::move(process)),
       TimeDelta::FromSeconds(2));
 }
 
diff --git a/base/profiler/stack_sampling_profiler.cc b/base/profiler/stack_sampling_profiler.cc
index 7297ec5..5d41b12f 100644
--- a/base/profiler/stack_sampling_profiler.cc
+++ b/base/profiler/stack_sampling_profiler.cc
@@ -397,7 +397,7 @@
 
   task_runner->PostTask(
       FROM_HERE, BindOnce(&SamplingThread::AddCollectionTask, Unretained(this),
-                          Passed(&collection)));
+                          std::move(collection)));
 
   return id;
 }
diff --git a/base/sequenced_task_runner_unittest.cc b/base/sequenced_task_runner_unittest.cc
index 7451e1d7..4dcc7e5a 100644
--- a/base/sequenced_task_runner_unittest.cc
+++ b/base/sequenced_task_runner_unittest.cc
@@ -4,6 +4,8 @@
 
 #include "base/sequenced_task_runner.h"
 
+#include <utility>
+
 #include "base/bind.h"
 #include "base/gtest_prod_util.h"
 #include "base/message_loop/message_loop.h"
@@ -71,7 +73,7 @@
       OnTaskRunnerDeleter(main_runner_));
   EXPECT_FALSE(deleted_on_main_thread);
   foreign_runner_->PostTask(
-      FROM_HERE, BindOnce([](SequenceBoundUniquePtr) {}, Passed(&ptr)));
+      FROM_HERE, BindOnce([](SequenceBoundUniquePtr) {}, std::move(ptr)));
 
   {
     RunLoop run_loop;
diff --git a/base/task/cancelable_task_tracker.cc b/base/task/cancelable_task_tracker.cc
index ee5f703..ddc997e 100644
--- a/base/task/cancelable_task_tracker.cc
+++ b/base/task/cancelable_task_tracker.cc
@@ -122,9 +122,9 @@
 
   // Will always run |untrack_and_delete_flag| on current sequence.
   ScopedClosureRunner* untrack_and_delete_flag_runner =
-      new ScopedClosureRunner(Bind(
+      new ScopedClosureRunner(BindOnce(
           &RunOrPostToTaskRunner, RetainedRef(SequencedTaskRunnerHandle::Get()),
-          Passed(&untrack_and_delete_flag)));
+          std::move(untrack_and_delete_flag)));
 
   *is_canceled_cb =
       Bind(&IsCanceled, flag, Owned(untrack_and_delete_flag_runner));
diff --git a/base/task_scheduler/delayed_task_manager.cc b/base/task_scheduler/delayed_task_manager.cc
index e6f0e498..eec40a8 100644
--- a/base/task_scheduler/delayed_task_manager.cc
+++ b/base/task_scheduler/delayed_task_manager.cc
@@ -86,8 +86,7 @@
   // TODO(fdoray): Use |task->delayed_run_time| on the service thread
   // MessageLoop rather than recomputing it from |delay|.
   service_thread_task_runner_->PostDelayedTask(
-      FROM_HERE,
-      BindOnce(std::move(post_task_now_callback), Passed(std::move(task))),
+      FROM_HERE, BindOnce(std::move(post_task_now_callback), std::move(task)),
       delay);
 }
 
diff --git a/base/test/launcher/test_launcher.cc b/base/test/launcher/test_launcher.cc
index 8175a5c..ccf6bf2 100644
--- a/base/test/launcher/test_launcher.cc
+++ b/base/test/launcher/test_launcher.cc
@@ -641,7 +641,7 @@
       FROM_HERE, {MayBlock(), TaskShutdownBehavior::BLOCK_SHUTDOWN},
       BindOnce(&DoLaunchChildTestProcess, new_command_line, timeout, options,
                redirect_stdio, RetainedRef(ThreadTaskRunnerHandle::Get()),
-               base::Passed(std::move(observer))));
+               std::move(observer)));
 }
 
 void TestLauncher::OnTestFinished(const TestResult& original_result) {
diff --git a/base/threading/sequenced_task_runner_handle_unittest.cc b/base/threading/sequenced_task_runner_handle_unittest.cc
index 544dc10..48394da 100644
--- a/base/threading/sequenced_task_runner_handle_unittest.cc
+++ b/base/threading/sequenced_task_runner_handle_unittest.cc
@@ -5,6 +5,7 @@
 #include "base/threading/sequenced_task_runner_handle.h"
 
 #include <memory>
+#include <utility>
 
 #include "base/bind.h"
 #include "base/callback.h"
@@ -40,7 +41,7 @@
     task_runner->PostTask(
         FROM_HERE,
         base::BindOnce(&SequencedTaskRunnerHandleTest::CheckValidSequence,
-                       base::Passed(&sequence_checker)));
+                       std::move(sequence_checker)));
   }
 
   static void CheckValidSequence(
diff --git a/base/threading/thread_task_runner_handle.cc b/base/threading/thread_task_runner_handle.cc
index 1e27675d..fca38b6 100644
--- a/base/threading/thread_task_runner_handle.cc
+++ b/base/threading/thread_task_runner_handle.cc
@@ -57,9 +57,9 @@
   if (!IsSet()) {
     auto top_level_ttrh = std::make_unique<ThreadTaskRunnerHandle>(
         std::move(overriding_task_runner));
-    return ScopedClosureRunner(base::Bind(
+    return ScopedClosureRunner(base::BindOnce(
         [](std::unique_ptr<ThreadTaskRunnerHandle> ttrh_to_release) {},
-        base::Passed(&top_level_ttrh)));
+        std::move(top_level_ttrh)));
   }
 
   ThreadTaskRunnerHandle* ttrh = thread_task_runner_tls.Pointer()->Get();
@@ -72,7 +72,7 @@
           ? nullptr
           : std::make_unique<RunLoop::ScopedDisallowRunningForTesting>();
 
-  return ScopedClosureRunner(base::Bind(
+  return ScopedClosureRunner(base::BindOnce(
       [](scoped_refptr<SingleThreadTaskRunner> task_runner_to_restore,
          SingleThreadTaskRunner* expected_task_runner_before_restore,
          std::unique_ptr<RunLoop::ScopedDisallowRunningForTesting>
@@ -85,9 +85,9 @@
 
         ttrh->task_runner_.swap(task_runner_to_restore);
       },
-      base::Passed(&overriding_task_runner),
+      std::move(overriding_task_runner),
       base::Unretained(ttrh->task_runner_.get()),
-      base::Passed(&no_running_during_override)));
+      std::move(no_running_during_override)));
 }
 
 ThreadTaskRunnerHandle::ThreadTaskRunnerHandle(
diff --git a/base/threading/thread_unittest.cc b/base/threading/thread_unittest.cc
index d0f732d..2519fd1 100644
--- a/base/threading/thread_unittest.cc
+++ b/base/threading/thread_unittest.cc
@@ -7,6 +7,7 @@
 #include <stddef.h>
 #include <stdint.h>
 
+#include <utility>
 #include <vector>
 
 #include "base/bind.h"
@@ -314,7 +315,7 @@
                        thread_to_stop->Stop();
                        event_to_signal->Signal();
                      },
-                     base::Passed(&a), base::Unretained(&event)));
+                     std::move(a), base::Unretained(&event)));
 
   event.Wait();
 }
diff --git a/base/trace_event/memory_dump_manager.cc b/base/trace_event/memory_dump_manager.cc
index f5b5614..33291032 100644
--- a/base/trace_event/memory_dump_manager.cc
+++ b/base/trace_event/memory_dump_manager.cc
@@ -734,7 +734,7 @@
         pmd_async_state->callback_task_runner;
     callback_task_runner->PostTask(
         FROM_HERE, BindOnce(&MemoryDumpManager::FinishAsyncProcessDump,
-                            Unretained(this), Passed(&pmd_async_state)));
+                            Unretained(this), std::move(pmd_async_state)));
     return;
   }
 
diff --git a/base/trace_event/memory_dump_manager_unittest.cc b/base/trace_event/memory_dump_manager_unittest.cc
index 2ea6899..48546cfce 100644
--- a/base/trace_event/memory_dump_manager_unittest.cc
+++ b/base/trace_event/memory_dump_manager_unittest.cc
@@ -7,6 +7,7 @@
 #include <stdint.h>
 
 #include <memory>
+#include <utility>
 #include <vector>
 
 #include "base/allocator/features.h"
@@ -812,10 +813,9 @@
     TestIOThread thread_for_unregistration(TestIOThread::kAutoStart);
     PostTaskAndWait(
         FROM_HERE, thread_for_unregistration.task_runner().get(),
-        base::BindOnce(
-            &MemoryDumpManager::UnregisterAndDeleteDumpProviderSoon,
-            base::Unretained(MemoryDumpManager::GetInstance()),
-            base::Passed(std::unique_ptr<MemoryDumpProvider>(std::move(mdp)))));
+        base::BindOnce(&MemoryDumpManager::UnregisterAndDeleteDumpProviderSoon,
+                       base::Unretained(MemoryDumpManager::GetInstance()),
+                       std::move(mdp)));
     thread_for_unregistration.Stop();
     return true;
   };
diff --git a/base/trace_event/trace_log.cc b/base/trace_event/trace_log.cc
index 7428b48..0466fff 100644
--- a/base/trace_event/trace_log.cc
+++ b/base/trace_event/trace_log.cc
@@ -948,7 +948,7 @@
         {MayBlock(), TaskPriority::BACKGROUND,
          TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN},
         BindOnce(&TraceLog::ConvertTraceEventsToTraceFormat,
-                 Passed(&previous_logged_events), flush_output_callback,
+                 std::move(previous_logged_events), flush_output_callback,
                  argument_filter_predicate));
     return;
   }
diff --git a/build/android/bytecode/java/org/chromium/bytecode/CustomResourcesClassAdapter.java b/build/android/bytecode/java/org/chromium/bytecode/CustomResourcesClassAdapter.java
index 29e8013..c702496 100644
--- a/build/android/bytecode/java/org/chromium/bytecode/CustomResourcesClassAdapter.java
+++ b/build/android/bytecode/java/org/chromium/bytecode/CustomResourcesClassAdapter.java
@@ -20,7 +20,6 @@
 import static org.objectweb.asm.Opcodes.RETURN;
 
 import static org.chromium.bytecode.TypeUtils.ASSET_MANAGER;
-import static org.chromium.bytecode.TypeUtils.BASE_CHROMIUM_APPLICATION;
 import static org.chromium.bytecode.TypeUtils.BOOLEAN;
 import static org.chromium.bytecode.TypeUtils.BUILD_HOOKS_ANDROID;
 import static org.chromium.bytecode.TypeUtils.CONFIGURATION;
@@ -74,8 +73,7 @@
             TypeUtils.getMethodSignature("setTheme", VOID, INT));
 
     private static final List<String> EXCEPTED_CLASS_METHODS = Arrays.asList(
-            DISPLAY_LEAK_ACTIVITY + TypeUtils.getMethodSignature("setTheme", VOID, INT),
-            BASE_CHROMIUM_APPLICATION + TypeUtils.getMethodSignature("getResources", RESOURCES));
+            DISPLAY_LEAK_ACTIVITY + TypeUtils.getMethodSignature("setTheme", VOID, INT));
 
     private boolean mShouldTransform;
     private String mClassName;
diff --git a/build/android/bytecode/java/org/chromium/bytecode/TypeUtils.java b/build/android/bytecode/java/org/chromium/bytecode/TypeUtils.java
index e297b11..84a020f9 100644
--- a/build/android/bytecode/java/org/chromium/bytecode/TypeUtils.java
+++ b/build/android/bytecode/java/org/chromium/bytecode/TypeUtils.java
@@ -22,7 +22,6 @@
 class TypeUtils {
     static final String ASSERTION_ERROR = "java/lang/AssertionError";
     static final String ASSET_MANAGER = "android/content/res/AssetManager";
-    static final String BASE_CHROMIUM_APPLICATION = "org/chromium/base/BaseChromiumApplication";
     static final String BUILD_HOOKS = "org/chromium/build/BuildHooks";
     static final String BUILD_HOOKS_ANDROID = "org/chromium/build/BuildHooksAndroid";
     static final String CONFIGURATION = "android/content/res/Configuration";
diff --git a/build/android/gyp/finalize_apk.py b/build/android/gyp/finalize_apk.py
index 69407e9..ecb5ebfe 100755
--- a/build/android/gyp/finalize_apk.py
+++ b/build/android/gyp/finalize_apk.py
@@ -3,51 +3,121 @@
 # 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.
-"""Signs and aligns an APK."""
+"""Signs and zipaligns APK.
 
-import argparse
+"""
+
+import optparse
+import os
 import shutil
-import subprocess
+import sys
 import tempfile
+import zipfile
+
+# resource_sizes modifies zipfile for zip64 compatibility. See
+# https://bugs.python.org/issue14315.
+sys.path.append(os.path.join(os.path.dirname(__file__), os.pardir))
+import resource_sizes  # pylint: disable=unused-import
+
+from util import build_utils
 
 
-def main():
-  parser = argparse.ArgumentParser()
+def JarSigner(key_path, key_name, key_passwd, unsigned_path, signed_path):
+  shutil.copy(unsigned_path, signed_path)
+  sign_cmd = [
+      'jarsigner',
+      '-sigalg', 'MD5withRSA',
+      '-digestalg', 'SHA1',
+      '-keystore', key_path,
+      '-storepass', key_passwd,
+      signed_path,
+      key_name,
+    ]
+  build_utils.CheckOutput(sign_cmd)
 
-  parser.add_argument('--apksigner-path', required=True,
-                      help='Path to the apksigner executable.')
-  parser.add_argument('--zipalign-path', required=True,
-                      help='Path to the zipalign executable.')
-  parser.add_argument('--unsigned-apk-path', required=True,
-                      help='Path to input unsigned APK.')
-  parser.add_argument('--final-apk-path', required=True,
-                      help='Path to output signed and aligned APK.')
-  parser.add_argument('--key-path', required=True,
-                      help='Path to keystore for signing.')
-  parser.add_argument('--key-passwd', required=True,
-                      help='Keystore password')
-  parser.add_argument('--key-name', required=True,
-                      help='Keystore name')
-  options = parser.parse_args()
 
-  # Use a tempfile so that Ctrl-C does not leave the file with a fresh mtime
-  # and a corrupted state.
-  with tempfile.NamedTemporaryFile() as staging_file:
-    # v2 signing requires that zipalign happen first.
-    subprocess.check_output([
-        options.zipalign_path, '-p', '-f', '4',
-        options.unsigned_apk_path, staging_file.name])
-    subprocess.check_output([
-        options.apksigner_path, 'sign',
-        '--in', staging_file.name,
-        '--out', staging_file.name,
-        '--ks', options.key_path,
-        '--ks-key-alias', options.key_name,
-        '--ks-pass', 'pass:' + options.key_passwd,
-    ])
-    shutil.move(staging_file.name, options.final_apk_path)
-    staging_file.delete = False
+def AlignApk(zipalign_path, unaligned_path, final_path):
+  # Note -p will page align native libraries (files ending with .so), but
+  # only those that are stored uncompressed.
+  align_cmd = [
+      zipalign_path,
+      '-p',
+      '-f',
+      ]
+
+
+  align_cmd += [
+      '4',  # 4 bytes
+      unaligned_path,
+      final_path,
+      ]
+  build_utils.CheckOutput(align_cmd)
+
+
+def main(args):
+  args = build_utils.ExpandFileArgs(args)
+
+  parser = optparse.OptionParser()
+  build_utils.AddDepfileOption(parser)
+
+  parser.add_option('--zipalign-path', help='Path to the zipalign tool.')
+  parser.add_option('--unsigned-apk-path', help='Path to input unsigned APK.')
+  parser.add_option('--final-apk-path',
+      help='Path to output signed and aligned APK.')
+  parser.add_option('--key-path', help='Path to keystore for signing.')
+  parser.add_option('--key-passwd', help='Keystore password')
+  parser.add_option('--key-name', help='Keystore name')
+
+  options, _ = parser.parse_args()
+
+  input_paths = [
+    options.unsigned_apk_path,
+    options.key_path,
+  ]
+
+  input_strings = [
+    options.key_name,
+    options.key_passwd,
+  ]
+
+  build_utils.CallAndWriteDepfileIfStale(
+      lambda: FinalizeApk(options),
+      options,
+      record_path=options.unsigned_apk_path + '.finalize.md5.stamp',
+      input_paths=input_paths,
+      input_strings=input_strings,
+      output_paths=[options.final_apk_path])
+
+
+def _NormalizeZip(path):
+  with tempfile.NamedTemporaryFile(suffix='.zip') as hermetic_signed_apk:
+    with zipfile.ZipFile(path, 'r') as zi:
+      with zipfile.ZipFile(hermetic_signed_apk, 'w') as zo:
+        for info in zi.infolist():
+          # Ignore 'extended local file headers'. Python doesn't write them
+          # properly (see https://bugs.python.org/issue1742205) which causes
+          # zipalign to miscalculate alignment. Since we don't use them except
+          # for alignment anyway, we write a stripped file here and let
+          # zipalign add them properly later. eLFHs are controlled by 'general
+          # purpose bit flag 03' (0x08) so we mask that out.
+          info.flag_bits = info.flag_bits & 0xF7
+
+          info.date_time = build_utils.HERMETIC_TIMESTAMP
+          zo.writestr(info, zi.read(info.filename))
+
+    shutil.copy(hermetic_signed_apk.name, path)
+
+
+def FinalizeApk(options):
+  with tempfile.NamedTemporaryFile() as signed_apk_path_tmp:
+    signed_apk_path = signed_apk_path_tmp.name
+    JarSigner(options.key_path, options.key_name, options.key_passwd,
+              options.unsigned_apk_path, signed_apk_path)
+    # Make the newly added signing files hermetic.
+    _NormalizeZip(signed_apk_path)
+
+    AlignApk(options.zipalign_path, signed_apk_path, options.final_apk_path)
 
 
 if __name__ == '__main__':
-  main()
+  sys.exit(main(sys.argv[1:]))
diff --git a/build/config/android/config.gni b/build/config/android/config.gni
index cf339a2..e4002393 100644
--- a/build/config/android/config.gni
+++ b/build/config/android/config.gni
@@ -263,6 +263,8 @@
   # Path to the SDK's android.jar
   android_sdk_jar = "$android_sdk/android.jar"
 
+  zipalign_path = "$android_sdk_build_tools/zipalign"
+
   # Subdirectories inside android_ndk_root that contain the sysroot for the
   # associated platform.
   x86_android_sysroot_subdir =
diff --git a/build/config/android/internal_rules.gni b/build/config/android/internal_rules.gni
index 5604f93..e9937a4 100644
--- a/build/config/android/internal_rules.gni
+++ b/build/config/android/internal_rules.gni
@@ -1866,6 +1866,9 @@
   #   keystore_password: Keystore password.
   template("finalize_apk") {
     action(target_name) {
+      deps = []
+      script = "//build/android/gyp/finalize_apk.py"
+      depfile = "$target_gen_dir/$target_name.d"
       forward_variables_from(invoker,
                              [
                                "deps",
@@ -1874,13 +1877,10 @@
                                "testonly",
                              ])
 
-      script = "//build/android/gyp/finalize_apk.py"
-      _apksigner = "$android_sdk_build_tools/apksigner"
-      _zipalign = "$android_sdk_build_tools/zipalign"
-      inputs = [
-        _apksigner,
-        _zipalign,
+      sources = [
         invoker.input_apk_path,
+      ]
+      inputs = [
         invoker.keystore_path,
       ]
       outputs = [
@@ -1891,14 +1891,14 @@
       ]
 
       args = [
+        "--depfile",
+        rebase_path(depfile, root_build_dir),
+        "--zipalign-path",
+        rebase_path(zipalign_path, root_build_dir),
         "--unsigned-apk-path",
         rebase_path(invoker.input_apk_path, root_build_dir),
         "--final-apk-path",
         rebase_path(invoker.output_apk_path, root_build_dir),
-        "--apksigner-path",
-        rebase_path(_apksigner, root_build_dir),
-        "--zipalign-path",
-        rebase_path(_zipalign, root_build_dir),
         "--key-path",
         rebase_path(invoker.keystore_path, root_build_dir),
         "--key-name",
diff --git a/cc/base/switches.cc b/cc/base/switches.cc
index 9e75789..b3688f98 100644
--- a/cc/base/switches.cc
+++ b/cc/base/switches.cc
@@ -53,11 +53,6 @@
 // Enables the GPU benchmarking extension
 const char kEnableGpuBenchmarking[] = "enable-gpu-benchmarking";
 
-// Effectively disables pipelining of compositor frame production stages by
-// waiting for each stage to finish before completing a frame.
-const char kRunAllCompositorStagesBeforeDraw[] =
-    "run-all-compositor-stages-before-draw";
-
 // Always asks the display compositor to send back presentation times.
 const char kAlwaysRequestPresentationTime[] =
     "always-request-presentation-time";
diff --git a/cc/base/switches.h b/cc/base/switches.h
index bf41907..adbea56 100644
--- a/cc/base/switches.h
+++ b/cc/base/switches.h
@@ -31,7 +31,6 @@
 
 // Switches for both the renderer and ui compositors.
 CC_BASE_EXPORT extern const char kEnableGpuBenchmarking[];
-CC_BASE_EXPORT extern const char kRunAllCompositorStagesBeforeDraw[];
 CC_BASE_EXPORT extern const char kAlwaysRequestPresentationTime[];
 
 // Debug visualizations.
diff --git a/cc/ipc/cc_param_traits_macros.h b/cc/ipc/cc_param_traits_macros.h
index c13016c..520c1a1 100644
--- a/cc/ipc/cc_param_traits_macros.h
+++ b/cc/ipc/cc_param_traits_macros.h
@@ -6,7 +6,6 @@
 #define CC_IPC_CC_PARAM_TRAITS_MACROS_H_
 
 #include "cc/paint/filter_operation.h"
-#include "cc/trees/render_frame_metadata.h"
 #include "components/viz/common/frame_sinks/begin_frame_args.h"
 #include "components/viz/common/quads/compositor_frame.h"
 #include "components/viz/common/quads/debug_border_draw_quad.h"
@@ -204,8 +203,4 @@
   IPC_STRUCT_TRAITS_MEMBER(frame_token)
 IPC_STRUCT_TRAITS_END()
 
-IPC_STRUCT_TRAITS_BEGIN(cc::RenderFrameMetadata)
-  IPC_STRUCT_TRAITS_MEMBER(root_scroll_offset)
-IPC_STRUCT_TRAITS_END()
-
 #endif  // CC_IPC_CC_PARAM_TRAITS_MACROS_H_
diff --git a/cc/resources/resource_pool.cc b/cc/resources/resource_pool.cc
index 44a2e1d..acfe2be 100644
--- a/cc/resources/resource_pool.cc
+++ b/cc/resources/resource_pool.cc
@@ -258,7 +258,7 @@
   DCHECK(busy_it != busy_resources_.end());
 
   PoolResource* resource = busy_it->get();
-  if (lost || evict_busy_resources_when_unused_) {
+  if (lost || evict_busy_resources_when_unused_ || resource->avoid_reuse()) {
     DeleteResource(std::move(*busy_it));
     busy_resources_.erase(busy_it);
     return;
@@ -303,6 +303,15 @@
           resource.resource_->unique_id()))));
 }
 
+void ResourcePool::InvalidateResources() {
+  while (!unused_resources_.empty())
+    DeleteResource(PopBack(&unused_resources_));
+  for (auto& pool_resource : busy_resources_)
+    pool_resource->mark_avoid_reuse();
+  for (auto& pair : in_use_resources_)
+    pair.second->mark_avoid_reuse();
+}
+
 void ResourcePool::ReleaseResource(InUsePoolResource in_use_resource) {
   PoolResource* pool_resource = in_use_resource.resource_;
   in_use_resource.SetWasFreedByResourcePool();
@@ -348,20 +357,27 @@
   in_use_memory_usage_bytes_ -= ResourceUtil::UncheckedSizeInBytes<size_t>(
       pool_resource->size(), pool_resource->format());
 
+  // Save the ResourceId since the |pool_resource| can be deleted in the next
+  // step.
+  viz::ResourceId resource_id = pool_resource->resource_id();
+
   // Transfer resource to |unused_resources_| or |busy_resources_|, depending if
   // it was exported to the ResourceProvider via PrepareForExport(). If not,
-  // then we can immediately make the resource available to be reused.
-  if (!pool_resource->resource_id())
-    DidFinishUsingResource(std::move(it->second));
-  else
+  // then we can immediately make the resource available to be reused, unless it
+  // was marked not for reuse.
+  if (resource_id)
     busy_resources_.push_front(std::move(it->second));
+  else if (pool_resource->avoid_reuse())
+    DeleteResource(std::move(it->second));  // This deletes |pool_resource|.
+  else
+    DidFinishUsingResource(std::move(it->second));
   in_use_resources_.erase(it);
 
   // If the resource was exported, then it has a resource id. By removing the
   // resource id, we will be notified in the ReleaseCallback when the resource
   // is no longer exported and can be reused.
-  if (pool_resource->resource_id())
-    resource_provider_->RemoveImportedResource(pool_resource->resource_id());
+  if (resource_id)
+    resource_provider_->RemoveImportedResource(resource_id);
 
   // Now that we have evictable resources, schedule an eviction call for this
   // resource if necessary.
diff --git a/cc/resources/resource_pool.h b/cc/resources/resource_pool.h
index 18ca984..ba37315b 100644
--- a/cc/resources/resource_pool.h
+++ b/cc/resources/resource_pool.h
@@ -184,6 +184,11 @@
   // RasterBufferProvider::AcquireBufferForRaster().
   void PrepareForExport(const InUsePoolResource& resource);
 
+  // Marks any resources in the pool as invalid, preventing their reuse. Call if
+  // previous resources were allocated in one way, but future resources should
+  // be allocated in a different way.
+  void InvalidateResources();
+
   // Called when a resource's content has been fully replaced (and is completely
   // valid). Updates the resource's content ID to its new value.
   void OnContentReplaced(const ResourcePool::InUsePoolResource& in_use_resource,
@@ -259,6 +264,9 @@
       invalidated_rect_ = invalidated_rect;
     }
 
+    bool avoid_reuse() const { return avoid_reuse_; }
+    void mark_avoid_reuse() { avoid_reuse_ = true; }
+
     void OnMemoryDump(base::trace_event::ProcessMemoryDump* pmd,
                       const LayerTreeResourceProvider* resource_provider,
                       bool is_free) const;
@@ -273,6 +281,10 @@
     base::TimeTicks last_usage_;
     gfx::Rect invalidated_rect_;
 
+    // Set to true for resources that should be destroyed instead of returned to
+    // the pool for reuse.
+    bool avoid_reuse_ = false;
+
     // An id used to name the backing for transfer to the display compositor.
     viz::ResourceId resource_id_ = 0;
 
diff --git a/cc/resources/resource_pool_unittest.cc b/cc/resources/resource_pool_unittest.cc
index 92a3e770..6c86025 100644
--- a/cc/resources/resource_pool_unittest.cc
+++ b/cc/resources/resource_pool_unittest.cc
@@ -511,6 +511,78 @@
   EXPECT_EQ(0u, resource_pool_->GetBusyResourceCountForTesting());
 }
 
+TEST_F(ResourcePoolTest, InvalidateResources) {
+  // Limits high enough to not be hit by this test.
+  size_t bytes_limit = 10 * 1024 * 1024;
+  size_t count_limit = 100;
+  resource_pool_->SetResourceUsageLimits(bytes_limit, count_limit);
+
+  gfx::Size size(100, 100);
+  viz::ResourceFormat format = viz::RGBA_8888;
+  gfx::ColorSpace color_space = gfx::ColorSpace::CreateSRGB();
+  ResourcePool::InUsePoolResource busy_resource =
+      resource_pool_->AcquireResource(size, format, color_space);
+  SetBackingOnResource(busy_resource);
+  resource_pool_->PrepareForExport(busy_resource);
+  EXPECT_EQ(1u, resource_pool_->GetTotalResourceCountForTesting());
+  EXPECT_EQ(0u, resource_pool_->GetBusyResourceCountForTesting());
+  EXPECT_EQ(1u, resource_pool_->resource_count());
+
+  // Make a 2nd resource which will be left available in the pool.
+  ResourcePool::InUsePoolResource avail_resource =
+      resource_pool_->AcquireResource(size, format, color_space);
+  EXPECT_EQ(2u, resource_pool_->GetTotalResourceCountForTesting());
+  EXPECT_EQ(0u, resource_pool_->GetBusyResourceCountForTesting());
+  EXPECT_EQ(2u, resource_pool_->resource_count());
+
+  // Make a 3nd resource which will be kept in use.
+  ResourcePool::InUsePoolResource in_use_resource =
+      resource_pool_->AcquireResource(size, format, color_space);
+  EXPECT_EQ(3u, resource_pool_->GetTotalResourceCountForTesting());
+  EXPECT_EQ(0u, resource_pool_->GetBusyResourceCountForTesting());
+  EXPECT_EQ(3u, resource_pool_->resource_count());
+
+  // Mark this one as available.
+  resource_pool_->ReleaseResource(std::move(avail_resource));
+  EXPECT_EQ(3u, resource_pool_->GetTotalResourceCountForTesting());
+  EXPECT_EQ(0u, resource_pool_->GetBusyResourceCountForTesting());
+  EXPECT_EQ(2u, resource_pool_->resource_count());
+
+  // Export the first resource to the display compositor, so it will be busy
+  // once released.
+  std::vector<viz::TransferableResource> transfers;
+  resource_provider_->PrepareSendToParent(
+      {busy_resource.resource_id_for_export()}, &transfers);
+
+  // Release the resource making it busy.
+  resource_pool_->ReleaseResource(std::move(busy_resource));
+  EXPECT_EQ(3u, resource_pool_->GetTotalResourceCountForTesting());
+  EXPECT_EQ(1u, resource_pool_->GetBusyResourceCountForTesting());
+  EXPECT_EQ(1u, resource_pool_->resource_count());
+
+  // Invalidating resources should prevent reuse of any resource.
+  resource_pool_->InvalidateResources();
+
+  // The available resource is just dropped immediately.
+  EXPECT_EQ(2u, resource_pool_->GetTotalResourceCountForTesting());
+  EXPECT_EQ(1u, resource_pool_->GetBusyResourceCountForTesting());
+  EXPECT_EQ(1u, resource_pool_->resource_count());
+
+  // The resource moves from busy to available, but since we invalidated,
+  // it is not kept.
+  resource_provider_->ReceiveReturnsFromParent(
+      viz::TransferableResource::ReturnResources(transfers));
+  EXPECT_EQ(1u, resource_pool_->GetTotalResourceCountForTesting());
+  EXPECT_EQ(0u, resource_pool_->GetBusyResourceCountForTesting());
+  EXPECT_EQ(1u, resource_pool_->resource_count());
+
+  // The last resource was in use, when it is released it will not become able
+  // to be reused.
+  resource_pool_->ReleaseResource(std::move(in_use_resource));
+  EXPECT_EQ(0u, resource_pool_->GetTotalResourceCountForTesting());
+  EXPECT_EQ(0u, resource_pool_->GetBusyResourceCountForTesting());
+}
+
 TEST_F(ResourcePoolTest, ExactRequestsRespected) {
   viz::ResourceFormat format = viz::RGBA_8888;
   gfx::ColorSpace color_space = gfx::ColorSpace::CreateSRGB();
diff --git a/cc/test/layer_tree_pixel_resource_test.cc b/cc/test/layer_tree_pixel_resource_test.cc
index 2f5bf3b..4c96f2c 100644
--- a/cc/test/layer_tree_pixel_resource_test.cc
+++ b/cc/test/layer_tree_pixel_resource_test.cc
@@ -34,10 +34,9 @@
   initialized_ = true;
 }
 
-void LayerTreeHostPixelResourceTest::CreateResourceAndRasterBufferProvider(
-    LayerTreeHostImpl* host_impl,
-    std::unique_ptr<RasterBufferProvider>* raster_buffer_provider,
-    std::unique_ptr<ResourcePool>* resource_pool) {
+std::unique_ptr<RasterBufferProvider>
+LayerTreeHostPixelResourceTest::CreateRasterBufferProvider(
+    LayerTreeHostImpl* host_impl) {
   scoped_refptr<base::SingleThreadTaskRunner> task_runner =
       task_runner_provider()->HasImplThread()
           ? task_runner_provider()->ImplThreadTaskRunner()
@@ -62,56 +61,37 @@
       EXPECT_FALSE(compositor_context_provider);
       EXPECT_EQ(PIXEL_TEST_SOFTWARE, test_type_);
 
-      *raster_buffer_provider = std::make_unique<BitmapRasterBufferProvider>(
+      return std::make_unique<BitmapRasterBufferProvider>(
           resource_provider, shared_bitmap_manager);
-      *resource_pool = std::make_unique<ResourcePool>(
-          resource_provider, std::move(task_runner),
-          ResourcePool::kDefaultExpirationDelay, ResourcePool::Mode::kSoftware,
-          false);
-      break;
     case GPU:
       EXPECT_TRUE(compositor_context_provider);
       EXPECT_TRUE(worker_context_provider);
       EXPECT_EQ(PIXEL_TEST_GL, test_type_);
 
-      *raster_buffer_provider = std::make_unique<GpuRasterBufferProvider>(
+      return std::make_unique<GpuRasterBufferProvider>(
           compositor_context_provider, worker_context_provider,
           resource_provider, false, false, 0,
           viz::PlatformColor::BestTextureFormat(), false);
-      *resource_pool = std::make_unique<ResourcePool>(
-          resource_provider, std::move(task_runner),
-          ResourcePool::kDefaultExpirationDelay, ResourcePool::Mode::kGpu,
-          false);
-      break;
     case ZERO_COPY:
       EXPECT_TRUE(compositor_context_provider);
       EXPECT_TRUE(gpu_memory_buffer_manager);
       EXPECT_EQ(PIXEL_TEST_GL, test_type_);
 
-      *raster_buffer_provider = std::make_unique<ZeroCopyRasterBufferProvider>(
+      return std::make_unique<ZeroCopyRasterBufferProvider>(
           resource_provider, gpu_memory_buffer_manager,
           compositor_context_provider, viz::PlatformColor::BestTextureFormat());
-      *resource_pool = std::make_unique<ResourcePool>(
-          resource_provider, std::move(task_runner),
-          ResourcePool::kDefaultExpirationDelay, ResourcePool::Mode::kGpu,
-          false);
-      break;
     case ONE_COPY:
       EXPECT_TRUE(compositor_context_provider);
       EXPECT_TRUE(worker_context_provider);
       EXPECT_EQ(PIXEL_TEST_GL, test_type_);
 
-      *raster_buffer_provider = std::make_unique<OneCopyRasterBufferProvider>(
+      return std::make_unique<OneCopyRasterBufferProvider>(
           task_runner, compositor_context_provider, worker_context_provider,
           resource_provider, max_bytes_per_copy_operation, false, false,
           max_staging_buffer_usage_in_bytes,
           viz::PlatformColor::BestTextureFormat());
-      *resource_pool = std::make_unique<ResourcePool>(
-          resource_provider, std::move(task_runner),
-          ResourcePool::kDefaultExpirationDelay, ResourcePool::Mode::kGpu,
-          false);
-      break;
   }
+  return {};
 }
 
 void LayerTreeHostPixelResourceTest::RunPixelResourceTest(
diff --git a/cc/test/layer_tree_pixel_resource_test.h b/cc/test/layer_tree_pixel_resource_test.h
index fe6e391f..653a0a17 100644
--- a/cc/test/layer_tree_pixel_resource_test.h
+++ b/cc/test/layer_tree_pixel_resource_test.h
@@ -10,10 +10,6 @@
 
 namespace cc {
 
-class LayerTreeHostImpl;
-class RasterBufferProvider;
-class ResourcePool;
-
 enum PixelResourceTestCase {
   SOFTWARE,
   GPU,
@@ -27,10 +23,8 @@
                                           Layer::LayerMaskType mask_type);
   LayerTreeHostPixelResourceTest();
 
-  void CreateResourceAndRasterBufferProvider(
-      LayerTreeHostImpl* host_impl,
-      std::unique_ptr<RasterBufferProvider>* raster_buffer_provider,
-      std::unique_ptr<ResourcePool>* resource_pool) override;
+  std::unique_ptr<RasterBufferProvider> CreateRasterBufferProvider(
+      LayerTreeHostImpl* host_impl) override;
 
   void RunPixelResourceTest(scoped_refptr<Layer> content_root,
                             base::FilePath file_name);
diff --git a/cc/test/layer_tree_test.cc b/cc/test/layer_tree_test.cc
index 4b46a68..94b0496 100644
--- a/cc/test/layer_tree_test.cc
+++ b/cc/test/layer_tree_test.cc
@@ -211,11 +211,8 @@
                           std::move(image_worker_task_runner)),
         test_hooks_(test_hooks) {}
 
-  void CreateResourceAndRasterBufferProvider(
-      std::unique_ptr<RasterBufferProvider>* raster_buffer_provider,
-      std::unique_ptr<ResourcePool>* resource_pool) override {
-    test_hooks_->CreateResourceAndRasterBufferProvider(
-        this, raster_buffer_provider, resource_pool);
+  std::unique_ptr<RasterBufferProvider> CreateRasterBufferProvider() override {
+    return test_hooks_->CreateRasterBufferProvider(this);
   }
 
   bool WillBeginImplFrame(const viz::BeginFrameArgs& args) override {
diff --git a/cc/test/test_hooks.cc b/cc/test/test_hooks.cc
index b254924..742f937b 100644
--- a/cc/test/test_hooks.cc
+++ b/cc/test/test_hooks.cc
@@ -17,12 +17,9 @@
   return draw_result;
 }
 
-void TestHooks::CreateResourceAndRasterBufferProvider(
-    LayerTreeHostImpl* host_impl,
-    std::unique_ptr<RasterBufferProvider>* raster_buffer_provider,
-    std::unique_ptr<ResourcePool>* resource_pool) {
-  host_impl->LayerTreeHostImpl::CreateResourceAndRasterBufferProvider(
-      raster_buffer_provider, resource_pool);
+std::unique_ptr<RasterBufferProvider> TestHooks::CreateRasterBufferProvider(
+    LayerTreeHostImpl* host_impl) {
+  return host_impl->LayerTreeHostImpl::CreateRasterBufferProvider();
 }
 
 }  // namespace cc
diff --git a/cc/test/test_hooks.h b/cc/test/test_hooks.h
index 2587c5c..4592762 100644
--- a/cc/test/test_hooks.h
+++ b/cc/test/test_hooks.h
@@ -25,10 +25,8 @@
   ~TestHooks() override;
 
   // Compositor thread hooks.
-  virtual void CreateResourceAndRasterBufferProvider(
-      LayerTreeHostImpl* host_impl,
-      std::unique_ptr<RasterBufferProvider>* raster_buffer_provider,
-      std::unique_ptr<ResourcePool>* resource_pool);
+  virtual std::unique_ptr<RasterBufferProvider> CreateRasterBufferProvider(
+      LayerTreeHostImpl* host_impl);
   virtual void WillBeginImplFrameOnThread(LayerTreeHostImpl* host_impl,
                                           const viz::BeginFrameArgs& args) {}
   virtual void DidFinishImplFrameOnThread(LayerTreeHostImpl* host_impl) {}
diff --git a/cc/trees/latency_info_swap_promise.cc b/cc/trees/latency_info_swap_promise.cc
index 2caa840..3dcaf1e 100644
--- a/cc/trees/latency_info_swap_promise.cc
+++ b/cc/trees/latency_info_swap_promise.cc
@@ -33,11 +33,9 @@
 
 LatencyInfoSwapPromise::~LatencyInfoSwapPromise() = default;
 
-void LatencyInfoSwapPromise::WillSwap(
-    viz::CompositorFrameMetadata* compositor_frame_metadata,
-    RenderFrameMetadata* render_frame_metadata) {
+void LatencyInfoSwapPromise::WillSwap(viz::CompositorFrameMetadata* metadata) {
   DCHECK(!latency_.terminated());
-  compositor_frame_metadata->latency_info.push_back(latency_);
+  metadata->latency_info.push_back(latency_);
 }
 
 void LatencyInfoSwapPromise::DidSwap() {}
diff --git a/cc/trees/latency_info_swap_promise.h b/cc/trees/latency_info_swap_promise.h
index 62a80777..2b23d67 100644
--- a/cc/trees/latency_info_swap_promise.h
+++ b/cc/trees/latency_info_swap_promise.h
@@ -19,8 +19,7 @@
   ~LatencyInfoSwapPromise() override;
 
   void DidActivate() override {}
-  void WillSwap(viz::CompositorFrameMetadata* compositor_frame_metadata,
-                RenderFrameMetadata* render_frame_metadata) override;
+  void WillSwap(viz::CompositorFrameMetadata* metadata) override;
   void DidSwap() override;
   DidNotSwapAction DidNotSwap(DidNotSwapReason reason) override;
   void OnCommit() override;
diff --git a/cc/trees/layer_tree_host_impl.cc b/cc/trees/layer_tree_host_impl.cc
index 7b68170..675a61e 100644
--- a/cc/trees/layer_tree_host_impl.cc
+++ b/cc/trees/layer_tree_host_impl.cc
@@ -1920,13 +1920,10 @@
       frame->use_default_lower_bound_deadline);
 
   metadata.activation_dependencies = std::move(frame->activation_dependencies);
-
-  RenderFrameMetadata render_frame_metadata = MakeRenderFrameMetadata();
-
-  // TODO(jonross): remove passing RenderFrameMetadata to SwapPromises.
-  active_tree()->FinishSwapPromises(&metadata, &render_frame_metadata);
+  active_tree()->FinishSwapPromises(&metadata);
 
   if (render_frame_metadata_observer_) {
+    RenderFrameMetadata render_frame_metadata = MakeRenderFrameMetadata();
     render_frame_metadata_observer_->OnRenderFrameSubmission(
         render_frame_metadata);
   }
@@ -2573,8 +2570,7 @@
 }
 
 void LayerTreeHostImpl::CreateTileManagerResources() {
-  CreateResourceAndRasterBufferProvider(&raster_buffer_provider_,
-                                        &resource_pool_);
+  raster_buffer_provider_ = CreateRasterBufferProvider();
 
   if (use_gpu_rasterization_) {
     image_decode_cache_ = std::make_unique<GpuImageDecodeCache>(
@@ -2612,35 +2608,18 @@
   UpdateTileManagerMemoryPolicy(ActualManagedMemoryPolicy());
 }
 
-void LayerTreeHostImpl::CreateResourceAndRasterBufferProvider(
-    std::unique_ptr<RasterBufferProvider>* raster_buffer_provider,
-    std::unique_ptr<ResourcePool>* resource_pool) {
+std::unique_ptr<RasterBufferProvider>
+LayerTreeHostImpl::CreateRasterBufferProvider() {
   DCHECK(GetTaskRunner());
-  // TODO(vmpstr): Make this a DCHECK (or remove) when crbug.com/419086 is
-  // resolved.
-  CHECK(resource_provider_);
 
   viz::ContextProvider* compositor_context_provider =
       layer_tree_frame_sink_->context_provider();
   if (!compositor_context_provider) {
-    // This ResourcePool will vend software resources.
-    *resource_pool = std::make_unique<ResourcePool>(
-        resource_provider_.get(), GetTaskRunner(),
-        ResourcePool::kDefaultExpirationDelay, ResourcePool::Mode::kSoftware,
-        settings_.disallow_non_exact_resource_reuse);
-
-    *raster_buffer_provider = std::make_unique<BitmapRasterBufferProvider>(
+    return std::make_unique<BitmapRasterBufferProvider>(
         resource_provider_.get(),
         layer_tree_frame_sink_->shared_bitmap_manager());
-    return;
   }
 
-  // The ResourcePool will vend gpu resources.
-  *resource_pool = std::make_unique<ResourcePool>(
-      resource_provider_.get(), GetTaskRunner(),
-      ResourcePool::kDefaultExpirationDelay, ResourcePool::Mode::kGpu,
-      settings_.disallow_non_exact_resource_reuse);
-
   viz::RasterContextProvider* worker_context_provider =
       layer_tree_frame_sink_->worker_context_provider();
   if (use_gpu_rasterization_) {
@@ -2656,12 +2635,11 @@
           worker_context_provider->ContextCapabilities().supports_oop_raster;
     }
 
-    *raster_buffer_provider = std::make_unique<GpuRasterBufferProvider>(
+    return std::make_unique<GpuRasterBufferProvider>(
         compositor_context_provider, worker_context_provider,
         resource_provider_.get(), settings_.use_distance_field_text,
         settings_.resource_settings.use_gpu_memory_buffer_resources,
         msaa_sample_count, settings_.preferred_tile_format, oop_raster_enabled);
-    return;
   }
 
   bool use_zero_copy = settings_.use_zero_copy;
@@ -2674,17 +2652,16 @@
   }
 
   if (use_zero_copy) {
-    *raster_buffer_provider = std::make_unique<ZeroCopyRasterBufferProvider>(
+    return std::make_unique<ZeroCopyRasterBufferProvider>(
         resource_provider_.get(),
         layer_tree_frame_sink_->gpu_memory_buffer_manager(),
         compositor_context_provider, settings_.preferred_tile_format);
-    return;
   }
 
   const int max_copy_texture_chromium_size =
       compositor_context_provider->ContextCapabilities()
           .max_copy_texture_chromium_size;
-  *raster_buffer_provider = std::make_unique<OneCopyRasterBufferProvider>(
+  return std::make_unique<OneCopyRasterBufferProvider>(
       GetTaskRunner(), compositor_context_provider, worker_context_provider,
       resource_provider_.get(), max_copy_texture_chromium_size,
       settings_.use_partial_raster,
@@ -2749,12 +2726,12 @@
 
 void LayerTreeHostImpl::CleanUpTileManagerResources() {
   tile_manager_.FinishTasksAndCleanUp();
-  // TODO(crbug.com/810925): If the ResourceProvider isn't being destroyed,
-  // instead of destroying the pool, just invalidate reuse of existing
-  // resources.
-  resource_pool_ = nullptr;
   single_thread_synchronous_task_graph_runner_ = nullptr;
   image_decode_cache_ = nullptr;
+  // Any resources that were allocated previously should be considered not good
+  // for reuse, as the RasterBufferProvider will be replaced and it may choose
+  // to allocate future resources differently.
+  resource_pool_->InvalidateResources();
 
   // We've potentially just freed a large number of resources on our various
   // contexts. Flushing now helps ensure these are cleaned up quickly
@@ -2787,6 +2764,7 @@
 
   // Note: ui resource cleanup uses the |resource_provider_|.
   CleanUpTileManagerResources();
+  resource_pool_ = nullptr;
   ClearUIResources();
   resource_provider_ = nullptr;
 
@@ -2825,6 +2803,19 @@
       layer_tree_frame_sink_->gpu_memory_buffer_manager(),
       layer_tree_frame_sink_->capabilities().delegated_sync_points_required,
       settings_.resource_settings);
+  if (!layer_tree_frame_sink_->context_provider()) {
+    // This ResourcePool will vend software resources.
+    resource_pool_ = std::make_unique<ResourcePool>(
+        resource_provider_.get(), GetTaskRunner(),
+        ResourcePool::kDefaultExpirationDelay, ResourcePool::Mode::kSoftware,
+        settings_.disallow_non_exact_resource_reuse);
+  } else {
+    // The ResourcePool will vend gpu resources.
+    resource_pool_ = std::make_unique<ResourcePool>(
+        resource_provider_.get(), GetTaskRunner(),
+        ResourcePool::kDefaultExpirationDelay, ResourcePool::Mode::kGpu,
+        settings_.disallow_non_exact_resource_reuse);
+  }
 
   // Since the new context may be capable of MSAA, update status here. We don't
   // need to check the return value since we are recreating all resources
diff --git a/cc/trees/layer_tree_host_impl.h b/cc/trees/layer_tree_host_impl.h
index 2a94f29..aeaa8c84 100644
--- a/cc/trees/layer_tree_host_impl.h
+++ b/cc/trees/layer_tree_host_impl.h
@@ -606,9 +606,8 @@
   bool SupportsImplScrolling() const;
   bool CommitToActiveTree() const;
 
-  virtual void CreateResourceAndRasterBufferProvider(
-      std::unique_ptr<RasterBufferProvider>* raster_buffer_provider,
-      std::unique_ptr<ResourcePool>* resource_pool);
+  // Virtual so tests can inject their own.
+  virtual std::unique_ptr<RasterBufferProvider> CreateRasterBufferProvider();
 
   bool prepare_tiles_needed() const { return tile_priorities_dirty_; }
 
diff --git a/cc/trees/layer_tree_host_unittest.cc b/cc/trees/layer_tree_host_unittest.cc
index 733d9635..76ad86c4 100644
--- a/cc/trees/layer_tree_host_unittest.cc
+++ b/cc/trees/layer_tree_host_unittest.cc
@@ -5310,8 +5310,7 @@
     result_->did_activate_called = true;
   }
 
-  void WillSwap(viz::CompositorFrameMetadata* compositor_frame_metadata,
-                RenderFrameMetadata* render_frame_metadata) override {
+  void WillSwap(viz::CompositorFrameMetadata* metadata) override {
     base::AutoLock lock(result_->lock);
     EXPECT_FALSE(result_->did_swap_called);
     EXPECT_FALSE(result_->did_not_swap_called);
diff --git a/cc/trees/layer_tree_impl.cc b/cc/trees/layer_tree_impl.cc
index ea114c9..b742532 100644
--- a/cc/trees/layer_tree_impl.cc
+++ b/cc/trees/layer_tree_impl.cc
@@ -1591,13 +1591,11 @@
   new_swap_promises.clear();
 }
 
-void LayerTreeImpl::FinishSwapPromises(
-    viz::CompositorFrameMetadata* compositor_frame_metadata,
-    RenderFrameMetadata* render_frame_metadata) {
+void LayerTreeImpl::FinishSwapPromises(viz::CompositorFrameMetadata* metadata) {
   for (const auto& swap_promise : swap_promise_list_)
-    swap_promise->WillSwap(compositor_frame_metadata, render_frame_metadata);
+    swap_promise->WillSwap(metadata);
   for (const auto& swap_promise : pinned_swap_promise_list_)
-    swap_promise->WillSwap(compositor_frame_metadata, render_frame_metadata);
+    swap_promise->WillSwap(metadata);
 }
 
 void LayerTreeImpl::ClearSwapPromises() {
diff --git a/cc/trees/layer_tree_impl.h b/cc/trees/layer_tree_impl.h
index f173297..4352049 100644
--- a/cc/trees/layer_tree_impl.h
+++ b/cc/trees/layer_tree_impl.h
@@ -48,7 +48,6 @@
 class LayerTreeSettings;
 class MemoryHistory;
 class PictureLayerImpl;
-class RenderFrameMetadata;
 class TaskRunnerProvider;
 class TileManager;
 class UIResourceRequest;
@@ -447,9 +446,7 @@
       std::vector<std::unique_ptr<SwapPromise>> new_swap_promises);
   void AppendSwapPromises(
       std::vector<std::unique_ptr<SwapPromise>> new_swap_promises);
-  void FinishSwapPromises(
-      viz::CompositorFrameMetadata* compositor_frame_metadata,
-      RenderFrameMetadata* render_frame_metadata);
+  void FinishSwapPromises(viz::CompositorFrameMetadata* metadata);
   void ClearSwapPromises();
   void BreakSwapPromises(SwapPromise::DidNotSwapReason reason);
 
diff --git a/cc/trees/layer_tree_impl_unittest.cc b/cc/trees/layer_tree_impl_unittest.cc
index a2a8e0a..36c37b3 100644
--- a/cc/trees/layer_tree_impl_unittest.cc
+++ b/cc/trees/layer_tree_impl_unittest.cc
@@ -2286,9 +2286,7 @@
   ~PersistentSwapPromise() override = default;
 
   void DidActivate() override {}
-  MOCK_METHOD2(WillSwap,
-               void(viz::CompositorFrameMetadata* compositor_frame_metadata,
-                    RenderFrameMetadata* render_frame_metadata));
+  MOCK_METHOD1(WillSwap, void(viz::CompositorFrameMetadata* metadata));
   MOCK_METHOD0(DidSwap, void());
 
   DidNotSwapAction DidNotSwap(DidNotSwapReason reason) override {
@@ -2307,8 +2305,7 @@
   ~NotPersistentSwapPromise() override = default;
 
   void DidActivate() override {}
-  void WillSwap(viz::CompositorFrameMetadata* compositor_frame_metadata,
-                RenderFrameMetadata* render_frame_metadata) override {}
+  void WillSwap(viz::CompositorFrameMetadata* metadata) override {}
   void DidSwap() override {}
 
   DidNotSwapAction DidNotSwap(DidNotSwapReason reason) override {
@@ -2346,9 +2343,9 @@
   for (size_t i = 0; i < persistent_promises.size(); ++i) {
     SCOPED_TRACE(testing::Message() << "While checking case #" << i);
     ASSERT_TRUE(persistent_promises[i]);
-    EXPECT_CALL(*persistent_promises[i], WillSwap(testing::_, testing::_));
+    EXPECT_CALL(*persistent_promises[i], WillSwap(testing::_));
   }
-  host_impl().active_tree()->FinishSwapPromises(nullptr, nullptr);
+  host_impl().active_tree()->FinishSwapPromises(nullptr);
 }
 
 TEST_F(LayerTreeImplTest, NotPersistentSwapPromisesAreDroppedWhenSwapFails) {
diff --git a/cc/trees/swap_promise.h b/cc/trees/swap_promise.h
index 0ab6136..81ec7cd0 100644
--- a/cc/trees/swap_promise.h
+++ b/cc/trees/swap_promise.h
@@ -8,7 +8,6 @@
 #include <stdint.h>
 
 #include "cc/cc_export.h"
-#include "cc/trees/render_frame_metadata.h"
 #include "components/viz/common/quads/compositor_frame_metadata.h"
 
 namespace cc {
@@ -62,8 +61,7 @@
   virtual ~SwapPromise() {}
 
   virtual void DidActivate() = 0;
-  virtual void WillSwap(viz::CompositorFrameMetadata* compositor_frame_metadata,
-                        RenderFrameMetadata* render_frame_metadata) = 0;
+  virtual void WillSwap(viz::CompositorFrameMetadata* metadata) = 0;
   virtual void DidSwap() = 0;
   // Return |KEEP_ACTIVE| if this promise should remain active (should not be
   // broken by the owner).
diff --git a/cc/trees/swap_promise_manager_unittest.cc b/cc/trees/swap_promise_manager_unittest.cc
index 85bfa97..59bd0980 100644
--- a/cc/trees/swap_promise_manager_unittest.cc
+++ b/cc/trees/swap_promise_manager_unittest.cc
@@ -31,8 +31,7 @@
   ~MockSwapPromise() override = default;
 
   void DidActivate() override {}
-  void WillSwap(viz::CompositorFrameMetadata* compositor_frame_metadata,
-                RenderFrameMetadata* render_frame_metadata) override {}
+  void WillSwap(viz::CompositorFrameMetadata* metadata) override {}
   void DidSwap() override {}
   DidNotSwapAction DidNotSwap(DidNotSwapReason reason) override {
     return DidNotSwapAction::BREAK_PROMISE;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ChromeApplication.java b/chrome/android/java/src/org/chromium/chrome/browser/ChromeApplication.java
index a01f7c13..fbafd8e 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ChromeApplication.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ChromeApplication.java
@@ -5,18 +5,21 @@
 package org.chromium.chrome.browser;
 
 import android.app.Activity;
+import android.app.Application;
 import android.content.Context;
 
 import org.chromium.base.ActivityState;
 import org.chromium.base.ApplicationStatus;
-import org.chromium.base.BaseChromiumApplication;
+import org.chromium.base.BuildConfig;
 import org.chromium.base.CommandLineInitUtil;
 import org.chromium.base.ContextUtils;
 import org.chromium.base.DiscardableReferencePool;
+import org.chromium.base.Log;
 import org.chromium.base.ThreadUtils;
 import org.chromium.base.TraceEvent;
 import org.chromium.base.annotations.MainDex;
 import org.chromium.base.library_loader.ProcessInitException;
+import org.chromium.base.multidex.ChromiumMultiDexInstaller;
 import org.chromium.build.BuildHooks;
 import org.chromium.build.BuildHooksAndroid;
 import org.chromium.build.BuildHooksConfig;
@@ -36,7 +39,7 @@
  * chrome layer.
  */
 @MainDex
-public class ChromeApplication extends BaseChromiumApplication {
+public class ChromeApplication extends Application {
     private static final String COMMAND_LINE_FILE = "chrome-command-line";
     private static final String TAG = "ChromiumApplication";
 
@@ -49,6 +52,10 @@
     protected void attachBaseContext(Context context) {
         UmaUtils.recordMainEntryPointTime();
         super.attachBaseContext(context);
+        checkAppBeingReplaced();
+        if (BuildConfig.isMultidexEnabled()) {
+            ChromiumMultiDexInstaller.install(this);
+        }
         ContextUtils.initApplicationContext(this);
 
         if (ContextUtils.isMainProcess()) {
@@ -83,6 +90,17 @@
         }
     }
 
+    /** Ensure this application object is not out-of-date. */
+    private void checkAppBeingReplaced() {
+        // During app update the old apk can still be triggered by broadcasts and spin up an
+        // out-of-date application. Kill old applications in this bad state. See
+        // http://crbug.com/658130 for more context and http://b.android.com/56296 for the bug.
+        if (getResources() == null) {
+            Log.e(TAG, "getResources() null, closing app.");
+            System.exit(0);
+        }
+    }
+
     @Override
     public void onTrimMemory(int level) {
         super.onTrimMemory(level);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabActivity.java
index f635311..1cd51ee8 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabActivity.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabActivity.java
@@ -153,13 +153,15 @@
     private static class PageLoadMetricsObserver implements PageLoadMetrics.Observer {
         private final CustomTabsConnection mConnection;
         private final CustomTabsSessionToken mSession;
-        private final WebContents mWebContents;
+        private final Tab mTab;
+        private final CustomTabObserver mCustomTabObserver;
 
         public PageLoadMetricsObserver(CustomTabsConnection connection,
-                CustomTabsSessionToken session, Tab tab) {
+                CustomTabsSessionToken session, Tab tab, CustomTabObserver tabObserver) {
             mConnection = connection;
             mSession = session;
-            mWebContents = tab.getWebContents();
+            mTab = tab;
+            mCustomTabObserver = tabObserver;
         }
 
         @Override
@@ -168,7 +170,7 @@
         @Override
         public void onNetworkQualityEstimate(WebContents webContents, long navigationId,
                 int effectiveConnectionType, long httpRttMs, long transportRttMs) {
-            if (webContents != mWebContents) return;
+            if (webContents != mTab.getWebContents()) return;
 
             Bundle args = new Bundle();
             args.putLong(PageLoadMetrics.EFFECTIVE_CONNECTION_TYPE, effectiveConnectionType);
@@ -182,16 +184,24 @@
         @Override
         public void onFirstContentfulPaint(WebContents webContents, long navigationId,
                 long navigationStartTick, long firstContentfulPaintMs) {
-            if (webContents != mWebContents) return;
+            if (webContents != mTab.getWebContents()) return;
 
             mConnection.notifySinglePageLoadMetric(mSession, PageLoadMetrics.FIRST_CONTENTFUL_PAINT,
                     navigationStartTick, firstContentfulPaintMs);
         }
 
         @Override
+        public void onFirstMeaningfulPaint(WebContents webContents, long navigationId,
+                long navigationStartTick, long firstContentfulPaintMs) {
+            if (webContents != mTab.getWebContents()) return;
+
+            mCustomTabObserver.onFirstMeaningfulPaint(mTab);
+        }
+
+        @Override
         public void onLoadEventStart(WebContents webContents, long navigationId,
                 long navigationStartTick, long loadEventStartMs) {
-            if (webContents != mWebContents) return;
+            if (webContents != mTab.getWebContents()) return;
             mConnection.notifySinglePageLoadMetric(mSession, PageLoadMetrics.LOAD_EVENT_START,
                     navigationStartTick, loadEventStartMs);
         }
@@ -200,7 +210,7 @@
         public void onLoadedMainResource(WebContents webContents, long navigationId,
                 long dnsStartMs, long dnsEndMs, long connectStartMs, long connectEndMs,
                 long requestStartMs, long sendStartMs, long sendEndMs) {
-            if (webContents != mWebContents) return;
+            if (webContents != mTab.getWebContents()) return;
 
             Bundle args = new Bundle();
             args.putLong(PageLoadMetrics.DOMAIN_LOOKUP_START, dnsStartMs);
@@ -647,7 +657,7 @@
         mTabObserver = new CustomTabObserver(
                 getApplication(), mSession, mIntentDataProvider.isOpenedByChrome());
 
-        mMetricsObserver = new PageLoadMetricsObserver(mConnection, mSession, tab);
+        mMetricsObserver = new PageLoadMetricsObserver(mConnection, mSession, tab, mTabObserver);
         // Immediately add the observer to PageLoadMetrics to catch early events that may
         // be generated in the middle of tab initialization.
         PageLoadMetrics.addObserver(mMetricsObserver);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabObserver.java b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabObserver.java
index f1b7f00f..9fb680f 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabObserver.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabObserver.java
@@ -12,7 +12,6 @@
 import android.support.customtabs.CustomTabsSessionToken;
 import android.text.TextUtils;
 
-import org.chromium.base.ThreadUtils;
 import org.chromium.base.metrics.RecordHistogram;
 import org.chromium.chrome.R;
 import org.chromium.chrome.browser.prerender.ExternalPrerenderHandler;
@@ -20,7 +19,6 @@
 import org.chromium.chrome.browser.tab.Tab;
 import org.chromium.chrome.browser.tab.TabObserver;
 import org.chromium.components.security_state.ConnectionSecurityLevel;
-import org.chromium.content_public.browser.ContentBitmapCallback;
 import org.chromium.content_public.browser.LoadUrlParams;
 
 import java.util.concurrent.TimeUnit;
@@ -32,6 +30,8 @@
     private final CustomTabsConnection mCustomTabsConnection;
     private final CustomTabsSessionToken mSession;
     private final boolean mOpenedByChrome;
+    private final NavigationInfoCaptureTrigger mNavigationInfoCaptureTrigger =
+            new NavigationInfoCaptureTrigger(this::captureNavigationInfo);
     private int mContentBitmapWidth;
     private int mContentBitmapHeight;
 
@@ -39,8 +39,6 @@
     private long mPageLoadStartedTimestamp;
     private long mFirstCommitTimestamp;
 
-    private boolean mScreenshotTakenForCurrentNavigation;
-
     private static final int STATE_RESET = 0;
     private static final int STATE_WAITING_LOAD_START = 1;
     private static final int STATE_WAITING_LOAD_FINISH = 2;
@@ -116,7 +114,7 @@
             mCustomTabsConnection.setSendNavigationInfoForSession(mSession, false);
             mCustomTabsConnection.notifyNavigationEvent(
                     mSession, CustomTabsCallback.NAVIGATION_STARTED);
-            mScreenshotTakenForCurrentNavigation = false;
+            mNavigationInfoCaptureTrigger.onNewNavigation();
         }
     }
 
@@ -130,7 +128,7 @@
 
     @Override
     public void onHidden(Tab tab) {
-        if (!mScreenshotTakenForCurrentNavigation) captureNavigationInfo(tab);
+        mNavigationInfoCaptureTrigger.onHide(tab);
     }
 
     @Override
@@ -178,7 +176,7 @@
             }
         }
         resetPageLoadTracking();
-        captureNavigationInfo(tab);
+        mNavigationInfoCaptureTrigger.onLoadFinished(tab);
     }
 
     @Override
@@ -211,6 +209,10 @@
         if (isFirstMainFrameCommit) mFirstCommitTimestamp = SystemClock.elapsedRealtime();
     }
 
+    public void onFirstMeaningfulPaint(Tab tab) {
+        mNavigationInfoCaptureTrigger.onFirstMeaningfulPaint(tab);
+    }
+
     private void resetPageLoadTracking() {
         mCurrentState = STATE_RESET;
         mIntentReceivedTimestamp = -1;
@@ -219,26 +221,15 @@
     private void captureNavigationInfo(final Tab tab) {
         if (mCustomTabsConnection == null) return;
         if (!mCustomTabsConnection.shouldSendNavigationInfoForSession(mSession)) return;
+        if (tab.getWebContents() == null) return;
 
-        final ContentBitmapCallback callback = new ContentBitmapCallback() {
-            @Override
-            public void onFinishGetBitmap(Bitmap bitmap, int response) {
-                if (TextUtils.isEmpty(tab.getTitle()) && bitmap == null) return;
-                mCustomTabsConnection.sendNavigationInfo(
-                        mSession, tab.getUrl(), tab.getTitle(), bitmap);
-            }
-        };
-        // Delay screenshot capture since the page might be doing post load tasks. And this also
-        // gives time to get rid of any redirects and avoid capturing screenshots for those.
-        ThreadUtils.postOnUiThreadDelayed(new Runnable() {
-            @Override
-            public void run() {
-                if (!tab.isHidden() && mCurrentState != STATE_RESET) return;
-                if (tab.getWebContents() == null) return;
-                tab.getWebContents().getContentBitmapAsync(
-                        mContentBitmapWidth, mContentBitmapHeight, callback);
-                mScreenshotTakenForCurrentNavigation = true;
-            }
-        }, 1000);
+        tab.getWebContents().getContentBitmapAsync(
+                mContentBitmapWidth, mContentBitmapHeight, (Bitmap bitmap, int response) -> {
+                    if (TextUtils.isEmpty(tab.getTitle()) && bitmap == null) return;
+                    mCustomTabsConnection.sendNavigationInfo(
+                            mSession, tab.getUrl(), tab.getTitle(), bitmap);
+                });
+
+        return;
     }
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/NavigationInfoCaptureTrigger.java b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/NavigationInfoCaptureTrigger.java
new file mode 100644
index 0000000..b62ac0c
--- /dev/null
+++ b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/NavigationInfoCaptureTrigger.java
@@ -0,0 +1,124 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.chrome.browser.customtabs;
+
+import android.os.Handler;
+
+import org.chromium.base.Callback;
+import org.chromium.base.ThreadUtils;
+import org.chromium.chrome.browser.tab.Tab;
+
+import java.util.LinkedList;
+import java.util.List;
+import java.util.concurrent.Callable;
+
+/**
+ * This class contains logic for capturing navigation info at an appropriate time.
+ *
+ * We want to capture navigation information after both onload and first meaningful paint have
+ * triggered. We add a slight delay to avoid capturing during CPU intensive periods.
+ *
+ * If a capture has not been taken after a long amount of time or when the Tab is hidden, we also
+ * capture.
+ */
+public class NavigationInfoCaptureTrigger {
+    private static final int ONLOAD_DELAY_MS = 1000;
+    private static final int ONLOAD_LONG_DELAY_MS = 15000;
+    private static final int ONHIDE_DELAY_MS = 1000;
+    private static final int FMP_DELAY_MS = 3000;
+
+    private final Callback<Tab> mCapture;
+    private final Handler mUiThreadHandler = new Handler(ThreadUtils.getUiThreadLooper());
+    private final List<Runnable> mPendingRunnables = new LinkedList<>();
+
+    private boolean mOnloadTriggered;
+    private boolean mFirstMeaningfulPaintTriggered;
+    private boolean mCaptureTaken;
+
+    public NavigationInfoCaptureTrigger(Callback<Tab> capture) {
+        mCapture = capture;
+    }
+
+    /** Notifies that a page navigation has occurred and state should reset. */
+    public void onNewNavigation() {
+        mOnloadTriggered = false;
+        mFirstMeaningfulPaintTriggered = false;
+        mCaptureTaken = false;
+        clearPendingRunnables();
+    }
+
+    /** Notifies that onload has occurred. */
+    public void onLoadFinished(Tab tab) {
+        mOnloadTriggered = true;
+        captureDelayedIf(tab, () -> mFirstMeaningfulPaintTriggered, ONLOAD_DELAY_MS);
+        captureDelayed(tab, ONLOAD_LONG_DELAY_MS);
+    }
+
+    /** Notifies that first meaningful paint has occurred. */
+    public void onFirstMeaningfulPaint(Tab tab) {
+        mFirstMeaningfulPaintTriggered = true;
+        captureDelayedIf(tab, () -> mOnloadTriggered, FMP_DELAY_MS);
+    }
+
+    /** Notifies that the Tab has been hidden. */
+    public void onHide(Tab tab) {
+        captureDelayed(tab, ONHIDE_DELAY_MS);
+    }
+
+    private void clearPendingRunnables() {
+        for (Runnable pendingRunnable: mPendingRunnables) {
+            mUiThreadHandler.removeCallbacks(pendingRunnable);
+        }
+        mPendingRunnables.clear();
+    }
+
+    /** Posts a CaptureRunnable that will capture navigation info after the delay (ms). */
+    private void captureDelayed(Tab tab, long delay) {
+        captureDelayedIf(tab, () -> true, delay);
+    }
+
+    /**
+     * Posts a CaptureRunnable that will capture navigation info after the delay (ms) if the check
+     * passes.
+     */
+    private void captureDelayedIf(Tab tab, Callable<Boolean> check, long delay) {
+        if (mCaptureTaken) return;
+        Runnable runnable = new CaptureRunnable(tab, check);
+        mPendingRunnables.add(runnable);
+        mUiThreadHandler.postDelayed(runnable, delay);
+    }
+
+    /**
+     * A Runnable that when executes ensures that no capture has already been taken and that the
+     * check passes, then captures the navigation info and clears all other pending Runnables.
+     */
+    private class CaptureRunnable implements Runnable {
+        private final Callable<Boolean> mCheck;
+        private final Tab mTab;
+
+        public CaptureRunnable(Tab tab, Callable<Boolean> check) {
+            mCheck = check;
+            mTab = tab;
+        }
+
+        @Override
+        public void run() {
+            assert !mCaptureTaken;
+
+            try {
+                if (!mCheck.call()) return;
+            } catch (Exception e) {
+                // In case mCheck.call throws an exception (which it shouldn't, but it's part of
+                // Callable#call's signature).
+                throw new RuntimeException(e);
+            }
+
+            mCapture.onResult(mTab);
+            mCaptureTaken = true;
+
+            clearPendingRunnables();
+        }
+    }
+}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/metrics/PageLoadMetrics.java b/chrome/android/java/src/org/chromium/chrome/browser/metrics/PageLoadMetrics.java
index 845e6e4..9a79212 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/metrics/PageLoadMetrics.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/metrics/PageLoadMetrics.java
@@ -39,7 +39,7 @@
          * @param webContents the WebContents this metrics is related to.
          * @param navigationId the unique id of a navigation this metrics is related to.
          */
-        public void onNewNavigation(WebContents webContents, long navigationId);
+        default void onNewNavigation(WebContents webContents, long navigationId) {}
 
         /**
          * Called when Network Quality Estimate is available, once per page load, when the
@@ -56,8 +56,8 @@
          * @param transportRttMs an estimate of transport RTT, in milliseconds. Will be zero
          *     if unknown.
          */
-        public void onNetworkQualityEstimate(WebContents webContents, long navigationId,
-                int effectiveConnectionType, long httpRttMs, long transportRttMs);
+        default void onNetworkQualityEstimate(WebContents webContents, long navigationId,
+                int effectiveConnectionType, long httpRttMs, long transportRttMs) {}
 
         /**
          * Called when the first contentful paint page load metric is available.
@@ -67,8 +67,20 @@
          * @param navigationStartTick Absolute navigation start time, as TimeTicks.
          * @param firstContentfulPaintMs Time to first contentful paint from navigation start.
          */
-        public void onFirstContentfulPaint(WebContents webContents, long navigationId,
-                long navigationStartTick, long firstContentfulPaintMs);
+        default void onFirstContentfulPaint(WebContents webContents, long navigationId,
+                long navigationStartTick, long firstContentfulPaintMs) {}
+
+        /**
+         * Called when the first meaningful paint page load metric is available. See
+         * FirstMeaningfulPaintDetector.cpp
+         *
+         * @param webContents the WebContents this metrics is related to.
+         * @param navigationId the unique id of a navigation this metrics is related to.
+         * @param navigationStartTick Absolute navigation start time, as TimeTicks.
+         * @param firstMeaningfulPaintMs Time to first meaningful paint from navigation start.
+         */
+        default void onFirstMeaningfulPaint(WebContents webContents, long navigationId,
+                long navigationStartTick, long firstMeaningfulPaintMs) {}
 
         /**
          * Called when the load event start metric is available.
@@ -78,8 +90,8 @@
          * @param navigationStartTick Absolute navigation start time, as TimeTicks.
          * @param loadEventStartMs Time to load event start from navigation start.
          */
-        public void onLoadEventStart(WebContents webContents, long navigationId,
-                long navigationStartTick, long loadEventStartMs);
+        default void onLoadEventStart(WebContents webContents, long navigationId,
+                long navigationStartTick, long loadEventStartMs) {}
 
         /**
          * Called when the main resource is loaded.
@@ -90,9 +102,9 @@
          * Remaining parameters are timing information in milliseconds from a common
          * arbitrary point (such as, but not guaranteed to be, system start).
          */
-        public void onLoadedMainResource(WebContents webContents, long navigationId,
+        default void onLoadedMainResource(WebContents webContents, long navigationId,
                 long dnsStartMs, long dnsEndMs, long connectStartMs, long connectEndMs,
-                long requestStartMs, long sendStartMs, long sendEndMs);
+                long requestStartMs, long sendStartMs, long sendEndMs) {}
     }
 
     private static ObserverList<Observer> sObservers;
@@ -143,6 +155,17 @@
     }
 
     @CalledByNative
+    static void onFirstMeaningfulPaint(WebContents webContents, long navigationId,
+            long navigationStartTick, long firstMeaningfulPaintMs) {
+        ThreadUtils.assertOnUiThread();
+        if (sObservers == null) return;
+        for (Observer observer : sObservers) {
+            observer.onFirstMeaningfulPaint(
+                    webContents, navigationId, navigationStartTick, firstMeaningfulPaintMs);
+        }
+    }
+
+    @CalledByNative
     static void onLoadEventStart(WebContents webContents, long navigationId,
             long navigationStartTick, long loadEventStartMs) {
         ThreadUtils.assertOnUiThread();
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/metrics/StartupPageLoadMetricsObserver.java b/chrome/android/java/src/org/chromium/chrome/browser/metrics/StartupPageLoadMetricsObserver.java
index 4836ca4..63d17ef 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/metrics/StartupPageLoadMetricsObserver.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/metrics/StartupPageLoadMetricsObserver.java
@@ -24,23 +24,10 @@
     }
 
     @Override
-    public void onNetworkQualityEstimate(WebContents webContents, long navigationId,
-            int effectiveConnectionType, long httpRttMs, long transportRttMs) {}
-
-    @Override
     public void onFirstContentfulPaint(WebContents webContents, long navigationId,
             long navigationStartTick, long firstContentfulPaintMs) {
         if (navigationId != mNavigationId || !mShouldRecordHistograms) return;
 
         UmaUtils.recordFirstContentfulPaint(navigationStartTick / 1000 + firstContentfulPaintMs);
     }
-
-    @Override
-    public void onLoadEventStart(WebContents webContents, long navigationId,
-            long navigationStartTick, long loadEventStartMs) {}
-
-    @Override
-    public void onLoadedMainResource(WebContents webContents, long navigationId, long dnsStartMs,
-            long dnsEndMs, long connectStartMs, long connectEndMs, long requestStartMs,
-            long sendStartMs, long sendEndMs) {}
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/NewTabPageRecyclerView.java b/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/NewTabPageRecyclerView.java
index 07aa5b3..09e810d 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/NewTabPageRecyclerView.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/NewTabPageRecyclerView.java
@@ -24,6 +24,7 @@
 import org.chromium.chrome.browser.preferences.ChromePreferenceManager;
 import org.chromium.chrome.browser.suggestions.SuggestionsRecyclerView;
 import org.chromium.chrome.browser.util.ViewUtils;
+import org.chromium.ui.base.DeviceFormFactor;
 
 /**
  * Simple wrapper on top of a RecyclerView that will acquire focus when tapped.  Ensures the
@@ -94,11 +95,14 @@
 
     @Override
     protected boolean getTouchEnabled() {
+        if (!super.getTouchEnabled()) return false;
+
+        if (DeviceFormFactor.isTablet()) return true;
+
         // The RecyclerView should not accept touch events while the URL bar is focused. This
         // prevents the RecyclerView from requesting focus during the URL focus animation, which
         // would cause the focus animation to be canceled. See https://crbug.com/798084.
-        return super.getTouchEnabled()
-                && (mFakeboxDelegate == null || !mFakeboxDelegate.isUrlBarFocused());
+        return mFakeboxDelegate == null || !mFakeboxDelegate.isUrlBarFocused();
     }
 
     private void scrollToFirstCard() {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/offlinepages/OfflinePageBridge.java b/chrome/android/java/src/org/chromium/chrome/browser/offlinepages/OfflinePageBridge.java
index 761d68b..4b3b83fca 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/offlinepages/OfflinePageBridge.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/offlinepages/OfflinePageBridge.java
@@ -515,6 +515,28 @@
     }
 
     /**
+     * Deletes offline pages based on the list of provided client IDs only if they originate
+     * from the same origin. Calls the callback when operation is complete. Requires that the
+     * model is already loaded.
+     *
+     * @param clientIds A list of Client IDs for which the offline pages will be deleted.
+     * @param callback A callback that will be called once operation is completed.
+     */
+    public void deletePagesByClientIdAndOrigin(
+            List<ClientId> clientIds, String origin, Callback<Integer> callback) {
+        String[] namespaces = new String[clientIds.size()];
+        String[] ids = new String[clientIds.size()];
+
+        for (int i = 0; i < clientIds.size(); i++) {
+            namespaces[i] = clientIds.get(i).getNamespace();
+            ids[i] = clientIds.get(i).getId();
+        }
+
+        nativeDeletePagesByClientIdAndOrigin(
+                mNativeOfflinePageBridge, namespaces, ids, origin, callback);
+    }
+
+    /**
      * Deletes offline pages based on the list of offline IDs. Calls the callback
      * when operation is complete. Note that offline IDs are not intended to be saved across
      * restarts of Chrome; they should be obtained by querying the model for the appropriate client
@@ -774,6 +796,8 @@
     @VisibleForTesting
     native void nativeDeletePagesByClientId(long nativeOfflinePageBridge, String[] namespaces,
             String[] ids, Callback<Integer> callback);
+    native void nativeDeletePagesByClientIdAndOrigin(long nativeOfflinePageBridge,
+            String[] namespaces, String[] ids, String origin, Callback<Integer> callback);
     @VisibleForTesting
     native void nativeDeletePagesByOfflineId(
             long nativeOfflinePageBridge, long[] offlineIds, Callback<Integer> callback);
diff --git a/chrome/android/java_sources.gni b/chrome/android/java_sources.gni
index 5385be2..04923cd 100644
--- a/chrome/android/java_sources.gni
+++ b/chrome/android/java_sources.gni
@@ -310,6 +310,7 @@
   "java/src/org/chromium/chrome/browser/customtabs/CustomTabTabPersistencePolicy.java",
   "java/src/org/chromium/chrome/browser/customtabs/LoadingPredictor.java",
   "java/src/org/chromium/chrome/browser/customtabs/RequestThrottler.java",
+  "java/src/org/chromium/chrome/browser/customtabs/NavigationInfoCaptureTrigger.java",
   "java/src/org/chromium/chrome/browser/customtabs/SeparateTaskCustomTabActivity.java",
   "java/src/org/chromium/chrome/browser/customtabs/SeparateTaskCustomTabActivity0.java",
   "java/src/org/chromium/chrome/browser/customtabs/SeparateTaskCustomTabActivity1.java",
@@ -1912,6 +1913,7 @@
   "junit/src/org/chromium/chrome/browser/contextmenu/ChromeContextMenuPopulatorTest.java",
   "junit/src/org/chromium/chrome/browser/cookies/CanonicalCookieTest.java",
   "junit/src/org/chromium/chrome/browser/crash/LogcatExtractionRunnableUnitTest.java",
+  "junit/src/org/chromium/chrome/browser/customtabs/NavigationInfoCaptureTriggerTest.java",
   "junit/src/org/chromium/chrome/browser/download/DownloadSharedPreferenceEntryTest.java",
   "junit/src/org/chromium/chrome/browser/download/items/OfflineContentAggregatorNotificationBridgeUiTest.java",
   "junit/src/org/chromium/chrome/browser/download/DownloadResumptionSchedulerTest.java",
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/metrics/PageLoadMetricsTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/metrics/PageLoadMetricsTest.java
index 467cec7..af84adf 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/metrics/PageLoadMetricsTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/metrics/PageLoadMetricsTest.java
@@ -122,15 +122,6 @@
         public long getNavigationId() {
             return mNavigationId;
         }
-
-        @Override
-        public void onLoadedMainResource(WebContents webContents, long navigationId,
-                long dnsStartMs, long dnsEndMs, long connectStartMs, long connectEndMs,
-                long requestStartMs, long sendStartMs, long sendEndMs) {}
-
-        @Override
-        public void onNetworkQualityEstimate(WebContents webContents, long navigationId,
-                int effectiveConnectionType, long httpRttMs, long transportRttMs) {}
     }
 
     @Test
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/vr_shell/WebVrDeviceTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/vr_shell/WebVrDeviceTest.java
index 83bbad7..8923ea3 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/vr_shell/WebVrDeviceTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/vr_shell/WebVrDeviceTest.java
@@ -47,19 +47,17 @@
     @Rule
     public RuleChain mRuleChain;
 
-    private ChromeActivityTestRule mTestRule;
+    private ChromeActivityTestRule mVrTestRule;
     private VrTestFramework mVrTestFramework;
-    private XrTestFramework mXrTestFramework;
 
     public WebVrDeviceTest(Callable<ChromeActivityTestRule> callable) throws Exception {
-        mTestRule = callable.call();
-        mRuleChain = VrTestRuleUtils.wrapRuleInVrActivityRestrictionRule(mTestRule);
+        mVrTestRule = callable.call();
+        mRuleChain = VrTestRuleUtils.wrapRuleInVrActivityRestrictionRule(mVrTestRule);
     }
 
     @Before
     public void setUp() throws Exception {
-        mVrTestFramework = new VrTestFramework(mTestRule);
-        mXrTestFramework = new XrTestFramework(mTestRule);
+        mVrTestFramework = new VrTestFramework(mVrTestRule);
     }
 
     /**
@@ -99,20 +97,4 @@
                 mVrTestFramework.getFirstTabWebContents());
         VrTestFramework.endTest(mVrTestFramework.getFirstTabWebContents());
     }
-
-    /**
-     * Tests that reported WebXR capabilities match expectations.
-     */
-    @Test
-    @MediumTest
-    @CommandLineFlags.Remove({"enable-webvr"})
-    @CommandLineFlags.Add({"enable-features=WebXR"})
-    @VrActivityRestriction({VrActivityRestriction.SupportedActivity.ALL})
-    public void testWebXrCapabilities() throws InterruptedException {
-        mXrTestFramework.loadUrlAndAwaitInitialization(
-                XrTestFramework.getHtmlTestFile("test_webxr_capabilities"), PAGE_LOAD_TIMEOUT_S);
-        XrTestFramework.executeStepAndWait(
-                "stepCheckCapabilities('Daydream')", mXrTestFramework.getFirstTabWebContents());
-        XrTestFramework.endTest(mXrTestFramework.getFirstTabWebContents());
-    }
 }
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/vr_shell/WebVrTabTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/vr_shell/WebVrTabTest.java
index 36df0d1..001a2a6b 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/vr_shell/WebVrTabTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/vr_shell/WebVrTabTest.java
@@ -43,19 +43,17 @@
     @Rule
     public RuleChain mRuleChain;
 
-    private ChromeActivityTestRule mTestRule;
+    private ChromeActivityTestRule mVrTestRule;
     private VrTestFramework mVrTestFramework;
-    private XrTestFramework mXrTestFramework;
 
     public WebVrTabTest(Callable<ChromeActivityTestRule> callable) throws Exception {
-        mTestRule = callable.call();
-        mRuleChain = VrTestRuleUtils.wrapRuleInVrActivityRestrictionRule(mTestRule);
+        mVrTestRule = callable.call();
+        mRuleChain = VrTestRuleUtils.wrapRuleInVrActivityRestrictionRule(mVrTestRule);
     }
 
     @Before
     public void setUp() throws Exception {
-        mVrTestFramework = new VrTestFramework(mTestRule);
-        mXrTestFramework = new XrTestFramework(mTestRule);
+        mVrTestFramework = new VrTestFramework(mVrTestRule);
     }
 
     /**
@@ -64,33 +62,16 @@
     @Test
     @MediumTest
     public void testPoseDataUnfocusedTab() throws InterruptedException {
-        testPoseDataUnfocusedTabImpl(
-                VrTestFramework.getHtmlTestFile("test_pose_data_unfocused_tab"), mVrTestFramework);
-    }
+        mVrTestFramework.loadUrlAndAwaitInitialization(
+                VrTestFramework.getHtmlTestFile("test_pose_data_unfocused_tab"),
+                PAGE_LOAD_TIMEOUT_S);
+        VrTestFramework.executeStepAndWait(
+                "stepCheckFrameDataWhileFocusedTab()", mVrTestFramework.getFirstTabWebContents());
 
-    /**
-     * Tests that non-focused tabs don't get WebXR rAFs called.
-     */
-    @Test
-    @MediumTest
-    @CommandLineFlags.Remove({"enable-webvr"})
-    @CommandLineFlags.Add({"enable-features=WebXR"})
-    public void testPoseDataUnfocusedTab_WebXr() throws InterruptedException {
-        testPoseDataUnfocusedTabImpl(
-                XrTestFramework.getHtmlTestFile("webxr_test_pose_data_unfocused_tab"),
-                mXrTestFramework);
-    }
+        mVrTestRule.loadUrlInNewTab("about:blank");
 
-    private void testPoseDataUnfocusedTabImpl(String url, TestFramework framework)
-            throws InterruptedException {
-        framework.loadUrlAndAwaitInitialization(url, PAGE_LOAD_TIMEOUT_S);
-        TestFramework.executeStepAndWait(
-                "stepCheckFrameDataWhileFocusedTab()", framework.getFirstTabWebContents());
-
-        mTestRule.loadUrlInNewTab("about:blank");
-
-        TestFramework.executeStepAndWait(
-                "stepCheckFrameDataWhileNonFocusedTab()", framework.getFirstTabWebContents());
-        TestFramework.endTest(framework.getFirstTabWebContents());
+        VrTestFramework.executeStepAndWait("stepCheckFrameDataWhileNonFocusedTab()",
+                mVrTestFramework.getFirstTabWebContents());
+        VrTestFramework.endTest(mVrTestFramework.getFirstTabWebContents());
     }
 }
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/vr_shell/WebVrTransitionTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/vr_shell/WebVrTransitionTest.java
index 1dac33c..5a2f288a 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/vr_shell/WebVrTransitionTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/vr_shell/WebVrTransitionTest.java
@@ -440,45 +440,4 @@
         framework.simulateRendererKilled();
         Assert.assertTrue("Browser is in VR", VrShellDelegate.isInVr());
     }
-
-    /**
-     * Tests that window.rAF continues to fire when we have a non-exclusive session.
-     */
-    @Test
-    @MediumTest
-    @CommandLineFlags.Remove({"enable-webvr"})
-    @CommandLineFlags.Add({"enable-features=WebXR"})
-    @VrActivityRestriction({VrActivityRestriction.SupportedActivity.ALL})
-    public void testWindowRafFiresDuringNonExclusiveSession() throws InterruptedException {
-        mXrTestFramework.loadUrlAndAwaitInitialization(
-                XrTestFramework.getHtmlTestFile(
-                        "test_window_raf_fires_during_non_exclusive_session"),
-                PAGE_LOAD_TIMEOUT_S);
-        XrTestFramework.waitOnJavaScriptStep(mXrTestFramework.getFirstTabWebContents());
-        XrTestFramework.endTest(mXrTestFramework.getFirstTabWebContents());
-    }
-
-    /**
-     * Tests that non-exclusive sessions stop receiving rAFs during an exclusive session, but resume
-     * once the exclusive session ends.
-     */
-    @Test
-    @MediumTest
-    @CommandLineFlags.Remove({"enable-webvr"})
-    @CommandLineFlags.Add({"enable-features=WebXR"})
-    @VrActivityRestriction({VrActivityRestriction.SupportedActivity.ALL})
-    public void testNonExclusiveStopsDuringExclusive() throws InterruptedException {
-        mXrTestFramework.loadUrlAndAwaitInitialization(
-                XrTestFramework.getHtmlTestFile("test_non_exclusive_stops_during_exclusive"),
-                PAGE_LOAD_TIMEOUT_S);
-        XrTestFramework.executeStepAndWait(
-                "stepBeforeExclusive()", mXrTestFramework.getFirstTabWebContents());
-        TransitionUtils.enterPresentationOrFail(mXrTestFramework);
-        XrTestFramework.executeStepAndWait(
-                "stepDuringExclusive()", mXrTestFramework.getFirstTabWebContents());
-        TransitionUtils.forceExitVr();
-        XrTestFramework.executeStepAndWait(
-                "stepAfterExclusive()", mXrTestFramework.getFirstTabWebContents());
-        XrTestFramework.endTest(mXrTestFramework.getFirstTabWebContents());
-    }
 }
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/ChromeBackupAgentTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/ChromeBackupAgentTest.java
index 13138f7..1c0decd 100644
--- a/chrome/android/junit/src/org/chromium/chrome/browser/ChromeBackupAgentTest.java
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/ChromeBackupAgentTest.java
@@ -39,7 +39,6 @@
 import org.robolectric.annotation.Implements;
 
 import org.chromium.base.ApiCompatibilityUtils;
-import org.chromium.base.BaseChromiumApplication;
 import org.chromium.base.CommandLine;
 import org.chromium.base.ContextUtils;
 import org.chromium.base.PathUtils;
@@ -65,8 +64,7 @@
  * Unit tests for {@link org.chromium.chrome.browser.ChromeBackupAgent}.
  */
 @RunWith(LocalRobolectricTestRunner.class)
-@Config(manifest = Config.NONE, application = BaseChromiumApplication.class,
-        shadows = {ChromeBackupAgentTest.BackupManagerShadow.class})
+@Config(manifest = Config.NONE, shadows = {ChromeBackupAgentTest.BackupManagerShadow.class})
 public class ChromeBackupAgentTest {
     /**
      * Shadow to allow counting of dataChanged calls.
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/customtabs/NavigationInfoCaptureTriggerTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/customtabs/NavigationInfoCaptureTriggerTest.java
new file mode 100644
index 0000000..d9365de
--- /dev/null
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/customtabs/NavigationInfoCaptureTriggerTest.java
@@ -0,0 +1,155 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.chrome.browser.customtabs;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.clearInvocations;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.robolectric.annotation.Config;
+import org.robolectric.shadows.ShadowLooper;
+
+import org.chromium.base.Callback;
+import org.chromium.base.test.util.Feature;
+import org.chromium.chrome.browser.tab.Tab;
+import org.chromium.testing.local.LocalRobolectricTestRunner;
+
+import java.util.concurrent.TimeUnit;
+
+/**
+ * Tests for {@link NavigationInfoCaptureTrigger}.
+ */
+@RunWith(LocalRobolectricTestRunner.class)
+@Config(manifest = Config.NONE)
+public class NavigationInfoCaptureTriggerTest {
+    @Mock
+    private Callback<Tab> mDelegate;
+    private NavigationInfoCaptureTrigger mTrigger;
+
+    @Before
+    public void setUp() {
+        MockitoAnnotations.initMocks(this);
+
+        mTrigger = new NavigationInfoCaptureTrigger(mDelegate);
+    }
+
+    /**
+     * Tests the normal flow where onload is called, then first meaningful paint happens soon
+     * after. We want the capture to trigger after first meaningful paint.
+     */
+    @Test
+    @Feature({"CustomTabs"})
+    public void testNormalFlow() {
+        mTrigger.onLoadFinished(null);
+
+        // If we run everything on the Looper, the backup onload capture will trigger. Therefore
+        // run long enough for the primary onload to trigger.
+        ShadowLooper.idleMainLooper(2, TimeUnit.SECONDS);
+        verify(mDelegate, times(0)).onResult(any());
+
+        mTrigger.onFirstMeaningfulPaint(null);
+        verifyCaptured(1);
+
+        mTrigger.onHide(null);
+        verifyCaptured(1);
+    }
+
+    /**
+     * Tests the flow where first meaningful paint is called before onload. The screen should only
+     * be captured once, after the first meaningful paint and onload.
+     */
+    @Test
+    @Feature({"CustomTabs"})
+    public void testDelayedOnload() {
+        mTrigger.onFirstMeaningfulPaint(null);
+        verifyCaptured(0);
+
+        mTrigger.onLoadFinished(null);
+        verifyCaptured(1);
+
+        mTrigger.onHide(null);
+        verifyCaptured(1);
+    }
+
+    /**
+     * Tests the flow where first meaningful paint and onload don't occur and we capture during
+     * on hide as a backup.
+     */
+    @Test
+    @Feature({"CustomTabs"})
+    public void testOnHide() {
+        mTrigger.onHide(null);
+        verifyCaptured(1);
+    }
+
+    /**
+     * Tests that the backup onload trigger works.
+     */
+    @Test
+    @Feature({"CustomTabs"})
+    public void testBackupOnload() {
+        mTrigger.onLoadFinished(null);
+
+        ShadowLooper.idleMainLooper(2, TimeUnit.SECONDS);
+        verify(mDelegate, times(0)).onResult(any());
+
+        verifyCaptured(1);
+    }
+
+    /**
+     * Tests that pending capture tasks are cancelled when the page navigates.
+     */
+    @Test
+    @Feature({"CustomTabs"})
+    public void testCancelOnNavigation() {
+        mTrigger.onLoadFinished(null);
+        mTrigger.onFirstMeaningfulPaint(null);
+
+        mTrigger.onNewNavigation();
+        verifyCaptured(0);
+    }
+
+    /**
+     * Tests that navigation resets the state.
+     */
+    @Test
+    @Feature({"CustomTabs"})
+    public void testResetOnNavigation() {
+        testNormalFlow();
+
+        mTrigger.onNewNavigation();
+
+        clearInvocations(mDelegate); // Clears the mock so the verifies in the original test work.
+        testNormalFlow();
+
+        mTrigger.onNewNavigation();
+
+        clearInvocations(mDelegate);
+        testDelayedOnload();
+    }
+
+    /**
+     * Tests that we capture only on the first FMP.
+     */
+    @Test
+    @Feature({"CustomTabs"})
+    public void testMultipleFmps() {
+        mTrigger.onLoadFinished(null);
+        mTrigger.onFirstMeaningfulPaint(null);
+        mTrigger.onFirstMeaningfulPaint(null);
+        verifyCaptured(1);
+    }
+
+    private void verifyCaptured(int times) {
+        ShadowLooper.runUiThreadTasksIncludingDelayedTasks();
+        verify(mDelegate, times(times)).onResult(any());
+    }
+}
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/download/DownloadSharedPreferenceEntryTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/download/DownloadSharedPreferenceEntryTest.java
index c0006e7a..84d3ac6c 100644
--- a/chrome/android/junit/src/org/chromium/chrome/browser/download/DownloadSharedPreferenceEntryTest.java
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/download/DownloadSharedPreferenceEntryTest.java
@@ -13,7 +13,6 @@
 import org.robolectric.annotation.Config;
 import org.robolectric.shadows.multidex.ShadowMultiDex;
 
-import org.chromium.base.BaseChromiumApplication;
 import org.chromium.base.test.BaseRobolectricTestRunner;
 import org.chromium.base.test.util.Feature;
 import org.chromium.components.offline_items_collection.ContentId;
@@ -23,8 +22,7 @@
 
 /** Unit tests for {@link DownloadSharedPreferenceEntry}. */
 @RunWith(BaseRobolectricTestRunner.class)
-@Config(manifest = Config.NONE, application = BaseChromiumApplication.class,
-        shadows = {ShadowMultiDex.class})
+@Config(manifest = Config.NONE, shadows = {ShadowMultiDex.class})
 public class DownloadSharedPreferenceEntryTest {
     private String newUUID() {
         return UUID.randomUUID().toString();
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/firstrun/FirstRunFlowSequencerTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/firstrun/FirstRunFlowSequencerTest.java
index d18b70b..ee00d48 100644
--- a/chrome/android/junit/src/org/chromium/chrome/browser/firstrun/FirstRunFlowSequencerTest.java
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/firstrun/FirstRunFlowSequencerTest.java
@@ -22,7 +22,6 @@
 import org.robolectric.annotation.Config;
 import org.robolectric.shadows.multidex.ShadowMultiDex;
 
-import org.chromium.base.BaseChromiumApplication;
 import org.chromium.base.test.BaseRobolectricTestRunner;
 import org.chromium.base.test.util.Feature;
 
@@ -31,8 +30,7 @@
  * first run.
  */
 @RunWith(BaseRobolectricTestRunner.class)
-@Config(manifest = Config.NONE, application = BaseChromiumApplication.class,
-        shadows = {ShadowMultiDex.class})
+@Config(manifest = Config.NONE, shadows = {ShadowMultiDex.class})
 public class FirstRunFlowSequencerTest {
     /** Information for Google OS account */
     private static final String GOOGLE_ACCOUNT_TYPE = "com.google";
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/media/remote/AbstractMediaRouteControllerTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/media/remote/AbstractMediaRouteControllerTest.java
index dda6e0c..a13701a 100644
--- a/chrome/android/junit/src/org/chromium/chrome/browser/media/remote/AbstractMediaRouteControllerTest.java
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/media/remote/AbstractMediaRouteControllerTest.java
@@ -42,7 +42,6 @@
 import org.robolectric.shadows.multidex.ShadowMultiDex;
 import org.robolectric.util.ReflectionHelpers;
 
-import org.chromium.base.BaseChromiumApplication;
 import org.chromium.base.CommandLine;
 import org.chromium.base.test.BaseRobolectricTestRunner;
 import org.chromium.base.test.util.Feature;
@@ -51,7 +50,7 @@
 
 /** Tests for {@link AbstractMediaRouteController}. */
 @RunWith(BaseRobolectricTestRunner.class)
-@Config(manifest = Config.NONE, application = BaseChromiumApplication.class,
+@Config(manifest = Config.NONE,
         shadows = {AbstractMediaRouteControllerTest.ShadowMediaRouter.class, ShadowMultiDex.class})
 public class AbstractMediaRouteControllerTest {
     /** Reset the environment before each test. */
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/media/ui/MediaNotificationActionsUpdatedTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/media/ui/MediaNotificationActionsUpdatedTest.java
index 258590b6..e2ed4d8 100644
--- a/chrome/android/junit/src/org/chromium/chrome/browser/media/ui/MediaNotificationActionsUpdatedTest.java
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/media/ui/MediaNotificationActionsUpdatedTest.java
@@ -16,7 +16,6 @@
 import org.junit.runner.RunWith;
 import org.robolectric.annotation.Config;
 
-import org.chromium.base.BaseChromiumApplication;
 import org.chromium.base.test.BaseRobolectricTestRunner;
 import org.chromium.blink.mojom.MediaSessionAction;
 import org.chromium.chrome.R;
@@ -30,7 +29,7 @@
  * change or the tab navigates.
  */
 @RunWith(BaseRobolectricTestRunner.class)
-@Config(manifest = Config.NONE, application = BaseChromiumApplication.class,
+@Config(manifest = Config.NONE,
         // Remove this after updating to a version of Robolectric that supports
         // notification channel creation. crbug.com/774315
         sdk = Build.VERSION_CODES.N_MR1,
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/media/ui/MediaNotificationFaviconTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/media/ui/MediaNotificationFaviconTest.java
index 6e5d3339..ce24ab7 100644
--- a/chrome/android/junit/src/org/chromium/chrome/browser/media/ui/MediaNotificationFaviconTest.java
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/media/ui/MediaNotificationFaviconTest.java
@@ -19,7 +19,6 @@
 import org.junit.runner.RunWith;
 import org.robolectric.annotation.Config;
 
-import org.chromium.base.BaseChromiumApplication;
 import org.chromium.base.BaseSwitches;
 import org.chromium.base.CommandLine;
 import org.chromium.base.test.BaseRobolectricTestRunner;
@@ -33,7 +32,7 @@
  * not displayed on Android Go devices.
  */
 @RunWith(BaseRobolectricTestRunner.class)
-@Config(manifest = Config.NONE, application = BaseChromiumApplication.class,
+@Config(manifest = Config.NONE,
         // Remove this after updating to a version of Robolectric that supports
         // notification channel creation. crbug.com/774315
         sdk = Build.VERSION_CODES.N_MR1,
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/media/ui/MediaNotificationManagerNotificationTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/media/ui/MediaNotificationManagerNotificationTest.java
index 3269501..ff283b9 100644
--- a/chrome/android/junit/src/org/chromium/chrome/browser/media/ui/MediaNotificationManagerNotificationTest.java
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/media/ui/MediaNotificationManagerNotificationTest.java
@@ -22,7 +22,6 @@
 import org.robolectric.annotation.Config;
 import org.robolectric.shadows.ShadowNotification;
 
-import org.chromium.base.BaseChromiumApplication;
 import org.chromium.base.test.BaseRobolectricTestRunner;
 import org.chromium.content_public.common.MediaMetadata;
 
@@ -31,7 +30,7 @@
  * NotificationManager.
  */
 @RunWith(BaseRobolectricTestRunner.class)
-@Config(manifest = Config.NONE, application = BaseChromiumApplication.class,
+@Config(manifest = Config.NONE,
         // Remove this after updating to a version of Robolectric that supports
         // notification channel creation. crbug.com/774315
         sdk = Build.VERSION_CODES.N_MR1, shadows = MediaNotificationTestShadowResources.class)
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/media/ui/MediaNotificationManagerServiceActionsTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/media/ui/MediaNotificationManagerServiceActionsTest.java
index e9fb5835..f291555 100644
--- a/chrome/android/junit/src/org/chromium/chrome/browser/media/ui/MediaNotificationManagerServiceActionsTest.java
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/media/ui/MediaNotificationManagerServiceActionsTest.java
@@ -19,7 +19,6 @@
 import org.junit.runner.RunWith;
 import org.robolectric.annotation.Config;
 
-import org.chromium.base.BaseChromiumApplication;
 import org.chromium.base.test.BaseRobolectricTestRunner;
 import org.chromium.blink.mojom.MediaSessionAction;
 import org.chromium.chrome.browser.media.ui.MediaNotificationManager.ListenerService;
@@ -29,7 +28,7 @@
  * correctly.
  */
 @RunWith(BaseRobolectricTestRunner.class)
-@Config(manifest = Config.NONE, application = BaseChromiumApplication.class,
+@Config(manifest = Config.NONE,
         shadows = {MediaNotificationTestShadowResources.class,
                 MediaNotificationTestShadowNotificationManager.class})
 public class MediaNotificationManagerServiceActionsTest extends MediaNotificationManagerTestBase {
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/media/ui/MediaNotificationManagerServiceLifecycleTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/media/ui/MediaNotificationManagerServiceLifecycleTest.java
index 86b0959..7107b71a 100644
--- a/chrome/android/junit/src/org/chromium/chrome/browser/media/ui/MediaNotificationManagerServiceLifecycleTest.java
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/media/ui/MediaNotificationManagerServiceLifecycleTest.java
@@ -31,7 +31,6 @@
 import org.mockito.InOrder;
 import org.robolectric.annotation.Config;
 
-import org.chromium.base.BaseChromiumApplication;
 import org.chromium.base.test.BaseRobolectricTestRunner;
 import org.chromium.chrome.browser.media.ui.MediaNotificationManager.ListenerService;
 import org.chromium.chrome.browser.notifications.NotificationUmaTracker;
@@ -45,7 +44,7 @@
  * correctly.
  */
 @RunWith(BaseRobolectricTestRunner.class)
-@Config(manifest = Config.NONE, application = BaseChromiumApplication.class,
+@Config(manifest = Config.NONE,
         // Remove this after updating to a version of Robolectric that supports
         // notification channel creation. crbug.com/774315
         sdk = Build.VERSION_CODES.N_MR1,
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/media/ui/MediaNotificationManagerThrottlerTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/media/ui/MediaNotificationManagerThrottlerTest.java
index a44d6d0..c1e7e3fd 100644
--- a/chrome/android/junit/src/org/chromium/chrome/browser/media/ui/MediaNotificationManagerThrottlerTest.java
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/media/ui/MediaNotificationManagerThrottlerTest.java
@@ -20,7 +20,6 @@
 import org.junit.runner.RunWith;
 import org.robolectric.annotation.Config;
 
-import org.chromium.base.BaseChromiumApplication;
 import org.chromium.base.test.BaseRobolectricTestRunner;
 
 /**
@@ -28,7 +27,7 @@
  * correctly.
  */
 @RunWith(BaseRobolectricTestRunner.class)
-@Config(manifest = Config.NONE, application = BaseChromiumApplication.class,
+@Config(manifest = Config.NONE,
         // Remove this after updating to a version of Robolectric that supports
         // notification channel creation. crbug.com/774315
         sdk = Build.VERSION_CODES.N_MR1, shadows = {MediaNotificationTestShadowResources.class})
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/media/ui/MediaNotificationTitleUpdatedTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/media/ui/MediaNotificationTitleUpdatedTest.java
index ec24e302..a6ed97a 100644
--- a/chrome/android/junit/src/org/chromium/chrome/browser/media/ui/MediaNotificationTitleUpdatedTest.java
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/media/ui/MediaNotificationTitleUpdatedTest.java
@@ -20,7 +20,6 @@
 import org.robolectric.annotation.Config;
 import org.robolectric.shadows.ShadowNotification;
 
-import org.chromium.base.BaseChromiumApplication;
 import org.chromium.base.test.BaseRobolectricTestRunner;
 import org.chromium.chrome.R;
 import org.chromium.chrome.browser.media.ui.MediaNotificationManager.ListenerService;
@@ -31,7 +30,7 @@
  * MediaMetadata gets updated.
  */
 @RunWith(BaseRobolectricTestRunner.class)
-@Config(manifest = Config.NONE, application = BaseChromiumApplication.class,
+@Config(manifest = Config.NONE,
         // Remove this after updating to a version of Robolectric that supports
         // notification channel creation. crbug.com/774315
         sdk = Build.VERSION_CODES.N_MR1,
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/offlinepages/ClientIdTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/offlinepages/ClientIdTest.java
index 07cd1f75..a7d20e0 100644
--- a/chrome/android/junit/src/org/chromium/chrome/browser/offlinepages/ClientIdTest.java
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/offlinepages/ClientIdTest.java
@@ -13,7 +13,6 @@
 import org.robolectric.annotation.Config;
 import org.robolectric.shadows.multidex.ShadowMultiDex;
 
-import org.chromium.base.BaseChromiumApplication;
 import org.chromium.base.test.BaseRobolectricTestRunner;
 import org.chromium.base.test.util.Feature;
 import org.chromium.components.bookmarks.BookmarkId;
@@ -23,8 +22,7 @@
  * Unit tests for ClientId.
  */
 @RunWith(BaseRobolectricTestRunner.class)
-@Config(manifest = Config.NONE, application = BaseChromiumApplication.class,
-        shadows = {ShadowMultiDex.class})
+@Config(manifest = Config.NONE, shadows = {ShadowMultiDex.class})
 public class ClientIdTest {
     private static final long INVALID_BOOKMARK_ID = -1;
     private static final long TEST_BOOKMARK_ID = 42;
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/offlinepages/OfflinePageBridgeUnitTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/offlinepages/OfflinePageBridgeUnitTest.java
index b007768f..5c7060a2 100644
--- a/chrome/android/junit/src/org/chromium/chrome/browser/offlinepages/OfflinePageBridgeUnitTest.java
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/offlinepages/OfflinePageBridgeUnitTest.java
@@ -24,7 +24,6 @@
 import org.robolectric.annotation.Config;
 import org.robolectric.shadows.multidex.ShadowMultiDex;
 
-import org.chromium.base.BaseChromiumApplication;
 import org.chromium.base.Callback;
 import org.chromium.base.test.BaseRobolectricTestRunner;
 import org.chromium.base.test.util.Feature;
@@ -37,8 +36,7 @@
  * Unit tests for OfflinePageUtils.
  */
 @RunWith(BaseRobolectricTestRunner.class)
-@Config(manifest = Config.NONE, application = BaseChromiumApplication.class,
-        shadows = {ShadowMultiDex.class})
+@Config(manifest = Config.NONE, shadows = {ShadowMultiDex.class})
 public class OfflinePageBridgeUnitTest {
     private OfflinePageBridge mBridge;
 
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/offlinepages/OfflinePageTabObserverTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/offlinepages/OfflinePageTabObserverTest.java
index 6b044e1..6378a76 100644
--- a/chrome/android/junit/src/org/chromium/chrome/browser/offlinepages/OfflinePageTabObserverTest.java
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/offlinepages/OfflinePageTabObserverTest.java
@@ -25,7 +25,6 @@
 import org.robolectric.annotation.Config;
 import org.robolectric.shadows.multidex.ShadowMultiDex;
 
-import org.chromium.base.BaseChromiumApplication;
 import org.chromium.base.test.BaseRobolectricTestRunner;
 import org.chromium.base.test.util.Feature;
 import org.chromium.chrome.browser.ChromeActivity;
@@ -38,8 +37,7 @@
  * Unit tests for OfflinePageUtils.
  */
 @RunWith(BaseRobolectricTestRunner.class)
-@Config(manifest = Config.NONE, application = BaseChromiumApplication.class,
-        shadows = {ShadowMultiDex.class})
+@Config(manifest = Config.NONE, shadows = {ShadowMultiDex.class})
 public class OfflinePageTabObserverTest {
     // Using a null tab, as it cannot be mocked. TabHelper will help return proper mocked responses.
     private static final int TAB_ID = 77;
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/offlinepages/OfflinePageUtilsUnitTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/offlinepages/OfflinePageUtilsUnitTest.java
index 676e4472..a317201 100644
--- a/chrome/android/junit/src/org/chromium/chrome/browser/offlinepages/OfflinePageUtilsUnitTest.java
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/offlinepages/OfflinePageUtilsUnitTest.java
@@ -26,7 +26,6 @@
 import org.robolectric.annotation.Implements;
 import org.robolectric.shadows.multidex.ShadowMultiDex;
 
-import org.chromium.base.BaseChromiumApplication;
 import org.chromium.base.test.BaseRobolectricTestRunner;
 import org.chromium.base.test.util.Feature;
 import org.chromium.chrome.browser.profiles.Profile;
@@ -41,7 +40,7 @@
  * Unit tests for OfflinePageUtils.
  */
 @RunWith(BaseRobolectricTestRunner.class)
-@Config(manifest = Config.NONE, application = BaseChromiumApplication.class,
+@Config(manifest = Config.NONE,
         shadows = {OfflinePageUtilsUnitTest.WrappedEnvironment.class, ShadowMultiDex.class})
 public class OfflinePageUtilsUnitTest {
     @Mock
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/offlinepages/prefetch/OfflineNotificationBackgroundTaskUnitTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/offlinepages/prefetch/OfflineNotificationBackgroundTaskUnitTest.java
index 4f8db48..4df73bf 100644
--- a/chrome/android/junit/src/org/chromium/chrome/browser/offlinepages/prefetch/OfflineNotificationBackgroundTaskUnitTest.java
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/offlinepages/prefetch/OfflineNotificationBackgroundTaskUnitTest.java
@@ -40,7 +40,6 @@
 import org.robolectric.annotation.Config;
 import org.robolectric.shadows.multidex.ShadowMultiDex;
 
-import org.chromium.base.BaseChromiumApplication;
 import org.chromium.base.Callback;
 import org.chromium.base.ContextUtils;
 import org.chromium.base.library_loader.ProcessInitException;
@@ -64,8 +63,7 @@
 
 /** Unit tests for {@link OfflineNotificationBackgroundTask}. */
 @RunWith(BaseRobolectricTestRunner.class)
-@Config(manifest = Config.NONE, application = BaseChromiumApplication.class,
-        shadows = {ShadowMultiDex.class, ShadowDeviceConditions.class})
+@Config(manifest = Config.NONE, shadows = {ShadowMultiDex.class, ShadowDeviceConditions.class})
 public class OfflineNotificationBackgroundTaskUnitTest {
     /**
      * Fake of BackgroundTaskScheduler system service.
diff --git a/chrome/app/generated_resources.grd b/chrome/app/generated_resources.grd
index 8b0eb61d..780f61a74 100644
--- a/chrome/app/generated_resources.grd
+++ b/chrome/app/generated_resources.grd
@@ -347,11 +347,6 @@
         <message name="IDS_CONTENT_CONTEXT_INSPECTELEMENT" desc="The name of the Inspect Element command in the content area context menu">
           I&amp;nspect
         </message>
-        <if expr="is_macosx">
-            <message name="IDS_CONTENT_CONTEXT_LOOK_UP" desc="The name of the 'Look Up “string”' item in the content area context menu. To translate, launch /Applications/TextEdit.app in an appropriately localized version of OS X, right-click on the text entry area and use the translation from there.">
-              Look Up “<ph name="LOOKUP_STRING">$1<ex>orthogonal</ex></ph>”
-            </message>
-        </if>
         <if expr="not use_titlecase">
           <message name="IDS_CONTENT_CONTEXT_BACK" desc="The name of the Back command in the content area context menu">
             &amp;Back
@@ -8784,16 +8779,6 @@
         <message name="IDS_EDIT_CHECK_GRAMMAR_MAC" desc="The Mac menu item for check grammar with spelling in the edit menu.">
           Check Grammar With Spelling
         </message>
-        <!-- Edit::Speech submenu -->
-        <message name="IDS_SPEECH_MAC" desc="The Mac menu item for the 'Speech' submenu in the edit and context menu. To translate, launch /Applications/TextEdit.app in an appropriately localized version of OS X, open the Edit menu and use the translation from there.">
-          Speech
-        </message>
-        <message name="IDS_SPEECH_START_SPEAKING_MAC" desc="The Mac menu item for the 'Start Speaking' item from the 'Speech' submenu in edit and context menu. To translate, launch /Applications/TextEdit.app in an appropriately localized version of OS X, open the Edit menu and use the translation from there.">
-          Start Speaking
-        </message>
-        <message name="IDS_SPEECH_STOP_SPEAKING_MAC" desc="The Mac menu item for the 'Stop Speaking' item from the 'Speech' submenu in edit and context menu. To translate, launch /Applications/TextEdit.app in an appropriately localized version of OS X, open the Edit menu and use the translation from there.">
-          Stop Speaking
-        </message>
         <!-- View menu -->
         <message name="IDS_BOOKMARK_BAR_ALWAYS_SHOW_MAC" desc="The Mac menu item for having bookmark bar always visible in the view menu.">
           Always Show Bookmarks Bar
diff --git a/chrome/browser/browser_about_handler.cc b/chrome/browser/browser_about_handler.cc
index 9c61033..64d48d1 100644
--- a/chrome/browser/browser_about_handler.cc
+++ b/chrome/browser/browser_about_handler.cc
@@ -65,11 +65,8 @@
   if (host == chrome::kDeprecatedChromeUIHistoryFrameHost)
     host = chrome::kChromeUIHistoryHost;
 
-  // Replace cache with view-http-cache.
-  if (host == chrome::kChromeUICacheHost) {
-    host = content::kChromeUINetworkViewCacheHost;
-  // Replace sync with sync-internals (for legacy reasons).
-  } else if (host == chrome::kChromeUISyncHost) {
+  if (host == chrome::kChromeUISyncHost) {
+    // Replace sync with sync-internals (for legacy reasons).
     host = chrome::kChromeUISyncInternalsHost;
 // Redirect chrome://extensions, chrome://extensions-frame, and
 // chrome://settings/extensions all to chrome://extensions and forward path.
diff --git a/chrome/browser/browser_about_handler_unittest.cc b/chrome/browser/browser_about_handler_unittest.cc
index 7aa32e78..98ebaf7 100644
--- a/chrome/browser/browser_about_handler_unittest.cc
+++ b/chrome/browser/browser_about_handler_unittest.cc
@@ -61,8 +61,6 @@
         GURL(chrome_prefix + chrome::kChromeUIVersionHost)},
        {GURL(chrome_prefix + chrome::kChromeUIAboutHost),
         GURL(chrome_prefix + chrome::kChromeUIChromeURLsHost)},
-       {GURL(chrome_prefix + chrome::kChromeUICacheHost),
-        GURL(chrome_prefix + content::kChromeUINetworkViewCacheHost)},
        {GURL(chrome_prefix + chrome::kChromeUISignInInternalsHost),
         GURL(chrome_prefix + chrome::kChromeUISignInInternalsHost)},
        {GURL(chrome_prefix + chrome::kChromeUISyncHost),
diff --git a/chrome/browser/chrome_content_browser_client.cc b/chrome/browser/chrome_content_browser_client.cc
index 6216691..5df707de 100644
--- a/chrome/browser/chrome_content_browser_client.cc
+++ b/chrome/browser/chrome_content_browser_client.cc
@@ -324,6 +324,7 @@
 #include "chrome/browser/payments/payment_request_factory.h"
 #include "chrome/browser/search/instant_service.h"
 #include "chrome/browser/search/instant_service_factory.h"
+#include "chrome/browser/ui/search/new_tab_page_navigation_throttle.h"
 #include "chrome/common/importer/profile_import.mojom.h"
 #endif
 
@@ -3528,6 +3529,11 @@
       DevToolsWindow::MaybeCreateNavigationThrottle(handle);
   if (devtools_throttle)
     throttles.push_back(std::move(devtools_throttle));
+
+  std::unique_ptr<content::NavigationThrottle> new_tab_page_throttle =
+      NewTabPageNavigationThrottle::MaybeCreateThrottleFor(handle);
+  if (new_tab_page_throttle)
+    throttles.push_back(std::move(new_tab_page_throttle));
 #endif
 
   return throttles;
diff --git a/chrome/browser/chrome_content_browser_manifest_overlay.json b/chrome/browser/chrome_content_browser_manifest_overlay.json
index a27a4ed3..64ec0ff 100644
--- a/chrome/browser/chrome_content_browser_manifest_overlay.json
+++ b/chrome/browser/chrome_content_browser_manifest_overlay.json
@@ -50,7 +50,7 @@
         "patch": [ "patch_file" ],
         "pdf_compositor": [ "compositor" ],
         "profile_import": [ "import" ],
-        "profiling": [ "profiling" ],
+        "profiling": [ "profiling", "heap_profiler" ],
         "proxy_resolver": [ "factory" ],
         "preferences": [ "pref_client", "pref_control" ],
         "removable_storage_writer": [ "removable_storage_writer" ],
diff --git a/chrome/browser/chromeos/extensions/external_cache_impl.cc b/chrome/browser/chromeos/extensions/external_cache_impl.cc
index 53fbdc2..59b62a1 100644
--- a/chrome/browser/chromeos/extensions/external_cache_impl.cc
+++ b/chrome/browser/chromeos/extensions/external_cache_impl.cc
@@ -29,6 +29,7 @@
 #include "extensions/browser/updater/extension_downloader.h"
 #include "extensions/common/extension.h"
 #include "extensions/common/extension_urls.h"
+#include "extensions/common/manifest.h"
 #include "net/url_request/url_request_context_getter.h"
 
 namespace chromeos {
@@ -285,8 +286,8 @@
 
       if (update_url.is_valid()) {
         downloader_->AddPendingExtension(
-            entry.first, update_url, false, 0,
-            extensions::ManifestFetchData::FetchPriority::BACKGROUND);
+            entry.first, update_url, extensions::Manifest::EXTERNAL_POLICY,
+            false, 0, extensions::ManifestFetchData::FetchPriority::BACKGROUND);
       }
     }
 
diff --git a/chrome/browser/chromeos/login/users/chrome_user_manager_impl.cc b/chrome/browser/chromeos/login/users/chrome_user_manager_impl.cc
index 34cbff6..131208a9 100644
--- a/chrome/browser/chromeos/login/users/chrome_user_manager_impl.cc
+++ b/chrome/browser/chromeos/login/users/chrome_user_manager_impl.cc
@@ -1423,13 +1423,13 @@
 
 void ChromeUserManagerImpl::ScheduleResolveLocale(
     const std::string& locale,
-    const base::Closure& on_resolved_callback,
+    base::OnceClosure on_resolved_callback,
     std::string* out_resolved_locale) const {
   base::PostTaskWithTraitsAndReply(
       FROM_HERE, {base::MayBlock(), base::TaskPriority::BACKGROUND},
       base::BindOnce(ResolveLocale, locale,
                      base::Unretained(out_resolved_locale)),
-      on_resolved_callback);
+      std::move(on_resolved_callback));
 }
 
 bool ChromeUserManagerImpl::IsValidDefaultUserImageId(int image_index) const {
diff --git a/chrome/browser/chromeos/login/users/chrome_user_manager_impl.h b/chrome/browser/chromeos/login/users/chrome_user_manager_impl.h
index e4fff29..2493bddb 100644
--- a/chrome/browser/chromeos/login/users/chrome_user_manager_impl.h
+++ b/chrome/browser/chromeos/login/users/chrome_user_manager_impl.h
@@ -112,7 +112,7 @@
   const gfx::ImageSkia& GetResourceImagekiaNamed(int id) const override;
   base::string16 GetResourceStringUTF16(int string_id) const override;
   void ScheduleResolveLocale(const std::string& locale,
-                             const base::Closure& on_resolved_callback,
+                             base::OnceClosure on_resolved_callback,
                              std::string* out_resolved_locale) const override;
   bool IsValidDefaultUserImageId(int image_index) const override;
 
diff --git a/chrome/browser/chromeos/login/users/fake_chrome_user_manager.cc b/chrome/browser/chromeos/login/users/fake_chrome_user_manager.cc
index 636fcb6..d8d081f 100644
--- a/chrome/browser/chromeos/login/users/fake_chrome_user_manager.cc
+++ b/chrome/browser/chromeos/login/users/fake_chrome_user_manager.cc
@@ -5,6 +5,7 @@
 #include "chrome/browser/chromeos/login/users/fake_chrome_user_manager.h"
 
 #include <set>
+#include <utility>
 
 #include "base/callback.h"
 #include "base/command_line.h"
@@ -363,7 +364,7 @@
 
 void FakeChromeUserManager::ScheduleResolveLocale(
     const std::string& locale,
-    const base::Closure& on_resolved_callback,
+    base::OnceClosure on_resolved_callback,
     std::string* out_resolved_locale) const {
   NOTIMPLEMENTED();
   return;
diff --git a/chrome/browser/chromeos/login/users/fake_chrome_user_manager.h b/chrome/browser/chromeos/login/users/fake_chrome_user_manager.h
index 1d892c1..acbc5c6 100644
--- a/chrome/browser/chromeos/login/users/fake_chrome_user_manager.h
+++ b/chrome/browser/chromeos/login/users/fake_chrome_user_manager.h
@@ -124,7 +124,7 @@
   const gfx::ImageSkia& GetResourceImagekiaNamed(int id) const override;
   base::string16 GetResourceStringUTF16(int string_id) const override;
   void ScheduleResolveLocale(const std::string& locale,
-                             const base::Closure& on_resolved_callback,
+                             base::OnceClosure on_resolved_callback,
                              std::string* out_resolved_locale) const override;
   bool IsValidDefaultUserImageId(int image_index) const override;
   bool AreEphemeralUsersEnabled() const override;
diff --git a/chrome/browser/chromeos/login/users/mock_user_manager.cc b/chrome/browser/chromeos/login/users/mock_user_manager.cc
index 9ae5733..0d1de70 100644
--- a/chrome/browser/chromeos/login/users/mock_user_manager.cc
+++ b/chrome/browser/chromeos/login/users/mock_user_manager.cc
@@ -4,6 +4,8 @@
 
 #include "chrome/browser/chromeos/login/users/mock_user_manager.h"
 
+#include <utility>
+
 #include "base/task_runner.h"
 #include "chrome/browser/chromeos/login/users/fake_supervised_user_manager.h"
 #include "chrome/browser/chromeos/profiles/profile_helper.h"
@@ -77,6 +79,13 @@
   return supervised_user_manager_.get();
 }
 
+void MockUserManager::ScheduleResolveLocale(
+    const std::string& locale,
+    base::OnceClosure on_resolved_callback,
+    std::string* out_resolved_locale) const {
+  DoScheduleResolveLocale(locale, &on_resolved_callback, out_resolved_locale);
+}
+
 // Creates a new User instance.
 void MockUserManager::SetActiveUser(const AccountId& account_id) {
   ClearUserList();
diff --git a/chrome/browser/chromeos/login/users/mock_user_manager.h b/chrome/browser/chromeos/login/users/mock_user_manager.h
index 82ff9b9..18c76bc 100644
--- a/chrome/browser/chromeos/login/users/mock_user_manager.h
+++ b/chrome/browser/chromeos/login/users/mock_user_manager.h
@@ -118,9 +118,9 @@
   MOCK_METHOD1(OnUserRemoved, void(const AccountId&));
   MOCK_CONST_METHOD1(GetResourceImagekiaNamed, const gfx::ImageSkia&(int));
   MOCK_CONST_METHOD1(GetResourceStringUTF16, base::string16(int));
-  MOCK_CONST_METHOD3(ScheduleResolveLocale,
+  MOCK_CONST_METHOD3(DoScheduleResolveLocale,
                      void(const std::string&,
-                          const base::Closure&,
+                          base::OnceClosure*,
                           std::string*));
   MOCK_CONST_METHOD1(IsValidDefaultUserImageId, bool(int));
 
@@ -147,6 +147,13 @@
 
   bool ShouldReportUser(const std::string& user_id) const override;
 
+  // We cannot mock ScheduleResolveLocale directly because of
+  // base::OnceClosure's removed deleter. This is a trampoline to the actual
+  // mock.
+  void ScheduleResolveLocale(const std::string& locale,
+                             base::OnceClosure on_resolved_callback,
+                             std::string* out_resolved_locale) const override;
+
   // Sets a new User instance. Users previously created by this MockUserManager
   // become invalid.
   void SetActiveUser(const AccountId& account_id);
diff --git a/chrome/browser/chromeos/policy/remote_commands/device_command_fetch_status_job.cc b/chrome/browser/chromeos/policy/remote_commands/device_command_fetch_status_job.cc
index ecf3bcc1..7c248d3 100644
--- a/chrome/browser/chromeos/policy/remote_commands/device_command_fetch_status_job.cc
+++ b/chrome/browser/chromeos/policy/remote_commands/device_command_fetch_status_job.cc
@@ -19,14 +19,6 @@
 
 namespace policy {
 
-namespace {
-
-// Determines the time, measured from the time of issue, after which the command
-// queue will consider this command expired if the command has not been started.
-const int kCommandExpirationTimeInMinutes = 10;
-
-}  // namespace
-
 DeviceCommandFetchStatusJob::DeviceCommandFetchStatusJob() {}
 
 DeviceCommandFetchStatusJob::~DeviceCommandFetchStatusJob() {}
@@ -36,14 +28,6 @@
   return enterprise_management::RemoteCommand_Type_DEVICE_FETCH_STATUS;
 }
 
-base::TimeDelta DeviceCommandFetchStatusJob::GetCommmandTimeout() const {
-  return base::TimeDelta::FromMinutes(kCommandExpirationTimeInMinutes);
-}
-
-bool DeviceCommandFetchStatusJob::IsExpired(base::TimeTicks now) {
-  return now > issued_time() + GetCommmandTimeout();
-}
-
 void DeviceCommandFetchStatusJob::RunImpl(
     const CallbackWithResult& succeeded_callback,
     const CallbackWithResult& failed_callback) {
diff --git a/chrome/browser/chromeos/policy/remote_commands/device_command_fetch_status_job.h b/chrome/browser/chromeos/policy/remote_commands/device_command_fetch_status_job.h
index 6bcea0fb..39cd3ddb 100644
--- a/chrome/browser/chromeos/policy/remote_commands/device_command_fetch_status_job.h
+++ b/chrome/browser/chromeos/policy/remote_commands/device_command_fetch_status_job.h
@@ -19,11 +19,9 @@
 
   // RemoteCommandJob:
   enterprise_management::RemoteCommand_Type GetType() const override;
-  base::TimeDelta GetCommmandTimeout() const override;
 
  protected:
   // RemoteCommandJob:
-  bool IsExpired(base::TimeTicks now) override;
   void RunImpl(const CallbackWithResult& succeeded_callback,
                const CallbackWithResult& failed_callback) override;
 
diff --git a/chrome/browser/chromeos/policy/remote_commands/device_command_reboot_job.cc b/chrome/browser/chromeos/policy/remote_commands/device_command_reboot_job.cc
index 562ccb6..3d2ecce 100644
--- a/chrome/browser/chromeos/policy/remote_commands/device_command_reboot_job.cc
+++ b/chrome/browser/chromeos/policy/remote_commands/device_command_reboot_job.cc
@@ -20,14 +20,6 @@
 
 namespace policy {
 
-namespace {
-
-// Determines the time, measured from the time of issue, after which the command
-// queue will consider this command expired if the command has not been started.
-const int kCommandExpirationTimeInMinutes = 10;
-
-}  // namespace
-
 DeviceCommandRebootJob::DeviceCommandRebootJob(
     chromeos::PowerManagerClient* power_manager_client)
     : power_manager_client_(power_manager_client) {
@@ -42,11 +34,6 @@
   return enterprise_management::RemoteCommand_Type_DEVICE_REBOOT;
 }
 
-bool DeviceCommandRebootJob::IsExpired(base::TimeTicks now) {
-  return now > issued_time() + base::TimeDelta::FromMinutes(
-                                   kCommandExpirationTimeInMinutes);
-}
-
 void DeviceCommandRebootJob::RunImpl(
     const CallbackWithResult& succeeded_callback,
     const CallbackWithResult& failed_callback) {
@@ -73,8 +60,4 @@
                                         "policy device command");
 }
 
-base::TimeDelta DeviceCommandRebootJob::GetCommmandTimeout() const {
-  return base::TimeDelta::FromMinutes(kCommandExpirationTimeInMinutes);
-}
-
 }  // namespace policy
diff --git a/chrome/browser/chromeos/policy/remote_commands/device_command_reboot_job.h b/chrome/browser/chromeos/policy/remote_commands/device_command_reboot_job.h
index 892c5a3..f7ebe99 100644
--- a/chrome/browser/chromeos/policy/remote_commands/device_command_reboot_job.h
+++ b/chrome/browser/chromeos/policy/remote_commands/device_command_reboot_job.h
@@ -27,10 +27,8 @@
 
  private:
   // RemoteCommandJob:
-  bool IsExpired(base::TimeTicks now) override;
   void RunImpl(const CallbackWithResult& succeeded_callback,
                const CallbackWithResult& failed_callback) override;
-  base::TimeDelta GetCommmandTimeout() const override;
 
   chromeos::PowerManagerClient* power_manager_client_;
 
diff --git a/chrome/browser/chromeos/policy/remote_commands/device_command_screenshot_job.cc b/chrome/browser/chromeos/policy/remote_commands/device_command_screenshot_job.cc
index ac0f0bf..303cd23 100644
--- a/chrome/browser/chromeos/policy/remote_commands/device_command_screenshot_job.cc
+++ b/chrome/browser/chromeos/policy/remote_commands/device_command_screenshot_job.cc
@@ -26,10 +26,6 @@
 
 namespace {
 
-// Determines the time, measured from the time of issue, after which the command
-// queue will consider this command expired if the command has not been started.
-const int kCommandExpirationTimeInMinutes = 10;
-
 // String constant identifying the result field in the result payload.
 const char* const kResultFieldName = "result";
 
@@ -133,11 +129,6 @@
                      base::Passed(std::make_unique<Payload>(result_code))));
 }
 
-bool DeviceCommandScreenshotJob::IsExpired(base::TimeTicks now) {
-  return now > issued_time() + base::TimeDelta::FromMinutes(
-                                   kCommandExpirationTimeInMinutes);
-}
-
 bool DeviceCommandScreenshotJob::ParseCommandPayload(
     const std::string& command_payload) {
   std::unique_ptr<base::Value> root(
diff --git a/chrome/browser/chromeos/policy/remote_commands/device_command_screenshot_job.h b/chrome/browser/chromeos/policy/remote_commands/device_command_screenshot_job.h
index da124bd..b6ba279 100644
--- a/chrome/browser/chromeos/policy/remote_commands/device_command_screenshot_job.h
+++ b/chrome/browser/chromeos/policy/remote_commands/device_command_screenshot_job.h
@@ -103,7 +103,6 @@
   void OnFailure(UploadJob::ErrorCode error_code) override;
 
   // RemoteCommandJob:
-  bool IsExpired(base::TimeTicks now) override;
   bool ParseCommandPayload(const std::string& command_payload) override;
   void RunImpl(const CallbackWithResult& succeeded_callback,
                const CallbackWithResult& failed_callback) override;
diff --git a/chrome/browser/chromeos/policy/remote_commands/device_command_set_volume_job.cc b/chrome/browser/chromeos/policy/remote_commands/device_command_set_volume_job.cc
index 7437130..814826d 100644
--- a/chrome/browser/chromeos/policy/remote_commands/device_command_set_volume_job.cc
+++ b/chrome/browser/chromeos/policy/remote_commands/device_command_set_volume_job.cc
@@ -19,10 +19,6 @@
 
 namespace {
 
-// Determines the time, measured from the time of issue, after which the command
-// queue will consider this command expired if the command has not been started.
-const int kCommandExpirationTimeInMinutes = 10;
-
 const char kVolumeFieldName[] = "volume";
 
 }  // namespace
@@ -36,10 +32,6 @@
   return enterprise_management::RemoteCommand_Type_DEVICE_SET_VOLUME;
 }
 
-base::TimeDelta DeviceCommandSetVolumeJob::GetCommmandTimeout() const {
-  return base::TimeDelta::FromMinutes(kCommandExpirationTimeInMinutes);
-}
-
 bool DeviceCommandSetVolumeJob::ParseCommandPayload(
     const std::string& command_payload) {
   std::unique_ptr<base::Value> root(
@@ -56,11 +48,6 @@
   return true;
 }
 
-bool DeviceCommandSetVolumeJob::IsExpired(base::TimeTicks now) {
-  return now > issued_time() + base::TimeDelta::FromMinutes(
-                                   kCommandExpirationTimeInMinutes);
-}
-
 void DeviceCommandSetVolumeJob::RunImpl(
     const CallbackWithResult& succeeded_callback,
     const CallbackWithResult& failed_callback) {
diff --git a/chrome/browser/chromeos/policy/remote_commands/device_command_set_volume_job.h b/chrome/browser/chromeos/policy/remote_commands/device_command_set_volume_job.h
index 624147a..1cd9709 100644
--- a/chrome/browser/chromeos/policy/remote_commands/device_command_set_volume_job.h
+++ b/chrome/browser/chromeos/policy/remote_commands/device_command_set_volume_job.h
@@ -19,12 +19,10 @@
 
   // RemoteCommandJob:
   enterprise_management::RemoteCommand_Type GetType() const override;
-  base::TimeDelta GetCommmandTimeout() const override;
 
  protected:
   // RemoteCommandJob:
   bool ParseCommandPayload(const std::string& command_payload) override;
-  bool IsExpired(base::TimeTicks now) override;
   void RunImpl(const CallbackWithResult& succeeded_callback,
                const CallbackWithResult& failed_callback) override;
 
diff --git a/chrome/browser/chromeos/printing/printers_sync_bridge.cc b/chrome/browser/chromeos/printing/printers_sync_bridge.cc
index bbdeee5..46e06ca 100644
--- a/chrome/browser/chromeos/printing/printers_sync_bridge.cc
+++ b/chrome/browser/chromeos/printing/printers_sync_bridge.cc
@@ -20,6 +20,7 @@
 #include "components/sync/model/mutable_data_batch.h"
 #include "components/sync/protocol/model_type_state.pb.h"
 #include "components/sync/protocol/sync.pb.h"
+#include "specifics_translation.h"
 
 namespace chromeos {
 
@@ -326,7 +327,7 @@
 
   // Modify the printer in-place then notify the change processor.
   sync_pb::PrinterSpecifics* merged = iter->second.get();
-  merged->MergeFrom(*printer);
+  MergePrinterToSpecifics(*SpecificsToPrinter(*printer), merged);
   merged->set_updated_timestamp(base::Time::Now().ToJavaTime());
   CommitPrinterPut(*merged);
 
diff --git a/chrome/browser/component_updater/crl_set_component_installer.cc b/chrome/browser/component_updater/crl_set_component_installer.cc
index 9c331de..1325f44 100644
--- a/chrome/browser/component_updater/crl_set_component_installer.cc
+++ b/chrome/browser/component_updater/crl_set_component_installer.cc
@@ -17,7 +17,6 @@
 #include "components/component_updater/component_installer.h"
 #include "components/component_updater/component_updater_service.h"
 #include "net/cert/crl_set.h"
-#include "net/cert/crl_set_storage.h"
 #include "net/ssl/ssl_config_service.h"
 
 namespace component_updater {
@@ -37,7 +36,7 @@
   scoped_refptr<net::CRLSet> crl_set;
   std::string crl_set_bytes;
   if (!base::ReadFileToString(crl_path, &crl_set_bytes) ||
-      !net::CRLSetStorage::Parse(crl_set_bytes, &crl_set)) {
+      !net::CRLSet::Parse(crl_set_bytes, &crl_set)) {
     return;
   }
   net::SSLConfigService::SetCRLSetIfNewer(crl_set);
diff --git a/chrome/browser/extensions/all_urls_apitest.cc b/chrome/browser/extensions/all_urls_apitest.cc
index 9eb283099..dfb9a57 100644
--- a/chrome/browser/extensions/all_urls_apitest.cc
+++ b/chrome/browser/extensions/all_urls_apitest.cc
@@ -9,6 +9,8 @@
 #include "chrome/browser/extensions/extension_service.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/ui/browser.h"
+#include "chrome/browser/ui/search/local_ntp_test_utils.h"
+#include "chrome/common/url_constants.h"
 #include "chrome/test/base/ui_test_utils.h"
 #include "components/crx_file/id_util.h"
 #include "extensions/browser/extension_registry.h"
@@ -45,8 +47,15 @@
   }
 
   void NavigateAndWait(const std::string& url) {
-    ExtensionTestMessageListener listener_a("content script: " + url, false);
-    ExtensionTestMessageListener listener_b("execute: " + url, false);
+    std::string expected_url = url;
+    if (url == chrome::kChromeUINewTabURL) {
+      expected_url =
+          local_ntp_test_utils::GetFinalNtpUrl(browser()->profile()).spec();
+    }
+    ExtensionTestMessageListener listener_a("content script: " + expected_url,
+                                            false);
+    ExtensionTestMessageListener listener_b("execute: " + expected_url, false);
+
     ui_test_utils::NavigateToURL(browser(), GURL(url));
     ASSERT_TRUE(listener_a.WaitUntilSatisfied());
     ASSERT_TRUE(listener_b.WaitUntilSatisfied());
diff --git a/chrome/browser/extensions/api/dial/dial_api.cc b/chrome/browser/extensions/api/dial/dial_api.cc
index a5922dc..04c086f8 100644
--- a/chrome/browser/extensions/api/dial/dial_api.cc
+++ b/chrome/browser/extensions/api/dial/dial_api.cc
@@ -255,7 +255,7 @@
   }
 
   device_description_fetcher_ = std::make_unique<DeviceDescriptionFetcher>(
-      url, Profile::FromBrowserContext(browser_context())->GetRequestContext(),
+      url,
       base::BindOnce(&DialFetchDeviceDescriptionFunction::OnFetchComplete,
                      this),
       base::BindOnce(&DialFetchDeviceDescriptionFunction::OnFetchError, this));
diff --git a/chrome/browser/extensions/content_script_apitest.cc b/chrome/browser/extensions/content_script_apitest.cc
index 5bab7e6..8d97ebb 100644
--- a/chrome/browser/extensions/content_script_apitest.cc
+++ b/chrome/browser/extensions/content_script_apitest.cc
@@ -681,10 +681,8 @@
   ResultCatcher catcher;
   test_listener.Reply(std::string());
   ASSERT_TRUE(catcher.GetNextResult()) << catcher.message();
-  EXPECT_EQ(GURL("chrome://newtab"), browser()
-                                         ->tab_strip_model()
-                                         ->GetActiveWebContents()
-                                         ->GetLastCommittedURL());
+  EXPECT_TRUE(search::IsInstantNTP(
+      browser()->tab_strip_model()->GetActiveWebContents()));
   EXPECT_FALSE(
       did_script_inject(browser()->tab_strip_model()->GetActiveWebContents()));
 
diff --git a/chrome/browser/extensions/extension_url_rewrite_browsertest.cc b/chrome/browser/extensions/extension_url_rewrite_browsertest.cc
index fa788bd..c9ee6ba 100644
--- a/chrome/browser/extensions/extension_url_rewrite_browsertest.cc
+++ b/chrome/browser/extensions/extension_url_rewrite_browsertest.cc
@@ -10,6 +10,7 @@
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/browser_window.h"
 #include "chrome/browser/ui/location_bar/location_bar.h"
+#include "chrome/browser/ui/search/local_ntp_test_utils.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
 #include "chrome/browser/ui/webui/md_bookmarks/md_bookmarks_ui.h"
 #include "chrome/common/url_constants.h"
@@ -72,7 +73,12 @@
   void TestURLNotShown(const GURL& url) {
     ui_test_utils::NavigateToURL(browser(), url);
     EXPECT_EQ("", GetLocationBarText());
-    EXPECT_EQ(url, GetNavigationEntry()->GetVirtualURL());
+    if (url == chrome::kChromeUINewTabURL) {
+      EXPECT_EQ(local_ntp_test_utils::GetFinalNtpUrl(browser()->profile()),
+                GetNavigationEntry()->GetVirtualURL());
+    } else {
+      EXPECT_EQ(url, GetNavigationEntry()->GetVirtualURL());
+    }
   }
 };
 
diff --git a/chrome/browser/extensions/process_manager_browsertest.cc b/chrome/browser/extensions/process_manager_browsertest.cc
index 1fe523f3..323795a 100644
--- a/chrome/browser/extensions/process_manager_browsertest.cc
+++ b/chrome/browser/extensions/process_manager_browsertest.cc
@@ -730,8 +730,8 @@
   }
 }
 
-// Time-outs on Win (http://crbug.com/806684).
-#if defined(OS_WIN)
+// Time-outs on Win, fails on Mac and Linux (http://crbug.com/806684).
+#if defined(OS_WIN) || defined(OS_MACOSX) || defined(OS_LINUX)
 #define MAYBE_NestedURLNavigationsToExtensionBlocked \
   DISABLED_NestedURLNavigationsToExtensionBlocked
 #else
diff --git a/chrome/browser/extensions/updater/extension_updater.cc b/chrome/browser/extensions/updater/extension_updater.cc
index 473bb5a..014cacd 100644
--- a/chrome/browser/extensions/updater/extension_updater.cc
+++ b/chrome/browser/extensions/updater/extension_updater.cc
@@ -362,7 +362,7 @@
         continue;
       }
       if (downloader_->AddPendingExtension(
-              *iter, info->update_url(),
+              *iter, info->update_url(), info->install_source(),
               pending_extension_manager->IsPolicyReinstallForCorruptionExpected(
                   *iter),
               request_id, params.fetch_priority))
diff --git a/chrome/browser/extensions/updater/extension_updater_unittest.cc b/chrome/browser/extensions/updater/extension_updater_unittest.cc
index 4472848..0f6e925c 100644
--- a/chrome/browser/extensions/updater/extension_updater_unittest.cc
+++ b/chrome/browser/extensions/updater/extension_updater_unittest.cc
@@ -758,7 +758,7 @@
   }
 
   void TestUpdateUrlDataEmpty() {
-    const std::string id = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";
+    const std::string id(32, 'a');
     const std::string version = "1.0";
 
     // Make sure that an empty update URL data string does not cause a ap=
@@ -766,7 +766,7 @@
     std::unique_ptr<ManifestFetchData> fetch_data(
         CreateManifestFetchData(GURL("http://localhost/foo")));
     fetch_data->AddExtension(id, version, &kNeverPingedData, std::string(),
-                             std::string(),
+                             std::string(), std::string(),
                              ManifestFetchData::FetchPriority::BACKGROUND);
 
     std::map<std::string, std::string> params;
@@ -777,7 +777,7 @@
   }
 
   void TestUpdateUrlDataSimple() {
-    const std::string id = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";
+    const std::string id(32, 'a');
     const std::string version = "1.0";
 
     // Make sure that an update URL data string causes an appropriate ap=
@@ -785,7 +785,7 @@
     std::unique_ptr<ManifestFetchData> fetch_data(
         CreateManifestFetchData(GURL("http://localhost/foo")));
     fetch_data->AddExtension(id, version, &kNeverPingedData, "bar",
-                             std::string(),
+                             std::string(), std::string(),
                              ManifestFetchData::FetchPriority::BACKGROUND);
     std::map<std::string, std::string> params;
     VerifyQueryAndExtractParameters(fetch_data->full_url().query(), &params);
@@ -795,7 +795,7 @@
   }
 
   void TestUpdateUrlDataCompound() {
-    const std::string id = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";
+    const std::string id(32, 'a');
     const std::string version = "1.0";
 
     // Make sure that an update URL data string causes an appropriate ap=
@@ -803,7 +803,7 @@
     std::unique_ptr<ManifestFetchData> fetch_data(
         CreateManifestFetchData(GURL("http://localhost/foo")));
     fetch_data->AddExtension(id, version, &kNeverPingedData, "a=1&b=2&c",
-                             std::string(),
+                             std::string(), std::string(),
                              ManifestFetchData::FetchPriority::BACKGROUND);
     std::map<std::string, std::string> params;
     VerifyQueryAndExtractParameters(fetch_data->full_url().query(), &params);
@@ -891,7 +891,7 @@
   }
 
   void TestInstallSource() {
-    const std::string id = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";
+    const std::string id(32, 'a');
     const std::string version = "1.0";
     const std::string install_source = "instally";
 
@@ -899,7 +899,7 @@
     std::unique_ptr<ManifestFetchData> fetch_data(
         CreateManifestFetchData(GURL("http://localhost/foo")));
     fetch_data->AddExtension(id, version, &kNeverPingedData,
-                             kEmptyUpdateUrlData, install_source,
+                             kEmptyUpdateUrlData, install_source, std::string(),
                              ManifestFetchData::FetchPriority::BACKGROUND);
     std::map<std::string, std::string> params;
     VerifyQueryAndExtractParameters(fetch_data->full_url().query(), &params);
@@ -908,6 +908,24 @@
     EXPECT_EQ(install_source, params["installsource"]);
   }
 
+  void TestInstallLocation() {
+    const std::string id(32, 'a');
+    const std::string version = "1.0";
+    const std::string install_location = "external";
+
+    // Make sure that installedby= appears in the x= parameter.
+    std::unique_ptr<ManifestFetchData> fetch_data(
+        CreateManifestFetchData(GURL("http://localhost/foo")));
+    fetch_data->AddExtension(
+        id, version, &kNeverPingedData, kEmptyUpdateUrlData, std::string(),
+        install_location, ManifestFetchData::FetchPriority::BACKGROUND);
+    std::map<std::string, std::string> params;
+    VerifyQueryAndExtractParameters(fetch_data->full_url().query(), &params);
+    EXPECT_EQ(id, params["id"]);
+    EXPECT_EQ(version, params["v"]);
+    EXPECT_EQ(install_location, params["installedby"]);
+  }
+
   void TestDetermineUpdates() {
     TestingProfile profile;
     MockExtensionDownloaderDelegate delegate;
@@ -928,11 +946,11 @@
     const std::string id1 = crx_file::id_util::GenerateId("1");
     const std::string id2 = crx_file::id_util::GenerateId("2");
     fetch_data->AddExtension(id1, "1.0.0.0", &kNeverPingedData,
-                             kEmptyUpdateUrlData, std::string(),
+                             kEmptyUpdateUrlData, std::string(), std::string(),
                              ManifestFetchData::FetchPriority::BACKGROUND);
     AddParseResult(id1, "1.1", "http://localhost/e1_1.1.crx", &updates);
     fetch_data->AddExtension(id2, "2.0.0.0", &kNeverPingedData,
-                             kEmptyUpdateUrlData, std::string(),
+                             kEmptyUpdateUrlData, std::string(), std::string(),
                              ManifestFetchData::FetchPriority::BACKGROUND);
     AddParseResult(id2, "2.0.0.0", "http://localhost/e2_2.0.crx", &updates);
 
@@ -972,9 +990,9 @@
     std::list<std::string>::const_iterator it;
     for (it = ids_for_update_check.begin();
          it != ids_for_update_check.end(); ++it) {
-      fetch_data->AddExtension(*it, "1.0.0.0", &kNeverPingedData,
-                               kEmptyUpdateUrlData, std::string(),
-                               ManifestFetchData::FetchPriority::BACKGROUND);
+      fetch_data->AddExtension(
+          *it, "1.0.0.0", &kNeverPingedData, kEmptyUpdateUrlData, std::string(),
+          std::string(), ManifestFetchData::FetchPriority::BACKGROUND);
       AddParseResult(*it, "1.1", "http://localhost/e1_1.1.crx", &updates);
     }
 
@@ -1013,16 +1031,16 @@
         CreateManifestFetchData(kUpdateUrl));
     ManifestFetchData::PingData zeroDays(0, 0, true, 0);
     fetch1->AddExtension("1111", "1.0", &zeroDays, kEmptyUpdateUrlData,
-                         std::string(),
+                         std::string(), std::string(),
                          ManifestFetchData::FetchPriority::BACKGROUND);
     fetch2->AddExtension("2222", "2.0", &zeroDays, kEmptyUpdateUrlData,
-                         std::string(),
+                         std::string(), std::string(),
                          ManifestFetchData::FetchPriority::BACKGROUND);
     fetch3->AddExtension("3333", "3.0", &zeroDays, kEmptyUpdateUrlData,
-                         std::string(),
+                         std::string(), std::string(),
                          ManifestFetchData::FetchPriority::BACKGROUND);
     fetch4->AddExtension("4444", "4.0", &zeroDays, kEmptyUpdateUrlData,
-                         std::string(),
+                         std::string(), std::string(),
                          ManifestFetchData::FetchPriority::BACKGROUND);
 
     // This will start the first fetcher and queue the others. The next in queue
@@ -1156,7 +1174,7 @@
         CreateManifestFetchData(kUpdateUrl));
     ManifestFetchData::PingData zeroDays(0, 0, true, 0);
     fetch->AddExtension("1111", "1.0", &zeroDays, kEmptyUpdateUrlData,
-                        std::string(),
+                        std::string(), std::string(),
                         ManifestFetchData::FetchPriority::BACKGROUND);
 
     // This will start the first fetcher.
@@ -1185,7 +1203,7 @@
     // should not retry.
     fetch.reset(CreateManifestFetchData(kUpdateUrl));
     fetch->AddExtension("1111", "1.0", &zeroDays, kEmptyUpdateUrlData,
-                        std::string(),
+                        std::string(), std::string(),
                         ManifestFetchData::FetchPriority::BACKGROUND);
 
     // This will start the first fetcher.
@@ -1240,7 +1258,7 @@
 
     GURL test_url("http://localhost/extension.crx");
 
-    std::string id = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";
+    const std::string id(32, 'a');
     std::string hash;
     base::Version version("0.0.1");
     std::set<int> requests;
@@ -1350,7 +1368,7 @@
         &kNoBackoffPolicy);
 
     GURL test_url(base::StringPrintf("%s/extension.crx", url_prefix.c_str()));
-    std::string id = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";
+    const std::string id(32, 'a');
     std::string hash;
     base::Version version("0.0.1");
     std::set<int> requests;
@@ -1534,8 +1552,8 @@
     GURL url1("http://localhost/extension1.crx");
     GURL url2("http://localhost/extension2.crx");
 
-    std::string id1 = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";
-    std::string id2 = "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb";
+    const std::string id1(32, 'a');
+    const std::string id2(32, 'b');
 
     std::string hash1;
     std::string hash2;
@@ -1847,7 +1865,7 @@
     const Extension* extension = tmp[0].get();
     fetch_data->AddExtension(extension->id(), extension->VersionString(),
                              &kNeverPingedData, kEmptyUpdateUrlData,
-                             std::string(),
+                             std::string(), std::string(),
                              ManifestFetchData::FetchPriority::BACKGROUND);
     auto results = std::make_unique<UpdateManifestResults>();
     constexpr int kDaystartElapsedSeconds = 750;
@@ -1962,14 +1980,14 @@
       ManifestFetchData::FetchPriority data_priority,
       ManifestFetchData::FetchPriority extension_priority,
       ManifestFetchData::FetchPriority expected_priority) {
-    const std::string id = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";
+    const std::string id(32, 'a');
     const std::string version = "1.0";
 
     std::unique_ptr<ManifestFetchData> fetch_data(
         CreateManifestFetchData(GURL("http://localhost/foo"), data_priority));
     ASSERT_TRUE(fetch_data->AddExtension(id, version, &kNeverPingedData,
                                          std::string(), std::string(),
-                                         extension_priority));
+                                         std::string(), extension_priority));
     ASSERT_EQ(expected_priority, fetch_data->fetch_priority());
   }
 
@@ -2053,6 +2071,10 @@
   TestInstallSource();
 }
 
+TEST_F(ExtensionUpdaterTest, TestInstallLocation) {
+  TestInstallLocation();
+}
+
 TEST_F(ExtensionUpdaterTest, TestDetermineUpdates) {
   TestDetermineUpdates();
 }
@@ -2254,7 +2276,7 @@
   std::string id = crx_file::id_util::GenerateId("foo");
   EXPECT_CALL(delegate, GetPingDataForExtension(id, _)).WillOnce(Return(false));
   EXPECT_TRUE(downloader->AddPendingExtension(
-      id, GURL("http://example.com/update"), false, 0,
+      id, GURL("http://example.com/update"), Manifest::INTERNAL, false, 0,
       ManifestFetchData::FetchPriority::BACKGROUND));
   downloader->StartAllPending(NULL);
   Mock::VerifyAndClearExpectations(&delegate);
@@ -2263,14 +2285,14 @@
   // Extensions with invalid update URLs should be rejected.
   id = crx_file::id_util::GenerateId("foo2");
   EXPECT_FALSE(downloader->AddPendingExtension(
-      id, GURL("http:google.com:foo"), false, 0,
+      id, GURL("http:google.com:foo"), Manifest::INTERNAL, false, 0,
       ManifestFetchData::FetchPriority::BACKGROUND));
   downloader->StartAllPending(NULL);
   EXPECT_EQ(1u, ManifestFetchersCount(downloader.get()));
 
   // Extensions with empty IDs should be rejected.
   EXPECT_FALSE(downloader->AddPendingExtension(
-      std::string(), GURL(), false, 0,
+      std::string(), GURL(), Manifest::INTERNAL, false, 0,
       ManifestFetchData::FetchPriority::BACKGROUND));
   downloader->StartAllPending(NULL);
   EXPECT_EQ(1u, ManifestFetchersCount(downloader.get()));
@@ -2288,7 +2310,8 @@
   id = crx_file::id_util::GenerateId("foo3");
   EXPECT_CALL(delegate, GetPingDataForExtension(id, _)).WillOnce(Return(false));
   EXPECT_TRUE(downloader->AddPendingExtension(
-      id, GURL(), false, 0, ManifestFetchData::FetchPriority::BACKGROUND));
+      id, GURL(), Manifest::INTERNAL, false, 0,
+      ManifestFetchData::FetchPriority::BACKGROUND));
   downloader->StartAllPending(NULL);
   EXPECT_EQ(1u, ManifestFetchersCount(downloader.get()));
 
diff --git a/chrome/browser/media/router/DEPS b/chrome/browser/media/router/DEPS
new file mode 100644
index 0000000..288ba20
--- /dev/null
+++ b/chrome/browser/media/router/DEPS
@@ -0,0 +1,3 @@
+include_rules = [
+  "+services/network"
+]
diff --git a/chrome/browser/media/router/discovery/dial/device_description_fetcher.cc b/chrome/browser/media/router/discovery/dial/device_description_fetcher.cc
index 5f4e506..9e8c4b1 100644
--- a/chrome/browser/media/router/discovery/dial/device_description_fetcher.cc
+++ b/chrome/browser/media/router/discovery/dial/device_description_fetcher.cc
@@ -6,18 +6,18 @@
 
 #include "base/strings/string_util.h"
 #include "base/strings/stringprintf.h"
+#include "chrome/browser/browser_process.h"
 #include "chrome/browser/media/router/discovery/dial/dial_device_data.h"
-#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/net/system_network_context_manager.h"
 #include "content/public/browser/browser_thread.h"
 #include "net/base/load_flags.h"
 #include "net/http/http_response_headers.h"
 #include "net/http/http_status_code.h"
 #include "net/http/http_util.h"
 #include "net/traffic_annotation/network_traffic_annotation.h"
-#include "net/url_request/url_fetcher.h"
-#include "net/url_request/url_request_context_getter.h"
-
-using content::BrowserThread;
+#include "net/url_request/redirect_info.h"
+#include "services/network/public/cpp/resource_request.h"
+#include "services/network/public/cpp/simple_url_loader.h"
 
 constexpr char kApplicationUrlHeaderName[] = "Application-URL";
 constexpr int kMaxRetries = 3;
@@ -27,29 +27,10 @@
 
 namespace media_router {
 
-DeviceDescriptionFetcher::DeviceDescriptionFetcher(
-    const GURL& device_description_url,
-    net::URLRequestContextGetter* request_context,
-    base::OnceCallback<void(const DialDeviceDescriptionData&)> success_cb,
-    base::OnceCallback<void(const std::string&)> error_cb)
-    : device_description_url_(device_description_url),
-      request_context_(request_context),
-      success_cb_(std::move(success_cb)),
-      error_cb_(std::move(error_cb)) {
-  DCHECK(request_context_);
-  DCHECK(device_description_url_.is_valid());
-}
+namespace {
 
-DeviceDescriptionFetcher::~DeviceDescriptionFetcher() {
-  DCHECK(thread_checker_.CalledOnValidThread());
-}
-
-void DeviceDescriptionFetcher::Start() {
-  DCHECK(thread_checker_.CalledOnValidThread());
-  DCHECK(!fetcher_);
-
-  net::NetworkTrafficAnnotationTag traffic_annotation =
-      net::DefineNetworkTrafficAnnotation("dial_get_device_description", R"(
+constexpr net::NetworkTrafficAnnotationTag kTrafficAnnotation =
+    net::DefineNetworkTrafficAnnotation("dial_get_device_description", R"(
         semantics {
           sender: "DIAL"
           description:
@@ -78,51 +59,111 @@
             }
           }
         })");
-  // DIAL returns device descriptions via GET request.
-  fetcher_ =
-      net::URLFetcher::Create(kURLFetcherIDForTest, device_description_url_,
-                              net::URLFetcher::GET, this, traffic_annotation);
+
+void BindURLLoaderFactoryRequestOnUIThread(
+    network::mojom::URLLoaderFactoryRequest request) {
+  network::mojom::URLLoaderFactory* factory =
+      g_browser_process->system_network_context_manager()
+          ->GetURLLoaderFactory();
+  factory->Clone(std::move(request));
+}
+
+}  // namespace
+
+DeviceDescriptionFetcher::DeviceDescriptionFetcher(
+    const GURL& device_description_url,
+    base::OnceCallback<void(const DialDeviceDescriptionData&)> success_cb,
+    base::OnceCallback<void(const std::string&)> error_cb)
+    : device_description_url_(device_description_url),
+      success_cb_(std::move(success_cb)),
+      error_cb_(std::move(error_cb)) {
+  DCHECK(device_description_url_.is_valid());
+}
+
+DeviceDescriptionFetcher::~DeviceDescriptionFetcher() {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+}
+
+void DeviceDescriptionFetcher::Start() {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  DCHECK(!loader_);
+
+  auto request = std::make_unique<network::ResourceRequest>();
+  request->url = device_description_url_;
 
   // net::LOAD_BYPASS_PROXY: Proxies almost certainly hurt more cases than they
   //     help.
   // net::LOAD_DISABLE_CACHE: The request should not touch the cache.
   // net::LOAD_DO_NOT_{SAVE,SEND}_COOKIES: The request should not touch cookies.
   // net::LOAD_DO_NOT_SEND_AUTH_DATA: The request should not send auth data.
-  fetcher_->SetLoadFlags(net::LOAD_BYPASS_PROXY | net::LOAD_DISABLE_CACHE |
-                         net::LOAD_DO_NOT_SAVE_COOKIES |
-                         net::LOAD_DO_NOT_SEND_COOKIES |
-                         net::LOAD_DO_NOT_SEND_AUTH_DATA);
+  request->load_flags = net::LOAD_BYPASS_PROXY | net::LOAD_DISABLE_CACHE |
+                        net::LOAD_DO_NOT_SAVE_COOKIES |
+                        net::LOAD_DO_NOT_SEND_COOKIES |
+                        net::LOAD_DO_NOT_SEND_AUTH_DATA;
 
-  // Section 5.4 of the DIAL spec prohibits redirects.
-  fetcher_->SetStopOnRedirect(true);
+  loader_ =
+      network::SimpleURLLoader::Create(std::move(request), kTrafficAnnotation);
 
   // Allow the fetcher to retry on 5XX responses and ERR_NETWORK_CHANGED.
-  fetcher_->SetMaxRetriesOn5xx(kMaxRetries);
-  fetcher_->SetAutomaticallyRetryOnNetworkChanges(kMaxRetries);
+  loader_->SetRetryOptions(
+      kMaxRetries,
+      network::SimpleURLLoader::RetryMode::RETRY_ON_5XX |
+          network::SimpleURLLoader::RetryMode::RETRY_ON_NETWORK_CHANGE);
 
-  fetcher_->SetRequestContext(request_context_.get());
-  fetcher_->Start();
+  // Section 5.4 of the DIAL spec prohibits redirects.
+  // In practice, the callback will only get called once, since |loader_| will
+  // be deleted on redirect.
+  loader_->SetOnRedirectCallback(base::BindRepeating(
+      &DeviceDescriptionFetcher::ReportRedirectError, base::Unretained(this)));
+
+  StartDownload();
 }
 
-void DeviceDescriptionFetcher::OnURLFetchComplete(
-    const net::URLFetcher* source) {
-  DCHECK_EQ(fetcher_.get(), source);
+void DeviceDescriptionFetcher::StartDownload() {
+  // Bind the request to the system URLLoaderFactory obtained on UI thread.
+  // Currently this is the only way to guarantee a live URLLoaderFactory.
+  // TOOD(mmenke): Figure out a way to do this transparently on IO thread.
+  network::mojom::URLLoaderFactoryPtr loader_factory;
+  content::BrowserThread::PostTask(
+      content::BrowserThread::UI, FROM_HERE,
+      base::BindOnce(&BindURLLoaderFactoryRequestOnUIThread,
+                     mojo::MakeRequest(&loader_factory)));
+  loader_->DownloadToString(
+      loader_factory.get(),
+      base::BindOnce(&DeviceDescriptionFetcher::ProcessResponse,
+                     base::Unretained(this)),
+      kMaxDescriptionSizeBytes);
+}
 
-  if (source->GetResponseCode() != net::HTTP_OK) {
-    ReportError(
-        base::StringPrintf("HTTP %d: Unable to fetch device description",
-                           source->GetResponseCode()));
+void DeviceDescriptionFetcher::ProcessResponse(
+    std::unique_ptr<std::string> response) {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  if (loader_->NetError() != net::Error::OK) {
+    ReportError(base::StringPrintf(
+        "HTTP %d: Unable to fetch device description", loader_->NetError()));
     return;
   }
 
-  const net::HttpResponseHeaders* headers = source->GetResponseHeaders();
+  if (!response || response->empty()) {
+    ReportError("Missing or empty response");
+    return;
+  }
+
+  if (!base::IsStringUTF8(*response)) {
+    ReportError("Invalid response encoding");
+    return;
+  }
+
+  const network::ResourceResponseHead* response_info = loader_->ResponseInfo();
+  DCHECK(response_info);
 
   // NOTE: The uPnP spec requires devices to set a Content-Type: header of
   // text/xml; charset="utf-8" (sec 2.11).  However Chromecast (and possibly
   // other devices) do not comply, so specifically not checking this header.
   std::string app_url_header;
-  if (!headers->GetNormalizedHeader(kApplicationUrlHeaderName,
-                                    &app_url_header) ||
+  if (!response_info->headers ||
+      !response_info->headers->GetNormalizedHeader(kApplicationUrlHeaderName,
+                                                   &app_url_header) ||
       app_url_header.empty()) {
     ReportError("Missing or empty Application-URL:");
     return;
@@ -145,37 +186,17 @@
     app_url = GURL(app_url_header.substr(0, app_url_header.length() - 1));
   }
 
-  if (source->GetReceivedResponseContentLength() > kMaxDescriptionSizeBytes) {
-    ReportError("Response too large");
-    return;
-  }
-
-  std::string device_description;
-  if (!source->GetResponseAsString(&device_description) ||
-      device_description.empty()) {
-    ReportError("Missing or empty response");
-    return;
-  }
-
-  if (!base::IsStringUTF8(device_description)) {
-    ReportError("Invalid response encoding");
-    return;
-  }
-
-  std::move(success_cb_)
-      .Run(DialDeviceDescriptionData(std::move(device_description), app_url));
+  std::move(success_cb_).Run(DialDeviceDescriptionData(*response, app_url));
 }
 
-void DeviceDescriptionFetcher::OnURLFetchDownloadProgress(
-    const net::URLFetcher* source,
-    int64_t current,
-    int64_t total,
-    int64_t current_network_bytes) {}
-
-void DeviceDescriptionFetcher::OnURLFetchUploadProgress(
-    const net::URLFetcher* source,
-    int64_t current,
-    int64_t total) {}
+void DeviceDescriptionFetcher::ReportRedirectError(
+    const net::RedirectInfo& redirect_info,
+    const network::ResourceResponseHead& response_head) {
+  // Cancel the request.
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  loader_.reset();
+  ReportError("Redirect not allowed");
+}
 
 void DeviceDescriptionFetcher::ReportError(const std::string& message) {
   std::move(error_cb_).Run(message);
diff --git a/chrome/browser/media/router/discovery/dial/device_description_fetcher.h b/chrome/browser/media/router/discovery/dial/device_description_fetcher.h
index 4152d152..7278b076f 100644
--- a/chrome/browser/media/router/discovery/dial/device_description_fetcher.h
+++ b/chrome/browser/media/router/discovery/dial/device_description_fetcher.h
@@ -9,14 +9,17 @@
 #include <string>
 
 #include "base/callback.h"
-#include "base/threading/thread_checker.h"
-#include "content/public/browser/browser_thread.h"
-#include "net/url_request/url_fetcher_delegate.h"
+#include "base/sequence_checker.h"
+#include "services/network/public/mojom/url_loader_factory.mojom.h"
 #include "url/gurl.h"
 
 namespace net {
-class URLFetcher;
-class URLRequestContextGetter;
+struct RedirectInfo;
+}
+
+namespace network {
+class SimpleURLLoader;
+struct ResourceResponseHead;
 }
 
 namespace media_router {
@@ -27,47 +30,46 @@
 // a uPnP device description from a DIAL device.  If successful, |success_cb| is
 // invoked with the result; otherwise, |error_cb| is invoked with an error
 // reason.
-// This class is not thread safe.
-class DeviceDescriptionFetcher : public net::URLFetcherDelegate {
+// This class is not sequence safe.
+class DeviceDescriptionFetcher {
  public:
-  // Used to identify the net::URLFetcher instance for tests.
-  static constexpr int kURLFetcherIDForTest = 1;
-
-  // |request_context| is unowned; the caller must ensure that this object does
-  // not outlive it.
   DeviceDescriptionFetcher(
       const GURL& device_description_url,
-      net::URLRequestContextGetter* request_context,
       base::OnceCallback<void(const DialDeviceDescriptionData&)> success_cb,
       base::OnceCallback<void(const std::string&)> error_cb);
 
-  ~DeviceDescriptionFetcher() override;
+  virtual ~DeviceDescriptionFetcher();
 
   const GURL& device_description_url() { return device_description_url_; }
 
   void Start();
 
  private:
-  // net::URLFetcherDelegate implementation.
-  void OnURLFetchComplete(const net::URLFetcher* source) override;
-  void OnURLFetchDownloadProgress(const net::URLFetcher* source,
-                                  int64_t current,
-                                  int64_t total,
-                                  int64_t current_network_bytes) override;
-  void OnURLFetchUploadProgress(const net::URLFetcher* source,
-                                int64_t current,
-                                int64_t total) override;
+  friend class TestDeviceDescriptionFetcher;
+
+  // Starts the download on |loader_|.
+  virtual void StartDownload();
+
+  // Processes the response from the GET request and invoke the success or
+  // error callback.
+  void ProcessResponse(std::unique_ptr<std::string> response);
+
+  // Invokes the error callback due to a redirect that had occurred. Also
+  // aborts the request.
+  void ReportRedirectError(const net::RedirectInfo& redirect_info,
+                           const network::ResourceResponseHead& response_head);
 
   // Runs |error_cb_| with |message| and clears it.
   void ReportError(const std::string& message);
 
   const GURL device_description_url_;
-  const scoped_refptr<net::URLRequestContextGetter> request_context_;
-  base::ThreadChecker thread_checker_;
 
   base::OnceCallback<void(const DialDeviceDescriptionData&)> success_cb_;
   base::OnceCallback<void(const std::string&)> error_cb_;
-  std::unique_ptr<net::URLFetcher> fetcher_;
+  std::unique_ptr<network::SimpleURLLoader> loader_;
+
+  SEQUENCE_CHECKER(sequence_checker_);
+  DISALLOW_COPY_AND_ASSIGN(DeviceDescriptionFetcher);
 };
 
 }  // namespace media_router
diff --git a/chrome/browser/media/router/discovery/dial/device_description_fetcher_unittest.cc b/chrome/browser/media/router/discovery/dial/device_description_fetcher_unittest.cc
index c6138935..fe2bfbb 100644
--- a/chrome/browser/media/router/discovery/dial/device_description_fetcher_unittest.cc
+++ b/chrome/browser/media/router/discovery/dial/device_description_fetcher_unittest.cc
@@ -8,180 +8,192 @@
 #include "base/callback.h"
 #include "base/macros.h"
 #include "base/memory/ref_counted.h"
+#include "base/run_loop.h"
+#include "base/test/scoped_task_environment.h"
 #include "chrome/browser/media/router/discovery/dial/device_description_fetcher.h"
 #include "chrome/browser/media/router/discovery/dial/dial_device_data.h"
-#include "chrome/test/base/testing_profile.h"
-#include "content/public/test/test_browser_thread_bundle.h"
 #include "net/http/http_response_headers.h"
 #include "net/http/http_status_code.h"
 #include "net/url_request/test_url_fetcher_factory.h"
 #include "net/url_request/url_fetcher.h"
+#include "services/network/public/cpp/simple_url_loader.h"
+#include "services/network/test/test_url_loader_factory.h"
+#include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "url/gurl.h"
 
 namespace media_router {
 
+class TestDeviceDescriptionFetcher : public DeviceDescriptionFetcher {
+ public:
+  TestDeviceDescriptionFetcher(
+      const GURL& device_description_url,
+      base::OnceCallback<void(const DialDeviceDescriptionData&)> success_cb,
+      base::OnceCallback<void(const std::string&)> error_cb,
+      network::TestURLLoaderFactory* factory)
+      : DeviceDescriptionFetcher(device_description_url,
+                                 std::move(success_cb),
+                                 std::move(error_cb)),
+        factory_(factory) {}
+  ~TestDeviceDescriptionFetcher() override = default;
+
+  void StartDownload() override {
+    loader_->DownloadToString(
+        factory_,
+        base::BindOnce(&DeviceDescriptionFetcher::ProcessResponse,
+                       base::Unretained(this)),
+        256 * 1024);
+  }
+
+ private:
+  std::vector<network::mojom::URLLoaderFactoryRequest> requests_;
+  network::TestURLLoaderFactory* const factory_;
+};
+
 class DeviceDescriptionFetcherTest : public testing::Test {
  public:
   DeviceDescriptionFetcherTest() : url_("http://127.0.0.1/description.xml") {}
 
-  void TearDown() override {
-    EXPECT_FALSE(error_cb_);
-    EXPECT_FALSE(success_cb_);
-  }
-
   void ExpectSuccess(const GURL& expected_app_url,
                      const std::string& expected_description) {
-    success_cb_ = base::BindOnce(&DeviceDescriptionFetcherTest::OnSuccess,
-                                 base::Unretained(this), expected_app_url,
-                                 expected_description);
+    expected_app_url_ = expected_app_url;
+    expected_description_ = expected_description;
+    EXPECT_CALL(*this, DoOnSuccess());
   }
 
-  void ExpectError(const std::string& expected_message) {
-    error_cb_ = base::BindOnce(&DeviceDescriptionFetcherTest::OnError,
-                               base::Unretained(this), expected_message);
+  void ExpectError(const std::string expected_error) {
+    expected_error_ = expected_error;
+    EXPECT_CALL(*this, DoOnError());
   }
 
-  net::TestURLFetcher* StartRequest() {
-    fetcher_ = std::make_unique<DeviceDescriptionFetcher>(
-        url_, profile_.GetRequestContext(), std::move(success_cb_),
-        std::move(error_cb_));
+  void StartRequest() {
+    fetcher_ = std::make_unique<TestDeviceDescriptionFetcher>(
+        url_,
+        base::BindOnce(&DeviceDescriptionFetcherTest::OnSuccess,
+                       base::Unretained(this)),
+        base::BindOnce(&DeviceDescriptionFetcherTest::OnError,
+                       base::Unretained(this)),
+        &loader_factory_);
     fetcher_->Start();
-    return factory_.GetFetcherByID(
-        DeviceDescriptionFetcher::kURLFetcherIDForTest);
+    base::RunLoop().RunUntilIdle();
   }
 
  protected:
-  const content::TestBrowserThreadBundle thread_bundle_;
-  TestingProfile profile_;
-  const net::TestURLFetcherFactory factory_;
+  base::test::ScopedTaskEnvironment environment_;
   const GURL url_;
+  network::TestURLLoaderFactory loader_factory_;
   base::OnceCallback<void(const DialDeviceDescriptionData&)> success_cb_;
   base::OnceCallback<void(const std::string&)> error_cb_;
-  std::unique_ptr<DeviceDescriptionFetcher> fetcher_;
+  std::unique_ptr<TestDeviceDescriptionFetcher> fetcher_;
+  GURL expected_app_url_;
+  std::string expected_description_;
+  std::string expected_error_;
 
  private:
-  void OnSuccess(const GURL& expected_app_url,
-                 const std::string& expected_description,
-                 const DialDeviceDescriptionData& description) {
-    EXPECT_EQ(expected_app_url, description.app_url);
-    EXPECT_EQ(expected_description, description.device_description);
+  MOCK_METHOD0(DoOnSuccess, void());
+  MOCK_METHOD0(DoOnError, void());
+
+  void OnSuccess(const DialDeviceDescriptionData& description) {
+    EXPECT_EQ(expected_app_url_, description.app_url);
+    EXPECT_EQ(expected_description_, description.device_description);
+    DoOnSuccess();
   }
 
-  void OnError(const std::string& expected_message,
-               const std::string& message) {
-    EXPECT_TRUE(message.find(expected_message) == 0);
+  void OnError(const std::string& message) {
+    EXPECT_TRUE(message.find(expected_error_) == 0);
+    DoOnError();
   }
 
   DISALLOW_COPY_AND_ASSIGN(DeviceDescriptionFetcherTest);
 };
 
 TEST_F(DeviceDescriptionFetcherTest, FetchSuccessful) {
-  ExpectSuccess(GURL("http://127.0.0.1/apps"), "<xml>description</xml>");
-  net::TestURLFetcher* test_fetcher = StartRequest();
-
-  test_fetcher->set_response_code(net::HTTP_OK);
-  scoped_refptr<net::HttpResponseHeaders> headers =
-      new net::HttpResponseHeaders("");
-  headers->AddHeader("Application-URL: http://127.0.0.1/apps");
-  test_fetcher->set_response_headers(headers);
-  test_fetcher->SetResponseString("<xml>description</xml>");
-  test_fetcher->delegate()->OnURLFetchComplete(test_fetcher);
+  std::string body("<xml>description</xml>");
+  ExpectSuccess(GURL("http://127.0.0.1/apps"), body);
+  network::ResourceResponseHead head;
+  head.headers = base::MakeRefCounted<net::HttpResponseHeaders>("");
+  head.headers->AddHeader("Application-URL: http://127.0.0.1/apps");
+  network::URLLoaderCompletionStatus status;
+  status.decoded_body_length = body.size();
+  loader_factory_.AddResponse(url_, head, body, status);
+  StartRequest();
 }
 
 TEST_F(DeviceDescriptionFetcherTest, FetchSuccessfulAppUrlWithTrailingSlash) {
-  ExpectSuccess(GURL("http://127.0.0.1/apps"), "<xml>description</xml>");
-  net::TestURLFetcher* test_fetcher = StartRequest();
-
-  test_fetcher->set_response_code(net::HTTP_OK);
-  scoped_refptr<net::HttpResponseHeaders> headers =
-      new net::HttpResponseHeaders("");
-  headers->AddHeader("Application-URL: http://127.0.0.1/apps/");
-  test_fetcher->set_response_headers(headers);
-  test_fetcher->SetResponseString("<xml>description</xml>");
-  test_fetcher->delegate()->OnURLFetchComplete(test_fetcher);
+  std::string body("<xml>description</xml>");
+  ExpectSuccess(GURL("http://127.0.0.1/apps"), body);
+  network::ResourceResponseHead head;
+  head.headers = base::MakeRefCounted<net::HttpResponseHeaders>("");
+  head.headers->AddHeader("Application-URL: http://127.0.0.1/apps/");
+  network::URLLoaderCompletionStatus status;
+  status.decoded_body_length = body.size();
+  loader_factory_.AddResponse(url_, head, body, status);
+  StartRequest();
 }
 
 TEST_F(DeviceDescriptionFetcherTest, FetchFailsOnMissingDescription) {
   ExpectError("HTTP 404:");
-  net::TestURLFetcher* test_fetcher = StartRequest();
-
-  test_fetcher->set_response_code(net::HTTP_NOT_FOUND);
-  test_fetcher->delegate()->OnURLFetchComplete(test_fetcher);
+  loader_factory_.AddResponse(
+      url_, network::ResourceResponseHead(), "",
+      network::URLLoaderCompletionStatus(net::HTTP_NOT_FOUND));
+  StartRequest();
 }
 
 TEST_F(DeviceDescriptionFetcherTest, FetchFailsOnMissingAppUrl) {
+  std::string body("<xml>description</xml>");
   ExpectError("Missing or empty Application-URL:");
-  net::TestURLFetcher* test_fetcher = StartRequest();
-
-  test_fetcher->set_response_code(net::HTTP_OK);
-  scoped_refptr<net::HttpResponseHeaders> headers =
-      new net::HttpResponseHeaders("");
-  test_fetcher->set_response_headers(headers);
-  test_fetcher->delegate()->OnURLFetchComplete(test_fetcher);
+  network::URLLoaderCompletionStatus status;
+  status.decoded_body_length = body.size();
+  loader_factory_.AddResponse(url_, network::ResourceResponseHead(), body,
+                              status);
+  StartRequest();
 }
 
 TEST_F(DeviceDescriptionFetcherTest, FetchFailsOnEmptyAppUrl) {
   ExpectError("Missing or empty Application-URL:");
-  net::TestURLFetcher* test_fetcher = StartRequest();
-
-  test_fetcher->set_response_code(net::HTTP_OK);
-  scoped_refptr<net::HttpResponseHeaders> headers =
-      new net::HttpResponseHeaders("");
-  headers->AddHeader("Application-URL:");
-  test_fetcher->set_response_headers(headers);
-  test_fetcher->delegate()->OnURLFetchComplete(test_fetcher);
+  std::string body("<xml>description</xml>");
+  network::ResourceResponseHead head;
+  head.headers = base::MakeRefCounted<net::HttpResponseHeaders>("");
+  head.headers->AddHeader("Application-URL:");
+  network::URLLoaderCompletionStatus status;
+  status.decoded_body_length = body.size();
+  loader_factory_.AddResponse(url_, head, body, status);
+  StartRequest();
 }
 
 TEST_F(DeviceDescriptionFetcherTest, FetchFailsOnInvalidAppUrl) {
   ExpectError("Invalid Application-URL:");
-  net::TestURLFetcher* test_fetcher = StartRequest();
-
-  test_fetcher->set_response_code(net::HTTP_OK);
-  scoped_refptr<net::HttpResponseHeaders> headers =
-      new net::HttpResponseHeaders("");
-  headers->AddHeader("Application-URL: http://www.example.com");
-  test_fetcher->set_response_headers(headers);
-  test_fetcher->delegate()->OnURLFetchComplete(test_fetcher);
+  std::string body("<xml>description</xml>");
+  network::ResourceResponseHead head;
+  head.headers = base::MakeRefCounted<net::HttpResponseHeaders>("");
+  head.headers->AddHeader("Application-URL: http://www.example.com");
+  network::URLLoaderCompletionStatus status;
+  status.decoded_body_length = body.size();
+  loader_factory_.AddResponse(url_, head, body, status);
+  StartRequest();
 }
 
 TEST_F(DeviceDescriptionFetcherTest, FetchFailsOnEmptyDescription) {
   ExpectError("Missing or empty response");
-  net::TestURLFetcher* test_fetcher = StartRequest();
+  network::ResourceResponseHead head;
+  head.headers = base::MakeRefCounted<net::HttpResponseHeaders>("");
+  head.headers->AddHeader("Application-URL: http://127.0.0.1/apps");
 
-  test_fetcher->set_response_code(net::HTTP_OK);
-  scoped_refptr<net::HttpResponseHeaders> headers =
-      new net::HttpResponseHeaders("");
-  headers->AddHeader("Application-URL: http://127.0.0.1/apps");
-  test_fetcher->set_response_headers(headers);
-  test_fetcher->SetResponseString("");
-  test_fetcher->delegate()->OnURLFetchComplete(test_fetcher);
+  loader_factory_.AddResponse(url_, head, "",
+                              network::URLLoaderCompletionStatus());
+  StartRequest();
 }
 
 TEST_F(DeviceDescriptionFetcherTest, FetchFailsOnBadDescription) {
   ExpectError("Invalid response encoding");
-  net::TestURLFetcher* test_fetcher = StartRequest();
-
-  test_fetcher->set_response_code(net::HTTP_OK);
-  scoped_refptr<net::HttpResponseHeaders> headers =
-      new net::HttpResponseHeaders("");
-  headers->AddHeader("Application-URL: http://127.0.0.1/apps");
-  test_fetcher->set_response_headers(headers);
-  test_fetcher->SetResponseString("\xfc\x9c\xbf\x80\xbf\x80");
-  test_fetcher->delegate()->OnURLFetchComplete(test_fetcher);
-}
-
-TEST_F(DeviceDescriptionFetcherTest, FetchFailsOnResponseTooLarge) {
-  ExpectError("Response too large");
-  net::TestURLFetcher* test_fetcher = StartRequest();
-
-  test_fetcher->set_response_code(net::HTTP_OK);
-  scoped_refptr<net::HttpResponseHeaders> headers =
-      new net::HttpResponseHeaders("");
-  headers->AddHeader("Application-URL: http://127.0.0.1/apps");
-  test_fetcher->set_response_headers(headers);
-  test_fetcher->SetResponseString(std::string(262145, 'd'));
-  test_fetcher->delegate()->OnURLFetchComplete(test_fetcher);
+  std::string body("\xfc\x9c\xbf\x80\xbf\x80");
+  network::ResourceResponseHead head;
+  head.headers = base::MakeRefCounted<net::HttpResponseHeaders>("");
+  head.headers->AddHeader("Application-URL: http://127.0.0.1/apps");
+  network::URLLoaderCompletionStatus status;
+  status.decoded_body_length = body.size();
+  loader_factory_.AddResponse(url_, head, body, status);
+  StartRequest();
 }
 
 }  // namespace media_router
diff --git a/chrome/browser/media/router/discovery/dial/device_description_service.cc b/chrome/browser/media/router/discovery/dial/device_description_service.cc
index 97b68005..9e5d945a 100644
--- a/chrome/browser/media/router/discovery/dial/device_description_service.cc
+++ b/chrome/browser/media/router/discovery/dial/device_description_service.cc
@@ -104,11 +104,10 @@
     const DeviceDescriptionParseErrorCallback& error_cb)
     : success_cb_(success_cb),
       error_cb_(error_cb),
-      device_description_parser_(connector) {
-  DETACH_FROM_THREAD(thread_checker_);
-}
+      device_description_parser_(connector) {}
 
 DeviceDescriptionService::~DeviceDescriptionService() {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   if (pending_device_count_ > 0) {
     DLOG(WARNING) << "Fail to finish parsing " << pending_device_count_
                   << " devices.";
@@ -116,9 +115,8 @@
 }
 
 void DeviceDescriptionService::GetDeviceDescriptions(
-    const std::vector<DialDeviceData>& devices,
-    net::URLRequestContextGetter* request_context) {
-  DCHECK(thread_checker_.CalledOnValidThread());
+    const std::vector<DialDeviceData>& devices) {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
 
   std::map<std::string, std::unique_ptr<DeviceDescriptionFetcher>>
       existing_fetcher_map;
@@ -148,7 +146,7 @@
       continue;
     }
 
-    FetchDeviceDescription(device_data, request_context);
+    FetchDeviceDescription(device_data);
   }
 
   // Start a clean up timer.
@@ -161,7 +159,7 @@
 }
 
 void DeviceDescriptionService::CleanUpCacheEntries() {
-  DCHECK(thread_checker_.CalledOnValidThread());
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   base::Time now = GetNow();
 
   DVLOG(2) << "Before clean up, cache size: " << description_cache_.size();
@@ -178,24 +176,21 @@
 }
 
 void DeviceDescriptionService::FetchDeviceDescription(
-    const DialDeviceData& device_data,
-    net::URLRequestContextGetter* request_context) {
-  DCHECK(thread_checker_.CalledOnValidThread());
+    const DialDeviceData& device_data) {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
 
   // Existing Fetcher.
   const auto& it = device_description_fetcher_map_.find(device_data.label());
   if (it != device_description_fetcher_map_.end())
     return;
 
-  auto device_description_fetcher =
-      base::WrapUnique(new DeviceDescriptionFetcher(
-          device_data.device_description_url(), request_context,
-          base::BindOnce(
-              &DeviceDescriptionService::OnDeviceDescriptionFetchComplete,
-              base::Unretained(this), device_data),
-          base::BindOnce(
-              &DeviceDescriptionService::OnDeviceDescriptionFetchError,
-              base::Unretained(this), device_data)));
+  auto device_description_fetcher = std::make_unique<DeviceDescriptionFetcher>(
+      device_data.device_description_url(),
+      base::BindOnce(
+          &DeviceDescriptionService::OnDeviceDescriptionFetchComplete,
+          base::Unretained(this), device_data),
+      base::BindOnce(&DeviceDescriptionService::OnDeviceDescriptionFetchError,
+                     base::Unretained(this), device_data));
 
   device_description_fetcher->Start();
   device_description_fetcher_map_.insert(std::make_pair(
@@ -236,7 +231,7 @@
     const DialDeviceData& device_data,
     const ParsedDialDeviceDescription& device_description,
     SafeDialDeviceDescriptionParser::ParsingError parsing_error) {
-  DCHECK(thread_checker_.CalledOnValidThread());
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
 
   pending_device_count_--;
 
@@ -285,7 +280,7 @@
 void DeviceDescriptionService::OnDeviceDescriptionFetchComplete(
     const DialDeviceData& device_data,
     const DialDeviceDescriptionData& description_data) {
-  DCHECK(thread_checker_.CalledOnValidThread());
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
 
   ParseDeviceDescription(device_data, description_data);
 
@@ -300,7 +295,7 @@
 void DeviceDescriptionService::OnDeviceDescriptionFetchError(
     const DialDeviceData& device_data,
     const std::string& error_message) {
-  DCHECK(thread_checker_.CalledOnValidThread());
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   DVLOG(2) << "OnDeviceDescriptionFetchError [label]: " << device_data.label();
 
   error_cb_.Run(device_data, error_message);
diff --git a/chrome/browser/media/router/discovery/dial/device_description_service.h b/chrome/browser/media/router/discovery/dial/device_description_service.h
index 32c957c..dc86b933 100644
--- a/chrome/browser/media/router/discovery/dial/device_description_service.h
+++ b/chrome/browser/media/router/discovery/dial/device_description_service.h
@@ -11,16 +11,12 @@
 #include "base/callback.h"
 #include "base/gtest_prod_util.h"
 #include "base/macros.h"
-#include "base/threading/thread_checker.h"
+#include "base/sequence_checker.h"
 #include "base/timer/timer.h"
 #include "chrome/browser/media/router/discovery/dial/dial_device_data.h"
 #include "chrome/browser/media/router/discovery/dial/parsed_dial_device_description.h"
 #include "chrome/browser/media/router/discovery/dial/safe_dial_device_description_parser.h"
 
-namespace net {
-class URLRequestContextGetter;
-}
-
 namespace service_manager {
 class Connector;
 }
@@ -32,7 +28,8 @@
 
 // This class fetches and parses device description XML for DIAL devices. Actual
 // parsing happens in a separate utility process via SafeDeviceDescriptionParser
-// (instead of in this class). This class lives on the IO thread.
+// (instead of in this class).
+// This class is not sequence safe.
 class DeviceDescriptionService {
  public:
   // Represents cached device description data parsed from device description
@@ -56,15 +53,15 @@
   // all fields are valid.
   // |device_data|: The device to look up.
   // |description_data|: Device description data from device description XML.
-  using DeviceDescriptionParseSuccessCallback =
-      base::Callback<void(const DialDeviceData& device_data,
-                          const ParsedDialDeviceDescription& description_data)>;
+  using DeviceDescriptionParseSuccessCallback = base::RepeatingCallback<void(
+      const DialDeviceData& device_data,
+      const ParsedDialDeviceDescription& description_data)>;
 
   // Called if parsing device description XML in utility process fails, or some
   // parsed fields are missing or invalid.
   using DeviceDescriptionParseErrorCallback =
-      base::Callback<void(const DialDeviceData& device_data,
-                          const std::string& error_message)>;
+      base::RepeatingCallback<void(const DialDeviceData& device_data,
+                                   const std::string& error_message)>;
 
   DeviceDescriptionService(
       service_manager::Connector* connector,
@@ -77,10 +74,8 @@
   // device description XML and parsing XML in utility process. Call
   // |success_cb_| if both fetching and parsing succeeds; otherwise call
   // |error_cb_|.
-  // |request_context|: Used by the background URLFetchers.
   virtual void GetDeviceDescriptions(
-      const std::vector<DialDeviceData>& devices,
-      net::URLRequestContextGetter* request_context);
+      const std::vector<DialDeviceData>& devices);
 
  protected:
   // Parses the device description data in |description_data| and invokes
@@ -114,9 +109,7 @@
   // Issues a HTTP GET request for the device description. No-op if there is
   // already a pending request.
   // |device_data|: The device to look up.
-  // |request_context|: Used by the background URLFetchers.
-  void FetchDeviceDescription(const DialDeviceData& device_data,
-                              net::URLRequestContextGetter* request_context);
+  void FetchDeviceDescription(const DialDeviceData& device_data);
 
   // Invoked when HTTP GET request finishes.
   // |device_data|: Device data initiating the HTTP request.
@@ -171,7 +164,7 @@
   // Safe DIAL parser. Does the parsing in a utility process.
   SafeDialDeviceDescriptionParser device_description_parser_;
 
-  base::ThreadChecker thread_checker_;
+  SEQUENCE_CHECKER(sequence_checker_);
 
   DISALLOW_COPY_AND_ASSIGN(DeviceDescriptionService);
 };
diff --git a/chrome/browser/media/router/discovery/dial/device_description_service_unittest.cc b/chrome/browser/media/router/discovery/dial/device_description_service_unittest.cc
index 74b98b8..906966e0 100644
--- a/chrome/browser/media/router/discovery/dial/device_description_service_unittest.cc
+++ b/chrome/browser/media/router/discovery/dial/device_description_service_unittest.cc
@@ -6,11 +6,11 @@
 
 #include "base/strings/stringprintf.h"
 #include "base/test/mock_callback.h"
+#include "base/test/scoped_task_environment.h"
 #include "chrome/browser/media/router/discovery/dial/device_description_fetcher.h"
 #include "chrome/browser/media/router/discovery/dial/dial_device_data.h"
 #include "chrome/browser/media/router/discovery/dial/parsed_dial_device_description.h"
 #include "chrome/browser/media/router/discovery/dial/safe_dial_device_description_parser.h"
-#include "chrome/test/base/testing_profile.h"
 #include "content/public/test/test_browser_thread_bundle.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -68,8 +68,7 @@
                                     mock_error_cb_.Get()),
         fetcher_map_(
             device_description_service_.device_description_fetcher_map_),
-        description_cache_(device_description_service_.description_cache_),
-        thread_bundle_(content::TestBrowserThreadBundle::IO_MAINLOOP) {}
+        description_cache_(device_description_service_.description_cache_) {}
 
   TestDeviceDescriptionService* device_description_service() {
     return &device_description_service_;
@@ -106,6 +105,7 @@
   }
 
  protected:
+  base::test::ScopedTaskEnvironment environment_;
   base::MockCallback<
       DeviceDescriptionService::DeviceDescriptionParseSuccessCallback>
       mock_success_cb_;
@@ -118,9 +118,6 @@
       fetcher_map_;
   std::map<std::string, DeviceDescriptionService::CacheEntry>&
       description_cache_;
-
-  const content::TestBrowserThreadBundle thread_bundle_;
-  TestingProfile profile_;
 };
 
 TEST_F(DeviceDescriptionServiceTest, TestGetDeviceDescriptionFromCache) {
@@ -131,7 +128,7 @@
   AddToCache(device_data.label(), description_data, false /* expired */);
 
   std::vector<DialDeviceData> devices = {device_data};
-  device_description_service()->GetDeviceDescriptions(devices, nullptr);
+  device_description_service()->GetDeviceDescriptions(devices);
 }
 
 TEST_F(DeviceDescriptionServiceTest, TestGetDeviceDescriptionFetchURL) {
@@ -140,8 +137,7 @@
 
   // Create Fetcher
   EXPECT_TRUE(fetcher_map_.empty());
-  device_description_service()->GetDeviceDescriptions(
-      devices, profile_.GetRequestContext());
+  device_description_service()->GetDeviceDescriptions(devices);
   EXPECT_EQ(size_t(1), fetcher_map_.size());
 
   // Remove fetcher.
@@ -166,8 +162,7 @@
 
   // Create Fetcher
   EXPECT_TRUE(fetcher_map_.empty());
-  device_description_service()->GetDeviceDescriptions(
-      devices, profile_.GetRequestContext());
+  device_description_service()->GetDeviceDescriptions(devices);
   EXPECT_EQ(size_t(1), fetcher_map_.size());
 
   EXPECT_CALL(mock_error_cb_, Run(device_data, ""));
@@ -187,8 +182,7 @@
   devices.push_back(device_data_2);
 
   // insert fetchers
-  device_description_service()->GetDeviceDescriptions(
-      devices, profile_.GetRequestContext());
+  device_description_service()->GetDeviceDescriptions(devices);
 
   // Keep fetchers non exist in current device list and remove fetchers with
   // different description url.
@@ -198,8 +192,7 @@
   devices.clear();
   devices.push_back(device_data_2);
   devices.push_back(device_data_3);
-  device_description_service()->GetDeviceDescriptions(
-      devices, profile_.GetRequestContext());
+  device_description_service()->GetDeviceDescriptions(devices);
 
   EXPECT_EQ(size_t(3), fetcher_map_.size());
 
diff --git a/chrome/browser/media/router/discovery/dial/dial_app_discovery_service.cc b/chrome/browser/media/router/discovery/dial/dial_app_discovery_service.cc
index 2eb0c9a..9508e2ec 100644
--- a/chrome/browser/media/router/discovery/dial/dial_app_discovery_service.cc
+++ b/chrome/browser/media/router/discovery/dial/dial_app_discovery_service.cc
@@ -46,17 +46,15 @@
     service_manager::Connector* connector,
     const DialAppInfoParseCompletedCallback& parse_completed_cb)
     : parse_completed_cb_(parse_completed_cb),
-      parser_(std::make_unique<SafeDialAppInfoParser>(connector)) {
-  DETACH_FROM_SEQUENCE(sequence_checker_);
+      parser_(std::make_unique<SafeDialAppInfoParser>(connector)) {}
+
+DialAppDiscoveryService::~DialAppDiscoveryService() {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
 }
 
-DialAppDiscoveryService::~DialAppDiscoveryService() = default;
-
 // Always query the device to get current app status.
-void DialAppDiscoveryService::FetchDialAppInfo(
-    const MediaSinkInternal& sink,
-    const std::string& app_name,
-    net::URLRequestContextGetter* request_context) {
+void DialAppDiscoveryService::FetchDialAppInfo(const MediaSinkInternal& sink,
+                                               const std::string& app_name) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
 
   std::string sink_id = sink.sink().id();
@@ -66,7 +64,7 @@
 
   std::unique_ptr<DialAppInfoFetcher> fetcher =
       std::make_unique<DialAppInfoFetcher>(
-          app_url, request_context,
+          app_url,
           base::BindOnce(&DialAppDiscoveryService::OnDialAppInfoFetchComplete,
                          base::Unretained(this), sink_id, app_name),
           base::BindOnce(&DialAppDiscoveryService::OnDialAppInfoFetchError,
diff --git a/chrome/browser/media/router/discovery/dial/dial_app_discovery_service.h b/chrome/browser/media/router/discovery/dial/dial_app_discovery_service.h
index c85e56f..c86b1301 100644
--- a/chrome/browser/media/router/discovery/dial/dial_app_discovery_service.h
+++ b/chrome/browser/media/router/discovery/dial/dial_app_discovery_service.h
@@ -18,10 +18,6 @@
 #include "chrome/common/media_router/discovery/media_sink_internal.h"
 #include "url/gurl.h"
 
-namespace net {
-class URLRequestContextGetter;
-}
-
 namespace service_manager {
 class Connector;
 }
@@ -39,9 +35,7 @@
 // separate utility process via SafeDialAppInfoParser instead of in this class.
 // During shutdown, this class aborts all pending requests and no callbacks get
 // invoked.
-// This class may be created on any thread. All methods, unless otherwise noted,
-// must be invoked on the SequencedTaskRunner given by
-// |DialMediaSinkServiceImpl::task_runner()|.
+// This class is not sequence safe.
 class DialAppDiscoveryService {
  public:
   // Called if parsing app info XML in utility process finishes.
@@ -66,10 +60,8 @@
   // http://127.0.0.1/apps/YouTube. "http://127.0.0.1/apps/" is the base part
   // which comes from |sink|; "YouTube" suffix is the app name part which comes
   // from |app_name|.
-  // |request_context|: Used by the background URLFetchers.
   virtual void FetchDialAppInfo(const MediaSinkInternal& sink,
-                                const std::string& app_name,
-                                net::URLRequestContextGetter* request_context);
+                                const std::string& app_name);
 
  private:
   friend class DialAppDiscoveryServiceTest;
@@ -83,6 +75,14 @@
                            TestGetAvailabilityFromAppInfoAvailable);
   FRIEND_TEST_ALL_PREFIXES(DialAppDiscoveryServiceTest,
                            TestGetAvailabilityFromAppInfoUnavailable);
+  FRIEND_TEST_ALL_PREFIXES(DialAppDiscoveryServiceTest,
+                           TestFetchDialAppInfoFetchURL);
+  FRIEND_TEST_ALL_PREFIXES(DialAppDiscoveryServiceTest,
+                           TestFetchDialAppInfoFetchURLTransientError);
+  FRIEND_TEST_ALL_PREFIXES(DialAppDiscoveryServiceTest,
+                           TestFetchDialAppInfoFetchURLError);
+  FRIEND_TEST_ALL_PREFIXES(DialAppDiscoveryServiceTest,
+                           TestFetchDialAppInfoParseError);
 
   // Used by unit test.
   void SetParserForTest(std::unique_ptr<SafeDialAppInfoParser> parser);
@@ -127,6 +127,7 @@
   std::unique_ptr<SafeDialAppInfoParser> parser_;
 
   SEQUENCE_CHECKER(sequence_checker_);
+  DISALLOW_COPY_AND_ASSIGN(DialAppDiscoveryService);
 };
 
 }  // namespace media_router
diff --git a/chrome/browser/media/router/discovery/dial/dial_app_discovery_service_unittest.cc b/chrome/browser/media/router/discovery/dial/dial_app_discovery_service_unittest.cc
index f617b9198..a5dc204 100644
--- a/chrome/browser/media/router/discovery/dial/dial_app_discovery_service_unittest.cc
+++ b/chrome/browser/media/router/discovery/dial/dial_app_discovery_service_unittest.cc
@@ -10,9 +10,7 @@
 #include "chrome/browser/media/router/discovery/dial/parsed_dial_device_description.h"
 #include "chrome/browser/media/router/discovery/dial/safe_dial_app_info_parser.h"
 #include "chrome/browser/media/router/test/test_helper.h"
-#include "chrome/test/base/testing_profile.h"
-#include "content/public/test/test_browser_thread_bundle.h"
-#include "net/url_request/test_url_fetcher_factory.h"
+#include "net/http/http_status_code.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -81,81 +79,50 @@
 
   TestSafeDialAppInfoParser* test_parser_;
   DialAppDiscoveryService dial_app_discovery_service_;
-  const content::TestBrowserThreadBundle thread_bundle_;
-  TestingProfile profile_;
-  const net::TestURLFetcherFactory factory_;
 };
 
 TEST_F(DialAppDiscoveryServiceTest, TestFetchDialAppInfoFetchURL) {
   MediaSinkInternal dial_sink = CreateDialSink(1);
   EXPECT_CALL(mock_completed_cb_, Run(dial_sink.sink().id(), kYouTubeName,
                                       SinkAppStatus::kAvailable));
-  dial_app_discovery_service_.FetchDialAppInfo(dial_sink, kYouTubeName,
-                                               profile_.GetRequestContext());
-
   EXPECT_CALL(*test_parser_, ParseInternal(_))
       .WillOnce(Invoke([&](const std::string& xml_text) {
         test_parser_->InvokeParseCallback(
             CreateParsedDialAppInfo(kYouTubeName, DialAppState::kRunning),
             SafeDialAppInfoParser::ParsingResult::kSuccess);
       }));
-  net::TestURLFetcher* test_fetcher =
-      factory_.GetFetcherByID(DialAppInfoFetcher::kURLFetcherIDForTest);
-  GURL expected_url("http://192.168.0.101/apps/YouTube");
-  EXPECT_EQ(expected_url, test_fetcher->GetOriginalURL());
-  test_fetcher->set_response_code(net::HTTP_OK);
-  test_fetcher->SetResponseString("<xml>appInfo</xml>");
-  test_fetcher->delegate()->OnURLFetchComplete(test_fetcher);
+  dial_app_discovery_service_.OnDialAppInfoFetchComplete(
+      dial_sink.sink().id(), kYouTubeName, "<xml>appInfo</xml>");
 }
 
 TEST_F(DialAppDiscoveryServiceTest,
        TestFetchDialAppInfoFetchURLTransientError) {
   MediaSinkInternal dial_sink = CreateDialSink(1);
   EXPECT_CALL(mock_completed_cb_, Run(_, _, _)).Times(0);
-  dial_app_discovery_service_.FetchDialAppInfo(dial_sink, kYouTubeName,
-                                               profile_.GetRequestContext());
-
-  net::TestURLFetcher* test_fetcher =
-      factory_.GetFetcherByID(DialAppInfoFetcher::kURLFetcherIDForTest);
-  test_fetcher->set_response_code(net::HTTP_TEMPORARY_REDIRECT);
-  test_fetcher->delegate()->OnURLFetchComplete(test_fetcher);
+  dial_app_discovery_service_.OnDialAppInfoFetchError(
+      dial_sink.sink().id(), kYouTubeName, net::HTTP_TEMPORARY_REDIRECT,
+      "Temporary redirect");
 }
 
 TEST_F(DialAppDiscoveryServiceTest, TestFetchDialAppInfoFetchURLError) {
   MediaSinkInternal dial_sink = CreateDialSink(1);
   EXPECT_CALL(mock_completed_cb_, Run(dial_sink.sink().id(), kYouTubeName,
                                       SinkAppStatus::kUnavailable));
-  dial_app_discovery_service_.FetchDialAppInfo(dial_sink, kYouTubeName,
-                                               profile_.GetRequestContext());
-
-  net::TestURLFetcher* test_fetcher =
-      factory_.GetFetcherByID(DialAppInfoFetcher::kURLFetcherIDForTest);
-  test_fetcher->set_response_code(net::HTTP_NOT_FOUND);
-  test_fetcher->delegate()->OnURLFetchComplete(test_fetcher);
-
-  EXPECT_CALL(mock_completed_cb_, Run(_, _, SinkAppStatus::kUnavailable))
-      .Times(0);
-  dial_app_discovery_service_.FetchDialAppInfo(dial_sink, kYouTubeName,
-                                               profile_.GetRequestContext());
+  dial_app_discovery_service_.OnDialAppInfoFetchError(
+      dial_sink.sink().id(), kYouTubeName, net::HTTP_NOT_FOUND, "Not found");
 }
 
 TEST_F(DialAppDiscoveryServiceTest, TestFetchDialAppInfoParseError) {
   MediaSinkInternal dial_sink = CreateDialSink(1);
   EXPECT_CALL(mock_completed_cb_, Run(dial_sink.sink().id(), kYouTubeName,
                                       SinkAppStatus::kUnavailable));
-  dial_app_discovery_service_.FetchDialAppInfo(dial_sink, kYouTubeName,
-                                               profile_.GetRequestContext());
-
   EXPECT_CALL(*test_parser_, ParseInternal(_))
       .WillOnce(Invoke([&](const std::string& xml_text) {
         test_parser_->InvokeParseCallback(
             nullptr, SafeDialAppInfoParser::ParsingResult::kMissingName);
       }));
-  net::TestURLFetcher* test_fetcher =
-      factory_.GetFetcherByID(DialAppInfoFetcher::kURLFetcherIDForTest);
-  test_fetcher->set_response_code(net::HTTP_OK);
-  test_fetcher->SetResponseString("<xml>appInfo</xml>");
-  test_fetcher->delegate()->OnURLFetchComplete(test_fetcher);
+  dial_app_discovery_service_.OnDialAppInfoFetchComplete(
+      dial_sink.sink().id(), kYouTubeName, "<xml>appInfo</xml>");
 }
 
 TEST_F(DialAppDiscoveryServiceTest, TestGetAvailabilityFromAppInfoAvailable) {
diff --git a/chrome/browser/media/router/discovery/dial/dial_app_info_fetcher.cc b/chrome/browser/media/router/discovery/dial/dial_app_info_fetcher.cc
index 0b991b88..a274e3f1 100644
--- a/chrome/browser/media/router/discovery/dial/dial_app_info_fetcher.cc
+++ b/chrome/browser/media/router/discovery/dial/dial_app_info_fetcher.cc
@@ -4,16 +4,18 @@
 
 #include "chrome/browser/media/router/discovery/dial/dial_app_info_fetcher.h"
 
-#include "chrome/browser/profiles/profile.h"
+#include "base/strings/stringprintf.h"
+#include "chrome/browser/browser_process.h"
+#include "chrome/browser/net/system_network_context_manager.h"
+#include "content/public/browser/browser_thread.h"
 #include "net/base/load_flags.h"
 #include "net/http/http_response_headers.h"
 #include "net/http/http_status_code.h"
 #include "net/http/http_util.h"
 #include "net/traffic_annotation/network_traffic_annotation.h"
-#include "net/url_request/url_fetcher.h"
-#include "net/url_request/url_request_context_getter.h"
-
-using content::BrowserThread;
+#include "net/url_request/redirect_info.h"
+#include "services/network/public/cpp/resource_request.h"
+#include "services/network/public/cpp/simple_url_loader.h"
 
 constexpr int kMaxRetries = 3;
 // DIAL devices are unlikely to expose uPnP functions other than DIAL, so 256kb
@@ -22,29 +24,10 @@
 
 namespace media_router {
 
-DialAppInfoFetcher::DialAppInfoFetcher(
-    const GURL& app_url,
-    net::URLRequestContextGetter* request_context,
-    base::OnceCallback<void(const std::string&)> success_cb,
-    base::OnceCallback<void(int, const std::string&)> error_cb)
-    : app_url_(app_url),
-      request_context_(request_context),
-      success_cb_(std::move(success_cb)),
-      error_cb_(std::move(error_cb)) {
-  DCHECK(request_context_);
-  DCHECK(app_url_.is_valid());
-}
+namespace {
 
-DialAppInfoFetcher::~DialAppInfoFetcher() {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-}
-
-void DialAppInfoFetcher::Start() {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-  DCHECK(!fetcher_);
-
-  net::NetworkTrafficAnnotationTag traffic_annotation =
-      net::DefineNetworkTrafficAnnotation("dial_get_app_info", R"(
+constexpr net::NetworkTrafficAnnotationTag kTrafficAnnotation =
+    net::DefineNetworkTrafficAnnotation("dial_get_app_info", R"(
         semantics {
           sender: "DIAL"
           description:
@@ -72,30 +55,64 @@
             }
           }
         })");
-  // DIAL returns app info via GET request.
-  fetcher_ =
-      net::URLFetcher::Create(kURLFetcherIDForTest, app_url_,
-                              net::URLFetcher::GET, this, traffic_annotation);
+
+void BindURLLoaderFactoryRequestOnUIThread(
+    network::mojom::URLLoaderFactoryRequest request) {
+  network::mojom::URLLoaderFactory* factory =
+      g_browser_process->system_network_context_manager()
+          ->GetURLLoaderFactory();
+  factory->Clone(std::move(request));
+}
+
+}  // namespace
+
+DialAppInfoFetcher::DialAppInfoFetcher(
+    const GURL& app_url,
+    base::OnceCallback<void(const std::string&)> success_cb,
+    base::OnceCallback<void(int, const std::string&)> error_cb)
+    : app_url_(app_url),
+      success_cb_(std::move(success_cb)),
+      error_cb_(std::move(error_cb)) {
+  DCHECK(app_url_.is_valid());
+}
+
+DialAppInfoFetcher::~DialAppInfoFetcher() {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+}
+
+void DialAppInfoFetcher::Start() {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  DCHECK(!loader_);
+
+  auto request = std::make_unique<network::ResourceRequest>();
+  request->url = app_url_;
 
   // net::LOAD_BYPASS_PROXY: Proxies almost certainly hurt more cases than they
   //     help.
   // net::LOAD_DISABLE_CACHE: The request should not touch the cache.
   // net::LOAD_DO_NOT_{SAVE,SEND}_COOKIES: The request should not touch cookies.
   // net::LOAD_DO_NOT_SEND_AUTH_DATA: The request should not send auth data.
-  fetcher_->SetLoadFlags(net::LOAD_BYPASS_PROXY | net::LOAD_DISABLE_CACHE |
-                         net::LOAD_DO_NOT_SAVE_COOKIES |
-                         net::LOAD_DO_NOT_SEND_COOKIES |
-                         net::LOAD_DO_NOT_SEND_AUTH_DATA);
+  request->load_flags = net::LOAD_BYPASS_PROXY | net::LOAD_DISABLE_CACHE |
+                        net::LOAD_DO_NOT_SAVE_COOKIES |
+                        net::LOAD_DO_NOT_SEND_COOKIES |
+                        net::LOAD_DO_NOT_SEND_AUTH_DATA;
 
-  // Section 5.4 of the DIAL spec prohibits redirects.
-  fetcher_->SetStopOnRedirect(true);
+  loader_ =
+      network::SimpleURLLoader::Create(std::move(request), kTrafficAnnotation);
 
   // Allow the fetcher to retry on 5XX responses and ERR_NETWORK_CHANGED.
-  fetcher_->SetMaxRetriesOn5xx(kMaxRetries);
-  fetcher_->SetAutomaticallyRetryOnNetworkChanges(kMaxRetries);
+  loader_->SetRetryOptions(
+      kMaxRetries,
+      network::SimpleURLLoader::RetryMode::RETRY_ON_5XX |
+          network::SimpleURLLoader::RetryMode::RETRY_ON_NETWORK_CHANGE);
 
-  fetcher_->SetRequestContext(request_context_.get());
-  fetcher_->Start();
+  // Section 5.4 of the DIAL spec prohibits redirects.
+  // In practice, the callback will only get called once, since |loader_| will
+  // be deleted.
+  loader_->SetOnRedirectCallback(base::BindRepeating(
+      &DialAppInfoFetcher::ReportRedirectError, base::Unretained(this)));
+
+  StartDownload();
 }
 
 void DialAppInfoFetcher::ReportError(int response_code,
@@ -103,34 +120,55 @@
   std::move(error_cb_).Run(response_code, message);
 }
 
-void DialAppInfoFetcher::OnURLFetchComplete(const net::URLFetcher* source) {
-  DCHECK_EQ(fetcher_.get(), source);
+void DialAppInfoFetcher::ReportRedirectError(
+    const net::RedirectInfo& redirect_info,
+    const network::ResourceResponseHead& response_head) {
+  // Cancel the request.
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  loader_.reset();
 
-  int response_code = source->GetResponseCode();
-  if (response_code != net::HTTP_OK) {
+  // Returning |OK| on error will be treated as unavailable.
+  ReportError(net::Error::OK, "Redirect not allowed");
+}
+
+void DialAppInfoFetcher::StartDownload() {
+  // Bind the request to the system URLLoaderFactory obtained on UI thread.
+  // Currently this is the only way to guarantee a live URLLoaderFactory.
+  // TOOD(mmenke): Figure out a way to do this transparently on IO thread.
+  network::mojom::URLLoaderFactoryPtr loader_factory;
+  content::BrowserThread::PostTask(
+      content::BrowserThread::UI, FROM_HERE,
+      base::BindOnce(&BindURLLoaderFactoryRequestOnUIThread,
+                     mojo::MakeRequest(&loader_factory)));
+
+  loader_->DownloadToString(loader_factory.get(),
+                            base::BindOnce(&DialAppInfoFetcher::ProcessResponse,
+                                           base::Unretained(this)),
+                            kMaxAppInfoSizeBytes);
+}
+
+void DialAppInfoFetcher::ProcessResponse(
+    std::unique_ptr<std::string> response) {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  int response_code = loader_->NetError();
+  if (response_code != net::Error::OK) {
     ReportError(response_code,
                 base::StringPrintf("HTTP %d: Unable to fetch DIAL app info",
                                    response_code));
     return;
   }
 
-  if (source->GetReceivedResponseContentLength() > kMaxAppInfoSizeBytes) {
-    ReportError(response_code, "Response too large");
-    return;
-  }
-
-  std::string app_info_xml;
-  if (!source->GetResponseAsString(&app_info_xml) || app_info_xml.empty()) {
+  if (!response || response->empty()) {
     ReportError(response_code, "Missing or empty response");
     return;
   }
 
-  if (!base::IsStringUTF8(app_info_xml)) {
+  if (!base::IsStringUTF8(*response)) {
     ReportError(response_code, "Invalid response encoding");
     return;
   }
 
-  std::move(success_cb_).Run(std::string(app_info_xml));
+  std::move(success_cb_).Run(*response);
 }
 
 }  // namespace media_router
diff --git a/chrome/browser/media/router/discovery/dial/dial_app_info_fetcher.h b/chrome/browser/media/router/discovery/dial/dial_app_info_fetcher.h
index 2c4b050..bd4c1fc 100644
--- a/chrome/browser/media/router/discovery/dial/dial_app_info_fetcher.h
+++ b/chrome/browser/media/router/discovery/dial/dial_app_info_fetcher.h
@@ -9,63 +9,62 @@
 #include <string>
 
 #include "base/callback.h"
-#include "base/threading/thread_checker.h"
-#include "content/public/browser/browser_thread.h"
-#include "net/url_request/url_fetcher_delegate.h"
+#include "services/network/public/mojom/url_loader_factory.mojom.h"
 #include "url/gurl.h"
 
 namespace net {
-class URLFetcher;
-class URLRequestContextGetter;
-}  // namespace net
+struct RedirectInfo;
+}
+
+namespace network {
+class SimpleURLLoader;
+struct ResourceResponseHead;
+}  // namespace network
 
 namespace media_router {
 
 // Used to make a single HTTP GET request with |app_url| to fetch an app info
 // from a DIAL device.  If successful, |success_cb| is invoked with the result;
 // otherwise, |error_cb| is invoked with an error reason.
-// This class is not thread safe and should be invoked .
-class DialAppInfoFetcher : public net::URLFetcherDelegate {
+// This class is not sequence safe.
+class DialAppInfoFetcher {
  public:
-  // Used to identify the net::URLFetcher instance for tests.
-  static constexpr int kURLFetcherIDForTest = 1;
-
-  // |request_context| is unowned; the caller must ensure that this object does
-  // not outlive it.
   DialAppInfoFetcher(
       const GURL& app_url,
-      net::URLRequestContextGetter* request_context,
       base::OnceCallback<void(const std::string&)> success_cb,
       base::OnceCallback<void(int, const std::string&)> error_cb);
 
-  ~DialAppInfoFetcher() override;
+  virtual ~DialAppInfoFetcher();
 
   const GURL& app_url() { return app_url_; }
 
-  virtual void Start();
+  // Starts the fetch. |ProcessResponse| will be invoked on completion.
+  // |ReportRedirectError| will be invoked when a redirect occurrs.
+  void Start();
 
- protected:
+ private:
+  friend class TestDialAppInfoFetcher;
+
+  // Starts the download on |loader_|.
+  virtual void StartDownload();
+
+  // Processes the response and invokes the success or error callback.
+  void ProcessResponse(std::unique_ptr<std::string> response);
+
+  // Invokes the error callback due to redirect, and aborts the request.
+  void ReportRedirectError(const net::RedirectInfo& redirect_info,
+                           const network::ResourceResponseHead& response_head);
+
   // Runs |error_cb_| with |message| and clears it.
   void ReportError(int response_code, const std::string& message);
 
- private:
-  // net::URLFetcherDelegate implementation.
-  void OnURLFetchComplete(const net::URLFetcher* source) override;
-  void OnURLFetchDownloadProgress(const net::URLFetcher* source,
-                                  int64_t current,
-                                  int64_t total,
-                                  int64_t current_network_bytes) override {}
-  void OnURLFetchUploadProgress(const net::URLFetcher* source,
-                                int64_t current,
-                                int64_t total) override {}
-
   const GURL app_url_;
-  const scoped_refptr<net::URLRequestContextGetter> request_context_;
   base::OnceCallback<void(const std::string&)> success_cb_;
   base::OnceCallback<void(int, const std::string&)> error_cb_;
-  std::unique_ptr<net::URLFetcher> fetcher_;
+  std::unique_ptr<network::SimpleURLLoader> loader_;
 
-  THREAD_CHECKER(thread_checker_);
+  SEQUENCE_CHECKER(sequence_checker_);
+  DISALLOW_COPY_AND_ASSIGN(DialAppInfoFetcher);
 };
 
 }  // namespace media_router
diff --git a/chrome/browser/media/router/discovery/dial/dial_app_info_fetcher_unittest.cc b/chrome/browser/media/router/discovery/dial/dial_app_info_fetcher_unittest.cc
index 5cff01d..4a6c60c 100644
--- a/chrome/browser/media/router/discovery/dial/dial_app_info_fetcher_unittest.cc
+++ b/chrome/browser/media/router/discovery/dial/dial_app_info_fetcher_unittest.cc
@@ -7,6 +7,8 @@
 
 #include "base/callback.h"
 #include "base/macros.h"
+#include "base/run_loop.h"
+#include "base/test/scoped_task_environment.h"
 #include "chrome/browser/media/router/discovery/dial/dial_app_info_fetcher.h"
 #include "chrome/test/base/testing_profile.h"
 #include "content/public/test/test_browser_thread_bundle.h"
@@ -14,104 +16,116 @@
 #include "net/http/http_status_code.h"
 #include "net/url_request/test_url_fetcher_factory.h"
 #include "net/url_request/url_fetcher.h"
+#include "services/network/public/cpp/simple_url_loader.h"
+#include "services/network/test/test_url_loader_factory.h"
+#include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "url/gurl.h"
 
 namespace media_router {
 
+class TestDialAppInfoFetcher : public DialAppInfoFetcher {
+ public:
+  TestDialAppInfoFetcher(
+      const GURL& app_url,
+      base::OnceCallback<void(const std::string&)> success_cb,
+      base::OnceCallback<void(int, const std::string&)> error_cb,
+      network::TestURLLoaderFactory* factory)
+      : DialAppInfoFetcher(app_url, std::move(success_cb), std::move(error_cb)),
+        factory_(factory) {}
+  ~TestDialAppInfoFetcher() override = default;
+
+  void StartDownload() override {
+    loader_->DownloadToString(
+        factory_,
+        base::BindOnce(&DialAppInfoFetcher::ProcessResponse,
+                       base::Unretained(this)),
+        256 * 1024);
+  }
+
+ private:
+  network::TestURLLoaderFactory* const factory_;
+};
+
 class DialAppInfoFetcherTest : public testing::Test {
  public:
   DialAppInfoFetcherTest() : url_("http://127.0.0.1/app/Youtube") {}
 
-  void TearDown() override {
-    EXPECT_FALSE(error_cb_);
-    EXPECT_FALSE(success_cb_);
-  }
-
   void ExpectSuccess(const std::string& expected_app_info) {
-    success_cb_ = base::BindOnce(&DialAppInfoFetcherTest::OnSuccess,
-                                 base::Unretained(this), expected_app_info);
+    EXPECT_CALL(*this, OnSuccess(expected_app_info));
   }
 
-  void ExpectError(const std::string& expected_message) {
-    error_cb_ = base::BindOnce(&DialAppInfoFetcherTest::OnError,
-                               base::Unretained(this), expected_message);
+  void ExpectError(const std::string& expected_error) {
+    expected_error_ = expected_error;
+    EXPECT_CALL(*this, DoOnError());
   }
 
-  net::TestURLFetcher* StartRequest() {
-    fetcher_ = std::make_unique<DialAppInfoFetcher>(
-        url_, profile_.GetRequestContext(), std::move(success_cb_),
-        std::move(error_cb_));
+  void StartRequest() {
+    fetcher_ = std::make_unique<TestDialAppInfoFetcher>(
+        url_,
+        base::BindOnce(&DialAppInfoFetcherTest::OnSuccess,
+                       base::Unretained(this)),
+        base::BindOnce(&DialAppInfoFetcherTest::OnError,
+                       base::Unretained(this)),
+        &loader_factory_);
     fetcher_->Start();
-    return factory_.GetFetcherByID(DialAppInfoFetcher::kURLFetcherIDForTest);
+    base::RunLoop().RunUntilIdle();
   }
 
  protected:
-  const content::TestBrowserThreadBundle thread_bundle_;
-  TestingProfile profile_;
-  const net::TestURLFetcherFactory factory_;
+  base::test::ScopedTaskEnvironment environment_;
+  network::TestURLLoaderFactory loader_factory_;
   const GURL url_;
-  base::OnceCallback<void(const std::string&)> success_cb_;
-  base::OnceCallback<void(int, const std::string&)> error_cb_;
-  std::unique_ptr<DialAppInfoFetcher> fetcher_;
+  std::string expected_error_;
+  std::unique_ptr<TestDialAppInfoFetcher> fetcher_;
 
  private:
-  void OnSuccess(const std::string& expected_app_info,
-                 const std::string& app_info) {
-    EXPECT_EQ(expected_app_info, app_info);
-  }
+  MOCK_METHOD1(OnSuccess, void(const std::string&));
+  MOCK_METHOD0(DoOnError, void());
 
-  void OnError(const std::string& expected_message,
-               int response_code,
-               const std::string& message) {
-    EXPECT_TRUE(message.find(expected_message) == 0);
+  void OnError(int response_code, const std::string& message) {
+    EXPECT_TRUE(message.find(expected_error_) == 0);
+    DoOnError();
   }
 
   DISALLOW_COPY_AND_ASSIGN(DialAppInfoFetcherTest);
 };
 
 TEST_F(DialAppInfoFetcherTest, FetchSuccessful) {
-  ExpectSuccess("<xml>appInfo</xml>");
-  net::TestURLFetcher* test_fetcher = StartRequest();
-
-  test_fetcher->set_response_code(net::HTTP_OK);
-  test_fetcher->SetResponseString("<xml>appInfo</xml>");
-  test_fetcher->delegate()->OnURLFetchComplete(test_fetcher);
+  std::string body("<xml>appInfo</xml>");
+  ExpectSuccess(body);
+  network::URLLoaderCompletionStatus status;
+  status.decoded_body_length = body.size();
+  loader_factory_.AddResponse(url_, network::ResourceResponseHead(), body,
+                              status);
+  StartRequest();
 }
 
 TEST_F(DialAppInfoFetcherTest, FetchFailsOnMissingAppInfo) {
   ExpectError("HTTP 404:");
-  net::TestURLFetcher* test_fetcher = StartRequest();
 
-  test_fetcher->set_response_code(net::HTTP_NOT_FOUND);
-  test_fetcher->delegate()->OnURLFetchComplete(test_fetcher);
+  loader_factory_.AddResponse(
+      url_, network::ResourceResponseHead(), "",
+      network::URLLoaderCompletionStatus(net::HTTP_NOT_FOUND));
+  StartRequest();
 }
 
 TEST_F(DialAppInfoFetcherTest, FetchFailsOnEmptyAppInfo) {
   ExpectError("Missing or empty response");
-  net::TestURLFetcher* test_fetcher = StartRequest();
 
-  test_fetcher->set_response_code(net::HTTP_OK);
-  test_fetcher->SetResponseString("");
-  test_fetcher->delegate()->OnURLFetchComplete(test_fetcher);
+  loader_factory_.AddResponse(url_, network::ResourceResponseHead(), "",
+                              network::URLLoaderCompletionStatus());
+  StartRequest();
 }
 
 TEST_F(DialAppInfoFetcherTest, FetchFailsOnBadAppInfo) {
   ExpectError("Invalid response encoding");
-  net::TestURLFetcher* test_fetcher = StartRequest();
-
-  test_fetcher->set_response_code(net::HTTP_OK);
-  test_fetcher->SetResponseString("\xfc\x9c\xbf\x80\xbf\x80");
-  test_fetcher->delegate()->OnURLFetchComplete(test_fetcher);
-}
-
-TEST_F(DialAppInfoFetcherTest, FetchFailsOnResponseTooLarge) {
-  ExpectError("Response too large");
-  net::TestURLFetcher* test_fetcher = StartRequest();
-
-  test_fetcher->set_response_code(net::HTTP_OK);
-  test_fetcher->SetResponseString(std::string(262145, 'd'));
-  test_fetcher->delegate()->OnURLFetchComplete(test_fetcher);
+  std::string body("\xfc\x9c\xbf\x80\xbf\x80");
+  network::URLLoaderCompletionStatus status;
+  status.decoded_body_length = body.size();
+  loader_factory_.AddResponse(url_, network::ResourceResponseHead(), body,
+                              status);
+  StartRequest();
 }
 
 }  // namespace media_router
diff --git a/chrome/browser/media/router/discovery/dial/dial_media_sink_service.cc b/chrome/browser/media/router/discovery/dial/dial_media_sink_service.cc
index 83d44d10..1c2fbf0 100644
--- a/chrome/browser/media/router/discovery/dial/dial_media_sink_service.cc
+++ b/chrome/browser/media/router/discovery/dial/dial_media_sink_service.cc
@@ -6,13 +6,12 @@
 
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/media/router/discovery/dial/dial_media_sink_service_impl.h"
+#include "chrome/browser/net/system_network_context_manager.h"
 #include "chrome/common/media_router/media_source_helper.h"
-#include "content/public/browser/browser_context.h"
+#include "content/public/browser/browser_thread.h"
 #include "content/public/common/service_manager_connection.h"
 #include "services/service_manager/public/cpp/connector.h"
 
-using content::BrowserThread;
-
 namespace media_router {
 
 namespace {
@@ -23,14 +22,9 @@
 
 }  // namespace
 
-DialMediaSinkService::DialMediaSinkService(
-    const scoped_refptr<net::URLRequestContextGetter>& request_context)
+DialMediaSinkService::DialMediaSinkService()
     : impl_(nullptr, base::OnTaskRunnerDeleter(nullptr)),
-      request_context_(request_context),
-      weak_ptr_factory_(this) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
-  DCHECK(request_context_);
-}
+      weak_ptr_factory_(this) {}
 
 DialMediaSinkService::~DialMediaSinkService() {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
@@ -40,7 +34,6 @@
     const OnSinksDiscoveredCallback& sink_discovery_cb,
     const OnDialSinkAddedCallback& dial_sink_added_cb) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-
   DCHECK(!impl_);
 
   OnSinksDiscoveredCallback sink_discovery_cb_impl = base::BindRepeating(
@@ -58,7 +51,7 @@
               weak_ptr_factory_.GetWeakPtr()));
 
   impl_ = CreateImpl(sink_discovery_cb_impl, dial_sink_added_cb,
-                     available_sinks_updated_cb_impl, request_context_);
+                     available_sinks_updated_cb_impl);
 
   impl_->task_runner()->PostTask(
       FROM_HERE, base::BindOnce(&DialMediaSinkServiceImpl::Start,
@@ -124,8 +117,7 @@
 DialMediaSinkService::CreateImpl(
     const OnSinksDiscoveredCallback& sink_discovery_cb,
     const OnDialSinkAddedCallback& dial_sink_added_cb,
-    const OnAvailableSinksUpdatedCallback& available_sinks_updated_cb,
-    const scoped_refptr<net::URLRequestContextGetter>& request_context) {
+    const OnAvailableSinksUpdatedCallback& available_sinks_updated_cb) {
   // Clone the connector so it can be used on the IO thread.
   std::unique_ptr<service_manager::Connector> connector =
       content::ServiceManagerConnection::GetForProcess()
@@ -133,14 +125,14 @@
           ->Clone();
 
   // Note: The SequencedTaskRunner needs to be IO thread because DialRegistry
-  // and URLRequestContextGetter run on IO thread.
+  // runs on IO thread.
   scoped_refptr<base::SequencedTaskRunner> task_runner =
       content::BrowserThread::GetTaskRunnerForThread(
           content::BrowserThread::IO);
   return std::unique_ptr<DialMediaSinkServiceImpl, base::OnTaskRunnerDeleter>(
-      new DialMediaSinkServiceImpl(
-          std::move(connector), sink_discovery_cb, dial_sink_added_cb,
-          available_sinks_updated_cb, request_context, task_runner),
+      new DialMediaSinkServiceImpl(std::move(connector), sink_discovery_cb,
+                                   dial_sink_added_cb,
+                                   available_sinks_updated_cb, task_runner),
       base::OnTaskRunnerDeleter(task_runner));
 }
 
diff --git a/chrome/browser/media/router/discovery/dial/dial_media_sink_service.h b/chrome/browser/media/router/discovery/dial/dial_media_sink_service.h
index e4d3cad4..d497d26 100644
--- a/chrome/browser/media/router/discovery/dial/dial_media_sink_service.h
+++ b/chrome/browser/media/router/discovery/dial/dial_media_sink_service.h
@@ -12,19 +12,14 @@
 #include "base/macros.h"
 #include "base/memory/ref_counted.h"
 #include "base/memory/weak_ptr.h"
+#include "base/observer_list.h"
 #include "base/sequence_checker.h"
-#include "base/sequenced_task_runner_helpers.h"
+#include "base/sequenced_task_runner.h"
 #include "chrome/browser/media/router/media_sinks_observer.h"
 #include "chrome/common/media_router/discovery/media_sink_internal.h"
 #include "chrome/common/media_router/discovery/media_sink_service_util.h"
-#include "content/public/browser/browser_thread.h"
-#include "net/url_request/url_request_context_getter.h"
 #include "url/origin.h"
 
-namespace net {
-class URLRequestContextGetter;
-}
-
 namespace media_router {
 
 class DialMediaSinkServiceImpl;
@@ -37,8 +32,7 @@
 // SequencedTaskRunner.
 class DialMediaSinkService {
  public:
-  explicit DialMediaSinkService(
-      const scoped_refptr<net::URLRequestContextGetter>& request_context);
+  DialMediaSinkService();
   virtual ~DialMediaSinkService();
 
   // Starts discovery of DIAL sinks. Can only be called once.
@@ -66,11 +60,9 @@
 
   // Marked virtual for tests.
   virtual std::unique_ptr<DialMediaSinkServiceImpl, base::OnTaskRunnerDeleter>
-  CreateImpl(
-      const OnSinksDiscoveredCallback& sink_discovery_cb,
-      const OnDialSinkAddedCallback& dial_sink_added_cb,
-      const OnAvailableSinksUpdatedCallback& available_sinks_updated_cb,
-      const scoped_refptr<net::URLRequestContextGetter>& request_context);
+  CreateImpl(const OnSinksDiscoveredCallback& sink_discovery_cb,
+             const OnDialSinkAddedCallback& dial_sink_added_cb,
+             const OnAvailableSinksUpdatedCallback& available_sinks_updated_cb);
 
   void RunSinksDiscoveredCallback(
       const OnSinksDiscoveredCallback& sinks_discovered_cb,
@@ -87,9 +79,6 @@
   // Created on the UI thread, used and destroyed on its SequencedTaskRunner.
   std::unique_ptr<DialMediaSinkServiceImpl, base::OnTaskRunnerDeleter> impl_;
 
-  // Passed to |impl_| when |Start| is called.
-  scoped_refptr<net::URLRequestContextGetter> request_context_;
-
   // Map of media sink observers, keyed by app name
   base::flat_map<std::string,
                  std::unique_ptr<base::ObserverList<MediaSinksObserver>>>
diff --git a/chrome/browser/media/router/discovery/dial/dial_media_sink_service_impl.cc b/chrome/browser/media/router/discovery/dial/dial_media_sink_service_impl.cc
index 8a266a1..1cc2961 100644
--- a/chrome/browser/media/router/discovery/dial/dial_media_sink_service_impl.cc
+++ b/chrome/browser/media/router/discovery/dial/dial_media_sink_service_impl.cc
@@ -8,14 +8,8 @@
 
 #include "base/strings/stringprintf.h"
 #include "chrome/browser/media/router/discovery/dial/dial_device_data.h"
-#include "chrome/browser/profiles/profile.h"
-#include "content/public/browser/browser_thread.h"
-#include "net/url_request/url_request_context.h"
-#include "net/url_request/url_request_context_getter.h"
 #include "services/service_manager/public/cpp/connector.h"
 
-using content::BrowserThread;
-
 namespace media_router {
 
 DialMediaSinkServiceImpl::DialMediaSinkServiceImpl(
@@ -23,27 +17,13 @@
     const OnSinksDiscoveredCallback& on_sinks_discovered_cb,
     const OnDialSinkAddedCallback& dial_sink_added_cb,
     const OnAvailableSinksUpdatedCallback& available_sinks_updated_callback,
-    const scoped_refptr<net::URLRequestContextGetter>& request_context,
     const scoped_refptr<base::SequencedTaskRunner>& task_runner)
     : MediaSinkServiceBase(on_sinks_discovered_cb),
       connector_(std::move(connector)),
-      description_service_(std::make_unique<DeviceDescriptionService>(
-          connector_.get(),
-          base::Bind(&DialMediaSinkServiceImpl::OnDeviceDescriptionAvailable,
-                     base::Unretained(this)),
-          base::Bind(&DialMediaSinkServiceImpl::OnDeviceDescriptionError,
-                     base::Unretained(this)))),
-      app_discovery_service_(std::make_unique<DialAppDiscoveryService>(
-          connector_.get(),
-          base::BindRepeating(
-              &DialMediaSinkServiceImpl::OnAppInfoParseCompleted,
-              base::Unretained(this)))),
       dial_sink_added_cb_(dial_sink_added_cb),
       available_sinks_updated_callback_(available_sinks_updated_callback),
-      request_context_(request_context),
       task_runner_(task_runner) {
   DETACH_FROM_SEQUENCE(sequence_checker_);
-  DCHECK(request_context_);
 }
 
 DialMediaSinkServiceImpl::~DialMediaSinkServiceImpl() {
@@ -60,10 +40,21 @@
   if (dial_registry_)
     return;
 
+  description_service_ = std::make_unique<DeviceDescriptionService>(
+      connector_.get(),
+      base::BindRepeating(
+          &DialMediaSinkServiceImpl::OnDeviceDescriptionAvailable,
+          base::Unretained(this)),
+      base::BindRepeating(&DialMediaSinkServiceImpl::OnDeviceDescriptionError,
+                          base::Unretained(this)));
+
+  app_discovery_service_ = std::make_unique<DialAppDiscoveryService>(
+      connector_.get(),
+      base::BindRepeating(&DialMediaSinkServiceImpl::OnAppInfoParseCompleted,
+                          base::Unretained(this)));
+
   dial_registry_ =
       test_dial_registry_ ? test_dial_registry_ : DialRegistry::GetInstance();
-  dial_registry_->SetNetLog(
-      request_context_->GetURLRequestContext()->net_log());
   dial_registry_->RegisterObserver(this);
   dial_registry_->OnListenerAdded();
   MediaSinkServiceBase::StartTimer();
@@ -135,7 +126,7 @@
   current_sinks_.clear();
   current_devices_ = devices;
 
-  description_service_->GetDeviceDescriptions(devices, request_context_.get());
+  description_service_->GetDeviceDescriptions(devices);
 }
 
 void DialMediaSinkServiceImpl::OnDialError(DialRegistry::DialErrorCode type) {
@@ -229,8 +220,7 @@
   if (app_status != SinkAppStatus::kUnknown)
     return;
 
-  app_discovery_service_->FetchDialAppInfo(dial_sink, app_name,
-                                           request_context_.get());
+  app_discovery_service_->FetchDialAppInfo(dial_sink, app_name);
 }
 
 void DialMediaSinkServiceImpl::RescanAppInfo() {
diff --git a/chrome/browser/media/router/discovery/dial/dial_media_sink_service_impl.h b/chrome/browser/media/router/discovery/dial/dial_media_sink_service_impl.h
index c826663..a5b6da6 100644
--- a/chrome/browser/media/router/discovery/dial/dial_media_sink_service_impl.h
+++ b/chrome/browser/media/router/discovery/dial/dial_media_sink_service_impl.h
@@ -10,7 +10,6 @@
 
 #include "base/containers/flat_map.h"
 #include "base/containers/flat_set.h"
-#include "base/memory/weak_ptr.h"
 #include "base/sequence_checker.h"
 #include "chrome/browser/media/router/discovery/dial/device_description_service.h"
 #include "chrome/browser/media/router/discovery/dial/dial_app_discovery_service.h"
@@ -42,18 +41,15 @@
   // |dial_sink_added_cb|: If not null, callback to invoke when a DIAL sink has
   // been discovered.
   // Note that both callbacks are invoked on |task_runner|.
-  // |request_context|: Used for network requests.
   // |task_runner|: The SequencedTaskRunner this class runs in.
   DialMediaSinkServiceImpl(
       std::unique_ptr<service_manager::Connector> connector,
       const OnSinksDiscoveredCallback& on_sinks_discovered_cb,
       const OnDialSinkAddedCallback& dial_sink_added_cb,
       const OnAvailableSinksUpdatedCallback& available_sinks_updated_callback,
-      const scoped_refptr<net::URLRequestContextGetter>& request_context,
       const scoped_refptr<base::SequencedTaskRunner>& task_runner);
   ~DialMediaSinkServiceImpl() override;
 
-  // Marked virtual for tests.
   virtual void Start();
 
   void OnUserGesture();
@@ -164,8 +160,10 @@
   // Connector to ServiceManager for safe XML parsing requests.
   std::unique_ptr<service_manager::Connector> connector_;
 
+  // Initialized in |Start()|.
   std::unique_ptr<DeviceDescriptionService> description_service_;
 
+  // Initialized in |Start()|.
   std::unique_ptr<DialAppDiscoveryService> app_discovery_service_;
 
   OnDialSinkAddedCallback dial_sink_added_cb_;
@@ -191,8 +189,6 @@
   // Set of registered app names.
   base::flat_set<std::string> registered_apps_;
 
-  scoped_refptr<net::URLRequestContextGetter> request_context_;
-
   scoped_refptr<base::SequencedTaskRunner> task_runner_;
 
   DialDeviceCountMetrics metrics_;
diff --git a/chrome/browser/media/router/discovery/dial/dial_media_sink_service_impl_unittest.cc b/chrome/browser/media/router/discovery/dial/dial_media_sink_service_impl_unittest.cc
index 16a9279..c148328 100644
--- a/chrome/browser/media/router/discovery/dial/dial_media_sink_service_impl_unittest.cc
+++ b/chrome/browser/media/router/discovery/dial/dial_media_sink_service_impl_unittest.cc
@@ -8,7 +8,6 @@
 #include "chrome/browser/media/router/discovery/dial/dial_device_data.h"
 #include "chrome/browser/media/router/discovery/dial/dial_registry.h"
 #include "chrome/browser/media/router/test/test_helper.h"
-#include "chrome/test/base/testing_profile.h"
 #include "content/public/test/test_browser_thread_bundle.h"
 #include "services/service_manager/public/cpp/connector.h"
 #include "testing/gmock/include/gmock/gmock.h"
@@ -38,9 +37,8 @@
       : DeviceDescriptionService(/*connector=*/nullptr, success_cb, error_cb) {}
   ~MockDeviceDescriptionService() override {}
 
-  MOCK_METHOD2(GetDeviceDescriptions,
-               void(const std::vector<DialDeviceData>& devices,
-                    net::URLRequestContextGetter* request_context));
+  MOCK_METHOD1(GetDeviceDescriptions,
+               void(const std::vector<DialDeviceData>& devices));
 };
 
 class MockDialAppDiscoveryService : public DialAppDiscoveryService {
@@ -50,10 +48,9 @@
       : DialAppDiscoveryService(/*connector=*/nullptr, completed_cb) {}
   ~MockDialAppDiscoveryService() override {}
 
-  MOCK_METHOD3(FetchDialAppInfo,
+  MOCK_METHOD2(FetchDialAppInfo,
                void(const MediaSinkInternal& sink,
-                    const std::string& app_name,
-                    net::URLRequestContextGetter* request_context));
+                    const std::string& app_name));
 };
 
 class DialMediaSinkServiceImplTest : public ::testing::Test {
@@ -65,7 +62,6 @@
             mock_sink_discovered_cb_.Get(),
             dial_sink_added_cb_.Get(),
             mock_available_sinks_updated_cb_.Get(),
-            profile_.GetRequestContext(),
             base::SequencedTaskRunnerHandle::Get())) {}
 
   void SetUp() override {
@@ -93,7 +89,6 @@
 
  protected:
   const content::TestBrowserThreadBundle thread_bundle_;
-  TestingProfile profile_;
 
   base::MockCallback<OnSinksDiscoveredCallback> mock_sink_discovered_cb_;
   base::MockCallback<OnDialSinkAddedCallback> dial_sink_added_cb_;
@@ -130,8 +125,7 @@
   EXPECT_TRUE(media_sink_service_->current_sinks_.empty());
 
   std::vector<DialDeviceData> device_list = {device_data};
-  EXPECT_CALL(*mock_description_service_,
-              GetDeviceDescriptions(device_list, _));
+  EXPECT_CALL(*mock_description_service_, GetDeviceDescriptions(device_list));
 
   EXPECT_CALL(dial_sink_added_cb_, Run(_));
   media_sink_service_->OnDialDeviceEvent(device_list);
@@ -152,8 +146,7 @@
   device_description.unique_id = "unique id";
 
   std::vector<DialDeviceData> device_list = {device_data};
-  EXPECT_CALL(*mock_description_service_,
-              GetDeviceDescriptions(device_list, _));
+  EXPECT_CALL(*mock_description_service_, GetDeviceDescriptions(device_list));
   media_sink_service_->OnDialDeviceEvent(device_list);
 
   EXPECT_CALL(dial_sink_added_cb_, Run(_));
@@ -183,8 +176,7 @@
   device_description.unique_id = "unique id";
 
   std::vector<DialDeviceData> device_list = {device_data};
-  EXPECT_CALL(*mock_description_service_,
-              GetDeviceDescriptions(device_list, _));
+  EXPECT_CALL(*mock_description_service_, GetDeviceDescriptions(device_list));
 
   EXPECT_FALSE(mock_timer_->IsRunning());
   EXPECT_CALL(dial_sink_added_cb_, Run(_));
@@ -222,8 +214,7 @@
   device_description2.unique_id = "unique id 2";
 
   std::vector<DialDeviceData> device_list = {device_data1, device_data2};
-  EXPECT_CALL(*mock_description_service_,
-              GetDeviceDescriptions(device_list, _));
+  EXPECT_CALL(*mock_description_service_, GetDeviceDescriptions(device_list));
   media_sink_service_->OnDialDeviceEvent(device_list);
 
   EXPECT_CALL(dial_sink_added_cb_, Run(_));
@@ -244,7 +235,7 @@
        TestStartStopMonitoringAvailableSinksForApp) {
   MediaSinkInternal dial_sink = CreateDialSink(1);
   EXPECT_CALL(*mock_app_discovery_service_,
-              FetchDialAppInfo(dial_sink, "YouTube", _))
+              FetchDialAppInfo(dial_sink, "YouTube"))
       .Times(1);
   media_sink_service_->current_sinks_.insert_or_assign(dial_sink.sink().id(),
                                                        dial_sink);
@@ -288,7 +279,7 @@
   media_sink_service_->current_sinks_.insert_or_assign(sink_id1, dial_sink1);
   media_sink_service_->current_sinks_.insert_or_assign(sink_id2, dial_sink2);
 
-  EXPECT_CALL(*mock_app_discovery_service_, FetchDialAppInfo(_, _, _)).Times(4);
+  EXPECT_CALL(*mock_app_discovery_service_, FetchDialAppInfo(_, _)).Times(4);
   media_sink_service_->StartMonitoringAvailableSinksForApp("YouTube");
   media_sink_service_->StartMonitoringAvailableSinksForApp("Netflix");
 
@@ -313,7 +304,7 @@
   MediaSinkInternal dial_sink = CreateDialSink(1);
   std::string sink_id = dial_sink.sink().id();
 
-  EXPECT_CALL(*mock_app_discovery_service_, FetchDialAppInfo(_, _, _));
+  EXPECT_CALL(*mock_app_discovery_service_, FetchDialAppInfo(_, _));
   media_sink_service_->current_sinks_.insert_or_assign(sink_id, dial_sink);
   media_sink_service_->StartMonitoringAvailableSinksForApp("YouTube");
 
@@ -332,7 +323,7 @@
        TestOnDialAppInfoAvailableWithAlreadyAvailableSinks) {
   MediaSinkInternal dial_sink = CreateDialSink(1);
 
-  EXPECT_CALL(*mock_app_discovery_service_, FetchDialAppInfo(_, _, _));
+  EXPECT_CALL(*mock_app_discovery_service_, FetchDialAppInfo(_, _));
   media_sink_service_->current_sinks_.insert_or_assign(dial_sink.sink().id(),
                                                        dial_sink);
   media_sink_service_->StartMonitoringAvailableSinksForApp("YouTube");
@@ -349,7 +340,7 @@
 TEST_F(DialMediaSinkServiceImplTest, TestFetchDialAppInfoWithCachedAppInfo) {
   MediaSinkInternal dial_sink = CreateDialSink(1);
 
-  EXPECT_CALL(*mock_app_discovery_service_, FetchDialAppInfo(_, _, _));
+  EXPECT_CALL(*mock_app_discovery_service_, FetchDialAppInfo(_, _));
   media_sink_service_->current_sinks_.insert_or_assign(dial_sink.sink().id(),
                                                        dial_sink);
   media_sink_service_->StartMonitoringAvailableSinksForApp("YouTube");
@@ -360,7 +351,7 @@
   media_sink_service_->OnAppInfoParseCompleted(dial_sink.sink().id(), "YouTube",
                                                SinkAppStatus::kAvailable);
 
-  EXPECT_CALL(*mock_app_discovery_service_, FetchDialAppInfo(_, _, _)).Times(0);
+  EXPECT_CALL(*mock_app_discovery_service_, FetchDialAppInfo(_, _)).Times(0);
   media_sink_service_->StartMonitoringAvailableSinksForApp("YouTube");
 }
 
diff --git a/chrome/browser/media/router/discovery/dial/dial_media_sink_service_unittest.cc b/chrome/browser/media/router/discovery/dial/dial_media_sink_service_unittest.cc
index 1c4e44df..eeb9d4f 100644
--- a/chrome/browser/media/router/discovery/dial/dial_media_sink_service_unittest.cc
+++ b/chrome/browser/media/router/discovery/dial/dial_media_sink_service_unittest.cc
@@ -41,13 +41,11 @@
       const OnSinksDiscoveredCallback& sinks_discovered_cb,
       const OnDialSinkAddedCallback& dial_sink_added_cb,
       const OnAvailableSinksUpdatedCallback& available_sinks_updated_cb,
-      const scoped_refptr<net::URLRequestContextGetter>& request_context,
       const scoped_refptr<base::SingleThreadTaskRunner>& task_runner)
       : DialMediaSinkServiceImpl(std::unique_ptr<service_manager::Connector>(),
                                  sinks_discovered_cb,
                                  dial_sink_added_cb,
                                  available_sinks_updated_cb,
-                                 request_context,
                                  task_runner),
         sinks_discovered_cb_(sinks_discovered_cb),
         dial_sink_added_cb_(dial_sink_added_cb),
@@ -77,22 +75,20 @@
 class TestDialMediaSinkService : public DialMediaSinkService {
  public:
   explicit TestDialMediaSinkService(
-      const scoped_refptr<net::URLRequestContextGetter>& request_context,
       const scoped_refptr<base::TestSimpleTaskRunner>& task_runner)
-      : DialMediaSinkService(request_context), task_runner_(task_runner) {}
+      : DialMediaSinkService(), task_runner_(task_runner) {}
   ~TestDialMediaSinkService() override = default;
 
   std::unique_ptr<DialMediaSinkServiceImpl, base::OnTaskRunnerDeleter>
   CreateImpl(const OnSinksDiscoveredCallback& sinks_discovered_cb,
              const OnDialSinkAddedCallback& dial_sink_added_cb,
-             const OnAvailableSinksUpdatedCallback& available_sinks_updated_cb,
-             const scoped_refptr<net::URLRequestContextGetter>& request_context)
+             const OnAvailableSinksUpdatedCallback& available_sinks_updated_cb)
       override {
     auto mock_impl = std::unique_ptr<MockDialMediaSinkServiceImpl,
                                      base::OnTaskRunnerDeleter>(
         new MockDialMediaSinkServiceImpl(
             sinks_discovered_cb, dial_sink_added_cb, available_sinks_updated_cb,
-            request_context, task_runner_),
+            task_runner_),
         base::OnTaskRunnerDeleter(task_runner_));
     mock_impl_ = mock_impl.get();
     return mock_impl;
@@ -109,8 +105,7 @@
  public:
   DialMediaSinkServiceTest()
       : task_runner_(new base::TestSimpleTaskRunner()),
-        service_(new TestDialMediaSinkService(profile_.GetRequestContext(),
-                                              task_runner_)) {}
+        service_(new TestDialMediaSinkService(task_runner_)) {}
 
   void SetUp() override {
     service_->Start(
diff --git a/chrome/browser/media/router/discovery/mdns/cast_media_sink_service.cc b/chrome/browser/media/router/discovery/mdns/cast_media_sink_service.cc
index 59d309c..b044847 100644
--- a/chrome/browser/media/router/discovery/mdns/cast_media_sink_service.cc
+++ b/chrome/browser/media/router/discovery/mdns/cast_media_sink_service.cc
@@ -18,7 +18,6 @@
 #include "components/cast_channel/cast_socket_service.h"
 #include "net/base/host_port_pair.h"
 #include "net/base/ip_address.h"
-#include "net/url_request/url_request_context_getter.h"
 
 namespace media_router {
 
@@ -92,17 +91,12 @@
 // static
 const char CastMediaSinkService::kCastServiceType[] = "_googlecast._tcp.local";
 
-CastMediaSinkService::CastMediaSinkService(
-    const scoped_refptr<net::URLRequestContextGetter>& request_context)
+CastMediaSinkService::CastMediaSinkService()
     : impl_(nullptr, base::OnTaskRunnerDeleter(nullptr)),
-      request_context_(request_context),
-      weak_ptr_factory_(this) {
-  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
-  DCHECK(request_context_);
-}
+      weak_ptr_factory_(this) {}
 
 CastMediaSinkService::~CastMediaSinkService() {
-  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   if (dns_sd_registry_) {
     dns_sd_registry_->UnregisterDnsSdListener(kCastServiceType);
     dns_sd_registry_->RemoveObserver(this);
@@ -112,7 +106,7 @@
 
 void CastMediaSinkService::Start(
     const OnSinksDiscoveredCallback& sinks_discovered_cb) {
-  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   DCHECK(!impl_);
 
   // |sinks_discovered_cb| should only be invoked on the current sequence.
@@ -142,8 +136,7 @@
       cast_socket_service->task_runner();
   return std::unique_ptr<CastMediaSinkServiceImpl, base::OnTaskRunnerDeleter>(
       new CastMediaSinkServiceImpl(sinks_discovered_cb, cast_socket_service,
-                                   DiscoveryNetworkMonitor::GetInstance(),
-                                   request_context_),
+                                   DiscoveryNetworkMonitor::GetInstance()),
       base::OnTaskRunnerDeleter(task_runner));
 }
 
@@ -160,7 +153,7 @@
 }
 
 void CastMediaSinkService::OnUserGesture() {
-  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   if (dns_sd_registry_)
     dns_sd_registry_->ForceDiscovery();
 
@@ -181,8 +174,7 @@
 void CastMediaSinkService::OnDnsSdEvent(
     const std::string& service_type,
     const DnsSdRegistry::DnsSdServiceList& services) {
-  // TODO(crbug.com/749305): Migrate the discovery code to use sequences.
-  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   DVLOG(2) << "CastMediaSinkService::OnDnsSdEvent found " << services.size()
            << " services";
 
@@ -211,16 +203,10 @@
   return impl_->GetDialSinkAddedCallback();
 }
 
-void CastMediaSinkService::OnDialSinkAdded(const MediaSinkInternal& sink) {
-  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
-  impl_->task_runner()->PostTask(
-      FROM_HERE, base::BindOnce(&CastMediaSinkServiceImpl::OnDialSinkAdded,
-                                base::Unretained(impl_.get()), sink));
-}
-
 void CastMediaSinkService::RunSinksDiscoveredCallback(
     const OnSinksDiscoveredCallback& sinks_discovered_cb,
     std::vector<MediaSinkInternal> sinks) {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   sinks_discovered_cb.Run(std::move(sinks));
 }
 
diff --git a/chrome/browser/media/router/discovery/mdns/cast_media_sink_service.h b/chrome/browser/media/router/discovery/mdns/cast_media_sink_service.h
index 3c973bb..cf854f4 100644
--- a/chrome/browser/media/router/discovery/mdns/cast_media_sink_service.h
+++ b/chrome/browser/media/router/discovery/mdns/cast_media_sink_service.h
@@ -17,7 +17,6 @@
 #include "chrome/browser/media/router/discovery/mdns/dns_sd_registry.h"
 #include "chrome/common/media_router/discovery/media_sink_internal.h"
 #include "chrome/common/media_router/discovery/media_sink_service_util.h"
-#include "content/public/browser/browser_thread.h"
 
 namespace media_router {
 
@@ -31,15 +30,13 @@
   // mDNS service types.
   static const char kCastServiceType[];
 
-  explicit CastMediaSinkService(
-      const scoped_refptr<net::URLRequestContextGetter>& request_context);
-
+  CastMediaSinkService();
   ~CastMediaSinkService() override;
 
   // Returns a callback to |impl_| when a DIAL sink is added (e.g., in order
-  // to perform dual discovery). The callback must be run on the sequence given
-  // by |GetImplTaskRunner()|. It is safe to invoke this callback after |this|
-  // is destroyed.
+  // to perform dual discovery). The callback must be run on the same sequence
+  // as |impl_| and must not be run after |impl_| is destroyed.
+  // This method can only be called after |Start()| is called.
   OnDialSinkAddedCallback GetDialSinkAddedCallback();
 
   // Starts Cast sink discovery. No-ops if already started.
@@ -77,7 +74,6 @@
   FRIEND_TEST_ALL_PREFIXES(CastMediaSinkServiceTest, TestOnDnsSdEvent);
   FRIEND_TEST_ALL_PREFIXES(CastMediaSinkServiceTest, TestTimer);
 
-  void OnDialSinkAdded(const MediaSinkInternal& sink);
   void RunSinksDiscoveredCallback(
       const OnSinksDiscoveredCallback& sinks_discovered_cb,
       std::vector<MediaSinkInternal> sinks);
@@ -96,8 +92,7 @@
   // List of cast sinks found in current round of mDNS discovery.
   std::vector<MediaSinkInternal> cast_sinks_;
 
-  scoped_refptr<net::URLRequestContextGetter> request_context_;
-
+  SEQUENCE_CHECKER(sequence_checker_);
   base::WeakPtrFactory<CastMediaSinkService> weak_ptr_factory_;
 
   DISALLOW_COPY_AND_ASSIGN(CastMediaSinkService);
diff --git a/chrome/browser/media/router/discovery/mdns/cast_media_sink_service_impl.cc b/chrome/browser/media/router/discovery/mdns/cast_media_sink_service_impl.cc
index b3ff166..66dc7373 100644
--- a/chrome/browser/media/router/discovery/mdns/cast_media_sink_service_impl.cc
+++ b/chrome/browser/media/router/discovery/mdns/cast_media_sink_service_impl.cc
@@ -8,7 +8,6 @@
 #include "base/rand_util.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/time/default_clock.h"
-#include "chrome/browser/browser_process.h"
 #include "chrome/browser/media/router/media_router_feature.h"
 #include "chrome/common/media_router/discovery/media_sink_internal.h"
 #include "chrome/common/media_router/media_sink.h"
@@ -19,8 +18,6 @@
 #include "components/net_log/chrome_net_log.h"
 #include "net/base/backoff_entry.h"
 #include "net/base/net_errors.h"
-#include "net/url_request/url_request_context.h"
-#include "net/url_request/url_request_context_getter.h"
 
 namespace {
 
@@ -169,14 +166,11 @@
 CastMediaSinkServiceImpl::CastMediaSinkServiceImpl(
     const OnSinksDiscoveredCallback& callback,
     cast_channel::CastSocketService* cast_socket_service,
-    DiscoveryNetworkMonitor* network_monitor,
-    const scoped_refptr<net::URLRequestContextGetter>&
-        url_request_context_getter)
+    DiscoveryNetworkMonitor* network_monitor)
     : MediaSinkServiceBase(callback),
       cast_socket_service_(cast_socket_service),
       network_monitor_(network_monitor),
       task_runner_(cast_socket_service_->task_runner()),
-      url_request_context_getter_(url_request_context_getter),
       clock_(base::DefaultClock::GetInstance()),
       weak_ptr_factory_(this) {
   DETACH_FROM_SEQUENCE(sequence_checker_);
@@ -407,11 +401,10 @@
                  kMaxLivenessTimeoutInSeconds);
   }
 
+  // TODO(crbug.com/814419): Switching cast socket implementation to use network
+  // service will allow us to get back NetLog.
   return cast_channel::CastSocketOpenParams(
-      ip_endpoint,
-      url_request_context_getter_.get()
-          ? url_request_context_getter_->GetURLRequestContext()->net_log()
-          : nullptr,
+      ip_endpoint, nullptr,
       base::TimeDelta::FromSeconds(connect_timeout_in_seconds),
       base::TimeDelta::FromSeconds(liveness_timeout_in_seconds),
       base::TimeDelta::FromSeconds(open_params_.ping_interval_in_seconds),
@@ -605,19 +598,8 @@
 }
 
 OnDialSinkAddedCallback CastMediaSinkServiceImpl::GetDialSinkAddedCallback() {
-  return base::BindRepeating(
-      &CastMediaSinkServiceImpl::InvokeOnDialSinkAddedOnTaskRunner,
-      GetWeakPtr(), task_runner_);
-}
-
-// static
-void CastMediaSinkServiceImpl::InvokeOnDialSinkAddedOnTaskRunner(
-    const base::WeakPtr<CastMediaSinkServiceImpl>& impl,
-    const scoped_refptr<base::SequencedTaskRunner>& task_runner,
-    const MediaSinkInternal& dial_sink) {
-  task_runner->PostTask(
-      FROM_HERE, base::BindOnce(&CastMediaSinkServiceImpl::OnDialSinkAdded,
-                                impl, dial_sink));
+  return base::BindRepeating(&CastMediaSinkServiceImpl::OnDialSinkAdded,
+                             base::Unretained(this));
 }
 
 CastMediaSinkServiceImpl::RetryParams::RetryParams()
diff --git a/chrome/browser/media/router/discovery/mdns/cast_media_sink_service_impl.h b/chrome/browser/media/router/discovery/mdns/cast_media_sink_service_impl.h
index fa76b49..48ce42f9 100644
--- a/chrome/browser/media/router/discovery/mdns/cast_media_sink_service_impl.h
+++ b/chrome/browser/media/router/discovery/mdns/cast_media_sink_service_impl.h
@@ -20,7 +20,6 @@
 #include "components/cast_channel/cast_channel_enum.h"
 #include "components/cast_channel/cast_socket.h"
 #include "net/base/backoff_entry.h"
-#include "net/url_request/url_request_context_getter.h"
 
 namespace cast_channel {
 class CastSocketService;
@@ -50,13 +49,9 @@
   // discovered devices.
   // |network_monitor|: DiscoveryNetworkMonitor to use to listen for network
   // changes.
-  // |url_request_context_getter|: URLRequestContextGetter used for making
-  // network requests.
   CastMediaSinkServiceImpl(const OnSinksDiscoveredCallback& callback,
                            cast_channel::CastSocketService* cast_socket_service,
-                           DiscoveryNetworkMonitor* network_monitor,
-                           const scoped_refptr<net::URLRequestContextGetter>&
-                               url_request_context_getter);
+                           DiscoveryNetworkMonitor* network_monitor);
   ~CastMediaSinkServiceImpl() override;
 
   // Returns the SequencedTaskRunner that should be used to invoke methods on
@@ -92,8 +87,11 @@
   void AttemptConnection(const std::vector<MediaSinkInternal>& cast_sinks);
 
   // Returns a callback to |this| when a DIAL sink is added (e.g., in order
-  // to perform dual discovery). It is safe to invoke this callback after |this|
-  // is destroyed.
+  // to perform dual discovery). This callback must be invoked on |impl_|'s
+  // sequence.
+  // It is NOT safe to invoke this callback after |this| is destroyed; the
+  // assumption is that |this| will outlive the invoker
+  // (DialMediaSinkServiceImpl), and that they run on the same sequence.
   OnDialSinkAddedCallback GetDialSinkAddedCallback();
 
  private:
@@ -198,14 +196,6 @@
     static OpenParams GetFromFieldTrialParam();
   };
 
-  // Invokes |impl->OnDialSinkAdded| with |dial_sink| on |task_runner|. This
-  // method may be called on any thread, and may be called after |impl| is
-  // destroyed.
-  static void InvokeOnDialSinkAddedOnTaskRunner(
-      const base::WeakPtr<CastMediaSinkServiceImpl>& impl,
-      const scoped_refptr<base::SequencedTaskRunner>& task_runner,
-      const MediaSinkInternal& dial_sink);
-
   // Marked virtual for testing.
   virtual void OpenChannels(const std::vector<MediaSinkInternal>& cast_sinks,
                             SinkSource sink_source);
@@ -337,10 +327,6 @@
   // same SequencedTaskRunner as the one used by |cast_socket_service_|.
   scoped_refptr<base::SequencedTaskRunner> task_runner_;
 
-  // This is a temporary workaround to get access to the net::NetLog* from the
-  // NetworkService.
-  scoped_refptr<net::URLRequestContextGetter> url_request_context_getter_;
-
   base::Clock* clock_;
 
   SEQUENCE_CHECKER(sequence_checker_);
diff --git a/chrome/browser/media/router/discovery/mdns/cast_media_sink_service_impl_unittest.cc b/chrome/browser/media/router/discovery/mdns/cast_media_sink_service_impl_unittest.cc
index f2f73a0..930cdfab 100644
--- a/chrome/browser/media/router/discovery/mdns/cast_media_sink_service_impl_unittest.cc
+++ b/chrome/browser/media/router/discovery/mdns/cast_media_sink_service_impl_unittest.cc
@@ -78,8 +78,7 @@
             new cast_channel::MockCastSocketService(mock_time_task_runner_)),
         media_sink_service_impl_(mock_sink_discovered_cb_.Get(),
                                  mock_cast_socket_service_.get(),
-                                 discovery_network_monitor_.get(),
-                                 nullptr /* url_request_context_getter */) {
+                                 discovery_network_monitor_.get()) {
     mock_cast_socket_service_->SetTaskRunnerForTest(mock_time_task_runner_);
   }
 
diff --git a/chrome/browser/media/router/discovery/mdns/cast_media_sink_service_unittest.cc b/chrome/browser/media/router/discovery/mdns/cast_media_sink_service_unittest.cc
index 6272e9a..a968f8a 100644
--- a/chrome/browser/media/router/discovery/mdns/cast_media_sink_service_unittest.cc
+++ b/chrome/browser/media/router/discovery/mdns/cast_media_sink_service_unittest.cc
@@ -11,7 +11,6 @@
 #include "chrome/browser/media/router/discovery/mdns/cast_media_sink_service_impl.h"
 #include "chrome/browser/media/router/test/mock_dns_sd_registry.h"
 #include "chrome/browser/media/router/test/test_helper.h"
-#include "chrome/test/base/testing_profile.h"
 #include "components/cast_channel/cast_socket.h"
 #include "components/cast_channel/cast_socket_service.h"
 #include "components/cast_channel/cast_test_util.h"
@@ -61,8 +60,7 @@
       DiscoveryNetworkMonitor* network_monitor)
       : CastMediaSinkServiceImpl(callback,
                                  cast_socket_service,
-                                 network_monitor,
-                                 nullptr /* url_request_context_getter */),
+                                 network_monitor),
         sinks_discovered_cb_(callback) {}
   ~MockCastMediaSinkServiceImpl() override {}
 
@@ -82,12 +80,9 @@
 
 class TestCastMediaSinkService : public CastMediaSinkService {
  public:
-  TestCastMediaSinkService(
-      const scoped_refptr<net::URLRequestContextGetter>& request_context,
-      cast_channel::CastSocketService* cast_socket_service,
-      DiscoveryNetworkMonitor* network_monitor)
-      : CastMediaSinkService(request_context),
-        cast_socket_service_(cast_socket_service),
+  TestCastMediaSinkService(cast_channel::CastSocketService* cast_socket_service,
+                           DiscoveryNetworkMonitor* network_monitor)
+      : cast_socket_service_(cast_socket_service),
         network_monitor_(network_monitor) {}
   ~TestCastMediaSinkService() override = default;
 
@@ -118,7 +113,6 @@
         mock_cast_socket_service_(
             new cast_channel::MockCastSocketService(task_runner_)),
         media_sink_service_(new TestCastMediaSinkService(
-            profile_.GetRequestContext(),
             mock_cast_socket_service_.get(),
             DiscoveryNetworkMonitor::GetInstance())),
         test_dns_sd_registry_(media_sink_service_.get()) {}
@@ -149,8 +143,6 @@
   scoped_refptr<base::TestSimpleTaskRunner> task_runner_;
   std::unique_ptr<net::NetworkChangeNotifier> network_change_notifier_;
 
-  TestingProfile profile_;
-
   base::MockCallback<OnSinksDiscoveredCallback> mock_sink_discovered_ui_cb_;
   std::unique_ptr<cast_channel::MockCastSocketService>
       mock_cast_socket_service_;
diff --git a/chrome/browser/media/router/mojo/media_router_desktop_unittest.cc b/chrome/browser/media/router/mojo/media_router_desktop_unittest.cc
index 1621cb2..e0889be 100644
--- a/chrome/browser/media/router/mojo/media_router_desktop_unittest.cc
+++ b/chrome/browser/media/router/mojo/media_router_desktop_unittest.cc
@@ -69,8 +69,7 @@
     std::unique_ptr<MockCastMediaSinkService> cast_media_sink_service;
     if (enable_cast_discovery) {
       feature_list_.InitWithFeatures({kEnableCastDiscovery}, {});
-      cast_media_sink_service = std::make_unique<MockCastMediaSinkService>(
-          profile()->GetRequestContext());
+      cast_media_sink_service = std::make_unique<MockCastMediaSinkService>();
       cast_media_sink_service_ = cast_media_sink_service.get();
     } else {
       feature_list_.InitWithFeatures({}, {kEnableCastDiscovery});
@@ -78,8 +77,7 @@
 
     media_sink_service_ = std::unique_ptr<DualMediaSinkService>(
         new DualMediaSinkService(std::move(cast_media_sink_service),
-                                 std::make_unique<MockDialMediaSinkService>(
-                                     profile()->GetRequestContext())));
+                                 std::make_unique<MockDialMediaSinkService>()));
     return std::unique_ptr<MediaRouterDesktop>(
         new MediaRouterDesktop(profile(), media_sink_service_.get()));
   }
diff --git a/chrome/browser/media/router/providers/cast/dual_media_sink_service.cc b/chrome/browser/media/router/providers/cast/dual_media_sink_service.cc
index 30d22d2e..7775626 100644
--- a/chrome/browser/media/router/providers/cast/dual_media_sink_service.cc
+++ b/chrome/browser/media/router/providers/cast/dual_media_sink_service.cc
@@ -4,13 +4,10 @@
 
 #include "chrome/browser/media/router/providers/cast/dual_media_sink_service.h"
 
-#include "base/memory/ref_counted.h"
-#include "chrome/browser/browser_process.h"
 #include "chrome/browser/media/router/discovery/dial/dial_media_sink_service.h"
 #include "chrome/browser/media/router/discovery/mdns/cast_media_sink_service.h"
 #include "chrome/browser/media/router/media_router_feature.h"
 #include "content/public/browser/browser_thread.h"
-#include "net/url_request/url_request_context_getter.h"
 
 namespace media_router {
 
@@ -56,23 +53,16 @@
 }
 
 DualMediaSinkService::DualMediaSinkService() {
-  scoped_refptr<net::URLRequestContextGetter> request_context =
-      g_browser_process->system_request_context();
-
+  OnDialSinkAddedCallback dial_sink_added_cb;
   if (media_router::CastDiscoveryEnabled()) {
-    cast_media_sink_service_ =
-        std::make_unique<CastMediaSinkService>(request_context);
+    cast_media_sink_service_ = std::make_unique<CastMediaSinkService>();
     cast_media_sink_service_->Start(
         base::BindRepeating(&DualMediaSinkService::OnSinksDiscovered,
                             base::Unretained(this), "cast"));
+    dial_sink_added_cb = cast_media_sink_service_->GetDialSinkAddedCallback();
   }
 
-  OnDialSinkAddedCallback dial_sink_added_cb;
-  if (cast_media_sink_service_)
-    dial_sink_added_cb = cast_media_sink_service_->GetDialSinkAddedCallback();
-
-  dial_media_sink_service_ =
-      std::make_unique<DialMediaSinkService>(request_context);
+  dial_media_sink_service_ = std::make_unique<DialMediaSinkService>();
   dial_media_sink_service_->Start(
       base::BindRepeating(&DualMediaSinkService::OnSinksDiscovered,
                           base::Unretained(this), "dial"),
diff --git a/chrome/browser/media/router/providers/cast/dual_media_sink_service.h b/chrome/browser/media/router/providers/cast/dual_media_sink_service.h
index a957e36..f81befd 100644
--- a/chrome/browser/media/router/providers/cast/dual_media_sink_service.h
+++ b/chrome/browser/media/router/providers/cast/dual_media_sink_service.h
@@ -15,13 +15,14 @@
 #include "base/gtest_prod_util.h"
 #include "base/macros.h"
 #include "base/sequence_checker.h"
-#include "chrome/browser/media/router/discovery/dial/dial_media_sink_service.h"
+#include "chrome/browser/media/router/media_sinks_observer.h"
 #include "chrome/common/media_router/discovery/media_sink_internal.h"
 #include "chrome/common/media_router/media_source.h"
 #include "url/origin.h"
 
 namespace media_router {
 
+class DialMediaSinkService;
 class CastMediaSinkService;
 
 // This class uses DialMediaSinkService and CastMediaSinkService to discover
diff --git a/chrome/browser/media/router/providers/cast/dual_media_sink_service_unittest.cc b/chrome/browser/media/router/providers/cast/dual_media_sink_service_unittest.cc
index fe3433f..9d420c74 100644
--- a/chrome/browser/media/router/providers/cast/dual_media_sink_service_unittest.cc
+++ b/chrome/browser/media/router/providers/cast/dual_media_sink_service_unittest.cc
@@ -5,8 +5,6 @@
 #include "chrome/browser/media/router/providers/cast/dual_media_sink_service.h"
 
 #include "chrome/browser/media/router/test/test_helper.h"
-#include "chrome/test/base/testing_profile.h"
-#include "content/public/test/test_browser_thread_bundle.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -15,10 +13,8 @@
 class DualMediaSinkServiceTest : public testing::Test {
  public:
   DualMediaSinkServiceTest() {
-    auto cast_media_sink_service = std::make_unique<MockCastMediaSinkService>(
-        profile_.GetRequestContext());
-    auto dial_media_sink_service = std::make_unique<MockDialMediaSinkService>(
-        profile_.GetRequestContext());
+    auto cast_media_sink_service = std::make_unique<MockCastMediaSinkService>();
+    auto dial_media_sink_service = std::make_unique<MockDialMediaSinkService>();
     cast_media_sink_service_ = cast_media_sink_service.get();
     dial_media_sink_service_ = dial_media_sink_service.get();
     dual_media_sink_service_ = std::unique_ptr<DualMediaSinkService>(
@@ -43,8 +39,6 @@
                     const std::vector<MediaSinkInternal>& sinks));
 
  private:
-  content::TestBrowserThreadBundle thread_bundle_;
-  TestingProfile profile_;
   MockCastMediaSinkService* cast_media_sink_service_;
   MockDialMediaSinkService* dial_media_sink_service_;
   std::unique_ptr<DualMediaSinkService> dual_media_sink_service_;
diff --git a/chrome/browser/media/router/test/test_helper.cc b/chrome/browser/media/router/test/test_helper.cc
index ea890da..1857df2de 100644
--- a/chrome/browser/media/router/test/test_helper.cc
+++ b/chrome/browser/media/router/test/test_helper.cc
@@ -50,14 +50,10 @@
 MockPresentationConnectionProxy::~MockPresentationConnectionProxy() {}
 
 #if !defined(OS_ANDROID)
-MockDialMediaSinkService::MockDialMediaSinkService(
-    const scoped_refptr<net::URLRequestContextGetter>& request_context)
-    : DialMediaSinkService(request_context) {}
+MockDialMediaSinkService::MockDialMediaSinkService() : DialMediaSinkService() {}
 MockDialMediaSinkService::~MockDialMediaSinkService() = default;
 
-MockCastMediaSinkService::MockCastMediaSinkService(
-    const scoped_refptr<net::URLRequestContextGetter>& request_context)
-    : CastMediaSinkService(request_context) {}
+MockCastMediaSinkService::MockCastMediaSinkService() : CastMediaSinkService() {}
 MockCastMediaSinkService::~MockCastMediaSinkService() = default;
 #endif  // !defined(OS_ANDROID)
 
diff --git a/chrome/browser/media/router/test/test_helper.h b/chrome/browser/media/router/test/test_helper.h
index 46b8d62..5bd879b 100644
--- a/chrome/browser/media/router/test/test_helper.h
+++ b/chrome/browser/media/router/test/test_helper.h
@@ -113,8 +113,7 @@
 #if !defined(OS_ANDROID)
 class MockDialMediaSinkService : public DialMediaSinkService {
  public:
-  explicit MockDialMediaSinkService(
-      const scoped_refptr<net::URLRequestContextGetter>& request_context);
+  MockDialMediaSinkService();
   ~MockDialMediaSinkService() override;
 
   MOCK_METHOD2(Start,
@@ -125,8 +124,7 @@
 
 class MockCastMediaSinkService : public CastMediaSinkService {
  public:
-  explicit MockCastMediaSinkService(
-      const scoped_refptr<net::URLRequestContextGetter>& request_context);
+  MockCastMediaSinkService();
   ~MockCastMediaSinkService() override;
 
   MOCK_METHOD1(Start, void(const OnSinksDiscoveredCallback&));
diff --git a/chrome/browser/net/network_context_configuration_browsertest.cc b/chrome/browser/net/network_context_configuration_browsertest.cc
index 862b8435..7a8f50e 100644
--- a/chrome/browser/net/network_context_configuration_browsertest.cc
+++ b/chrome/browser/net/network_context_configuration_browsertest.cc
@@ -8,6 +8,7 @@
 #include "base/files/file_path.h"
 #include "base/files/file_util.h"
 #include "base/files/scoped_temp_dir.h"
+#include "base/guid.h"
 #include "base/strings/string_util.h"
 #include "base/strings/stringprintf.h"
 #include "base/test/scoped_feature_list.h"
@@ -53,6 +54,8 @@
 
 namespace {
 
+const char kCacheRandomPath[] = "/cacherandom";
+
 enum class NetworkServiceState {
   kDisabled,
   kEnabled,
@@ -86,9 +89,25 @@
   };
 
   NetworkContextConfigurationBrowserTest() {
+    embedded_test_server()->RegisterRequestHandler(
+        base::Bind(&NetworkContextConfigurationBrowserTest::HandleCacheRandom));
     EXPECT_TRUE(embedded_test_server()->Start());
   }
 
+  // Returns a cacheable response (10 hours) that is some random text.
+  static std::unique_ptr<net::test_server::HttpResponse> HandleCacheRandom(
+      const net::test_server::HttpRequest& request) {
+    if (request.relative_url != kCacheRandomPath)
+      return nullptr;
+
+    std::unique_ptr<net::test_server::BasicHttpResponse> response =
+        std::make_unique<net::test_server::BasicHttpResponse>();
+    response->set_content(base::GenerateGUID());
+    response->set_content_type("text/plain");
+    response->AddCustomHeader("Cache-Control", "max-age=60000");
+    return std::move(response);
+  }
+
   ~NetworkContextConfigurationBrowserTest() override {}
 
   void SetUpInProcessBrowserTestFixture() override {
@@ -406,19 +425,16 @@
   // a random port, so need to know the port to try and retrieve it from the
   // cache in the next test). The profile directory is preserved between the
   // PRE_DiskCache and DiskCache run, so can just keep a file there.
-  GURL test_url = embedded_test_server()->GetURL("/echoheadercache?foo");
+  GURL test_url = embedded_test_server()->GetURL(kCacheRandomPath);
   base::ScopedAllowBlockingForTesting allow_blocking;
   base::FilePath save_url_file_path = browser()->profile()->GetPath().Append(
       FILE_PATH_LITERAL("url_for_test.txt"));
-  ASSERT_EQ(static_cast<int>(test_url.spec().length()),
-            base::WriteFile(save_url_file_path, test_url.spec().c_str(),
-                            test_url.spec().length()));
 
   // Make a request whose response should be cached.
   std::unique_ptr<network::ResourceRequest> request =
       std::make_unique<network::ResourceRequest>();
   request->url = test_url;
-  request->headers.SetHeader("foo", "foopity foo");
+
   content::SimpleURLLoaderTestHelper simple_loader_helper;
   std::unique_ptr<network::SimpleURLLoader> simple_loader =
       network::SimpleURLLoader::Create(std::move(request),
@@ -429,7 +445,16 @@
 
   EXPECT_EQ(net::OK, simple_loader->NetError());
   ASSERT_TRUE(simple_loader_helper.response_body());
-  EXPECT_EQ(*simple_loader_helper.response_body(), "foopity foo");
+  EXPECT_FALSE(simple_loader_helper.response_body()->empty());
+
+  // Write the URL and expected response to a file.
+  std::string file_data =
+      test_url.spec() + "\n" + *simple_loader_helper.response_body();
+  ASSERT_EQ(
+      static_cast<int>(file_data.length()),
+      base::WriteFile(save_url_file_path, file_data.data(), file_data.size()));
+
+  EXPECT_TRUE(embedded_test_server()->ShutdownAndWaitUntilComplete());
 }
 
 // Check if the URL loaded in PRE_DiskCache is still in the cache, across a
@@ -439,34 +464,39 @@
   base::ScopedAllowBlockingForTesting allow_blocking;
   base::FilePath save_url_file_path = browser()->profile()->GetPath().Append(
       FILE_PATH_LITERAL("url_for_test.txt"));
-  std::string test_url_string;
-  ASSERT_TRUE(ReadFileToString(save_url_file_path, &test_url_string));
-  GURL test_url = GURL(content::kChromeUINetworkViewCacheURL + test_url_string);
-  ASSERT_TRUE(test_url.is_valid()) << test_url_string;
+  std::string file_data;
+  ASSERT_TRUE(ReadFileToString(save_url_file_path, &file_data));
 
-  network::TestURLLoaderClient client;
-  // Read from the cache directly, as the test server may theoretically have
-  // been restarted on the same port by another test.
-  network_context()->HandleViewCacheRequest(test_url,
-                                            client.CreateInterfacePtr());
+  size_t newline_pos = file_data.find('\n');
+  ASSERT_NE(newline_pos, std::string::npos);
 
-  // The request should succeed, whether the response was cached or not.
-  client.RunUntilResponseReceived();
-  ASSERT_TRUE(client.response_head().headers);
-  EXPECT_EQ(200, client.response_head().headers->response_code());
-  client.RunUntilResponseBodyArrived();
-  std::string response_body;
-  EXPECT_TRUE(mojo::common::BlockingCopyToString(client.response_body_release(),
-                                                 &response_body));
-  client.RunUntilComplete();
-  EXPECT_EQ(net::OK, client.completion_status().error_code);
+  GURL test_url = GURL(file_data.substr(0, newline_pos));
+  ASSERT_TRUE(test_url.is_valid()) << test_url.possibly_invalid_spec();
 
-  // The response body from the above test should only appear in the view-cache
-  // result if there is an on-disk cache.
+  std::string original_response = file_data.substr(newline_pos + 1);
+
+  // Request the same test URL as may have been cached by PRE_DiskCache.
+  std::unique_ptr<network::ResourceRequest> request =
+      std::make_unique<network::ResourceRequest>();
+  request->url = test_url;
+  content::SimpleURLLoaderTestHelper simple_loader_helper;
+  std::unique_ptr<network::SimpleURLLoader> simple_loader =
+      network::SimpleURLLoader::Create(std::move(request),
+                                       TRAFFIC_ANNOTATION_FOR_TESTS);
+  simple_loader->DownloadToStringOfUnboundedSizeUntilCrashAndDie(
+      loader_factory(), simple_loader_helper.GetCallback());
+  simple_loader_helper.WaitForCallback();
+
+  std::string response_body = simple_loader_helper.response_body()
+                                  ? *simple_loader_helper.response_body()
+                                  : "";
+
+  // The response body from the above test should only appear in the response
+  // if there is an on-disk cache.
   if (GetHttpCacheType() != StorageType::kDisk) {
-    EXPECT_EQ(response_body.find("foopity foo"), std::string::npos);
+    EXPECT_NE(original_response, response_body);
   } else {
-    EXPECT_NE(response_body.find("foopity foo"), std::string::npos);
+    EXPECT_EQ(original_response, response_body);
   }
 }
 
diff --git a/chrome/browser/notifications/notification_platform_bridge_win.cc b/chrome/browser/notifications/notification_platform_bridge_win.cc
index 76caf984..2f33b5c5 100644
--- a/chrome/browser/notifications/notification_platform_bridge_win.cc
+++ b/chrome/browser/notifications/notification_platform_bridge_win.cc
@@ -276,11 +276,11 @@
       return;
     }
 
-    std::string encoded_id = NotificationPlatformBridgeWin::EncodeTemplateId(
+    std::string launch_id = NotificationPlatformBridgeWin::EncodeLaunchId(
         notification_type, notification->id(), profile_id, incognito,
         notification->origin_url());
     std::unique_ptr<NotificationTemplateBuilder> notification_template =
-        NotificationTemplateBuilder::Build(image_retainer_.get(), encoded_id,
+        NotificationTemplateBuilder::Build(image_retainer_.get(), launch_id,
                                            profile_id, *notification);
     mswr::ComPtr<winui::Notifications::IToastNotification> toast;
     HRESULT hr = GetToastNotification(*notification, *notification_template,
@@ -449,12 +449,12 @@
     auto displayed_notifications = std::make_unique<std::set<std::string>>();
     for (winui::Notifications::IToastNotification* notification :
          notifications) {
-      std::string toast_id = GetNotificationId(notification);
+      std::string launch_id = GetNotificationLaunchId(notification);
       std::string decoded_notification_id;
       std::string decoded_profile_id;
       bool decoded_incognito;
-      if (!NotificationPlatformBridgeWin::DecodeTemplateId(
-              toast_id, nullptr, &decoded_notification_id, &decoded_profile_id,
+      if (!NotificationPlatformBridgeWin::DecodeLaunchId(
+              launch_id, nullptr, &decoded_notification_id, &decoded_profile_id,
               &decoded_incognito, nullptr)) {
         LOG(ERROR) << "Failed to decode notification ID";
         continue;
@@ -486,11 +486,11 @@
     bool incognito;
     GURL origin_url;
 
-    std::string toast_id = GetNotificationId(notification);
-    if (!NotificationPlatformBridgeWin::DecodeTemplateId(
-            toast_id, &notification_type, &notification_id, &profile_id,
+    std::string launch_id = GetNotificationLaunchId(notification);
+    if (!NotificationPlatformBridgeWin::DecodeLaunchId(
+            launch_id, &notification_type, &notification_id, &profile_id,
             &incognito, &origin_url)) {
-      LOG(ERROR) << "Failed to decode template ID for operation " << operation;
+      LOG(ERROR) << "Failed to decode launch ID for operation " << operation;
       return;
     }
 
@@ -510,8 +510,12 @@
 
     ScopedHString arguments_scoped(arguments);
     std::string arguments_str = arguments_scoped.GetAsUTF8();
+    std::vector<std::string> tokens = base::SplitString(
+        arguments_str, "$", base::TRIM_WHITESPACE, base::SPLIT_WANT_NONEMPTY);
+    std::string button_index = tokens[0];
+
     std::vector<std::string> parts = base::SplitString(
-        arguments_str, "=", base::TRIM_WHITESPACE, base::SPLIT_WANT_NONEMPTY);
+        button_index, "=", base::TRIM_WHITESPACE, base::SPLIT_WANT_NONEMPTY);
     if (parts.size() < 2 || base::CompareCaseInsensitiveASCII(
                                 parts[0], kNotificationButtonIndex) != 0)
       return base::nullopt;
@@ -544,7 +548,7 @@
     return base::UintToString16(base::Hash(notification_id));
   }
 
-  std::string GetNotificationId(
+  std::string GetNotificationLaunchId(
       winui::Notifications::IToastNotification* notification) const {
     mswr::ComPtr<winxml::Dom::IXmlDocument> document;
     HRESULT hr = notification->get_Content(&document);
@@ -786,8 +790,8 @@
 }
 
 // static
-bool NotificationPlatformBridgeWin::DecodeTemplateId(
-    const std::string& encoded,
+bool NotificationPlatformBridgeWin::DecodeLaunchId(
+    const std::string& launch_id,
     NotificationHandler::Type* notification_type,
     std::string* notification_id,
     std::string* profile_id,
@@ -797,7 +801,7 @@
   const char kDelimiter[] = "|";
   const int kMinVectorSize = 5;
   std::vector<std::string> split = base::SplitString(
-      encoded, kDelimiter, base::KEEP_WHITESPACE, base::SPLIT_WANT_ALL);
+      launch_id, kDelimiter, base::KEEP_WHITESPACE, base::SPLIT_WANT_ALL);
   if (split.size() < kMinVectorSize)
     return false;
 
@@ -829,7 +833,7 @@
 }
 
 // static
-std::string NotificationPlatformBridgeWin::EncodeTemplateId(
+std::string NotificationPlatformBridgeWin::EncodeLaunchId(
     NotificationHandler::Type notification_type,
     const std::string& notification_id,
     const std::string& profile_id,
diff --git a/chrome/browser/notifications/notification_platform_bridge_win.h b/chrome/browser/notifications/notification_platform_bridge_win.h
index c54e35d2..85e36239 100644
--- a/chrome/browser/notifications/notification_platform_bridge_win.h
+++ b/chrome/browser/notifications/notification_platform_bridge_win.h
@@ -68,23 +68,22 @@
       const NotificationTemplateBuilder& notification_template_builder,
       ABI::Windows::UI::Notifications::IToastNotification** toast_notification);
 
-  // Takes an |encoded| string as input and decodes it, returning the values in
-  // the out parameters. |encoded| and |notifiation_id| must be provided. Other
+  // Takes |launch_id| as input and decodes it, returning the values in the out
+  // parameters. |launch_id| and |notifiation_id| must be provided. Other
   // pointers can be nullptr. Returns true if successful, but false otherwise.
-  static bool DecodeTemplateId(const std::string& encoded,
-                               NotificationHandler::Type* notification_type,
-                               std::string* notification_id,
-                               std::string* profile_id,
-                               bool* incognito,
-                               GURL* origin_url) WARN_UNUSED_RESULT;
+  static bool DecodeLaunchId(const std::string& launch_id,
+                             NotificationHandler::Type* notification_type,
+                             std::string* notification_id,
+                             std::string* profile_id,
+                             bool* incognito,
+                             GURL* origin_url) WARN_UNUSED_RESULT;
 
-  // Encodes a template ID string given the input parameters.
-  static std::string EncodeTemplateId(
-      NotificationHandler::Type notification_type,
-      const std::string& notification_id,
-      const std::string& profile_id,
-      bool incognito,
-      const GURL& origin_url);
+  // Encodes a launch ID string given the input parameters.
+  static std::string EncodeLaunchId(NotificationHandler::Type notification_type,
+                                    const std::string& notification_id,
+                                    const std::string& profile_id,
+                                    bool incognito,
+                                    const GURL& origin_url);
 
   scoped_refptr<NotificationPlatformBridgeWinImpl> impl_;
 
diff --git a/chrome/browser/notifications/notification_platform_bridge_win_unittest.cc b/chrome/browser/notifications/notification_platform_bridge_win_unittest.cc
index 2c57ef3..e876760 100644
--- a/chrome/browser/notifications/notification_platform_bridge_win_unittest.cc
+++ b/chrome/browser/notifications/notification_platform_bridge_win_unittest.cc
@@ -33,7 +33,7 @@
 
 namespace {
 
-const char kEncodedId[] = "0|Default|0|https://example.com/|notification_id";
+const char kLaunchId[] = "0|Default|0|https://example.com/|notification_id";
 const char kOrigin[] = "https://www.google.com/";
 const char kNotificationId[] = "id";
 const char kProfileId[] = "Default";
@@ -59,7 +59,7 @@
     notification->set_renotify(renotify);
     MockNotificationImageRetainer image_retainer;
     std::unique_ptr<NotificationTemplateBuilder> builder =
-        NotificationTemplateBuilder::Build(&image_retainer, kEncodedId,
+        NotificationTemplateBuilder::Build(&image_retainer, kLaunchId,
                                            kProfileId, *notification);
 
     mswr::ComPtr<winui::Notifications::IToastNotification> toast;
@@ -98,7 +98,7 @@
   bool incognito = false;
   GURL origin_url("http://www.google.com/");
 
-  std::string encoded = notification_platform_bridge_win_->EncodeTemplateId(
+  std::string launch_id = notification_platform_bridge_win_->EncodeLaunchId(
       notification_type, notification_id, profile_id, incognito, origin_url);
 
   NotificationHandler::Type decoded_notification_type;
@@ -108,13 +108,13 @@
   GURL decoded_origin_url;
 
   // Empty string.
-  EXPECT_FALSE(notification_platform_bridge_win_->DecodeTemplateId(
+  EXPECT_FALSE(notification_platform_bridge_win_->DecodeLaunchId(
       "", &decoded_notification_type, &decoded_notification_id,
       &decoded_profile_id, &decoded_incognito, &decoded_origin_url));
 
   // Actual data.
-  EXPECT_TRUE(notification_platform_bridge_win_->DecodeTemplateId(
-      encoded, &decoded_notification_type, &decoded_notification_id,
+  EXPECT_TRUE(notification_platform_bridge_win_->DecodeLaunchId(
+      launch_id, &decoded_notification_type, &decoded_notification_id,
       &decoded_profile_id, &decoded_incognito, &decoded_origin_url));
 
   EXPECT_EQ(decoded_notification_type, notification_type);
@@ -124,20 +124,20 @@
   EXPECT_EQ(decoded_origin_url, origin_url);
 
   // Actual data, but only notification_id is requested.
-  EXPECT_TRUE(notification_platform_bridge_win_->DecodeTemplateId(
-      encoded, nullptr /* notification_type */, &decoded_notification_id,
+  EXPECT_TRUE(notification_platform_bridge_win_->DecodeLaunchId(
+      launch_id, nullptr /* notification_type */, &decoded_notification_id,
       nullptr /* profile_id */, nullptr /* incognito */,
       nullptr /* origin_url */));
   EXPECT_EQ(decoded_notification_id, notification_id);
 
   // Throw in a few extra separators (becomes part of the notification id).
   std::string extra = "|Extra|Data|";
-  encoded += extra;
+  launch_id += extra;
   // Update the expected output as well.
   notification_id += extra;
 
-  EXPECT_TRUE(notification_platform_bridge_win_->DecodeTemplateId(
-      encoded, &decoded_notification_type, &decoded_notification_id,
+  EXPECT_TRUE(notification_platform_bridge_win_->DecodeLaunchId(
+      launch_id, &decoded_notification_type, &decoded_notification_id,
       &decoded_profile_id, &decoded_incognito, &decoded_origin_url));
 
   EXPECT_EQ(decoded_notification_type, notification_type);
diff --git a/chrome/browser/notifications/notification_template_builder.cc b/chrome/browser/notifications/notification_template_builder.cc
index 57fcbe6..16840945 100644
--- a/chrome/browser/notifications/notification_template_builder.cc
+++ b/chrome/browser/notifications/notification_template_builder.cc
@@ -129,7 +129,7 @@
 
   builder->StartActionsElement();
   if (!notification.buttons().empty())
-    builder->AddActions(notification);
+    builder->AddActions(notification, launch_attribute);
   builder->AddContextMenu();
   builder->EndActionsElement();
 
@@ -289,7 +289,8 @@
 }
 
 void NotificationTemplateBuilder::AddActions(
-    const message_center::Notification& notification) {
+    const message_center::Notification& notification,
+    const std::string& launch_attribute) {
   const std::vector<message_center::ButtonInfo>& buttons =
       notification.buttons();
   bool inline_reply = false;
@@ -312,7 +313,8 @@
   }
 
   for (size_t i = 0; i < buttons.size(); ++i)
-    WriteActionElement(buttons[i], i, notification.origin_url());
+    WriteActionElement(buttons[i], i, notification.origin_url(),
+                       launch_attribute);
 }
 
 void NotificationTemplateBuilder::AddContextMenu() {
@@ -340,12 +342,14 @@
 void NotificationTemplateBuilder::WriteActionElement(
     const message_center::ButtonInfo& button,
     int index,
-    const GURL& origin) {
+    const GURL& origin,
+    const std::string& launch_attribute) {
   xml_writer_->StartElement(kActionElement);
   xml_writer_->AddAttribute(kActivationType, kForeground);
   xml_writer_->AddAttribute(kContent, base::UTF16ToUTF8(button.title));
-  std::string param =
-      std::string(kNotificationButtonIndex) + "=" + base::IntToString(index);
+  std::string param = base::StringPrintf("%s=%s$%s", kNotificationButtonIndex,
+                                         base::IntToString(index).c_str(),
+                                         launch_attribute.c_str());
   xml_writer_->AddAttribute(kArguments, param);
 
   if (!button.icon.IsEmpty()) {
diff --git a/chrome/browser/notifications/notification_template_builder.h b/chrome/browser/notifications/notification_template_builder.h
index 81267c13..74e73779 100644
--- a/chrome/browser/notifications/notification_template_builder.h
+++ b/chrome/browser/notifications/notification_template_builder.h
@@ -120,10 +120,12 @@
 
   // Fills in the details for the actions (the buttons the notification
   // contains).
-  void AddActions(const message_center::Notification& notification);
+  void AddActions(const message_center::Notification& notification,
+                  const std::string& launch_attribute);
   void WriteActionElement(const message_center::ButtonInfo& button,
                           int index,
-                          const GURL& origin);
+                          const GURL& origin,
+                          const std::string& launch_attribute);
 
   // Adds context menu actions to the notification sent by |origin|.
   void AddContextMenu();
diff --git a/chrome/browser/notifications/notification_template_builder_unittest.cc b/chrome/browser/notifications/notification_template_builder_unittest.cc
index c7fed72..7ed3c4b 100644
--- a/chrome/browser/notifications/notification_template_builder_unittest.cc
+++ b/chrome/browser/notifications/notification_template_builder_unittest.cc
@@ -139,8 +139,8 @@
   </binding>
  </visual>
  <actions>
-  <action activationType="foreground" content="Button1" arguments="buttonIndex=0"/>
-  <action activationType="foreground" content="Button2" arguments="buttonIndex=1"/>
+  <action activationType="foreground" content="Button1" arguments="buttonIndex=0$0|Default|0|https://example.com/|notification_id"/>
+  <action activationType="foreground" content="Button2" arguments="buttonIndex=1$0|Default|0|https://example.com/|notification_id"/>
   <action content="settings" placement="contextMenu" activationType="foreground" arguments="notificationSettings"/>
  </actions>
 </toast>
@@ -171,8 +171,8 @@
  </visual>
  <actions>
   <input id="userResponse" type="text" placeHolderContent="Reply here"/>
-  <action activationType="foreground" content="Button1" arguments="buttonIndex=0"/>
-  <action activationType="foreground" content="Button2" arguments="buttonIndex=1"/>
+  <action activationType="foreground" content="Button1" arguments="buttonIndex=0$0|Default|0|https://example.com/|notification_id"/>
+  <action activationType="foreground" content="Button2" arguments="buttonIndex=1$0|Default|0|https://example.com/|notification_id"/>
   <action content="settings" placement="contextMenu" activationType="foreground" arguments="notificationSettings"/>
  </actions>
 </toast>
@@ -205,8 +205,8 @@
  </visual>
  <actions>
   <input id="userResponse" type="text" placeHolderContent="Reply here"/>
-  <action activationType="foreground" content="Button1" arguments="buttonIndex=0"/>
-  <action activationType="foreground" content="Button2" arguments="buttonIndex=1"/>
+  <action activationType="foreground" content="Button1" arguments="buttonIndex=0$0|Default|0|https://example.com/|notification_id"/>
+  <action activationType="foreground" content="Button2" arguments="buttonIndex=1$0|Default|0|https://example.com/|notification_id"/>
   <action content="settings" placement="contextMenu" activationType="foreground" arguments="notificationSettings"/>
  </actions>
 </toast>
@@ -237,8 +237,8 @@
  </visual>
  <actions>
   <input id="userResponse" type="text" placeHolderContent="Reply here"/>
-  <action activationType="foreground" content="Button1" arguments="buttonIndex=0"/>
-  <action activationType="foreground" content="Button2" arguments="buttonIndex=1"/>
+  <action activationType="foreground" content="Button1" arguments="buttonIndex=0$0|Default|0|https://example.com/|notification_id"/>
+  <action activationType="foreground" content="Button2" arguments="buttonIndex=1$0|Default|0|https://example.com/|notification_id"/>
   <action content="settings" placement="contextMenu" activationType="foreground" arguments="notificationSettings"/>
  </actions>
 </toast>
@@ -290,7 +290,7 @@
   </binding>
  </visual>
  <actions>
-  <action activationType="foreground" content="Button1" arguments="buttonIndex=0"/>
+  <action activationType="foreground" content="Button1" arguments="buttonIndex=0$0|Default|0|https://example.com/|notification_id"/>
   <action content="settings" placement="contextMenu" activationType="foreground" arguments="notificationSettings"/>
  </actions>
 </toast>
@@ -383,7 +383,7 @@
  </visual>
  <actions>
   <input id="userResponse" type="text" placeHolderContent="Reply here"/>
-  <action activationType="foreground" content="Button1" arguments="buttonIndex=0" imageUri="c:\temp\img2.tmp"/>
+  <action activationType="foreground" content="Button1" arguments="buttonIndex=0$0|Default|0|https://example.com/|notification_id" imageUri="c:\temp\img2.tmp"/>
   <action content="settings" placement="contextMenu" activationType="foreground" arguments="notificationSettings"/>
  </actions>
 </toast>
diff --git a/chrome/browser/offline_pages/android/offline_page_bridge.cc b/chrome/browser/offline_pages/android/offline_page_bridge.cc
index e522e73f..1355c87 100644
--- a/chrome/browser/offline_pages/android/offline_page_bridge.cc
+++ b/chrome/browser/offline_pages/android/offline_page_bridge.cc
@@ -454,6 +454,22 @@
       client_ids, base::Bind(&DeletePageCallback, j_callback_ref));
 }
 
+void OfflinePageBridge::DeletePagesByClientIdAndOrigin(
+    JNIEnv* env,
+    const base::android::JavaParamRef<jobject>& obj,
+    const base::android::JavaParamRef<jobjectArray>& j_namespaces_array,
+    const base::android::JavaParamRef<jobjectArray>& j_ids_array,
+    const base::android::JavaParamRef<jstring>& j_origin,
+    const base::android::JavaParamRef<jobject>& j_callback_obj) {
+  ScopedJavaGlobalRef<jobject> j_callback_ref;
+  j_callback_ref.Reset(env, j_callback_obj);
+  std::vector<ClientId> client_ids =
+      getClientIdsFromObjectArrays(env, j_namespaces_array, j_ids_array);
+  offline_page_model_->DeletePagesByClientIdsAndOrigin(
+      client_ids, ConvertJavaStringToUTF8(j_origin),
+      base::Bind(&DeletePageCallback, j_callback_ref));
+}
+
 void OfflinePageBridge::DeletePagesByOfflineId(
     JNIEnv* env,
     const JavaParamRef<jobject>& obj,
diff --git a/chrome/browser/offline_pages/android/offline_page_bridge.h b/chrome/browser/offline_pages/android/offline_page_bridge.h
index 76b0d16..24516ecc 100644
--- a/chrome/browser/offline_pages/android/offline_page_bridge.h
+++ b/chrome/browser/offline_pages/android/offline_page_bridge.h
@@ -68,6 +68,14 @@
       const base::android::JavaParamRef<jobjectArray>& j_ids_array,
       const base::android::JavaParamRef<jobject>& j_callback_obj);
 
+  void DeletePagesByClientIdAndOrigin(
+      JNIEnv* env,
+      const base::android::JavaParamRef<jobject>& obj,
+      const base::android::JavaParamRef<jobjectArray>& j_namespaces_array,
+      const base::android::JavaParamRef<jobjectArray>& j_ids_array,
+      const base::android::JavaParamRef<jstring>& j_origin,
+      const base::android::JavaParamRef<jobject>& j_callback_obj);
+
   void DeletePagesByOfflineId(
       JNIEnv* env,
       const base::android::JavaParamRef<jobject>& obj,
diff --git a/chrome/browser/page_load_metrics/observers/android_page_load_metrics_observer.cc b/chrome/browser/page_load_metrics/observers/android_page_load_metrics_observer.cc
index 05d3352..742a2b6 100644
--- a/chrome/browser/page_load_metrics/observers/android_page_load_metrics_observer.cc
+++ b/chrome/browser/page_load_metrics/observers/android_page_load_metrics_observer.cc
@@ -66,6 +66,17 @@
       first_contentful_paint_ms);
 }
 
+void AndroidPageLoadMetricsObserver::OnFirstMeaningfulPaintInMainFrameDocument(
+    const page_load_metrics::mojom::PageLoadTiming& timing,
+    const page_load_metrics::PageLoadExtraInfo& extra_info) {
+  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+  int64_t first_meaningful_paint_ms =
+      timing.paint_timing->first_meaningful_paint->InMilliseconds();
+  ReportFirstMeaningfulPaint(
+      (extra_info.navigation_start - base::TimeTicks()).InMicroseconds(),
+      first_meaningful_paint_ms);
+}
+
 void AndroidPageLoadMetricsObserver::OnLoadEventStart(
     const page_load_metrics::mojom::PageLoadTiming& timing,
     const page_load_metrics::PageLoadExtraInfo& info) {
@@ -144,6 +155,18 @@
       static_cast<jlong>(first_contentful_paint_ms));
 }
 
+void AndroidPageLoadMetricsObserver::ReportFirstMeaningfulPaint(
+    int64_t navigation_start_tick,
+    int64_t first_meaningful_paint_ms) {
+  base::android::ScopedJavaLocalRef<jobject> java_web_contents =
+      web_contents_->GetJavaWebContents();
+  JNIEnv* env = base::android::AttachCurrentThread();
+  Java_PageLoadMetrics_onFirstMeaningfulPaint(
+      env, java_web_contents, static_cast<jlong>(navigation_id_),
+      static_cast<jlong>(navigation_start_tick),
+      static_cast<jlong>(first_meaningful_paint_ms));
+}
+
 void AndroidPageLoadMetricsObserver::ReportLoadEventStart(
     int64_t navigation_start_tick,
     int64_t load_event_start_ms) {
diff --git a/chrome/browser/page_load_metrics/observers/android_page_load_metrics_observer.h b/chrome/browser/page_load_metrics/observers/android_page_load_metrics_observer.h
index 439e6208..fb17461c 100644
--- a/chrome/browser/page_load_metrics/observers/android_page_load_metrics_observer.h
+++ b/chrome/browser/page_load_metrics/observers/android_page_load_metrics_observer.h
@@ -30,6 +30,9 @@
   void OnFirstContentfulPaintInPage(
       const page_load_metrics::mojom::PageLoadTiming& timing,
       const page_load_metrics::PageLoadExtraInfo& extra_info) override;
+  void OnFirstMeaningfulPaintInMainFrameDocument(
+      const page_load_metrics::mojom::PageLoadTiming& timing,
+      const page_load_metrics::PageLoadExtraInfo& extra_info) override;
   void OnLoadEventStart(
       const page_load_metrics::mojom::PageLoadTiming& timing,
       const page_load_metrics::PageLoadExtraInfo& info) override;
@@ -54,6 +57,9 @@
   virtual void ReportFirstContentfulPaint(int64_t navigation_start_tick,
                                           int64_t first_contentful_paint_ms);
 
+  virtual void ReportFirstMeaningfulPaint(int64_t navigation_start_tick,
+                                          int64_t first_meaningful_paint_ms);
+
   virtual void ReportLoadEventStart(int64_t navigation_start_tick,
                                     int64_t load_event_start_ms);
 
diff --git a/chrome/browser/page_load_metrics/observers/use_counter/ukm_features.cc b/chrome/browser/page_load_metrics/observers/use_counter/ukm_features.cc
index ce44f98..586396e8 100644
--- a/chrome/browser/page_load_metrics/observers/use_counter/ukm_features.cc
+++ b/chrome/browser/page_load_metrics/observers/use_counter/ukm_features.cc
@@ -22,6 +22,8 @@
           WebFeature::kDataUriHasOctothorpe,
           WebFeature::kApplicationCacheManifestSelectInsecureOrigin,
           WebFeature::kApplicationCacheManifestSelectSecureOrigin,
+          WebFeature::kMixedContentAudio, WebFeature::kMixedContentImage,
+          WebFeature::kMixedContentVideo, WebFeature::kMixedContentPlugin,
       }));
   return opt_in_features.count(feature);
 }
diff --git a/chrome/browser/page_load_metrics/page_load_metrics_browsertest.cc b/chrome/browser/page_load_metrics/page_load_metrics_browsertest.cc
index faf6193..e89818c 100644
--- a/chrome/browser/page_load_metrics/page_load_metrics_browsertest.cc
+++ b/chrome/browser/page_load_metrics/page_load_metrics_browsertest.cc
@@ -1219,6 +1219,40 @@
 }
 
 IN_PROC_BROWSER_TEST_F(PageLoadMetricsBrowserTest,
+                       UseCounterFeaturesMixedContent) {
+  // UseCounterFeaturesInMainFrame loads the test file on a loopback
+  // address. Loopback is treated as a secure origin in most ways, but it
+  // doesn't count as mixed content when it loads http://
+  // subresources. Therefore, this test loads the test file on a real HTTPS
+  // server.
+  net::EmbeddedTestServer https_server(net::EmbeddedTestServer::TYPE_HTTPS);
+  https_server.AddDefaultHandlers(
+      base::FilePath(FILE_PATH_LITERAL("chrome/test/data")));
+  ASSERT_TRUE(https_server.Start());
+
+  auto waiter = CreatePageLoadMetricsWaiter();
+  waiter->AddPageExpectation(TimingField::LOAD_EVENT);
+  ui_test_utils::NavigateToURL(
+      browser(),
+      https_server.GetURL("/page_load_metrics/use_counter_features.html"));
+  waiter->Wait();
+  NavigateToUntrackedUrl();
+
+  histogram_tester_.ExpectBucketCount(
+      internal::kFeaturesHistogramName,
+      static_cast<int32_t>(WebFeature::kMixedContentAudio), 1);
+  histogram_tester_.ExpectBucketCount(
+      internal::kFeaturesHistogramName,
+      static_cast<int32_t>(WebFeature::kMixedContentImage), 1);
+  histogram_tester_.ExpectBucketCount(
+      internal::kFeaturesHistogramName,
+      static_cast<int32_t>(WebFeature::kMixedContentVideo), 1);
+  histogram_tester_.ExpectBucketCount(
+      internal::kFeaturesHistogramName,
+      static_cast<int32_t>(WebFeature::kPageVisits), 1);
+}
+
+IN_PROC_BROWSER_TEST_F(PageLoadMetricsBrowserTest,
                        UseCounterFeaturesInNonSecureMainFrame) {
   ASSERT_TRUE(embedded_test_server()->Start());
 
@@ -1286,6 +1320,46 @@
               WebFeature::kApplicationCacheManifestSelectSecureOrigin)));
 }
 
+// Test UseCounter UKM mixed content features observed.
+IN_PROC_BROWSER_TEST_F(PageLoadMetricsBrowserTest,
+                       UseCounterUkmMixedContentFeaturesLogged) {
+  // As with UseCounterFeaturesMixedContent, load on a real HTTPS server to
+  // trigger mixed content.
+  net::EmbeddedTestServer https_server(net::EmbeddedTestServer::TYPE_HTTPS);
+  https_server.AddDefaultHandlers(
+      base::FilePath(FILE_PATH_LITERAL("chrome/test/data")));
+  ASSERT_TRUE(https_server.Start());
+
+  auto waiter = CreatePageLoadMetricsWaiter();
+  waiter->AddPageExpectation(TimingField::LOAD_EVENT);
+  GURL url =
+      https_server.GetURL("/page_load_metrics/use_counter_features.html");
+  ui_test_utils::NavigateToURL(browser(), url);
+  waiter->Wait();
+  NavigateToUntrackedUrl();
+
+  const auto& entries =
+      test_ukm_recorder_->GetEntriesByName(internal::kUkmUseCounterEventName);
+  EXPECT_EQ(6u, entries.size());
+  std::vector<int64_t> ukm_features;
+  for (const auto* entry : entries) {
+    test_ukm_recorder_->ExpectEntrySourceHasUrl(entry, url);
+    const auto* metric =
+        test_ukm_recorder_->FindMetric(entry, internal::kUkmUseCounterFeature);
+    EXPECT_TRUE(metric);
+    ukm_features.push_back(metric->value);
+  }
+  EXPECT_THAT(ukm_features,
+              UnorderedElementsAre(
+                  static_cast<int64_t>(WebFeature::kNavigatorVibrate),
+                  static_cast<int64_t>(WebFeature::kDataUriHasOctothorpe),
+                  static_cast<int64_t>(
+                      WebFeature::kApplicationCacheManifestSelectSecureOrigin),
+                  static_cast<int64_t>(WebFeature::kMixedContentImage),
+                  static_cast<int64_t>(WebFeature::kMixedContentAudio),
+                  static_cast<int64_t>(WebFeature::kMixedContentVideo)));
+}
+
 // Test UseCounter Features observed in a child frame are recorded, exactly
 // once per feature.
 IN_PROC_BROWSER_TEST_F(PageLoadMetricsBrowserTest, UseCounterFeaturesInIframe) {
diff --git a/chrome/browser/policy/policy_browsertest.cc b/chrome/browser/policy/policy_browsertest.cc
index d367b623..bf485c2 100644
--- a/chrome/browser/policy/policy_browsertest.cc
+++ b/chrome/browser/policy/policy_browsertest.cc
@@ -71,6 +71,7 @@
 #include "chrome/browser/prefs/session_startup_pref.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/safe_browsing/chrome_password_protection_service.h"
+#include "chrome/browser/search/search.h"
 #include "chrome/browser/search_engines/template_url_service_factory.h"
 #include "chrome/browser/ssl/ssl_blocking_page.h"
 #include "chrome/browser/task_manager/task_manager_interface.h"
@@ -2297,7 +2298,7 @@
   UpdateProviderPolicy(policies);
   EXPECT_TRUE(chrome::ExecuteCommand(browser(), IDC_HOME));
   content::WaitForLoadStop(contents);
-  EXPECT_EQ(GURL(chrome::kChromeUINewTabURL), contents->GetURL());
+  EXPECT_TRUE(search::IsInstantNTP(contents));
 }
 
 #if defined(OS_MACOSX) && defined(ADDRESS_SANITIZER)
@@ -4408,7 +4409,7 @@
   ASSERT_EQ(1, post_interceptor_->GetCount())
       << post_interceptor_->GetRequestsAsString();
   EXPECT_NE(std::string::npos,
-            post_interceptor_->GetRequests()[0].find(base::StringPrintf(
+            post_interceptor_->GetRequestBody(0).find(base::StringPrintf(
                 "<updatecheck%s/>",
                 update_disabled ? " updatedisabled=\"true\"" : "")));
 }
diff --git a/chrome/browser/profiles/profile_io_data.cc b/chrome/browser/profiles/profile_io_data.cc
index 2118d08..1b1d0e8 100644
--- a/chrome/browser/profiles/profile_io_data.cc
+++ b/chrome/browser/profiles/profile_io_data.cc
@@ -126,9 +126,6 @@
 
 #if defined(OS_ANDROID)
 #include "content/public/browser/android/content_protocol_handler.h"
-#else
-#include "chrome/browser/ui/search/new_tab_page_interceptor_service.h"
-#include "chrome/browser/ui/search/new_tab_page_interceptor_service_factory.h"
 #endif  // defined(OS_ANDROID)
 
 #if defined(OS_CHROMEOS)
@@ -457,15 +454,6 @@
   params->protocol_handler_interceptor =
       protocol_handler_registry->CreateJobInterceptorFactory();
 
-#if !defined(OS_ANDROID)
-  NewTabPageInterceptorService* new_tab_interceptor_service =
-      NewTabPageInterceptorServiceFactory::GetForProfile(profile);
-  if (new_tab_interceptor_service) {
-    params->new_tab_page_interceptor =
-        new_tab_interceptor_service->CreateInterceptor();
-  }
-#endif
-
 #if defined(OS_CHROMEOS)
   // Enable client certificates for the Chrome OS sign-in frame, if this feature
   // is not disabled by a flag.
diff --git a/chrome/browser/profiling_host/profiling_process_host.cc b/chrome/browser/profiling_host/profiling_process_host.cc
index 2655513..e282f3c 100644
--- a/chrome/browser/profiling_host/profiling_process_host.cc
+++ b/chrome/browser/profiling_host/profiling_process_host.cc
@@ -11,6 +11,7 @@
 
 #include "base/allocator/features.h"
 #include "base/base_switches.h"
+#include "base/callback_helpers.h"
 #include "base/command_line.h"
 #include "base/files/file_util.h"
 #include "base/metrics/field_trial_params.h"
@@ -51,6 +52,8 @@
 #include "mojo/edk/embedder/platform_channel_pair.h"
 #include "mojo/edk/embedder/scoped_platform_handle.h"
 #include "mojo/public/cpp/system/platform_handle.h"
+#include "services/resource_coordinator/public/cpp/memory_instrumentation/memory_instrumentation.h"
+#include "services/resource_coordinator/public/mojom/service_constants.mojom.h"
 #include "third_party/zlib/zlib.h"
 
 #if defined(OS_WIN)
@@ -59,19 +62,6 @@
 
 namespace {
 
-// A wrapper classes that allows a string to be exported as JSON in a trace
-// event.
-class StringWrapper : public base::trace_event::ConvertableToTraceFormat {
- public:
-  explicit StringWrapper(std::string string) : json_(std::move(string)) {}
-
-  void AppendAsTraceFormat(std::string* out) const override {
-    out->append(json_);
-  }
-
-  std::string json_;
-};
-
 base::trace_event::TraceConfig GetBackgroundTracingConfig(bool anonymize) {
   // Disable all categories other than memory-infra.
   base::trace_event::TraceConfig trace_config(
@@ -82,19 +72,6 @@
   if (anonymize)
     trace_config.EnableArgumentFilter();
 
-  // Trigger a background memory dump exactly once by setting a time-delta
-  // between dumps of 2**29.
-  base::trace_event::TraceConfig::MemoryDumpConfig memory_config;
-  memory_config.allowed_dump_modes.insert(
-      base::trace_event::MemoryDumpLevelOfDetail::BACKGROUND);
-  base::trace_event::TraceConfig::MemoryDumpConfig::Trigger trigger;
-  trigger.min_time_between_dumps_ms = 1 << 30;
-  trigger.level_of_detail =
-      base::trace_event::MemoryDumpLevelOfDetail::BACKGROUND;
-  trigger.trigger_type = base::trace_event::MemoryDumpType::PERIODIC_INTERVAL;
-  memory_config.triggers.clear();
-  memory_config.triggers.push_back(trigger);
-  trace_config.ResetMemoryDumpConfig(memory_config);
   return trace_config;
 }
 
@@ -266,88 +243,6 @@
   }
 }
 
-bool ProfilingProcessHost::OnMemoryDump(
-    const base::trace_event::MemoryDumpArgs& args,
-    base::trace_event::ProcessMemoryDump* pmd) {
-  content::BrowserThread::GetTaskRunnerForThread(content::BrowserThread::IO)
-      ->PostTask(FROM_HERE,
-                 base::BindOnce(&ProfilingProcessHost::OnMemoryDumpOnIOThread,
-                                base::Unretained(this), args.dump_guid));
-  return true;
-}
-
-void ProfilingProcessHost::OnMemoryDumpOnIOThread(uint64_t dump_guid) {
-  bool force_prune = TakingTraceForUpload();
-  const base::CommandLine* cmdline = base::CommandLine::ForCurrentProcess();
-  bool keep_small_allocations =
-      !force_prune && cmdline->HasSwitch(switches::kMemlogKeepSmallAllocations);
-
-  bool strip_path_from_mapped_files = base::trace_event::TraceLog::GetInstance()
-                                          ->GetCurrentTraceConfig()
-                                          .IsArgumentFilterEnabled();
-  profiling_service_->DumpProcessesForTracing(
-      keep_small_allocations, strip_path_from_mapped_files,
-      base::BindOnce(&ProfilingProcessHost::OnDumpProcessesForTracingCallback,
-                     base::Unretained(this), dump_guid));
-}
-
-void ProfilingProcessHost::OnDumpProcessesForTracingCallback(
-    uint64_t guid,
-    std::vector<profiling::mojom::SharedBufferWithSizePtr> buffers) {
-  for (auto& buffer_ptr : buffers) {
-    mojo::ScopedSharedBufferHandle& buffer = buffer_ptr->buffer;
-    uint32_t size = buffer_ptr->size;
-
-    if (!buffer->is_valid())
-      return;
-
-    mojo::ScopedSharedBufferMapping mapping = buffer->Map(size);
-    if (!mapping) {
-      DLOG(ERROR) << "Failed to map buffer";
-      return;
-    }
-
-    const char* char_buffer = static_cast<const char*>(mapping.get());
-    std::string json(char_buffer, char_buffer + size);
-
-    const int kTraceEventNumArgs = 1;
-    const char* const kTraceEventArgNames[] = {"dumps"};
-    const unsigned char kTraceEventArgTypes[] = {TRACE_VALUE_TYPE_CONVERTABLE};
-    std::unique_ptr<base::trace_event::ConvertableToTraceFormat> wrapper(
-        new StringWrapper(std::move(json)));
-
-    // Using the same id merges all of the heap dumps into a single detailed
-    // dump node in the UI.
-    TRACE_EVENT_API_ADD_TRACE_EVENT_WITH_PROCESS_ID(
-        TRACE_EVENT_PHASE_MEMORY_DUMP,
-        base::trace_event::TraceLog::GetCategoryGroupEnabled(
-            base::trace_event::MemoryDumpManager::kTraceCategory),
-        "periodic_interval", trace_event_internal::kGlobalScope, guid,
-        buffer_ptr->pid, kTraceEventNumArgs, kTraceEventArgNames,
-        kTraceEventArgTypes, nullptr /* arg_values */, &wrapper,
-        TRACE_EVENT_FLAG_HAS_ID);
-  }
-
-  content::BrowserThread::GetTaskRunnerForThread(content::BrowserThread::UI)
-      ->PostTask(FROM_HERE,
-                 base::Bind(&ProfilingProcessHost::DumpProcessFinishedUIThread,
-                            base::Unretained(this)));
-}
-
-void ProfilingProcessHost::DumpProcessFinishedUIThread() {
-  DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
-  heap_dump_has_been_added_ = true;
-  if (minimum_time_has_elapsed_ && !finish_tracing_callback_.is_null())
-    std::move(finish_tracing_callback_).Run();
-}
-
-void ProfilingProcessHost::OnMinimumTimeHasElapsed() {
-  DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
-  minimum_time_has_elapsed_ = true;
-  if (heap_dump_has_been_added_ && !finish_tracing_callback_.is_null())
-    std::move(finish_tracing_callback_).Run();
-}
-
 void ProfilingProcessHost::AddClientToProfilingService(
     profiling::mojom::ProfilingClientPtr client,
     base::ProcessId pid,
@@ -568,7 +463,6 @@
       },
       std::move(dest), std::move(done));
   RequestTraceWithHeapDump(std::move(finish_trace_callback),
-                           stop_immediately_after_heap_dump_for_tests,
                            false /* anonymize */);
 }
 
@@ -602,13 +496,11 @@
       base::Unretained(this), std::move(trigger_name),
       should_sample_ ? sampling_rate_ : 1);
   RequestTraceWithHeapDump(std::move(finish_report_callback),
-                           false /* keep_small_allocations */,
                            true /* anonymize */);
 }
 
 void ProfilingProcessHost::RequestTraceWithHeapDump(
     TraceFinishedCallback callback,
-    bool stop_immediately_after_heap_dump_for_tests,
     bool anonymize) {
   DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
 
@@ -620,58 +512,47 @@
     return;
   }
 
-  bool result = content::TracingController::GetInstance()->StartTracing(
-      GetBackgroundTracingConfig(anonymize), base::Closure());
-  if (!result) {
+  if (content::TracingController::GetInstance()->IsTracing()) {
     DLOG(ERROR) << "Requesting heap dump when tracing has already started.";
     base::ThreadTaskRunnerHandle::Get()->PostTask(
         FROM_HERE, base::BindOnce(std::move(callback), false, std::string()));
     return;
   }
 
-  // Once the trace has stopped, run |callback| on the UI thread. At this point,
-  // ownership of |callback| has been transfered to |finish_sink_callback|.
-  auto finish_sink_callback = base::Bind(
-      [](TraceFinishedCallback callback,
-         std::unique_ptr<const base::DictionaryValue> metadata,
-         base::RefCountedString* in) {
-        std::string result;
-        result.swap(in->data());
-        content::BrowserThread::GetTaskRunnerForThread(
-            content::BrowserThread::UI)
-            ->PostTask(FROM_HERE, base::BindOnce(std::move(callback), true,
-                                                 std::move(result)));
+  auto finished_dump_callback = base::BindOnce(
+      [](TraceFinishedCallback callback, bool success, uint64_t dump_guid) {
+        // Once the trace has stopped, run |callback| on the UI thread.
+        auto finish_sink_callback = base::Bind(
+            [](TraceFinishedCallback callback,
+               std::unique_ptr<const base::DictionaryValue> metadata,
+               base::RefCountedString* in) {
+              std::string result;
+              result.swap(in->data());
+              content::BrowserThread::GetTaskRunnerForThread(
+                  content::BrowserThread::UI)
+                  ->PostTask(FROM_HERE,
+                             base::BindOnce(std::move(callback), true,
+                                            std::move(result)));
+            },
+            base::Passed(std::move(callback)));
+        scoped_refptr<content::TracingController::TraceDataEndpoint> sink =
+            content::TracingController::CreateStringEndpoint(
+                std::move(finish_sink_callback));
+        content::TracingController::GetInstance()->StopTracing(sink);
       },
-      base::Passed(std::move(callback)));
+      std::move(callback));
 
-  scoped_refptr<content::TracingController::TraceDataEndpoint> sink =
-      content::TracingController::CreateStringEndpoint(
-          std::move(finish_sink_callback));
-  base::OnceClosure stop_tracing_closure = base::BindOnce(
-      base::IgnoreResult<bool (content::TracingController::*)(  // NOLINT
-          const scoped_refptr<content::TracingController::TraceDataEndpoint>&)>(
-          &content::TracingController::StopTracing),
-      base::Unretained(content::TracingController::GetInstance()), sink);
+  memory_instrumentation::MemoryInstrumentation::GetInstance()
+      ->RequestGlobalDumpAndAppendToTrace(
+          base::trace_event::MemoryDumpType::EXPLICITLY_TRIGGERED,
+          base::trace_event::MemoryDumpLevelOfDetail::BACKGROUND,
+          base::AdaptCallbackForRepeating(std::move(finished_dump_callback)));
 
-  // There is no race condition between setting
-  // |finish_tracing_callback_| and starting tracing, since
-  // the callback is only ever accessed on the UI thread.
-  DCHECK(!finish_tracing_callback_);
-  finish_tracing_callback_ = std::move(stop_tracing_closure);
-
-  heap_dump_has_been_added_ = false;
-  if (stop_immediately_after_heap_dump_for_tests) {
-    minimum_time_has_elapsed_ = true;
-  } else {
-    minimum_time_has_elapsed_ = false;
-
-    // Give the MDPs 10 seconds to emit their memory dumps to the trace.
-    base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
-        FROM_HERE,
-        base::BindOnce(&ProfilingProcessHost::OnMinimumTimeHasElapsed,
-                       base::Unretained(this)),
-        base::TimeDelta::FromSeconds(10));
-  }
+  // The only reason this should return false is if tracing is already enabled,
+  // which we've already checked.
+  bool result = content::TracingController::GetInstance()->StartTracing(
+      GetBackgroundTracingConfig(anonymize), base::Closure());
+  DCHECK(result);
 }
 
 void ProfilingProcessHost::GetProfiledPids(GetProfiledPidsCallback callback) {
@@ -741,6 +622,22 @@
   }
 }
 
+void ProfilingProcessHost::SetKeepSmallAllocations(
+    bool keep_small_allocations) {
+  // May get called on different threads, we need to be on the IO thread to
+  // work.
+  if (!content::BrowserThread::CurrentlyOn(content::BrowserThread::IO)) {
+    content::BrowserThread::GetTaskRunnerForThread(content::BrowserThread::IO)
+        ->PostTask(
+            FROM_HERE,
+            base::BindOnce(&ProfilingProcessHost::SetKeepSmallAllocations,
+                           base::Unretained(this), keep_small_allocations));
+    return;
+  }
+
+  profiling_service_->SetKeepSmallAllocations(keep_small_allocations);
+}
+
 void ProfilingProcessHost::StartProfilingPidOnIOThread(base::ProcessId pid) {
   DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
 
@@ -786,15 +683,25 @@
     return;
   }
 
-  // No need to unregister since ProfilingProcessHost is never destroyed.
-  base::trace_event::MemoryDumpManager::GetInstance()->RegisterDumpProvider(
-      this, "OutOfProcessHeapProfilingDumpProvider",
-      content::BrowserThread::GetTaskRunnerForThread(
-          content::BrowserThread::IO));
-
   // Bind to the memlog service. This will start it if it hasn't started
   // already.
-  connector_->BindInterface(mojom::kServiceName, &profiling_service_);
+  connector_->BindInterface(profiling::mojom::kServiceName,
+                            &profiling_service_);
+
+  // Set some state for heap dumps.
+  bool keep_small_allocations =
+      base::CommandLine::ForCurrentProcess()->HasSwitch(
+          switches::kMemlogKeepSmallAllocations);
+  SetKeepSmallAllocations(keep_small_allocations);
+
+  // Grab a HeapProfiler InterfacePtr and pass that to memory instrumentation.
+  memory_instrumentation::mojom::HeapProfilerPtr heap_profiler;
+  connector_->BindInterface(profiling::mojom::kServiceName, &heap_profiler);
+
+  memory_instrumentation::mojom::CoordinatorPtr coordinator;
+  connector_->BindInterface(resource_coordinator::mojom::kServiceName,
+                            &coordinator);
+  coordinator->RegisterHeapProfiler(std::move(heap_profiler));
 
   // Start profiling the browser if the mode allows.
   if (ShouldProfileNonRendererProcessType(
diff --git a/chrome/browser/profiling_host/profiling_process_host.h b/chrome/browser/profiling_host/profiling_process_host.h
index e63824e2..fcaea7e 100644
--- a/chrome/browser/profiling_host/profiling_process_host.h
+++ b/chrome/browser/profiling_host/profiling_process_host.h
@@ -13,7 +13,6 @@
 #include "base/macros.h"
 #include "base/memory/singleton.h"
 #include "base/process/process.h"
-#include "base/trace_event/memory_dump_provider.h"
 #include "build/build_config.h"
 #include "chrome/browser/profiling_host/background_profiling_triggers.h"
 #include "chrome/common/chrome_features.h"
@@ -57,8 +56,7 @@
 // TODO(ajwong): This host class seems over kill at this point. Can this be
 // fully subsumed by the ProfilingService class?
 class ProfilingProcessHost : public content::BrowserChildProcessObserver,
-                             content::NotificationObserver,
-                             base::trace_event::MemoryDumpProvider {
+                             content::NotificationObserver {
  public:
   // These values are persisted to logs. Entries should not be renumbered and
   // numeric values should never be reused.
@@ -143,17 +141,16 @@
       base::OnceCallback<void(bool success, std::string trace_json)>;
 
   // This method must be called from the UI thread. |callback| will be called
-  // asynchronously on the UI thread. If
-  // |stop_immediately_after_heap_dump_for_tests| is true, then |callback| will
-  // be called as soon as the heap dump is added to the trace. Otherwise,
-  // |callback| will be called after 10s. This gives time for the
-  // MemoryDumpProviders to dump to the trace, which is asynchronous and has no
-  // finish notification. This intentionally avoids waiting for the heap-dump
-  // finished signal, in case there's a problem with the profiling process and
-  // the heap-dump is never added to the trace.
+  // asynchronously on the UI thread.
+  //
+  // This function does the following:
+  //   1. Starts tracing with no categories enabled.
+  //   2. Requests and waits for memory_instrumentation service to dump to
+  //   trace.
+  //   3. Stops tracing.
+  //
   // Public for testing.
   void RequestTraceWithHeapDump(TraceFinishedCallback callback,
-                                bool stop_immediately_after_heap_dump_for_tests,
                                 bool anonymize);
 
   // Returns the pids of all profiled processes. The callback is posted on the
@@ -170,6 +167,10 @@
   // dropped by the profiling service].
   void StartProfilingRenderersForTesting();
 
+  // Public for testing. Controls whether the profiling service keeps small
+  // allocations in heap dumps.
+  void SetKeepSmallAllocations(bool keep_small_allocations);
+
  private:
   friend struct base::DefaultSingletonTraits<ProfilingProcessHost>;
   friend class BackgroundProfilingTriggersTest;
@@ -200,25 +201,12 @@
                const content::NotificationSource& source,
                const content::NotificationDetails& details) override;
 
-  // base::trace_event::MemoryDumpProvider
-  bool OnMemoryDump(const base::trace_event::MemoryDumpArgs& args,
-                    base::trace_event::ProcessMemoryDump* pmd) override;
-  void OnMemoryDumpOnIOThread(uint64_t dump_guid);
-
-  void OnDumpProcessesForTracingCallback(
-      uint64_t guid,
-      std::vector<profiling::mojom::SharedBufferWithSizePtr> buffers);
-
   // Starts the profiling process.
   void LaunchAsService();
 
   // Called on the UI thread after the heap dump has been added to the trace.
   void DumpProcessFinishedUIThread();
 
-  // Must be called on the UI thread.
-  // Called after the MDPs have been given time to emit memory dumps.
-  void OnMinimumTimeHasElapsed();
-
   // Sends the end of the data pipe to the profiling service.
   void AddClientToProfilingService(profiling::mojom::ProfilingClientPtr client,
                                    base::ProcessId pid,
@@ -293,11 +281,6 @@
   // simplicity, it's easier to just track this variable in this process.
   std::unordered_set<void*> profiled_renderers_;
 
-  // Must only ever be used from the UI thread. Will be called after the
-  // profiling process dumps heaps into the trace log and MDPs have been given
-  // time to do the same.
-  base::OnceClosure finish_tracing_callback_;
-
   // True if the instance is attempting to take a trace to upload to the crash
   // servers. Pruning of small allocations is always enabled for these traces.
   bool taking_trace_for_upload_ = false;
@@ -305,11 +288,6 @@
   // Guards |taking_trace_for_upload_|.
   base::Lock taking_trace_for_upload_lock_;
 
-  // If the instance has started a trace, the trace should be stopped when both
-  // members become true. Both members must only be accessed on the UI thread.
-  bool minimum_time_has_elapsed_ = false;
-  bool heap_dump_has_been_added_ = false;
-
   DISALLOW_COPY_AND_ASSIGN(ProfilingProcessHost);
 };
 
diff --git a/chrome/browser/profiling_host/profiling_test_driver.cc b/chrome/browser/profiling_host/profiling_test_driver.cc
index c89124f6..bcf1965 100644
--- a/chrome/browser/profiling_host/profiling_test_driver.cc
+++ b/chrome/browser/profiling_host/profiling_test_driver.cc
@@ -663,6 +663,7 @@
   ProfilingProcessHost::Start(connection, options_.mode, options_.stack_mode,
                               options_.should_sample,
                               options_.sample_everything ? 2 : kSampleRate);
+  ProfilingProcessHost::GetInstance()->SetKeepSmallAllocations(true);
 
   if (run_loop)
     run_loop->Run();
@@ -738,7 +739,6 @@
   profiling::ProfilingProcessHost::GetInstance()->RequestTraceWithHeapDump(
       base::Bind(&ProfilingTestDriver::TraceFinished, base::Unretained(this),
                  std::move(finish_tracing_closure)),
-      true /* keep_small_allocations */,
       false /* strip_path_from_mapped_files */);
 
   if (synchronous)
diff --git a/chrome/browser/resources/chromeos/select_to_speak/select_to_speak.js b/chrome/browser/resources/chromeos/select_to_speak/select_to_speak.js
index e50dc96f..91cee3a 100644
--- a/chrome/browser/resources/chromeos/select_to_speak/select_to_speak.js
+++ b/chrome/browser/resources/chromeos/select_to_speak/select_to_speak.js
@@ -262,6 +262,9 @@
   /** @private {boolean} */
   this.visible_ = true;
 
+  /** @private {boolean} */
+  this.scrollToSpokenNode_ = false;
+
   /**
    * The interval ID from a call to setInterval, which is set whenever
    * speech is in progress.
@@ -569,10 +572,26 @@
     } else {
       this.startSpeechQueue_(nodes, firstPosition.offset, lastPosition.offset);
     }
-
+    this.initializeScrollingToOffscreenNodes_(focusedNode.root);
     this.recordStartEvent_(START_SPEECH_METHOD_KEYSTROKE);
   },
 
+  initializeScrollingToOffscreenNodes_: function(root) {
+    this.scrollToSpokenNode_ = true;
+    let listener = (event) => {
+      if (event.eventFrom != 'action') {
+        // User initiated event. Cancel all future scrolling to spoken nodes.
+        // If the user wants a certain scroll position we will respect that.
+        this.scrollToSpokenNode_ = false;
+
+        // Now remove this event listener, we no longer need it.
+        root.removeEventListener(
+            EventType.SCROLL_POSITION_CHANGED, listener, false);
+      }
+    };
+    root.addEventListener(EventType.SCROLL_POSITION_CHANGED, listener, false);
+  },
+
   /**
    * Plays a tone to let the user know they did the correct
    * keystroke but nothing was selected.
@@ -606,6 +625,7 @@
     this.currentNodeWord_ = null;
     clearInterval(this.intervalId_);
     this.intervalId_ = undefined;
+    this.scrollToSpokenNode_ = false;
   },
 
   /**
@@ -982,6 +1002,9 @@
         findInlineTextNodeByCharacterIndex(
             nodeGroupItem.node, this.currentNodeWord_.start) :
         nodeGroupItem.node;
+    if (this.scrollToSpokenNode_ && node.state.offscreen) {
+      node.makeVisible();
+    }
     if (this.wordHighlight_ && this.currentNodeWord_ != null) {
       // Only show the highlight if this is an inline text box.
       // Otherwise we'd be highlighting entire nodes, like images.
diff --git a/chrome/browser/resources/net_internals/http_cache_view.html b/chrome/browser/resources/net_internals/http_cache_view.html
index e2c4513..9af570e 100644
--- a/chrome/browser/resources/net_internals/http_cache_view.html
+++ b/chrome/browser/resources/net_internals/http_cache_view.html
@@ -1,8 +1,4 @@
 <div id=http-cache-view-tab-content class=content-box>
-  <div class="hide-when-not-capturing">
-    <a href="chrome://view-http-cache" target=_blank>Explore cache entries</a>
-  </div>
-
   <h4>Statistics</h4>
   <div id=http-cache-view-cache-stats>Nothing loaded yet.</div>
 </div>
diff --git a/chrome/browser/resources/settings/people_page/people_page.html b/chrome/browser/resources/settings/people_page/people_page.html
index ef6c11ae..d7b6822e 100644
--- a/chrome/browser/resources/settings/people_page/people_page.html
+++ b/chrome/browser/resources/settings/people_page/people_page.html
@@ -163,7 +163,7 @@
 <if expr="not chromeos">
           <template is="dom-if" if="[[!diceEnabled_]]">
 </if>
-            <div class="settings-box two-line"
+            <div class="settings-box two-line" id="sync-overview"
                 hidden="[[!syncStatus.signinAllowed]]">
               <div class="start">
                 $i18n{syncOverview}
diff --git a/chrome/browser/resources/settings/people_page/sync_account_control.html b/chrome/browser/resources/settings/people_page/sync_account_control.html
index 915bedde..9b05cf8 100644
--- a/chrome/browser/resources/settings/people_page/sync_account_control.html
+++ b/chrome/browser/resources/settings/people_page/sync_account_control.html
@@ -36,7 +36,7 @@
         padding: 12px;
       }
 
-      #menu .dropdown-item .email {
+      #menu .dropdown-item span {
         -webkit-margin-start: 8px;
       }
 
@@ -135,7 +135,7 @@
       </paper-button>
     </div>
     <template is="dom-if" if="[[shouldShowAvatarRow_]]">
-      <div class="settings-box first two-line">
+      <div class="settings-box first two-line" id="avatar-row">
         <div id="avatar-container">
           <img class="account-icon"
               src="[[getAccountImageSrc_(shownAccount_.avatarImage)]]">
@@ -144,7 +144,7 @@
           </div>
         </div>
         <div class="middle two-line no-min-width">
-          <div class="flex text-elide">
+          <div class="flex text-elide" id="user-info">
             <span>
               [[getNameDisplay_('$i18nPolymer{syncedToName}',
                   shownAccount_.fullName, syncStatus.signedIn)]]
@@ -152,7 +152,7 @@
             <div class="secondary">[[shownAccount_.email]]</div>
           </div>
           <div class="separator" hidden="[[syncStatus.signedIn]]"></div>
-          <button is="paper-icon-button-light" id="dots"
+          <button is="paper-icon-button-light" id="dropdown-arrow"
               on-click="onMenuButtonTap_" title="$i18n{moreActions}"
               class="icon-arrow-dropdown" hidden="[[syncStatus.signedIn]]">
           </button>
@@ -175,14 +175,14 @@
             <button class="dropdown-item" on-click="onAccountTap_" slot="item">
               <img class="account-icon small"
                   src="[[getAccountImageSrc_(item.avatarImage)]]">
-              <span class="email">[[item.email]]</span>
+              <span>[[item.email]]</span>
             </button>
           </template>
           <button class="dropdown-item" on-click="onSigninTap_" slot="item"
-              disabled="[[syncStatus.setupInProgress]]">
+              disabled="[[syncStatus.setupInProgress]]" id="sign-in-item">
             <img class="account-icon small"
                 src="chrome://theme/IDR_PROFILE_AVATAR_PLACEHOLDER_LARGE">
-            <span class="email">$i18n{useAnotherAccount}</span>
+            <span>$i18n{useAnotherAccount}</span>
           </button>
         </dialog>
       </template>
diff --git a/chrome/browser/resources/settings/people_page/sync_account_control.js b/chrome/browser/resources/settings/people_page/sync_account_control.js
index f0a28b7..cb5dee1 100644
--- a/chrome/browser/resources/settings/people_page/sync_account_control.js
+++ b/chrome/browser/resources/settings/people_page/sync_account_control.js
@@ -6,6 +6,11 @@
  * 'settings-sync-account-section' is the settings page containing sign-in
  * settings.
  */
+cr.exportPath('settings');
+
+/** @const {number} */
+settings.MAX_SIGNIN_PROMO_IMPRESSION = 10;
+
 Polymer({
   is: 'settings-sync-account-control',
   behaviors: [WebUIListenerBehavior],
@@ -84,7 +89,8 @@
   /** @private */
   onSignedInChanged_: function() {
     if (!this.showingPromo && !this.syncStatus.signedIn &&
-        this.syncBrowserProxy_.getPromoImpressionCount() < 10) {
+        this.syncBrowserProxy_.getPromoImpressionCount() <
+            settings.MAX_SIGNIN_PROMO_IMPRESSION) {
       this.showingPromo = true;
       this.syncBrowserProxy_.incrementPromoImpressionCount();
     } else {
@@ -176,7 +182,7 @@
   onMenuButtonTap_: function() {
     const actionMenu =
         /** @type {!CrActionMenuElement} */ (this.$$('#menu'));
-    actionMenu.showAt(assert(this.$$('#dots')), {
+    actionMenu.showAt(assert(this.$$('#dropdown-arrow')), {
       anchorAlignmentY: AnchorAlignment.AFTER_END,
     });
   },
diff --git a/chrome/browser/ui/BUILD.gn b/chrome/browser/ui/BUILD.gn
index 67907a15..5d4d323d 100644
--- a/chrome/browser/ui/BUILD.gn
+++ b/chrome/browser/ui/BUILD.gn
@@ -1433,10 +1433,8 @@
       "scoped_tabbed_browser_displayer.h",
       "search/instant_controller.cc",
       "search/instant_controller.h",
-      "search/new_tab_page_interceptor_service.cc",
-      "search/new_tab_page_interceptor_service.h",
-      "search/new_tab_page_interceptor_service_factory.cc",
-      "search/new_tab_page_interceptor_service_factory.h",
+      "search/new_tab_page_navigation_throttle.cc",
+      "search/new_tab_page_navigation_throttle.h",
       "search/ntp_user_data_logger.cc",
       "search/ntp_user_data_logger.h",
       "search/search_ipc_router.cc",
diff --git a/chrome/browser/ui/browser_browsertest.cc b/chrome/browser/ui/browser_browsertest.cc
index c433f0a..6013607 100644
--- a/chrome/browser/ui/browser_browsertest.cc
+++ b/chrome/browser/ui/browser_browsertest.cc
@@ -57,6 +57,7 @@
 #include "chrome/browser/ui/extensions/app_launch_params.h"
 #include "chrome/browser/ui/extensions/application_launch.h"
 #include "chrome/browser/ui/javascript_dialogs/javascript_dialog_tab_helper.h"
+#include "chrome/browser/ui/search/local_ntp_test_utils.h"
 #include "chrome/browser/ui/search/search_tab_helper.h"
 #include "chrome/browser/ui/startup/startup_browser_creator.h"
 #include "chrome/browser/ui/startup/startup_browser_creator_impl.h"
@@ -517,8 +518,7 @@
   ASSERT_TRUE(embedded_test_server()->Start());
   WebContents* web_contents =
       browser()->tab_strip_model()->GetActiveWebContents();
-  GURL ntp_url(search::GetNewTabPageURL(browser()->profile()));
-  ui_test_utils::NavigateToURL(browser(), ntp_url);
+  ui_test_utils::NavigateToURL(browser(), GURL(chrome::kChromeUINewTabURL));
 
   // Navigate to a 204 URL (aborts with no content) on the NTP and make sure it
   // sticks around so that the user can edit it.
@@ -1143,9 +1143,7 @@
 
   // There should only be one tab now, with the NTP loaded.
   ASSERT_EQ(1, tab_strip_model->count());
-  EXPECT_EQ(
-      chrome::kChromeUINewTabURL,
-      tab_strip_model->GetActiveWebContents()->GetLastCommittedURL().spec());
+  EXPECT_TRUE(search::IsInstantNTP(tab_strip_model->GetActiveWebContents()));
 }
 
 // Open with --app-id=<id>, and see that an application tab opens by default.
@@ -1237,8 +1235,7 @@
   ASSERT_TRUE(embedded_test_server()->Start());
   WebContents* web_contents =
       browser()->tab_strip_model()->GetActiveWebContents();
-  GURL ntp_url = search::GetNewTabPageURL(browser()->profile());
-  ui_test_utils::NavigateToURL(browser(), ntp_url);
+  ui_test_utils::NavigateToURL(browser(), GURL(chrome::kChromeUINewTabURL));
 
   // Open a devtools window.
   DevToolsWindow* devtools_window =
diff --git a/chrome/browser/ui/browser_navigator_browsertest.cc b/chrome/browser/ui/browser_navigator_browsertest.cc
index 7056256b..b7f96211 100644
--- a/chrome/browser/ui/browser_navigator_browsertest.cc
+++ b/chrome/browser/ui/browser_navigator_browsertest.cc
@@ -12,6 +12,7 @@
 #include "chrome/browser/prefs/incognito_mode_prefs.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/renderer_host/chrome_navigation_ui_data.h"
+#include "chrome/browser/search/search.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/browser_commands.h"
 #include "chrome/browser/ui/browser_finder.h"
@@ -21,6 +22,7 @@
 #include "chrome/browser/ui/browser_window.h"
 #include "chrome/browser/ui/chrome_pages.h"
 #include "chrome/browser/ui/location_bar/location_bar.h"
+#include "chrome/browser/ui/search/local_ntp_test_utils.h"
 #include "chrome/browser/ui/singleton_tabs.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
 #include "chrome/common/pref_names.h"
@@ -1349,8 +1351,8 @@
   params.url = GURL(chrome::kChromeUINewTabURL);
   ui_test_utils::NavigateToURL(&params);
   EXPECT_EQ(1, browser()->tab_strip_model()->count());
-  EXPECT_EQ(GURL(chrome::kChromeUINewTabURL),
-            browser()->tab_strip_model()->GetActiveWebContents()->GetURL());
+  EXPECT_TRUE(search::IsInstantNTP(
+      browser()->tab_strip_model()->GetActiveWebContents()));
 
   {
     content::WindowedNotificationObserver observer(
diff --git a/chrome/browser/ui/cocoa/extensions/extension_popup_views_mac.h b/chrome/browser/ui/cocoa/extensions/extension_popup_views_mac.h
index d50938f5..3b900ff 100644
--- a/chrome/browser/ui/cocoa/extensions/extension_popup_views_mac.h
+++ b/chrome/browser/ui/cocoa/extensions/extension_popup_views_mac.h
@@ -5,7 +5,7 @@
 #ifndef CHROME_BROWSER_UI_COCOA_EXTENSIONS_EXTENSION_POPUP_VIEWS_MAC_H_
 #define CHROME_BROWSER_UI_COCOA_EXTENSIONS_EXTENSION_POPUP_VIEWS_MAC_H_
 
-#import <Foundation/NSArray.h>
+#import <Foundation/Foundation.h>
 
 #include <memory>
 
@@ -29,12 +29,12 @@
   static ExtensionPopupViewsMac* ShowPopup(
       std::unique_ptr<extensions::ExtensionViewHost> host,
       gfx::NativeWindow parent_window,
-      gfx::Point anchor_point,
+      const gfx::Point& anchor_point,
       ExtensionPopup::ShowAction show_action);
 
  private:
   ExtensionPopupViewsMac(std::unique_ptr<extensions::ExtensionViewHost> host,
-                         gfx::Point anchor_point,
+                         const gfx::Point& anchor_point,
                          ExtensionPopup::ShowAction show_action);
 
   base::scoped_nsobject<NSMutableArray> observer_tokens_;
diff --git a/chrome/browser/ui/cocoa/extensions/extension_popup_views_mac.mm b/chrome/browser/ui/cocoa/extensions/extension_popup_views_mac.mm
index 6984279c..529ae54 100644
--- a/chrome/browser/ui/cocoa/extensions/extension_popup_views_mac.mm
+++ b/chrome/browser/ui/cocoa/extensions/extension_popup_views_mac.mm
@@ -4,8 +4,7 @@
 
 #include "chrome/browser/ui/cocoa/extensions/extension_popup_views_mac.h"
 
-#import <AppKit/NSWindow.h>
-#import <Foundation/NSNotification.h>
+#import <AppKit/AppKit.h>
 
 #include "chrome/browser/extensions/extension_view_host.h"
 #import "chrome/browser/ui/cocoa/bubble_anchor_helper_views.h"
@@ -22,7 +21,7 @@
 ExtensionPopupViewsMac* ExtensionPopupViewsMac::ShowPopup(
     std::unique_ptr<extensions::ExtensionViewHost> host,
     gfx::NativeWindow parent_window,
-    gfx::Point anchor_point,
+    const gfx::Point& anchor_point,
     ExtensionPopup::ShowAction show_action) {
   // We can't use std::make_unique here as the constructor is private.
   std::unique_ptr<ExtensionPopupViewsMac> popup_owned(
@@ -47,7 +46,7 @@
 
 ExtensionPopupViewsMac::ExtensionPopupViewsMac(
     std::unique_ptr<extensions::ExtensionViewHost> host,
-    gfx::Point anchor_point,
+    const gfx::Point& anchor_point,
     ExtensionPopup::ShowAction show_action)
     : ExtensionPopup(host.release(),
                      nullptr,
diff --git a/chrome/browser/ui/cocoa/renderer_context_menu/render_view_context_menu_mac.mm b/chrome/browser/ui/cocoa/renderer_context_menu/render_view_context_menu_mac.mm
index a66de1d..85c0610 100644
--- a/chrome/browser/ui/cocoa/renderer_context_menu/render_view_context_menu_mac.mm
+++ b/chrome/browser/ui/cocoa/renderer_context_menu/render_view_context_menu_mac.mm
@@ -22,6 +22,7 @@
 #include "content/public/browser/render_widget_host_view.h"
 #import "ui/base/cocoa/menu_controller.h"
 #include "ui/base/l10n/l10n_util.h"
+#include "ui/strings/grit/ui_strings.h"
 
 using content::WebContents;
 
diff --git a/chrome/browser/ui/input_method/input_method_engine.cc b/chrome/browser/ui/input_method/input_method_engine.cc
index 7ad0f90..d6ac803 100644
--- a/chrome/browser/ui/input_method/input_method_engine.cc
+++ b/chrome/browser/ui/input_method/input_method_engine.cc
@@ -255,7 +255,8 @@
   // Checks if the last committed url is whitelisted url.
   url::Origin origin = url::Origin::Create(url);
   std::vector<GURL> whitelist_urls{GURL(url::kAboutBlankURL),
-                                   GURL(chrome::kChromeUINewTabURL)};
+                                   GURL(chrome::kChromeUINewTabURL),
+                                   GURL(chrome::kChromeSearchLocalNtpUrl)};
   for (const GURL& whitelist_url : whitelist_urls) {
     if (url::Origin::Create(whitelist_url).IsSameOriginWith(origin))
       return false;
diff --git a/chrome/browser/ui/search/local_ntp_test_utils.cc b/chrome/browser/ui/search/local_ntp_test_utils.cc
index 7288628..23b82682 100644
--- a/chrome/browser/ui/search/local_ntp_test_utils.cc
+++ b/chrome/browser/ui/search/local_ntp_test_utils.cc
@@ -126,4 +126,17 @@
   template_url_service->SetUserSelectedDefaultSearchProvider(template_url);
 }
 
+GURL GetFinalNtpUrl(Profile* profile) {
+  if (search::GetNewTabPageURL(profile) == chrome::kChromeSearchLocalNtpUrl) {
+    // If chrome://newtab/ already maps to the local NTP, then that will load
+    // correctly, even without network.  The URL associated with the WebContents
+    // will stay chrome://newtab/
+    return GURL(chrome::kChromeUINewTabURL);
+  }
+  // If chrome://newtab/ maps to a remote URL, then it will fail to load in a
+  // browser_test environment.  In this case, we will get redirected to the
+  // local NTP, which changes the URL associated with the WebContents.
+  return GURL(chrome::kChromeSearchLocalNtpUrl);
+}
+
 }  // namespace local_ntp_test_utils
diff --git a/chrome/browser/ui/search/local_ntp_test_utils.h b/chrome/browser/ui/search/local_ntp_test_utils.h
index 2962347..1b63eb7 100644
--- a/chrome/browser/ui/search/local_ntp_test_utils.h
+++ b/chrome/browser/ui/search/local_ntp_test_utils.h
@@ -32,6 +32,12 @@
                                           const std::string& base_url,
                                           const std::string& ntp_url);
 
+// Get the URL that WebContents->GetVisibleURL() will return after navigating to
+// chrome://newtab/.  While this should typically be chrome://newtab/, in a test
+// environment where there is no network connection, it may be
+// chrome-search://local-ntp/local-ntp.html.
+GURL GetFinalNtpUrl(Profile* profile);
+
 }  // namespace local_ntp_test_utils
 
 #endif  // CHROME_BROWSER_UI_SEARCH_LOCAL_NTP_TEST_UTILS_H_
diff --git a/chrome/browser/ui/search/new_tab_page_interceptor_browsertest.cc b/chrome/browser/ui/search/new_tab_page_interceptor_browsertest.cc
deleted file mode 100644
index 0e1bdc7..0000000
--- a/chrome/browser/ui/search/new_tab_page_interceptor_browsertest.cc
+++ /dev/null
@@ -1,111 +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 <memory>
-
-#include "base/files/file_path.h"
-#include "base/strings/utf_string_conversions.h"
-#include "chrome/browser/browser_process.h"
-#include "chrome/browser/search/search.h"
-#include "chrome/browser/search_engines/template_url_service_factory.h"
-#include "chrome/browser/search_engines/ui_thread_search_terms_data.h"
-#include "chrome/browser/ui/browser.h"
-#include "chrome/browser/ui/tabs/tab_strip_model.h"
-#include "chrome/common/url_constants.h"
-#include "chrome/test/base/in_process_browser_test.h"
-#include "chrome/test/base/search_test_utils.h"
-#include "chrome/test/base/ui_test_utils.h"
-#include "components/search_engines/template_url_service.h"
-#include "content/public/browser/navigation_controller.h"
-#include "content/public/browser/navigation_entry.h"
-#include "content/public/browser/web_contents.h"
-#include "net/test/embedded_test_server/embedded_test_server.h"
-#include "net/test/url_request/url_request_mock_http_job.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#include "url/gurl.h"
-
-using content::BrowserThread;
-
-class NewTabPageInterceptorTest : public InProcessBrowserTest {
- public:
-  NewTabPageInterceptorTest() {}
-
-  void SetUpOnMainThread() override {
-    base::FilePath path =
-        ui_test_utils::GetTestFilePath(base::FilePath(), base::FilePath());
-    BrowserThread::PostTask(
-        BrowserThread::IO, FROM_HERE,
-        base::BindOnce(&net::URLRequestMockHTTPJob::AddUrlHandlers, path));
-  }
-
-  void ChangeDefaultSearchProvider(const char* new_tab_path) {
-    TemplateURLService* template_url_service =
-        TemplateURLServiceFactory::GetForProfile(browser()->profile());
-    search_test_utils::WaitForTemplateURLServiceToLoad(template_url_service);
-    UIThreadSearchTermsData::SetGoogleBaseURL("https://mock.http/");
-    std::string base_url("{google:baseURL}");
-    TemplateURLData data;
-    data.SetShortName(base::ASCIIToUTF16("Google"));
-    data.SetKeyword(base::UTF8ToUTF16(base_url));
-    data.SetURL(base_url + "url?bar={searchTerms}");
-    data.new_tab_url = base_url + new_tab_path;
-    TemplateURL* template_url =
-        template_url_service->Add(std::make_unique<TemplateURL>(data));
-    template_url_service->SetUserSelectedDefaultSearchProvider(template_url);
-  }
-};
-
-IN_PROC_BROWSER_TEST_F(NewTabPageInterceptorTest, NoInterception) {
-  net::EmbeddedTestServer https_test_server(
-      net::EmbeddedTestServer::TYPE_HTTPS);
-  ASSERT_TRUE(https_test_server.Start());
-  GURL new_tab_url = https_test_server.GetURL("/instant_extended.html");
-  ChangeDefaultSearchProvider("instant_extended.html");
-
-  ui_test_utils::NavigateToURL(browser(), new_tab_url);
-  content::WebContents* contents =
-      browser()->tab_strip_model()->GetWebContentsAt(0);
-  // A correct, 200-OK file works correctly.
-  EXPECT_EQ(new_tab_url,
-            contents->GetController().GetLastCommittedEntry()->GetURL());
-}
-
-IN_PROC_BROWSER_TEST_F(NewTabPageInterceptorTest, 404Interception) {
-  GURL new_tab_url =
-      net::URLRequestMockHTTPJob::GetMockHttpsUrl("page404.html");
-  ChangeDefaultSearchProvider("page404.html");
-
-  ui_test_utils::NavigateToURL(browser(), new_tab_url);
-  content::WebContents* contents =
-      browser()->tab_strip_model()->GetWebContentsAt(0);
-  // 404 makes a redirect to the local NTP.
-  EXPECT_EQ(GURL(chrome::kChromeSearchLocalNtpUrl),
-            contents->GetController().GetLastCommittedEntry()->GetURL());
-}
-
-IN_PROC_BROWSER_TEST_F(NewTabPageInterceptorTest, 204Interception) {
-  GURL new_tab_url =
-      net::URLRequestMockHTTPJob::GetMockHttpsUrl("page204.html");
-  ChangeDefaultSearchProvider("page204.html");
-
-  ui_test_utils::NavigateToURL(browser(), new_tab_url);
-  content::WebContents* contents =
-      browser()->tab_strip_model()->GetWebContentsAt(0);
-  // 204 makes a redirect to the local NTP.
-  EXPECT_EQ(GURL(chrome::kChromeSearchLocalNtpUrl),
-            contents->GetController().GetLastCommittedEntry()->GetURL());
-}
-
-IN_PROC_BROWSER_TEST_F(NewTabPageInterceptorTest, FailedRequestInterception) {
-  GURL new_tab_url =
-      net::URLRequestMockHTTPJob::GetMockHttpsUrl("notarealfile.html");
-  ChangeDefaultSearchProvider("notarealfile.html");
-
-  ui_test_utils::NavigateToURL(browser(), new_tab_url);
-  content::WebContents* contents =
-      browser()->tab_strip_model()->GetWebContentsAt(0);
-  // Failed navigation makes a redirect to the local NTP.
-  EXPECT_EQ(GURL(chrome::kChromeSearchLocalNtpUrl),
-            contents->GetController().GetLastCommittedEntry()->GetURL());
-}
diff --git a/chrome/browser/ui/search/new_tab_page_interceptor_service.cc b/chrome/browser/ui/search/new_tab_page_interceptor_service.cc
deleted file mode 100644
index 44d2b031..0000000
--- a/chrome/browser/ui/search/new_tab_page_interceptor_service.cc
+++ /dev/null
@@ -1,130 +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 "chrome/browser/ui/search/new_tab_page_interceptor_service.h"
-
-#include <utility>
-
-#include "base/location.h"
-#include "base/logging.h"
-#include "base/macros.h"
-#include "base/metrics/histogram_macros.h"
-#include "chrome/browser/profiles/profile.h"
-#include "chrome/browser/search/search.h"
-#include "chrome/browser/search_engines/template_url_service_factory.h"
-#include "chrome/common/url_constants.h"
-#include "components/search_engines/template_url_service.h"
-#include "content/public/browser/browser_thread.h"
-#include "net/base/net_errors.h"
-#include "net/http/http_status_code.h"
-#include "net/url_request/url_request.h"
-#include "net/url_request/url_request_interceptor.h"
-#include "net/url_request/url_request_job.h"
-#include "net/url_request/url_request_redirect_job.h"
-#include "url/gurl.h"
-
-// Implementation of the URLRequestInterceptor for the New Tab Page. Will look
-// at incoming response from the server and possibly divert to the local NTP.
-class NewTabPageInterceptor : public net::URLRequestInterceptor {
- public:
-  explicit NewTabPageInterceptor(const GURL& new_tab_url)
-      : new_tab_url_(new_tab_url), weak_factory_(this) {
-    DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
-  }
-
-  ~NewTabPageInterceptor() override {
-    DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
-  }
-
-  base::WeakPtr<NewTabPageInterceptor> GetWeakPtr() {
-    DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
-    return weak_factory_.GetWeakPtr();
-  }
-
-  void SetNewTabPageURL(const GURL& new_tab_page_url) {
-    DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
-    new_tab_url_ = new_tab_page_url;
-  }
-
- private:
-  // Overrides from net::URLRequestInterceptor:
-  net::URLRequestJob* MaybeInterceptRequest(
-      net::URLRequest* request,
-      net::NetworkDelegate* network_delegate) const override {
-    DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
-    return nullptr;
-  }
-
-  net::URLRequestJob* MaybeInterceptResponse(
-      net::URLRequest* request,
-      net::NetworkDelegate* network_delegate) const override {
-    DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
-    if ((request->url() != new_tab_url_) ||
-        (new_tab_url_ == chrome::kChromeSearchLocalNtpUrl)) {
-      return nullptr;
-    }
-    // User has canceled this navigation so it shouldn't be redirected.
-    // TODO(maksims): Remove request->status() and use int net_error
-    // once MaybeInterceptResponse() starts to pass that.
-    if (request->status().status() == net::URLRequestStatus::CANCELED ||
-        (request->status().status() == net::URLRequestStatus::FAILED &&
-         request->status().error() == net::ERR_ABORTED)) {
-      return nullptr;
-    }
-
-    // Request to NTP was successful.
-    // TODO(maksims): Remove request->status() and use int net_error
-    // once MaybeInterceptResponse() starts to pass that.
-    if (request->status().is_success() &&
-        request->GetResponseCode() != net::HTTP_NO_CONTENT &&
-        request->GetResponseCode() < 400) {
-      return nullptr;
-    }
-
-    // Failure to load the NTP correctly; redirect to Local NTP.
-    UMA_HISTOGRAM_ENUMERATION("InstantExtended.CacheableNTPLoad",
-                              search::CACHEABLE_NTP_LOAD_FAILED,
-                              search::CACHEABLE_NTP_LOAD_MAX);
-    return new net::URLRequestRedirectJob(
-        request, network_delegate, GURL(chrome::kChromeSearchLocalNtpUrl),
-        net::URLRequestRedirectJob::REDIRECT_307_TEMPORARY_REDIRECT,
-        "NTP Request Interceptor");
-  }
-
-  GURL new_tab_url_;
-  base::WeakPtrFactory<NewTabPageInterceptor> weak_factory_;
-
-  DISALLOW_COPY_AND_ASSIGN(NewTabPageInterceptor);
-};
-
-NewTabPageInterceptorService::NewTabPageInterceptorService(Profile* profile)
-    : profile_(profile),
-      template_url_service_(TemplateURLServiceFactory::GetForProfile(profile)) {
-  DCHECK(profile_);
-  if (template_url_service_)
-    template_url_service_->AddObserver(this);
-}
-
-NewTabPageInterceptorService::~NewTabPageInterceptorService() {
-  if (template_url_service_)
-    template_url_service_->RemoveObserver(this);
-}
-
-void NewTabPageInterceptorService::OnTemplateURLServiceChanged() {
-  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
-  GURL new_tab_page_url(search::GetNewTabPageURL(profile_));
-  content::BrowserThread::PostTask(
-      content::BrowserThread::IO, FROM_HERE,
-      base::BindOnce(&NewTabPageInterceptor::SetNewTabPageURL, interceptor_,
-                     new_tab_page_url));
-}
-
-std::unique_ptr<net::URLRequestInterceptor>
-NewTabPageInterceptorService::CreateInterceptor() {
-  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
-  std::unique_ptr<NewTabPageInterceptor> interceptor(
-      new NewTabPageInterceptor(search::GetNewTabPageURL(profile_)));
-  interceptor_ = interceptor->GetWeakPtr();
-  return std::move(interceptor);
-}
diff --git a/chrome/browser/ui/search/new_tab_page_interceptor_service.h b/chrome/browser/ui/search/new_tab_page_interceptor_service.h
deleted file mode 100644
index ff5f22c..0000000
--- a/chrome/browser/ui/search/new_tab_page_interceptor_service.h
+++ /dev/null
@@ -1,46 +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 CHROME_BROWSER_UI_SEARCH_NEW_TAB_PAGE_INTERCEPTOR_SERVICE_H_
-#define CHROME_BROWSER_UI_SEARCH_NEW_TAB_PAGE_INTERCEPTOR_SERVICE_H_
-
-#include <memory>
-
-#include "base/macros.h"
-#include "base/memory/weak_ptr.h"
-#include "components/keyed_service/core/keyed_service.h"
-#include "components/search_engines/template_url_service_observer.h"
-
-class NewTabPageInterceptor;
-class Profile;
-class TemplateURLService;
-
-namespace net {
-class URLRequestInterceptor;
-}
-
-// Owns a NewTabPageInterceptor.
-class NewTabPageInterceptorService : public KeyedService,
-                                     public TemplateURLServiceObserver {
- public:
-  explicit NewTabPageInterceptorService(Profile* profile);
-  ~NewTabPageInterceptorService() override;
-
-  // TemplateURLServiceObserver override.
-  void OnTemplateURLServiceChanged() override;
-
-  std::unique_ptr<net::URLRequestInterceptor> CreateInterceptor();
-
- private:
-  Profile* profile_;
-  base::WeakPtr<NewTabPageInterceptor> interceptor_;
-  // The TemplateURLService that we are observing. It will outlive this
-  // NewTabPageInterceptorService due to the dependency declared in
-  // NewTabPageInterceptorServiceFactory.
-  TemplateURLService* template_url_service_;
-
-  DISALLOW_COPY_AND_ASSIGN(NewTabPageInterceptorService);
-};
-
-#endif  // CHROME_BROWSER_UI_SEARCH_NEW_TAB_PAGE_INTERCEPTOR_SERVICE_H_
diff --git a/chrome/browser/ui/search/new_tab_page_interceptor_service_factory.cc b/chrome/browser/ui/search/new_tab_page_interceptor_service_factory.cc
deleted file mode 100644
index 0aa11814..0000000
--- a/chrome/browser/ui/search/new_tab_page_interceptor_service_factory.cc
+++ /dev/null
@@ -1,48 +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 "chrome/browser/ui/search/new_tab_page_interceptor_service_factory.h"
-
-#include "chrome/browser/profiles/profile.h"
-#include "chrome/browser/search/instant_service_factory.h"
-#include "chrome/browser/search_engines/template_url_service_factory.h"
-#include "chrome/browser/ui/search/new_tab_page_interceptor_service.h"
-#include "components/keyed_service/content/browser_context_dependency_manager.h"
-#include "content/public/browser/browser_thread.h"
-
-// static
-NewTabPageInterceptorServiceFactory*
-NewTabPageInterceptorServiceFactory::GetInstance() {
-  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
-  return base::Singleton<NewTabPageInterceptorServiceFactory>::get();
-}
-
-// static
-NewTabPageInterceptorService*
-NewTabPageInterceptorServiceFactory::GetForProfile(Profile* profile) {
-  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
-  if (profile->IsOffTheRecord())
-    return nullptr;
-
-  return static_cast<NewTabPageInterceptorService*>(
-      GetInstance()->GetServiceForBrowserContext(profile, true));
-}
-
-NewTabPageInterceptorServiceFactory::NewTabPageInterceptorServiceFactory()
-    : BrowserContextKeyedServiceFactory(
-          "NTP Request Interceptor Service Factory",
-          BrowserContextDependencyManager::GetInstance()) {
-  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
-  DependsOn(TemplateURLServiceFactory::GetInstance());
-}
-
-NewTabPageInterceptorServiceFactory::~NewTabPageInterceptorServiceFactory() {
-}
-
-KeyedService* NewTabPageInterceptorServiceFactory::BuildServiceInstanceFor(
-    content::BrowserContext* context) const {
-  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
-  Profile* profile = Profile::FromBrowserContext(context);
-  return new NewTabPageInterceptorService(profile);
-}
diff --git a/chrome/browser/ui/search/new_tab_page_interceptor_service_factory.h b/chrome/browser/ui/search/new_tab_page_interceptor_service_factory.h
deleted file mode 100644
index 37dee82c..0000000
--- a/chrome/browser/ui/search/new_tab_page_interceptor_service_factory.h
+++ /dev/null
@@ -1,41 +0,0 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROME_BROWSER_UI_SEARCH_NEW_TAB_PAGE_INTERCEPTOR_SERVICE_FACTORY_H_
-#define CHROME_BROWSER_UI_SEARCH_NEW_TAB_PAGE_INTERCEPTOR_SERVICE_FACTORY_H_
-
-#include "base/macros.h"
-#include "base/memory/singleton.h"
-#include "components/keyed_service/content/browser_context_keyed_service_factory.h"
-#include "components/keyed_service/core/keyed_service.h"
-
-class NewTabPageInterceptorService;
-class Profile;
-
-namespace content {
-class BrowserContext;
-}
-
-// Owns and creates NewTabPageInterceptorService instances.
-class NewTabPageInterceptorServiceFactory
-    : public BrowserContextKeyedServiceFactory {
- public:
-  static NewTabPageInterceptorService* GetForProfile(Profile* profile);
-  static NewTabPageInterceptorServiceFactory* GetInstance();
-
- private:
-  friend struct base::DefaultSingletonTraits<
-      NewTabPageInterceptorServiceFactory>;
-
-  NewTabPageInterceptorServiceFactory();
-  ~NewTabPageInterceptorServiceFactory() override;
-
-  // BrowserContextKeyedServiceFactory:
-  KeyedService* BuildServiceInstanceFor(
-      content::BrowserContext* context) const override;
-
-  DISALLOW_COPY_AND_ASSIGN(NewTabPageInterceptorServiceFactory);
-};
-
-#endif  // CHROME_BROWSER_UI_SEARCH_NEW_TAB_PAGE_INTERCEPTOR_SERVICE_FACTORY_H_
diff --git a/chrome/browser/ui/search/new_tab_page_navigation_throttle.cc b/chrome/browser/ui/search/new_tab_page_navigation_throttle.cc
new file mode 100644
index 0000000..b964991
--- /dev/null
+++ b/chrome/browser/ui/search/new_tab_page_navigation_throttle.cc
@@ -0,0 +1,74 @@
+// 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 "chrome/browser/ui/search/new_tab_page_navigation_throttle.h"
+
+#include "base/metrics/histogram_macros.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/search/search.h"
+#include "chrome/common/url_constants.h"
+#include "content/public/browser/navigation_handle.h"
+#include "content/public/browser/web_contents.h"
+#include "net/http/http_status_code.h"
+#include "url/gurl.h"
+
+NewTabPageNavigationThrottle::NewTabPageNavigationThrottle(
+    content::NavigationHandle* navigation_handle)
+    : content::NavigationThrottle(navigation_handle) {}
+
+NewTabPageNavigationThrottle::~NewTabPageNavigationThrottle() = default;
+
+const char* NewTabPageNavigationThrottle::GetNameForLogging() {
+  return "NewTabPageNavigationThrottle";
+}
+
+// static
+std::unique_ptr<content::NavigationThrottle>
+NewTabPageNavigationThrottle::MaybeCreateThrottleFor(
+    content::NavigationHandle* handle) {
+  content::WebContents* web_contents = handle->GetWebContents();
+  Profile* profile =
+      Profile::FromBrowserContext(web_contents->GetBrowserContext());
+  if (web_contents->GetVisibleURL() != chrome::kChromeUINewTabURL ||
+      !search::IsInstantNTPURL(handle->GetURL(), profile) ||
+      handle->GetURL() == chrome::kChromeSearchLocalNtpUrl) {
+    return nullptr;
+  }
+
+  return std::make_unique<NewTabPageNavigationThrottle>(handle);
+}
+
+content::NavigationThrottle::ThrottleCheckResult
+NewTabPageNavigationThrottle::WillProcessResponse() {
+  const net::HttpResponseHeaders* headers =
+      navigation_handle()->GetResponseHeaders();
+  if (!headers)
+    return content::NavigationThrottle::PROCEED;
+
+  int response_code = headers->response_code();
+  if (response_code < 400 && response_code != net::HTTP_NO_CONTENT)
+    return content::NavigationThrottle::PROCEED;
+
+  return OpenLocalNewTabPage();
+}
+
+content::NavigationThrottle::ThrottleCheckResult
+NewTabPageNavigationThrottle::WillFailRequest() {
+  return OpenLocalNewTabPage();
+}
+
+content::NavigationThrottle::ThrottleCheckResult
+NewTabPageNavigationThrottle::OpenLocalNewTabPage() {
+  UMA_HISTOGRAM_ENUMERATION("InstantExtended.CacheableNTPLoad",
+                            search::CACHEABLE_NTP_LOAD_FAILED,
+                            search::CACHEABLE_NTP_LOAD_MAX);
+  navigation_handle()->GetWebContents()->OpenURL(
+      content::OpenURLParams(GURL(chrome::kChromeSearchLocalNtpUrl),
+                             navigation_handle()->GetReferrer(),
+                             navigation_handle()->GetFrameTreeNodeId(),
+                             WindowOpenDisposition::CURRENT_TAB,
+                             navigation_handle()->GetPageTransition(),
+                             false /* is_renderer_initiated */));
+  return content::NavigationThrottle::CANCEL_AND_IGNORE;
+}
diff --git a/chrome/browser/ui/search/new_tab_page_navigation_throttle.h b/chrome/browser/ui/search/new_tab_page_navigation_throttle.h
new file mode 100644
index 0000000..be0498b
--- /dev/null
+++ b/chrome/browser/ui/search/new_tab_page_navigation_throttle.h
@@ -0,0 +1,38 @@
+// 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 CHROME_BROWSER_UI_SEARCH_NEW_TAB_PAGE_NAVIGATION_THROTTLE_H_
+#define CHROME_BROWSER_UI_SEARCH_NEW_TAB_PAGE_NAVIGATION_THROTTLE_H_
+
+#include <memory>
+
+#include "content/public/browser/navigation_throttle.h"
+
+namespace content {
+class NavigationHandle;
+}  // namespace content
+
+// A NavigationThrottle that opens the local New Tab Page when there is any
+// issue opening the remote New Tab Page.
+class NewTabPageNavigationThrottle : public content::NavigationThrottle {
+ public:
+  // Returns a NavigationThrottle when:
+  // - we are navigating to the new tab page, and
+  // - the main frame is pointed at the new tab URL.
+  static std::unique_ptr<content::NavigationThrottle> MaybeCreateThrottleFor(
+      content::NavigationHandle* handle);
+
+  explicit NewTabPageNavigationThrottle(content::NavigationHandle* handle);
+  ~NewTabPageNavigationThrottle() override;
+
+  // content::NavigationThrottle:
+  ThrottleCheckResult WillFailRequest() override;
+  ThrottleCheckResult WillProcessResponse() override;
+  const char* GetNameForLogging() override;
+
+ private:
+  ThrottleCheckResult OpenLocalNewTabPage();
+};
+
+#endif  // CHROME_BROWSER_UI_SEARCH_NEW_TAB_PAGE_NAVIGATION_THROTTLE_H_
diff --git a/chrome/browser/ui/search/new_tab_page_navigation_throttle_browsertest.cc b/chrome/browser/ui/search/new_tab_page_navigation_throttle_browsertest.cc
new file mode 100644
index 0000000..dc40271c
--- /dev/null
+++ b/chrome/browser/ui/search/new_tab_page_navigation_throttle_browsertest.cc
@@ -0,0 +1,97 @@
+// 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 "chrome/browser/search/search.h"
+#include "chrome/browser/search_engines/template_url_service_factory.h"
+#include "chrome/browser/ui/browser.h"
+#include "chrome/browser/ui/search/local_ntp_test_utils.h"
+#include "chrome/browser/ui/tabs/tab_strip_model.h"
+#include "chrome/common/chrome_paths.h"
+#include "chrome/common/url_constants.h"
+#include "chrome/test/base/in_process_browser_test.h"
+#include "chrome/test/base/search_test_utils.h"
+#include "chrome/test/base/ui_test_utils.h"
+#include "components/search_engines/template_url_service.h"
+#include "content/public/browser/navigation_entry.h"
+#include "content/public/browser/web_contents.h"
+#include "net/test/embedded_test_server/embedded_test_server.h"
+#include "url/gurl.h"
+
+namespace {
+
+class NewTabPageNavigationThrottleTest : public InProcessBrowserTest {
+ public:
+  NewTabPageNavigationThrottleTest()
+      : https_test_server_(net::EmbeddedTestServer::TYPE_HTTPS) {
+    https_test_server()->AddDefaultHandlers(
+        base::FilePath(FILE_PATH_LITERAL("chrome/test/data")));
+  }
+
+  void SetNewTabPage(const std::string& ntp_url) {
+    // Set the new tab page.
+    local_ntp_test_utils::SetUserSelectedDefaultSearchProvider(
+        browser()->profile(), https_test_server()->base_url().spec(), ntp_url);
+
+    // Ensure we are using the newly set new_tab_url and won't be directed
+    // to the local new tab page.
+    TemplateURLService* service =
+        TemplateURLServiceFactory::GetForProfile(browser()->profile());
+    search_test_utils::WaitForTemplateURLServiceToLoad(service);
+    ASSERT_EQ(search::GetNewTabPageURL(browser()->profile()), ntp_url);
+  }
+
+  // Navigates to the New Tab Page and then returns the GURL that ultimately was
+  // navigated to.
+  GURL NavigateToNewTabPage() {
+    ui_test_utils::NavigateToURL(browser(), GURL(chrome::kChromeUINewTabURL));
+    content::WebContents* contents =
+        browser()->tab_strip_model()->GetWebContentsAt(0);
+    return contents->GetController().GetLastCommittedEntry()->GetURL();
+  }
+
+  net::EmbeddedTestServer* https_test_server() { return &https_test_server_; }
+
+  net::EmbeddedTestServer https_test_server_;
+};
+
+IN_PROC_BROWSER_TEST_F(NewTabPageNavigationThrottleTest, NoThrottle) {
+  ASSERT_TRUE(https_test_server()->Start());
+  std::string ntp_url =
+      https_test_server()->GetURL("/instant_extended.html").spec();
+  SetNewTabPage(ntp_url);
+  // A correct, 200-OK file works correctly.
+  EXPECT_EQ(ntp_url, NavigateToNewTabPage());
+}
+
+IN_PROC_BROWSER_TEST_F(NewTabPageNavigationThrottleTest,
+                       FailedRequestThrottle) {
+  ASSERT_TRUE(https_test_server()->Start());
+  SetNewTabPage(https_test_server()->GetURL("/instant_extended.html").spec());
+  ASSERT_TRUE(https_test_server()->ShutdownAndWaitUntilComplete());
+  // Failed navigation makes a redirect to the local NTP.
+  EXPECT_EQ(chrome::kChromeSearchLocalNtpUrl, NavigateToNewTabPage());
+}
+
+IN_PROC_BROWSER_TEST_F(NewTabPageNavigationThrottleTest, LocalNewTabPage) {
+  ASSERT_TRUE(https_test_server()->Start());
+  SetNewTabPage(chrome::kChromeSearchLocalNtpUrl);
+  // Already going to the local NTP, so we should arrive there as expected.
+  EXPECT_EQ(chrome::kChromeSearchLocalNtpUrl, NavigateToNewTabPage());
+}
+
+IN_PROC_BROWSER_TEST_F(NewTabPageNavigationThrottleTest, 404Throttle) {
+  ASSERT_TRUE(https_test_server()->Start());
+  SetNewTabPage(https_test_server()->GetURL("/page404.html").spec());
+  // 404 makes a redirect to the local NTP.
+  EXPECT_EQ(chrome::kChromeSearchLocalNtpUrl, NavigateToNewTabPage());
+}
+
+IN_PROC_BROWSER_TEST_F(NewTabPageNavigationThrottleTest, 204Throttle) {
+  ASSERT_TRUE(https_test_server()->Start());
+  SetNewTabPage(https_test_server()->GetURL("/page204.html").spec());
+  // 204 makes a redirect to the local NTP.
+  EXPECT_EQ(chrome::kChromeSearchLocalNtpUrl, NavigateToNewTabPage());
+}
+
+}  // namespace
diff --git a/chrome/browser/ui/startup/startup_browser_creator_browsertest.cc b/chrome/browser/ui/startup/startup_browser_creator_browsertest.cc
index d013123..1386caf9 100644
--- a/chrome/browser/ui/startup/startup_browser_creator_browsertest.cc
+++ b/chrome/browser/ui/startup/startup_browser_creator_browsertest.cc
@@ -30,6 +30,7 @@
 #include "chrome/browser/profiles/profile_attributes_storage.h"
 #include "chrome/browser/profiles/profile_impl.h"
 #include "chrome/browser/profiles/profile_manager.h"
+#include "chrome/browser/search/search.h"
 #include "chrome/browser/sessions/session_restore.h"
 #include "chrome/browser/signin/signin_promo.h"
 #include "chrome/browser/ui/browser.h"
@@ -757,8 +758,7 @@
 
   // The new browser should have only the NTP.
   ASSERT_EQ(1, tab_strip->count());
-  EXPECT_EQ(GURL(chrome::kChromeUINewTabURL),
-            tab_strip->GetWebContentsAt(0)->GetURL());
+  EXPECT_TRUE(search::IsInstantNTP(tab_strip->GetWebContentsAt(0)));
 
   // profile_urls opened the urls.
   ASSERT_EQ(1u, chrome::GetBrowserCount(profile_urls));
@@ -871,8 +871,7 @@
 
   // The new browser should have only the NTP.
   ASSERT_EQ(1, tab_strip->count());
-  EXPECT_EQ(GURL(chrome::kChromeUINewTabURL),
-            tab_strip->GetWebContentsAt(0)->GetURL());
+  EXPECT_TRUE(search::IsInstantNTP(tab_strip->GetWebContentsAt(0)));
 
   EnsureRestoreUIWasShown(tab_strip->GetWebContentsAt(0));
 
@@ -882,8 +881,7 @@
   ASSERT_TRUE(new_browser);
   tab_strip = new_browser->tab_strip_model();
   ASSERT_EQ(1, tab_strip->count());
-  EXPECT_EQ(GURL(chrome::kChromeUINewTabURL),
-            tab_strip->GetWebContentsAt(0)->GetURL());
+  EXPECT_TRUE(search::IsInstantNTP(tab_strip->GetWebContentsAt(0)));
   EnsureRestoreUIWasShown(tab_strip->GetWebContentsAt(0));
 
   // The profile which normally opens URLs displays the new tab page.
@@ -892,8 +890,7 @@
   ASSERT_TRUE(new_browser);
   tab_strip = new_browser->tab_strip_model();
   ASSERT_EQ(1, tab_strip->count());
-  EXPECT_EQ(GURL(chrome::kChromeUINewTabURL),
-            tab_strip->GetWebContentsAt(0)->GetURL());
+  EXPECT_TRUE(search::IsInstantNTP(tab_strip->GetWebContentsAt(0)));
   EnsureRestoreUIWasShown(tab_strip->GetWebContentsAt(0));
 
 #if !defined(OS_MACOSX) && !defined(GOOGLE_CHROME_BUILD)
diff --git a/chrome/browser/ui/views/extensions/media_galleries_dialog_views.cc b/chrome/browser/ui/views/extensions/media_galleries_dialog_views.cc
index 6059602..ce91bd3 100644
--- a/chrome/browser/ui/views/extensions/media_galleries_dialog_views.cc
+++ b/chrome/browser/ui/views/extensions/media_galleries_dialog_views.cc
@@ -218,6 +218,10 @@
   return controller_->GetHeader();
 }
 
+bool MediaGalleriesDialogViews::ShouldShowCloseButton() const {
+  return false;
+}
+
 void MediaGalleriesDialogViews::DeleteDelegate() {
   controller_->DialogFinished(accepted_);
 }
diff --git a/chrome/browser/ui/views/extensions/media_galleries_dialog_views.h b/chrome/browser/ui/views/extensions/media_galleries_dialog_views.h
index 5ca9e9b..6cf4eaa 100644
--- a/chrome/browser/ui/views/extensions/media_galleries_dialog_views.h
+++ b/chrome/browser/ui/views/extensions/media_galleries_dialog_views.h
@@ -40,6 +40,7 @@
 
   // views::DialogDelegate implementation:
   base::string16 GetWindowTitle() const override;
+  bool ShouldShowCloseButton() const override;
   void DeleteDelegate() override;
   views::Widget* GetWidget() override;
   const views::Widget* GetWidget() const override;
diff --git a/chrome/browser/ui/views/page_info/page_info_bubble_view.cc b/chrome/browser/ui/views/page_info/page_info_bubble_view.cc
index 7b78809..ce22411 100644
--- a/chrome/browser/ui/views/page_info/page_info_bubble_view.cc
+++ b/chrome/browser/ui/views/page_info/page_info_bubble_view.cc
@@ -1031,7 +1031,7 @@
     // Use the Cocoa code path for showing the Views page info dialog so that it
     // anchors properly.
     return chrome::ShowPageInfoBubbleViews(browser, web_contents, virtual_url,
-                                           security_info);
+                                           security_info, anchor);
   }
 #endif
   views::BubbleDialogDelegateView* bubble =
diff --git a/chrome/browser/ui/views/renderer_context_menu/render_view_context_menu_views.cc b/chrome/browser/ui/views/renderer_context_menu/render_view_context_menu_views.cc
index 4bb5c78..13ad66d 100644
--- a/chrome/browser/ui/views/renderer_context_menu/render_view_context_menu_views.cc
+++ b/chrome/browser/ui/views/renderer_context_menu/render_view_context_menu_views.cc
@@ -25,6 +25,7 @@
 #include "ui/base/accelerators/accelerator.h"
 #include "ui/base/l10n/l10n_util.h"
 #include "ui/events/keycodes/keyboard_codes.h"
+#include "ui/strings/grit/ui_strings.h"
 #include "ui/views/widget/widget.h"
 
 using content::WebContents;
diff --git a/chrome/common/profiling/profiling_service.mojom b/chrome/common/profiling/profiling_service.mojom
index 60bc8834..2d98b61 100644
--- a/chrome/common/profiling/profiling_service.mojom
+++ b/chrome/common/profiling/profiling_service.mojom
@@ -5,16 +5,9 @@
 module profiling.mojom;
 
 import "chrome/common/profiling/profiling_client.mojom";
-import "mojo/common/file.mojom";
 import "mojo/common/process_id.mojom";
 import "mojo/common/values.mojom";
 
-struct SharedBufferWithSize {
-  handle<shared_buffer> buffer;
-  uint32 size;
-  mojo.common.mojom.ProcessId pid;
-};
-
 // These values are persisted to logs. Entries should not be renumbered and
 // numeric values should never be reused.
 enum ProcessType {
@@ -44,18 +37,9 @@
                      ProcessType process_type,
                      ProfilingParams params);
 
-  // Dumps the memory log of all profiled processes into shared buffers. The
-  // contents of each shared buffer is a JSON string compatible with
-  // TRACE_EVENT* macros. Processes that fail to dump will be omitted from
-  // |buffers|. When |strip_path_from_mapped_files| is true, only the base name
-  // of mapped files is emitted. This prevents usernames from sneaking into the
-  // trace.
-  // |strip_path_from_mapped_files| should only be true for traces that will be
-  // uploaded to the crash servers - this strips potential PII, but prevents
-  // symbolization of local builds.
-  DumpProcessesForTracing(bool keep_small_allocations,
-                          bool strip_path_from_mapped_files) =>
-      (array<SharedBufferWithSize> buffers);
+  // |keep_small_allocations| controls whether small allocations are emitted in
+  // heap dumps.
+  SetKeepSmallAllocations(bool keep_small_allocations);
 
   // Returns the pids of all profiled processes.
   GetProfiledPids() => (array<mojo.common.mojom.ProcessId> pids);
diff --git a/chrome/common/webui_url_constants.cc b/chrome/common/webui_url_constants.cc
index 3029c5a..3cf749e 100644
--- a/chrome/common/webui_url_constants.cc
+++ b/chrome/common/webui_url_constants.cc
@@ -24,7 +24,6 @@
 const char kChromeUIBluetoothInternalsHost[] = "bluetooth-internals";
 const char kChromeUIBookmarksHost[] = "bookmarks";
 const char kChromeUIBookmarksURL[] = "chrome://bookmarks/";
-const char kChromeUICacheHost[] = "cache";
 const char kChromeUICertificateViewerDialogHost[] = "view-cert-dialog";
 const char kChromeUICertificateViewerDialogURL[] = "chrome://view-cert-dialog/";
 const char kChromeUICertificateViewerHost[] = "view-cert";
@@ -299,7 +298,6 @@
 const char* const kChromeHostURLs[] = {
     kChromeUIAboutHost,
     kChromeUIBluetoothInternalsHost,
-    kChromeUICacheHost,
     kChromeUIChromeURLsHost,
     kChromeUIComponentsHost,
     kChromeUICrashesHost,
@@ -351,7 +349,6 @@
     content::kChromeUIMediaInternalsHost,
     content::kChromeUINetworkErrorHost,
     content::kChromeUINetworkErrorsListingHost,
-    content::kChromeUINetworkViewCacheHost,
     content::kChromeUIServiceWorkerInternalsHost,
 #if !defined(OS_ANDROID)
     content::kChromeUITracingHost,
diff --git a/chrome/common/webui_url_constants.h b/chrome/common/webui_url_constants.h
index 54e9b00..c94d706 100644
--- a/chrome/common/webui_url_constants.h
+++ b/chrome/common/webui_url_constants.h
@@ -31,7 +31,6 @@
 extern const char kChromeUIBluetoothInternalsHost[];
 extern const char kChromeUIBookmarksHost[];
 extern const char kChromeUIBookmarksURL[];
-extern const char kChromeUICacheHost[];
 extern const char kChromeUICertificateViewerDialogHost[];
 extern const char kChromeUICertificateViewerDialogURL[];
 extern const char kChromeUICertificateViewerHost[];
diff --git a/chrome/profiling/memlog_connection_manager.cc b/chrome/profiling/memlog_connection_manager.cc
index 3c0b9ee..83a5278 100644
--- a/chrome/profiling/memlog_connection_manager.cc
+++ b/chrome/profiling/memlog_connection_manager.cc
@@ -53,13 +53,13 @@
   size_t waiting_responses = 0;
 
   // Callback to issue when dumps are complete.
-  mojom::ProfilingService::DumpProcessesForTracingCallback callback;
+  DumpProcessesForTracingCallback callback;
 
   // Info about the request.
   VmRegions vm_regions;
 
   // Collects the results.
-  std::vector<profiling::mojom::SharedBufferWithSizePtr> results;
+  std::vector<memory_instrumentation::mojom::SharedBufferWithSizePtr> results;
 
  private:
   friend class base::RefCountedThreadSafe<DumpProcessesForTracingTracking>;
@@ -234,14 +234,14 @@
 void MemlogConnectionManager::DumpProcessesForTracing(
     bool keep_small_allocations,
     bool strip_path_from_mapped_files,
-    mojom::ProfilingService::DumpProcessesForTracingCallback callback,
+    DumpProcessesForTracingCallback callback,
     VmRegions vm_regions) {
   base::AutoLock lock(connections_lock_);
 
   // Early out if there are no connections.
   if (connections_.empty()) {
     std::move(callback).Run(
-        std::vector<profiling::mojom::SharedBufferWithSizePtr>());
+        std::vector<memory_instrumentation::mojom::SharedBufferWithSizePtr>());
     return;
   }
 
@@ -337,8 +337,8 @@
           } else {
             memcpy(mapping.get(), reply.c_str(), reply.size());
 
-            profiling::mojom::SharedBufferWithSizePtr result =
-                profiling::mojom::SharedBufferWithSize::New();
+            memory_instrumentation::mojom::SharedBufferWithSizePtr result =
+                memory_instrumentation::mojom::SharedBufferWithSize::New();
             result->buffer = std::move(buffer);
             result->size = reply.size();
             result->pid = pid;
diff --git a/chrome/profiling/memlog_connection_manager.h b/chrome/profiling/memlog_connection_manager.h
index e8fb787..8da3e47 100644
--- a/chrome/profiling/memlog_connection_manager.h
+++ b/chrome/profiling/memlog_connection_manager.h
@@ -44,7 +44,9 @@
 // This object is constructed on the UI thread, but the rest of the usage
 // (including deletion) is on the IO thread.
 class MemlogConnectionManager {
- private:
+  using DumpProcessesForTracingCallback = memory_instrumentation::mojom::
+      HeapProfiler::DumpProcessesForTracingCallback;
+
  public:
   MemlogConnectionManager();
   ~MemlogConnectionManager();
@@ -68,11 +70,10 @@
   // Dumping is asynchronous so will not be complete when this function
   // returns. The dump is complete when the callback provided in the args is
   // fired.
-  void DumpProcessesForTracing(
-      bool keep_small_allocations,
-      bool strip_path_from_mapped_files,
-      mojom::ProfilingService::DumpProcessesForTracingCallback callback,
-      VmRegions vm_regions);
+  void DumpProcessesForTracing(bool keep_small_allocations,
+                               bool strip_path_from_mapped_files,
+                               DumpProcessesForTracingCallback callback,
+                               VmRegions vm_regions);
 
   void OnNewConnection(base::ProcessId pid,
                        mojom::ProfilingClientPtr client,
diff --git a/chrome/profiling/profiling_manifest.json b/chrome/profiling/profiling_manifest.json
index b3f7c33..5eb6f0ec 100644
--- a/chrome/profiling/profiling_manifest.json
+++ b/chrome/profiling/profiling_manifest.json
@@ -5,11 +5,12 @@
   "interface_provider_specs": {
     "service_manager:connector": {
       "provides": {
-        "profiling": [ "profiling::mojom::ProfilingService" ]
+        "profiling": [ "profiling::mojom::ProfilingService" ],
+        "heap_profiler": [ "memory_instrumentation::mojom::HeapProfiler" ]
       },
       "requires": {
         "*": [ "app" ],
-        "resource_coordinator": [ "heap_profiling" ],
+        "resource_coordinator": [ "heap_profiler_helper" ],
         "service_manager": [ "service_manager:all_users" ]
       }
     }
diff --git a/chrome/profiling/profiling_service.cc b/chrome/profiling/profiling_service.cc
index 64488994..6055221 100644
--- a/chrome/profiling/profiling_service.cc
+++ b/chrome/profiling/profiling_service.cc
@@ -14,7 +14,8 @@
 
 namespace profiling {
 
-ProfilingService::ProfilingService() : binding_(this), weak_factory_(this) {}
+ProfilingService::ProfilingService()
+    : binding_(this), heap_profiler_binding_(this), weak_factory_(this) {}
 
 ProfilingService::~ProfilingService() {}
 
@@ -25,6 +26,8 @@
 void ProfilingService::OnStart() {
   registry_.AddInterface(base::Bind(
       &ProfilingService::OnProfilingServiceRequest, base::Unretained(this)));
+  registry_.AddInterface(base::Bind(&ProfilingService::OnHeapProfilerRequest,
+                                    base::Unretained(this)));
 }
 
 void ProfilingService::OnBindInterface(
@@ -39,6 +42,11 @@
   binding_.Bind(std::move(request));
 }
 
+void ProfilingService::OnHeapProfilerRequest(
+    memory_instrumentation::mojom::HeapProfilerRequest request) {
+  heap_profiler_binding_.Bind(std::move(request));
+}
+
 void ProfilingService::AddProfilingClient(
     base::ProcessId pid,
     mojom::ProfilingClientPtr client,
@@ -52,10 +60,17 @@
                                       process_type, std::move(params));
 }
 
+void ProfilingService::SetKeepSmallAllocations(bool keep_small_allocations) {
+  keep_small_allocations_ = keep_small_allocations;
+}
+
+void ProfilingService::GetProfiledPids(GetProfiledPidsCallback callback) {
+  std::move(callback).Run(connection_manager_.GetConnectionPids());
+}
+
 void ProfilingService::DumpProcessesForTracing(
-    bool keep_small_allocations,
     bool strip_path_from_mapped_files,
-    DumpProcessesForTracingCallback callback) {
+    const DumpProcessesForTracingCallback& callback) {
   if (!helper_) {
     context()->connector()->BindInterface(
         resource_coordinator::mojom::kServiceName, &helper_);
@@ -65,7 +80,7 @@
       connection_manager_.GetConnectionPidsThatNeedVmRegions();
   if (pids.empty()) {
     connection_manager_.DumpProcessesForTracing(
-        keep_small_allocations, strip_path_from_mapped_files,
+        keep_small_allocations_, strip_path_from_mapped_files,
         std::move(callback), VmRegions());
   } else {
     // Need a memory map to make sense of the dump. The dump will be triggered
@@ -74,23 +89,18 @@
         pids,
         base::Bind(
             &ProfilingService::OnGetVmRegionsCompleteForDumpProcessesForTracing,
-            weak_factory_.GetWeakPtr(), keep_small_allocations,
-            strip_path_from_mapped_files, base::Passed(&callback)));
+            weak_factory_.GetWeakPtr(), strip_path_from_mapped_files,
+            callback));
   }
 }
 
-void ProfilingService::GetProfiledPids(GetProfiledPidsCallback callback) {
-  std::move(callback).Run(connection_manager_.GetConnectionPids());
-}
-
 void ProfilingService::OnGetVmRegionsCompleteForDumpProcessesForTracing(
-    bool keep_small_allocations,
     bool strip_path_from_mapped_files,
-    mojom::ProfilingService::DumpProcessesForTracingCallback callback,
+    const DumpProcessesForTracingCallback& callback,
     VmRegions vm_regions) {
   connection_manager_.DumpProcessesForTracing(
-      keep_small_allocations, strip_path_from_mapped_files, std::move(callback),
-      std::move(vm_regions));
+      keep_small_allocations_, strip_path_from_mapped_files,
+      std::move(callback), std::move(vm_regions));
 }
 
 }  // namespace profiling
diff --git a/chrome/profiling/profiling_service.h b/chrome/profiling/profiling_service.h
index 417f047f..ff77ff8 100644
--- a/chrome/profiling/profiling_service.h
+++ b/chrome/profiling/profiling_service.h
@@ -24,7 +24,11 @@
 //
 // This class lives in the I/O thread of the Utility process.
 class ProfilingService : public service_manager::Service,
-                         public mojom::ProfilingService {
+                         public mojom::ProfilingService,
+                         public memory_instrumentation::mojom::HeapProfiler {
+  using DumpProcessesForTracingCallback = memory_instrumentation::mojom::
+      HeapProfiler::DumpProcessesForTracingCallback;
+
  public:
   ProfilingService();
   ~ProfilingService() override;
@@ -45,28 +49,36 @@
                           mojo::ScopedHandle memlog_pipe_receiver,
                           mojom::ProcessType process_type,
                           mojom::ProfilingParamsPtr params) override;
-  void DumpProcessesForTracing(
-      bool keep_small_allocations,
-      bool strip_path_from_mapped_files,
-      DumpProcessesForTracingCallback callback) override;
+  void SetKeepSmallAllocations(bool keep_small_allocations) override;
   void GetProfiledPids(GetProfiledPidsCallback callback) override;
 
+  // HeapProfiler implementation.
+  void DumpProcessesForTracing(
+      bool strip_path_from_mapped_files,
+      const DumpProcessesForTracingCallback& callback) override;
+
  private:
   void OnProfilingServiceRequest(
       mojom::ProfilingServiceRequest request);
+  void OnHeapProfilerRequest(
+      memory_instrumentation::mojom::HeapProfilerRequest request);
 
   void OnGetVmRegionsCompleteForDumpProcessesForTracing(
-      bool keep_small_allocations,
       bool strip_path_from_mapped_files,
-      mojom::ProfilingService::DumpProcessesForTracingCallback callback,
+      const DumpProcessesForTracingCallback& callback,
       VmRegions vm_regions);
 
   service_manager::BinderRegistry registry_;
   mojo::Binding<mojom::ProfilingService> binding_;
 
+  mojo::Binding<memory_instrumentation::mojom::HeapProfiler>
+      heap_profiler_binding_;
+
   memory_instrumentation::mojom::HeapProfilerHelperPtr helper_;
   MemlogConnectionManager connection_manager_;
 
+  bool keep_small_allocations_ = false;
+
   // Must be last.
   base::WeakPtrFactory<ProfilingService> weak_factory_;
 };
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn
index 7ef42ad..1a32e19 100644
--- a/chrome/test/BUILD.gn
+++ b/chrome/test/BUILD.gn
@@ -792,7 +792,7 @@
       "../browser/ui/search/local_ntp_test_utils.cc",
       "../browser/ui/search/local_ntp_test_utils.h",
       "../browser/ui/search/local_ntp_voice_search_browsertest.cc",
-      "../browser/ui/search/new_tab_page_interceptor_browsertest.cc",
+      "../browser/ui/search/new_tab_page_navigation_throttle_browsertest.cc",
       "../browser/ui/search_engines/search_engine_tab_helper_browsertest.cc",
       "../browser/ui/settings_window_manager_browsertest_chromeos.cc",
       "../browser/ui/startup/startup_browser_creator_browsertest.cc",
@@ -3067,7 +3067,10 @@
       "../common/media_router/mojo/media_router_struct_traits_unittest.cc",
       "../common/media_router/providers/cast/cast_media_source_unittest.cc",
     ]
-    deps += [ "//components/bubble:test_support" ]
+    deps += [
+      "//components/bubble:test_support",
+      "//services/network:test_support",
+    ]
 
     if (include_js_tests) {
       deps += [ "//chrome/test/data/webui:unit_tests_js" ]
diff --git a/chrome/test/data/extensions/api_test/content_scripts/ntp/background.js b/chrome/test/data/extensions/api_test/content_scripts/ntp/background.js
index b1f8ea2..d31eb37 100644
--- a/chrome/test/data/extensions/api_test/content_scripts/ntp/background.js
+++ b/chrome/test/data/extensions/api_test/content_scripts/ntp/background.js
@@ -2,12 +2,20 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+var newTabUrls = [
+  'chrome://newtab/',
+  // The tab URL will be redirected to the Local New Tab Page if
+  // features::kUseGoogleLocalNtp is not enabled.
+  'chrome-search://local-ntp/local-ntp.html',
+];
+
 function testExecuteScriptInNewTab() {
   // Create a new tab to chrome://newtab and wait for the loading to complete.
   // Then, try to inject a script into that tab. The injection should fail.
   chrome.tabs.onUpdated.addListener(function listener(tabId, changeInfo, tab) {
-    if (tab.url != 'chrome://newtab/' || changeInfo.status != 'complete')
+    if (!newTabUrls.includes(tab.url) || changeInfo.status != 'complete') {
       return;
+    }
     chrome.tabs.onUpdated.removeListener(listener);
     chrome.tabs.executeScript(tab.id, {file: 'script.js'}, function() {
       chrome.test.assertTrue(!!chrome.runtime.lastError);
diff --git a/chrome/test/data/extensions/api_test/tabs/basics/crud2.js b/chrome/test/data/extensions/api_test/tabs/basics/crud2.js
index 09fa0cb..d0f37879 100644
--- a/chrome/test/data/extensions/api_test/tabs/basics/crud2.js
+++ b/chrome/test/data/extensions/api_test/tabs/basics/crud2.js
@@ -2,6 +2,13 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+var newTabUrls = [
+  'chrome://newtab/',
+  // The tab URL will be redirected to the Local New Tab Page if
+  // features::kUseGoogleLocalNtp is not enabled.
+  'chrome-search://local-ntp/local-ntp.html',
+];
+
 var secondWindowId;
 var thirdWindowId;
 var testTabId;
@@ -39,7 +46,7 @@
         assertEq((i == 0), tabs[i].active && tabs[i].selected);
       }
       assertEq("about:blank", tabs[0].url);
-      assertEq("chrome://newtab/", tabs[1].url);
+      assertTrue(newTabUrls.includes(tabs[1].url));
       assertEq(pageUrl("a"), tabs[2].url);
     }));
 
@@ -50,7 +57,7 @@
         assertEq(thirdWindowId, tabs[i].windowId);
         assertEq(i, tabs[i].index);
       }
-      assertEq("chrome://newtab/", tabs[0].url);
+      assertTrue(newTabUrls.includes(tabs[0].url));
       assertEq(pageUrl("b"), tabs[1].url);
     }));
   },
diff --git a/chrome/test/data/extensions/api_test/tabs/basics/move.js b/chrome/test/data/extensions/api_test/tabs/basics/move.js
index aefe426..e64c15f21 100644
--- a/chrome/test/data/extensions/api_test/tabs/basics/move.js
+++ b/chrome/test/data/extensions/api_test/tabs/basics/move.js
@@ -7,6 +7,13 @@
 var moveTabIds = {};
 var kChromeUINewTabURL = "chrome://newtab/";
 
+var newTabUrls = [
+  kChromeUINewTabURL,
+  // The tab URL will be redirected to the Local New Tab Page if
+  // features::kUseGoogleLocalNtp is not enabled.
+  'chrome-search://local-ntp/local-ntp.html',
+];
+
 chrome.test.runTests([
   // Do a series of moves and removes so that we get the following
   //
@@ -32,7 +39,8 @@
       }));
       chrome.tabs.getAllInWindow(firstWindowId, pass(function(tabs) {
         assertEq(pages.length, tabs.length);
-        for (var i in tabs) {
+        assertTrue(newTabUrls.includes(tabs[0].url));
+        for (var i = 1; i < tabs.length; i++) {
           assertEq(pages[i], tabs[i].url);
         }
       }));
@@ -44,7 +52,7 @@
     function checkMoveResults() {
       chrome.tabs.getAllInWindow(firstWindowId, pass(function(tabs) {
         assertEq(4, tabs.length);
-        assertEq(kChromeUINewTabURL, tabs[0].url);
+        assertTrue(newTabUrls.includes(tabs[0].url));
         assertEq(pageUrl("a"), tabs[1].url);
         assertEq(pageUrl("e"), tabs[2].url);
         assertEq(pageUrl("c"), tabs[3].url);
@@ -52,7 +60,7 @@
         chrome.tabs.getAllInWindow(secondWindowId, pass(function(tabs) {
           assertEq(3, tabs.length);
           assertEq(pageUrl("b"), tabs[0].url);
-          assertEq(kChromeUINewTabURL, tabs[1].url);
+          assertTrue(newTabUrls.includes(tabs[1].url));
           assertEq(pageUrl("d"), tabs[2].url);
         }));
       }));
@@ -78,14 +86,14 @@
     function checkMoveResults() {
       chrome.tabs.getAllInWindow(firstWindowId, pass(function(tabs) {
         assertEq(3, tabs.length);
-        assertEq(kChromeUINewTabURL, tabs[0].url);
+        assertTrue(newTabUrls.includes(tabs[0].url));
         assertEq(pageUrl("a"), tabs[1].url);
         assertEq(pageUrl("c"), tabs[2].url);
 
         chrome.tabs.getAllInWindow(secondWindowId, pass(function(tabs) {
           assertEq(4, tabs.length);
           assertEq(pageUrl("b"), tabs[0].url);
-          assertEq(kChromeUINewTabURL, tabs[1].url);
+          assertTrue(newTabUrls.includes(tabs[1].url));
           assertEq(pageUrl("d"), tabs[2].url);
           assertEq(pageUrl("e"), tabs[3].url);
         }));
@@ -106,7 +114,7 @@
                                  pass(function(tabs) {
         assertEq(3, tabs.length);
         assertEq(pageUrl("b"), tabs[0].url);
-        assertEq(kChromeUINewTabURL, tabs[1].url);
+        assertTrue(newTabUrls.includes(tabs[1].url));
         assertEq(pageUrl("e"), tabs[2].url);
       }));
     }));
@@ -135,7 +143,7 @@
         assertEq(3, tabs.length);
         assertEq(pageUrl("b"), tabs[0].url);
         assertEq(pageUrl("a"), tabs[1].url);
-        assertEq(kChromeUINewTabURL, tabs[2].url);
+        assertTrue(newTabUrls.includes(tabs[2].url));
       }));
     }));
   },
diff --git a/chrome/test/data/extensions/api_test/tabs/on_updated/test.js b/chrome/test/data/extensions/api_test/tabs/on_updated/test.js
index 7fcd443f..0399058 100644
--- a/chrome/test/data/extensions/api_test/tabs/on_updated/test.js
+++ b/chrome/test/data/extensions/api_test/tabs/on_updated/test.js
@@ -47,19 +47,15 @@
     chrome.tabs.create({ url: getURL('browserThenRendererInitiated/a.html') });
   },
 
-  function newTab() {
+  function chromeUrls() {
     // Test for crbug.com/27208.
-    //
-    // Note the two title settings. That is expected and due to the unusual way
-    // the NTP code ensures a set title.
     expect([
-      { status: 'loading', url: 'chrome://newtab/' },
-      { title : "New Tab" },
-      { title : "New Tab" },
+      { status: 'loading', url: 'chrome://chrome-urls/' },
+      { title : "Chrome URLs" },
       { status: 'complete' }
     ]);
 
-    chrome.tabs.create({ url: 'chrome://newtab/' });
+    chrome.tabs.create({ url: 'chrome://chrome-urls/' });
   },
 
   /*
diff --git a/chrome/test/data/page_load_metrics/use_counter_features.html b/chrome/test/data/page_load_metrics/use_counter_features.html
index 9980e16..82583b6 100644
--- a/chrome/test/data/page_load_metrics/use_counter_features.html
+++ b/chrome/test/data/page_load_metrics/use_counter_features.html
@@ -14,5 +14,8 @@
     navigator.vibrate(10);
   }
   </script>
+  <img src="http://example.test"/>
+  <audio controls><source src="http://example.test" type="audio/mpeg"></audio>
+  <video controls><source src="http://example.test" type="video/mp4"></video>
   </body>
 </html>
diff --git a/chrome/test/data/vr/e2e_test_files/html/test_non_exclusive_stops_during_exclusive.html b/chrome/test/data/vr/e2e_test_files/html/test_non_exclusive_stops_during_exclusive.html
deleted file mode 100644
index b9acb20..0000000
--- a/chrome/test/data/vr/e2e_test_files/html/test_non_exclusive_stops_during_exclusive.html
+++ /dev/null
@@ -1,57 +0,0 @@
-<!doctype html>
-<!--
-Tests that a non-exclusive session's rAF stops firing when an exclusive session
-is active, but resumes afterwards.
--->
-<html>
-  <head>
-    <link rel="stylesheet" type="text/css" href="../resources/webxr_e2e.css">
-  </head>
-  <body>
-    <canvas id="webgl-canvas"></canvas>
-    <script src="../../../../../../third_party/WebKit/LayoutTests/resources/testharness.js"></script>
-    <script src="../resources/webxr_e2e.js"></script>
-    <script src="../resources/webxr_boilerplate.js"></script>
-    <script>
-      var t = async_test("Non-exclusive rAF stops during exclusive session");
-      let counter = 0;
-
-      function stepBeforeExclusive() {
-        onMagicWindowXRFrameCallback = function() {
-          // Verify that we call a rAF once, then make sure any subsequent calls
-          // are not done while there is an exclusive session.
-          onMagicWindowXRFrameCallback = function() {
-            if (exclusiveSession !== null) {
-              t.step( () => {
-                assert_unreached(
-                    "Non-exclusive rAF called during exclusive session");
-              });
-            }
-          }
-          finishJavaScriptStep();
-        };
-      }
-
-      function stepDuringExclusive() {
-        // Let the exclusive session run for a bit so the non-exclusive rAF
-        // can fire if it's going to.
-        onExclusiveXRFrameCallback = function() {
-          if (counter < 10) {
-            counter++;
-            return;
-          }
-
-          onExclusiveXRFrameCallback = null;
-          finishJavaScriptStep();
-        };
-      }
-
-      function stepAfterExclusive() {
-        // Make sure we fire at least once after exiting the exclusive session
-        onMagicWindowXRFrameCallback = function() {
-          t.done();
-        };
-      }
-    </script>
-  </body>
-</html>
diff --git a/chrome/test/data/vr/e2e_test_files/html/test_webxr_capabilities.html b/chrome/test/data/vr/e2e_test_files/html/test_webxr_capabilities.html
deleted file mode 100644
index 841cdad..0000000
--- a/chrome/test/data/vr/e2e_test_files/html/test_webxr_capabilities.html
+++ /dev/null
@@ -1,64 +0,0 @@
-<!doctype html>
-<!--
-Tests that the provided WebXR device has the expected capabilities
--->
-<html>
-  <head>
-    <link rel="stylesheet" type="text/css" href="../resources/webxr_e2e.css">
-  </head>
-  <body>
-    <canvas id="webgl-canvas"></canvas>
-    <script src="../../../../../../third_party/WebKit/LayoutTests/resources/testharness.js"></script>
-    <script src="../resources/webxr_e2e.js"></script>
-    <script src="../resources/webxr_boilerplate.js"></script>
-    <script>
-      var expectations = {
-        "Daydream": {
-          "external": false,
-          "exclusive": true,
-          "non-exclusive": true,
-        }
-      };
-      var t = async_test("XRDevice capabilities match expectations");
-
-      function stepCheckCapabilities(device) {
-        if (!(device in expectations)) {
-          t.step_func_done( () => {
-            assert_unreached("Given device " + device + " not in expectations");
-          })();
-          return;
-        }
-
-        let expected = expectations[device];
-        t.step( () => {
-          assert_equals(xrDevice.external, expected["external"],
-              'Device has external display');
-        });
-
-        var supportsNonExclusive;
-        var supportsExclusive;
-        var ctx = webglCanvas.getContext("xrpresent");
-        xrDevice.supportsSession(
-            {exclusive: false, outputContext: ctx}).then( () => {
-          supportsNonExclusive = true;
-        }, () => {
-          supportsNonExclusive = false;
-        }).then( () => {
-          xrDevice.supportsSession({exclusive: true}).then( () => {
-            supportsExclusive = true;
-          }, () => {
-            supportsExclusive = false;
-          }).then( () => {
-            t.step( () => {
-              assert_equals(supportsNonExclusive, expected["non-exclusive"],
-                  'Device supports non-exclusive sessions');
-              assert_equals(supportsExclusive, expected["exclusive"],
-                  'Device supports exclusive sessions');
-            });
-            t.done();
-          });
-        });
-      }
-    </script>
-  </body>
-</html>
diff --git a/chrome/test/data/vr/e2e_test_files/html/test_window_raf_fires_during_non_exclusive_session.html b/chrome/test/data/vr/e2e_test_files/html/test_window_raf_fires_during_non_exclusive_session.html
deleted file mode 100644
index 6161848..0000000
--- a/chrome/test/data/vr/e2e_test_files/html/test_window_raf_fires_during_non_exclusive_session.html
+++ /dev/null
@@ -1,24 +0,0 @@
-<!doctype html>
-<!--
-Tests that window.rAF continues to fire during a non-exclusive session.
--->
-<html>
-  <head>
-    <link rel="stylesheet" type="text/css" href="../resources/webxr_e2e.css">
-  </head>
-  <body>
-    <canvas id="webgl-canvas"></canvas>
-    <script src="../../../../../../third_party/WebKit/LayoutTests/resources/testharness.js"></script>
-    <script src="../resources/webxr_e2e.js"></script>
-    <script src="../resources/webxr_boilerplate.js"></script>
-    <script>
-      var t = async_test("window.rAF fires during a non-exclusive session");
-
-      onMagicWindowXRFrameCallback = function() {
-        window.requestAnimationFrame( () => {
-          t.done();
-        });
-      }
-    </script>
-  </body>
-</html>
diff --git a/chrome/test/data/vr/e2e_test_files/html/webxr_test_pose_data_unfocused_tab.html b/chrome/test/data/vr/e2e_test_files/html/webxr_test_pose_data_unfocused_tab.html
deleted file mode 100644
index 35f18c1..0000000
--- a/chrome/test/data/vr/e2e_test_files/html/webxr_test_pose_data_unfocused_tab.html
+++ /dev/null
@@ -1,56 +0,0 @@
-<!doctype html>
-<!--
-Tests that WebXR doesn't update frame data when the tab is not focused
--->
-<html>
-  <head>
-    <link rel="stylesheet" type="text/css" href="../resources/webxr_e2e.css">
-  </head>
-  <body>
-    <canvas id="webgl-canvas"></canvas>
-    <script src="../../../../../../third_party/WebKit/LayoutTests/resources/testharness.js"></script>
-    <script src="../resources/webxr_e2e.js"></script>
-    <script src="../resources/webxr_boilerplate.js"></script>
-    <script>
-      var t = async_test("Test pose data in unfocused tab");
-      var pose = null;
-      let counter = 0;
-
-      function stepCheckFrameDataWhileFocusedTab() {
-        function onAnimationFrame(session, frame) {
-          // TODO(bsheedy): This is a workaround for crbug.com/787196. Either
-          // remove the workaround once fixed or remove this todo.
-          // Let several animation frames get triggered so we're sure to have a
-          // pose
-          if (counter <= 2) {
-            counter++;
-            return;
-          }
-          onMagicWindowXRFrameCallback = null;
-          pose = frame.getDevicePose(magicWindowFrameOfRef);
-          t.step( () => {
-            assert_true(pose != null,
-                "getDevicePose returned a non-null object");
-            assert_true(pose instanceof XRDevicePose,
-                "getDevicePose returned an XRDevicePose")
-          });
-          finishJavaScriptStep();
-        }
-        // Make sure at least one rAF call has happened so we get valid data
-        onMagicWindowXRFrameCallback = onAnimationFrame;
-      }
-
-      function stepCheckFrameDataWhileNonFocusedTab() {
-        // Unlike WebVR, WebXR doesn't fire rAFs when in a different tab
-        onMagicWindowXRFrameCallback = function() {
-          t.step( () => {
-            assert_unreached("Magic window fired rAF while in a different tab");
-          });
-        }
-        window.setTimeout( () => {
-          t.done();
-        }, 1000);
-      }
-    </script>
-  </body>
-</html>
diff --git a/chrome/test/data/vr/e2e_test_files/resources/webxr_boilerplate.js b/chrome/test/data/vr/e2e_test_files/resources/webxr_boilerplate.js
index 981712d..baa0f1e 100644
--- a/chrome/test/data/vr/e2e_test_files/resources/webxr_boilerplate.js
+++ b/chrome/test/data/vr/e2e_test_files/resources/webxr_boilerplate.js
@@ -49,7 +49,6 @@
     gl.clearColor(0.0, 1.0, 0.0, 1.0);
     gl.enable(gl.DEPTH_TEST);
     gl.enable(gl.CULL_FACE);
-    gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
   }
 
   session.baseLayer = new XRWebGLLayer(session, gl);
@@ -89,14 +88,14 @@
   // If in an exclusive session, set canvas to blue. Otherwise, red.
   if (session.exclusive) {
     if (onExclusiveXRFrameCallback) {
-      onExclusiveXRFrameCallback(session, frame);
+      onExclusiveXRFrameCallback(session);
     }
     gl.clearColor(0.0, 0.0, 1.0, 1.0);
   } else {
     if (onMagicWindowXRFrameCallback) {
-      onMagicWindowXRFrameCallback(session, frame);
+      onMagicWindowXRFrameCallback(session);
     }
-    gl.clearColor(1.0, 0.0, 0.0, 1.0);
+    gl.clearcolor(1.0, 0.0, 0.0, 1.0);
   }
   gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
 }
@@ -111,11 +110,14 @@
     // Set up the device to have a non-exclusive session (magic window) drawing
     // into the full screen canvas on the page
     let ctx = webglCanvas.getContext('xrpresent');
-    device.requestSession({outputContext: ctx}).then( (session) => {
+    // TODO(bsheedy): Enable and test this once non-exclusive session support
+    // is actually added to the implementation.
+    /*device.requestSession({outputContext: ctx}).then( (session) => {
       onSessionStarted(session);
     }).then( () => {
       initializationSteps['magicWindowStarted'] = true;
-    });
+    });*/
+    initializationSteps['magicWindowStarted'] = true;
   }).then( () => {
     initializationSteps['getXRDevice'] = true;
   });
diff --git a/chrome/test/data/webui/settings/cr_settings_browsertest.js b/chrome/test/data/webui/settings/cr_settings_browsertest.js
index 9d89cb9ce..8aa4cccf 100644
--- a/chrome/test/data/webui/settings/cr_settings_browsertest.js
+++ b/chrome/test/data/webui/settings/cr_settings_browsertest.js
@@ -415,6 +415,7 @@
   /** @override */
   extraLibraries: CrSettingsBrowserTest.prototype.extraLibraries.concat([
     '../test_browser_proxy.js',
+    'sync_test_util.js',
     'test_profile_info_browser_proxy.js',
     'test_sync_browser_proxy.js',
     'people_page_test.js',
@@ -425,6 +426,36 @@
   mocha.run();
 });
 
+GEN('#if !defined(OS_CHROMEOS)');
+/**
+ * Test fixture for
+ * chrome/browser/resources/settings/people_page/sync_account_control.html.
+ * @constructor
+ * @extends {CrSettingsBrowserTest}
+ */
+function CrSettingsPeoplePageSyncAccountControlTest() {}
+
+CrSettingsPeoplePageSyncAccountControlTest.prototype = {
+  __proto__: CrSettingsBrowserTest.prototype,
+
+  /** @override */
+  browsePreload: 'chrome://settings/people_page/sync_account_control.html',
+
+  /** @override */
+  extraLibraries: CrSettingsBrowserTest.prototype.extraLibraries.concat([
+    '../test_browser_proxy.js',
+    'sync_test_util.js',
+    'test_sync_browser_proxy.js',
+    'sync_account_control_test.js',
+  ]),
+};
+
+TEST_F('CrSettingsPeoplePageSyncAccountControlTest', 'All', function() {
+  mocha.run();
+});
+
+GEN('#endif  // !defined(OS_CHROMEOS)');
+
 /**
  * Test fixture for
  * chrome/browser/resources/settings/people_page/sync_page.html.
diff --git a/chrome/test/data/webui/settings/people_page_test.js b/chrome/test/data/webui/settings/people_page_test.js
index 95c45cd..7e6dcf8f 100644
--- a/chrome/test/data/webui/settings/people_page_test.js
+++ b/chrome/test/data/webui/settings/people_page_test.js
@@ -125,11 +125,10 @@
         }).then(function(deleteProfile) {
           assertFalse(deleteProfile);
 
-          cr.webUIListenerCallback('sync-status-changed', {
+          sync_test_util.simulateSyncStatus({
             signedIn: true,
             domain: 'example.com',
           });
-          Polymer.dom.flush();
 
           assertFalse(!!peoplePage.$$('#disconnectDialog'));
           MockInteractions.tap(disconnectButton);
@@ -246,7 +245,7 @@
                 listenOnce(window, 'popstate', resolve);
               });
 
-              cr.webUIListenerCallback('sync-status-changed', {
+              sync_test_util.simulateSyncStatus({
                 signedIn: false,
               });
 
@@ -267,7 +266,7 @@
         assertFalse(!!peoplePage.$$('#sync-status'));
 
         return browserProxy.whenCalled('getSyncStatus').then(function() {
-          cr.webUIListenerCallback('sync-status-changed', {
+          sync_test_util.simulateSyncStatus({
             signedIn: true,
             syncSystemEnabled: true,
           });
@@ -277,7 +276,7 @@
           assertTrue(!!syncStatusContainer);
           assertTrue(syncStatusContainer.hasAttribute('actionable'));
 
-          cr.webUIListenerCallback('sync-status-changed', {
+          sync_test_util.simulateSyncStatus({
             managed: true,
             signedIn: true,
             syncSystemEnabled: true,
@@ -294,7 +293,7 @@
         assertFalse(!!peoplePage.$$('#sync-status'));
 
         return browserProxy.whenCalled('getSyncStatus').then(function() {
-          cr.webUIListenerCallback('sync-status-changed', {
+          sync_test_util.simulateSyncStatus({
             hasError: true,
             statusAction: settings.StatusAction.NO_ACTION,
             signedIn: true,
@@ -306,7 +305,7 @@
           assertTrue(!!syncStatusContainer);
           assertFalse(syncStatusContainer.hasAttribute('actionable'));
 
-          cr.webUIListenerCallback('sync-status-changed', {
+          sync_test_util.simulateSyncStatus({
             hasError: true,
             statusAction: settings.StatusAction.UPGRADE_CLIENT,
             signedIn: true,
@@ -352,8 +351,41 @@
         peoplePage.remove();
       });
 
-      test('ManageProfileRow', function() {
-        assertTrue(!!peoplePage.$$('#edit-profile'));
+      test('ShowCorrectRows', function() {
+        return browserProxy.whenCalled('getSyncStatus').then(function() {
+          // The correct /manageProfile link row is shown.
+          assertTrue(!!peoplePage.$$('#edit-profile'));
+          assertFalse(!!peoplePage.$$('#picture-subpage-trigger'));
+
+          // Sync-overview row should not exist when diceEnabled is true, even
+          // if syncStatus values would've warranted the row otherwise.
+          sync_test_util.simulateSyncStatus({
+            signedIn: false,
+            signinAllowed: true,
+            syncSystemEnabled: true,
+          });
+          assertFalse(!!peoplePage.$$('#sync-overview'));
+
+          // The control element should exist when policy allows.
+          const accountControl = peoplePage.$$('settings-sync-account-control');
+          assertTrue(
+              window.getComputedStyle(accountControl)['display'] != 'none');
+
+          // Control element doesn't exist when policy forbids sync or sign-in.
+          sync_test_util.simulateSyncStatus({
+            signinAllowed: false,
+            syncSystemEnabled: true,
+          });
+          assertEquals(
+              window.getComputedStyle(accountControl)['display'], 'none');
+
+          sync_test_util.simulateSyncStatus({
+            signinAllowed: true,
+            syncSystemEnabled: false,
+          });
+          assertEquals(
+              window.getComputedStyle(accountControl)['display'], 'none');
+        });
       });
     });
   }
diff --git a/chrome/test/data/webui/settings/sync_account_control_test.js b/chrome/test/data/webui/settings/sync_account_control_test.js
new file mode 100644
index 0000000..3c22e2a
--- /dev/null
+++ b/chrome/test/data/webui/settings/sync_account_control_test.js
@@ -0,0 +1,225 @@
+// 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.
+
+cr.define('settings_sync_account_control', function() {
+  /**
+   * @param {!Element} element
+   * @param {boolean} displayed
+   */
+  function assertVisible(element, displayed) {
+    assertEquals(
+        displayed, window.getComputedStyle(element)['display'] != 'none');
+  }
+
+  suite('SyncAccountControl', function() {
+    let peoplePage = null;
+    let browserProxy = null;
+    let testElement = null;
+
+    /**
+     * @param {number} count
+     * @param {boolean} signedIn
+     */
+    function forcePromoResetWithCount(count, signedIn) {
+      browserProxy.setImpressionCount(count);
+      // Flipping syncStatus.signedIn will force promo state to be reset.
+      sync_test_util.simulateSyncStatus({
+        signedIn: !signedIn,
+      });
+      sync_test_util.simulateSyncStatus({
+        signedIn: signedIn,
+      });
+    }
+
+    suiteSetup(function() {
+      // Force UIs to think DICE is enabled for this profile.
+      loadTimeData.overrideValues({
+        diceEnabled: true,
+      });
+    });
+
+    setup(function() {
+      browserProxy = new TestSyncBrowserProxy();
+      settings.SyncBrowserProxyImpl.instance_ = browserProxy;
+
+      PolymerTest.clearBody();
+      testElement = document.createElement('settings-sync-account-control');
+      document.body.appendChild(testElement);
+
+      Polymer.dom.flush();
+
+      return Promise.all([
+        browserProxy.whenCalled('getSyncStatus'),
+        browserProxy.whenCalled('getStoredAccounts'),
+      ]);
+    });
+
+    teardown(function() {
+      testElement.remove();
+    });
+
+    test('promo shows/hides in the right states', function() {
+      // Not signed in, no accounts, will show banner.
+      sync_test_util.simulateStoredAccounts([]);
+      forcePromoResetWithCount(0, false);
+      const banner = testElement.$$('#banner');
+      assertVisible(banner, true);
+      // Flipping signedIn in forcePromoResetWithCount should increment count.
+      return browserProxy.whenCalled('incrementPromoImpressionCount')
+          .then(() => {
+            forcePromoResetWithCount(
+                settings.MAX_SIGNIN_PROMO_IMPRESSION + 1, false);
+            assertVisible(banner, false);
+
+            // Not signed in, has accounts, will show banner.
+            sync_test_util.simulateStoredAccounts([{email: 'foo@foo.com'}]);
+            forcePromoResetWithCount(0, false);
+            assertVisible(banner, true);
+            forcePromoResetWithCount(
+                settings.MAX_SIGNIN_PROMO_IMPRESSION + 1, false);
+            assertVisible(banner, false);
+
+            // signed in, banners never show.
+            sync_test_util.simulateStoredAccounts([{email: 'foo@foo.com'}]);
+            forcePromoResetWithCount(0, true);
+            assertVisible(banner, false);
+            forcePromoResetWithCount(
+                settings.MAX_SIGNIN_PROMO_IMPRESSION + 1, true);
+            assertVisible(banner, false);
+          });
+    });
+
+    test('not signed in and no stored accounts', function() {
+      sync_test_util.simulateSyncStatus(
+          {signedIn: false, signedInUsername: ''});
+      sync_test_util.simulateStoredAccounts([]);
+
+      assertVisible(testElement.$$('#promo-headers'), true);
+      assertVisible(testElement.$$('#avatar-row'), false);
+      assertVisible(testElement.$$('#menu'), false);
+      assertVisible(testElement.$$('#sign-in'), true);
+
+      testElement.$$('#sign-in').click();
+      return browserProxy.whenCalled('startSignIn');
+    });
+
+    test('not signed in but has stored accounts', function() {
+      sync_test_util.simulateSyncStatus(
+          {signedIn: false, signedInUsername: ''});
+      sync_test_util.simulateStoredAccounts([
+        {
+          fullName: 'fooName',
+          email: 'foo@foo.com',
+        },
+        {
+          fullName: 'barName',
+          email: 'bar@bar.com',
+        },
+      ]);
+
+      const userInfo = testElement.$$('#user-info');
+      const syncButton = testElement.$$('#avatar-row .action-button');
+
+      // Avatar row shows the right account.
+      assertVisible(testElement.$$('#promo-headers'), true);
+      assertVisible(testElement.$$('#avatar-row'), true);
+      assertTrue(userInfo.textContent.includes('fooName'));
+      assertTrue(userInfo.textContent.includes('foo@foo.com'));
+      assertFalse(userInfo.textContent.includes('barName'));
+      assertFalse(userInfo.textContent.includes('bar@bar.com'));
+
+      // Menu contains the right items.
+      assertTrue(!!testElement.$$('#menu'));
+      assertFalse(testElement.$$('#menu').open);
+      const items = testElement.root.querySelectorAll('.dropdown-item');
+      assertEquals(3, items.length);
+      assertTrue(items[0].textContent.includes('foo@foo.com'));
+      assertTrue(items[1].textContent.includes('bar@bar.com'));
+      assertEquals(items[2].id, 'sign-in-item');
+
+      // "sync to" button is showing the correct name and syncs with the
+      // correct account when clicked.
+      assertVisible(syncButton, true);
+      assertVisible(testElement.$$('#avatar-row .secondary-button'), false);
+      assertTrue(syncButton.textContent.includes('fooName'));
+      assertFalse(syncButton.textContent.includes('barName'));
+      syncButton.click();
+      Polymer.dom.flush();
+
+      return browserProxy.whenCalled('startSyncingWithEmail')
+          .then(email => {
+            assertEquals(email, 'foo@foo.com');
+
+            assertVisible(testElement.$$('#dropdown-arrow'), true);
+            assertFalse(
+                testElement.$$('#sync-logo-container').hasAttribute('syncing'));
+
+            testElement.$$('#dropdown-arrow').click();
+            Polymer.dom.flush();
+            assertTrue(testElement.$$('#menu').open);
+
+            // Switching selected account will update UI with the right name and
+            // email.
+            items[1].click();
+            Polymer.dom.flush();
+            assertFalse(userInfo.textContent.includes('fooName'));
+            assertFalse(userInfo.textContent.includes('foo@foo.com'));
+            assertTrue(userInfo.textContent.includes('barName'));
+            assertTrue(userInfo.textContent.includes('bar@bar.com'));
+            assertVisible(syncButton, true);
+            assertTrue(syncButton.textContent.includes('barName'));
+            assertFalse(syncButton.textContent.includes('fooName'));
+
+            browserProxy.resetResolver('startSyncingWithEmail');
+            syncButton.click();
+            Polymer.dom.flush();
+
+            return browserProxy.whenCalled('startSyncingWithEmail');
+          })
+          .then(email => {
+            assertEquals(email, 'bar@bar.com');
+
+            // Tapping the last menu item will initiate sign-in.
+            items[2].click();
+            return browserProxy.whenCalled('startSignIn');
+          });
+    });
+
+    test('signed in', function() {
+      sync_test_util.simulateSyncStatus(
+          {signedIn: true, signedInUsername: 'bar@bar.com'});
+      sync_test_util.simulateStoredAccounts([
+        {
+          fullName: 'fooName',
+          email: 'foo@foo.com',
+        },
+        {
+          fullName: 'barName',
+          email: 'bar@bar.com',
+        },
+      ]);
+
+      assertVisible(testElement.$$('#avatar-row'), true);
+      assertVisible(testElement.$$('#dropdown-arrow'), false);
+      assertVisible(testElement.$$('#promo-headers'), false);
+      assertTrue(
+          testElement.$$('#sync-logo-container').hasAttribute('syncing'));
+      assertFalse(!!testElement.$$('#menu'));
+
+      const userInfo = testElement.$$('#user-info');
+      assertTrue(userInfo.textContent.includes('barName'));
+      assertTrue(userInfo.textContent.includes('bar@bar.com'));
+      assertFalse(userInfo.textContent.includes('fooName'));
+      assertFalse(userInfo.textContent.includes('foo@foo.com'));
+
+      assertVisible(testElement.$$('#avatar-row .action-button'), false);
+      assertVisible(testElement.$$('#avatar-row .secondary-button'), true);
+
+      testElement.$$('#avatar-row .secondary-button').click();
+      Polymer.dom.flush();
+
+      assertEquals(settings.getCurrentRoute(), settings.routes.SIGN_OUT);
+    });
+  });
+});
diff --git a/chrome/test/data/webui/settings/sync_test_util.js b/chrome/test/data/webui/settings/sync_test_util.js
new file mode 100644
index 0000000..a86f77d
--- /dev/null
+++ b/chrome/test/data/webui/settings/sync_test_util.js
@@ -0,0 +1,22 @@
+// 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.
+
+cr.define('sync_test_util', function() {
+  /** @param {!settings.SyncStatus} */
+  function simulateSyncStatus(status) {
+    cr.webUIListenerCallback('sync-status-changed', status);
+    Polymer.dom.flush();
+  }
+
+  /** @param {Array<!settings.StoredAccount>} */
+  function simulateStoredAccounts(accounts) {
+    cr.webUIListenerCallback('stored-accounts-updated', accounts);
+    Polymer.dom.flush();
+  }
+
+  return {
+    simulateSyncStatus: simulateSyncStatus,
+    simulateStoredAccounts: simulateStoredAccounts,
+  };
+});
\ No newline at end of file
diff --git a/chrome/test/data/webui/settings/test_sync_browser_proxy.js b/chrome/test/data/webui/settings/test_sync_browser_proxy.js
index dc2690fb..df36bab 100644
--- a/chrome/test/data/webui/settings/test_sync_browser_proxy.js
+++ b/chrome/test/data/webui/settings/test_sync_browser_proxy.js
@@ -9,7 +9,14 @@
       'getSyncStatus',
       'getStoredAccounts',
       'signOut',
+      'startSignIn',
+      'startSyncingWithEmail',
+      'getPromoImpressionCount',
+      'incrementPromoImpressionCount',
     ]);
+
+    /** @private {number} */
+    this.impressionCount_ = 0;
   }
 
   /** @override */
@@ -31,4 +38,29 @@
   signOut(deleteProfile) {
     this.methodCalled('signOut', deleteProfile);
   }
+
+  /** @override */
+  startSignIn() {
+    this.methodCalled('startSignIn');
+  }
+
+  /** @override */
+  startSyncingWithEmail(email) {
+    this.methodCalled('startSyncingWithEmail', email);
+  }
+
+  setImpressionCount(count) {
+    this.impressionCount_ = count;
+  }
+
+  /** @override */
+  getPromoImpressionCount() {
+    this.methodCalled('getPromoImpressionCount');
+    return this.impressionCount_;
+  }
+
+  /** @override */
+  incrementPromoImpressionCount() {
+    this.methodCalled('incrementPromoImpressionCount');
+  }
 }
\ No newline at end of file
diff --git a/chromecast/browser/android/apk/src/org/chromium/chromecast/shell/CastApplication.java b/chromecast/browser/android/apk/src/org/chromium/chromecast/shell/CastApplication.java
index 165350d..7a844ac 100644
--- a/chromecast/browser/android/apk/src/org/chromium/chromecast/shell/CastApplication.java
+++ b/chromecast/browser/android/apk/src/org/chromium/chromecast/shell/CastApplication.java
@@ -4,10 +4,10 @@
 
 package org.chromium.chromecast.shell;
 
+import android.app.Application;
 import android.content.Context;
 
 import org.chromium.base.ApplicationStatus;
-import org.chromium.base.BaseChromiumApplication;
 import org.chromium.base.CommandLineInitUtil;
 import org.chromium.base.ContextUtils;
 import org.chromium.base.PathUtils;
@@ -20,7 +20,7 @@
  * processes don't need most of the full "setup" performed in CastBrowserHelper.java, but they do
  * require a few basic pieces (found here).
  */
-public class CastApplication extends BaseChromiumApplication {
+public class CastApplication extends Application {
     private static final String TAG = "CastApplication";
 
     private static final String PRIVATE_DATA_DIRECTORY_SUFFIX = "cast_shell";
diff --git a/components/arc/crash_collector/arc_crash_collector_bridge.cc b/components/arc/crash_collector/arc_crash_collector_bridge.cc
index a84bb82..e75aada 100644
--- a/components/arc/crash_collector/arc_crash_collector_bridge.cc
+++ b/components/arc/crash_collector/arc_crash_collector_bridge.cc
@@ -97,7 +97,7 @@
   base::PostTaskWithTraits(
       FROM_HERE, {base::WithBaseSyncPrimitives()},
       base::BindOnce(&RunCrashReporter, type, device_, board_, cpu_abi_,
-                     base::Passed(std::move(pipe_handle))));
+                     std::move(pipe_handle)));
 }
 
 void ArcCrashCollectorBridge::SetBuildProperties(const std::string& device,
diff --git a/components/arc/midis/arc_midis_bridge.cc b/components/arc/midis/arc_midis_bridge.cc
index 657fcc4..2ba7218 100644
--- a/components/arc/midis/arc_midis_bridge.cc
+++ b/components/arc/midis/arc_midis_bridge.cc
@@ -100,9 +100,9 @@
       ->GetArcMidisClient()
       ->BootstrapMojoConnection(
           std::move(fd),
-          base::Bind(&ArcMidisBridge::OnBootstrapMojoConnection,
-                     weak_factory_.GetWeakPtr(), base::Passed(&request),
-                     base::Passed(&client_ptr)));
+          base::BindOnce(&ArcMidisBridge::OnBootstrapMojoConnection,
+                         weak_factory_.GetWeakPtr(), std::move(request),
+                         std::move(client_ptr)));
 }
 
 }  // namespace arc
diff --git a/components/arc/test/fake_file_system_instance.cc b/components/arc/test/fake_file_system_instance.cc
index 8d7420c..e15130b209 100644
--- a/components/arc/test/fake_file_system_instance.cc
+++ b/components/arc/test/fake_file_system_instance.cc
@@ -199,8 +199,7 @@
   auto iter = files_.find(url);
   if (iter == files_.end()) {
     base::ThreadTaskRunnerHandle::Get()->PostTask(
-        FROM_HERE, base::BindOnce(std::move(callback),
-                                  base::Passed(mojo::ScopedHandle())));
+        FROM_HERE, base::BindOnce(std::move(callback), mojo::ScopedHandle()));
     return;
   }
   const File& file = iter->second;
@@ -216,8 +215,8 @@
   DCHECK_EQ(MOJO_RESULT_OK, result);
   base::ThreadTaskRunnerHandle::Get()->PostTask(
       FROM_HERE,
-      base::BindOnce(std::move(callback), base::Passed(mojo::ScopedHandle(
-                                              mojo::Handle(wrapped_handle)))));
+      base::BindOnce(std::move(callback),
+                     mojo::ScopedHandle(mojo::Handle(wrapped_handle))));
 }
 
 void FakeFileSystemInstance::GetDocument(const std::string& authority,
@@ -227,13 +226,12 @@
   auto iter = documents_.find(DocumentKey(authority, document_id));
   if (iter == documents_.end()) {
     base::ThreadTaskRunnerHandle::Get()->PostTask(
-        FROM_HERE, base::BindOnce(std::move(callback),
-                                  base::Passed(mojom::DocumentPtr())));
+        FROM_HERE, base::BindOnce(std::move(callback), mojom::DocumentPtr()));
     return;
   }
   base::ThreadTaskRunnerHandle::Get()->PostTask(
-      FROM_HERE, base::BindOnce(std::move(callback),
-                                base::Passed(MakeDocument(iter->second))));
+      FROM_HERE,
+      base::BindOnce(std::move(callback), MakeDocument(iter->second)));
 }
 
 void FakeFileSystemInstance::GetChildDocuments(
@@ -256,9 +254,8 @@
     children.emplace_back(MakeDocument(doc_iter->second));
   }
   base::ThreadTaskRunnerHandle::Get()->PostTask(
-      FROM_HERE,
-      base::BindOnce(std::move(callback),
-                     base::Passed(base::make_optional(std::move(children)))));
+      FROM_HERE, base::BindOnce(std::move(callback),
+                                base::make_optional(std::move(children))));
 }
 
 void FakeFileSystemInstance::GetRecentDocuments(
diff --git a/components/arc/test/fake_intent_helper_instance.cc b/components/arc/test/fake_intent_helper_instance.cc
index aacb8d1..836cca6 100644
--- a/components/arc/test/fake_intent_helper_instance.cc
+++ b/components/arc/test/fake_intent_helper_instance.cc
@@ -103,8 +103,7 @@
   }
   // Post the reply to run asynchronously to match the real implementation.
   base::ThreadTaskRunnerHandle::Get()->PostTask(
-      FROM_HERE,
-      base::BindOnce(std::move(callback), base::Passed(std::move(handlers))));
+      FROM_HERE, base::BindOnce(std::move(callback), std::move(handlers)));
 }
 
 void FakeIntentHelperInstance::RequestUrlHandlerList(
diff --git a/components/arc/video_accelerator/gpu_arc_video_encode_accelerator.cc b/components/arc/video_accelerator/gpu_arc_video_encode_accelerator.cc
index 2d5e7fb..3b4b47f 100644
--- a/components/arc/video_accelerator/gpu_arc_video_encode_accelerator.cc
+++ b/components/arc/video_accelerator/gpu_arc_video_encode_accelerator.cc
@@ -176,8 +176,8 @@
   // the shared memory as well as notifies |client_| about the end of processing
   // the |frame|.
   frame->AddDestructionObserver(
-      base::Bind(&DropShareMemoryAndVideoFrameDoneNotifier, base::Passed(&shm),
-                 base::Passed(&notifier)));
+      base::BindOnce(&DropShareMemoryAndVideoFrameDoneNotifier, std::move(shm),
+                     std::move(notifier)));
 
   accelerator_->Encode(frame, force_keyframe);
 }
diff --git a/components/bookmarks/browser/bookmark_storage.cc b/components/bookmarks/browser/bookmark_storage.cc
index f440d3c4..7f46d13 100644
--- a/components/bookmarks/browser/bookmark_storage.cc
+++ b/components/bookmarks/browser/bookmark_storage.cc
@@ -114,9 +114,9 @@
                         TimeTicks::Now() - start_time);
   }
 
-  task_runner->PostTask(FROM_HERE,
-                        base::Bind(&BookmarkStorage::OnLoadFinished, storage,
-                                   base::Passed(&details)));
+  task_runner->PostTask(
+      FROM_HERE, base::BindOnce(&BookmarkStorage::OnLoadFinished, storage,
+                                std::move(details)));
 }
 
 }  // namespace
@@ -172,8 +172,8 @@
     const scoped_refptr<base::SequencedTaskRunner>& task_runner) {
   sequenced_task_runner_->PostTask(
       FROM_HERE,
-      base::Bind(&LoadCallback, writer_.path(), weak_factory_.GetWeakPtr(),
-                 base::Passed(&details), base::RetainedRef(task_runner)));
+      base::BindOnce(&LoadCallback, writer_.path(), weak_factory_.GetWeakPtr(),
+                     std::move(details), base::RetainedRef(task_runner)));
 }
 
 void BookmarkStorage::ScheduleSave() {
diff --git a/components/browser_sync/profile_sync_service.cc b/components/browser_sync/profile_sync_service.cc
index c9841ff25..1202561 100644
--- a/components/browser_sync/profile_sync_service.cc
+++ b/components/browser_sync/profile_sync_service.cc
@@ -19,6 +19,7 @@
 #include "base/logging.h"
 #include "base/memory/ref_counted.h"
 #include "base/metrics/histogram.h"
+#include "base/metrics/histogram_macros.h"
 #include "base/single_thread_task_runner.h"
 #include "base/strings/stringprintf.h"
 #include "base/threading/thread_restrictions.h"
diff --git a/components/browser_watcher/window_hang_monitor_win_unittest.cc b/components/browser_watcher/window_hang_monitor_win_unittest.cc
index e5a31bf..9bdedec 100644
--- a/components/browser_watcher/window_hang_monitor_win_unittest.cc
+++ b/components/browser_watcher/window_hang_monitor_win_unittest.cc
@@ -5,6 +5,7 @@
 #include "components/browser_watcher/window_hang_monitor_win.h"
 
 #include <memory>
+#include <utility>
 
 #include "base/base_paths.h"
 #include "base/base_switches.h"
@@ -266,9 +267,9 @@
         base::WaitableEvent::InitialState::NOT_SIGNALED);
     if (!thread_.task_runner()->PostTask(
             FROM_HERE,
-            base::Bind(&HangMonitorThread::StartupOnThread,
-                       base::Unretained(this), base::Passed(std::move(process)),
-                       base::Unretained(&complete)))) {
+            base::BindOnce(&HangMonitorThread::StartupOnThread,
+                           base::Unretained(this), std::move(process),
+                           base::Unretained(&complete)))) {
       return false;
     }
 
diff --git a/components/cast_channel/cast_socket.cc b/components/cast_channel/cast_socket.cc
index d07d822..ccfc004 100644
--- a/components/cast_channel/cast_socket.cc
+++ b/components/cast_channel/cast_socket.cc
@@ -107,9 +107,10 @@
       ready_state_(ReadyState::NONE),
       auth_delegate_(nullptr) {
   DCHECK(open_params.ip_endpoint.address().IsValid());
-  DCHECK(open_params_.net_log);
-  net_log_source_.type = net::NetLogSourceType::SOCKET;
-  net_log_source_.id = open_params_.net_log->NextID();
+  if (open_params_.net_log) {
+    net_log_source_.type = net::NetLogSourceType::SOCKET;
+    net_log_source_.id = open_params_.net_log->NextID();
+  }
 }
 
 CastSocketImpl::~CastSocketImpl() {
diff --git a/components/cdm/browser/media_drm_storage_impl_unittest.cc b/components/cdm/browser/media_drm_storage_impl_unittest.cc
index 786d4e3..1dc150a 100644
--- a/components/cdm/browser/media_drm_storage_impl_unittest.cc
+++ b/components/cdm/browser/media_drm_storage_impl_unittest.cc
@@ -5,6 +5,7 @@
 #include "components/cdm/browser/media_drm_storage_impl.h"
 
 #include <memory>
+#include <utility>
 
 #include "base/run_loop.h"
 #include "base/unguessable_token.h"
@@ -135,7 +136,7 @@
       std::unique_ptr<SessionData> expected_session_data) {
     return base::BindOnce(&MediaDrmStorageImplTest::CheckLoadedSession,
                           base::Unretained(this),
-                          base::Passed(&expected_session_data));
+                          std::move(expected_session_data));
   }
 
   void CheckResult(bool expected_result, bool result) {
diff --git a/components/component_updater/component_installer.cc b/components/component_updater/component_installer.cc
index 6514574..3918172f 100644
--- a/components/component_updater/component_installer.cc
+++ b/components/component_updater/component_installer.cc
@@ -183,7 +183,7 @@
   // returned.
   main_task_runner_->PostTask(
       FROM_HERE, base::BindOnce(&ComponentInstaller::ComponentReady, this,
-                                base::Passed(std::move(manifest))));
+                                std::move(manifest)));
   main_task_runner_->PostTask(FROM_HERE,
                               base::BindOnce(std::move(callback), result));
 }
diff --git a/components/crash/content/browser/crash_handler_host_linux.cc b/components/crash/content/browser/crash_handler_host_linux.cc
index 3480236..1c0fd983 100644
--- a/components/crash/content/browser/crash_handler_host_linux.cc
+++ b/components/crash/content/browser/crash_handler_host_linux.cc
@@ -330,21 +330,16 @@
     LOG(WARNING) << "Could not translate tid, attempt = " << attempt
                  << " retry ...";
     base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
-      FROM_HERE,
-      base::Bind(&CrashHandlerHostLinux::FindCrashingThreadAndDump,
-                 base::Unretained(this),
-                 crashing_pid,
-                 expected_syscall_data,
-                 base::Passed(&crash_context),
-                 base::Passed(&crash_keys),
+        FROM_HERE,
+        base::BindOnce(&CrashHandlerHostLinux::FindCrashingThreadAndDump,
+                       base::Unretained(this), crashing_pid,
+                       expected_syscall_data, std::move(crash_context),
+                       std::move(crash_keys),
 #if defined(ADDRESS_SANITIZER)
-                 base::Passed(&asan_report),
+                       std::move(asan_report),
 #endif
-                 uptime,
-                 oom_size,
-                 signal_fd,
-                 attempt),
-      base::TimeDelta::FromMilliseconds(kRetryIntervalTranslatingTidInMs));
+                       uptime, oom_size, signal_fd, attempt),
+        base::TimeDelta::FromMilliseconds(kRetryIntervalTranslatingTidInMs));
     return;
   }
 
@@ -396,10 +391,10 @@
   blocking_task_runner_->PostTaskAndReply(
       FROM_HERE,
       base::BindOnce(&CrashHandlerHostLinux::WriteDumpFile,
-                     base::Unretained(this), info_ptr,
-                     base::Passed(&crash_context), crashing_pid),
+                     base::Unretained(this), info_ptr, std::move(crash_context),
+                     crashing_pid),
       base::BindOnce(&CrashHandlerHostLinux::QueueCrashDumpTask,
-                     base::Unretained(this), base::Passed(&info), signal_fd));
+                     base::Unretained(this), std::move(info), signal_fd));
 }
 
 void CrashHandlerHostLinux::WriteDumpFile(BreakpadInfo* info,
@@ -477,7 +472,7 @@
 
   uploader_thread_->task_runner()->PostTask(
       FROM_HERE,
-      base::Bind(&CrashDumpTask, base::Unretained(this), base::Passed(&info)));
+      base::BindOnce(&CrashDumpTask, base::Unretained(this), std::move(info)));
 }
 
 void CrashHandlerHostLinux::WillDestroyCurrentMessageLoop() {
diff --git a/components/crash/content/tools/generate_breakpad_symbols.py b/components/crash/content/tools/generate_breakpad_symbols.py
index d076e8fa..dbf7961 100755
--- a/components/crash/content/tools/generate_breakpad_symbols.py
+++ b/components/crash/content/tools/generate_breakpad_symbols.py
@@ -212,11 +212,10 @@
         with print_lock:
           print "Generating symbols for %s" % binary
 
-      syms = GetCommandOutput([dump_syms, '-r', binary])
       mkdir_p(os.path.dirname(output_path))
       try:
         with open(output_path, 'wb') as f:
-          f.write(syms)
+          subprocess.check_call([dump_syms, '-r', binary], stdout=f)
       except Exception, e:
         # Not much we can do about this.
         with print_lock:
diff --git a/components/cronet/android/cronet_bidirectional_stream_adapter.cc b/components/cronet/android/cronet_bidirectional_stream_adapter.cc
index 1532601..486a5b58 100644
--- a/components/cronet/android/cronet_bidirectional_stream_adapter.cc
+++ b/components/cronet/android/cronet_bidirectional_stream_adapter.cc
@@ -5,6 +5,7 @@
 #include "cronet_bidirectional_stream_adapter.h"
 
 #include <string>
+#include <utility>
 #include <vector>
 
 #include "base/bind.h"
@@ -112,7 +113,7 @@
     const base::android::JavaParamRef<jobject>& jcaller) {
   context_->PostTaskToNetworkThread(
       FROM_HERE,
-      base::Bind(
+      base::BindOnce(
           &CronetBidirectionalStreamAdapter::SendRequestHeadersOnNetworkThread,
           base::Unretained(this)));
 }
@@ -150,8 +151,8 @@
 
   context_->PostTaskToNetworkThread(
       FROM_HERE,
-      base::Bind(&CronetBidirectionalStreamAdapter::StartOnNetworkThread,
-                 base::Unretained(this), base::Passed(&request_info)));
+      base::BindOnce(&CronetBidirectionalStreamAdapter::StartOnNetworkThread,
+                     base::Unretained(this), std::move(request_info)));
   return 0;
 }
 
@@ -174,8 +175,8 @@
 
   context_->PostTaskToNetworkThread(
       FROM_HERE,
-      base::Bind(&CronetBidirectionalStreamAdapter::ReadDataOnNetworkThread,
-                 base::Unretained(this), read_buffer, remaining_capacity));
+      base::BindOnce(&CronetBidirectionalStreamAdapter::ReadDataOnNetworkThread,
+                     base::Unretained(this), read_buffer, remaining_capacity));
   return JNI_TRUE;
 }
 
@@ -221,9 +222,9 @@
 
   context_->PostTaskToNetworkThread(
       FROM_HERE,
-      base::Bind(&CronetBidirectionalStreamAdapter::WritevDataOnNetworkThread,
-                 base::Unretained(this),
-                 base::Passed(std::move(pending_write_data))));
+      base::BindOnce(
+          &CronetBidirectionalStreamAdapter::WritevDataOnNetworkThread,
+          base::Unretained(this), std::move(pending_write_data)));
   return JNI_TRUE;
 }
 
@@ -238,8 +239,8 @@
   // network thread with the adapter pointer.
   context_->PostTaskToNetworkThread(
       FROM_HERE,
-      base::Bind(&CronetBidirectionalStreamAdapter::DestroyOnNetworkThread,
-                 base::Unretained(this), jsend_on_canceled));
+      base::BindOnce(&CronetBidirectionalStreamAdapter::DestroyOnNetworkThread,
+                     base::Unretained(this), jsend_on_canceled));
 }
 
 void CronetBidirectionalStreamAdapter::OnStreamReady(
diff --git a/components/cronet/android/cronet_url_request_context_adapter.cc b/components/cronet/android/cronet_url_request_context_adapter.cc
index 4fba584..1a1e21c 100644
--- a/components/cronet/android/cronet_url_request_context_adapter.cc
+++ b/components/cronet/android/cronet_url_request_context_adapter.cc
@@ -218,8 +218,8 @@
 
 void CronetURLRequestContextAdapter::PostTaskToNetworkThread(
     const base::Location& posted_from,
-    const base::Closure& callback) {
-  context_->PostTaskToNetworkThread(posted_from, callback);
+    base::OnceClosure callback) {
+  context_->PostTaskToNetworkThread(posted_from, std::move(callback));
 }
 
 bool CronetURLRequestContextAdapter::IsOnNetworkThread() const {
diff --git a/components/cronet/android/cronet_url_request_context_adapter.h b/components/cronet/android/cronet_url_request_context_adapter.h
index e84e653..f86a8e5e 100644
--- a/components/cronet/android/cronet_url_request_context_adapter.h
+++ b/components/cronet/android/cronet_url_request_context_adapter.h
@@ -57,7 +57,7 @@
   // Posts a task that might depend on the context being initialized
   // to the network thread.
   void PostTaskToNetworkThread(const base::Location& posted_from,
-                               const base::Closure& callback);
+                               base::OnceClosure callback);
 
   bool IsOnNetworkThread() const;
 
diff --git a/components/cronet/cronet_url_request.cc b/components/cronet/cronet_url_request.cc
index 9d56dd38..906d0030 100644
--- a/components/cronet/cronet_url_request.cc
+++ b/components/cronet/cronet_url_request.cc
@@ -109,15 +109,14 @@
       base::BindOnce(&CronetURLRequest::NetworkTasks::Start,
                      base::Unretained(&network_tasks_),
                      base::Unretained(context_), initial_method_,
-                     base::Passed(std::move(initial_request_headers_)),
-                     base::Passed(std::move(upload_))));
+                     std::move(initial_request_headers_), std::move(upload_)));
 }
 
 void CronetURLRequest::GetStatus(OnStatusCallback callback) const {
   context_->PostTaskToNetworkThread(
-      FROM_HERE, base::BindOnce(&CronetURLRequest::NetworkTasks::GetStatus,
-                                base::Unretained(&network_tasks_),
-                                base::Passed(&callback)));
+      FROM_HERE,
+      base::BindOnce(&CronetURLRequest::NetworkTasks::GetStatus,
+                     base::Unretained(&network_tasks_), std::move(callback)));
 }
 
 void CronetURLRequest::FollowDeferredRedirect() {
diff --git a/components/cronet/cronet_url_request_context.cc b/components/cronet/cronet_url_request_context.cc
index 423d807e..75cbda5 100644
--- a/components/cronet/cronet_url_request_context.cc
+++ b/components/cronet/cronet_url_request_context.cc
@@ -228,7 +228,7 @@
       base::BindOnce(&CronetURLRequestContext::NetworkTasks::Initialize,
                      base::Unretained(network_tasks_), GetNetworkTaskRunner(),
                      GetFileThread()->task_runner(),
-                     base::Passed(&proxy_config_service)));
+                     std::move(proxy_config_service)));
 }
 
 void CronetURLRequestContext::NetworkTasks::
@@ -482,7 +482,7 @@
       posted_from,
       base::BindOnce(
           &CronetURLRequestContext::NetworkTasks::RunTaskAfterContextInit,
-          base::Unretained(network_tasks_), base::Passed(std::move(callback))));
+          base::Unretained(network_tasks_), std::move(callback)));
 }
 
 void CronetURLRequestContext::NetworkTasks::RunTaskAfterContextInit(
diff --git a/components/data_reduction_proxy/core/browser/data_reduction_proxy_io_data.cc b/components/data_reduction_proxy/core/browser/data_reduction_proxy_io_data.cc
index 4d11e358..b6ff673 100644
--- a/components/data_reduction_proxy/core/browser/data_reduction_proxy_io_data.cc
+++ b/components/data_reduction_proxy/core/browser/data_reduction_proxy_io_data.cc
@@ -348,8 +348,8 @@
 void DataReductionProxyIOData::AddEvent(std::unique_ptr<base::Value> event) {
   DCHECK(io_task_runner_->BelongsToCurrentThread());
   ui_task_runner_->PostTask(
-      FROM_HERE, base::Bind(&DataReductionProxyService::AddEvent, service_,
-                            base::Passed(&event)));
+      FROM_HERE, base::BindOnce(&DataReductionProxyService::AddEvent, service_,
+                                std::move(event)));
 }
 
 void DataReductionProxyIOData::AddEnabledEvent(
@@ -357,8 +357,8 @@
     bool enabled) {
   DCHECK(io_task_runner_->BelongsToCurrentThread());
   ui_task_runner_->PostTask(
-      FROM_HERE, base::Bind(&DataReductionProxyService::AddEnabledEvent,
-                            service_, base::Passed(&event), enabled));
+      FROM_HERE, base::BindOnce(&DataReductionProxyService::AddEnabledEvent,
+                                service_, std::move(event), enabled));
 }
 
 void DataReductionProxyIOData::AddEventAndSecureProxyCheckState(
@@ -367,8 +367,9 @@
   DCHECK(io_task_runner_->BelongsToCurrentThread());
   ui_task_runner_->PostTask(
       FROM_HERE,
-      base::Bind(&DataReductionProxyService::AddEventAndSecureProxyCheckState,
-                 service_, base::Passed(&event), state));
+      base::BindOnce(
+          &DataReductionProxyService::AddEventAndSecureProxyCheckState,
+          service_, std::move(event), state));
 }
 
 void DataReductionProxyIOData::AddAndSetLastBypassEvent(
@@ -377,8 +378,8 @@
   DCHECK(io_task_runner_->BelongsToCurrentThread());
   ui_task_runner_->PostTask(
       FROM_HERE,
-      base::Bind(&DataReductionProxyService::AddAndSetLastBypassEvent, service_,
-                 base::Passed(&event), expiration_ticks));
+      base::BindOnce(&DataReductionProxyService::AddAndSetLastBypassEvent,
+                     service_, std::move(event), expiration_ticks));
 }
 
 void DataReductionProxyIOData::SetUnreachable(bool unreachable) {
diff --git a/components/data_reduction_proxy/core/browser/data_reduction_proxy_service.cc b/components/data_reduction_proxy/core/browser/data_reduction_proxy_service.cc
index c37b3861..257ee7b 100644
--- a/components/data_reduction_proxy/core/browser/data_reduction_proxy_service.cc
+++ b/components/data_reduction_proxy/core/browser/data_reduction_proxy_service.cc
@@ -211,10 +211,11 @@
       new std::vector<DataUsageBucket>());
   std::vector<DataUsageBucket>* data_usage_ptr = data_usage.get();
   db_task_runner_->PostTaskAndReply(
-      FROM_HERE, base::Bind(&DBDataOwner::LoadHistoricalDataUsage,
-                            db_data_owner_->GetWeakPtr(),
-                            base::Unretained(data_usage_ptr)),
-      base::Bind(load_data_usage_callback, base::Passed(&data_usage)));
+      FROM_HERE,
+      base::BindOnce(&DBDataOwner::LoadHistoricalDataUsage,
+                     db_data_owner_->GetWeakPtr(),
+                     base::Unretained(data_usage_ptr)),
+      base::BindOnce(load_data_usage_callback, std::move(data_usage)));
 }
 
 void DataReductionProxyService::LoadCurrentDataUsageBucket(
@@ -223,17 +224,18 @@
   DataUsageBucket* bucket_ptr = bucket.get();
   db_task_runner_->PostTaskAndReply(
       FROM_HERE,
-      base::Bind(&DBDataOwner::LoadCurrentDataUsageBucket,
-                 db_data_owner_->GetWeakPtr(), base::Unretained(bucket_ptr)),
-      base::Bind(load_current_data_usage_callback, base::Passed(&bucket)));
+      base::BindOnce(&DBDataOwner::LoadCurrentDataUsageBucket,
+                     db_data_owner_->GetWeakPtr(),
+                     base::Unretained(bucket_ptr)),
+      base::BindOnce(load_current_data_usage_callback, std::move(bucket)));
 }
 
 void DataReductionProxyService::StoreCurrentDataUsageBucket(
     std::unique_ptr<DataUsageBucket> current) {
   db_task_runner_->PostTask(
       FROM_HERE,
-      base::Bind(&DBDataOwner::StoreCurrentDataUsageBucket,
-                 db_data_owner_->GetWeakPtr(), base::Passed(&current)));
+      base::BindOnce(&DBDataOwner::StoreCurrentDataUsageBucket,
+                     db_data_owner_->GetWeakPtr(), std::move(current)));
 }
 
 void DataReductionProxyService::DeleteHistoricalDataUsage() {
diff --git a/components/discardable_memory/client/client_discardable_shared_memory_manager.cc b/components/discardable_memory/client/client_discardable_shared_memory_manager.cc
index 73b8ec7e..337e1eb 100644
--- a/components/discardable_memory/client/client_discardable_shared_memory_manager.cc
+++ b/components/discardable_memory/client/client_discardable_shared_memory_manager.cc
@@ -108,8 +108,8 @@
       base::ThreadTaskRunnerHandle::Get());
   mojom::DiscardableSharedMemoryManagerPtrInfo info = manager.PassInterface();
   io_task_runner_->PostTask(
-      FROM_HERE, base::Bind(&InitManagerMojoOnIO, manager_mojo_.get(),
-                            base::Passed(&info)));
+      FROM_HERE, base::BindOnce(&InitManagerMojoOnIO, manager_mojo_.get(),
+                                std::move(info)));
 }
 
 ClientDiscardableSharedMemoryManager::~ClientDiscardableSharedMemoryManager() {
@@ -363,9 +363,10 @@
   base::ScopedClosureRunner event_signal_runner(
       base::Bind(&base::WaitableEvent::Signal, base::Unretained(&event)));
   io_task_runner_->PostTask(
-      FROM_HERE, base::Bind(&ClientDiscardableSharedMemoryManager::AllocateOnIO,
-                            base::Unretained(this), size, id, &handle,
-                            base::Passed(&event_signal_runner)));
+      FROM_HERE,
+      base::BindOnce(&ClientDiscardableSharedMemoryManager::AllocateOnIO,
+                     base::Unretained(this), size, id, &handle,
+                     std::move(event_signal_runner)));
   // Waiting until IPC has finished on the IO thread.
   event.Wait();
   auto memory = std::make_unique<base::DiscardableSharedMemory>(handle);
@@ -382,9 +383,9 @@
   (*manager_mojo_)
       ->AllocateLockedDiscardableSharedMemory(
           static_cast<uint32_t>(size), id,
-          base::Bind(
+          base::BindOnce(
               &ClientDiscardableSharedMemoryManager::AllocateCompletedOnIO,
-              base::Unretained(this), handle, base::Passed(&closure_runner)));
+              base::Unretained(this), handle, std::move(closure_runner)));
 }
 
 void ClientDiscardableSharedMemoryManager::AllocateCompletedOnIO(
diff --git a/components/discardable_memory/common/discardable_shared_memory_heap_perftest.cc b/components/discardable_memory/common/discardable_shared_memory_heap_perftest.cc
index acbf1f45..7ddb426 100644
--- a/components/discardable_memory/common/discardable_shared_memory_heap_perftest.cc
+++ b/components/discardable_memory/common/discardable_shared_memory_heap_perftest.cc
@@ -74,8 +74,8 @@
           heap.SearchFreeLists(random_blocks[i], slack);
       if (span) {
         spans.push_back(std::make_unique<base::ScopedClosureRunner>(
-            base::Bind(&DiscardableSharedMemoryHeap::MergeIntoFreeLists,
-                       base::Unretained(&heap), base::Passed(&span))));
+            base::BindOnce(&DiscardableSharedMemoryHeap::MergeIntoFreeLists,
+                           base::Unretained(&heap), std::move(span))));
       } else if (!spans.empty()) {
         // Merge a random span back into the free list.
         std::swap(spans[random_span[i] % spans.size()], spans.back());
diff --git a/components/dom_distiller/core/distilled_content_store.cc b/components/dom_distiller/core/distilled_content_store.cc
index a2ae21e..ffe6944a 100644
--- a/components/dom_distiller/core/distilled_content_store.cc
+++ b/components/dom_distiller/core/distilled_content_store.cc
@@ -4,6 +4,8 @@
 
 #include "components/dom_distiller/core/distilled_content_store.h"
 
+#include <utility>
+
 #include "base/threading/thread_task_runner_handle.h"
 
 namespace dom_distiller {
@@ -57,7 +59,7 @@
   }
   base::ThreadTaskRunnerHandle::Get()->PostTask(
       FROM_HERE,
-      base::Bind(callback, success, base::Passed(&distilled_article)));
+      base::BindOnce(callback, success, std::move(distilled_article)));
 }
 
 void InMemoryContentStore::InjectContent(const ArticleEntry& entry,
diff --git a/components/dom_distiller/core/distiller_page.cc b/components/dom_distiller/core/distiller_page.cc
index ad37b5f..36eafa9 100644
--- a/components/dom_distiller/core/distiller_page.cc
+++ b/components/dom_distiller/core/distiller_page.cc
@@ -6,6 +6,8 @@
 
 #include <stddef.h>
 
+#include <utility>
+
 #include "base/bind.h"
 #include "base/json/json_writer.h"
 #include "base/location.h"
@@ -155,8 +157,8 @@
   }
 
   base::ThreadTaskRunnerHandle::Get()->PostTask(
-      FROM_HERE, base::Bind(distiller_page_callback_,
-                            base::Passed(&distiller_result), found_content));
+      FROM_HERE, base::BindOnce(distiller_page_callback_,
+                                std::move(distiller_result), found_content));
 }
 
 }  // namespace dom_distiller
diff --git a/components/dom_distiller/core/fake_distiller.cc b/components/dom_distiller/core/fake_distiller.cc
index ab64ce6e..6b046b1 100644
--- a/components/dom_distiller/core/fake_distiller.cc
+++ b/components/dom_distiller/core/fake_distiller.cc
@@ -74,8 +74,8 @@
 void FakeDistiller::PostDistillerCallback(
     std::unique_ptr<DistilledArticleProto> proto) {
   base::ThreadTaskRunnerHandle::Get()->PostTask(
-      FROM_HERE, base::Bind(&FakeDistiller::RunDistillerCallbackInternal,
-                            base::Unretained(this), base::Passed(&proto)));
+      FROM_HERE, base::BindOnce(&FakeDistiller::RunDistillerCallbackInternal,
+                                base::Unretained(this), std::move(proto)));
 }
 
 void FakeDistiller::RunDistillerCallbackInternal(
diff --git a/components/domain_reliability/service.cc b/components/domain_reliability/service.cc
index d11adad..c1bce26 100644
--- a/components/domain_reliability/service.cc
+++ b/components/domain_reliability/service.cc
@@ -4,6 +4,8 @@
 
 #include "components/domain_reliability/service.h"
 
+#include <utility>
+
 #include "base/bind.h"
 #include "base/callback.h"
 #include "base/location.h"
@@ -118,10 +120,8 @@
     DCHECK(network_task_runner_.get());
 
     network_task_runner_->PostTask(
-        FROM_HERE,
-        base::Bind(&AddContextForTestingOnNetworkTaskRunner,
-                   monitor_,
-                   base::Passed(&config)));
+        FROM_HERE, base::BindOnce(&AddContextForTestingOnNetworkTaskRunner,
+                                  monitor_, std::move(config)));
   }
 
   void ForceUploadsForTesting() override {
@@ -145,7 +145,7 @@
         base::BindOnce(
             &DomainReliabilityServiceImpl::CheckUploadAllowedOnUIThread,
             service, base::RetainedRef(network_task_runner), origin,
-            base::Passed(&callback)));
+            std::move(callback)));
   }
 
   void CheckUploadAllowedOnUIThread(
diff --git a/components/download/internal/background_service/blob_task_proxy.cc b/components/download/internal/background_service/blob_task_proxy.cc
index d654b35..ab52593 100644
--- a/components/download/internal/background_service/blob_task_proxy.cc
+++ b/components/download/internal/background_service/blob_task_proxy.cc
@@ -4,6 +4,8 @@
 
 #include "components/download/internal/background_service/blob_task_proxy.h"
 
+#include <utility>
+
 #include "base/guid.h"
 #include "base/task_runner_util.h"
 #include "base/threading/thread_task_runner_handle.h"
@@ -64,10 +66,9 @@
       blob_storage_context_->AddFinishedBlob(std::move(builder));
 
   // Wait for blob data construction complete.
-  auto cb = base::BindRepeating(&BlobTaskProxy::BlobSavedOnIO,
-                                weak_ptr_factory_.GetWeakPtr(),
-                                base::Passed(std::move(callback)));
-  blob_data_handle_->RunOnConstructionComplete(cb);
+  auto cb = base::BindOnce(&BlobTaskProxy::BlobSavedOnIO,
+                           weak_ptr_factory_.GetWeakPtr(), std::move(callback));
+  blob_data_handle_->RunOnConstructionComplete(std::move(cb));
 }
 
 void BlobTaskProxy::BlobSavedOnIO(BlobDataHandleCallback callback,
@@ -75,8 +76,8 @@
   io_task_runner_->BelongsToCurrentThread();
 
   // Relay BlobDataHandle and |status| back to main thread.
-  auto cb = base::BindOnce(std::move(callback),
-                           base::Passed(std::move(blob_data_handle_)), status);
+  auto cb =
+      base::BindOnce(std::move(callback), std::move(blob_data_handle_), status);
   main_task_runner_->PostTask(FROM_HERE, std::move(cb));
 }
 
diff --git a/components/drive/chromeos/change_list_loader.cc b/components/drive/chromeos/change_list_loader.cc
index 88d25ed..e2f34774 100644
--- a/components/drive/chromeos/change_list_loader.cc
+++ b/components/drive/chromeos/change_list_loader.cc
@@ -268,10 +268,10 @@
   if (cached_about_resource_) {
     base::ThreadTaskRunnerHandle::Get()->PostTask(
         FROM_HERE,
-        base::Bind(
+        base::BindOnce(
             callback, google_apis::HTTP_NO_CONTENT,
-            base::Passed(std::unique_ptr<google_apis::AboutResource>(
-                new google_apis::AboutResource(*cached_about_resource_)))));
+            std::unique_ptr<google_apis::AboutResource>(
+                new google_apis::AboutResource(*cached_about_resource_))));
   } else {
     UpdateAboutResource(callback);
   }
diff --git a/components/drive/chromeos/directory_loader.cc b/components/drive/chromeos/directory_loader.cc
index 10dbf35..1c35c2a 100644
--- a/components/drive/chromeos/directory_loader.cc
+++ b/components/drive/chromeos/directory_loader.cc
@@ -351,20 +351,13 @@
   ResourceEntry* entry = new ResourceEntry;
   int64_t* local_changestamp = new int64_t;
   base::PostTaskAndReplyWithResult(
-      blocking_task_runner_.get(),
-      FROM_HERE,
-      base::Bind(&CheckLocalState,
-                 resource_metadata_,
-                 *about_resource_ptr,
-                 local_id,
-                 entry,
-                 local_changestamp),
-      base::Bind(&DirectoryLoader::ReadDirectoryAfterCheckLocalState,
-                 weak_ptr_factory_.GetWeakPtr(),
-                 base::Passed(&about_resource),
-                 local_id,
-                 base::Owned(entry),
-                 base::Owned(local_changestamp)));
+      blocking_task_runner_.get(), FROM_HERE,
+      base::BindOnce(&CheckLocalState, resource_metadata_, *about_resource_ptr,
+                     local_id, entry, local_changestamp),
+      base::BindOnce(&DirectoryLoader::ReadDirectoryAfterCheckLocalState,
+                     weak_ptr_factory_.GetWeakPtr(), std::move(about_resource),
+                     local_id, base::Owned(entry),
+                     base::Owned(local_changestamp)));
 }
 
 void DirectoryLoader::ReadDirectoryAfterCheckLocalState(
diff --git a/components/drive/chromeos/file_system.cc b/components/drive/chromeos/file_system.cc
index b086def..05f4b59 100644
--- a/components/drive/chromeos/file_system.cc
+++ b/components/drive/chromeos/file_system.cc
@@ -654,14 +654,10 @@
   std::unique_ptr<ResourceEntry> entry(new ResourceEntry);
   ResourceEntry* entry_ptr = entry.get();
   base::PostTaskAndReplyWithResult(
-      blocking_task_runner_.get(),
-      FROM_HERE,
-      base::Bind(&GetLocallyStoredResourceEntry,
-                 resource_metadata_,
-                 cache_,
-                 file_path,
-                 entry_ptr),
-      base::Bind(&RunGetResourceEntryCallback, callback, base::Passed(&entry)));
+      blocking_task_runner_.get(), FROM_HERE,
+      base::BindOnce(&GetLocallyStoredResourceEntry, resource_metadata_, cache_,
+                     file_path, entry_ptr),
+      base::BindOnce(&RunGetResourceEntryCallback, callback, std::move(entry)));
 }
 
 void FileSystem::ReadDirectory(
diff --git a/components/drive/chromeos/file_system/copy_operation.cc b/components/drive/chromeos/file_system/copy_operation.cc
index 50aa4a04..853b60fc 100644
--- a/components/drive/chromeos/file_system/copy_operation.cc
+++ b/components/drive/chromeos/file_system/copy_operation.cc
@@ -7,6 +7,7 @@
 #include <stdint.h>
 
 #include <string>
+#include <utility>
 
 #include "base/task_runner_util.h"
 #include "components/drive/chromeos/file_cache.h"
@@ -577,18 +578,12 @@
   // metadata.
   base::FilePath* file_path = new base::FilePath;
   base::PostTaskAndReplyWithResult(
-      blocking_task_runner_.get(),
-      FROM_HERE,
-      base::Bind(&UpdateLocalStateForServerSideOperation,
-                 metadata_,
-                 base::Passed(&entry),
-                 resource_entry,
-                 file_path),
-      base::Bind(&CopyOperation::UpdateAfterLocalStateUpdate,
-                 weak_ptr_factory_.GetWeakPtr(),
-                 callback,
-                 base::Owned(file_path),
-                 base::Owned(resource_entry)));
+      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(
diff --git a/components/drive/chromeos/file_system/download_operation.cc b/components/drive/chromeos/file_system/download_operation.cc
index 1b7dcda6..ed5b19a3 100644
--- a/components/drive/chromeos/file_system/download_operation.cc
+++ b/components/drive/chromeos/file_system/download_operation.cc
@@ -378,22 +378,15 @@
                          completion_callback, base::WrapUnique(entry)));
   base::Closure cancel_closure = download_params->GetCancelClosure();
   base::PostTaskAndReplyWithResult(
-      blocking_task_runner_.get(),
-      FROM_HERE,
-      base::Bind(&CheckPreConditionForEnsureFileDownloadedByLocalId,
-                 params,
-                 local_id,
-                 drive_file_path,
-                 cache_file_path,
-                 temp_download_file_path,
-                 entry),
-      base::Bind(&DownloadOperation::EnsureFileDownloadedAfterCheckPreCondition,
-                 weak_ptr_factory_.GetWeakPtr(),
-                 base::Passed(&download_params),
-                 context,
-                 base::Owned(drive_file_path),
-                 base::Owned(cache_file_path),
-                 base::Owned(temp_download_file_path)));
+      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;
 }
 
@@ -419,21 +412,15 @@
                          completion_callback, base::WrapUnique(entry)));
   base::Closure cancel_closure = download_params->GetCancelClosure();
   base::PostTaskAndReplyWithResult(
-      blocking_task_runner_.get(),
-      FROM_HERE,
-      base::Bind(&CheckPreConditionForEnsureFileDownloadedByPath,
-                 params,
-                 file_path,
-                 cache_file_path,
-                 temp_download_file_path,
-                 entry),
-      base::Bind(&DownloadOperation::EnsureFileDownloadedAfterCheckPreCondition,
-                 weak_ptr_factory_.GetWeakPtr(),
-                 base::Passed(&download_params),
-                 context,
-                 base::Owned(drive_file_path),
-                 base::Owned(cache_file_path),
-                 base::Owned(temp_download_file_path)));
+      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;
 }
 
@@ -498,14 +485,13 @@
   base::FilePath* cache_file_path = new base::FilePath;
   base::PostTaskAndReplyWithResult(
       blocking_task_runner_.get(), FROM_HERE,
-      base::Bind(&UpdateLocalStateForDownloadFile, metadata_, cache_,
-                 params_ptr->entry(), gdata_error, downloaded_file_path,
-                 entry_after_update, cache_file_path),
-      base::Bind(&DownloadOperation::EnsureFileDownloadedAfterUpdateLocalState,
-                 weak_ptr_factory_.GetWeakPtr(), drive_file_path,
-                 base::Passed(&params),
-                 base::Passed(base::WrapUnique(entry_after_update)),
-                 base::Owned(cache_file_path)));
+      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(
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
index 47577026..c7a1730 100644
--- a/components/drive/chromeos/file_system/get_file_for_saving_operation.cc
+++ b/components/drive/chromeos/file_system/get_file_for_saving_operation.cc
@@ -120,20 +120,13 @@
   std::unique_ptr<base::ScopedClosureRunner>* file_closer =
       new std::unique_ptr<base::ScopedClosureRunner>;
   base::PostTaskAndReplyWithResult(
-      blocking_task_runner_.get(),
-      FROM_HERE,
-      base::Bind(&OpenCacheFileForWrite,
-                 metadata_,
-                 cache_,
-                 local_id,
-                 file_closer,
-                 entry_ptr),
-      base::Bind(&GetFileForSavingOperation::GetFileForSavingAfterOpenForWrite,
-                 weak_ptr_factory_.GetWeakPtr(),
-                 callback,
-                 cache_path,
-                 base::Passed(&entry),
-                 base::Owned(file_closer)));
+      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(), callback, cache_path,
+          std::move(entry), base::Owned(file_closer)));
 }
 
 void GetFileForSavingOperation::GetFileForSavingAfterOpenForWrite(
diff --git a/components/drive/chromeos/search_metadata.cc b/components/drive/chromeos/search_metadata.cc
index 2c5eb93..fe24ed7 100644
--- a/components/drive/chromeos/search_metadata.cc
+++ b/components/drive/chromeos/search_metadata.cc
@@ -292,10 +292,10 @@
   MetadataSearchResultVector* results_ptr = results.get();
   base::PostTaskAndReplyWithResult(
       blocking_task_runner.get(), FROM_HERE,
-      base::Bind(&SearchMetadataOnBlockingPool, resource_metadata, query,
-                 predicate, at_most_num_matches, order, results_ptr),
-      base::Bind(&RunSearchMetadataCallback, callback, start_time,
-                 base::Passed(&results)));
+      base::BindOnce(&SearchMetadataOnBlockingPool, resource_metadata, query,
+                     predicate, at_most_num_matches, order, results_ptr),
+      base::BindOnce(&RunSearchMetadataCallback, callback, start_time,
+                     std::move(results)));
 }
 
 bool MatchesType(int options, const ResourceEntry& entry) {
diff --git a/components/drive/chromeos/sync/entry_revert_performer.cc b/components/drive/chromeos/sync/entry_revert_performer.cc
index a5cb7b1..38b4dfe20 100644
--- a/components/drive/chromeos/sync/entry_revert_performer.cc
+++ b/components/drive/chromeos/sync/entry_revert_performer.cc
@@ -4,6 +4,8 @@
 
 #include "components/drive/chromeos/sync/entry_revert_performer.h"
 
+#include <utility>
+
 #include "components/drive/chromeos/change_list_processor.h"
 #include "components/drive/chromeos/file_system/operation_delegate.h"
 #include "components/drive/chromeos/resource_metadata.h"
@@ -106,13 +108,12 @@
   std::unique_ptr<ResourceEntry> entry(new ResourceEntry);
   ResourceEntry* entry_ptr = entry.get();
   base::PostTaskAndReplyWithResult(
-      blocking_task_runner_.get(),
-      FROM_HERE,
-      base::Bind(&ResourceMetadata::GetResourceEntryById,
-                 base::Unretained(metadata_), local_id, entry_ptr),
-      base::Bind(&EntryRevertPerformer::RevertEntryAfterPrepare,
-                 weak_ptr_factory_.GetWeakPtr(), context, callback,
-                 base::Passed(&entry)));
+      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(
@@ -148,18 +149,12 @@
 
   FileChange* changed_files = new FileChange;
   base::PostTaskAndReplyWithResult(
-      blocking_task_runner_.get(),
-      FROM_HERE,
-      base::Bind(&FinishRevert,
-                 metadata_,
-                 local_id,
-                 status,
-                 base::Passed(&entry),
-                 changed_files),
-      base::Bind(&EntryRevertPerformer::RevertEntryAfterFinishRevert,
-                 weak_ptr_factory_.GetWeakPtr(),
-                 callback,
-                 base::Owned(changed_files)));
+      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(
diff --git a/components/drive/drive_uploader.cc b/components/drive/drive_uploader.cc
index 727c27f..1ae8772 100644
--- a/components/drive/drive_uploader.cc
+++ b/components/drive/drive_uploader.cc
@@ -268,15 +268,13 @@
 
   UploadFileInfo* info_ptr = upload_file_info.get();
   base::PostTaskAndReplyWithResult(
-      blocking_task_runner_.get(),
-      FROM_HERE,
-      base::Bind(&base::GetFileSize,
-                 info_ptr->file_path,
-                 &info_ptr->content_length),
-      base::Bind(&DriveUploader::StartUploadFileAfterGetFileSize,
-                 weak_ptr_factory_.GetWeakPtr(),
-                 base::Passed(&upload_file_info),
-                 start_initiate_upload_callback));
+      blocking_task_runner_.get(), FROM_HERE,
+      base::BindOnce(&base::GetFileSize, info_ptr->file_path,
+                     &info_ptr->content_length),
+      base::BindOnce(&DriveUploader::StartUploadFileAfterGetFileSize,
+                     weak_ptr_factory_.GetWeakPtr(),
+                     std::move(upload_file_info),
+                     start_initiate_upload_callback));
   return info_ptr->GetCancelCallback();
 }
 
diff --git a/components/drive/drive_uploader_unittest.cc b/components/drive/drive_uploader_unittest.cc
index 93aac728..e4d37c7 100644
--- a/components/drive/drive_uploader_unittest.cc
+++ b/components/drive/drive_uploader_unittest.cc
@@ -10,6 +10,7 @@
 #include <algorithm>
 #include <memory>
 #include <string>
+#include <utility>
 #include <vector>
 
 #include "base/bind.h"
@@ -76,7 +77,7 @@
   entry.reset(new FileResource);
   entry->set_md5_checksum(kTestDummyMd5);
   base::ThreadTaskRunnerHandle::Get()->PostTask(
-      FROM_HERE, base::Bind(callback, response_code, base::Passed(&entry)));
+      FROM_HERE, base::BindOnce(callback, response_code, std::move(entry)));
   return CancelCallback();
 }
 
@@ -226,8 +227,8 @@
           HTTP_RESUME_INCOMPLETE, 0, received_bytes_);
     }
     // ResumeUpload is an asynchronous function, so don't callback directly.
-    base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE,
-        base::Bind(callback, response, base::Passed(&entry)));
+    base::ThreadTaskRunnerHandle::Get()->PostTask(
+        FROM_HERE, base::BindOnce(callback, response, std::move(entry)));
   }
 
   CancelCallback MultipartUploadNewFile(
@@ -266,9 +267,7 @@
 
     if (!options.etag.empty() && options.etag != kTestETag) {
       base::ThreadTaskRunnerHandle::Get()->PostTask(
-          FROM_HERE,
-          base::Bind(callback, HTTP_PRECONDITION,
-                     base::Passed(base::WrapUnique<FileResource>(nullptr))));
+          FROM_HERE, base::BindOnce(callback, HTTP_PRECONDITION, nullptr));
       return CancelCallback();
     }
 
@@ -335,9 +334,7 @@
       const google_apis::FileResourceCallback& callback,
       const google_apis::ProgressCallback& progress_callback) override {
     base::ThreadTaskRunnerHandle::Get()->PostTask(
-        FROM_HERE,
-        base::Bind(callback, DRIVE_NO_CONNECTION,
-                   base::Passed(base::WrapUnique<FileResource>(nullptr))));
+        FROM_HERE, base::BindOnce(callback, DRIVE_NO_CONNECTION, nullptr));
     return CancelCallback();
   }
 
@@ -350,9 +347,7 @@
       const google_apis::FileResourceCallback& callback,
       const google_apis::ProgressCallback& progress_callback) override {
     base::ThreadTaskRunnerHandle::Get()->PostTask(
-        FROM_HERE,
-        base::Bind(callback, DRIVE_NO_CONNECTION,
-                   base::Passed(base::WrapUnique<FileResource>(nullptr))));
+        FROM_HERE, base::BindOnce(callback, DRIVE_NO_CONNECTION, nullptr));
     return CancelCallback();
   }
 };
@@ -395,8 +390,9 @@
       const ProgressCallback& progress_callback) override {
     base::ThreadTaskRunnerHandle::Get()->PostTask(
         FROM_HERE,
-        base::Bind(callback, UploadRangeResponse(DRIVE_NO_CONNECTION, -1, -1),
-                   base::Passed(std::unique_ptr<FileResource>())));
+        base::BindOnce(callback,
+                       UploadRangeResponse(DRIVE_NO_CONNECTION, -1, -1),
+                       nullptr));
     return CancelCallback();
   }
 };
@@ -409,8 +405,9 @@
                                  const UploadRangeCallback& callback) override {
     base::ThreadTaskRunnerHandle::Get()->PostTask(
         FROM_HERE,
-        base::Bind(callback, UploadRangeResponse(DRIVE_NO_CONNECTION, -1, -1),
-                   base::Passed(std::unique_ptr<FileResource>())));
+        base::BindOnce(callback,
+                       UploadRangeResponse(DRIVE_NO_CONNECTION, -1, -1),
+                       nullptr));
     return CancelCallback();
   }
 };
diff --git a/components/drive/service/fake_drive_service.cc b/components/drive/service/fake_drive_service.cc
index 4638c62..91f6b4f 100644
--- a/components/drive/service/fake_drive_service.cc
+++ b/components/drive/service/fake_drive_service.cc
@@ -117,11 +117,9 @@
                                  std::unique_ptr<FileResource> entry) {
   base::ThreadTaskRunnerHandle::Get()->PostTask(
       FROM_HERE,
-      base::Bind(callback,
-                 UploadRangeResponse(error,
-                                     start_position,
-                                     end_position),
-                 base::Passed(&entry)));
+      base::BindOnce(callback,
+                     UploadRangeResponse(error, start_position, end_position),
+                     std::move(entry)));
 }
 
 void FileListCallbackAdapter(const FileListCallback& callback,
@@ -404,8 +402,8 @@
     const google_apis::TeamDriveListCallback& callback) {
   if (offline_) {
     base::ThreadTaskRunnerHandle::Get()->PostTask(
-        FROM_HERE, base::Bind(callback, DRIVE_NO_CONNECTION,
-                              base::Passed(std::unique_ptr<TeamDriveList>())));
+        FROM_HERE, base::BindOnce(callback, DRIVE_NO_CONNECTION,
+                                  std::unique_ptr<TeamDriveList>()));
     return;
   }
   if (load_counter)
@@ -427,7 +425,7 @@
     result->mutable_items()->push_back(std::move(team_drive));
   }
   base::ThreadTaskRunnerHandle::Get()->PostTask(
-      FROM_HERE, base::Bind(callback, HTTP_SUCCESS, base::Passed(&result)));
+      FROM_HERE, base::BindOnce(callback, HTTP_SUCCESS, std::move(result)));
 }
 
 CancelCallback FakeDriveService::GetAllTeamDriveList(
@@ -613,23 +611,23 @@
 
   if (offline_) {
     base::ThreadTaskRunnerHandle::Get()->PostTask(
-        FROM_HERE, base::Bind(callback, DRIVE_NO_CONNECTION,
-                              base::Passed(std::unique_ptr<FileResource>())));
+        FROM_HERE, base::BindOnce(callback, DRIVE_NO_CONNECTION,
+                                  std::unique_ptr<FileResource>()));
     return CancelCallback();
   }
 
   EntryInfo* entry = FindEntryByResourceId(resource_id);
   if (entry && entry->change_resource.file()) {
     base::ThreadTaskRunnerHandle::Get()->PostTask(
-        FROM_HERE, base::Bind(callback, HTTP_SUCCESS,
-                              base::Passed(std::make_unique<FileResource>(
-                                  *entry->change_resource.file()))));
+        FROM_HERE, base::BindOnce(callback, HTTP_SUCCESS,
+                                  std::make_unique<FileResource>(
+                                      *entry->change_resource.file())));
     return CancelCallback();
   }
 
   base::ThreadTaskRunnerHandle::Get()->PostTask(
-      FROM_HERE, base::Bind(callback, HTTP_NOT_FOUND,
-                            base::Passed(std::unique_ptr<FileResource>())));
+      FROM_HERE, base::BindOnce(callback, HTTP_NOT_FOUND,
+                                std::unique_ptr<FileResource>()));
   return CancelCallback();
 }
 
@@ -672,8 +670,7 @@
     std::unique_ptr<AboutResource> null;
     base::ThreadTaskRunnerHandle::Get()->PostTask(
         FROM_HERE,
-        base::Bind(callback,
-                   DRIVE_NO_CONNECTION, base::Passed(&null)));
+        base::BindOnce(callback, DRIVE_NO_CONNECTION, std::move(null)));
     return CancelCallback();
   }
 
@@ -682,8 +679,7 @@
       new AboutResource(*about_resource_));
   base::ThreadTaskRunnerHandle::Get()->PostTask(
       FROM_HERE,
-      base::Bind(callback,
-                 HTTP_SUCCESS, base::Passed(&about_resource)));
+      base::BindOnce(callback, HTTP_SUCCESS, std::move(about_resource)));
   return CancelCallback();
 }
 
@@ -696,17 +692,14 @@
     std::unique_ptr<AppList> null;
     base::ThreadTaskRunnerHandle::Get()->PostTask(
         FROM_HERE,
-        base::Bind(callback,
-                   DRIVE_NO_CONNECTION,
-                   base::Passed(&null)));
+        base::BindOnce(callback, DRIVE_NO_CONNECTION, std::move(null)));
     return CancelCallback();
   }
 
   ++app_list_load_count_;
   std::unique_ptr<AppList> app_list(AppList::CreateFrom(*app_info_value_));
   base::ThreadTaskRunnerHandle::Get()->PostTask(
-      FROM_HERE,
-      base::Bind(callback, HTTP_SUCCESS, base::Passed(&app_list)));
+      FROM_HERE, base::BindOnce(callback, HTTP_SUCCESS, std::move(app_list)));
   return CancelCallback();
 }
 
@@ -845,9 +838,8 @@
       std::unique_ptr<std::string> content_for_callback(
           new std::string(content_data.substr(i, size)));
       base::ThreadTaskRunnerHandle::Get()->PostTask(
-          FROM_HERE,
-          base::Bind(get_content_callback, HTTP_SUCCESS,
-                     base::Passed(&content_for_callback)));
+          FROM_HERE, base::BindOnce(get_content_callback, HTTP_SUCCESS,
+                                    std::move(content_for_callback)));
     }
   }
 
@@ -890,8 +882,8 @@
 
   if (offline_) {
     base::ThreadTaskRunnerHandle::Get()->PostTask(
-        FROM_HERE, base::Bind(callback, DRIVE_NO_CONNECTION,
-                              base::Passed(std::unique_ptr<FileResource>())));
+        FROM_HERE, base::BindOnce(callback, DRIVE_NO_CONNECTION,
+                                  std::unique_ptr<FileResource>()));
     return CancelCallback();
   }
 
@@ -901,8 +893,8 @@
   EntryInfo* entry = FindEntryByResourceId(resource_id);
   if (!entry) {
     base::ThreadTaskRunnerHandle::Get()->PostTask(
-        FROM_HERE, base::Bind(callback, HTTP_NOT_FOUND,
-                              base::Passed(std::unique_ptr<FileResource>())));
+        FROM_HERE, base::BindOnce(callback, HTTP_NOT_FOUND,
+                                  std::unique_ptr<FileResource>()));
     return CancelCallback();
   }
 
@@ -939,9 +931,8 @@
   entries_[new_resource_id] = std::move(copied_entry);
 
   base::ThreadTaskRunnerHandle::Get()->PostTask(
-      FROM_HERE,
-      base::Bind(callback, HTTP_SUCCESS,
-                 base::Passed(std::make_unique<FileResource>(*new_file))));
+      FROM_HERE, base::BindOnce(callback, HTTP_SUCCESS,
+                                std::make_unique<FileResource>(*new_file)));
   base::ThreadTaskRunnerHandle::Get()->PostTask(
       FROM_HERE,
       base::Bind(&FakeDriveService::NotifyObservers,
@@ -962,23 +953,23 @@
 
   if (offline_) {
     base::ThreadTaskRunnerHandle::Get()->PostTask(
-        FROM_HERE, base::Bind(callback, DRIVE_NO_CONNECTION,
-                              base::Passed(std::unique_ptr<FileResource>())));
+        FROM_HERE, base::BindOnce(callback, DRIVE_NO_CONNECTION,
+                                  std::unique_ptr<FileResource>()));
     return CancelCallback();
   }
 
   EntryInfo* entry = FindEntryByResourceId(resource_id);
   if (!entry) {
     base::ThreadTaskRunnerHandle::Get()->PostTask(
-        FROM_HERE, base::Bind(callback, HTTP_NOT_FOUND,
-                              base::Passed(std::unique_ptr<FileResource>())));
+        FROM_HERE, base::BindOnce(callback, HTTP_NOT_FOUND,
+                                  std::unique_ptr<FileResource>()));
     return CancelCallback();
   }
 
   if (!UserHasWriteAccess(entry->user_permission)) {
     base::ThreadTaskRunnerHandle::Get()->PostTask(
-        FROM_HERE, base::Bind(callback, HTTP_FORBIDDEN,
-                              base::Passed(std::unique_ptr<FileResource>())));
+        FROM_HERE, base::BindOnce(callback, HTTP_FORBIDDEN,
+                                  std::unique_ptr<FileResource>()));
     return CancelCallback();
   }
 
@@ -1010,9 +1001,8 @@
   UpdateETag(file);
 
   base::ThreadTaskRunnerHandle::Get()->PostTask(
-      FROM_HERE,
-      base::Bind(callback, HTTP_SUCCESS,
-                 base::Passed(std::make_unique<FileResource>(*file))));
+      FROM_HERE, base::BindOnce(callback, HTTP_SUCCESS,
+                                std::make_unique<FileResource>(*file)));
   base::ThreadTaskRunnerHandle::Get()->PostTask(
       FROM_HERE,
       base::Bind(&FakeDriveService::NotifyObservers,
@@ -1467,8 +1457,8 @@
 
   if (offline_) {
     base::ThreadTaskRunnerHandle::Get()->PostTask(
-        FROM_HERE, base::Bind(callback, DRIVE_NO_CONNECTION,
-                              base::Passed(std::unique_ptr<FileResource>())));
+        FROM_HERE, base::BindOnce(callback, DRIVE_NO_CONNECTION,
+                                  std::unique_ptr<FileResource>()));
     return;
   }
 
@@ -1480,15 +1470,15 @@
                                            shared_with_me);
   if (!new_entry) {
     base::ThreadTaskRunnerHandle::Get()->PostTask(
-        FROM_HERE, base::Bind(callback, HTTP_NOT_FOUND,
-                              base::Passed(std::unique_ptr<FileResource>())));
+        FROM_HERE, base::BindOnce(callback, HTTP_NOT_FOUND,
+                                  std::unique_ptr<FileResource>()));
     return;
   }
 
   base::ThreadTaskRunnerHandle::Get()->PostTask(
-      FROM_HERE, base::Bind(callback, HTTP_CREATED,
-                            base::Passed(std::make_unique<FileResource>(
-                                *new_entry->change_resource.file()))));
+      FROM_HERE, base::BindOnce(callback, HTTP_CREATED,
+                                std::make_unique<FileResource>(
+                                    *new_entry->change_resource.file())));
   base::ThreadTaskRunnerHandle::Get()->PostTask(
       FROM_HERE,
       base::Bind(&FakeDriveService::NotifyObservers,
@@ -1506,8 +1496,8 @@
 
   if (offline_) {
     base::ThreadTaskRunnerHandle::Get()->PostTask(
-        FROM_HERE, base::Bind(callback, DRIVE_NO_CONNECTION,
-                              base::Passed(std::unique_ptr<FileResource>())));
+        FROM_HERE, base::BindOnce(callback, DRIVE_NO_CONNECTION,
+                                  std::unique_ptr<FileResource>()));
     return CancelCallback();
   }
 
@@ -1519,8 +1509,8 @@
                                            false);  // shared_with_me
   if (!new_entry) {
     base::ThreadTaskRunnerHandle::Get()->PostTask(
-        FROM_HERE, base::Bind(callback, HTTP_NOT_FOUND,
-                              base::Passed(std::unique_ptr<FileResource>())));
+        FROM_HERE, base::BindOnce(callback, HTTP_NOT_FOUND,
+                                  std::unique_ptr<FileResource>()));
     return CancelCallback();
   }
 
@@ -1530,9 +1520,9 @@
   DCHECK_EQ(HTTP_SUCCESS, result);
 
   base::ThreadTaskRunnerHandle::Get()->PostTask(
-      FROM_HERE, base::Bind(callback, HTTP_CREATED,
-                            base::Passed(std::make_unique<FileResource>(
-                                *new_entry->change_resource.file()))));
+      FROM_HERE, base::BindOnce(callback, HTTP_CREATED,
+                                std::make_unique<FileResource>(
+                                    *new_entry->change_resource.file())));
   base::ThreadTaskRunnerHandle::Get()->PostTask(
       FROM_HERE,
       base::Bind(&FakeDriveService::NotifyObservers,
@@ -1549,16 +1539,16 @@
 
   if (offline_) {
     base::ThreadTaskRunnerHandle::Get()->PostTask(
-        FROM_HERE, base::Bind(callback, DRIVE_NO_CONNECTION,
-                              base::Passed(std::unique_ptr<FileResource>())));
+        FROM_HERE, base::BindOnce(callback, DRIVE_NO_CONNECTION,
+                                  std::unique_ptr<FileResource>()));
     return;
   }
 
   EntryInfo* entry = FindEntryByResourceId(resource_id);
   if (!entry) {
     base::ThreadTaskRunnerHandle::Get()->PostTask(
-        FROM_HERE, base::Bind(callback, HTTP_NOT_FOUND,
-                              base::Passed(std::unique_ptr<FileResource>())));
+        FROM_HERE, base::BindOnce(callback, HTTP_NOT_FOUND,
+                                  std::unique_ptr<FileResource>()));
     return;
   }
 
@@ -1568,9 +1558,8 @@
   file->set_modified_by_me_date(last_modified_time);
 
   base::ThreadTaskRunnerHandle::Get()->PostTask(
-      FROM_HERE,
-      base::Bind(callback, HTTP_SUCCESS,
-                 base::Passed(std::make_unique<FileResource>(*file))));
+      FROM_HERE, base::BindOnce(callback, HTTP_SUCCESS,
+                                std::make_unique<FileResource>(*file)));
 }
 
 google_apis::DriveApiErrorCode FakeDriveService::SetUserPermission(
@@ -1740,8 +1729,8 @@
     const ChangeListCallback& callback) {
   if (offline_) {
     base::ThreadTaskRunnerHandle::Get()->PostTask(
-        FROM_HERE, base::Bind(callback, DRIVE_NO_CONNECTION,
-                              base::Passed(std::unique_ptr<ChangeList>())));
+        FROM_HERE, base::BindOnce(callback, DRIVE_NO_CONNECTION,
+                                  std::unique_ptr<ChangeList>()));
     return;
   }
 
@@ -1853,7 +1842,7 @@
     *load_counter += 1;
   base::ThreadTaskRunnerHandle::Get()->PostTask(
       FROM_HERE,
-      base::Bind(callback, HTTP_SUCCESS, base::Passed(&change_list)));
+      base::BindOnce(callback, HTTP_SUCCESS, std::move(change_list)));
 }
 
 GURL FakeDriveService::GetNewUploadSessionUrl() {
diff --git a/components/feature_engagement/internal/in_memory_event_store.cc b/components/feature_engagement/internal/in_memory_event_store.cc
index 140d6ea5..348727a9 100644
--- a/components/feature_engagement/internal/in_memory_event_store.cc
+++ b/components/feature_engagement/internal/in_memory_event_store.cc
@@ -5,6 +5,7 @@
 #include "components/feature_engagement/internal/in_memory_event_store.h"
 
 #include <memory>
+#include <utility>
 #include <vector>
 
 #include "base/bind.h"
@@ -44,7 +45,7 @@
 void InMemoryEventStore::HandleLoadResult(const OnLoadedCallback& callback,
                                           bool success) {
   base::ThreadTaskRunnerHandle::Get()->PostTask(
-      FROM_HERE, base::Bind(callback, success, base::Passed(&events_)));
+      FROM_HERE, base::BindOnce(callback, success, std::move(events_)));
   ready_ = success;
 }
 
diff --git a/components/feedback/feedback_data.cc b/components/feedback/feedback_data.cc
index 5beccf7..c58dce1f 100644
--- a/components/feedback/feedback_data.cc
+++ b/components/feedback/feedback_data.cc
@@ -86,10 +86,10 @@
   ++pending_op_count_;
   base::PostTaskWithTraitsAndReply(
       FROM_HERE, {base::MayBlock(), base::TaskPriority::BACKGROUND},
-      base::Bind(&FeedbackData::CompressFile, this,
-                 base::FilePath(kHistogramsFilename), kHistogramsAttachmentName,
-                 base::Passed(&histograms)),
-      base::Bind(&FeedbackData::OnCompressComplete, this));
+      base::BindOnce(&FeedbackData::CompressFile, this,
+                     base::FilePath(kHistogramsFilename),
+                     kHistogramsAttachmentName, std::move(histograms)),
+      base::BindOnce(&FeedbackData::OnCompressComplete, this));
 }
 
 void FeedbackData::AttachAndCompressFileData(
@@ -103,9 +103,9 @@
                   base::FilePath::FromUTF8Unsafe(attached_filename_);
   base::PostTaskWithTraitsAndReply(
       FROM_HERE, {base::MayBlock(), base::TaskPriority::BACKGROUND},
-      base::Bind(&FeedbackData::CompressFile, this, attached_file,
-                 std::string(), base::Passed(&attached_filedata)),
-      base::Bind(&FeedbackData::OnCompressComplete, this));
+      base::BindOnce(&FeedbackData::CompressFile, this, attached_file,
+                     std::string(), std::move(attached_filedata)),
+      base::BindOnce(&FeedbackData::OnCompressComplete, this));
 }
 
 void FeedbackData::OnGetTraceData(
diff --git a/components/gcm_driver/crypto/BUILD.gn b/components/gcm_driver/crypto/BUILD.gn
index 5ee3c7d..30cda55 100644
--- a/components/gcm_driver/crypto/BUILD.gn
+++ b/components/gcm_driver/crypto/BUILD.gn
@@ -65,6 +65,8 @@
     "//base",
     "//base/test:test_support",
     "//components/gcm_driver/common",
+    "//components/gcm_driver/crypto/proto",
+    "//components/leveldb_proto",
     "//crypto",
     "//crypto:platform",
     "//net:test_support",
diff --git a/components/gcm_driver/crypto/gcm_key_store.cc b/components/gcm_driver/crypto/gcm_key_store.cc
index e269c3ba2..dc621c6 100644
--- a/components/gcm_driver/crypto/gcm_key_store.cc
+++ b/components/gcm_driver/crypto/gcm_key_store.cc
@@ -22,6 +22,9 @@
 
 namespace {
 
+using EntryVectorType =
+    leveldb_proto::ProtoDatabase<EncryptionData>::KeyEntryVector;
+
 // Statistics are logged to UMA with this string as part of histogram name. They
 // can all be found under LevelDB.*.GCMKeyStore. Changing this needs to
 // synchronize with histograms.xml, AND will also become incompatible with older
@@ -164,9 +167,6 @@
   // {Get/Create/Remove}Keys can see them.
   key_data_[app_id][authorized_entity] = {key->Copy(), auth_secret};
 
-  using EntryVectorType =
-      leveldb_proto::ProtoDatabase<EncryptionData>::KeyEntryVector;
-
   std::unique_ptr<EntryVectorType> entries_to_save(new EntryVectorType());
   std::unique_ptr<std::vector<std::string>> keys_to_remove(
       new std::vector<std::string>());
@@ -187,7 +187,7 @@
   UMA_HISTOGRAM_BOOLEAN("GCM.Crypto.CreateKeySuccessRate", success);
 
   if (!success) {
-    LOG(ERROR) << "Unable to store the created key in the GCM Key Store.";
+    DVLOG(1) << "Unable to store the created key in the GCM Key Store.";
 
     // Our cache is now inconsistent. Reject requests until restarted.
     state_ = State::FAILED;
@@ -219,9 +219,6 @@
     return;
   }
 
-  using EntryVectorType =
-      leveldb_proto::ProtoDatabase<EncryptionData>::KeyEntryVector;
-
   std::unique_ptr<EntryVectorType> entries_to_save(new EntryVectorType());
   std::unique_ptr<std::vector<std::string>> keys_to_remove(
       new std::vector<std::string>());
@@ -260,7 +257,7 @@
   UMA_HISTOGRAM_BOOLEAN("GCM.Crypto.RemoveKeySuccessRate", success);
 
   if (!success) {
-    LOG(ERROR) << "Unable to delete a key from the GCM Key Store.";
+    DVLOG(1) << "Unable to delete a key from the GCM Key Store.";
 
     // Our cache is now inconsistent. Reject requests until restarted.
     state_ = State::FAILED;
@@ -269,6 +266,20 @@
   std::move(callback).Run();
 }
 
+void GCMKeyStore::DidUpgradeDatabase(bool success) {
+  UMA_HISTOGRAM_BOOLEAN("GCM.Crypto.GCMDatabaseUpgradeResult", success);
+  if (!success) {
+    DVLOG(1) << "Unable to upgrade the GCM Key Store database.";
+    // Our cache is now inconsistent. Reject requests until restarted.
+    state_ = State::FAILED;
+    delayed_task_controller_.SetReady();
+    return;
+  }
+
+  database_->LoadEntries(
+      base::BindOnce(&GCMKeyStore::DidLoadKeys, weak_factory_.GetWeakPtr()));
+}
+
 void GCMKeyStore::LazyInitialize(base::OnceClosure done_closure) {
   if (delayed_task_controller_.CanRunTaskWithoutDelay()) {
     std::move(done_closure).Run();
@@ -305,6 +316,41 @@
       base::BindOnce(&GCMKeyStore::DidLoadKeys, weak_factory_.GetWeakPtr()));
 }
 
+void GCMKeyStore::UpgradeDatabase(
+    std::unique_ptr<std::vector<EncryptionData>> entries) {
+  std::unique_ptr<EntryVectorType> entries_to_save =
+      std::make_unique<EntryVectorType>();
+  std::unique_ptr<std::vector<std::string>> keys_to_remove =
+      std::make_unique<std::vector<std::string>>();
+
+  // Loop over entries, create list of database entries to overwrite.
+  for (EncryptionData& entry : *entries) {
+    if (!entry.keys_size())
+      continue;
+    std::string decrypted_private_key;
+    if (!DecryptPrivateKey(entry.keys(0).private_key(),
+                           &decrypted_private_key)) {
+      DVLOG(1) << "Unable to decrypt private key: "
+               << entry.keys(0).private_key();
+      state_ = State::FAILED;
+      delayed_task_controller_.SetReady();
+      UMA_HISTOGRAM_BOOLEAN("GCM.Crypto.GCMDatabaseUpgradeResult",
+                            false /* sucess */);
+      return;
+    }
+
+    entry.set_private_key(decrypted_private_key);
+    entry.clear_keys();
+    entries_to_save->push_back(std::make_pair(
+        DatabaseKey(entry.app_id(), entry.authorized_entity()), entry));
+  }
+
+  database_->UpdateEntries(std::move(entries_to_save),
+                           std::move(keys_to_remove),
+                           base::BindOnce(&GCMKeyStore::DidUpgradeDatabase,
+                                          weak_factory_.GetWeakPtr()));
+}
+
 void GCMKeyStore::DidLoadKeys(
     bool success,
     std::unique_ptr<std::vector<EncryptionData>> entries) {
@@ -323,19 +369,18 @@
       authorized_entity = entry.authorized_entity();
     std::unique_ptr<crypto::ECPrivateKey> key;
 
-    // TODO(nator): Remove the old format EncryptionData from the database
-    // and update with the new format.
     // The old format of EncryptionData has a KeyPair in it. Previously
     // we used to cache the key pair and auth secret in key_data_.
     // The new code adds the pair {ECPrivateKey, auth_secret} to
     // key_data_ instead.
     if (entry.keys_size()) {
-      // Old format of EncryptionData. Create an ECPrivateKey from it.
-      std::string private_key_str = entry.keys(0).private_key();
-      key = crypto::ECPrivateKey::CreateFromEncryptedPrivateKeyInfo(
-          std::vector<uint8_t>(
-              private_key_str.data(),
-              private_key_str.data() + private_key_str.size()));
+      if (state_ == State::FAILED)
+        return;
+
+      // Old format of EncryptionData. Upgrade database so there are no such
+      // entries. We'll reload keys from the database once this is done.
+      UpgradeDatabase(std::move(entries));
+      return;
     } else {
       std::string private_key_str = entry.private_key();
       if (private_key_str.empty())
@@ -354,4 +399,20 @@
   delayed_task_controller_.SetReady();
 }
 
+bool GCMKeyStore::DecryptPrivateKey(const std::string& to_decrypt,
+                                    std::string* decrypted) {
+  DCHECK(decrypted);
+  std::vector<uint8_t> to_decrypt_vector(to_decrypt.begin(), to_decrypt.end());
+  std::unique_ptr<crypto::ECPrivateKey> key_to_decrypt =
+      crypto::ECPrivateKey::CreateFromEncryptedPrivateKeyInfo(
+          to_decrypt_vector);
+  if (!key_to_decrypt)
+    return false;
+  std::vector<uint8_t> decrypted_vector;
+  if (!key_to_decrypt->ExportPrivateKey(&decrypted_vector))
+    return false;
+  decrypted->assign(decrypted_vector.begin(), decrypted_vector.end());
+  return true;
+}
+
 }  // namespace gcm
diff --git a/components/gcm_driver/crypto/gcm_key_store.h b/components/gcm_driver/crypto/gcm_key_store.h
index 72d8e78..4ef50bd7 100644
--- a/components/gcm_driver/crypto/gcm_key_store.h
+++ b/components/gcm_driver/crypto/gcm_key_store.h
@@ -80,9 +80,14 @@
                   base::OnceClosure callback);
 
  private:
+  friend class GCMKeyStoreTest;
   // Initializes the database if necessary, and runs |done_closure| when done.
   void LazyInitialize(base::OnceClosure done_closure);
 
+  // Upgrades the stored encryption keys from pairs including deprecated PKCS #8
+  // EncryptedPrivateKeyInfo blocks, to storing a single PrivateKeyInfo block.
+  void UpgradeDatabase(std::unique_ptr<std::vector<EncryptionData>> entries);
+
   void DidInitialize(bool success);
   void DidLoadKeys(bool success,
                    std::unique_ptr<std::vector<EncryptionData>> entries);
@@ -90,6 +95,7 @@
                     const std::string& auth_secret,
                     KeysCallback callback,
                     bool success);
+  void DidUpgradeDatabase(bool success);
 
   void DidRemoveKeys(base::OnceClosure callback, bool success);
 
@@ -107,6 +113,10 @@
                                  const std::string& authorized_entity,
                                  base::OnceClosure callback);
 
+  // Converts private key from old deprecated format (where it is encrypted with
+  // and empty string) to the new format, where it's unencrypted.
+  bool DecryptPrivateKey(const std::string& to_decrypt, std::string* decrypted);
+
   // Path in which the key store database will be saved.
   base::FilePath key_store_path_;
 
diff --git a/components/gcm_driver/crypto/gcm_key_store_unittest.cc b/components/gcm_driver/crypto/gcm_key_store_unittest.cc
index 75c3f96..c17e8cd7 100644
--- a/components/gcm_driver/crypto/gcm_key_store_unittest.cc
+++ b/components/gcm_driver/crypto/gcm_key_store_unittest.cc
@@ -6,16 +6,20 @@
 
 #include <string>
 
+#include "base/base64url.h"
 #include "base/bind.h"
 #include "base/bind_helpers.h"
 #include "base/files/scoped_temp_dir.h"
 #include "base/logging.h"
 #include "base/message_loop/message_loop.h"
 #include "base/run_loop.h"
+#include "base/strings/string_util.h"
 #include "base/test/gtest_util.h"
 #include "base/test/histogram_tester.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "components/gcm_driver/crypto/p256_key_util.h"
+#include "components/leveldb_proto/proto_database.h"
+#include "crypto/random.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace gcm {
@@ -23,11 +27,32 @@
 namespace {
 
 using ECPrivateKeyUniquePtr = std::unique_ptr<crypto::ECPrivateKey>;
+using EncryptDataVectorUniquePtr = std::unique_ptr<std::vector<EncryptionData>>;
+using EntryVectorType =
+    leveldb_proto::ProtoDatabase<EncryptionData>::KeyEntryVector;
 
 const char kFakeAppId[] = "my_app_id";
 const char kSecondFakeAppId[] = "my_other_app_id";
 const char kFakeAuthorizedEntity[] = "my_sender_id";
 const char kSecondFakeAuthorizedEntity[] = "my_other_sender_id";
+const char kPrivateEncrypted[] =
+    "MIGxMBwGCiqGSIb3DQEMAQMwDgQIh9aZ3UvuDloCAggABIGQZ-T8CJZe-no4mOTDgX1Gm986"
+    "Gsbe3mjJeABhA4KOmut_qJh5kt_DLqdNShiQr-afk3AdkX-fxLZdrcHiW9aWvBjnMAY65zg5"
+    "oHsuUaoEuG88Ksbku2u193OENWTQTsYaYE2O44qmRfsX773UNVcWXg_omwIbhbgf6tLZUZH_"
+    "dTC3YjzuxjbSP89HPEJ-eBXA";
+const char kPrivateDecrypted[] =
+    "MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgnCScek-QpEjmOOlT-rQ38nZz"
+    "vdPlqa00Zy0i6m2OJvahRANCAATaEQ22_OCRpvIOWeQhcbq0qrF1iddSLX1xFmFSxPOWOwmJ"
+    "A417CBHOGqsWGkNRvAapFwiegz6Q61rXVo_5roB1";
+const char kPublicKey[] =
+    "BNoRDbb84JGm8g5Z5CFxurSqsXWJ11ItfXEWYVLE85Y7CYkDjXsIEc4aqxYaQ1G8BqkXCJ6D"
+    "PpDrWtdWj_mugHU";
+
+// Number of cryptographically secure random bytes to generate as a key pair's
+// authentication secret. Must be at least 16 bytes.
+const size_t kAuthSecretBytes = 16;
+
+}  // namespace
 
 class GCMKeyStoreTest : public ::testing::Test {
  public:
@@ -57,16 +82,68 @@
   // Callback to use with GCMKeyStore::{GetKeys, CreateKeys} calls.
   void GotKeys(ECPrivateKeyUniquePtr* key_out,
                std::string* auth_secret_out,
+               const base::Closure& quit_closure,
                ECPrivateKeyUniquePtr key,
                const std::string& auth_secret) {
     *key_out = std::move(key);
     *auth_secret_out = auth_secret;
+    if (quit_closure)
+      quit_closure.Run();
+  }
+
+  void AddOldFormatEncryptionDataToKeyStoreDatabase(
+      const std::string& app_id,
+      const std::string& authorized_entity) {
+    EncryptionData encryption_data;
+    encryption_data.set_app_id(app_id);
+    encryption_data.set_authorized_entity(authorized_entity);
+
+    // Create the authentication secret, which has to be a cryptographically
+    // secure random number of at least 128 bits (16 bytes).
+    std::string auth_secret;
+    crypto::RandBytes(base::WriteInto(&auth_secret, kAuthSecretBytes + 1),
+                      kAuthSecretBytes);
+    encryption_data.set_auth_secret(auth_secret);
+
+    // Add keys.
+    KeyPair* pair = encryption_data.add_keys();
+    pair->set_type(KeyPair::ECDH_P256);
+    std::string private_key;
+    ASSERT_TRUE(base::Base64UrlDecode(
+        kPrivateEncrypted, base::Base64UrlDecodePolicy::IGNORE_PADDING,
+        &private_key));
+    pair->set_private_key(private_key);
+    std::string public_key;
+    ASSERT_TRUE(base::Base64UrlDecode(
+        kPublicKey, base::Base64UrlDecodePolicy::IGNORE_PADDING, &public_key));
+    pair->set_public_key(public_key);
+
+    // Add this to database.
+    std::unique_ptr<EntryVectorType> entries_to_save =
+        std::make_unique<EntryVectorType>();
+    std::unique_ptr<std::vector<std::string>> keys_to_remove =
+        std::make_unique<std::vector<std::string>>();
+    entries_to_save->push_back(std::make_pair(
+        encryption_data.app_id() + ',' + encryption_data.authorized_entity(),
+        encryption_data));
+    base::RunLoop run_loop;
+    gcm_key_store_->database_->UpdateEntries(
+        std::move(entries_to_save), std::move(keys_to_remove),
+        base::BindOnce(&GCMKeyStoreTest::UpdatedEntries, base::Unretained(this),
+                       run_loop.QuitClosure()));
+    run_loop.Run();
   }
 
  protected:
   GCMKeyStore* gcm_key_store() { return gcm_key_store_.get(); }
   base::HistogramTester* histogram_tester() { return &histogram_tester_; }
 
+  void UpdatedEntries(const base::Closure& quit_closure, bool success) {
+    EXPECT_TRUE(success);
+    if (quit_closure)
+      quit_closure.Run();
+  }
+
  private:
   base::MessageLoop message_loop_;
   base::ScopedTempDir scoped_temp_dir_;
@@ -83,13 +160,14 @@
 
   ECPrivateKeyUniquePtr key;
   std::string auth_secret;
+  base::RunLoop run_loop;
   gcm_key_store()->GetKeys(
       kFakeAppId, kFakeAuthorizedEntity,
       false /* fallback_to_empty_authorized_entity */,
       base::BindOnce(&GCMKeyStoreTest::GotKeys, base::Unretained(this), &key,
-                     &auth_secret));
+                     &auth_secret, run_loop.QuitClosure()));
 
-  base::RunLoop().RunUntilIdle();
+  run_loop.Run();
 
   ASSERT_FALSE(key);
   EXPECT_EQ(0u, auth_secret.size());
@@ -101,12 +179,13 @@
 TEST_F(GCMKeyStoreTest, CreateAndGetKeys) {
   ECPrivateKeyUniquePtr key;
   std::string auth_secret;
+  base::RunLoop run_loop;
   gcm_key_store()->CreateKeys(
       kFakeAppId, kFakeAuthorizedEntity,
       base::BindOnce(&GCMKeyStoreTest::GotKeys, base::Unretained(this), &key,
-                     &auth_secret));
+                     &auth_secret, run_loop.QuitClosure()));
 
-  base::RunLoop().RunUntilIdle();
+  run_loop.Run();
 
   ASSERT_TRUE(key);
   std::string public_key, private_key;
@@ -122,13 +201,15 @@
 
   ECPrivateKeyUniquePtr read_key;
   std::string read_auth_secret;
+  base::RunLoop first_get_run_loop;
   gcm_key_store()->GetKeys(
       kFakeAppId, kFakeAuthorizedEntity,
       false /* fallback_to_empty_authorized_entity */,
       base::BindOnce(&GCMKeyStoreTest::GotKeys, base::Unretained(this),
-                     &read_key, &read_auth_secret));
+                     &read_key, &read_auth_secret,
+                     first_get_run_loop.QuitClosure()));
 
-  base::RunLoop().RunUntilIdle();
+  first_get_run_loop.Run();
 
   ASSERT_TRUE(read_key);
   std::string read_public_key, read_private_key;
@@ -143,13 +224,15 @@
 
   // GetKey should also succeed if fallback_to_empty_authorized_entity is true
   // (fallback should not occur, since an exact match is found).
+  base::RunLoop second_get_run_loop;
   gcm_key_store()->GetKeys(
       kFakeAppId, kFakeAuthorizedEntity,
       true /* fallback_to_empty_authorized_entity */,
       base::BindOnce(&GCMKeyStoreTest::GotKeys, base::Unretained(this),
-                     &read_key, &read_auth_secret));
+                     &read_key, &read_auth_secret,
+                     second_get_run_loop.QuitClosure()));
 
-  base::RunLoop().RunUntilIdle();
+  second_get_run_loop.Run();
 
   ASSERT_TRUE(read_key);
 
@@ -166,12 +249,15 @@
 TEST_F(GCMKeyStoreTest, GetKeysFallback) {
   ECPrivateKeyUniquePtr key;
   std::string auth_secret;
-  gcm_key_store()->CreateKeys(
-      kFakeAppId, "" /* empty authorized entity for non-InstanceID */,
-      base::BindOnce(&GCMKeyStoreTest::GotKeys, base::Unretained(this), &key,
-                     &auth_secret));
+  {
+    base::RunLoop run_loop;
+    gcm_key_store()->CreateKeys(
+        kFakeAppId, "" /* empty authorized entity for non-InstanceID */,
+        base::BindOnce(&GCMKeyStoreTest::GotKeys, base::Unretained(this), &key,
+                       &auth_secret, run_loop.QuitClosure()));
 
-  base::RunLoop().RunUntilIdle();
+    run_loop.Run();
+  }
 
   ASSERT_TRUE(key);
 
@@ -190,13 +276,16 @@
   // there is not an exact match for kFakeAuthorizedEntity.
   ECPrivateKeyUniquePtr read_key;
   std::string read_auth_secret;
-  gcm_key_store()->GetKeys(
-      kFakeAppId, kFakeAuthorizedEntity,
-      false /* fallback_to_empty_authorized_entity */,
-      base::BindOnce(&GCMKeyStoreTest::GotKeys, base::Unretained(this),
-                     &read_key, &read_auth_secret));
+  {
+    base::RunLoop run_loop;
+    gcm_key_store()->GetKeys(
+        kFakeAppId, kFakeAuthorizedEntity,
+        false /* fallback_to_empty_authorized_entity */,
+        base::BindOnce(&GCMKeyStoreTest::GotKeys, base::Unretained(this),
+                       &read_key, &read_auth_secret, run_loop.QuitClosure()));
 
-  base::RunLoop().RunUntilIdle();
+    run_loop.Run();
+  }
 
   ASSERT_FALSE(read_key);
   EXPECT_EQ(0u, read_auth_secret.size());
@@ -206,13 +295,16 @@
 
   // GetKey should succeed when fallback_to_empty_authorized_entity is true, as
   // falling back to empty authorized entity will match the created key.
-  gcm_key_store()->GetKeys(
-      kFakeAppId, kFakeAuthorizedEntity,
-      true /* fallback_to_empty_authorized_entity */,
-      base::BindOnce(&GCMKeyStoreTest::GotKeys, base::Unretained(this),
-                     &read_key, &read_auth_secret));
+  {
+    base::RunLoop run_loop;
+    gcm_key_store()->GetKeys(
+        kFakeAppId, kFakeAuthorizedEntity,
+        true /* fallback_to_empty_authorized_entity */,
+        base::BindOnce(&GCMKeyStoreTest::GotKeys, base::Unretained(this),
+                       &read_key, &read_auth_secret, run_loop.QuitClosure()));
 
-  base::RunLoop().RunUntilIdle();
+    run_loop.Run();
+  }
 
   ASSERT_TRUE(read_key);
 
@@ -231,12 +323,15 @@
 TEST_F(GCMKeyStoreTest, KeysPersistenceBetweenInstances) {
   ECPrivateKeyUniquePtr key;
   std::string auth_secret;
-  gcm_key_store()->CreateKeys(
-      kFakeAppId, kFakeAuthorizedEntity,
-      base::BindOnce(&GCMKeyStoreTest::GotKeys, base::Unretained(this), &key,
-                     &auth_secret));
+  {
+    base::RunLoop run_loop;
+    gcm_key_store()->CreateKeys(
+        kFakeAppId, kFakeAuthorizedEntity,
+        base::BindOnce(&GCMKeyStoreTest::GotKeys, base::Unretained(this), &key,
+                       &auth_secret, run_loop.QuitClosure()));
 
-  base::RunLoop().RunUntilIdle();
+    run_loop.Run();
+  }
 
   ASSERT_TRUE(key);
 
@@ -250,13 +345,16 @@
 
   ECPrivateKeyUniquePtr read_key;
   std::string read_auth_secret;
-  gcm_key_store()->GetKeys(
-      kFakeAppId, kFakeAuthorizedEntity,
-      false /* fallback_to_empty_authorized_entity */,
-      base::BindOnce(&GCMKeyStoreTest::GotKeys, base::Unretained(this),
-                     &read_key, &read_auth_secret));
+  {
+    base::RunLoop run_loop;
+    gcm_key_store()->GetKeys(
+        kFakeAppId, kFakeAuthorizedEntity,
+        false /* fallback_to_empty_authorized_entity */,
+        base::BindOnce(&GCMKeyStoreTest::GotKeys, base::Unretained(this),
+                       &read_key, &read_auth_secret, run_loop.QuitClosure()));
 
-  base::RunLoop().RunUntilIdle();
+    run_loop.Run();
+  }
 
   ASSERT_TRUE(read_key);
   EXPECT_GT(read_auth_secret.size(), 0u);
@@ -270,24 +368,30 @@
 TEST_F(GCMKeyStoreTest, CreateAndRemoveKeys) {
   ECPrivateKeyUniquePtr key;
   std::string auth_secret;
-  gcm_key_store()->CreateKeys(
-      kFakeAppId, kFakeAuthorizedEntity,
-      base::BindOnce(&GCMKeyStoreTest::GotKeys, base::Unretained(this), &key,
-                     &auth_secret));
+  {
+    base::RunLoop run_loop;
+    gcm_key_store()->CreateKeys(
+        kFakeAppId, kFakeAuthorizedEntity,
+        base::BindOnce(&GCMKeyStoreTest::GotKeys, base::Unretained(this), &key,
+                       &auth_secret, run_loop.QuitClosure()));
 
-  base::RunLoop().RunUntilIdle();
+    run_loop.Run();
+  }
 
   ASSERT_TRUE(key);
 
   ECPrivateKeyUniquePtr read_key;
   std::string read_auth_secret;
-  gcm_key_store()->GetKeys(
-      kFakeAppId, kFakeAuthorizedEntity,
-      false /* fallback_to_empty_authorized_entity */,
-      base::BindOnce(&GCMKeyStoreTest::GotKeys, base::Unretained(this),
-                     &read_key, &read_auth_secret));
+  {
+    base::RunLoop run_loop;
+    gcm_key_store()->GetKeys(
+        kFakeAppId, kFakeAuthorizedEntity,
+        false /* fallback_to_empty_authorized_entity */,
+        base::BindOnce(&GCMKeyStoreTest::GotKeys, base::Unretained(this),
+                       &read_key, &read_auth_secret, run_loop.QuitClosure()));
 
-  base::RunLoop().RunUntilIdle();
+    run_loop.Run();
+  }
 
   ASSERT_TRUE(read_key);
 
@@ -299,13 +403,16 @@
   histogram_tester()->ExpectBucketCount(
       "GCM.Crypto.RemoveKeySuccessRate", 1, 1);  // success
 
-  gcm_key_store()->GetKeys(
-      kFakeAppId, kFakeAuthorizedEntity,
-      false /* fallback_to_empty_authorized_entity */,
-      base::BindOnce(&GCMKeyStoreTest::GotKeys, base::Unretained(this),
-                     &read_key, &read_auth_secret));
+  {
+    base::RunLoop run_loop;
+    gcm_key_store()->GetKeys(
+        kFakeAppId, kFakeAuthorizedEntity,
+        false /* fallback_to_empty_authorized_entity */,
+        base::BindOnce(&GCMKeyStoreTest::GotKeys, base::Unretained(this),
+                       &read_key, &read_auth_secret, run_loop.QuitClosure()));
 
-  base::RunLoop().RunUntilIdle();
+    run_loop.Run();
+  }
 
   ASSERT_FALSE(read_key);
 }
@@ -316,7 +423,7 @@
   gcm_key_store()->CreateKeys(
       kFakeAppId, kFakeAuthorizedEntity,
       base::BindOnce(&GCMKeyStoreTest::GotKeys, base::Unretained(this), &key,
-                     &auth_secret));
+                     &auth_secret, base::Closure()));
 
   // Continue synchronously, without running RunUntilIdle first.
   ECPrivateKeyUniquePtr key_after_create;
@@ -325,7 +432,8 @@
       kFakeAppId, kFakeAuthorizedEntity,
       false /* fallback_to_empty_authorized_entity */,
       base::BindOnce(&GCMKeyStoreTest::GotKeys, base::Unretained(this),
-                     &key_after_create, &auth_secret_after_create));
+                     &key_after_create, &auth_secret_after_create,
+                     base::Closure()));
 
   // Continue synchronously, without running RunUntilIdle first.
   gcm_key_store()->RemoveKeys(kFakeAppId, kFakeAuthorizedEntity,
@@ -338,7 +446,8 @@
       kFakeAppId, kFakeAuthorizedEntity,
       false /* fallback_to_empty_authorized_entity */,
       base::BindOnce(&GCMKeyStoreTest::GotKeys, base::Unretained(this),
-                     &key_after_remove, &auth_secret_after_remove));
+                     &key_after_remove, &auth_secret_after_remove,
+                     base::Closure()));
 
   base::RunLoop().RunUntilIdle();
 
@@ -351,7 +460,8 @@
       kFakeAppId, kFakeAuthorizedEntity,
       false /* fallback_to_empty_authorized_entity */,
       base::BindOnce(&GCMKeyStoreTest::GotKeys, base::Unretained(this),
-                     &key_after_idle, &auth_secret_after_idle));
+                     &key_after_idle, &auth_secret_after_idle,
+                     base::Closure()));
 
   base::RunLoop().RunUntilIdle();
 
@@ -377,15 +487,15 @@
   gcm_key_store()->CreateKeys(
       kFakeAppId, kFakeAuthorizedEntity,
       base::BindOnce(&GCMKeyStoreTest::GotKeys, base::Unretained(this), &key1,
-                     &auth_secret1));
+                     &auth_secret1, base::Closure()));
   gcm_key_store()->CreateKeys(
       kFakeAppId, kSecondFakeAuthorizedEntity,
       base::BindOnce(&GCMKeyStoreTest::GotKeys, base::Unretained(this), &key2,
-                     &auth_secret2));
+                     &auth_secret2, base::Closure()));
   gcm_key_store()->CreateKeys(
       kSecondFakeAppId, kFakeAuthorizedEntity,
       base::BindOnce(&GCMKeyStoreTest::GotKeys, base::Unretained(this), &key3,
-                     &auth_secret3));
+                     &auth_secret3, base::Closure()));
 
   base::RunLoop().RunUntilIdle();
 
@@ -399,17 +509,17 @@
       kFakeAppId, kFakeAuthorizedEntity,
       false /* fallback_to_empty_authorized_entity */,
       base::BindOnce(&GCMKeyStoreTest::GotKeys, base::Unretained(this),
-                     &read_key1, &read_auth_secret1));
+                     &read_key1, &read_auth_secret1, base::Closure()));
   gcm_key_store()->GetKeys(
       kFakeAppId, kSecondFakeAuthorizedEntity,
       false /* fallback_to_empty_authorized_entity */,
       base::BindOnce(&GCMKeyStoreTest::GotKeys, base::Unretained(this),
-                     &read_key2, &read_auth_secret2));
+                     &read_key2, &read_auth_secret2, base::Closure()));
   gcm_key_store()->GetKeys(
       kSecondFakeAppId, kFakeAuthorizedEntity,
       false /* fallback_to_empty_authorized_entity */,
       base::BindOnce(&GCMKeyStoreTest::GotKeys, base::Unretained(this),
-                     &read_key3, &read_auth_secret3));
+                     &read_key3, &read_auth_secret3, base::Closure()));
 
   base::RunLoop().RunUntilIdle();
 
@@ -429,17 +539,17 @@
       kFakeAppId, kFakeAuthorizedEntity,
       false /* fallback_to_empty_authorized_entity */,
       base::BindOnce(&GCMKeyStoreTest::GotKeys, base::Unretained(this),
-                     &read_key1, &read_auth_secret1));
+                     &read_key1, &read_auth_secret1, base::Closure()));
   gcm_key_store()->GetKeys(
       kFakeAppId, kSecondFakeAuthorizedEntity,
       false /* fallback_to_empty_authorized_entity */,
       base::BindOnce(&GCMKeyStoreTest::GotKeys, base::Unretained(this),
-                     &read_key2, &read_auth_secret2));
+                     &read_key2, &read_auth_secret2, base::Closure()));
   gcm_key_store()->GetKeys(
       kSecondFakeAppId, kFakeAuthorizedEntity,
       false /* fallback_to_empty_authorized_entity */,
       base::BindOnce(&GCMKeyStoreTest::GotKeys, base::Unretained(this),
-                     &read_key3, &read_auth_secret3));
+                     &read_key3, &read_auth_secret3, base::Closure()));
 
   base::RunLoop().RunUntilIdle();
 
@@ -451,33 +561,42 @@
 TEST_F(GCMKeyStoreTest, GetKeysMultipleAppIds) {
   ECPrivateKeyUniquePtr key;
   std::string auth_secret;
-  gcm_key_store()->CreateKeys(
-      kFakeAppId, kFakeAuthorizedEntity,
-      base::BindOnce(&GCMKeyStoreTest::GotKeys, base::Unretained(this), &key,
-                     &auth_secret));
+  {
+    base::RunLoop run_loop;
+    gcm_key_store()->CreateKeys(
+        kFakeAppId, kFakeAuthorizedEntity,
+        base::BindOnce(&GCMKeyStoreTest::GotKeys, base::Unretained(this), &key,
+                       &auth_secret, run_loop.QuitClosure()));
 
-  base::RunLoop().RunUntilIdle();
+    run_loop.Run();
+  }
 
   ASSERT_TRUE(key);
 
-  gcm_key_store()->CreateKeys(
-      kSecondFakeAppId, kSecondFakeAuthorizedEntity,
-      base::BindOnce(&GCMKeyStoreTest::GotKeys, base::Unretained(this), &key,
-                     &auth_secret));
+  {
+    base::RunLoop run_loop;
+    gcm_key_store()->CreateKeys(
+        kSecondFakeAppId, kSecondFakeAuthorizedEntity,
+        base::BindOnce(&GCMKeyStoreTest::GotKeys, base::Unretained(this), &key,
+                       &auth_secret, run_loop.QuitClosure()));
 
-  base::RunLoop().RunUntilIdle();
+    run_loop.Run();
+  }
 
   ASSERT_TRUE(key);
 
   ECPrivateKeyUniquePtr read_key;
   std::string read_auth_secret;
-  gcm_key_store()->GetKeys(
-      kFakeAppId, kFakeAuthorizedEntity,
-      false /* fallback_to_empty_authorized_entity */,
-      base::BindOnce(&GCMKeyStoreTest::GotKeys, base::Unretained(this),
-                     &read_key, &read_auth_secret));
+  {
+    base::RunLoop run_loop;
+    gcm_key_store()->GetKeys(
+        kFakeAppId, kFakeAuthorizedEntity,
+        false /* fallback_to_empty_authorized_entity */,
+        base::BindOnce(&GCMKeyStoreTest::GotKeys, base::Unretained(this),
+                       &read_key, &read_auth_secret, run_loop.QuitClosure()));
 
-  base::RunLoop().RunUntilIdle();
+    run_loop.Run();
+  }
 
   ASSERT_TRUE(read_key);
 }
@@ -488,7 +607,7 @@
   gcm_key_store()->CreateKeys(
       kFakeAppId, kFakeAuthorizedEntity,
       base::BindOnce(&GCMKeyStoreTest::GotKeys, base::Unretained(this), &key,
-                     &auth_secret));
+                     &auth_secret, base::Closure()));
 
   // Deliberately do not run the message loop, so that the callback has not
   // been resolved yet. The following EXPECT() ensures this.
@@ -500,7 +619,7 @@
       kFakeAppId, kFakeAuthorizedEntity,
       false /* fallback_to_empty_authorized_entity */,
       base::BindOnce(&GCMKeyStoreTest::GotKeys, base::Unretained(this),
-                     &read_key, &read_auth_secret));
+                     &read_key, &read_auth_secret, base::Closure()));
 
   EXPECT_FALSE(read_key);
 
@@ -515,50 +634,140 @@
 TEST_F(GCMKeyStoreTest, CannotShareAppIdFromGCMToInstanceID) {
   ECPrivateKeyUniquePtr key_unused;
   std::string auth_secret_unused;
-  gcm_key_store()->CreateKeys(
-      kFakeAppId, "" /* empty authorized entity for non-InstanceID */,
-      base::BindOnce(&GCMKeyStoreTest::GotKeys, base::Unretained(this),
-                     &key_unused, &auth_secret_unused));
+  {
+    base::RunLoop run_loop;
+    gcm_key_store()->CreateKeys(
+        kFakeAppId, "" /* empty authorized entity for non-InstanceID */,
+        base::BindOnce(&GCMKeyStoreTest::GotKeys, base::Unretained(this),
+                       &key_unused, &auth_secret_unused,
+                       run_loop.QuitClosure()));
 
-  base::RunLoop().RunUntilIdle();
+    run_loop.Run();
+  }
 
   EXPECT_DCHECK_DEATH({
+    base::RunLoop run_loop;
     gcm_key_store()->CreateKeys(
         kFakeAppId, kFakeAuthorizedEntity,
         base::BindOnce(&GCMKeyStoreTest::GotKeys, base::Unretained(this),
-                       &key_unused, &auth_secret_unused));
+                       &key_unused, &auth_secret_unused,
+                       run_loop.QuitClosure()));
 
-    base::RunLoop().RunUntilIdle();
+    run_loop.Run();
   });
 }
 
 TEST_F(GCMKeyStoreTest, CannotShareAppIdFromInstanceIDToGCM) {
   ECPrivateKeyUniquePtr key_unused;
   std::string auth_secret_unused;
-  gcm_key_store()->CreateKeys(
-      kFakeAppId, kFakeAuthorizedEntity,
-      base::BindOnce(&GCMKeyStoreTest::GotKeys, base::Unretained(this),
-                     &key_unused, &auth_secret_unused));
+  {
+    base::RunLoop run_loop;
+    gcm_key_store()->CreateKeys(
+        kFakeAppId, kFakeAuthorizedEntity,
+        base::BindOnce(&GCMKeyStoreTest::GotKeys, base::Unretained(this),
+                       &key_unused, &auth_secret_unused,
+                       run_loop.QuitClosure()));
 
-  base::RunLoop().RunUntilIdle();
+    run_loop.Run();
+  }
 
-  gcm_key_store()->CreateKeys(
-      kFakeAppId, kSecondFakeAuthorizedEntity,
-      base::BindOnce(&GCMKeyStoreTest::GotKeys, base::Unretained(this),
-                     &key_unused, &auth_secret_unused));
+  {
+    base::RunLoop run_loop;
+    gcm_key_store()->CreateKeys(
+        kFakeAppId, kSecondFakeAuthorizedEntity,
+        base::BindOnce(&GCMKeyStoreTest::GotKeys, base::Unretained(this),
+                       &key_unused, &auth_secret_unused,
+                       run_loop.QuitClosure()));
 
-  base::RunLoop().RunUntilIdle();
+    run_loop.Run();
+  }
 
   EXPECT_DCHECK_DEATH({
+    base::RunLoop run_loop;
     gcm_key_store()->CreateKeys(
         kFakeAppId, "" /* empty authorized entity for non-InstanceID */,
         base::BindOnce(&GCMKeyStoreTest::GotKeys, base::Unretained(this),
-                       &key_unused, &auth_secret_unused));
+                       &key_unused, &auth_secret_unused,
+                       run_loop.QuitClosure()));
 
-    base::RunLoop().RunUntilIdle();
+    run_loop.Run();
   });
 }
 
-}  // namespace
+TEST_F(GCMKeyStoreTest, TestUpgradePathForKeyStorageDeprecation) {
+  // Expect Upgrade count to  be 0.
+  histogram_tester()->ExpectTotalCount("GCM.Crypto.GCMDatabaseUpgradeResult",
+                                       0);
+  // Initialize GCM store and the underlying levelDB database by trying
+  // to fetch keys.
+  ECPrivateKeyUniquePtr key;
+  std::string auth_secret;
+  {
+    base::RunLoop run_loop;
+    gcm_key_store()->GetKeys(
+        kFakeAppId, kFakeAuthorizedEntity,
+        false /* fallback_to_empty_authorized_entity */,
+        base::BindOnce(&GCMKeyStoreTest::GotKeys, base::Unretained(this), &key,
+                       &auth_secret, run_loop.QuitClosure()));
+
+    run_loop.Run();
+  }
+  ASSERT_FALSE(key);
+  histogram_tester()->ExpectTotalCount("GCM.Crypto.GCMDatabaseUpgradeResult",
+                                       0);
+
+  // Add old format Encryption Data.
+  ASSERT_NO_FATAL_FAILURE(AddOldFormatEncryptionDataToKeyStoreDatabase(
+      kFakeAppId, kFakeAuthorizedEntity));
+
+  // Create a new GCM Key Store instance, so we can initialize again.
+  CreateKeyStore();
+
+  // GetKeys again, verify private key is decrypted and we have upgraded
+  // database exactly once
+  {
+    base::RunLoop run_loop;
+    gcm_key_store()->GetKeys(
+        kFakeAppId, kFakeAuthorizedEntity,
+        false /* fallback_to_empty_authorized_entity */,
+        base::BindOnce(&GCMKeyStoreTest::GotKeys, base::Unretained(this), &key,
+                       &auth_secret, run_loop.QuitClosure()));
+    run_loop.Run();
+  }
+
+  histogram_tester()->ExpectBucketCount("GCM.Crypto.GCMDatabaseUpgradeResult",
+                                        1, 1);
+  ASSERT_TRUE(key);
+  ASSERT_GT(auth_secret.size(), 0u);
+
+  // Verify also that the private key is decrypted.
+  std::string read_private_key;
+  ASSERT_TRUE(GetRawPrivateKey(*key, &read_private_key));
+  std::string decrypted_private_key;
+  ASSERT_TRUE(base::Base64UrlDecode(kPrivateDecrypted,
+                                    base::Base64UrlDecodePolicy::IGNORE_PADDING,
+                                    &decrypted_private_key));
+  ASSERT_EQ(decrypted_private_key, read_private_key);
+
+  // AddOldFormatEncryptionDataToKeyStoreDatabase() again, different keys
+  ASSERT_NO_FATAL_FAILURE(AddOldFormatEncryptionDataToKeyStoreDatabase(
+      kSecondFakeAppId, kSecondFakeAuthorizedEntity));
+
+  // GetKeys on this one, should return nullptr
+  {
+    base::RunLoop run_loop;
+    gcm_key_store()->GetKeys(
+        kSecondFakeAppId, kSecondFakeAuthorizedEntity,
+        false /* fallback_to_empty_authorized_entity */,
+        base::BindOnce(&GCMKeyStoreTest::GotKeys, base::Unretained(this), &key,
+                       &auth_secret, run_loop.QuitClosure()));
+    run_loop.Run();
+  }
+  ASSERT_FALSE(key);
+  ASSERT_EQ(auth_secret.size(), 0u);
+  // GCMDatabaseUpgradeResult should not have increased.
+  histogram_tester()->ExpectBucketCount("GCM.Crypto.GCMDatabaseUpgradeResult",
+                                        1, 1);
+}
 
 }  // namespace gcm
diff --git a/components/gcm_driver/crypto/proto/BUILD.gn b/components/gcm_driver/crypto/proto/BUILD.gn
index b6d951c9..975000a 100644
--- a/components/gcm_driver/crypto/proto/BUILD.gn
+++ b/components/gcm_driver/crypto/proto/BUILD.gn
@@ -5,7 +5,10 @@
 import("//third_party/protobuf/proto_library.gni")
 
 proto_library("proto") {
-  visibility = [ "//components/gcm_driver/crypto" ]
+  visibility = [
+    "//components/gcm_driver/crypto:crypto",
+    "//components/gcm_driver/crypto:unit_tests",
+  ]
 
   sources = [
     "gcm_encryption_data.proto",
diff --git a/components/gcm_driver/gcm_driver_desktop.cc b/components/gcm_driver/gcm_driver_desktop.cc
index ec3d80b..b891f72d 100644
--- a/components/gcm_driver/gcm_driver_desktop.cc
+++ b/components/gcm_driver/gcm_driver_desktop.cc
@@ -552,13 +552,10 @@
   io_worker_.reset(new IOWorker(ui_thread, io_thread));
   io_thread_->PostTask(
       FROM_HERE,
-      base::Bind(&GCMDriverDesktop::IOWorker::Initialize,
-                 base::Unretained(io_worker_.get()),
-                 base::Passed(&gcm_client_factory),
-                 chrome_build_info,
-                 store_path,
-                 request_context,
-                 blocking_task_runner));
+      base::BindOnce(&GCMDriverDesktop::IOWorker::Initialize,
+                     base::Unretained(io_worker_.get()),
+                     std::move(gcm_client_factory), chrome_build_info,
+                     store_path, request_context, blocking_task_runner));
 }
 
 GCMDriverDesktop::~GCMDriverDesktop() {
diff --git a/components/grpc_support/bidirectional_stream.cc b/components/grpc_support/bidirectional_stream.cc
index 9e0ff9d6..814e9ec 100644
--- a/components/grpc_support/bidirectional_stream.cc
+++ b/components/grpc_support/bidirectional_stream.cc
@@ -102,7 +102,7 @@
   write_end_of_stream_ = end_of_stream;
   PostToNetworkThread(FROM_HERE,
                       base::BindOnce(&BidirectionalStream::StartOnNetworkThread,
-                                     weak_this_, base::Passed(&request_info)));
+                                     weak_this_, std::move(request_info)));
   return 0;
 }
 
diff --git a/components/history/core/browser/history_model_worker.cc b/components/history/core/browser/history_model_worker.cc
index 2d1b46a43..155e526e 100644
--- a/components/history/core/browser/history_model_worker.cc
+++ b/components/history/core/browser/history_model_worker.cc
@@ -79,9 +79,9 @@
 }
 
 void HistoryModelWorker::ScheduleWork(base::OnceClosure work) {
-  ui_thread_->PostTask(FROM_HERE, base::Bind(&PostWorkerTask, history_service_,
-                                             base::Passed(std::move(work)),
-                                             cancelable_tracker_.get()));
+  ui_thread_->PostTask(
+      FROM_HERE, base::BindOnce(&PostWorkerTask, history_service_,
+                                std::move(work), cancelable_tracker_.get()));
 }
 
 }  // namespace browser_sync
diff --git a/components/history/core/browser/history_model_worker_unittest.cc b/components/history/core/browser/history_model_worker_unittest.cc
index 016edcb..be48908 100644
--- a/components/history/core/browser/history_model_worker_unittest.cc
+++ b/components/history/core/browser/history_model_worker_unittest.cc
@@ -35,10 +35,11 @@
     history::HistoryDBTask* task_raw = task.get();
     history_thread_->PostTaskAndReply(
         from_here,
-        base::Bind(base::IgnoreResult(&history::HistoryDBTask::RunOnDBThread),
-                   base::Unretained(task_raw), nullptr, nullptr),
-        base::Bind(&history::HistoryDBTask::DoneRunOnMainThread,
-                   base::Passed(std::move(task))));
+        base::BindOnce(
+            base::IgnoreResult(&history::HistoryDBTask::RunOnDBThread),
+            base::Unretained(task_raw), nullptr, nullptr),
+        base::BindOnce(&history::HistoryDBTask::DoneRunOnMainThread,
+                       std::move(task)));
     return base::CancelableTaskTracker::kBadTaskId;  // Unused.
   }
 
@@ -79,9 +80,9 @@
   void DoWorkAndWaitUntilDoneOnSyncThread(base::Closure work) {
     sync_thread_.task_runner()->PostTask(
         FROM_HERE,
-        base::Bind(
+        base::BindOnce(
             base::IgnoreResult(&HistoryModelWorker::DoWorkAndWaitUntilDone),
-            worker_, base::Passed(ClosureToWorkCallback(work))));
+            worker_, ClosureToWorkCallback(work)));
     sync_thread_.task_runner()->PostTask(
         FROM_HERE, base::Bind(&base::AtomicFlag::Set,
                               base::Unretained(&sync_thread_unblocked_)));
diff --git a/components/history/core/browser/history_service.cc b/components/history/core/browser/history_service.cc
index 8bbf61a..e01f2c1 100644
--- a/components/history/core/browser/history_service.cc
+++ b/components/history/core/browser/history_service.cc
@@ -124,8 +124,8 @@
       std::unique_ptr<InMemoryHistoryBackend> backend) override {
     // Send the backend to the history service on the main thread.
     service_task_runner_->PostTask(
-        FROM_HERE, base::Bind(&HistoryService::SetInMemoryBackend,
-                              history_service_, base::Passed(&backend)));
+        FROM_HERE, base::BindOnce(&HistoryService::SetInMemoryBackend,
+                                  history_service_, std::move(backend)));
   }
 
   void NotifyFaviconsChanged(const std::set<GURL>& page_urls,
@@ -318,9 +318,10 @@
   // the current message loop so that we can forward the call to the method
   // HistoryDBTask::DoneRunOnMainThread() in the correct thread.
   backend_task_runner_->PostTask(
-      from_here, base::Bind(&HistoryBackend::ProcessDBTask, history_backend_,
-                            base::Passed(&task),
-                            base::ThreadTaskRunnerHandle::Get(), is_canceled));
+      from_here,
+      base::BindOnce(&HistoryBackend::ProcessDBTask, history_backend_,
+                     std::move(task), base::ThreadTaskRunnerHandle::Get(),
+                     is_canceled));
   return task_id;
 }
 
@@ -790,13 +791,13 @@
   std::vector<DownloadRow>* rows = new std::vector<DownloadRow>();
   std::unique_ptr<std::vector<DownloadRow>> scoped_rows(rows);
   // Beware! The first Bind() does not simply |scoped_rows.get()| because
-  // base::Passed(&scoped_rows) nullifies |scoped_rows|, and compilers do not
+  // std::move(scoped_rows) nullifies |scoped_rows|, and compilers do not
   // guarantee that the first Bind's arguments are evaluated before the second
   // Bind's arguments.
   backend_task_runner_->PostTaskAndReply(
       FROM_HERE,
-      base::Bind(&HistoryBackend::QueryDownloads, history_backend_, rows),
-      base::Bind(callback, base::Passed(&scoped_rows)));
+      base::BindOnce(&HistoryBackend::QueryDownloads, history_backend_, rows),
+      base::BindOnce(callback, std::move(scoped_rows)));
 }
 
 // Handle updates for a particular download. This is a 'fire and forget'
diff --git a/components/invalidation/impl/non_blocking_invalidator.cc b/components/invalidation/impl/non_blocking_invalidator.cc
index 139bd67..33e0f74 100644
--- a/components/invalidation/impl/non_blocking_invalidator.cc
+++ b/components/invalidation/impl/non_blocking_invalidator.cc
@@ -93,7 +93,7 @@
   std::unique_ptr<base::DictionaryValue> copied(value.DeepCopy());
   running_thread_->PostTask(
       FROM_HERE,
-      base::Bind(&CallbackProxy::DoRun, callback_, base::Passed(&copied)));
+      base::BindOnce(&CallbackProxy::DoRun, callback_, std::move(copied)));
 }
 }
 
diff --git a/components/leveldb_proto/proto_database_impl.h b/components/leveldb_proto/proto_database_impl.h
index 45e497f..b7ecf115 100644
--- a/components/leveldb_proto/proto_database_impl.h
+++ b/components/leveldb_proto/proto_database_impl.h
@@ -244,8 +244,7 @@
 
   bool* success = new bool(false);
   task_runner_->PostTaskAndReply(
-      FROM_HERE,
-      base::Bind(DestroyFromTaskRunner, base::Passed(std::move(db_)), success),
+      FROM_HERE, base::BindOnce(DestroyFromTaskRunner, std::move(db_), success),
       base::BindOnce(RunDestroyCallback<T>, std::move(callback),
                      base::Owned(success)));
 }
@@ -278,9 +277,9 @@
   bool* success = new bool(false);
   task_runner_->PostTaskAndReply(
       FROM_HERE,
-      base::Bind(UpdateEntriesFromTaskRunner<T>, base::Unretained(db_.get()),
-                 base::Passed(&entries_to_save), base::Passed(&keys_to_remove),
-                 success),
+      base::BindOnce(UpdateEntriesFromTaskRunner<T>,
+                     base::Unretained(db_.get()), std::move(entries_to_save),
+                     std::move(keys_to_remove), success),
       base::BindOnce(RunUpdateCallback<T>, std::move(callback),
                      base::Owned(success)));
 }
@@ -292,15 +291,15 @@
   bool* success = new bool(false);
 
   std::unique_ptr<std::vector<T>> entries(new std::vector<T>());
-  // Get this pointer before entries is base::Passed() so we can use it below.
+  // Get this pointer before entries is std::move()'d so we can use it below.
   std::vector<T>* entries_ptr = entries.get();
 
   task_runner_->PostTaskAndReply(
       FROM_HERE,
-      base::Bind(LoadEntriesFromTaskRunner<T>, base::Unretained(db_.get()),
-                 entries_ptr, success),
+      base::BindOnce(LoadEntriesFromTaskRunner<T>, base::Unretained(db_.get()),
+                     entries_ptr, success),
       base::BindOnce(RunLoadCallback<T>, std::move(callback),
-                     base::Owned(success), base::Passed(&entries)));
+                     base::Owned(success), std::move(entries)));
 }
 
 template <typename T>
@@ -315,7 +314,7 @@
   task_runner_->PostTaskAndReply(
       FROM_HERE, load_task,
       base::BindOnce(RunLoadKeysCallback<T>, std::move(callback),
-                     base::Passed(&success), base::Passed(&keys)));
+                     std::move(success), std::move(keys)));
 }
 
 template <typename T>
@@ -327,16 +326,16 @@
   bool* found = new bool(false);
 
   std::unique_ptr<T> entry(new T());
-  // Get this pointer before entry is base::Passed() so we can use it below.
+  // Get this pointer before entry is std::move()'d so we can use it below.
   T* entry_ptr = entry.get();
 
   task_runner_->PostTaskAndReply(
       FROM_HERE,
-      base::Bind(GetEntryFromTaskRunner<T>, base::Unretained(db_.get()), key,
-                 entry_ptr, found, success),
+      base::BindOnce(GetEntryFromTaskRunner<T>, base::Unretained(db_.get()),
+                     key, entry_ptr, found, success),
       base::BindOnce(RunGetCallback<T>, std::move(callback),
                      base::Owned(success), base::Owned(found),
-                     base::Passed(&entry)));
+                     std::move(entry)));
 }
 
 }  // namespace leveldb_proto
diff --git a/components/leveldb_proto/testing/fake_db.h b/components/leveldb_proto/testing/fake_db.h
index bea5346..8be2645 100644
--- a/components/leveldb_proto/testing/fake_db.h
+++ b/components/leveldb_proto/testing/fake_db.h
@@ -122,8 +122,8 @@
   for (const auto& pair : *db_)
     entries->push_back(pair.second);
 
-  load_callback_ = base::BindOnce(RunLoadCallback, std::move(callback),
-                                  base::Passed(&entries));
+  load_callback_ =
+      base::BindOnce(RunLoadCallback, std::move(callback), std::move(entries));
 }
 
 template <typename T>
@@ -133,8 +133,8 @@
   for (const auto& pair : *db_)
     keys->push_back(pair.first);
 
-  load_keys_callback_ = base::BindOnce(RunLoadKeysCallback, std::move(callback),
-                                       base::Passed(&keys));
+  load_keys_callback_ =
+      base::BindOnce(RunLoadKeysCallback, std::move(callback), std::move(keys));
 }
 
 template <typename T>
@@ -146,7 +146,7 @@
     entry.reset(new T(it->second));
 
   get_callback_ =
-      base::BindOnce(RunGetCallback, std::move(callback), base::Passed(&entry));
+      base::BindOnce(RunGetCallback, std::move(callback), std::move(entry));
 }
 
 template <typename T>
diff --git a/components/metrics/child_call_stack_profile_collector.cc b/components/metrics/child_call_stack_profile_collector.cc
index b4a210d0d..71ed56ca 100644
--- a/components/metrics/child_call_stack_profile_collector.cc
+++ b/components/metrics/child_call_stack_profile_collector.cc
@@ -91,10 +91,10 @@
        base::ThreadTaskRunnerHandle::Get() != task_runner_)) {
     // Post back to the thread that owns the the parent interface.
     task_runner_->PostTask(
-        FROM_HERE, base::Bind(&ChildCallStackProfileCollector::CollectImpl,
-                              // This class has lazy instance lifetime.
-                              base::Unretained(this), params, start_timestamp,
-                              base::Passed(std::move(profiles))));
+        FROM_HERE, base::BindOnce(&ChildCallStackProfileCollector::CollectImpl,
+                                  // This class has lazy instance lifetime.
+                                  base::Unretained(this), params,
+                                  start_timestamp, std::move(profiles)));
     return;
   }
 
diff --git a/components/nacl/browser/nacl_process_host.cc b/components/nacl/browser/nacl_process_host.cc
index 1006b365..b69582b 100644
--- a/components/nacl/browser/nacl_process_host.cc
+++ b/components/nacl/browser/nacl_process_host.cc
@@ -274,16 +274,16 @@
     // handles.
     base::File file(IPC::PlatformFileForTransitToFile(
         prefetched_resource_files_[i].file));
-    base::PostTaskWithTraits(
-        FROM_HERE, {base::TaskPriority::BACKGROUND, base::MayBlock()},
-        base::Bind(&CloseFile, base::Passed(std::move(file))));
+    base::PostTaskWithTraits(FROM_HERE,
+                             {base::TaskPriority::BACKGROUND, base::MayBlock()},
+                             base::BindOnce(&CloseFile, std::move(file)));
   }
 #endif
   // Open files need to be closed on the blocking pool.
   if (nexe_file_.IsValid()) {
-    base::PostTaskWithTraits(
-        FROM_HERE, {base::TaskPriority::BACKGROUND, base::MayBlock()},
-        base::Bind(&CloseFile, base::Passed(std::move(nexe_file_))));
+    base::PostTaskWithTraits(FROM_HERE,
+                             {base::TaskPriority::BACKGROUND, base::MayBlock()},
+                             base::BindOnce(&CloseFile, std::move(nexe_file_)));
   }
 
   if (reply_msg_) {
@@ -846,9 +846,9 @@
   if (checked_nexe_file.IsValid()) {
     // Release the file received from the renderer. This has to be done on a
     // thread where IO is permitted, though.
-    base::PostTaskWithTraits(
-        FROM_HERE, {base::TaskPriority::BACKGROUND, base::MayBlock()},
-        base::Bind(&CloseFile, base::Passed(std::move(nexe_file_))));
+    base::PostTaskWithTraits(FROM_HERE,
+                             {base::TaskPriority::BACKGROUND, base::MayBlock()},
+                             base::BindOnce(&CloseFile, std::move(nexe_file_)));
     params.nexe_file_path_metadata = file_path;
     params.nexe_file =
         IPC::TakePlatformFileForTransit(std::move(checked_nexe_file));
diff --git a/components/nacl/loader/nacl_ipc_adapter.cc b/components/nacl/loader/nacl_ipc_adapter.cc
index f3bc37be..8a93a73 100644
--- a/components/nacl/loader/nacl_ipc_adapter.cc
+++ b/components/nacl/loader/nacl_ipc_adapter.cc
@@ -779,9 +779,9 @@
     msg = std::move(new_msg);
 
   // Actual send must be done on the I/O thread.
-  task_runner_->PostTask(FROM_HERE,
-      base::Bind(&NaClIPCAdapter::SendMessageOnIOThread, this,
-                 base::Passed(&msg)));
+  task_runner_->PostTask(
+      FROM_HERE, base::BindOnce(&NaClIPCAdapter::SendMessageOnIOThread, this,
+                                std::move(msg)));
   return true;
 }
 
diff --git a/components/nacl/loader/nacl_trusted_listener.cc b/components/nacl/loader/nacl_trusted_listener.cc
index d2c9ea4b4..1d9d9a8 100644
--- a/components/nacl/loader/nacl_trusted_listener.cc
+++ b/components/nacl/loader/nacl_trusted_listener.cc
@@ -5,6 +5,7 @@
 #include "components/nacl/loader/nacl_trusted_listener.h"
 
 #include <memory>
+#include <utility>
 
 #include "base/single_thread_task_runner.h"
 #include "build/build_config.h"
@@ -50,8 +51,8 @@
   // by NaClListener is busy in NaClChromeMainAppStart(), so it can't be used
   // for servicing messages.
   io_task_runner->PostTask(
-      FROM_HERE, base::Bind(&CreateExitControl,
-                            base::Passed(mojo::MakeRequest(&exit_control))));
+      FROM_HERE,
+      base::BindOnce(&CreateExitControl, mojo::MakeRequest(&exit_control)));
   renderer_host_->ProvideExitControl(std::move(exit_control));
 }
 
diff --git a/components/nacl/renderer/ppb_nacl_private_impl.cc b/components/nacl/renderer/ppb_nacl_private_impl.cc
index 62dd8cae..f5fbf34 100644
--- a/components/nacl/renderer/ppb_nacl_private_impl.cc
+++ b/components/nacl/renderer/ppb_nacl_private_impl.cc
@@ -268,7 +268,7 @@
         process_type_ != kPNaClTranslatorProcessType) {
       // Return an error.
       base::ThreadTaskRunnerHandle::Get()->PostTask(
-          FROM_HERE, base::Bind(callback, base::Passed(base::File()), 0, 0));
+          FROM_HERE, base::BindOnce(callback, base::File(), 0, 0));
       return;
     }
 
@@ -284,7 +284,7 @@
     if (!ManifestResolveKey(pp_instance_, is_helper_process, key, &url,
                             &pnacl_options)) {
       base::ThreadTaskRunnerHandle::Get()->PostTask(
-          FROM_HERE, base::Bind(callback, base::Passed(base::File()), 0, 0));
+          FROM_HERE, base::BindOnce(callback, base::File(), 0, 0));
       return;
     }
 
diff --git a/components/net_log/OWNERS b/components/net_log/OWNERS
index cadff51..b3a1999 100644
--- a/components/net_log/OWNERS
+++ b/components/net_log/OWNERS
@@ -1,12 +1,3 @@
-agl@chromium.org
-battre@chromium.org
-cbentzel@chromium.org
-eroman@chromium.org
-mattm@chromium.org
-mef@chromium.org
-mmenke@chromium.org
-rdsmith@chromium.org
-rsleevi@chromium.org
-rtenneti@chromium.org
+file://net/log/OWNERS
 
 # COMPONENT: Internals>Network>Logging
diff --git a/components/net_log/net_export_file_writer.cc b/components/net_log/net_export_file_writer.cc
index cc225d7..c30d2d7 100644
--- a/components/net_log/net_export_file_writer.cc
+++ b/components/net_log/net_export_file_writer.cc
@@ -229,9 +229,9 @@
   if (context_getter) {
     base::PostTaskAndReplyWithResult(
         net_task_runner_.get(), FROM_HERE,
-        base::Bind(&AddNetInfo, context_getter, base::Passed(&polled_data)),
-        base::Bind(&NetExportFileWriter::StopNetLogAfterAddNetInfo,
-                   weak_ptr_factory_.GetWeakPtr()));
+        base::BindOnce(&AddNetInfo, context_getter, std::move(polled_data)),
+        base::BindOnce(&NetExportFileWriter::StopNetLogAfterAddNetInfo,
+                       weak_ptr_factory_.GetWeakPtr()));
   } else {
     StopNetLogAfterAddNetInfo(std::move(polled_data));
   }
diff --git a/components/ntp_snippets/remote/remote_suggestions_database.cc b/components/ntp_snippets/remote/remote_suggestions_database.cc
index a126ee2..7e317ad9 100644
--- a/components/ntp_snippets/remote/remote_suggestions_database.cc
+++ b/components/ntp_snippets/remote/remote_suggestions_database.cc
@@ -178,10 +178,9 @@
 void RemoteSuggestionsDatabase::GarbageCollectImages(
     std::unique_ptr<std::set<std::string>> alive_snippet_ids) {
   DCHECK(image_database_initialized_);
-  image_database_->LoadKeys(
-      base::Bind(&RemoteSuggestionsDatabase::DeleteUnreferencedImages,
-                 weak_ptr_factory_.GetWeakPtr(),
-                 base::Passed(std::move(alive_snippet_ids))));
+  image_database_->LoadKeys(base::BindOnce(
+      &RemoteSuggestionsDatabase::DeleteUnreferencedImages,
+      weak_ptr_factory_.GetWeakPtr(), std::move(alive_snippet_ids)));
 }
 
 void RemoteSuggestionsDatabase::OnDatabaseInited(bool success) {
diff --git a/components/offline_pages/core/background/request_queue_in_memory_store.cc b/components/offline_pages/core/background/request_queue_in_memory_store.cc
index 69e06b8..ee71451 100644
--- a/components/offline_pages/core/background/request_queue_in_memory_store.cc
+++ b/components/offline_pages/core/background/request_queue_in_memory_store.cc
@@ -5,6 +5,7 @@
 #include "components/offline_pages/core/background/request_queue_in_memory_store.h"
 
 #include <unordered_set>
+#include <utility>
 
 #include "base/bind.h"
 #include "base/location.h"
@@ -40,8 +41,7 @@
     result_requests.push_back(std::move(request));
   }
   base::ThreadTaskRunnerHandle::Get()->PostTask(
-      FROM_HERE,
-      base::Bind(callback, true, base::Passed(std::move(result_requests))));
+      FROM_HERE, base::BindOnce(callback, true, std::move(result_requests)));
 }
 
 void RequestQueueInMemoryStore::GetRequestsByIds(
@@ -69,7 +69,7 @@
   }
 
   base::ThreadTaskRunnerHandle::Get()->PostTask(
-      FROM_HERE, base::Bind(callback, base::Passed(&result)));
+      FROM_HERE, base::BindOnce(callback, std::move(result)));
 }
 
 void RequestQueueInMemoryStore::AddRequest(const SavePageRequest& request,
@@ -110,7 +110,7 @@
   }
 
   base::ThreadTaskRunnerHandle::Get()->PostTask(
-      FROM_HERE, base::Bind(callback, base::Passed(&result)));
+      FROM_HERE, base::BindOnce(callback, std::move(result)));
 }
 
 void RequestQueueInMemoryStore::RemoveRequests(
@@ -136,7 +136,7 @@
   }
 
   base::ThreadTaskRunnerHandle::Get()->PostTask(
-      FROM_HERE, base::Bind(callback, base::Passed(&result)));
+      FROM_HERE, base::BindOnce(callback, std::move(result)));
 }
 
 void RequestQueueInMemoryStore::Reset(const ResetCallback& callback) {
diff --git a/components/offline_pages/core/background/request_queue_store_sql.cc b/components/offline_pages/core/background/request_queue_store_sql.cc
index 2b944f9..0920e902 100644
--- a/components/offline_pages/core/background/request_queue_store_sql.cc
+++ b/components/offline_pages/core/background/request_queue_store_sql.cc
@@ -5,6 +5,7 @@
 #include "components/offline_pages/core/background/request_queue_store_sql.h"
 
 #include <unordered_set>
+#include <utility>
 
 #include "base/bind.h"
 #include "base/files/file_path.h"
@@ -260,7 +261,7 @@
       new UpdateRequestsResult(store_state));
   for (const auto& item_id : item_ids)
     result->item_statuses.push_back(std::make_pair(item_id, action_status));
-  runner->PostTask(FROM_HERE, base::Bind(callback, base::Passed(&result)));
+  runner->PostTask(FROM_HERE, base::BindOnce(callback, std::move(result)));
 }
 
 void PostStoreErrorForAllRequests(
@@ -313,8 +314,8 @@
   while (statement.Step())
     requests.push_back(MakeSavePageRequest(statement));
 
-  runner->PostTask(FROM_HERE, base::Bind(callback, statement.Succeeded(),
-                                         base::Passed(&requests)));
+  runner->PostTask(FROM_HERE, base::BindOnce(callback, statement.Succeeded(),
+                                             std::move(requests)));
 }
 
 void GetRequestsByIdsSync(sql::Connection* db,
@@ -351,7 +352,7 @@
     return;
   }
 
-  runner->PostTask(FROM_HERE, base::Bind(callback, base::Passed(&result)));
+  runner->PostTask(FROM_HERE, base::BindOnce(callback, std::move(result)));
 }
 
 void AddRequestSync(sql::Connection* db,
@@ -388,7 +389,7 @@
     return;
   }
 
-  runner->PostTask(FROM_HERE, base::Bind(callback, base::Passed(&result)));
+  runner->PostTask(FROM_HERE, base::BindOnce(callback, std::move(result)));
 }
 
 void RemoveRequestsSync(sql::Connection* db,
@@ -421,7 +422,7 @@
     return;
   }
 
-  runner->PostTask(FROM_HERE, base::Bind(callback, base::Passed(&result)));
+  runner->PostTask(FROM_HERE, base::BindOnce(callback, std::move(result)));
 }
 
 void OpenConnectionSync(sql::Connection* db,
@@ -477,7 +478,7 @@
   if (!CheckDb()) {
     std::vector<std::unique_ptr<SavePageRequest>> requests;
     base::ThreadTaskRunnerHandle::Get()->PostTask(
-        FROM_HERE, base::Bind(callback, false, base::Passed(&requests)));
+        FROM_HERE, base::BindOnce(callback, false, std::move(requests)));
     return;
   }
 
diff --git a/components/offline_pages/core/model/delete_page_task.cc b/components/offline_pages/core/model/delete_page_task.cc
index 0e1bcae..43bbfe8 100644
--- a/components/offline_pages/core/model/delete_page_task.cc
+++ b/components/offline_pages/core/model/delete_page_task.cc
@@ -242,6 +242,59 @@
   return result;
 }
 
+// Gets page infos for |client_id|, returning a vector of
+// DeletedPageInfoWrappers because ClientId can refer to multiple pages.
+std::vector<DeletedPageInfoWrapper>
+GetDeletedPageInfoWrappersByClientIdAndOriginSync(sql::Connection* db,
+                                                  ClientId client_id,
+                                                  const std::string& origin) {
+  std::vector<DeletedPageInfoWrapper> info_wrappers;
+  static const char kSql[] =
+      "SELECT " INFO_WRAPPER_FIELDS " FROM " OFFLINE_PAGES_TABLE_NAME
+      " WHERE client_namespace = ? AND client_id = ? AND request_origin = ?";
+  sql::Statement statement(db->GetCachedStatement(SQL_FROM_HERE, kSql));
+  statement.BindString(0, client_id.name_space);
+  statement.BindString(1, client_id.id);
+  statement.BindString(2, origin);
+
+  while (statement.Step())
+    info_wrappers.emplace_back(CreateInfoWrapper(statement));
+
+  return info_wrappers;
+}
+
+DeletePageTaskResult DeletePagesByClientIdsAndOriginSync(
+    const std::vector<ClientId> client_ids,
+    const std::string& origin,
+    sql::Connection* db) {
+  std::vector<DeletedPageInfoWrapper> infos;
+
+  if (!db)
+    return DeletePageTaskResult(DeletePageResult::STORE_FAILURE, {});
+  if (client_ids.empty())
+    return DeletePageTaskResult(DeletePageResult::SUCCESS, {});
+
+  // If you create a transaction but dont Commit() it is automatically
+  // rolled back by its destructor when it falls out of scope.
+  sql::Transaction transaction(db);
+  if (!transaction.Begin())
+    return DeletePageTaskResult(DeletePageResult::STORE_FAILURE, {});
+
+  for (ClientId client_id : client_ids) {
+    std::vector<DeletedPageInfoWrapper> temp_infos =
+        GetDeletedPageInfoWrappersByClientIdAndOriginSync(db, client_id,
+                                                          origin);
+    infos.insert(infos.end(), temp_infos.begin(), temp_infos.end());
+  }
+
+  DeletePageTaskResult result =
+      DeletePagesByDeletedPageInfoWrappersSync(db, infos);
+
+  if (!transaction.Commit())
+    return DeletePageTaskResult(DeletePageResult::STORE_FAILURE, {});
+  return result;
+}
+
 // Gets the page information of pages that are within the provided temporary
 // namespaces and satisfy the provided URL predicate.
 std::vector<DeletedPageInfoWrapper>
@@ -389,6 +442,19 @@
 
 // static
 std::unique_ptr<DeletePageTask>
+DeletePageTask::CreateTaskMatchingClientIdsAndOrigin(
+    OfflinePageMetadataStoreSQL* store,
+    DeletePageTask::DeletePageTaskCallback callback,
+    const std::vector<ClientId>& client_ids,
+    const std::string& origin) {
+  return std::unique_ptr<DeletePageTask>(new DeletePageTask(
+      store,
+      base::BindOnce(&DeletePagesByClientIdsAndOriginSync, client_ids, origin),
+      std::move(callback)));
+}
+
+// static
+std::unique_ptr<DeletePageTask>
 DeletePageTask::CreateTaskMatchingUrlPredicateForCachedPages(
     OfflinePageMetadataStoreSQL* store,
     DeletePageTask::DeletePageTaskCallback callback,
diff --git a/components/offline_pages/core/model/delete_page_task.h b/components/offline_pages/core/model/delete_page_task.h
index 94bb86c..adb3af784 100644
--- a/components/offline_pages/core/model/delete_page_task.h
+++ b/components/offline_pages/core/model/delete_page_task.h
@@ -61,6 +61,14 @@
       DeletePageTask::DeletePageTaskCallback callback,
       const std::vector<ClientId>& client_ids);
 
+  // Creates a task to delete pages with the client ids in |client_ids|
+  // provided they also have origin |origin|.
+  static std::unique_ptr<DeletePageTask> CreateTaskMatchingClientIdsAndOrigin(
+      OfflinePageMetadataStoreSQL* store,
+      DeletePageTask::DeletePageTaskCallback callback,
+      const std::vector<ClientId>& client_ids,
+      const std::string& origin);
+
   // Creates a task to delete pages which satisfy |predicate|.
   static std::unique_ptr<DeletePageTask>
   CreateTaskMatchingUrlPredicateForCachedPages(
diff --git a/components/offline_pages/core/model/delete_page_task_unittest.cc b/components/offline_pages/core/model/delete_page_task_unittest.cc
index b357d6f..4e9102c 100644
--- a/components/offline_pages/core/model/delete_page_task_unittest.cc
+++ b/components/offline_pages/core/model/delete_page_task_unittest.cc
@@ -270,7 +270,6 @@
 }
 
 TEST_F(DeletePageTaskTest, DeletePageByClientIdNotFound) {
-  // Add 3 pages and try to delete 2 of them using client id.
   generator()->SetNamespace(kTestNamespace);
   OfflinePageItem page1 = generator()->CreateItemWithTempFile();
   OfflinePageItem page2 = generator()->CreateItemWithTempFile();
@@ -302,6 +301,77 @@
       0);
 }
 
+TEST_F(DeletePageTaskTest, DeletePageByClientIdAndOrigin) {
+  // Add 3 pages and try to delete 2 of them using client id and origin
+  // Page1: {test namespace, random id, abc.xyz}
+  // Page2: {test namespace, foo, abc.xyz}
+  // Page3: {test namespace, foo, <none>}
+  generator()->SetNamespace(kTestNamespace);
+  generator()->SetRequestOrigin("abc.xyz");
+  OfflinePageItem page1 = generator()->CreateItemWithTempFile();
+  generator()->SetId("foo");
+  OfflinePageItem page2 = generator()->CreateItemWithTempFile();
+  generator()->SetRequestOrigin("");
+  OfflinePageItem page3 = generator()->CreateItemWithTempFile();
+  store_test_util()->InsertItem(page1);
+  store_test_util()->InsertItem(page2);
+  store_test_util()->InsertItem(page3);
+
+  std::vector<ClientId> client_ids({page1.client_id, page2.client_id});
+  auto task = DeletePageTask::CreateTaskMatchingClientIdsAndOrigin(
+      store(), delete_page_callback(), client_ids, "abc.xyz");
+  runner()->RunTask(std::move(task));
+
+  EXPECT_EQ(DeletePageResult::SUCCESS, last_delete_page_result());
+  EXPECT_EQ(2UL, last_deleted_page_infos().size());
+  EXPECT_EQ(1LL, store_test_util()->GetPageCount());
+  EXPECT_TRUE(CheckPageDeleted(page1));
+  EXPECT_TRUE(CheckPageDeleted(page2));
+  EXPECT_FALSE(CheckPageDeleted(page3));
+  histogram_tester()->ExpectTotalCount(
+      model_utils::AddHistogramSuffix(page1.client_id.name_space,
+                                      "OfflinePages.PageLifetime"),
+      2);
+  histogram_tester()->ExpectTotalCount(
+      model_utils::AddHistogramSuffix(page1.client_id.name_space,
+                                      "OfflinePages.AccessCount"),
+      2);
+}
+
+TEST_F(DeletePageTaskTest, DeletePageByClientIdAndOriginNotFound) {
+  generator()->SetNamespace(kTestNamespace);
+  OfflinePageItem page1 = generator()->CreateItemWithTempFile();
+  OfflinePageItem page2 = generator()->CreateItemWithTempFile();
+  OfflinePageItem page3 = generator()->CreateItemWithTempFile();
+  store_test_util()->InsertItem(page1);
+  store_test_util()->InsertItem(page2);
+  store_test_util()->InsertItem(page3);
+
+  EXPECT_EQ(3LL, store_test_util()->GetPageCount());
+
+  // The pages with the client ids will be removed from the store given that
+  // their origin matches. But since the origin isn't in the store, there will
+  // be no pages deleted and the result will be success since there's no
+  // NOT_FOUND anymore.
+  std::vector<ClientId> client_ids(
+      {page1.client_id, page2.client_id, page3.client_id});
+  auto task = DeletePageTask::CreateTaskMatchingClientIdsAndOrigin(
+      store(), delete_page_callback(), client_ids, "abc.xyz");
+  runner()->RunTask(std::move(task));
+
+  EXPECT_EQ(DeletePageResult::SUCCESS, last_delete_page_result());
+  EXPECT_EQ(0UL, last_deleted_page_infos().size());
+  EXPECT_EQ(3LL, store_test_util()->GetPageCount());
+  histogram_tester()->ExpectTotalCount(
+      model_utils::AddHistogramSuffix(page1.client_id.name_space,
+                                      "OfflinePages.PageLifetime"),
+      0);
+  histogram_tester()->ExpectTotalCount(
+      model_utils::AddHistogramSuffix(page1.client_id.name_space,
+                                      "OfflinePages.AccessCount"),
+      0);
+}
+
 TEST_F(DeletePageTaskTest, DeletePageByUrlPredicate) {
   // Add 3 pages and try to delete 2 of them using url predicate.
   generator()->SetNamespace(kTestNamespace);
diff --git a/components/offline_pages/core/model/offline_page_model_taskified.cc b/components/offline_pages/core/model/offline_page_model_taskified.cc
index 09b062a..23ee7e09 100644
--- a/components/offline_pages/core/model/offline_page_model_taskified.cc
+++ b/components/offline_pages/core/model/offline_page_model_taskified.cc
@@ -237,6 +237,18 @@
   task_queue_.AddTask(std::move(task));
 }
 
+void OfflinePageModelTaskified::DeletePagesByClientIdsAndOrigin(
+    const std::vector<ClientId>& client_ids,
+    const std::string& origin,
+    const DeletePageCallback& callback) {
+  auto task = DeletePageTask::CreateTaskMatchingClientIdsAndOrigin(
+      store_.get(),
+      base::BindOnce(&OfflinePageModelTaskified::OnDeleteDone,
+                     weak_ptr_factory_.GetWeakPtr(), callback),
+      client_ids, origin);
+  task_queue_.AddTask(std::move(task));
+}
+
 void OfflinePageModelTaskified::DeleteCachedPagesByURLPredicate(
     const UrlPredicate& predicate,
     const DeletePageCallback& callback) {
diff --git a/components/offline_pages/core/model/offline_page_model_taskified.h b/components/offline_pages/core/model/offline_page_model_taskified.h
index bdc65604..702dd4f9 100644
--- a/components/offline_pages/core/model/offline_page_model_taskified.h
+++ b/components/offline_pages/core/model/offline_page_model_taskified.h
@@ -90,6 +90,10 @@
                               const DeletePageCallback& callback) override;
   void DeletePagesByClientIds(const std::vector<ClientId>& client_ids,
                               const DeletePageCallback& callback) override;
+  void DeletePagesByClientIdsAndOrigin(
+      const std::vector<ClientId>& client_ids,
+      const std::string& origin,
+      const DeletePageCallback& callback) override;
   void DeleteCachedPagesByURLPredicate(
       const UrlPredicate& predicate,
       const DeletePageCallback& callback) override;
diff --git a/components/offline_pages/core/offline_page_model.h b/components/offline_pages/core/offline_page_model.h
index 2aa9ee47..0d9a680f 100644
--- a/components/offline_pages/core/offline_page_model.h
+++ b/components/offline_pages/core/offline_page_model.h
@@ -150,6 +150,13 @@
   virtual void DeletePagesByClientIds(const std::vector<ClientId>& client_ids,
                                       const DeletePageCallback& callback) = 0;
 
+  // Deletes all pages associated with any of the |client_ids| provided the page
+  // also was created by origin.
+  virtual void DeletePagesByClientIdsAndOrigin(
+      const std::vector<ClientId>& client_ids,
+      const std::string& origin,
+      const DeletePageCallback& callback) = 0;
+
   // Deletes cached offline pages matching the URL predicate.
   virtual void DeleteCachedPagesByURLPredicate(
       const UrlPredicate& predicate,
diff --git a/components/offline_pages/core/offline_page_test_store.cc b/components/offline_pages/core/offline_page_test_store.cc
index 1f63830..8a69733 100644
--- a/components/offline_pages/core/offline_page_test_store.cc
+++ b/components/offline_pages/core/offline_page_test_store.cc
@@ -5,6 +5,7 @@
 #include "components/offline_pages/core/offline_page_test_store.h"
 
 #include <map>
+#include <utility>
 
 #include "base/bind.h"
 #include "base/location.h"
@@ -90,7 +91,7 @@
   }
   if (!callback.is_null())
     task_runner_->PostTask(FROM_HERE,
-                           base::Bind(callback, base::Passed(&result)));
+                           base::BindOnce(callback, std::move(result)));
 }
 
 void OfflinePageTestStore::RemoveOfflinePages(
@@ -123,7 +124,7 @@
   }
 
   task_runner_->PostTask(FROM_HERE,
-                         base::Bind(callback, base::Passed(&result)));
+                         base::BindOnce(callback, std::move(result)));
 }
 
 void OfflinePageTestStore::Reset(const ResetCallback& callback) {
diff --git a/components/offline_pages/core/prefetch/prefetch_dispatcher_impl.cc b/components/offline_pages/core/prefetch/prefetch_dispatcher_impl.cc
index 267de8ab..df90f87 100644
--- a/components/offline_pages/core/prefetch/prefetch_dispatcher_impl.cc
+++ b/components/offline_pages/core/prefetch/prefetch_dispatcher_impl.cc
@@ -246,8 +246,8 @@
 
   // Delay the deletion till the caller finishes.
   base::ThreadTaskRunnerHandle::Get()->PostTask(
-      FROM_HERE, base::Bind(&DeleteBackgroundTaskHelper,
-                            base::Passed(std::move(background_task_))));
+      FROM_HERE,
+      base::BindOnce(&DeleteBackgroundTaskHelper, std::move(background_task_)));
 }
 
 void PrefetchDispatcherImpl::GCMOperationCompletedMessageReceived(
diff --git a/components/offline_pages/core/stub_offline_page_model.cc b/components/offline_pages/core/stub_offline_page_model.cc
index 66eb341c..8a6b40e 100644
--- a/components/offline_pages/core/stub_offline_page_model.cc
+++ b/components/offline_pages/core/stub_offline_page_model.cc
@@ -27,6 +27,10 @@
 void StubOfflinePageModel::DeletePagesByClientIds(
     const std::vector<ClientId>& client_ids,
     const DeletePageCallback& callback) {}
+void StubOfflinePageModel::DeletePagesByClientIdsAndOrigin(
+    const std::vector<ClientId>& client_ids,
+    const std::string& origin,
+    const DeletePageCallback& callback) {}
 void StubOfflinePageModel::GetPagesByClientIds(
     const std::vector<ClientId>& client_ids,
     const MultipleOfflinePageItemCallback& callback) {}
diff --git a/components/offline_pages/core/stub_offline_page_model.h b/components/offline_pages/core/stub_offline_page_model.h
index 782e4bd3..983f549 100644
--- a/components/offline_pages/core/stub_offline_page_model.h
+++ b/components/offline_pages/core/stub_offline_page_model.h
@@ -34,6 +34,10 @@
                               const DeletePageCallback& callback) override;
   void DeletePagesByClientIds(const std::vector<ClientId>& client_ids,
                               const DeletePageCallback& callback) override;
+  void DeletePagesByClientIdsAndOrigin(
+      const std::vector<ClientId>& client_ids,
+      const std::string& origin,
+      const DeletePageCallback& callback) override;
   void GetPagesByClientIds(
       const std::vector<ClientId>& client_ids,
       const MultipleOfflinePageItemCallback& callback) override;
diff --git a/components/omnibox/browser/zero_suggest_provider.cc b/components/omnibox/browser/zero_suggest_provider.cc
index d12b6a3..ceac475 100644
--- a/components/omnibox/browser/zero_suggest_provider.cc
+++ b/components/omnibox/browser/zero_suggest_provider.cc
@@ -573,11 +573,8 @@
                ? ResultType::MOST_VISITED
                : ResultType::DEFAULT_SERP;
 
-  // The const-cast allows the non-const AutocompleteProviderClient::GetPrefs()
-  // function to be called. OmniboxFieldTrial does not modify prefs, so the
-  // cast is safe in this application.
   if (OmniboxFieldTrial::InZeroSuggestMostVisitedWithoutSerpFieldTrial(
-          const_cast<AutocompleteProviderClient*>(client())->GetPrefs()) &&
+          client()->GetPrefs()) &&
       client()
           ->GetTemplateURLService()
           ->IsSearchResultsPageFromDefaultSearchProvider(current_url))
diff --git a/components/password_manager/core/browser/android_affiliation/affiliated_match_helper.cc b/components/password_manager/core/browser/android_affiliation/affiliated_match_helper.cc
index 42a236b..7737748 100644
--- a/components/password_manager/core/browser/android_affiliation/affiliated_match_helper.cc
+++ b/components/password_manager/core/browser/android_affiliation/affiliated_match_helper.cc
@@ -94,10 +94,10 @@
     if (IsValidAndroidCredential(PasswordStore::FormDigest(*form)))
       android_credentials.push_back(form.get());
   }
-  base::Closure on_get_all_realms(
-      base::Bind(result_callback, base::Passed(&forms)));
-  base::Closure barrier_closure =
-      base::BarrierClosure(android_credentials.size(), on_get_all_realms);
+  base::OnceClosure on_get_all_realms(
+      base::BindOnce(result_callback, std::move(forms)));
+  base::RepeatingClosure barrier_closure = base::BarrierClosure(
+      android_credentials.size(), std::move(on_get_all_realms));
   for (auto* form : android_credentials) {
     affiliation_service_->GetAffiliationsAndBranding(
         FacetURI::FromPotentiallyInvalidSpec(form->signon_realm),
diff --git a/components/password_manager/core/browser/export/password_manager_exporter.cc b/components/password_manager/core/browser/export/password_manager_exporter.cc
index 670490f..44858773 100644
--- a/components/password_manager/core/browser/export/password_manager_exporter.cc
+++ b/components/password_manager/core/browser/export/password_manager_exporter.cc
@@ -60,7 +60,7 @@
   base::PostTaskAndReplyWithResult(
       task_runner_.get(), FROM_HERE,
       base::BindOnce(&password_manager::PasswordCSVWriter::SerializePasswords,
-                     base::Passed(std::move(password_list))),
+                     std::move(password_list)),
       base::BindOnce(&PasswordManagerExporter::SetSerialisedPasswordList,
                      weak_factory_.GetWeakPtr(), password_list_size));
 }
diff --git a/components/password_manager/core/browser/http_data_cleaner.cc b/components/password_manager/core/browser/http_data_cleaner.cc
index 1a3c719..f57f8413 100644
--- a/components/password_manager/core/browser/http_data_cleaner.cc
+++ b/components/password_manager/core/browser/http_data_cleaner.cc
@@ -8,6 +8,7 @@
 #include <iterator>
 #include <memory>
 #include <tuple>
+#include <utility>
 #include <vector>
 
 #include "base/bind.h"
@@ -208,9 +209,9 @@
     const auto post_to_thread =
         [](std::unique_ptr<ObsoleteHttpCleaner> cleaner, PrefService* prefs,
            scoped_refptr<base::SequencedTaskRunner> thread_runner) {
-          thread_runner->PostTask(
-              FROM_HERE, base::Bind(&WaitUntilCleaningIsDone,
-                                    base::Passed(std::move(cleaner)), prefs));
+          thread_runner->PostTask(FROM_HERE,
+                                  base::BindOnce(&WaitUntilCleaningIsDone,
+                                                 std::move(cleaner), prefs));
         };
 
     // Calling |ScheduleTask| through the raw pointer is necessary, because
diff --git a/components/password_manager/core/browser/password_store.cc b/components/password_manager/core/browser/password_store.cc
index 1bb9c265..66d0eb2 100644
--- a/components/password_manager/core/browser/password_store.cc
+++ b/components/password_manager/core/browser/password_store.cc
@@ -53,15 +53,16 @@
   }
 
   origin_task_runner_->PostTask(
-      FROM_HERE, base::Bind(&PasswordStoreConsumer::OnGetPasswordStoreResults,
-                            consumer_weak_, base::Passed(&results)));
+      FROM_HERE,
+      base::BindOnce(&PasswordStoreConsumer::OnGetPasswordStoreResults,
+                     consumer_weak_, std::move(results)));
 }
 
 void PasswordStore::GetLoginsRequest::NotifyWithSiteStatistics(
     std::vector<InteractionsStats> stats) {
   origin_task_runner_->PostTask(
-      FROM_HERE, base::Bind(&PasswordStoreConsumer::OnGetSiteStatistics,
-                            consumer_weak_, base::Passed(&stats)));
+      FROM_HERE, base::BindOnce(&PasswordStoreConsumer::OnGetSiteStatistics,
+                                consumer_weak_, std::move(stats)));
 }
 
 // TODO(crbug.com/706392): Fix password reuse detection for Android.
@@ -502,7 +503,7 @@
   std::unique_ptr<GetLoginsRequest> request(new GetLoginsRequest(consumer));
   consumer->cancelable_task_tracker()->PostTask(
       background_task_runner_.get(), FROM_HERE,
-      base::BindOnce(func, this, base::Passed(&request)));
+      base::BindOnce(func, this, std::move(request)));
 }
 
 void PasswordStore::WrapModificationTask(ModificationTask task) {
@@ -607,8 +608,8 @@
   // post a request to UI thread.
   main_task_runner_->PostTask(
       FROM_HERE,
-      base::Bind(&PasswordStore::InjectAffiliationAndBrandingInformation, this,
-                 base::Passed(&obtained_forms), base::Passed(&request)));
+      base::BindOnce(&PasswordStore::InjectAffiliationAndBrandingInformation,
+                     this, std::move(obtained_forms), std::move(request)));
 }
 
 void PasswordStore::GetBlacklistLoginsImpl(
@@ -628,8 +629,8 @@
   // post a request to UI thread.
   main_task_runner_->PostTask(
       FROM_HERE,
-      base::Bind(&PasswordStore::InjectAffiliationAndBrandingInformation, this,
-                 base::Passed(&obtained_forms), base::Passed(&request)));
+      base::BindOnce(&PasswordStore::InjectAffiliationAndBrandingInformation,
+                     this, std::move(obtained_forms), std::move(request)));
 }
 
 void PasswordStore::NotifyAllSiteStats(
diff --git a/components/password_manager/core/browser/site_affiliation/asset_link_retriever.cc b/components/password_manager/core/browser/site_affiliation/asset_link_retriever.cc
index 9095f63..87edae5 100644
--- a/components/password_manager/core/browser/site_affiliation/asset_link_retriever.cc
+++ b/components/password_manager/core/browser/site_affiliation/asset_link_retriever.cc
@@ -83,7 +83,7 @@
         base::BindOnce(&AssetLinkData::Parse, base::Unretained(data_raw),
                        std::move(response_string)),
         base::BindOnce(&AssetLinkRetriever::OnResponseParsed, this,
-                       base::Passed(&data)));
+                       std::move(data)));
   }
   fetcher_.reset();
 }
diff --git a/components/policy/core/common/async_policy_provider.cc b/components/policy/core/common/async_policy_provider.cc
index d0af420..7e05e255 100644
--- a/components/policy/core/common/async_policy_provider.cc
+++ b/components/policy/core/common/async_policy_provider.cc
@@ -126,9 +126,8 @@
     base::WeakPtr<AsyncPolicyProvider> weak_this,
     std::unique_ptr<PolicyBundle> bundle) {
   runner->PostTask(FROM_HERE,
-                 base::Bind(&AsyncPolicyProvider::OnLoaderReloaded,
-                            weak_this,
-                            base::Passed(&bundle)));
+                   base::BindOnce(&AsyncPolicyProvider::OnLoaderReloaded,
+                                  weak_this, std::move(bundle)));
 }
 
 }  // namespace policy
diff --git a/components/policy/core/common/cloud/cloud_policy_validator.cc b/components/policy/core/common/cloud/cloud_policy_validator.cc
index 8a51556..22640fa 100644
--- a/components/policy/core/common/cloud/cloud_policy_validator.cc
+++ b/components/policy/core/common/cloud/cloud_policy_validator.cc
@@ -180,9 +180,9 @@
   const auto task_runner = validator->background_task_runner_;
   task_runner->PostTask(
       FROM_HERE,
-      base::Bind(&CloudPolicyValidatorBase::PerformValidation,
-                 base::Passed(&validator), base::ThreadTaskRunnerHandle::Get(),
-                 completion_callback));
+      base::BindOnce(&CloudPolicyValidatorBase::PerformValidation,
+                     std::move(validator), base::ThreadTaskRunnerHandle::Get(),
+                     completion_callback));
 }
 
 // static
@@ -195,10 +195,8 @@
 
   // Report completion on |task_runner|.
   task_runner->PostTask(
-      FROM_HERE,
-      base::Bind(&CloudPolicyValidatorBase::ReportCompletion,
-                 base::Passed(&self),
-                 completion_callback));
+      FROM_HERE, base::BindOnce(&CloudPolicyValidatorBase::ReportCompletion,
+                                std::move(self), completion_callback));
 }
 
 // static
diff --git a/components/policy/core/common/cloud/component_cloud_policy_service.cc b/components/policy/core/common/cloud/component_cloud_policy_service.cc
index 3f2fd3a..5bb4bea5 100644
--- a/components/policy/core/common/cloud/component_cloud_policy_service.cc
+++ b/components/policy/core/common/cloud/component_cloud_policy_service.cc
@@ -201,8 +201,8 @@
   std::unique_ptr<PolicyBundle> bundle(std::make_unique<PolicyBundle>());
   bundle->CopyFrom(store_.policy());
   service_task_runner_->PostTask(
-      FROM_HERE, base::Bind(&ComponentCloudPolicyService::SetPolicy, service_,
-                            base::Passed(&bundle)));
+      FROM_HERE, base::BindOnce(&ComponentCloudPolicyService::SetPolicy,
+                                service_, std::move(bundle)));
 
   initialized_ = true;
 
@@ -232,8 +232,8 @@
   std::unique_ptr<PolicyBundle> bundle(std::make_unique<PolicyBundle>());
   bundle->CopyFrom(store_.policy());
   service_task_runner_->PostTask(
-      FROM_HERE, base::Bind(&ComponentCloudPolicyService::SetPolicy, service_,
-                            base::Passed(&bundle)));
+      FROM_HERE, base::BindOnce(&ComponentCloudPolicyService::SetPolicy,
+                                service_, std::move(bundle)));
 }
 
 void ComponentCloudPolicyService::Backend::UpdateWithLastFetchedPolicy() {
@@ -462,9 +462,9 @@
   }
 
   backend_task_runner_->PostTask(
-      FROM_HERE,
-      base::Bind(&Backend::SetFetchedPolicy, base::Unretained(backend_.get()),
-                 base::Passed(&valid_responses)));
+      FROM_HERE, base::BindOnce(&Backend::SetFetchedPolicy,
+                                base::Unretained(backend_.get()),
+                                std::move(valid_responses)));
 }
 
 void ComponentCloudPolicyService::UpdateFromSchemaRegistry() {
diff --git a/components/policy/core/common/cloud/external_policy_data_fetcher.cc b/components/policy/core/common/cloud/external_policy_data_fetcher.cc
index d8fa40dc..53c8b792 100644
--- a/components/policy/core/common/cloud/external_policy_data_fetcher.cc
+++ b/components/policy/core/common/cloud/external_policy_data_fetcher.cc
@@ -35,7 +35,7 @@
     ExternalPolicyDataFetcher::Result result,
     std::unique_ptr<std::string> data) {
   task_runner->PostTask(FROM_HERE,
-                        base::Bind(callback, job, result, base::Passed(&data)));
+                        base::BindOnce(callback, job, result, std::move(data)));
 }
 
 // Helper that forwards a job cancelation confirmation from the thread that the
diff --git a/components/policy/core/common/remote_commands/remote_command_job.cc b/components/policy/core/common/remote_commands/remote_command_job.cc
index b0675ad..c3a58c2 100644
--- a/components/policy/core/common/remote_commands/remote_command_job.cc
+++ b/components/policy/core/common/remote_commands/remote_command_job.cc
@@ -13,7 +13,10 @@
 
 namespace {
 
-const int kDefaultCommandTimeoutInMinutes = 3;
+constexpr base::TimeDelta kDefaultCommandTimeout =
+    base::TimeDelta::FromMinutes(10);
+constexpr base::TimeDelta kDefaultCommandExpirationTime =
+    base::TimeDelta::FromMinutes(10);
 
 }  // namespace
 
@@ -141,8 +144,8 @@
     finished_callback_.Run();
 }
 
-base::TimeDelta RemoteCommandJob::GetCommmandTimeout() const {
-  return base::TimeDelta::FromMinutes(kDefaultCommandTimeoutInMinutes);
+base::TimeDelta RemoteCommandJob::GetCommandTimeout() const {
+  return kDefaultCommandTimeout;
 }
 
 bool RemoteCommandJob::IsExecutionFinished() const {
@@ -168,7 +171,7 @@
 }
 
 bool RemoteCommandJob::IsExpired(base::TimeTicks now) {
-  return false;
+  return now > issued_time() + kDefaultCommandExpirationTime;
 }
 
 void RemoteCommandJob::TerminateImpl() {
diff --git a/components/policy/core/common/remote_commands/remote_command_job.h b/components/policy/core/common/remote_commands/remote_command_job.h
index 4fa649ac..4bba1cd 100644
--- a/components/policy/core/common/remote_commands/remote_command_job.h
+++ b/components/policy/core/common/remote_commands/remote_command_job.h
@@ -76,7 +76,7 @@
 
   // Returns the remote command timeout. If the command takes longer than the
   // returned time interval to execute, the command queue will kill it.
-  virtual base::TimeDelta GetCommmandTimeout() const;
+  virtual base::TimeDelta GetCommandTimeout() const;
 
   // Helpful accessors.
   UniqueIDType unique_id() const { return unique_id_; }
@@ -119,7 +119,6 @@
   // checking. |now| is the current time obtained from a clock. Implementations
   // are usually expected to compare |now| to the issued_time(), which is the
   // timestamp when the command was issued on the server.
-  // The default implementation always returns false.
   virtual bool IsExpired(base::TimeTicks now);
 
   // Subclasses should implement this method for actual command execution logic.
diff --git a/components/policy/core/common/remote_commands/remote_commands_queue.cc b/components/policy/core/common/remote_commands/remote_commands_queue.cc
index 9543712..2b86051 100644
--- a/components/policy/core/common/remote_commands/remote_commands_queue.cc
+++ b/components/policy/core/common/remote_commands/remote_commands_queue.cc
@@ -80,7 +80,7 @@
   incoming_commands_.pop();
 
   execution_timeout_timer_.Start(FROM_HERE,
-                                 running_command_->GetCommmandTimeout(), this,
+                                 running_command_->GetCommandTimeout(), this,
                                  &RemoteCommandsQueue::OnCommandTimeout);
 
   if (running_command_->Run(clock_->NowTicks(),
diff --git a/components/policy/core/common/remote_commands/remote_commands_queue_unittest.cc b/components/policy/core/common/remote_commands/remote_commands_queue_unittest.cc
index 3ec38a4..7dda6349 100644
--- a/components/policy/core/common/remote_commands/remote_commands_queue_unittest.cc
+++ b/components/policy/core/common/remote_commands/remote_commands_queue_unittest.cc
@@ -218,16 +218,16 @@
 }
 
 TEST_F(RemoteCommandsQueueTest, SingleTerminatedCommand) {
-  // Initialize a job expected to fail after 200 seconds, from a protobuf with
+  // Initialize a job expected to fail after 600 seconds, from a protobuf with
   // |kUniqueID|, |kPayload| and |test_start_time_| as command issued time.
   std::unique_ptr<RemoteCommandJob> job(
-      new TestRemoteCommandJob(false, base::TimeDelta::FromSeconds(200)));
+      new TestRemoteCommandJob(false, base::TimeDelta::FromSeconds(600)));
   InitializeJob(job.get(), kUniqueID, test_start_time_, kPayload);
 
   AddJobAndVerifyRunningAfter(std::move(job),
-                              base::TimeDelta::FromSeconds(179));
+                              base::TimeDelta::FromSeconds(599));
 
-  // After 181 seconds, the job is expected to be terminated (3 minutes is the
+  // After 601 seconds, the job is expected to be terminated (10 minutes is the
   // timeout duration).
   EXPECT_CALL(observer_, OnJobFinished(Property(&RemoteCommandJob::status,
                                                 RemoteCommandJob::TERMINATED)));
diff --git a/components/policy/core/common/remote_commands/remote_commands_service_unittest.cc b/components/policy/core/common/remote_commands/remote_commands_service_unittest.cc
index bb1ddcd..d7da7fe 100644
--- a/components/policy/core/common/remote_commands/remote_commands_service_unittest.cc
+++ b/components/policy/core/common/remote_commands/remote_commands_service_unittest.cc
@@ -136,10 +136,10 @@
     // Simulate delay from client to DMServer.
     base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
         FROM_HERE,
-        base::Bind(
+        base::BindOnce(
             &TestingCloudPolicyClientForRemoteCommands::DoFetchRemoteCommands,
-            base::Unretained(this), base::Passed(&last_command_id),
-            command_results, callback, fetch_call_expectation),
+            base::Unretained(this), std::move(last_command_id), command_results,
+            callback, fetch_call_expectation),
         base::TimeDelta::FromSeconds(
             kTestClientServerCommunicationDelayInSeconds));
   }
diff --git a/components/policy/core/common/remote_commands/test_remote_command_job.cc b/components/policy/core/common/remote_commands/test_remote_command_job.cc
index 6677007d..dba416c 100644
--- a/components/policy/core/common/remote_commands/test_remote_command_job.cc
+++ b/components/policy/core/common/remote_commands/test_remote_command_job.cc
@@ -5,6 +5,7 @@
 #include "components/policy/core/common/remote_commands/test_remote_command_job.h"
 
 #include <memory>
+#include <utility>
 
 #include "base/bind.h"
 #include "base/bind_helpers.h"
@@ -70,8 +71,9 @@
   std::unique_ptr<ResultPayload> echo_payload(
       new EchoPayload(command_payload_));
   base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
-      FROM_HERE, base::Bind(succeed_ ? succeed_callback : failed_callback,
-                            base::Passed(&echo_payload)),
+      FROM_HERE,
+      base::BindOnce(succeed_ ? succeed_callback : failed_callback,
+                     std::move(echo_payload)),
       execution_duration_);
 }
 
diff --git a/components/previews/content/previews_io_data.cc b/components/previews/content/previews_io_data.cc
index 4c03057..668e5b55 100644
--- a/components/previews/content/previews_io_data.cc
+++ b/components/previews/content/previews_io_data.cc
@@ -5,6 +5,7 @@
 #include "components/previews/content/previews_io_data.h"
 
 #include <algorithm>
+#include <utility>
 
 #include "base/bind.h"
 #include "base/bind_helpers.h"
@@ -111,9 +112,9 @@
 
   // Set up the IO thread portion of |this|.
   io_task_runner_->PostTask(
-      FROM_HERE,
-      base::Bind(&PreviewsIOData::InitializeOnIOThread, base::Unretained(this),
-                 base::Passed(&previews_opt_out_store)));
+      FROM_HERE, base::BindOnce(&PreviewsIOData::InitializeOnIOThread,
+                                base::Unretained(this),
+                                std::move(previews_opt_out_store)));
 }
 
 void PreviewsIOData::OnNewBlacklistedHost(const std::string& host,
@@ -174,9 +175,9 @@
     uint64_t page_id) const {
   LogPreviewsEligibilityReason(reason, type);
   ui_task_runner_->PostTask(
-      FROM_HERE, base::Bind(&PreviewsUIService::LogPreviewDecisionMade,
-                            previews_ui_service_, reason, url, time, type,
-                            base::Passed(std::move(passed_reasons)), page_id));
+      FROM_HERE, base::BindOnce(&PreviewsUIService::LogPreviewDecisionMade,
+                                previews_ui_service_, reason, url, time, type,
+                                std::move(passed_reasons), page_id));
 }
 
 void PreviewsIOData::AddPreviewNavigation(const GURL& url,
diff --git a/components/previews/content/previews_io_data_unittest.cc b/components/previews/content/previews_io_data_unittest.cc
index b6012d19..f8c46447 100644
--- a/components/previews/content/previews_io_data_unittest.cc
+++ b/components/previews/content/previews_io_data_unittest.cc
@@ -8,6 +8,7 @@
 #include <map>
 #include <memory>
 #include <string>
+#include <utility>
 
 #include "base/bind.h"
 #include "base/bind_helpers.h"
@@ -318,9 +319,9 @@
     std::unique_ptr<PreviewsBlackListItem> host_indifferent_black_list_item =
         PreviewsBlackList::CreateHostIndifferentBlackListItem();
     base::ThreadTaskRunnerHandle::Get()->PostTask(
-        FROM_HERE, base::Bind(&RunLoadCallback, callback,
-                              base::Passed(&black_list_item_map),
-                              base::Passed(&host_indifferent_black_list_item)));
+        FROM_HERE, base::BindOnce(&RunLoadCallback, callback,
+                                  std::move(black_list_item_map),
+                                  std::move(host_indifferent_black_list_item)));
   }
 
   void ClearBlackList(base::Time begin_time, base::Time end_time) override {}
diff --git a/components/previews/core/previews_black_list_unittest.cc b/components/previews/core/previews_black_list_unittest.cc
index fa84053..fb851da 100644
--- a/components/previews/core/previews_black_list_unittest.cc
+++ b/components/previews/core/previews_black_list_unittest.cc
@@ -9,6 +9,7 @@
 #include <memory>
 #include <string>
 #include <unordered_map>
+#include <utility>
 
 #include "base/bind.h"
 #include "base/bind_helpers.h"
@@ -128,9 +129,9 @@
     }
     base::ThreadTaskRunnerHandle::Get()->PostTask(
         FROM_HERE,
-        base::Bind(&RunLoadCallback, callback,
-                   base::Passed(&black_list_item_map_),
-                   base::Passed(&host_indifferent_black_list_item_)));
+        base::BindOnce(&RunLoadCallback, callback,
+                       std::move(black_list_item_map_),
+                       std::move(host_indifferent_black_list_item_)));
   }
 
   void ClearBlackList(base::Time begin_time, base::Time end_time) override {
diff --git a/components/previews/core/previews_opt_out_store_sql.cc b/components/previews/core/previews_opt_out_store_sql.cc
index 503fd31..88bb76b6 100644
--- a/components/previews/core/previews_opt_out_store_sql.cc
+++ b/components/previews/core/previews_opt_out_store_sql.cc
@@ -361,8 +361,8 @@
   }
 
   runner->PostTask(FROM_HERE,
-                   base::Bind(callback, base::Passed(&black_list_item_map),
-                              base::Passed(&host_indifferent_black_list_item)));
+                   base::BindOnce(callback, std::move(black_list_item_map),
+                                  std::move(host_indifferent_black_list_item)));
 }
 
 // Synchronous implementations, these are run on the background thread
@@ -453,9 +453,9 @@
   std::unique_ptr<PreviewsTypeList> enabled_previews =
       std::make_unique<PreviewsTypeList>(*enabled_previews_);
   background_task_runner_->PostTask(
-      FROM_HERE, base::Bind(&LoadBlackListSync, db_.get(), db_file_path_,
-                            base::Passed(std::move(enabled_previews)),
-                            base::ThreadTaskRunnerHandle::Get(), callback));
+      FROM_HERE, base::BindOnce(&LoadBlackListSync, db_.get(), db_file_path_,
+                                std::move(enabled_previews),
+                                base::ThreadTaskRunnerHandle::Get(), callback));
 }
 
 }  // namespace previews
diff --git a/components/reading_list/core/reading_list_store_unittest.cc b/components/reading_list/core/reading_list_store_unittest.cc
index 84f2fad..7282617 100644
--- a/components/reading_list/core/reading_list_store_unittest.cc
+++ b/components/reading_list/core/reading_list_store_unittest.cc
@@ -6,6 +6,7 @@
 
 #include <map>
 #include <set>
+#include <utility>
 
 #include "base/bind.h"
 #include "base/message_loop/message_loop.h"
@@ -91,8 +92,8 @@
       : store_(syncer::ModelTypeStoreTestUtil::CreateInMemoryStoreForTest()) {
     ClearState();
     reading_list_store_ = std::make_unique<ReadingListStore>(
-        base::Bind(&syncer::ModelTypeStoreTestUtil::MoveStoreToCallback,
-                   base::Passed(&store_)),
+        base::BindOnce(&syncer::ModelTypeStoreTestUtil::MoveStoreToCallback,
+                       std::move(store_)),
         base::Bind(&ReadingListStoreTest::CreateModelTypeChangeProcessor,
                    base::Unretained(this)));
     auto clock = std::make_unique<base::SimpleTestClock>();
diff --git a/components/safe_browsing/android/safe_browsing_api_handler_bridge.cc b/components/safe_browsing/android/safe_browsing_api_handler_bridge.cc
index db16c9f2..2d79865 100644
--- a/components/safe_browsing/android/safe_browsing_api_handler_bridge.cc
+++ b/components/safe_browsing/android/safe_browsing_api_handler_bridge.cc
@@ -194,8 +194,8 @@
   api_task_runner_->PostTask(
       FROM_HERE,
       base::BindOnce(&SafeBrowsingApiHandlerBridge::Core::StartURLCheck,
-                     base::Unretained(core_.get()), base::Passed(&callback),
-                     url, threat_types));
+                     base::Unretained(core_.get()), std::move(callback), url,
+                     threat_types));
 }
 
 SafeBrowsingApiHandlerBridge::Core::Core() {
diff --git a/components/safe_browsing/browser/threat_details.cc b/components/safe_browsing/browser/threat_details.cc
index 9c5ab8f5..da73d15 100644
--- a/components/safe_browsing/browser/threat_details.cc
+++ b/components/safe_browsing/browser/threat_details.cc
@@ -9,6 +9,7 @@
 #include <stddef.h>
 #include <stdint.h>
 #include <unordered_set>
+#include <utility>
 #include <vector>
 
 #include "base/bind.h"
@@ -767,9 +768,9 @@
 
   BrowserThread::PostTask(
       content::BrowserThread::UI, FROM_HERE,
-      base::Bind(&WebUIInfoSingleton::AddToReportsSent,
-                 base::Unretained(WebUIInfoSingleton::GetInstance()),
-                 base::Passed(&report_)));
+      base::BindOnce(&WebUIInfoSingleton::AddToReportsSent,
+                     base::Unretained(WebUIInfoSingleton::GetInstance()),
+                     std::move(report_)));
   ui_manager_->SendSerializedThreatDetails(serialized);
 
   AllDone();
diff --git a/components/safe_browsing/db/v4_database.cc b/components/safe_browsing/db/v4_database.cc
index b03300f4..3e77977f 100644
--- a/components/safe_browsing/db/v4_database.cc
+++ b/components/safe_browsing/db/v4_database.cc
@@ -2,7 +2,10 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include "components/safe_browsing/db/v4_database.h"
+
 #include <memory>
+#include <utility>
 
 #include "base/callback.h"
 #include "base/files/file_util.h"
@@ -10,7 +13,6 @@
 #include "base/metrics/histogram_macros.h"
 #include "base/task_runner_util.h"
 #include "base/threading/thread_task_runner_handle.h"
-#include "components/safe_browsing/db/v4_database.h"
 #include "components/safe_browsing/proto/webui.pb.h"
 #include "content/public/browser/browser_thread.h"
 
@@ -108,7 +110,7 @@
   // Database is done loading, pass it to the new_db_callback on the caller's
   // thread. This would unblock resource loads.
   callback_task_runner->PostTask(
-      FROM_HERE, base::Bind(new_db_callback, base::Passed(&v4_database)));
+      FROM_HERE, base::BindOnce(new_db_callback, std::move(v4_database)));
 
   UMA_HISTOGRAM_TIMES("SafeBrowsing.V4DatabaseOpen.Time",
                       TimeTicks::Now() - create_start_time);
@@ -176,10 +178,10 @@
             base::Bind(&V4Database::UpdatedStoreReady,
                        weak_factory_on_io_.GetWeakPtr(), identifier);
         db_task_runner_->PostTask(
-            FROM_HERE,
-            base::Bind(&V4Store::ApplyUpdate, base::Unretained(old_store.get()),
-                       base::Passed(std::move(response)), current_task_runner,
-                       store_ready_callback));
+            FROM_HERE, base::BindOnce(&V4Store::ApplyUpdate,
+                                      base::Unretained(old_store.get()),
+                                      std::move(response), current_task_runner,
+                                      store_ready_callback));
       }
     } else {
       NOTREACHED() << "Got update for unexpected identifier: " << identifier;
diff --git a/components/safe_browsing/db/v4_local_database_manager.cc b/components/safe_browsing/db/v4_local_database_manager.cc
index 74e1ad88..26d83c5 100644
--- a/components/safe_browsing/db/v4_local_database_manager.cc
+++ b/components/safe_browsing/db/v4_local_database_manager.cc
@@ -7,6 +7,7 @@
 
 #include "components/safe_browsing/db/v4_local_database_manager.h"
 
+#include <utility>
 #include <vector>
 
 #include "base/bind_helpers.h"
@@ -764,9 +765,9 @@
   // Post on the IO thread to enforce async behavior.
   BrowserThread::PostTask(
       BrowserThread::IO, FROM_HERE,
-      base::Bind(&V4LocalDatabaseManager::PerformFullHashCheck,
-                 weak_factory_.GetWeakPtr(), base::Passed(std::move(check)),
-                 full_hash_to_store_and_hash_prefixes));
+      base::BindOnce(&V4LocalDatabaseManager::PerformFullHashCheck,
+                     weak_factory_.GetWeakPtr(), std::move(check),
+                     full_hash_to_store_and_hash_prefixes));
 }
 
 bool V4LocalDatabaseManager::HandleHashSynchronously(
diff --git a/components/safe_browsing/db/v4_local_database_manager_unittest.cc b/components/safe_browsing/db/v4_local_database_manager_unittest.cc
index 77d82e4..7231c925 100644
--- a/components/safe_browsing/db/v4_local_database_manager_unittest.cc
+++ b/components/safe_browsing/db/v4_local_database_manager_unittest.cc
@@ -3,6 +3,9 @@
 // found in the LICENSE file.
 
 #include "components/safe_browsing/db/v4_local_database_manager.h"
+
+#include <utility>
+
 #include "base/files/file_util.h"
 #include "base/files/scoped_temp_dir.h"
 #include "base/memory/ref_counted.h"
@@ -105,10 +108,10 @@
     const scoped_refptr<base::SingleThreadTaskRunner>& callback_task_runner =
         base::MessageLoop::current()->task_runner();
     db_task_runner->PostTask(
-        FROM_HERE,
-        base::Bind(&FakeV4Database::CreateOnTaskRunner, db_task_runner,
-                   base::Passed(&store_map), store_and_hash_prefixes,
-                   callback_task_runner, new_db_callback, stores_available));
+        FROM_HERE, base::BindOnce(&FakeV4Database::CreateOnTaskRunner,
+                                  db_task_runner, std::move(store_map),
+                                  store_and_hash_prefixes, callback_task_runner,
+                                  new_db_callback, stores_available));
   }
 
   // V4Database implementation
@@ -151,7 +154,7 @@
                            store_and_hash_prefixes, stores_available));
     callback_task_runner->PostTask(
         FROM_HERE,
-        base::Bind(new_db_callback, base::Passed(&fake_v4_database)));
+        base::BindOnce(new_db_callback, std::move(fake_v4_database)));
   }
 
   FakeV4Database(const scoped_refptr<base::SequencedTaskRunner>& db_task_runner,
diff --git a/components/safe_browsing/db/v4_store.cc b/components/safe_browsing/db/v4_store.cc
index ec4d08c..3ebcfcd 100644
--- a/components/safe_browsing/db/v4_store.cc
+++ b/components/safe_browsing/db/v4_store.cc
@@ -4,6 +4,8 @@
 
 #include "components/safe_browsing/db/v4_store.h"
 
+#include <utility>
+
 #include "base/base64.h"
 #include "base/bind.h"
 #include "base/files/file_util.h"
@@ -393,7 +395,7 @@
   // happens, the old store will get destoyed and can lead to use-after-free in
   // this function.
   callback_task_runner->PostTask(
-      FROM_HERE, base::Bind(callback, base::Passed(&new_store)));
+      FROM_HERE, base::BindOnce(callback, std::move(new_store)));
 }
 
 ApplyUpdateResult V4Store::UpdateHashPrefixMapFromAdditions(
diff --git a/components/search_provider_logos/logo_tracker.cc b/components/search_provider_logos/logo_tracker.cc
index 4a42d13..3e11082 100644
--- a/components/search_provider_logos/logo_tracker.cc
+++ b/components/search_provider_logos/logo_tracker.cc
@@ -449,11 +449,11 @@
       FROM_HERE,
       {base::MayBlock(), base::TaskPriority::USER_VISIBLE,
        base::TaskShutdownBehavior::SKIP_ON_SHUTDOWN},
-      base::Bind(parse_logo_response_func_, base::Passed(&response),
-                 response_time, parsing_failed),
-      base::Bind(&LogoTracker::OnFreshLogoParsed,
-                 weak_ptr_factory_.GetWeakPtr(), base::Owned(parsing_failed),
-                 from_http_cache));
+      base::BindOnce(parse_logo_response_func_, std::move(response),
+                     response_time, parsing_failed),
+      base::BindOnce(&LogoTracker::OnFreshLogoParsed,
+                     weak_ptr_factory_.GetWeakPtr(),
+                     base::Owned(parsing_failed), from_http_cache));
 }
 
 void LogoTracker::OnURLFetchDownloadProgress(const net::URLFetcher* source,
diff --git a/components/sessions/core/base_session_service.cc b/components/sessions/core/base_session_service.cc
index ba4a368..3e76628 100644
--- a/components/sessions/core/base_session_service.cc
+++ b/components/sessions/core/base_session_service.cc
@@ -39,7 +39,7 @@
     callback.Run(std::move(commands));
   } else {
     task_runner->PostTask(FROM_HERE,
-                          base::Bind(callback, base::Passed(&commands)));
+                          base::BindOnce(callback, std::move(commands)));
   }
 }
 
@@ -139,9 +139,8 @@
   // We create a new vector which will receive all elements from the
   // current commands. This will also clear the current list.
   RunTaskOnBackendThread(
-      FROM_HERE,
-      base::BindOnce(&SessionBackend::AppendCommands, backend_,
-                     base::Passed(&pending_commands_), pending_reset_));
+      FROM_HERE, base::BindOnce(&SessionBackend::AppendCommands, backend_,
+                                std::move(pending_commands_), pending_reset_));
 
   if (pending_reset_) {
     commands_since_reset_ = 0;
diff --git a/components/subresource_filter/content/browser/async_document_subresource_filter.cc b/components/subresource_filter/content/browser/async_document_subresource_filter.cc
index 94dd814..9dd0c275 100644
--- a/components/subresource_filter/content/browser/async_document_subresource_filter.cc
+++ b/components/subresource_filter/content/browser/async_document_subresource_filter.cc
@@ -111,11 +111,11 @@
   // below task is posted.
   base::PostTaskAndReplyWithResult(
       task_runner_, FROM_HERE,
-      base::Bind(&Core::Initialize, base::Unretained(core_.get()),
-                 base::Passed(&params), ruleset_handle->ruleset_.get()),
-      base::Bind(&AsyncDocumentSubresourceFilter::OnActivateStateCalculated,
-                 weak_ptr_factory_.GetWeakPtr(),
-                 std::move(activation_state_callback)));
+      base::BindOnce(&Core::Initialize, base::Unretained(core_.get()),
+                     std::move(params), ruleset_handle->ruleset_.get()),
+      base::BindOnce(&AsyncDocumentSubresourceFilter::OnActivateStateCalculated,
+                     weak_ptr_factory_.GetWeakPtr(),
+                     std::move(activation_state_callback)));
 }
 
 AsyncDocumentSubresourceFilter::~AsyncDocumentSubresourceFilter() {
diff --git a/components/subresource_filter/content/browser/content_ruleset_service.cc b/components/subresource_filter/content/browser/content_ruleset_service.cc
index 90c4fe1..bad103d 100644
--- a/components/subresource_filter/content/browser/content_ruleset_service.cc
+++ b/components/subresource_filter/content/browser/content_ruleset_service.cc
@@ -41,7 +41,7 @@
     return;
   base::PostTaskWithTraits(FROM_HERE,
                            {base::TaskPriority::BACKGROUND, base::MayBlock()},
-                           base::Bind(&CloseFile, base::Passed(file)));
+                           base::BindOnce(&CloseFile, std::move(*file)));
 }
 
 }  // namespace
diff --git a/components/subresource_filter/content/browser/verified_ruleset_dealer.cc b/components/subresource_filter/content/browser/verified_ruleset_dealer.cc
index 2ec1c37..33ce31c 100644
--- a/components/subresource_filter/content/browser/verified_ruleset_dealer.cc
+++ b/components/subresource_filter/content/browser/verified_ruleset_dealer.cc
@@ -4,6 +4,8 @@
 
 #include "components/subresource_filter/content/browser/verified_ruleset_dealer.h"
 
+#include <utility>
+
 #include "base/bind.h"
 #include "base/bind_helpers.h"
 #include "base/files/file.h"
@@ -79,8 +81,8 @@
   DCHECK(sequence_checker_.CalledOnValidSequence());
   task_runner_->PostTask(
       FROM_HERE,
-      base::Bind(&VerifiedRulesetDealer::SetRulesetFile,
-                 base::Unretained(dealer_.get()), base::Passed(&file)));
+      base::BindOnce(&VerifiedRulesetDealer::SetRulesetFile,
+                     base::Unretained(dealer_.get()), std::move(file)));
 }
 
 // VerifiedRuleset and its Handle. ---------------------------------------------
diff --git a/components/sync/device_info/device_info_sync_bridge_unittest.cc b/components/sync/device_info/device_info_sync_bridge_unittest.cc
index 0e09254..5ba1aab 100644
--- a/components/sync/device_info/device_info_sync_bridge_unittest.cc
+++ b/components/sync/device_info/device_info_sync_bridge_unittest.cc
@@ -185,7 +185,7 @@
     bridge_ = std::make_unique<DeviceInfoSyncBridge>(
         provider_.get(),
         base::BindOnce(&ModelTypeStoreTestUtil::MoveStoreToCallback,
-                       base::Passed(&store_)),
+                       std::move(store_)),
         RecordingModelTypeChangeProcessor::FactoryForBridgeTest(&processor_));
     bridge_->AddObserver(this);
   }
diff --git a/components/sync/driver/async_directory_type_controller_unittest.cc b/components/sync/driver/async_directory_type_controller_unittest.cc
index 2e052bc..8d26223 100644
--- a/components/sync/driver/async_directory_type_controller_unittest.cc
+++ b/components/sync/driver/async_directory_type_controller_unittest.cc
@@ -467,9 +467,8 @@
   SyncError error(FROM_HERE, SyncError::DATATYPE_ERROR, "error",
                   non_ui_dtc_->type());
   backend_thread_.task_runner()->PostTask(
-      FROM_HERE,
-      base::Bind(&DataTypeErrorHandler::OnUnrecoverableError,
-                 base::Passed(non_ui_dtc_->CreateErrorHandler()), error));
+      FROM_HERE, base::BindOnce(&DataTypeErrorHandler::OnUnrecoverableError,
+                                non_ui_dtc_->CreateErrorHandler(), error));
   WaitForDTC();
 }
 
diff --git a/components/sync/driver/glue/sync_backend_host_impl.cc b/components/sync/driver/glue/sync_backend_host_impl.cc
index ccd29569..39a1603 100644
--- a/components/sync/driver/glue/sync_backend_host_impl.cc
+++ b/components/sync/driver/glue/sync_backend_host_impl.cc
@@ -71,8 +71,8 @@
   registrar_ = params.registrar.get();
 
   sync_task_runner_->PostTask(
-      FROM_HERE, base::Bind(&SyncBackendHostCore::DoInitialize, core_,
-                            base::Passed(&params)));
+      FROM_HERE, base::BindOnce(&SyncBackendHostCore::DoInitialize, core_,
+                                std::move(params)));
 }
 
 void SyncBackendHostImpl::TriggerRefresh(const ModelTypeSet& types) {
@@ -162,8 +162,8 @@
       base::Bind(&SyncBackendHostCore::DoPurgeDisabledTypes, core_,
                  params.to_purge, params.to_journal, params.to_unapply));
   sync_task_runner_->PostTask(
-      FROM_HERE, base::Bind(&SyncBackendHostCore::DoConfigureSyncer, core_,
-                            base::Passed(&params)));
+      FROM_HERE, base::BindOnce(&SyncBackendHostCore::DoConfigureSyncer, core_,
+                                std::move(params)));
 }
 
 void SyncBackendHostImpl::RegisterDirectoryDataType(ModelType type,
diff --git a/components/sync/driver/model_type_controller.cc b/components/sync/driver/model_type_controller.cc
index 83be1bc9..ef8640c2 100644
--- a/components/sync/driver/model_type_controller.cc
+++ b/components/sync/driver/model_type_controller.cc
@@ -265,8 +265,8 @@
                                          BridgeTask task) {
   DCHECK(model_thread_);
   model_thread_->PostTask(
-      location, base::Bind(&RunBridgeTask, base::Passed(GetBridgeProvider()),
-                           base::Passed(std::move(task))));
+      location,
+      base::BindOnce(&RunBridgeTask, GetBridgeProvider(), std::move(task)));
 }
 
 }  // namespace syncer
diff --git a/components/sync/engine/model_safe_worker.cc b/components/sync/engine/model_safe_worker.cc
index d7f109bb3..4fff0da5 100644
--- a/components/sync/engine/model_safe_worker.cc
+++ b/components/sync/engine/model_safe_worker.cc
@@ -112,14 +112,14 @@
 
   SyncerError error = UNSET;
   bool did_run = false;
-  ScheduleWork(base::BindOnce(
-      &ModelSafeWorker::DoWork, this, base::Passed(std::move(work)),
-      base::Passed(base::ScopedClosureRunner(base::Bind(
-          [](scoped_refptr<ModelSafeWorker> worker) {
-            worker->work_done_or_abandoned_.Signal();
-          },
-          base::WrapRefCounted(this)))),
-      base::Unretained(&error), base::Unretained(&did_run)));
+  ScheduleWork(base::BindOnce(&ModelSafeWorker::DoWork, this, std::move(work),
+                              base::ScopedClosureRunner(base::BindOnce(
+                                  [](scoped_refptr<ModelSafeWorker> worker) {
+                                    worker->work_done_or_abandoned_.Signal();
+                                  },
+                                  base::WrapRefCounted(this))),
+                              base::Unretained(&error),
+                              base::Unretained(&did_run)));
 
   // Unblocked when the task runs or is deleted or when RequestStop() is called
   // before the task starts running.
diff --git a/components/sync/engine/model_safe_worker_unittest.cc b/components/sync/engine/model_safe_worker_unittest.cc
index 1de6012..5836150c 100644
--- a/components/sync/engine/model_safe_worker_unittest.cc
+++ b/components/sync/engine/model_safe_worker_unittest.cc
@@ -65,12 +65,12 @@
 
   void DoWorkAndWaitUntilDoneOnSyncThread(base::Closure work) {
     sync_thread_.task_runner()->PostTask(
-        FROM_HERE,
-        base::Bind(base::IgnoreResult(&ModelSafeWorker::DoWorkAndWaitUntilDone),
-                   worker_, base::Passed(ClosureToWorkCallback(work))));
+        FROM_HERE, base::BindOnce(base::IgnoreResult(
+                                      &ModelSafeWorker::DoWorkAndWaitUntilDone),
+                                  worker_, ClosureToWorkCallback(work)));
     sync_thread_.task_runner()->PostTask(
-        FROM_HERE, base::Bind(&base::AtomicFlag::Set,
-                              base::Unretained(&sync_thread_unblocked_)));
+        FROM_HERE, base::BindOnce(&base::AtomicFlag::Set,
+                                  base::Unretained(&sync_thread_unblocked_)));
   }
 
   base::AtomicFlag sync_thread_unblocked_;
diff --git a/components/sync/engine/model_type_processor_proxy.cc b/components/sync/engine/model_type_processor_proxy.cc
index 5a990fc3..dd96731 100644
--- a/components/sync/engine/model_type_processor_proxy.cc
+++ b/components/sync/engine/model_type_processor_proxy.cc
@@ -21,8 +21,8 @@
 
 void ModelTypeProcessorProxy::ConnectSync(std::unique_ptr<CommitQueue> worker) {
   task_runner_->PostTask(
-      FROM_HERE, base::Bind(&ModelTypeProcessor::ConnectSync, processor_,
-                            base::Passed(std::move(worker))));
+      FROM_HERE, base::BindOnce(&ModelTypeProcessor::ConnectSync, processor_,
+                                std::move(worker)));
 }
 
 void ModelTypeProcessorProxy::DisconnectSync() {
diff --git a/components/sync/engine/ui_model_worker_unittest.cc b/components/sync/engine/ui_model_worker_unittest.cc
index b7223b5..c82ba1be 100644
--- a/components/sync/engine/ui_model_worker_unittest.cc
+++ b/components/sync/engine/ui_model_worker_unittest.cc
@@ -50,9 +50,9 @@
 
   void PostWorkToSyncThread(base::Closure work) {
     sync_thread_.task_runner()->PostTask(
-        FROM_HERE,
-        base::Bind(base::IgnoreResult(&UIModelWorker::DoWorkAndWaitUntilDone),
-                   worker_, base::Passed(ClosureToWorkCallback(work))));
+        FROM_HERE, base::BindOnce(base::IgnoreResult(
+                                      &UIModelWorker::DoWorkAndWaitUntilDone),
+                                  worker_, ClosureToWorkCallback(work)));
   }
 
  protected:
diff --git a/components/sync/engine_impl/model_type_connector_proxy.cc b/components/sync/engine_impl/model_type_connector_proxy.cc
index 86adea02..895bb40 100644
--- a/components/sync/engine_impl/model_type_connector_proxy.cc
+++ b/components/sync/engine_impl/model_type_connector_proxy.cc
@@ -4,6 +4,8 @@
 
 #include "components/sync/engine_impl/model_type_connector_proxy.h"
 
+#include <utility>
+
 #include "base/bind.h"
 #include "base/location.h"
 #include "base/single_thread_task_runner.h"
@@ -21,10 +23,10 @@
 void ModelTypeConnectorProxy::ConnectNonBlockingType(
     ModelType type,
     std::unique_ptr<ActivationContext> activation_context) {
-  task_runner_->PostTask(FROM_HERE,
-                         base::Bind(&ModelTypeConnector::ConnectNonBlockingType,
-                                    model_type_connector_, type,
-                                    base::Passed(&activation_context)));
+  task_runner_->PostTask(
+      FROM_HERE, base::BindOnce(&ModelTypeConnector::ConnectNonBlockingType,
+                                model_type_connector_, type,
+                                std::move(activation_context)));
 }
 
 void ModelTypeConnectorProxy::DisconnectNonBlockingType(ModelType type) {
diff --git a/components/sync/model/mock_model_type_store.h b/components/sync/model/mock_model_type_store.h
index 813a22761..37120317 100644
--- a/components/sync/model/mock_model_type_store.h
+++ b/components/sync/model/mock_model_type_store.h
@@ -30,7 +30,7 @@
 //   record_list->push_back(ModelTypeStore::Record("id1", "value1"));
 //   base::ThreadTaskRunnerHandle::Get()->PostTask(
 //       FROM_HERE, base::BindOnce(callback, /*error=*/base::nullopt,
-//                                 base::Passed(record_list)));
+//                                 std::move(record_list)));
 // }
 //
 // MockModelTypeStore mock_model_type_store;
diff --git a/components/sync_sessions/BUILD.gn b/components/sync_sessions/BUILD.gn
index 8fb5705..b251775a 100644
--- a/components/sync_sessions/BUILD.gn
+++ b/components/sync_sessions/BUILD.gn
@@ -11,24 +11,6 @@
     "lost_navigations_recorder.h",
     "open_tabs_ui_delegate.cc",
     "open_tabs_ui_delegate.h",
-    "revisit/bookmarks_by_url_provider_impl.cc",
-    "revisit/bookmarks_by_url_provider_impl.h",
-    "revisit/bookmarks_page_revisit_observer.cc",
-    "revisit/bookmarks_page_revisit_observer.h",
-    "revisit/current_tab_matcher.cc",
-    "revisit/current_tab_matcher.h",
-    "revisit/offset_tab_matcher.cc",
-    "revisit/offset_tab_matcher.h",
-    "revisit/page_equality.h",
-    "revisit/page_revisit_broadcaster.cc",
-    "revisit/page_revisit_broadcaster.h",
-    "revisit/page_visit_observer.h",
-    "revisit/sessions_page_revisit_observer.cc",
-    "revisit/sessions_page_revisit_observer.h",
-    "revisit/typed_url_page_revisit_observer.cc",
-    "revisit/typed_url_page_revisit_observer.h",
-    "revisit/typed_url_page_revisit_task.cc",
-    "revisit/typed_url_page_revisit_task.h",
     "session_data_type_controller.cc",
     "session_data_type_controller.h",
     "sessions_global_id_mapper.cc",
@@ -97,12 +79,6 @@
   sources = [
     "favicon_cache_unittest.cc",
     "lost_navigations_recorder_unittest.cc",
-    "revisit/bookmarks_page_revisit_observer_unittest.cc",
-    "revisit/current_tab_matcher_unittest.cc",
-    "revisit/offset_tab_matcher_unittest.cc",
-    "revisit/page_revisit_broadcaster_unittest.cc",
-    "revisit/sessions_page_revisit_observer_unittest.cc",
-    "revisit/typed_url_page_revisit_task_unittest.cc",
     "session_data_type_controller_unittest.cc",
     "sessions_global_id_mapper_unittest.cc",
     "sessions_sync_manager_unittest.cc",
diff --git a/components/sync_sessions/revisit/bookmarks_by_url_provider_impl.cc b/components/sync_sessions/revisit/bookmarks_by_url_provider_impl.cc
deleted file mode 100644
index 7d234cd..0000000
--- a/components/sync_sessions/revisit/bookmarks_by_url_provider_impl.cc
+++ /dev/null
@@ -1,23 +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/sync_sessions/revisit/bookmarks_by_url_provider_impl.h"
-
-#include "components/bookmarks/browser/bookmark_model.h"
-#include "components/bookmarks/browser/bookmark_node.h"
-#include "url/gurl.h"
-
-namespace sync_sessions {
-
-BookmarksByUrlProviderImpl::BookmarksByUrlProviderImpl(
-    bookmarks::BookmarkModel* model)
-    : model_(model) {}
-
-void BookmarksByUrlProviderImpl::GetNodesByURL(
-    const GURL& url,
-    std::vector<const bookmarks::BookmarkNode*>* nodes) {
-  model_->GetNodesByURL(url, nodes);
-}
-
-}  // namespace sync_sessions
diff --git a/components/sync_sessions/revisit/bookmarks_by_url_provider_impl.h b/components/sync_sessions/revisit/bookmarks_by_url_provider_impl.h
deleted file mode 100644
index 45252d3..0000000
--- a/components/sync_sessions/revisit/bookmarks_by_url_provider_impl.h
+++ /dev/null
@@ -1,39 +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_SYNC_SESSIONS_REVISIT_BOOKMARKS_BY_URL_PROVIDER_IMPL_H_
-#define COMPONENTS_SYNC_SESSIONS_REVISIT_BOOKMARKS_BY_URL_PROVIDER_IMPL_H_
-
-#include <vector>
-
-#include "base/macros.h"
-#include "components/sync_sessions/revisit/bookmarks_page_revisit_observer.h"
-
-class GURL;
-
-namespace bookmarks {
-class BookmarkModel;
-class BookmarkNode;
-}  // namespace bookmarks
-
-namespace sync_sessions {
-
-// Simple implementation of BookmarksByUrlProvider that delegates to a
-// BookmarkModel. It holds a non-owning pointer, with the assumption that this
-// object is destroyed before the BookmarkModel.
-class BookmarksByUrlProviderImpl : public BookmarksByUrlProvider {
- public:
-  explicit BookmarksByUrlProviderImpl(bookmarks::BookmarkModel* model);
-  void GetNodesByURL(
-      const GURL& url,
-      std::vector<const bookmarks::BookmarkNode*>* nodes) override;
-
- private:
-  bookmarks::BookmarkModel* model_;
-  DISALLOW_COPY_AND_ASSIGN(BookmarksByUrlProviderImpl);
-};
-
-}  // namespace sync_sessions
-
-#endif  // COMPONENTS_SYNC_SESSIONS_REVISIT_BOOKMARKS_BY_URL_PROVIDER_IMPL_H_
diff --git a/components/sync_sessions/revisit/bookmarks_page_revisit_observer.cc b/components/sync_sessions/revisit/bookmarks_page_revisit_observer.cc
deleted file mode 100644
index 813348a..0000000
--- a/components/sync_sessions/revisit/bookmarks_page_revisit_observer.cc
+++ /dev/null
@@ -1,52 +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/sync_sessions/revisit/bookmarks_page_revisit_observer.h"
-
-#include <algorithm>
-#include <utility>
-
-#include "base/metrics/histogram_macros.h"
-#include "base/time/time.h"
-#include "components/bookmarks/browser/bookmark_model.h"
-#include "components/bookmarks/browser/bookmark_node.h"
-#include "url/gurl.h"
-
-namespace sync_sessions {
-
-BookmarksPageRevisitObserver::BookmarksPageRevisitObserver(
-    std::unique_ptr<BookmarksByUrlProvider> provider)
-    : provider_(std::move(provider)) {}
-
-BookmarksPageRevisitObserver::~BookmarksPageRevisitObserver() {}
-
-void BookmarksPageRevisitObserver::OnPageVisit(
-    const GURL& url,
-    const TransitionType transition) {
-  base::TimeTicks start(base::TimeTicks::Now());
-
-  std::vector<const bookmarks::BookmarkNode*> nodes;
-  provider_->GetNodesByURL(url, &nodes);
-  if (nodes.empty()) {
-    UMA_HISTOGRAM_ENUMERATION("Sync.PageRevisitBookmarksMissTransition",
-                              transition,
-                              PageVisitObserver::kTransitionTypeLast);
-  } else {
-    auto last_added = std::max_element(
-        nodes.begin(), nodes.end(),
-        [](const bookmarks::BookmarkNode* a, const bookmarks::BookmarkNode* b) {
-          return a->date_added() < b->date_added();
-        });
-    REVISIT_HISTOGRAM_AGE("Sync.PageRevisitBookmarksMatchAge",
-                          (*last_added)->date_added());
-    UMA_HISTOGRAM_ENUMERATION("Sync.PageRevisitBookmarksMatchTransition",
-                              transition,
-                              PageVisitObserver::kTransitionTypeLast);
-  }
-
-  base::TimeDelta duration(base::TimeTicks::Now() - start);
-  UMA_HISTOGRAM_TIMES("Sync.PageRevisitBookmarksDuration", duration);
-}
-
-}  // namespace sync_sessions
diff --git a/components/sync_sessions/revisit/bookmarks_page_revisit_observer.h b/components/sync_sessions/revisit/bookmarks_page_revisit_observer.h
deleted file mode 100644
index e016149..0000000
--- a/components/sync_sessions/revisit/bookmarks_page_revisit_observer.h
+++ /dev/null
@@ -1,53 +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_SYNC_SESSIONS_REVISIT_BOOKMARKS_PAGE_REVISIT_OBSERVER_H_
-#define COMPONENTS_SYNC_SESSIONS_REVISIT_BOOKMARKS_PAGE_REVISIT_OBSERVER_H_
-
-#include <memory>
-#include <vector>
-
-#include "base/macros.h"
-#include "components/sync_sessions/revisit/page_visit_observer.h"
-
-class GURL;
-
-namespace bookmarks {
-class BookmarkNode;
-}  // namespace bookmarks
-
-namespace sync_sessions {
-
-// A simple interface to abstract away who is providing bookmarks.
-class BookmarksByUrlProvider {
- public:
-  // Fills the passed vector with all bookmark nodes for the given URL.
-  virtual void GetNodesByURL(
-      const GURL& url,
-      std::vector<const bookmarks::BookmarkNode*>* nodes) = 0;
-  virtual ~BookmarksByUrlProvider() {}
-};
-
-// Responds to OnPageVisit events by looking for bookmarks with matching URLs,
-// and emits metrics about the results. If multiple bookmarks match, the most
-// recently created one is used. Currently there isn't enough information to
-// determine modificatoin times or remote vs local. This observer does all
-// processing in task/thread, which is okay since it only accesses values in
-// memory. Potential slow downs could occur when it fails to get bookmarks lock
-// and when the number of matching Bookmarks for a single URL is very large.
-class BookmarksPageRevisitObserver : public PageVisitObserver {
- public:
-  explicit BookmarksPageRevisitObserver(
-      std::unique_ptr<BookmarksByUrlProvider> provider);
-  ~BookmarksPageRevisitObserver() override;
-  void OnPageVisit(const GURL& url, const TransitionType transition) override;
-
- private:
-  std::unique_ptr<BookmarksByUrlProvider> provider_;
-  DISALLOW_COPY_AND_ASSIGN(BookmarksPageRevisitObserver);
-};
-
-}  // namespace sync_sessions
-
-#endif  // COMPONENTS_SYNC_SESSIONS_REVISIT_BOOKMARKS_PAGE_REVISIT_OBSERVER_H_
diff --git a/components/sync_sessions/revisit/bookmarks_page_revisit_observer_unittest.cc b/components/sync_sessions/revisit/bookmarks_page_revisit_observer_unittest.cc
deleted file mode 100644
index e9dd2cea6..0000000
--- a/components/sync_sessions/revisit/bookmarks_page_revisit_observer_unittest.cc
+++ /dev/null
@@ -1,80 +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/sync_sessions/revisit/bookmarks_page_revisit_observer.h"
-
-#include "base/test/histogram_tester.h"
-#include "components/bookmarks/browser/bookmark_node.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#include "url/gurl.h"
-
-namespace sync_sessions {
-
-namespace {
-
-static const GURL kExampleGurl = GURL("http://www.example.com");
-
-class TestBookmarksByUrlProvider : public BookmarksByUrlProvider {
- public:
-  TestBookmarksByUrlProvider(
-      const std::vector<const bookmarks::BookmarkNode*>& nodes)
-      : nodes_(nodes) {}
-  void GetNodesByURL(
-      const GURL& url,
-      std::vector<const bookmarks::BookmarkNode*>* nodes) override {
-    *nodes = nodes_;
-  }
-
- private:
-  const std::vector<const bookmarks::BookmarkNode*>& nodes_;
-};
-
-}  // namespace
-
-void RunObserver(const std::vector<const bookmarks::BookmarkNode*>& nodes) {
-  BookmarksPageRevisitObserver observer(
-      std::make_unique<TestBookmarksByUrlProvider>(nodes));
-  observer.OnPageVisit(kExampleGurl, PageVisitObserver::kTransitionPage);
-}
-
-void ExpectMiss(const std::vector<const bookmarks::BookmarkNode*>& nodes) {
-  base::HistogramTester histogram_tester;
-  RunObserver(nodes);
-  histogram_tester.ExpectUniqueSample("Sync.PageRevisitBookmarksMissTransition",
-                                      PageVisitObserver::kTransitionPage, 1);
-  histogram_tester.ExpectTotalCount("Sync.PageRevisitBookmarksDuration", 1);
-}
-
-void ExpectMatch(const std::vector<const bookmarks::BookmarkNode*>& nodes) {
-  base::HistogramTester histogram_tester;
-  RunObserver(nodes);
-  histogram_tester.ExpectTotalCount("Sync.PageRevisitBookmarksMatchAge", 1);
-  histogram_tester.ExpectUniqueSample(
-      "Sync.PageRevisitBookmarksMatchTransition",
-      PageVisitObserver::kTransitionPage, 1);
-  histogram_tester.ExpectTotalCount("Sync.PageRevisitBookmarksDuration", 1);
-}
-
-TEST(BookmarksPageRevisitObserver, NoMatchingBookmarks) {
-  std::vector<const bookmarks::BookmarkNode*> nodes;
-  ExpectMiss(nodes);
-}
-
-TEST(BookmarksPageRevisitObserver, OneMatchingBookmark) {
-  bookmarks::BookmarkNode node(kExampleGurl);
-  std::vector<const bookmarks::BookmarkNode*> nodes;
-  nodes.push_back(&node);
-  ExpectMatch(nodes);
-}
-
-TEST(BookmarksPageRevisitObserver, MultipleMatchingBookmarks) {
-  bookmarks::BookmarkNode node1(kExampleGurl);
-  bookmarks::BookmarkNode node2(kExampleGurl);
-  std::vector<const bookmarks::BookmarkNode*> nodes;
-  nodes.push_back(&node1);
-  nodes.push_back(&node2);
-  ExpectMatch(nodes);
-}
-
-}  // namespace sync_sessions
diff --git a/components/sync_sessions/revisit/current_tab_matcher.cc b/components/sync_sessions/revisit/current_tab_matcher.cc
deleted file mode 100644
index 2f70eb3..0000000
--- a/components/sync_sessions/revisit/current_tab_matcher.cc
+++ /dev/null
@@ -1,45 +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/sync_sessions/revisit/current_tab_matcher.h"
-
-#include "base/metrics/histogram_macros.h"
-#include "base/time/time.h"
-#include "components/sessions/core/serialized_navigation_entry.h"
-#include "components/sessions/core/session_types.h"
-
-namespace sync_sessions {
-
-CurrentTabMatcher::CurrentTabMatcher(const PageEquality& page_equality)
-    : page_equality_(page_equality) {}
-
-void CurrentTabMatcher::Check(const sessions::SessionTab* tab) {
-  if (tab->navigations.empty()) {
-    return;
-  }
-  const sessions::SerializedNavigationEntry& currentEntry =
-      tab->navigations[tab->normalized_navigation_index()];
-  // Cannot rely on SerializedNavigationEntry timestamps, they're
-  // not set for foreign sessions. Instead rely on tab timestamps.
-  if (page_equality_.IsSamePage(currentEntry.virtual_url()) &&
-      (most_recent_match_ == nullptr ||
-       tab->timestamp > most_recent_match_->timestamp)) {
-    most_recent_match_ = tab;
-  }
-}
-
-void CurrentTabMatcher::Emit(
-    const PageVisitObserver::TransitionType transition) {
-  if (most_recent_match_ == nullptr) {
-    UMA_HISTOGRAM_ENUMERATION("Sync.PageRevisitTabMissTransition", transition,
-                              PageVisitObserver::kTransitionTypeLast);
-  } else {
-    REVISIT_HISTOGRAM_AGE("Sync.PageRevisitTabMatchAge",
-                          most_recent_match_->timestamp);
-    UMA_HISTOGRAM_ENUMERATION("Sync.PageRevisitTabMatchTransition", transition,
-                              PageVisitObserver::kTransitionTypeLast);
-  }
-}
-
-}  // namespace sync_sessions
diff --git a/components/sync_sessions/revisit/current_tab_matcher.h b/components/sync_sessions/revisit/current_tab_matcher.h
deleted file mode 100644
index 2aa037c8..0000000
--- a/components/sync_sessions/revisit/current_tab_matcher.h
+++ /dev/null
@@ -1,39 +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_SYNC_SESSIONS_REVISIT_CURRENT_TAB_MATCHER_H_
-#define COMPONENTS_SYNC_SESSIONS_REVISIT_CURRENT_TAB_MATCHER_H_
-
-#include "base/gtest_prod_util.h"
-#include "base/macros.h"
-#include "components/sync_sessions/revisit/page_equality.h"
-#include "components/sync_sessions/revisit/page_visit_observer.h"
-
-namespace sessions {
-struct SessionTab;
-};  // namespace sessions
-
-namespace sync_sessions {
-
-// This class checks the current navigation entry for the given tabs to see if
-// they correspond to the same page we were constructed to look for. Upon
-// finding multiple matches, the most recently modified will be chosen.
-class CurrentTabMatcher {
- public:
-  explicit CurrentTabMatcher(const PageEquality& page_equality);
-  void Check(const sessions::SessionTab* tab);
-  void Emit(const PageVisitObserver::TransitionType transition);
-
- private:
-  FRIEND_TEST_ALL_PREFIXES(CurrentTabMatcherTest, Timestamp);
-
-  const PageEquality page_equality_;
-  const sessions::SessionTab* most_recent_match_ = nullptr;
-
-  DISALLOW_COPY_AND_ASSIGN(CurrentTabMatcher);
-};
-
-}  // namespace sync_sessions
-
-#endif  // COMPONENTS_SYNC_SESSIONS_REVISIT_CURRENT_TAB_MATCHER_H_
diff --git a/components/sync_sessions/revisit/current_tab_matcher_unittest.cc b/components/sync_sessions/revisit/current_tab_matcher_unittest.cc
deleted file mode 100644
index 4add6b7..0000000
--- a/components/sync_sessions/revisit/current_tab_matcher_unittest.cc
+++ /dev/null
@@ -1,115 +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/sync_sessions/revisit/current_tab_matcher.h"
-
-#include <memory>
-#include <string>
-
-#include "base/test/histogram_tester.h"
-#include "base/time/time.h"
-#include "components/sessions/core/serialized_navigation_entry.h"
-#include "components/sessions/core/serialized_navigation_entry_test_helper.h"
-#include "components/sessions/core/session_types.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#include "url/gurl.h"
-
-using sessions::SessionTab;
-
-namespace sync_sessions {
-
-namespace {
-
-const char kExampleUrl[] = "http://www.example.com";
-const char kDifferentUrl[] = "http://www.different.com";
-
-sessions::SerializedNavigationEntry Entry(const std::string& url) {
-  return sessions::SerializedNavigationEntryTestHelper::CreateNavigation(url,
-                                                                         "");
-}
-
-std::unique_ptr<SessionTab> Tab(const int index, const base::Time timestamp) {
-  std::unique_ptr<SessionTab> tab(new SessionTab());
-  tab->current_navigation_index = index;
-  tab->timestamp = timestamp;
-  return tab;
-}
-
-void VerifyMatch(CurrentTabMatcher* matcher) {
-  base::HistogramTester histogram_tester;
-  matcher->Emit(PageVisitObserver::kTransitionPage);
-  histogram_tester.ExpectUniqueSample("Sync.PageRevisitTabMatchTransition",
-                                      PageVisitObserver::kTransitionPage, 1);
-  histogram_tester.ExpectTotalCount("Sync.PageRevisitTabMatchAge", 1);
-}
-
-void VerifyMiss(CurrentTabMatcher* matcher) {
-  base::HistogramTester histogram_tester;
-  matcher->Emit(PageVisitObserver::kTransitionPage);
-  histogram_tester.ExpectUniqueSample("Sync.PageRevisitTabMissTransition",
-                                      PageVisitObserver::kTransitionPage, 1);
-}
-
-}  // namespace
-
-TEST(CurrentTabMatcherTest, NoCheck) {
-  CurrentTabMatcher matcher((PageEquality(GURL(kExampleUrl))));
-  VerifyMiss(&matcher);
-}
-
-TEST(CurrentTabMatcherTest, EmptyTab) {
-  std::unique_ptr<SessionTab> tab = Tab(0, base::Time::Now());
-  CurrentTabMatcher matcher((PageEquality(GURL(kExampleUrl))));
-  matcher.Check(tab.get());
-  VerifyMiss(&matcher);
-}
-
-TEST(CurrentTabMatcherTest, SameUrl) {
-  std::unique_ptr<SessionTab> tab = Tab(0, base::Time::Now());
-  tab->navigations.push_back(Entry(kExampleUrl));
-
-  CurrentTabMatcher matcher((PageEquality(GURL(kExampleUrl))));
-  matcher.Check(tab.get());
-  VerifyMatch(&matcher);
-}
-
-TEST(CurrentTabMatcherTest, DifferentUrl) {
-  std::unique_ptr<SessionTab> tab = Tab(0, base::Time::Now());
-  tab->navigations.push_back(Entry(kDifferentUrl));
-
-  CurrentTabMatcher matcher((PageEquality(GURL(kExampleUrl))));
-  matcher.Check(tab.get());
-  VerifyMiss(&matcher);
-}
-
-TEST(CurrentTabMatcherTest, DifferentIndex) {
-  std::unique_ptr<SessionTab> tab = Tab(0, base::Time::Now());
-  tab->navigations.push_back(Entry(kDifferentUrl));
-  tab->navigations.push_back(Entry(kExampleUrl));
-
-  CurrentTabMatcher matcher((PageEquality(GURL(kExampleUrl))));
-  matcher.Check(tab.get());
-  VerifyMiss(&matcher);
-}
-
-TEST(CurrentTabMatcherTest, Timestamp) {
-  std::unique_ptr<SessionTab> tab1 = Tab(0, base::Time::UnixEpoch());
-  tab1->navigations.push_back(Entry(kExampleUrl));
-
-  std::unique_ptr<SessionTab> tab2 = Tab(0, base::Time::Now());
-  tab2->navigations.push_back(Entry(kExampleUrl));
-
-  CurrentTabMatcher matcher1((PageEquality(GURL(kExampleUrl))));
-  matcher1.Check(tab1.get());
-  matcher1.Check(tab2.get());
-  ASSERT_EQ(tab2.get(), matcher1.most_recent_match_);
-
-  // Now repeat the same test but check the tabs in the opposite order.
-  CurrentTabMatcher matcher2((PageEquality(GURL(kExampleUrl))));
-  matcher2.Check(tab2.get());
-  matcher2.Check(tab1.get());
-  ASSERT_EQ(tab2.get(), matcher2.most_recent_match_);
-}
-
-}  // namespace sync_sessions
diff --git a/components/sync_sessions/revisit/offset_tab_matcher.cc b/components/sync_sessions/revisit/offset_tab_matcher.cc
deleted file mode 100644
index 545f2ef..0000000
--- a/components/sync_sessions/revisit/offset_tab_matcher.cc
+++ /dev/null
@@ -1,82 +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/sync_sessions/revisit/offset_tab_matcher.h"
-
-#include <stddef.h>
-
-#include <algorithm>
-
-#include "base/metrics/histogram_functions.h"
-#include "base/metrics/histogram_macros.h"
-#include "components/sessions/core/serialized_navigation_entry.h"
-#include "components/sessions/core/session_types.h"
-
-namespace sync_sessions {
-
-namespace {
-
-// This is an upper bound of the max size of positive offset we will emit
-// correct metrics for. Anything larger than this will be clamped to this value.
-// This value doesn't exactly correspond to what we actually expect, this value
-// is currently larger than expected. This value is more for the safety of our
-// sparse histogram usage. It is assumed that the max negative offset is
-// symmetrical and can be found by taking the negative of this value.
-const int kMaxOffset = 10;
-
-}  // namespace
-
-OffsetTabMatcher::OffsetTabMatcher(const PageEquality& page_equality)
-    : page_equality_(page_equality) {}
-
-void OffsetTabMatcher::Check(const sessions::SessionTab* tab) {
-  const int current_index = tab->normalized_navigation_index();
-  for (std::size_t i = 0; i < tab->navigations.size(); ++i) {
-    // Ignore the entry if it is the current entry. There's actually some
-    // ambiguity here, the index of a tab is located in two places. Hopefully
-    // they are equal, but it is possible for the index() accessor of an entry
-    // to be different from the index in the tab's vector. Theoretically this
-    // should not happen outside of tab construction logic, but to be safe all
-    // matcher logic treats the index in the vector as the authoritative index.
-    // We chose this because the other matcher wants efficient random access.
-    if (current_index >= 0 && (std::size_t)current_index == i) {
-      continue;
-    }
-    const int offset = i - current_index;
-    if (page_equality_.IsSamePage(tab->navigations[i].virtual_url()) &&
-        (best_tab_ == nullptr || best_tab_->timestamp < tab->timestamp ||
-         (best_tab_->timestamp == tab->timestamp && best_offset_ < offset))) {
-      best_tab_ = tab;
-      best_offset_ = offset;
-    }
-  }
-}
-
-void OffsetTabMatcher::Emit(
-    const PageVisitObserver::TransitionType transition) {
-  if (best_tab_ == nullptr) {
-    UMA_HISTOGRAM_ENUMERATION("Sync.PageRevisitNavigationMissTransition",
-                              transition,
-                              PageVisitObserver::kTransitionTypeLast);
-  } else {
-    // The sparse macro allows us to handle negative offsets. However, we need
-    // to be careful when doing this because of the unrestricted nature of
-    // sparse we could end up with a very large output space across many
-    // clients. So we clamp on a resonable bound that's larger than we expect to
-    // be sure no unexpected data causes problems.
-    base::UmaHistogramSparse("Sync.PageRevisitNavigationMatchOffset",
-                             Clamp(best_offset_, -kMaxOffset, kMaxOffset));
-    REVISIT_HISTOGRAM_AGE("Sync.PageRevisitNavigationMatchAge",
-                          best_tab_->timestamp);
-    UMA_HISTOGRAM_ENUMERATION("Sync.PageRevisitNavigationMatchTransition",
-                              transition,
-                              PageVisitObserver::kTransitionTypeLast);
-  }
-}
-
-int OffsetTabMatcher::Clamp(const int input, const int lower, const int upper) {
-  return std::max(lower, std::min(upper, input));
-}
-
-}  // namespace sync_sessions
diff --git a/components/sync_sessions/revisit/offset_tab_matcher.h b/components/sync_sessions/revisit/offset_tab_matcher.h
deleted file mode 100644
index 725b05b..0000000
--- a/components/sync_sessions/revisit/offset_tab_matcher.h
+++ /dev/null
@@ -1,44 +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_SYNC_SESSIONS_REVISIT_OFFSET_TAB_MATCHER_H_
-#define COMPONENTS_SYNC_SESSIONS_REVISIT_OFFSET_TAB_MATCHER_H_
-
-#include "base/macros.h"
-#include "components/sync_sessions/revisit/page_equality.h"
-#include "components/sync_sessions/revisit/page_visit_observer.h"
-
-namespace sessions {
-struct SessionTab;
-};  // namespace sessions
-
-namespace sync_sessions {
-
-// This class looks for tabs that have matching pages that are not the current
-// navigation entry. This corresponds to the pages you would arrive at if you
-// pressed the forward/backwards buttons. The goal is to emit metrics for the
-// most recent/current entry. So to break ties of multiple entries that match,
-// first the timestamp on the tab is used, followed by the index of the entry.
-// This isn't necessarily perfect at determining the most recent, but it should
-// be a reasonable enough approximation.
-class OffsetTabMatcher {
- public:
-  explicit OffsetTabMatcher(const PageEquality& page_equality);
-  void Check(const sessions::SessionTab* tab);
-  void Emit(const PageVisitObserver::TransitionType transition);
-
- private:
-  int Clamp(int input, int lower, int upper);
-
-  const PageEquality page_equality_;
-  const sessions::SessionTab* best_tab_ = nullptr;
-  // Invalid while best_tab_ is nullptr.
-  int best_offset_ = 0;
-
-  DISALLOW_COPY_AND_ASSIGN(OffsetTabMatcher);
-};
-
-}  // namespace sync_sessions
-
-#endif  // COMPONENTS_SYNC_SESSIONS_REVISIT_OFFSET_TAB_MATCHER_H_
diff --git a/components/sync_sessions/revisit/offset_tab_matcher_unittest.cc b/components/sync_sessions/revisit/offset_tab_matcher_unittest.cc
deleted file mode 100644
index 4388c29d..0000000
--- a/components/sync_sessions/revisit/offset_tab_matcher_unittest.cc
+++ /dev/null
@@ -1,188 +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/sync_sessions/revisit/offset_tab_matcher.h"
-
-#include <memory>
-#include <string>
-
-#include "base/test/histogram_tester.h"
-#include "base/time/time.h"
-#include "components/sessions/core/serialized_navigation_entry.h"
-#include "components/sessions/core/serialized_navigation_entry_test_helper.h"
-#include "components/sessions/core/session_types.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#include "url/gurl.h"
-
-using sessions::SessionTab;
-
-namespace sync_sessions {
-
-namespace {
-
-const char kExampleUrl[] = "http://www.example.com";
-const char kDifferentUrl[] = "http://www.different.com";
-
-sessions::SerializedNavigationEntry Entry(const std::string& url) {
-  return sessions::SerializedNavigationEntryTestHelper::CreateNavigation(url,
-                                                                         "");
-}
-
-std::unique_ptr<SessionTab> Tab(
-    const int index,
-    const base::Time timestamp = base::Time::Now()) {
-  std::unique_ptr<SessionTab> tab(new SessionTab());
-  tab->current_navigation_index = index;
-  tab->timestamp = timestamp;
-  return tab;
-}
-
-void VerifyMatch(OffsetTabMatcher* matcher, const int offset) {
-  base::HistogramTester histogram_tester;
-  matcher->Emit(PageVisitObserver::kTransitionPage);
-  histogram_tester.ExpectUniqueSample("Sync.PageRevisitNavigationMatchOffset",
-                                      offset, 1);
-  histogram_tester.ExpectUniqueSample(
-      "Sync.PageRevisitNavigationMatchTransition",
-      PageVisitObserver::kTransitionPage, 1);
-  histogram_tester.ExpectTotalCount("Sync.PageRevisitNavigationMatchAge", 1);
-}
-
-void VerifyMiss(OffsetTabMatcher* matcher) {
-  base::HistogramTester histogram_tester;
-  matcher->Emit(PageVisitObserver::kTransitionPage);
-  histogram_tester.ExpectUniqueSample(
-      "Sync.PageRevisitNavigationMissTransition",
-      PageVisitObserver::kTransitionPage, 1);
-}
-
-}  // namespace
-
-TEST(OffsetTabMatcherTest, NoCheck) {
-  OffsetTabMatcher matcher((PageEquality(GURL(kExampleUrl))));
-  VerifyMiss(&matcher);
-}
-
-TEST(OffsetTabMatcherTest, EmptyTab) {
-  std::unique_ptr<SessionTab> tab = Tab(0);
-  OffsetTabMatcher matcher((PageEquality(GURL(kExampleUrl))));
-  matcher.Check(tab.get());
-  VerifyMiss(&matcher);
-}
-
-TEST(OffsetTabMatcherTest, HasMatchForward) {
-  std::unique_ptr<SessionTab> tab = Tab(0);
-  tab->navigations.push_back(Entry(kDifferentUrl));
-  tab->navigations.push_back(Entry(kExampleUrl));
-
-  OffsetTabMatcher matcher((PageEquality(GURL(kExampleUrl))));
-  matcher.Check(tab.get());
-  VerifyMatch(&matcher, 1);
-}
-
-TEST(OffsetTabMatcherTest, HasMatchBackward) {
-  std::unique_ptr<SessionTab> tab = Tab(1);
-  tab->navigations.push_back(Entry(kExampleUrl));
-  tab->navigations.push_back(Entry(kDifferentUrl));
-
-  OffsetTabMatcher matcher((PageEquality(GURL(kExampleUrl))));
-  matcher.Check(tab.get());
-  VerifyMatch(&matcher, -1);
-}
-
-TEST(OffsetTabMatcherTest, NoMatch) {
-  std::unique_ptr<SessionTab> tab = Tab(0);
-  tab->navigations.push_back(Entry(kExampleUrl));
-  tab->navigations.push_back(Entry(kDifferentUrl));
-
-  OffsetTabMatcher matcher((PageEquality(GURL(kExampleUrl))));
-  matcher.Check(tab.get());
-  VerifyMiss(&matcher);
-}
-
-TEST(OffsetTabMatcherTest, MultipleBackwardOffsets) {
-  std::unique_ptr<SessionTab> tab = Tab(4);
-  tab->navigations.push_back(Entry(kExampleUrl));
-  tab->navigations.push_back(Entry(kExampleUrl));
-  tab->navigations.push_back(Entry(kExampleUrl));  // Expected.
-  tab->navigations.push_back(Entry(kDifferentUrl));
-  tab->navigations.push_back(Entry(kExampleUrl));  // Current.
-
-  OffsetTabMatcher matcher((PageEquality(GURL(kExampleUrl))));
-  matcher.Check(tab.get());
-  VerifyMatch(&matcher, -2);
-}
-
-TEST(OffsetTabMatcherTest, MultipleOffsets) {
-  std::unique_ptr<SessionTab> tab = Tab(1);
-  tab->navigations.push_back(Entry(kExampleUrl));
-  tab->navigations.push_back(Entry(kExampleUrl));  // Current.
-  tab->navigations.push_back(Entry(kExampleUrl));
-  tab->navigations.push_back(Entry(kExampleUrl));  // Expected.
-  tab->navigations.push_back(Entry(kDifferentUrl));
-
-  OffsetTabMatcher matcher((PageEquality(GURL(kExampleUrl))));
-  matcher.Check(tab.get());
-  VerifyMatch(&matcher, 2);
-}
-
-TEST(OffsetTabMatcherTest, VeryForwardOffset) {
-  std::unique_ptr<SessionTab> tab = Tab(0);
-  for (int i = 0; i < 20; i++) {
-    tab->navigations.push_back(Entry(kDifferentUrl));
-  }
-  tab->navigations.push_back(Entry(kExampleUrl));
-
-  OffsetTabMatcher matcher((PageEquality(GURL(kExampleUrl))));
-  matcher.Check(tab.get());
-  // Expect the offset to be clamped to +10.
-  VerifyMatch(&matcher, 10);
-}
-
-TEST(OffsetTabMatcherTest, VeryBackwardOffset) {
-  std::unique_ptr<SessionTab> tab = Tab(20);
-  tab->navigations.push_back(Entry(kExampleUrl));
-  for (int i = 0; i < 20; i++) {
-    tab->navigations.push_back(Entry(kDifferentUrl));
-  }
-
-  OffsetTabMatcher matcher((PageEquality(GURL(kExampleUrl))));
-  matcher.Check(tab.get());
-  // Expect the offset to be clamped to -10.
-  VerifyMatch(&matcher, -10);
-}
-
-TEST(OffsetTabMatcherTest, MultipleTabs) {
-  std::unique_ptr<SessionTab> tab1 = Tab(0, base::Time::UnixEpoch());
-  tab1->navigations.push_back(Entry(kExampleUrl));
-  tab1->navigations.push_back(Entry(kExampleUrl));
-
-  std::unique_ptr<SessionTab> tab2 = Tab(1, base::Time::Now());
-  tab2->navigations.push_back(Entry(kExampleUrl));
-  tab2->navigations.push_back(Entry(kExampleUrl));
-
-  OffsetTabMatcher matcher((PageEquality(GURL(kExampleUrl))));
-  matcher.Check(tab1.get());
-  matcher.Check(tab2.get());
-  VerifyMatch(&matcher, -1);
-}
-
-TEST(OffsetTabMatcherTest, MultipleTabsSameTime) {
-  base::Time shared_now = base::Time::Now();
-
-  std::unique_ptr<SessionTab> tab1 = Tab(0, shared_now);
-  tab1->navigations.push_back(Entry(kExampleUrl));
-  tab1->navigations.push_back(Entry(kExampleUrl));
-
-  std::unique_ptr<SessionTab> tab2 = Tab(1, shared_now);
-  tab2->navigations.push_back(Entry(kExampleUrl));
-  tab2->navigations.push_back(Entry(kExampleUrl));
-
-  OffsetTabMatcher matcher((PageEquality(GURL(kExampleUrl))));
-  matcher.Check(tab1.get());
-  matcher.Check(tab2.get());
-  VerifyMatch(&matcher, 1);
-}
-
-}  // namespace sync_sessions
diff --git a/components/sync_sessions/revisit/page_equality.h b/components/sync_sessions/revisit/page_equality.h
deleted file mode 100644
index 6f678277..0000000
--- a/components/sync_sessions/revisit/page_equality.h
+++ /dev/null
@@ -1,28 +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_SYNC_SESSIONS_REVISIT_PAGE_EQUALITY_H_
-#define COMPONENTS_SYNC_SESSIONS_REVISIT_PAGE_EQUALITY_H_
-
-#include "url/gurl.h"
-
-namespace sync_sessions {
-
-// An extremely simplistic approach to determining page equality, given two
-// URLs. Some of the notable examples this fails to accommodate are varying
-// schemes, mobile subdomains, unimpactful query parameters/fragments, and
-// page changing headers/cookies.
-class PageEquality {
- public:
-  explicit PageEquality(const GURL& url) : url_(url) {}
-  PageEquality(const PageEquality&) = default;
-  bool IsSamePage(const GURL& url) const { return url == url_; }
-
- private:
-  const GURL url_;
-};
-
-}  // namespace sync_sessions
-
-#endif  // COMPONENTS_SYNC_SESSIONS_REVISIT_PAGE_EQUALITY_H_
diff --git a/components/sync_sessions/revisit/page_revisit_broadcaster.cc b/components/sync_sessions/revisit/page_revisit_broadcaster.cc
deleted file mode 100644
index 77e4cdf..0000000
--- a/components/sync_sessions/revisit/page_revisit_broadcaster.cc
+++ /dev/null
@@ -1,130 +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/sync_sessions/revisit/page_revisit_broadcaster.h"
-
-#include <string>
-
-#include "base/metrics/field_trial.h"
-#include "components/bookmarks/browser/bookmark_model.h"
-#include "components/history/core/browser/history_service.h"
-#include "components/sync_sessions/revisit/bookmarks_by_url_provider_impl.h"
-#include "components/sync_sessions/revisit/bookmarks_page_revisit_observer.h"
-#include "components/sync_sessions/revisit/sessions_page_revisit_observer.h"
-#include "components/sync_sessions/revisit/typed_url_page_revisit_observer.h"
-#include "components/sync_sessions/sessions_sync_manager.h"
-#include "components/sync_sessions/sync_sessions_client.h"
-
-namespace sync_sessions {
-
-namespace {
-
-// Simple implementation of ForeignSessionsProvider that delegates to
-// SessionsSyncManager. It holds onto a non-owning pointer, with the assumption
-// that this class is only used by classes owned by SessionsSyncManager itself.
-class SessionsSyncManagerWrapper : public ForeignSessionsProvider {
- public:
-  explicit SessionsSyncManagerWrapper(SessionsSyncManager* manager)
-      : manager_(manager) {}
-  ~SessionsSyncManagerWrapper() override {}
-  bool GetAllForeignSessions(
-      std::vector<const SyncedSession*>* sessions) override {
-    return manager_->GetAllForeignSessions(sessions);
-  }
-
- private:
-  SessionsSyncManager* manager_;
-  DISALLOW_COPY_AND_ASSIGN(SessionsSyncManagerWrapper);
-};
-
-}  // namespace
-
-PageRevisitBroadcaster::PageRevisitBroadcaster(
-    SessionsSyncManager* manager,
-    SyncSessionsClient* sessions_client)
-    : sessions_client_(sessions_client) {
-  const std::string group_name =
-      base::FieldTrialList::FindFullName("PageRevisitInstrumentation");
-  bool shouldInstrument = group_name == "Enabled";
-  if (shouldInstrument) {
-    revisit_observers_.push_back(std::make_unique<SessionsPageRevisitObserver>(
-        std::make_unique<SessionsSyncManagerWrapper>(manager)));
-
-    history::HistoryService* history = sessions_client_->GetHistoryService();
-    if (history) {
-      revisit_observers_.push_back(
-          std::make_unique<TypedUrlPageRevisitObserver>(history));
-    }
-
-    bookmarks::BookmarkModel* bookmarks = sessions_client_->GetBookmarkModel();
-    if (bookmarks) {
-      revisit_observers_.push_back(
-          std::make_unique<BookmarksPageRevisitObserver>(
-              std::make_unique<BookmarksByUrlProviderImpl>(bookmarks)));
-    }
-  }
-}
-
-PageRevisitBroadcaster::~PageRevisitBroadcaster() {}
-
-void PageRevisitBroadcaster::OnPageVisit(const GURL& url,
-                                         const ui::PageTransition transition) {
-  if (sessions_client_->ShouldSyncURL(url)) {
-    PageVisitObserver::TransitionType converted(
-        ConvertTransitionEnum(transition));
-    for (auto& observer : revisit_observers_) {
-      observer->OnPageVisit(url, converted);
-    }
-  }
-}
-
-// Static
-PageVisitObserver::TransitionType PageRevisitBroadcaster::ConvertTransitionEnum(
-    const ui::PageTransition original) {
-  switch (ui::PageTransitionStripQualifier(original)) {
-    case ui::PAGE_TRANSITION_LINK:
-      if (original & ui::PAGE_TRANSITION_FROM_ADDRESS_BAR) {
-        return PageVisitObserver::kTransitionCopyPaste;
-      } else {
-        return PageVisitObserver::kTransitionPage;
-      }
-    case ui::PAGE_TRANSITION_TYPED:
-      return PageVisitObserver::kTransitionOmniboxUrl;
-
-    case ui::PAGE_TRANSITION_AUTO_BOOKMARK:
-      return PageVisitObserver::kTransitionBookmark;
-
-    case ui::PAGE_TRANSITION_AUTO_SUBFRAME:
-    case ui::PAGE_TRANSITION_MANUAL_SUBFRAME:
-      // These are not expected, we only expect top-level frame transitions.
-      return PageVisitObserver::kTransitionUnknown;
-
-    case ui::PAGE_TRANSITION_GENERATED:
-      return PageVisitObserver::kTransitionOmniboxDefaultSearch;
-
-    case ui::PAGE_TRANSITION_AUTO_TOPLEVEL:
-      if (original & ui::PAGE_TRANSITION_FORWARD_BACK) {
-        return PageVisitObserver::kTransitionForwardBackward;
-      } else {
-        return PageVisitObserver::kTransitionUnknown;
-      }
-
-    case ui::PAGE_TRANSITION_FORM_SUBMIT:
-      return PageVisitObserver::kTransitionPage;
-
-    case ui::PAGE_TRANSITION_RELOAD:
-      // Refreshing pages also carry PAGE_TRANSITION_RELOAD but the url never
-      // changes so we don't expect to ever get them.
-      return PageVisitObserver::kTransitionRestore;
-
-    case ui::PAGE_TRANSITION_KEYWORD:
-    case ui::PAGE_TRANSITION_KEYWORD_GENERATED:
-      return PageVisitObserver::kTransitionOmniboxTemplateSearch;
-
-    default:
-      return PageVisitObserver::kTransitionUnknown;
-  }
-}
-
-}  // namespace sync_sessions
diff --git a/components/sync_sessions/revisit/page_revisit_broadcaster.h b/components/sync_sessions/revisit/page_revisit_broadcaster.h
deleted file mode 100644
index 150320c..0000000
--- a/components/sync_sessions/revisit/page_revisit_broadcaster.h
+++ /dev/null
@@ -1,57 +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_SYNC_SESSIONS_REVISIT_PAGE_REVISIT_BROADCASTER_H_
-#define COMPONENTS_SYNC_SESSIONS_REVISIT_PAGE_REVISIT_BROADCASTER_H_
-
-#include <memory>
-#include <vector>
-
-#include "base/macros.h"
-#include "components/sync_sessions/revisit/page_visit_observer.h"
-#include "ui/base/page_transition_types.h"
-#include "url/gurl.h"
-
-namespace sync_sessions {
-class SyncSessionsClient;
-}
-
-namespace sync_sessions {
-
-class SessionsSyncManager;
-
-// This class has the job of creating and holding onto the PageVisitObservers
-// that are to be notified on page change for purposes of instrumenting
-// revisists.
-class PageRevisitBroadcaster {
- public:
-  PageRevisitBroadcaster(SessionsSyncManager* manager,
-                         SyncSessionsClient* sessions_client);
-  ~PageRevisitBroadcaster();
-
-  // Broadcasts to all observers the given page visit event. Should only be
-  // called when the url changes.
-  void OnPageVisit(const GURL& url, const ui::PageTransition transition);
-
- private:
-  friend class SyncPageRevisitBroadcasterTest;
-
-  // We convert between enums here for a couple reasons. We don't want to force
-  // observers to depend on ui/, and the high bit masks don't work for emitting
-  // histograms. Some of the high bit masks correspond to cases we're
-  // particularly interested in and want to treat as first class values.
-  static PageVisitObserver::TransitionType ConvertTransitionEnum(
-      const ui::PageTransition original);
-
-  // The client of this sync sessions datatype.
-  SyncSessionsClient* const sessions_client_;
-
-  std::vector<std::unique_ptr<PageVisitObserver>> revisit_observers_;
-
-  DISALLOW_COPY_AND_ASSIGN(PageRevisitBroadcaster);
-};
-
-}  // namespace sync_sessions
-
-#endif  // COMPONENTS_SYNC_SESSIONS_REVISIT_PAGE_REVISIT_BROADCASTER_H_
diff --git a/components/sync_sessions/revisit/page_revisit_broadcaster_unittest.cc b/components/sync_sessions/revisit/page_revisit_broadcaster_unittest.cc
deleted file mode 100644
index a2e13fd4..0000000
--- a/components/sync_sessions/revisit/page_revisit_broadcaster_unittest.cc
+++ /dev/null
@@ -1,108 +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/sync_sessions/revisit/page_revisit_broadcaster.h"
-
-#include <stdint.h>
-
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace sync_sessions {
-
-class SyncPageRevisitBroadcasterTest : public ::testing::Test {
- protected:
-  PageVisitObserver::TransitionType Convert(
-      const ui::PageTransition conversionInput) {
-    return PageRevisitBroadcaster::ConvertTransitionEnum(conversionInput);
-  }
-
-  void Check(const PageVisitObserver::TransitionType expected,
-             const ui::PageTransition conversionInput) {
-    EXPECT_EQ(expected, Convert(conversionInput));
-  }
-
-  void Check(const PageVisitObserver::TransitionType expected,
-             const int32_t conversionInput) {
-    Check(expected, ui::PageTransitionFromInt(conversionInput));
-  }
-};
-
-TEST_F(SyncPageRevisitBroadcasterTest, ConvertPageInteraction) {
-  Check(PageVisitObserver::kTransitionPage, ui::PAGE_TRANSITION_LINK);
-  Check(PageVisitObserver::kTransitionPage,
-        ui::PAGE_TRANSITION_LINK | ui::PAGE_TRANSITION_BLOCKED);
-  Check(PageVisitObserver::kTransitionPage,
-        ui::PAGE_TRANSITION_LINK | ui::PAGE_TRANSITION_FORWARD_BACK);
-  // Don't check ui::PAGE_TRANSITION_FROM_ADDRESS_BAR, this is actually a copy
-  // and paste action when combined with ui::PAGE_TRANSITION_LINK.
-  Check(PageVisitObserver::kTransitionPage,
-        ui::PAGE_TRANSITION_LINK | ui::PAGE_TRANSITION_HOME_PAGE);
-  Check(PageVisitObserver::kTransitionPage,
-        ui::PAGE_TRANSITION_LINK | ui::PAGE_TRANSITION_FROM_API);
-  Check(PageVisitObserver::kTransitionPage,
-        ui::PAGE_TRANSITION_LINK | ui::PAGE_TRANSITION_CHAIN_START);
-  Check(PageVisitObserver::kTransitionPage,
-        ui::PAGE_TRANSITION_LINK | ui::PAGE_TRANSITION_CHAIN_END);
-  Check(PageVisitObserver::kTransitionPage,
-        ui::PAGE_TRANSITION_LINK | ui::PAGE_TRANSITION_CLIENT_REDIRECT);
-  Check(PageVisitObserver::kTransitionPage,
-        ui::PAGE_TRANSITION_LINK | ui::PAGE_TRANSITION_SERVER_REDIRECT);
-  Check(PageVisitObserver::kTransitionPage,
-        ui::PAGE_TRANSITION_LINK | ui::PAGE_TRANSITION_IS_REDIRECT_MASK);
-}
-
-TEST_F(SyncPageRevisitBroadcasterTest, ConvertOmniboxURL) {
-  Check(PageVisitObserver::kTransitionOmniboxUrl, ui::PAGE_TRANSITION_TYPED);
-  Check(PageVisitObserver::kTransitionOmniboxUrl,
-        ui::PAGE_TRANSITION_TYPED | ui::PAGE_TRANSITION_FROM_ADDRESS_BAR);
-}
-
-TEST_F(SyncPageRevisitBroadcasterTest, ConvertOmniboxDefaultSearch) {
-  Check(PageVisitObserver::kTransitionOmniboxDefaultSearch,
-        ui::PAGE_TRANSITION_GENERATED);
-  Check(PageVisitObserver::kTransitionOmniboxDefaultSearch,
-        ui::PAGE_TRANSITION_GENERATED | ui::PAGE_TRANSITION_FROM_ADDRESS_BAR);
-}
-
-TEST_F(SyncPageRevisitBroadcasterTest, ConvertOmniboxTemplateSearch) {
-  Check(PageVisitObserver::kTransitionOmniboxTemplateSearch,
-        ui::PAGE_TRANSITION_KEYWORD);
-  Check(PageVisitObserver::kTransitionOmniboxTemplateSearch,
-        ui::PAGE_TRANSITION_KEYWORD | ui::PAGE_TRANSITION_FROM_ADDRESS_BAR);
-  Check(PageVisitObserver::kTransitionOmniboxTemplateSearch,
-        ui::PAGE_TRANSITION_KEYWORD_GENERATED);
-  Check(PageVisitObserver::kTransitionOmniboxTemplateSearch,
-        ui::PAGE_TRANSITION_KEYWORD_GENERATED |
-            ui::PAGE_TRANSITION_FROM_ADDRESS_BAR);
-}
-
-TEST_F(SyncPageRevisitBroadcasterTest, ConvertBookmark) {
-  Check(PageVisitObserver::kTransitionBookmark,
-        ui::PAGE_TRANSITION_AUTO_BOOKMARK);
-}
-
-TEST_F(SyncPageRevisitBroadcasterTest, ConvertCopyPaste) {
-  Check(PageVisitObserver::kTransitionCopyPaste,
-        ui::PAGE_TRANSITION_LINK | ui::PAGE_TRANSITION_FROM_ADDRESS_BAR);
-}
-
-TEST_F(SyncPageRevisitBroadcasterTest, ConvertForwardBackward) {
-  Check(PageVisitObserver::kTransitionForwardBackward,
-        ui::PAGE_TRANSITION_AUTO_TOPLEVEL | ui::PAGE_TRANSITION_FORWARD_BACK);
-}
-
-TEST_F(SyncPageRevisitBroadcasterTest, ConvertRestore) {
-  Check(PageVisitObserver::kTransitionRestore, ui::PAGE_TRANSITION_RELOAD);
-}
-
-TEST_F(SyncPageRevisitBroadcasterTest, ConvertUnknown) {
-  Check(PageVisitObserver::kTransitionUnknown,
-        ui::PAGE_TRANSITION_AUTO_SUBFRAME);
-  Check(PageVisitObserver::kTransitionUnknown,
-        ui::PAGE_TRANSITION_MANUAL_SUBFRAME);
-  Check(PageVisitObserver::kTransitionUnknown,
-        ui::PAGE_TRANSITION_AUTO_TOPLEVEL);
-}
-
-}  // namespace sync_sessions
diff --git a/components/sync_sessions/revisit/page_visit_observer.h b/components/sync_sessions/revisit/page_visit_observer.h
deleted file mode 100644
index 477d724..0000000
--- a/components/sync_sessions/revisit/page_visit_observer.h
+++ /dev/null
@@ -1,54 +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_SYNC_SESSIONS_REVISIT_PAGE_VISIT_OBSERVER_H_
-#define COMPONENTS_SYNC_SESSIONS_REVISIT_PAGE_VISIT_OBSERVER_H_
-
-#include <string>
-
-#include "base/metrics/histogram_macros.h"
-#include "base/time/time.h"
-
-class GURL;
-
-namespace sync_sessions {
-
-// The upper bound of 90 days and the bucket count of 100 try to strike a
-// balance. We want multiple single minute digit buckets, but also notice
-// differences that happen many weeks ago. It also helps that typed URLs age out
-// around 90 days, which makes these values even more fitting. These might not
-// handle bookmarks quite as elegantly, but we're less interested in knowing the
-// age of very old objects. This must be defind as a macro instead of a static
-// method because the histogram macro makes an inline static variable that must
-// be unique for separately named histograms.
-#define REVISIT_HISTOGRAM_AGE(name, timestamp)                                \
-  UMA_HISTOGRAM_CUSTOM_COUNTS(name,                                           \
-                              (base::Time::Now() - timestamp).InMinutes(), 1, \
-                              base::TimeDelta::FromDays(90).InMinutes(), 100)
-
-// An interface that allows observers to be notified when a page is visited.
-class PageVisitObserver {
- public:
-  // This enum represents the most common ways to visit a new page/URL.
-  enum TransitionType {
-    kTransitionPage = 0,
-    kTransitionOmniboxUrl = 1,
-    kTransitionOmniboxDefaultSearch = 2,
-    kTransitionOmniboxTemplateSearch = 3,
-    kTransitionBookmark = 4,
-    kTransitionCopyPaste = 5,
-    kTransitionForwardBackward = 6,
-    kTransitionRestore = 7,
-    kTransitionUnknown = 8,
-    kTransitionTypeLast = 9,
-  };
-
-  virtual ~PageVisitObserver() {}
-  virtual void OnPageVisit(const GURL& url,
-                           const TransitionType transition) = 0;
-};
-
-}  // namespace sync_sessions
-
-#endif  // COMPONENTS_SYNC_SESSIONS_REVISIT_PAGE_VISIT_OBSERVER_H_
diff --git a/components/sync_sessions/revisit/sessions_page_revisit_observer.cc b/components/sync_sessions/revisit/sessions_page_revisit_observer.cc
deleted file mode 100644
index 1a99c70a..0000000
--- a/components/sync_sessions/revisit/sessions_page_revisit_observer.cc
+++ /dev/null
@@ -1,82 +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/sync_sessions/revisit/sessions_page_revisit_observer.h"
-
-#include <utility>
-
-#include "base/metrics/histogram_macros.h"
-#include "base/threading/thread_task_runner_handle.h"
-#include "base/time/time.h"
-#include "components/sessions/core/session_types.h"
-#include "components/sync_sessions/revisit/current_tab_matcher.h"
-#include "components/sync_sessions/revisit/offset_tab_matcher.h"
-#include "components/sync_sessions/revisit/page_equality.h"
-#include "components/sync_sessions/synced_session.h"
-#include "url/gurl.h"
-
-namespace sync_sessions {
-
-SessionsPageRevisitObserver::SessionsPageRevisitObserver(
-    std::unique_ptr<ForeignSessionsProvider> provider)
-    : provider_(std::move(provider)) {}
-
-SessionsPageRevisitObserver::~SessionsPageRevisitObserver() {}
-
-void SessionsPageRevisitObserver::OnPageVisit(
-    const GURL& url,
-    const PageVisitObserver::TransitionType transition) {
-  // We need to be invoked and eventually execute on the thread which owns the
-  // session objects the provider will give us. However, this work is not
-  // especially time sensitive, and so we post a task to perform this to get out
-  // of the way of any currently executing logic.
-
-  // Bind this task to this->AsWeakPtr() so that if we're destructed this task
-  // just vanish instead of breaking things.
-  base::ThreadTaskRunnerHandle::Get()->PostTask(
-      FROM_HERE, base::Bind(&SessionsPageRevisitObserver::CheckForRevisit,
-                            this->AsWeakPtr(), url, transition));
-}
-
-void SessionsPageRevisitObserver::CheckForRevisit(
-    const GURL& url,
-    const PageVisitObserver::TransitionType transition) {
-  base::TimeTicks start(base::TimeTicks::Now());
-
-  // We want to match tabs/navigation entries in two slightly different ways. We
-  // value the current url/navigation entry of a tab more highly, and want to
-  // actually seperate metrics from the backwards/forwards entries. And then
-  // to make things a little bit messier, we only have an accurate modified time
-  // for the tabs/current entries. So use index offset for forward/back entries.
-  PageEquality page_equality(url);
-  CurrentTabMatcher current_matcher(page_equality);
-  OffsetTabMatcher offset_matcher(page_equality);
-
-  std::vector<const SyncedSession*> foreign_sessions;
-  if (provider_->GetAllForeignSessions(&foreign_sessions)) {
-    for (const SyncedSession* session : foreign_sessions) {
-      for (const auto& key_value : session->windows) {
-        for (const auto& tab : key_value.second->wrapped_window.tabs) {
-          // These matchers look identical and could easily implement an
-          // interface and we could iterate through a vector of matchers here.
-          // However this would cause quite a bit of overhead at the inner most
-          // loop of something that takes linear time in relation to the number
-          // of open foreign tabs. A small fraction of users have thousands of
-          // open tabs.
-          current_matcher.Check(tab.get());
-          offset_matcher.Check(tab.get());
-        }
-      }
-    }
-  }
-
-  // emit even if there are no foreign sessions so that that counts all match.
-  current_matcher.Emit(transition);
-  offset_matcher.Emit(transition);
-
-  base::TimeDelta duration(base::TimeTicks::Now() - start);
-  UMA_HISTOGRAM_TIMES("Sync.PageRevisitSessionDuration", duration);
-}
-
-}  // namespace sync_sessions
diff --git a/components/sync_sessions/revisit/sessions_page_revisit_observer.h b/components/sync_sessions/revisit/sessions_page_revisit_observer.h
deleted file mode 100644
index 87d653e2..0000000
--- a/components/sync_sessions/revisit/sessions_page_revisit_observer.h
+++ /dev/null
@@ -1,60 +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_SYNC_SESSIONS_REVISIT_SESSIONS_PAGE_REVISIT_OBSERVER_H_
-#define COMPONENTS_SYNC_SESSIONS_REVISIT_SESSIONS_PAGE_REVISIT_OBSERVER_H_
-
-#include <memory>
-#include <vector>
-
-#include "base/macros.h"
-#include "base/memory/weak_ptr.h"
-#include "components/sync_sessions/revisit/page_visit_observer.h"
-
-class GURL;
-
-namespace sync_sessions {
-
-struct SyncedSession;
-
-// A simple interface to abstract away who is providing sessions.
-class ForeignSessionsProvider {
- public:
-  // Fills the already instantiated passed vector with all foreign sessions.
-  // Returned boolean representes if there were foreign sessions and the vector
-  // should be examimed.
-  virtual bool GetAllForeignSessions(
-      std::vector<const SyncedSession*>* sessions) = 0;
-  virtual ~ForeignSessionsProvider() {}
-};
-
-// An implementation of PageVisitObserver that checks the given page's url
-// against in memory session information to detect if we've seen this page
-// before, constituting a revisit. Then histogram information is emitted about
-// this page navigation.
-class SessionsPageRevisitObserver
-    : public PageVisitObserver,
-      public base::SupportsWeakPtr<SessionsPageRevisitObserver> {
- public:
-  explicit SessionsPageRevisitObserver(
-      std::unique_ptr<ForeignSessionsProvider> provider);
-  ~SessionsPageRevisitObserver() override;
-  void OnPageVisit(const GURL& url, const TransitionType transition) override;
-
- private:
-  friend class SessionsPageRevisitObserverTest;
-
-  // Although the signature is identical to OnPageVisit(...), this method
-  // actually does all of the work. The assumption is that this method is the
-  // target of a PostTask call coming from OnPageVisit(...).
-  void CheckForRevisit(const GURL& url, const TransitionType transition);
-
-  std::unique_ptr<ForeignSessionsProvider> provider_;
-
-  DISALLOW_COPY_AND_ASSIGN(SessionsPageRevisitObserver);
-};
-
-}  // namespace sync_sessions
-
-#endif  // COMPONENTS_SYNC_SESSIONS_REVISIT_SESSIONS_PAGE_REVISIT_OBSERVER_H_
diff --git a/components/sync_sessions/revisit/sessions_page_revisit_observer_unittest.cc b/components/sync_sessions/revisit/sessions_page_revisit_observer_unittest.cc
deleted file mode 100644
index 97878c0..0000000
--- a/components/sync_sessions/revisit/sessions_page_revisit_observer_unittest.cc
+++ /dev/null
@@ -1,195 +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/sync_sessions/revisit/sessions_page_revisit_observer.h"
-
-#include <string>
-#include <utility>
-
-#include "base/test/histogram_tester.h"
-#include "components/sessions/core/serialized_navigation_entry.h"
-#include "components/sessions/core/serialized_navigation_entry_test_helper.h"
-#include "components/sessions/core/session_types.h"
-#include "components/sync_sessions/synced_session.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#include "url/gurl.h"
-
-using sessions::SessionTab;
-using sessions::SessionWindow;
-
-namespace sync_sessions {
-
-namespace {
-
-static const char kExampleUrl[] = "http://www.example.com";
-static const char kDifferentUrl[] = "http://www.different.com";
-
-class TestForeignSessionsProvider : public ForeignSessionsProvider {
- public:
-  TestForeignSessionsProvider(const std::vector<const SyncedSession*>& sessions,
-                              bool return_value)
-      : sessions_(sessions), return_value_(return_value) {}
-  ~TestForeignSessionsProvider() override {}
-
-  bool GetAllForeignSessions(
-      std::vector<const SyncedSession*>* sessions) override {
-    sessions->clear();
-    *sessions = sessions_;
-    return return_value_;
-  }
-
- private:
-  const std::vector<const SyncedSession*>& sessions_;
-  const bool return_value_;
-};
-
-}  // namespace
-
-class SessionsPageRevisitObserverTest : public ::testing::Test {
- protected:
-  void CheckAndExpect(SessionsPageRevisitObserver* observer,
-                      const GURL& url,
-                      const bool current_match,
-                      const bool offset_match) {
-    base::HistogramTester histogram_tester;
-    observer->CheckForRevisit(url, PageVisitObserver::kTransitionPage);
-
-    histogram_tester.ExpectTotalCount("Sync.PageRevisitTabMatchTransition",
-                                      current_match ? 1 : 0);
-    histogram_tester.ExpectTotalCount("Sync.PageRevisitTabMissTransition",
-                                      current_match ? 0 : 1);
-    histogram_tester.ExpectTotalCount(
-        "Sync.PageRevisitNavigationMatchTransition", offset_match ? 1 : 0);
-    histogram_tester.ExpectTotalCount(
-        "Sync.PageRevisitNavigationMissTransition", offset_match ? 0 : 1);
-    histogram_tester.ExpectTotalCount("Sync.PageRevisitSessionDuration", 1);
-  }
-
-  void CheckAndExpect(const SyncedSession* session,
-                      const GURL& url,
-                      const bool current_match,
-                      const bool offset_match) {
-    std::vector<const SyncedSession*> sessions;
-    sessions.push_back(session);
-    SessionsPageRevisitObserver observer(
-        std::make_unique<TestForeignSessionsProvider>(sessions, true));
-    CheckAndExpect(&observer, url, current_match, offset_match);
-  }
-};
-
-TEST_F(SessionsPageRevisitObserverTest, RunMatchersNoSessions) {
-  std::vector<const SyncedSession*> sessions;
-  SessionsPageRevisitObserver observer(
-      std::make_unique<TestForeignSessionsProvider>(sessions, true));
-  CheckAndExpect(&observer, GURL(kExampleUrl), false, false);
-}
-
-TEST_F(SessionsPageRevisitObserverTest, RunMatchersNoWindows) {
-  auto session = std::make_unique<SyncedSession>();
-  CheckAndExpect(session.get(), GURL(kExampleUrl), false, false);
-}
-
-TEST_F(SessionsPageRevisitObserverTest, RunMatchersNoTabs) {
-  auto session = std::make_unique<SyncedSession>();
-  session->windows[0] = std::make_unique<SyncedSessionWindow>();
-  CheckAndExpect(session.get(), GURL(kExampleUrl), false, false);
-}
-
-TEST_F(SessionsPageRevisitObserverTest, RunMatchersNoEntries) {
-  auto window = std::make_unique<SyncedSessionWindow>();
-  window->wrapped_window.tabs.push_back(std::make_unique<SessionTab>());
-  auto session = std::make_unique<SyncedSession>();
-  session->windows[0] = std::move(window);
-  CheckAndExpect(session.get(), GURL(kExampleUrl), false, false);
-}
-
-TEST_F(SessionsPageRevisitObserverTest, RunMatchersSingle) {
-  auto tab = std::make_unique<SessionTab>();
-  tab->navigations.push_back(
-      sessions::SerializedNavigationEntryTestHelper::CreateNavigation(
-          kExampleUrl, ""));
-  tab->current_navigation_index = 0;
-  auto window = std::make_unique<SyncedSessionWindow>();
-  window->wrapped_window.tabs.push_back(std::move(tab));
-  auto session = std::make_unique<SyncedSession>();
-  session->windows[0] = std::move(window);
-  CheckAndExpect(session.get(), GURL(kExampleUrl), true, false);
-}
-
-TEST_F(SessionsPageRevisitObserverTest, RunMatchersFalseProvider) {
-  auto tab = std::make_unique<SessionTab>();
-  tab->navigations.push_back(
-      sessions::SerializedNavigationEntryTestHelper::CreateNavigation(
-          kExampleUrl, ""));
-  tab->navigations.push_back(
-      sessions::SerializedNavigationEntryTestHelper::CreateNavigation(
-          kExampleUrl, ""));
-  tab->current_navigation_index = 1;
-  auto window = std::make_unique<SyncedSessionWindow>();
-  window->wrapped_window.tabs.push_back(std::move(tab));
-  auto session = std::make_unique<SyncedSession>();
-  session->windows[0] = std::move(window);
-
-  // The provider returns false when asked for foreign sessions, even though
-  // it has has a valid tab.
-  std::vector<const SyncedSession*> sessions;
-  sessions.push_back(session.get());
-  SessionsPageRevisitObserver observer(
-      std::make_unique<TestForeignSessionsProvider>(sessions, false));
-  CheckAndExpect(&observer, GURL(kExampleUrl), false, false);
-}
-
-TEST_F(SessionsPageRevisitObserverTest, RunMatchersMany) {
-  auto tab1 = std::make_unique<SessionTab>();
-  tab1->navigations.push_back(
-      sessions::SerializedNavigationEntryTestHelper::CreateNavigation(
-          kExampleUrl, ""));
-  tab1->current_navigation_index = 0;
-
-  auto tab2 = std::make_unique<SessionTab>();
-  tab2->navigations.push_back(
-      sessions::SerializedNavigationEntryTestHelper::CreateNavigation(
-          kDifferentUrl, ""));
-  tab2->current_navigation_index = 0;
-
-  auto tab3 = std::make_unique<SessionTab>();
-  tab3->navigations.push_back(
-      sessions::SerializedNavigationEntryTestHelper::CreateNavigation(
-          kDifferentUrl, ""));
-  tab3->current_navigation_index = 0;
-
-  auto tab4 = std::make_unique<SessionTab>();
-  tab4->navigations.push_back(
-      sessions::SerializedNavigationEntryTestHelper::CreateNavigation(
-          kExampleUrl, ""));
-  tab4->navigations.push_back(
-      sessions::SerializedNavigationEntryTestHelper::CreateNavigation(
-          kDifferentUrl, ""));
-  tab4->current_navigation_index = 1;
-
-  auto window1 = std::make_unique<SyncedSessionWindow>();
-  window1->wrapped_window.tabs.push_back(std::move(tab1));
-  auto window2 = std::make_unique<SyncedSessionWindow>();
-  window2->wrapped_window.tabs.push_back(std::move(tab2));
-  auto window3 = std::make_unique<SyncedSessionWindow>();
-  window3->wrapped_window.tabs.push_back(std::move(tab3));
-  window3->wrapped_window.tabs.push_back(std::move(tab4));
-
-  auto session1 = std::make_unique<SyncedSession>();
-  session1->windows[1] = std::move(window1);
-  auto session2 = std::make_unique<SyncedSession>();
-  session2->windows[2] = std::move(window2);
-  session2->windows[3] = std::move(window3);
-
-  std::vector<const SyncedSession*> sessions;
-  sessions.push_back(session1.get());
-  sessions.push_back(session2.get());
-  SessionsPageRevisitObserver observer(
-      std::make_unique<TestForeignSessionsProvider>(sessions, true));
-
-  base::HistogramTester histogram_tester;
-  CheckAndExpect(&observer, GURL(kExampleUrl), true, true);
-}
-
-}  // namespace sync_sessions
diff --git a/components/sync_sessions/revisit/typed_url_page_revisit_observer.cc b/components/sync_sessions/revisit/typed_url_page_revisit_observer.cc
deleted file mode 100644
index f0740de..0000000
--- a/components/sync_sessions/revisit/typed_url_page_revisit_observer.cc
+++ /dev/null
@@ -1,31 +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/sync_sessions/revisit/typed_url_page_revisit_observer.h"
-
-#include <memory>
-
-#include "components/history/core/browser/history_service.h"
-#include "components/sync_sessions/revisit/typed_url_page_revisit_task.h"
-#include "url/gurl.h"
-
-namespace sync_sessions {
-
-TypedUrlPageRevisitObserver::TypedUrlPageRevisitObserver(
-    history::HistoryService* history)
-    : history_(base::AsWeakPtr(history)) {}
-
-TypedUrlPageRevisitObserver::~TypedUrlPageRevisitObserver() {}
-
-void TypedUrlPageRevisitObserver::OnPageVisit(
-    const GURL& url,
-    const PageVisitObserver::TransitionType transition) {
-  if (history_) {
-    history_->ScheduleDBTask(
-        FROM_HERE, std::make_unique<TypedUrlPageRevisitTask>(url, transition),
-        &task_tracker_);
-  }
-}
-
-}  // namespace sync_sessions
diff --git a/components/sync_sessions/revisit/typed_url_page_revisit_observer.h b/components/sync_sessions/revisit/typed_url_page_revisit_observer.h
deleted file mode 100644
index fc69d1d..0000000
--- a/components/sync_sessions/revisit/typed_url_page_revisit_observer.h
+++ /dev/null
@@ -1,42 +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_SYNC_SESSIONS_REVISIT_TYPED_URL_PAGE_REVISIT_OBSERVER_H_
-#define COMPONENTS_SYNC_SESSIONS_REVISIT_TYPED_URL_PAGE_REVISIT_OBSERVER_H_
-
-#include "base/macros.h"
-#include "base/memory/weak_ptr.h"
-#include "base/task/cancelable_task_tracker.h"
-#include "components/sync_sessions/revisit/page_visit_observer.h"
-
-class GURL;
-
-namespace history {
-class HistoryService;
-}  // namespace history
-
-namespace sync_sessions {
-
-// This class's job is to respond to OnPageVisit events and launch a task to
-// the history thread to perform the requisite checks and instrumentation. It is
-// important that this object is created and called on the same thread, since it
-// creates and uses a weak pointer to the HistoryService.
-class TypedUrlPageRevisitObserver : public PageVisitObserver {
- public:
-  explicit TypedUrlPageRevisitObserver(history::HistoryService* history);
-  ~TypedUrlPageRevisitObserver() override;
-  void OnPageVisit(const GURL& url,
-                   const PageVisitObserver::TransitionType transition) override;
-
- private:
-  const base::WeakPtr<history::HistoryService> history_;
-  // This is never used to cancel tasks, but required by the history interface.
-  base::CancelableTaskTracker task_tracker_;
-
-  DISALLOW_COPY_AND_ASSIGN(TypedUrlPageRevisitObserver);
-};
-
-}  // namespace sync_sessions
-
-#endif  // COMPONENTS_SYNC_SESSIONS_REVISIT_TYPED_URL_PAGE_REVISIT_OBSERVER_H_
diff --git a/components/sync_sessions/revisit/typed_url_page_revisit_task.cc b/components/sync_sessions/revisit/typed_url_page_revisit_task.cc
deleted file mode 100644
index 240cdc3..0000000
--- a/components/sync_sessions/revisit/typed_url_page_revisit_task.cc
+++ /dev/null
@@ -1,76 +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/sync_sessions/revisit/typed_url_page_revisit_task.h"
-
-#include "base/metrics/histogram_macros.h"
-#include "base/time/time.h"
-#include "components/history/core/browser/history_backend.h"
-#include "components/history/core/browser/history_service.h"
-#include "components/history/core/browser/url_row.h"
-
-namespace sync_sessions {
-
-TypedUrlPageRevisitTask::TypedUrlPageRevisitTask(
-    const GURL& url,
-    const PageVisitObserver::TransitionType transition)
-    : url_(url), transition_(transition) {}
-
-TypedUrlPageRevisitTask::~TypedUrlPageRevisitTask() {}
-
-bool TypedUrlPageRevisitTask::FillVisitsAndSources(
-    history::HistoryBackend* backend,
-    history::VisitVector* visits,
-    history::VisitSourceMap* sources) {
-  history::URLRow row;
-  return backend->GetURL(url_, &row) &&
-         backend->GetVisitsForURL(row.id(), visits) &&
-         backend->GetVisitsSource(*visits, sources);
-}
-
-bool TypedUrlPageRevisitTask::FindLastSyncedMatchAge(
-    history::HistoryBackend* backend,
-    base::Time* lastVisitTime) {
-  history::VisitVector visits;
-  history::VisitSourceMap sources;
-  if (FillVisitsAndSources(backend, &visits, &sources)) {
-    // The visits are in chronological order. We only care about the most
-    // recent remote visit, so iterate backwards.
-    for (auto row_itr = visits.rbegin(); row_itr != visits.rend(); ++row_itr) {
-      auto map_itr = sources.find(row_itr->visit_id);
-      if (map_itr != sources.end() &&
-          map_itr->second == history::SOURCE_SYNCED) {
-        *lastVisitTime = row_itr->visit_time;
-        return true;
-      }
-    }
-  }
-  return false;
-}
-
-bool TypedUrlPageRevisitTask::RunOnDBThread(history::HistoryBackend* backend,
-                                            history::HistoryDatabase* db) {
-  base::TimeTicks start(base::TimeTicks::Now());
-  base::Time lastVisitTime;
-  if (FindLastSyncedMatchAge(backend, &lastVisitTime)) {
-    REVISIT_HISTOGRAM_AGE("Sync.PageRevisitTypedUrlMatchAge", lastVisitTime);
-    UMA_HISTOGRAM_ENUMERATION("Sync.PageRevisitTypedUrlMatchTransition",
-                              transition_,
-                              PageVisitObserver::kTransitionTypeLast);
-  } else {
-    UMA_HISTOGRAM_ENUMERATION("Sync.PageRevisitTypedUrlMissTransition",
-                              transition_,
-                              PageVisitObserver::kTransitionTypeLast);
-  }
-
-  base::TimeDelta duration(base::TimeTicks::Now() - start);
-  UMA_HISTOGRAM_TIMES("Sync.PageRevisitTypedUrlDuration", duration);
-
-  // This indicates success and retring is not needed.
-  return true;
-}
-
-void TypedUrlPageRevisitTask::DoneRunOnMainThread() {}
-
-}  // namespace sync_sessions
diff --git a/components/sync_sessions/revisit/typed_url_page_revisit_task.h b/components/sync_sessions/revisit/typed_url_page_revisit_task.h
deleted file mode 100644
index 49b4398..0000000
--- a/components/sync_sessions/revisit/typed_url_page_revisit_task.h
+++ /dev/null
@@ -1,63 +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_SYNC_SESSIONS_REVISIT_TYPED_URL_PAGE_REVISIT_TASK_H_
-#define COMPONENTS_SYNC_SESSIONS_REVISIT_TYPED_URL_PAGE_REVISIT_TASK_H_
-
-#include "base/gtest_prod_util.h"
-#include "base/macros.h"
-#include "components/history/core/browser/history_db_task.h"
-#include "components/history/core/browser/history_types.h"
-#include "components/sync_sessions/revisit/page_visit_observer.h"
-#include "url/gurl.h"
-
-namespace base {
-class Time;
-}  // namespace base
-
-namespace history {
-class HistoryBackend;
-class HistoryDatabase;
-}  // namespace history
-
-namespace sync_sessions {
-
-// This is the actual logic to check if the history database has a foreign,
-// synced, typed URL record for a given page/URL or not. This class implements
-// the HistoryDBTask interface with the assumption that is is being run by the
-// history mechanisms and on the correct thread.
-class TypedUrlPageRevisitTask : public history::HistoryDBTask {
- public:
-  TypedUrlPageRevisitTask(const GURL& url,
-                          const PageVisitObserver::TransitionType transition);
-  ~TypedUrlPageRevisitTask() override;
-  bool RunOnDBThread(history::HistoryBackend* backend,
-                     history::HistoryDatabase* db) override;
-  void DoneRunOnMainThread() override;
-
- private:
-  FRIEND_TEST_ALL_PREFIXES(TypedUrlPageRevisitTaskTest, MultipleMatches);
-
-  // Returns if there was a previously synced match. lastVisitTime is an out
-  // parameter. Its value is not read, but will be set if the return value is
-  // true.
-  bool FindLastSyncedMatchAge(history::HistoryBackend* backend,
-                              base::Time* lastVisitTime);
-
-  // Returns if there are visits and sources the instance url value, and
-  // populates the parameters repspectively. Virtual so that unit tests can
-  // override this functionality.
-  virtual bool FillVisitsAndSources(history::HistoryBackend* backend,
-                                    history::VisitVector* visits,
-                                    history::VisitSourceMap* sources);
-
-  const GURL url_;
-  const PageVisitObserver::TransitionType transition_;
-
-  DISALLOW_COPY_AND_ASSIGN(TypedUrlPageRevisitTask);
-};
-
-}  // namespace sync_sessions
-
-#endif  // COMPONENTS_SYNC_SESSIONS_REVISIT_TYPED_URL_PAGE_REVISIT_TASK_H_
diff --git a/components/sync_sessions/revisit/typed_url_page_revisit_task_unittest.cc b/components/sync_sessions/revisit/typed_url_page_revisit_task_unittest.cc
deleted file mode 100644
index ac6db2c1..0000000
--- a/components/sync_sessions/revisit/typed_url_page_revisit_task_unittest.cc
+++ /dev/null
@@ -1,147 +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/sync_sessions/revisit/typed_url_page_revisit_task.h"
-
-#include "base/test/histogram_tester.h"
-#include "base/time/time.h"
-#include "components/history/core/browser/history_backend.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace sync_sessions {
-
-namespace {
-
-class FakeTask : public TypedUrlPageRevisitTask {
- public:
-  FakeTask(const PageVisitObserver::TransitionType transition,
-           bool result,
-           const history::VisitVector& visits,
-           const history::VisitSourceMap& sources)
-      : TypedUrlPageRevisitTask(GURL("http://www.example.com"), transition),
-        result_(result),
-        visits_(visits),
-        sources_(sources) {}
-
-  bool FillVisitsAndSources(history::HistoryBackend* backend,
-                            history::VisitVector* visits,
-                            history::VisitSourceMap* sources) override {
-    *visits = visits_;
-    *sources = sources_;
-    return result_;
-  }
-
- private:
-  const bool result_;
-  const history::VisitVector visits_;
-  const history::VisitSourceMap sources_;
-};
-
-void VerifyMatch(TypedUrlPageRevisitTask* task,
-                 const PageVisitObserver::TransitionType transition) {
-  base::HistogramTester histogram_tester;
-  task->RunOnDBThread(nullptr, nullptr);
-  histogram_tester.ExpectTotalCount("Sync.PageRevisitTypedUrlMatchAge", 1);
-  histogram_tester.ExpectUniqueSample("Sync.PageRevisitTypedUrlMatchTransition",
-                                      PageVisitObserver::kTransitionPage, 1);
-  histogram_tester.ExpectTotalCount("Sync.PageRevisitTypedUrlDuration", 1);
-}
-
-void VerifyMiss(TypedUrlPageRevisitTask* task,
-                const PageVisitObserver::TransitionType transition) {
-  base::HistogramTester histogram_tester;
-  task->RunOnDBThread(nullptr, nullptr);
-  histogram_tester.ExpectUniqueSample("Sync.PageRevisitTypedUrlMissTransition",
-                                      PageVisitObserver::kTransitionPage, 1);
-  histogram_tester.ExpectTotalCount("Sync.PageRevisitTypedUrlDuration", 1);
-}
-
-history::VisitRow Row(history::VisitID id) {
-  history::VisitRow row;
-  row.visit_id = id;
-  return row;
-}
-
-history::VisitRow Row(history::VisitID id, base::Time visit_time) {
-  history::VisitRow row;
-  row.visit_id = id;
-  row.visit_time = visit_time;
-  return row;
-}
-
-}  // namespace
-
-TEST(TypedUrlPageRevisitTaskTest, NoMatchesFillReturnsFalse) {
-  history::VisitVector visits;
-  history::VisitSourceMap sources;
-  FakeTask task(PageVisitObserver::TransitionType::kTransitionPage, false,
-                visits, sources);
-  VerifyMiss(&task, PageVisitObserver::kTransitionPage);
-}
-
-TEST(TypedUrlPageRevisitTaskTest, NoMatchesFillReturnsTrue) {
-  history::VisitVector visits;
-  history::VisitSourceMap sources;
-  FakeTask task(PageVisitObserver::TransitionType::kTransitionPage, true,
-                visits, sources);
-  VerifyMiss(&task, PageVisitObserver::kTransitionPage);
-}
-
-TEST(TypedUrlPageRevisitTaskTest, NoSyncedSources) {
-  history::VisitVector visits;
-  visits.push_back(Row(1));
-  visits.push_back(Row(2));
-  visits.push_back(Row(3));
-  visits.push_back(Row(4));
-  visits.push_back(Row(5));
-  visits.push_back(Row(6));
-  visits.push_back(Row(7));
-
-  history::VisitSourceMap sources;
-  sources[1] = history::SOURCE_BROWSED;
-  sources[2] = history::SOURCE_EXTENSION;
-  sources[3] = history::SOURCE_EXTENSION;
-  sources[4] = history::SOURCE_FIREFOX_IMPORTED;
-  sources[5] = history::SOURCE_IE_IMPORTED;
-  sources[6] = history::SOURCE_SAFARI_IMPORTED;
-  // No source for id 7.
-
-  FakeTask task(PageVisitObserver::TransitionType::kTransitionPage, true,
-                visits, sources);
-  VerifyMiss(&task, PageVisitObserver::kTransitionPage);
-}
-
-TEST(TypedUrlPageRevisitTaskTest, SingleMatch) {
-  history::VisitVector visits;
-  visits.push_back(Row(1));
-
-  history::VisitSourceMap sources;
-  sources[1] = history::SOURCE_SYNCED;
-
-  FakeTask task(PageVisitObserver::TransitionType::kTransitionPage, true,
-                visits, sources);
-  VerifyMatch(&task, PageVisitObserver::kTransitionPage);
-}
-
-TEST(TypedUrlPageRevisitTaskTest, MultipleMatches) {
-  base::Time expected = base::Time::UnixEpoch() + base::TimeDelta::FromDays(1);
-  history::VisitVector visits;
-  visits.push_back(Row(1, base::Time::UnixEpoch()));
-  visits.push_back(Row(2, expected));
-  visits.push_back(
-      Row(3, base::Time::UnixEpoch() + base::TimeDelta::FromDays(2)));
-
-  history::VisitSourceMap sources;
-  sources[1] = history::SOURCE_SYNCED;
-  sources[2] = history::SOURCE_SYNCED;
-  // No source for id 3.
-
-  FakeTask task(PageVisitObserver::TransitionType::kTransitionPage, true,
-                visits, sources);
-  base::Time lastVisitTime;
-  ASSERT_TRUE(task.FindLastSyncedMatchAge(nullptr, &lastVisitTime));
-  ASSERT_EQ(expected, lastVisitTime);
-}
-
-}  // namespace sync_sessions
diff --git a/components/sync_sessions/sessions_sync_manager.cc b/components/sync_sessions/sessions_sync_manager.cc
index d1e6537..cb6b9d6 100644
--- a/components/sync_sessions/sessions_sync_manager.cc
+++ b/components/sync_sessions/sessions_sync_manager.cc
@@ -138,7 +138,6 @@
       local_session_header_node_id_(TabNodePool::kInvalidTabNodeID),
       stale_session_threshold_days_(kDefaultStaleSessionThresholdDays),
       local_event_router_(router),
-      page_revisit_broadcaster_(this, sessions_client),
       sessions_updated_callback_(sessions_updated_callback),
       datatype_refresh_callback_(datatype_refresh_callback),
       task_tracker_(std::make_unique<TaskTracker>()) {}
@@ -518,8 +517,6 @@
   if (new_url != old_url) {
     favicon_cache_.OnFaviconVisited(
         new_url, tab_delegate->GetFaviconURLAtIndex(current_index));
-    page_revisit_broadcaster_.OnPageVisit(
-        new_url, tab_delegate->GetTransitionAtIndex(current_index));
   }
 }
 
diff --git a/components/sync_sessions/sessions_sync_manager.h b/components/sync_sessions/sessions_sync_manager.h
index 2fea9ab..18a95fc 100644
--- a/components/sync_sessions/sessions_sync_manager.h
+++ b/components/sync_sessions/sessions_sync_manager.h
@@ -28,7 +28,6 @@
 #include "components/sync_sessions/local_session_event_router.h"
 #include "components/sync_sessions/lost_navigations_recorder.h"
 #include "components/sync_sessions/open_tabs_ui_delegate.h"
-#include "components/sync_sessions/revisit/page_revisit_broadcaster.h"
 #include "components/sync_sessions/sessions_global_id_mapper.h"
 #include "components/sync_sessions/synced_session.h"
 #include "components/sync_sessions/synced_session_tracker.h"
@@ -336,9 +335,6 @@
 
   LocalSessionEventRouter* local_event_router_;
 
-  // Owns revisiting instrumentation logic for page visit events.
-  PageRevisitBroadcaster page_revisit_broadcaster_;
-
   std::unique_ptr<sync_sessions::LostNavigationsRecorder>
       lost_navigations_recorder_;
 
diff --git a/components/test/android/browsertests_apk/src/org/chromium/components_browsertests_apk/ComponentsBrowserTestsApplication.java b/components/test/android/browsertests_apk/src/org/chromium/components_browsertests_apk/ComponentsBrowserTestsApplication.java
index 1e03afe2..014298a 100644
--- a/components/test/android/browsertests_apk/src/org/chromium/components_browsertests_apk/ComponentsBrowserTestsApplication.java
+++ b/components/test/android/browsertests_apk/src/org/chromium/components_browsertests_apk/ComponentsBrowserTestsApplication.java
@@ -4,22 +4,27 @@
 
 package org.chromium.components_browsertests_apk;
 
+import android.app.Application;
 import android.content.Context;
 
 import org.chromium.base.ApplicationStatus;
-import org.chromium.base.BaseChromiumApplication;
+import org.chromium.base.BuildConfig;
 import org.chromium.base.ContextUtils;
 import org.chromium.base.PathUtils;
+import org.chromium.base.multidex.ChromiumMultiDexInstaller;
 
 /**
  * A basic content browser tests {@link android.app.Application}.
  */
-public class ComponentsBrowserTestsApplication extends BaseChromiumApplication {
+public class ComponentsBrowserTestsApplication extends Application {
     static final String PRIVATE_DATA_DIRECTORY_SUFFIX = "components_shell";
 
     @Override
     protected void attachBaseContext(Context base) {
         super.attachBaseContext(base);
+        if (BuildConfig.isMultidexEnabled()) {
+            ChromiumMultiDexInstaller.install(this);
+        }
         ContextUtils.initApplicationContext(this);
     }
 
diff --git a/components/update_client/component.cc b/components/update_client/component.cc
index aa6cd4f..dfe50d2 100644
--- a/components/update_client/component.cc
+++ b/components/update_client/component.cc
@@ -314,8 +314,7 @@
     is_final_ = true;
 
   base::ThreadTaskRunnerHandle::Get()->PostTask(
-      FROM_HERE,
-      base::BindOnce(std::move(callback_), base::Passed(&next_state)));
+      FROM_HERE, base::BindOnce(std::move(callback_), std::move(next_state)));
 }
 
 Component::StateNew::StateNew(Component* component)
@@ -618,7 +617,7 @@
               base::ThreadTaskRunnerHandle::Get(),
               component.crx_component_.pk_hash, component.crx_path_,
               component.next_fp_, component.crx_component_.installer,
-              base::Passed(&connector),
+              std::move(connector),
               base::BindOnce(&Component::StateUpdatingDiff::InstallComplete,
                              base::Unretained(this))));
 }
@@ -681,7 +680,7 @@
                      base::ThreadTaskRunnerHandle::Get(),
                      component.crx_component_.pk_hash, component.crx_path_,
                      component.next_fp_, component.crx_component_.installer,
-                     base::Passed(&connector),
+                     std::move(connector),
                      base::BindOnce(&Component::StateUpdating::InstallComplete,
                                     base::Unretained(this))));
 }
diff --git a/components/update_client/component_patcher_operation.cc b/components/update_client/component_patcher_operation.cc
index 7b1a1ca..cc36bb36e 100644
--- a/components/update_client/component_patcher_operation.cc
+++ b/components/update_client/component_patcher_operation.cc
@@ -193,8 +193,8 @@
 void DeltaUpdateOpPatch::DoRun(ComponentPatcher::Callback callback) {
   patch::Patch(connector_, operation_, input_abs_path_, patch_abs_path_,
                output_abs_path_,
-               base::Bind(&DeltaUpdateOpPatch::DonePatching, this,
-                          base::Passed(&callback)));
+               base::BindOnce(&DeltaUpdateOpPatch::DonePatching, this,
+                              std::move(callback)));
 }
 
 void DeltaUpdateOpPatch::DonePatching(ComponentPatcher::Callback callback,
diff --git a/components/update_client/ping_manager.cc b/components/update_client/ping_manager.cc
index 084edb0..f728f3e 100644
--- a/components/update_client/ping_manager.cc
+++ b/components/update_client/ping_manager.cc
@@ -16,6 +16,7 @@
 #include "base/location.h"
 #include "base/logging.h"
 #include "base/macros.h"
+#include "base/optional.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "components/update_client/configurator.h"
 #include "components/update_client/protocol_builder.h"
@@ -84,7 +85,8 @@
   callback_ = std::move(callback);
 
   request_sender_ = std::make_unique<RequestSender>(config_);
-  request_sender_->Send(false, BuildEventPingRequest(*config_, component), urls,
+  request_sender_->Send(false, BuildEventPingRequest(*config_, component),
+                        base::nullopt, urls,
                         base::BindOnce(&PingSender::SendPingComplete, this));
 }
 
diff --git a/components/update_client/ping_manager_unittest.cc b/components/update_client/ping_manager_unittest.cc
index 791563eb..5ea1d97a 100644
--- a/components/update_client/ping_manager_unittest.cc
+++ b/components/update_client/ping_manager_unittest.cc
@@ -126,12 +126,17 @@
 
     EXPECT_EQ(1, interceptor->GetCount()) << interceptor->GetRequestsAsString();
     EXPECT_NE(string::npos,
-              interceptor->GetRequests()[0].find(
+              interceptor->GetRequestBody(0).find(
                   "<app appid=\"abc\">"
                   "<event eventtype=\"3\" eventresult=\"1\" "
                   "previousversion=\"1.0\" nextversion=\"2.0\"/></app>"))
         << interceptor->GetRequestsAsString();
-    EXPECT_NE(string::npos, interceptor->GetRequests()[0].find(" sessionid="));
+    EXPECT_NE(string::npos, interceptor->GetRequestBody(0).find(" sessionid="));
+
+    // Check the ping request does not carry the interactivity header.
+    EXPECT_FALSE(interceptor->GetRequests()[0].second.HasHeader(
+        "X-GoogleUpdate-Interactivity"));
+
     interceptor->Reset();
   }
 
@@ -150,7 +155,7 @@
 
     EXPECT_EQ(1, interceptor->GetCount()) << interceptor->GetRequestsAsString();
     EXPECT_NE(string::npos,
-              interceptor->GetRequests()[0].find(
+              interceptor->GetRequestBody(0).find(
                   "<app appid=\"abc\">"
                   "<event eventtype=\"3\" eventresult=\"0\" "
                   "previousversion=\"1.0\" nextversion=\"2.0\"/></app>"))
@@ -182,7 +187,7 @@
 
     EXPECT_EQ(1, interceptor->GetCount()) << interceptor->GetRequestsAsString();
     EXPECT_NE(string::npos,
-              interceptor->GetRequests()[0].find(
+              interceptor->GetRequestBody(0).find(
                   "<app appid=\"abc\">"
                   "<event eventtype=\"3\" eventresult=\"0\" errorcat=\"1\" "
                   "errorcode=\"2\" extracode1=\"-1\" diffresult=\"0\" "
@@ -209,7 +214,7 @@
 
     EXPECT_EQ(1, interceptor->GetCount()) << interceptor->GetRequestsAsString();
     EXPECT_NE(string::npos,
-              interceptor->GetRequests()[0].find(
+              interceptor->GetRequestBody(0).find(
                   "<app appid=\"abc\"><event eventtype=\"3\" eventresult=\"0\" "
                   "previousversion=\"1.0\"/></app>"))
         << interceptor->GetRequestsAsString();
@@ -229,7 +234,7 @@
 
     EXPECT_EQ(1, interceptor->GetCount()) << interceptor->GetRequestsAsString();
     EXPECT_NE(string::npos,
-              interceptor->GetRequests()[0].find(
+              interceptor->GetRequestBody(0).find(
                   "<app appid=\"abc\">"
                   "<event eventtype=\"4\" eventresult=\"1\" "
                   "previousversion=\"1.2.3.4\" nextversion=\"0\"/></app>"))
@@ -272,7 +277,7 @@
     EXPECT_EQ(1, interceptor->GetCount()) << interceptor->GetRequestsAsString();
     EXPECT_NE(
         string::npos,
-        interceptor->GetRequests()[0].find(
+        interceptor->GetRequestBody(0).find(
             "<app appid=\"abc\">"
             "<event eventtype=\"3\" eventresult=\"1\" previousversion=\"1.0\" "
             "nextversion=\"2.0\"/>"
diff --git a/components/update_client/request_sender.cc b/components/update_client/request_sender.cc
index c5fda4d..d0a2542 100644
--- a/components/update_client/request_sender.cc
+++ b/components/update_client/request_sender.cc
@@ -61,11 +61,13 @@
 
 void RequestSender::Send(bool use_signing,
                          const std::string& request_body,
+                         base::Optional<bool> is_foreground,
                          const std::vector<GURL>& urls,
                          RequestSenderCallback request_sender_callback) {
   DCHECK(thread_checker_.CalledOnValidThread());
 
   use_signing_ = use_signing;
+  is_foreground_ = is_foreground;
   request_body_ = request_body;
   urls_ = urls;
   request_sender_callback_ = std::move(request_sender_callback);
@@ -101,8 +103,8 @@
     url = BuildUpdateUrl(url, request_query_string);
   }
 
-  url_fetcher_ =
-      SendProtocolRequest(url, request_body_, this, config_->RequestContext());
+  url_fetcher_ = SendProtocolRequest(url, request_body_, is_foreground_, this,
+                                     config_->RequestContext());
   if (!url_fetcher_.get())
     base::ThreadTaskRunnerHandle::Get()->PostTask(
         FROM_HERE, base::BindOnce(&RequestSender::SendInternalComplete,
diff --git a/components/update_client/request_sender.h b/components/update_client/request_sender.h
index 75f1ef9..f833fe4 100644
--- a/components/update_client/request_sender.h
+++ b/components/update_client/request_sender.h
@@ -14,6 +14,7 @@
 #include "base/callback.h"
 #include "base/macros.h"
 #include "base/memory/ref_counted.h"
+#include "base/optional.h"
 #include "base/threading/thread_checker.h"
 #include "net/url_request/url_fetcher_delegate.h"
 #include "url/gurl.h"
@@ -55,9 +56,14 @@
   ~RequestSender() override;
 
   // |use_signing| enables CUP signing of protocol messages exchanged using
-  // this class.
+  // this class. |is_foreground| controls the presence and the value for the
+  // X-GoogleUpdate-Interactvity header serialized in the protocol request.
+  // If this optional parameter is set, the values of "fg" or "bg" are sent
+  // for true or false values of this parameter. Otherwise the header is not
+  // sent at all.
   void Send(bool use_signing,
             const std::string& request_body,
+            base::Optional<bool> is_foreground,
             const std::vector<GURL>& urls,
             RequestSenderCallback request_sender_callback);
 
@@ -100,6 +106,7 @@
   bool use_signing_;  // True if CUP signing is used.
   std::vector<GURL> urls_;
   std::string request_body_;
+  base::Optional<bool> is_foreground_;
   RequestSenderCallback request_sender_callback_;
 
   std::string public_key_;
diff --git a/components/update_client/request_sender_unittest.cc b/components/update_client/request_sender_unittest.cc
index 8310e7b..4225f58 100644
--- a/components/update_client/request_sender_unittest.cc
+++ b/components/update_client/request_sender_unittest.cc
@@ -9,6 +9,7 @@
 
 #include "base/macros.h"
 #include "base/memory/ref_counted.h"
+#include "base/optional.h"
 #include "base/path_service.h"
 #include "base/run_loop.h"
 #include "base/strings/string_util.h"
@@ -41,7 +42,8 @@
 
 }  // namespace
 
-class RequestSenderTest : public testing::Test {
+class RequestSenderTest : public testing::Test,
+                          public ::testing::WithParamInterface<bool> {
  public:
   RequestSenderTest();
   ~RequestSenderTest() override;
@@ -77,6 +79,8 @@
   DISALLOW_COPY_AND_ASSIGN(RequestSenderTest);
 };
 
+INSTANTIATE_TEST_CASE_P(IsForeground, RequestSenderTest, ::testing::Bool());
+
 RequestSenderTest::RequestSenderTest()
     : scoped_task_environment_(
           base::test::ScopedTaskEnvironment::MainThreadType::IO) {}
@@ -133,14 +137,15 @@
 
 // Tests that when a request to the first url succeeds, the subsequent urls are
 // not tried.
-TEST_F(RequestSenderTest, RequestSendSuccess) {
+TEST_P(RequestSenderTest, RequestSendSuccess) {
   EXPECT_TRUE(post_interceptor_1_->ExpectRequest(
       new PartialMatch("test"), test_file("updatecheck_reply_1.xml")));
 
   const std::vector<GURL> urls = {GURL(kUrl1), GURL(kUrl2)};
+  const bool is_foreground = GetParam();
   request_sender_ = std::make_unique<RequestSender>(config_);
   request_sender_->Send(
-      false, "test", urls,
+      false, "test", base::make_optional(is_foreground), urls,
       base::BindOnce(&RequestSenderTest::RequestSenderComplete,
                      base::Unretained(this)));
   RunThreads();
@@ -156,7 +161,7 @@
       << post_interceptor_2_->GetRequestsAsString();
 
   // Sanity check the request.
-  EXPECT_STREQ("test", post_interceptor_1_->GetRequests()[0].c_str());
+  EXPECT_STREQ("test", post_interceptor_1_->GetRequestBody(0).c_str());
 
   // Check the response post conditions.
   EXPECT_EQ(0, error_);
@@ -165,6 +170,14 @@
                                base::CompareCase::SENSITIVE));
   EXPECT_EQ(505ul, response_.size());
 
+  // Check the interactivity header value.
+  const auto extra_request_headers =
+      post_interceptor_1_->GetRequests()[0].second;
+  EXPECT_TRUE(extra_request_headers.HasHeader("X-GoogleUpdate-Interactivity"));
+  std::string header;
+  extra_request_headers.GetHeader("X-GoogleUpdate-Interactivity", &header);
+  EXPECT_STREQ(is_foreground ? "fg" : "bg", header.c_str());
+
   interceptor_factory_ = nullptr;
 }
 
@@ -178,7 +191,7 @@
   const std::vector<GURL> urls = {GURL(kUrl1), GURL(kUrl2)};
   request_sender_ = std::make_unique<RequestSender>(config_);
   request_sender_->Send(
-      false, "test", urls,
+      false, "test", base::make_optional(false), urls,
       base::BindOnce(&RequestSenderTest::RequestSenderComplete,
                      base::Unretained(this)));
   RunThreads();
@@ -192,8 +205,8 @@
   EXPECT_EQ(1, post_interceptor_2_->GetCount())
       << post_interceptor_2_->GetRequestsAsString();
 
-  EXPECT_STREQ("test", post_interceptor_1_->GetRequests()[0].c_str());
-  EXPECT_STREQ("test", post_interceptor_2_->GetRequests()[0].c_str());
+  EXPECT_STREQ("test", post_interceptor_1_->GetRequestBody(0).c_str());
+  EXPECT_STREQ("test", post_interceptor_2_->GetRequestBody(0).c_str());
   EXPECT_EQ(0, error_);
 }
 
@@ -207,7 +220,7 @@
   const std::vector<GURL> urls = {GURL(kUrl1), GURL(kUrl2)};
   request_sender_ = std::make_unique<RequestSender>(config_);
   request_sender_->Send(
-      false, "test", urls,
+      false, "test", base::nullopt, urls,
       base::BindOnce(&RequestSenderTest::RequestSenderComplete,
                      base::Unretained(this)));
   RunThreads();
@@ -221,8 +234,8 @@
   EXPECT_EQ(1, post_interceptor_2_->GetCount())
       << post_interceptor_2_->GetRequestsAsString();
 
-  EXPECT_STREQ("test", post_interceptor_1_->GetRequests()[0].c_str());
-  EXPECT_STREQ("test", post_interceptor_2_->GetRequests()[0].c_str());
+  EXPECT_STREQ("test", post_interceptor_1_->GetRequestBody(0).c_str());
+  EXPECT_STREQ("test", post_interceptor_2_->GetRequestBody(0).c_str());
   EXPECT_EQ(403, error_);
 }
 
@@ -231,7 +244,7 @@
   std::vector<GURL> urls;
   request_sender_ = std::make_unique<RequestSender>(config_);
   request_sender_->Send(
-      false, "test", urls,
+      false, "test", base::nullopt, urls,
       base::BindOnce(&RequestSenderTest::RequestSenderComplete,
                      base::Unretained(this)));
   RunThreads();
@@ -247,7 +260,7 @@
   const std::vector<GURL> urls = {GURL(kUrl1)};
   request_sender_ = std::make_unique<RequestSender>(config_);
   request_sender_->Send(
-      true, "test", urls,
+      true, "test", base::nullopt, urls,
       base::BindOnce(&RequestSenderTest::RequestSenderComplete,
                      base::Unretained(this)));
   RunThreads();
@@ -257,7 +270,7 @@
   EXPECT_EQ(1, post_interceptor_1_->GetCount())
       << post_interceptor_1_->GetRequestsAsString();
 
-  EXPECT_STREQ("test", post_interceptor_1_->GetRequests()[0].c_str());
+  EXPECT_STREQ("test", post_interceptor_1_->GetRequestBody(0).c_str());
   EXPECT_EQ(RequestSender::kErrorResponseNotTrusted, error_);
   EXPECT_TRUE(response_.empty());
 }
diff --git a/components/update_client/update_checker.cc b/components/update_client/update_checker.cc
index 85d2b8c..292a94f 100644
--- a/components/update_client/update_checker.cc
+++ b/components/update_client/update_checker.cc
@@ -60,6 +60,7 @@
                        const IdToComponentPtrMap& components,
                        const std::string& additional_attributes,
                        bool enabled_component_updates,
+                       bool is_foreground,
                        UpdateCheckCallback update_check_callback) override;
 
  private:
@@ -67,7 +68,8 @@
   void CheckForUpdatesHelper(const std::string& session_id,
                              const IdToComponentPtrMap& components,
                              const std::string& additional_attributes,
-                             bool enabled_component_updates);
+                             bool enabled_component_updates,
+                             bool is_foreground);
   void OnRequestSenderComplete(const IdToComponentPtrMap& components,
                                int error,
                                const std::string& response,
@@ -105,6 +107,7 @@
     const IdToComponentPtrMap& components,
     const std::string& additional_attributes,
     bool enabled_component_updates,
+    bool is_foreground,
     UpdateCheckCallback update_check_callback) {
   DCHECK(thread_checker_.CalledOnValidThread());
 
@@ -118,7 +121,7 @@
       base::BindOnce(&UpdateCheckerImpl::CheckForUpdatesHelper,
                      base::Unretained(this), session_id,
                      base::ConstRef(components), additional_attributes,
-                     enabled_component_updates));
+                     enabled_component_updates, is_foreground));
 }
 
 // This function runs on the blocking pool task runner.
@@ -139,7 +142,8 @@
     const std::string& session_id,
     const IdToComponentPtrMap& components,
     const std::string& additional_attributes,
-    bool enabled_component_updates) {
+    bool enabled_component_updates,
+    bool is_foreground) {
   DCHECK(thread_checker_.CalledOnValidThread());
 
   auto urls(config_->UpdateUrl());
@@ -153,7 +157,7 @@
                               metadata_, additional_attributes,
                               enabled_component_updates,
                               updater_state_attributes_),
-      urls,
+      base::make_optional(is_foreground), urls,
       base::BindOnce(&UpdateCheckerImpl::OnRequestSenderComplete,
                      base::Unretained(this), base::ConstRef(components)));
 }
diff --git a/components/update_client/update_checker.h b/components/update_client/update_checker.h
index d308271e..24e224a 100644
--- a/components/update_client/update_checker.h
+++ b/components/update_client/update_checker.h
@@ -35,6 +35,8 @@
   // |additional_attributes| provides a way to customize the <request> element.
   // This value is inserted as-is, therefore it must be well-formed as an
   // XML attribute string.
+  // |is_foreground| controls the value of "X-GoogleUpdate-Interactivity"
+  // header which is sent with the update check.
   // On completion, the state of |components| is mutated as required by the
   // server response received.
   virtual void CheckForUpdates(const std::string& session_id,
@@ -42,6 +44,7 @@
                                const IdToComponentPtrMap& components,
                                const std::string& additional_attributes,
                                bool enabled_component_updates,
+                               bool is_foreground,
                                UpdateCheckCallback update_check_callback) = 0;
 
   static std::unique_ptr<UpdateChecker> Create(
diff --git a/components/update_client/update_checker_unittest.cc b/components/update_client/update_checker_unittest.cc
index 91bb1b40..bdd47e5 100644
--- a/components/update_client/update_checker_unittest.cc
+++ b/components/update_client/update_checker_unittest.cc
@@ -104,7 +104,8 @@
 
 }  // namespace
 
-class UpdateCheckerTest : public testing::Test {
+class UpdateCheckerTest : public testing::Test,
+                          public ::testing::WithParamInterface<bool> {
  public:
   UpdateCheckerTest();
   ~UpdateCheckerTest() override;
@@ -146,6 +147,8 @@
   DISALLOW_COPY_AND_ASSIGN(UpdateCheckerTest);
 };
 
+INSTANTIATE_TEST_CASE_P(IsForeground, UpdateCheckerTest, ::testing::Bool());
+
 UpdateCheckerTest::UpdateCheckerTest()
     : scoped_task_environment_(
           base::test::ScopedTaskEnvironment::MainThreadType::IO) {}
@@ -225,7 +228,7 @@
   return component;
 }
 
-TEST_F(UpdateCheckerTest, UpdateCheckSuccess) {
+TEST_P(UpdateCheckerTest, UpdateCheckSuccess) {
   EXPECT_TRUE(post_interceptor_->ExpectRequest(
       new PartialMatch("updatecheck"), test_file("updatecheck_reply_1.xml")));
 
@@ -237,9 +240,10 @@
   auto& component = components[kUpdateItemId];
   component->crx_component_.installer_attributes["ap"] = "some_ap";
 
+  const bool is_foreground = GetParam();
   update_checker_->CheckForUpdates(
       update_context_->session_id, std::vector<std::string>{kUpdateItemId},
-      components, "extra=\"params\"", true,
+      components, "extra=\"params\"", true, is_foreground,
       base::BindOnce(&UpdateCheckerTest::UpdateCheckComplete,
                      base::Unretained(this)));
   RunThreads();
@@ -250,9 +254,9 @@
       << post_interceptor_->GetRequestsAsString();
 
   // Sanity check the request.
-  const auto request = post_interceptor_->GetRequests()[0];
-  EXPECT_NE(string::npos, post_interceptor_->GetRequests()[0].find(
-                              "request protocol=\"3.1\" extra=\"params\""));
+  const auto request = post_interceptor_->GetRequestBody(0);
+  EXPECT_NE(string::npos,
+            request.find("request protocol=\"3.1\" extra=\"params\""));
   // The request must not contain any "dlpref" in the default case.
   EXPECT_EQ(string::npos, request.find(" dlpref=\""));
   EXPECT_NE(string::npos,
@@ -292,6 +296,13 @@
   EXPECT_NE(string::npos, request.find(" name=\"Omaha\" "));
 #endif  // GOOGLE_CHROME_BUILD
 #endif  // OS_WINDOWS
+
+  // Check the interactivity header value.
+  const auto extra_request_headers = post_interceptor_->GetRequests()[0].second;
+  EXPECT_TRUE(extra_request_headers.HasHeader("X-GoogleUpdate-Interactivity"));
+  std::string header;
+  extra_request_headers.GetHeader("X-GoogleUpdate-Interactivity", &header);
+  EXPECT_STREQ(is_foreground ? "fg" : "bg", header.c_str());
 }
 
 // Tests that an invalid "ap" is not serialized.
@@ -310,19 +321,19 @@
 
   update_checker_->CheckForUpdates(
       update_context_->session_id, std::vector<std::string>{kUpdateItemId},
-      components, "", true,
+      components, "", true, true,
       base::BindOnce(&UpdateCheckerTest::UpdateCheckComplete,
                      base::Unretained(this)));
 
   RunThreads();
 
-  EXPECT_NE(string::npos, post_interceptor_->GetRequests()[0].find(
-                              std::string("app appid=\"") + kUpdateItemId +
-                              "\" version=\"0.9\" brand=\"TEST\" enabled=\"1\">"
-                              "<updatecheck/><ping r=\"-2\" "));
+  const auto request = post_interceptor_->GetRequestBody(0);
   EXPECT_NE(string::npos,
-            post_interceptor_->GetRequests()[0].find(
-                "<packages><package fp=\"fp1\"/></packages></app>"));
+            request.find(std::string("app appid=\"") + kUpdateItemId +
+                         "\" version=\"0.9\" brand=\"TEST\" enabled=\"1\">"
+                         "<updatecheck/><ping r=\"-2\" "));
+  EXPECT_NE(string::npos,
+            request.find("<packages><package fp=\"fp1\"/></packages></app>"));
 }
 
 TEST_F(UpdateCheckerTest, UpdateCheckSuccessNoBrand) {
@@ -337,19 +348,19 @@
 
   update_checker_->CheckForUpdates(
       update_context_->session_id, std::vector<std::string>{kUpdateItemId},
-      components, "", true,
+      components, "", true, true,
       base::BindOnce(&UpdateCheckerTest::UpdateCheckComplete,
                      base::Unretained(this)));
 
   RunThreads();
 
-  EXPECT_NE(string::npos, post_interceptor_->GetRequests()[0].find(
-                              std::string("<app appid=\"") + kUpdateItemId +
-                              "\" version=\"0.9\" enabled=\"1\">"
-                              "<updatecheck/><ping r=\"-2\" "));
+  const auto request = post_interceptor_->GetRequestBody(0);
   EXPECT_NE(string::npos,
-            post_interceptor_->GetRequests()[0].find(
-                "<packages><package fp=\"fp1\"/></packages></app>"));
+            request.find(std::string("<app appid=\"") + kUpdateItemId +
+                         "\" version=\"0.9\" enabled=\"1\">"
+                         "<updatecheck/><ping r=\"-2\" "));
+  EXPECT_NE(string::npos,
+            request.find("<packages><package fp=\"fp1\"/></packages></app>"));
 }
 
 // Simulates a 403 server response error.
@@ -366,7 +377,7 @@
 
   update_checker_->CheckForUpdates(
       update_context_->session_id, std::vector<std::string>{kUpdateItemId},
-      components, "", true,
+      components, "", true, true,
       base::BindOnce(&UpdateCheckerTest::UpdateCheckComplete,
                      base::Unretained(this)));
   RunThreads();
@@ -393,15 +404,15 @@
 
   update_checker_->CheckForUpdates(
       update_context_->session_id, std::vector<std::string>{kUpdateItemId},
-      components, "extra=\"params\"", true,
+      components, "extra=\"params\"", true, true,
       base::BindOnce(&UpdateCheckerTest::UpdateCheckComplete,
                      base::Unretained(this)));
 
   RunThreads();
 
   // The request must contain dlpref="cacheable".
-  EXPECT_NE(string::npos,
-            post_interceptor_->GetRequests()[0].find(" dlpref=\"cacheable\""));
+  const auto request = post_interceptor_->GetRequestBody(0);
+  EXPECT_NE(string::npos, request.find(" dlpref=\"cacheable\""));
 }
 
 // This test is checking that an update check signed with CUP fails, since there
@@ -421,7 +432,7 @@
 
   update_checker_->CheckForUpdates(
       update_context_->session_id, std::vector<std::string>{kUpdateItemId},
-      components, "", true,
+      components, "", true, true,
       base::BindOnce(&UpdateCheckerTest::UpdateCheckComplete,
                      base::Unretained(this)));
 
@@ -433,14 +444,14 @@
       << post_interceptor_->GetRequestsAsString();
 
   // Sanity check the request.
-  EXPECT_NE(string::npos, post_interceptor_->GetRequests()[0].find(
-                              std::string("<app appid=\"") + kUpdateItemId +
-                              "\" version=\"0.9\" "
-                              "brand=\"TEST\" enabled=\"1\">"
-                              "<updatecheck/><ping r=\"-2\" "));
+  const auto request = post_interceptor_->GetRequestBody(0);
   EXPECT_NE(string::npos,
-            post_interceptor_->GetRequests()[0].find(
-                "<packages><package fp=\"fp1\"/></packages></app>"));
+            request.find(std::string("<app appid=\"") + kUpdateItemId +
+                         "\" version=\"0.9\" "
+                         "brand=\"TEST\" enabled=\"1\">"
+                         "<updatecheck/><ping r=\"-2\" "));
+  EXPECT_NE(string::npos,
+            request.find("<packages><package fp=\"fp1\"/></packages></app>"));
 
   // Expect an error since the response is not trusted.
   EXPECT_EQ(-10000, error_);
@@ -462,7 +473,7 @@
 
   update_checker_->CheckForUpdates(
       update_context_->session_id, std::vector<std::string>{kUpdateItemId},
-      components, "", true,
+      components, "", true, true,
       base::BindOnce(&UpdateCheckerTest::UpdateCheckComplete,
                      base::Unretained(this)));
   RunThreads();
@@ -488,7 +499,7 @@
   activity_data_service_->SetDaysSinceLastRollCall(kUpdateItemId, 5);
   update_checker_->CheckForUpdates(
       update_context_->session_id, std::vector<std::string>{kUpdateItemId},
-      components, "extra=\"params\"", true,
+      components, "extra=\"params\"", true, true,
       base::BindOnce(&UpdateCheckerTest::UpdateCheckComplete,
                      base::Unretained(this)));
   RunThreads();
@@ -496,7 +507,7 @@
   update_checker_ = UpdateChecker::Create(config_, metadata_.get());
   update_checker_->CheckForUpdates(
       update_context_->session_id, std::vector<std::string>{kUpdateItemId},
-      components, "extra=\"params\"", true,
+      components, "extra=\"params\"", true, true,
       base::BindOnce(&UpdateCheckerTest::UpdateCheckComplete,
                      base::Unretained(this)));
   RunThreads();
@@ -505,9 +516,9 @@
       << post_interceptor_->GetRequestsAsString();
   ASSERT_EQ(2, post_interceptor_->GetCount())
       << post_interceptor_->GetRequestsAsString();
-  EXPECT_NE(string::npos, post_interceptor_->GetRequests()[0].find(
+  EXPECT_NE(string::npos, post_interceptor_->GetRequestBody(0).find(
                               "<ping r=\"5\" ping_freshness="));
-  EXPECT_NE(string::npos, post_interceptor_->GetRequests()[1].find(
+  EXPECT_NE(string::npos, post_interceptor_->GetRequestBody(1).find(
                               "<ping rd=\"3383\" ping_freshness="));
 }
 
@@ -528,7 +539,7 @@
   activity_data_service_->SetDaysSinceLastActive(kUpdateItemId, 10);
   update_checker_->CheckForUpdates(
       update_context_->session_id, std::vector<std::string>{kUpdateItemId},
-      components, "extra=\"params\"", true,
+      components, "extra=\"params\"", true, true,
       base::BindOnce(&UpdateCheckerTest::UpdateCheckComplete,
                      base::Unretained(this)));
   RunThreads();
@@ -540,7 +551,7 @@
   update_checker_ = UpdateChecker::Create(config_, metadata_.get());
   update_checker_->CheckForUpdates(
       update_context_->session_id, std::vector<std::string>{kUpdateItemId},
-      components, "extra=\"params\"", true,
+      components, "extra=\"params\"", true, true,
       base::BindOnce(&UpdateCheckerTest::UpdateCheckComplete,
                      base::Unretained(this)));
   RunThreads();
@@ -551,7 +562,7 @@
   update_checker_ = UpdateChecker::Create(config_, metadata_.get());
   update_checker_->CheckForUpdates(
       update_context_->session_id, std::vector<std::string>{kUpdateItemId},
-      components, "extra=\"params\"", true,
+      components, "extra=\"params\"", true, true,
       base::BindOnce(&UpdateCheckerTest::UpdateCheckComplete,
                      base::Unretained(this)));
   RunThreads();
@@ -562,11 +573,11 @@
       << post_interceptor_->GetRequestsAsString();
   ASSERT_EQ(3, post_interceptor_->GetCount())
       << post_interceptor_->GetRequestsAsString();
-  EXPECT_NE(string::npos, post_interceptor_->GetRequests()[0].find(
+  EXPECT_NE(string::npos, post_interceptor_->GetRequestBody(0).find(
                               "<ping a=\"10\" r=\"-2\" ping_freshness="));
-  EXPECT_NE(string::npos, post_interceptor_->GetRequests()[1].find(
+  EXPECT_NE(string::npos, post_interceptor_->GetRequestBody(1).find(
                               "<ping ad=\"3383\" rd=\"3383\" ping_freshness="));
-  EXPECT_NE(string::npos, post_interceptor_->GetRequests()[2].find(
+  EXPECT_NE(string::npos, post_interceptor_->GetRequestBody(2).find(
                               "<ping rd=\"3383\" ping_freshness="));
 }
 
@@ -583,25 +594,25 @@
       new PartialMatch("updatecheck"), test_file("updatecheck_reply_1.xml")));
   update_checker_->CheckForUpdates(
       update_context_->session_id, std::vector<std::string>{kUpdateItemId},
-      components, "", false,
+      components, "", false, true,
       base::BindOnce(&UpdateCheckerTest::UpdateCheckComplete,
                      base::Unretained(this)));
   RunThreads();
 
   EXPECT_EQ(string::npos,
-            post_interceptor_->GetRequests()[0].find("installsource="));
+            post_interceptor_->GetRequestBody(0).find("installsource="));
 
   component->set_on_demand(true);
   EXPECT_TRUE(post_interceptor_->ExpectRequest(
       new PartialMatch("updatecheck"), test_file("updatecheck_reply_1.xml")));
   update_checker_->CheckForUpdates(
       update_context_->session_id, std::vector<std::string>{kUpdateItemId},
-      components, "", false,
+      components, "", false, true,
       base::BindOnce(&UpdateCheckerTest::UpdateCheckComplete,
                      base::Unretained(this)));
   RunThreads();
 
-  EXPECT_NE(string::npos, post_interceptor_->GetRequests()[1].find(
+  EXPECT_NE(string::npos, post_interceptor_->GetRequestBody(1).find(
                               "installsource=\"ondemand\""));
 
   component->set_on_demand(false);
@@ -610,12 +621,12 @@
       new PartialMatch("updatecheck"), test_file("updatecheck_reply_1.xml")));
   update_checker_->CheckForUpdates(
       update_context_->session_id, std::vector<std::string>{kUpdateItemId},
-      components, "", false,
+      components, "", false, true,
       base::BindOnce(&UpdateCheckerTest::UpdateCheckComplete,
                      base::Unretained(this)));
   RunThreads();
 
-  EXPECT_NE(string::npos, post_interceptor_->GetRequests()[2].find(
+  EXPECT_NE(string::npos, post_interceptor_->GetRequestBody(2).find(
                               "installsource=\"webstore\""));
 
   component->set_on_demand(true);
@@ -624,12 +635,12 @@
       new PartialMatch("updatecheck"), test_file("updatecheck_reply_1.xml")));
   update_checker_->CheckForUpdates(
       update_context_->session_id, std::vector<std::string>{kUpdateItemId},
-      components, "", false,
+      components, "", false, true,
       base::BindOnce(&UpdateCheckerTest::UpdateCheckComplete,
                      base::Unretained(this)));
   RunThreads();
 
-  EXPECT_NE(string::npos, post_interceptor_->GetRequests()[3].find(
+  EXPECT_NE(string::npos, post_interceptor_->GetRequestBody(3).find(
                               "installsource=\"sideload\""));
 }
 
@@ -646,14 +657,14 @@
       new PartialMatch("updatecheck"), test_file("updatecheck_reply_1.xml")));
   update_checker_->CheckForUpdates(
       update_context_->session_id, std::vector<std::string>{kUpdateItemId},
-      components, "", false,
+      components, "", false, true,
       base::BindOnce(&UpdateCheckerTest::UpdateCheckComplete,
                      base::Unretained(this)));
   RunThreads();
   EXPECT_NE(string::npos,
-            post_interceptor_->GetRequests()[0].find("enabled=\"1\""));
+            post_interceptor_->GetRequestBody(0).find("enabled=\"1\""));
   EXPECT_EQ(string::npos,
-            post_interceptor_->GetRequests()[0].find("<disabled"));
+            post_interceptor_->GetRequestBody(0).find("<disabled"));
 
   crx_component.disabled_reasons = std::vector<int>();
   update_checker_ = UpdateChecker::Create(config_, metadata_.get());
@@ -661,27 +672,27 @@
       new PartialMatch("updatecheck"), test_file("updatecheck_reply_1.xml")));
   update_checker_->CheckForUpdates(
       update_context_->session_id, std::vector<std::string>{kUpdateItemId},
-      components, "", false,
+      components, "", false, true,
       base::BindOnce(&UpdateCheckerTest::UpdateCheckComplete,
                      base::Unretained(this)));
   RunThreads();
   EXPECT_NE(string::npos,
-            post_interceptor_->GetRequests()[1].find("enabled=\"1\""));
+            post_interceptor_->GetRequestBody(1).find("enabled=\"1\""));
   EXPECT_EQ(string::npos,
-            post_interceptor_->GetRequests()[1].find("<disabled"));
+            post_interceptor_->GetRequestBody(1).find("<disabled"));
 
   crx_component.disabled_reasons = std::vector<int>({0});
   EXPECT_TRUE(post_interceptor_->ExpectRequest(
       new PartialMatch("updatecheck"), test_file("updatecheck_reply_1.xml")));
   update_checker_->CheckForUpdates(
       update_context_->session_id, std::vector<std::string>{kUpdateItemId},
-      components, "", false,
+      components, "", false, true,
       base::BindOnce(&UpdateCheckerTest::UpdateCheckComplete,
                      base::Unretained(this)));
   RunThreads();
   EXPECT_NE(string::npos,
-            post_interceptor_->GetRequests()[2].find("enabled=\"0\""));
-  EXPECT_NE(string::npos, post_interceptor_->GetRequests()[2].find(
+            post_interceptor_->GetRequestBody(2).find("enabled=\"0\""));
+  EXPECT_NE(string::npos, post_interceptor_->GetRequestBody(2).find(
                               "<disabled reason=\"0\"/>"));
 
   crx_component.disabled_reasons = std::vector<int>({1});
@@ -690,13 +701,13 @@
       new PartialMatch("updatecheck"), test_file("updatecheck_reply_1.xml")));
   update_checker_->CheckForUpdates(
       update_context_->session_id, std::vector<std::string>{kUpdateItemId},
-      components, "", false,
+      components, "", false, true,
       base::BindOnce(&UpdateCheckerTest::UpdateCheckComplete,
                      base::Unretained(this)));
   RunThreads();
   EXPECT_NE(string::npos,
-            post_interceptor_->GetRequests()[3].find("enabled=\"0\""));
-  EXPECT_NE(string::npos, post_interceptor_->GetRequests()[3].find(
+            post_interceptor_->GetRequestBody(3).find("enabled=\"0\""));
+  EXPECT_NE(string::npos, post_interceptor_->GetRequestBody(3).find(
                               "<disabled reason=\"1\"/>"));
 
   crx_component.disabled_reasons = std::vector<int>({4, 8, 16});
@@ -705,17 +716,17 @@
       new PartialMatch("updatecheck"), test_file("updatecheck_reply_1.xml")));
   update_checker_->CheckForUpdates(
       update_context_->session_id, std::vector<std::string>{kUpdateItemId},
-      components, "", false,
+      components, "", false, true,
       base::BindOnce(&UpdateCheckerTest::UpdateCheckComplete,
                      base::Unretained(this)));
   RunThreads();
   EXPECT_NE(string::npos,
-            post_interceptor_->GetRequests()[4].find("enabled=\"0\""));
-  EXPECT_NE(string::npos, post_interceptor_->GetRequests()[4].find(
+            post_interceptor_->GetRequestBody(4).find("enabled=\"0\""));
+  EXPECT_NE(string::npos, post_interceptor_->GetRequestBody(4).find(
                               "<disabled reason=\"4\"/>"));
-  EXPECT_NE(string::npos, post_interceptor_->GetRequests()[4].find(
+  EXPECT_NE(string::npos, post_interceptor_->GetRequestBody(4).find(
                               "<disabled reason=\"8\"/>"));
-  EXPECT_NE(string::npos, post_interceptor_->GetRequests()[4].find(
+  EXPECT_NE(string::npos, post_interceptor_->GetRequestBody(4).find(
                               "<disabled reason=\"16\"/>"));
 
   crx_component.disabled_reasons = std::vector<int>({0, 4, 8, 16});
@@ -724,19 +735,19 @@
       new PartialMatch("updatecheck"), test_file("updatecheck_reply_1.xml")));
   update_checker_->CheckForUpdates(
       update_context_->session_id, std::vector<std::string>{kUpdateItemId},
-      components, "", false,
+      components, "", false, true,
       base::BindOnce(&UpdateCheckerTest::UpdateCheckComplete,
                      base::Unretained(this)));
   RunThreads();
   EXPECT_NE(string::npos,
-            post_interceptor_->GetRequests()[5].find("enabled=\"0\""));
-  EXPECT_NE(string::npos, post_interceptor_->GetRequests()[5].find(
+            post_interceptor_->GetRequestBody(5).find("enabled=\"0\""));
+  EXPECT_NE(string::npos, post_interceptor_->GetRequestBody(5).find(
                               "<disabled reason=\"0\"/>"));
-  EXPECT_NE(string::npos, post_interceptor_->GetRequests()[5].find(
+  EXPECT_NE(string::npos, post_interceptor_->GetRequestBody(5).find(
                               "<disabled reason=\"4\"/>"));
-  EXPECT_NE(string::npos, post_interceptor_->GetRequests()[5].find(
+  EXPECT_NE(string::npos, post_interceptor_->GetRequestBody(5).find(
                               "<disabled reason=\"8\"/>"));
-  EXPECT_NE(string::npos, post_interceptor_->GetRequests()[5].find(
+  EXPECT_NE(string::npos, post_interceptor_->GetRequestBody(5).find(
                               "<disabled reason=\"16\"/>"));
 }
 
@@ -761,11 +772,11 @@
       new PartialMatch("updatecheck"), test_file("updatecheck_reply_1.xml")));
   update_checker_->CheckForUpdates(
       update_context_->session_id, std::vector<std::string>{kUpdateItemId},
-      components, "", false,
+      components, "", false, true,
       base::BindOnce(&UpdateCheckerTest::UpdateCheckComplete,
                      base::Unretained(this)));
   RunThreads();
-  EXPECT_NE(string::npos, post_interceptor_->GetRequests()[0].find(
+  EXPECT_NE(string::npos, post_interceptor_->GetRequestBody(0).find(
                               std::string("<app appid=\"") + kUpdateItemId +
                               "\" version=\"0.9\" enabled=\"1\">"
                               "<updatecheck/>"));
@@ -781,11 +792,11 @@
       new PartialMatch("updatecheck"), test_file("updatecheck_reply_1.xml")));
   update_checker_->CheckForUpdates(
       update_context_->session_id, std::vector<std::string>{kUpdateItemId},
-      components, "", false,
+      components, "", false, true,
       base::BindOnce(&UpdateCheckerTest::UpdateCheckComplete,
                      base::Unretained(this)));
   RunThreads();
-  EXPECT_NE(string::npos, post_interceptor_->GetRequests()[1].find(
+  EXPECT_NE(string::npos, post_interceptor_->GetRequestBody(1).find(
                               std::string("<app appid=\"") + kUpdateItemId +
                               "\" version=\"0.9\" enabled=\"1\">"
                               "<updatecheck updatedisabled=\"true\"/>"));
@@ -801,11 +812,11 @@
       new PartialMatch("updatecheck"), test_file("updatecheck_reply_1.xml")));
   update_checker_->CheckForUpdates(
       update_context_->session_id, std::vector<std::string>{kUpdateItemId},
-      components, "", true,
+      components, "", true, true,
       base::BindOnce(&UpdateCheckerTest::UpdateCheckComplete,
                      base::Unretained(this)));
   RunThreads();
-  EXPECT_NE(string::npos, post_interceptor_->GetRequests()[2].find(
+  EXPECT_NE(string::npos, post_interceptor_->GetRequestBody(2).find(
                               std::string("<app appid=\"") + kUpdateItemId +
                               "\" version=\"0.9\" enabled=\"1\">"
                               "<updatecheck/>"));
@@ -821,11 +832,11 @@
       new PartialMatch("updatecheck"), test_file("updatecheck_reply_1.xml")));
   update_checker_->CheckForUpdates(
       update_context_->session_id, std::vector<std::string>{kUpdateItemId},
-      components, "", true,
+      components, "", true, true,
       base::BindOnce(&UpdateCheckerTest::UpdateCheckComplete,
                      base::Unretained(this)));
   RunThreads();
-  EXPECT_NE(string::npos, post_interceptor_->GetRequests()[3].find(
+  EXPECT_NE(string::npos, post_interceptor_->GetRequestBody(3).find(
                               std::string("<app appid=\"") + kUpdateItemId +
                               "\" version=\"0.9\" enabled=\"1\">"
                               "<updatecheck/>"));
@@ -845,7 +856,7 @@
 
   update_checker_->CheckForUpdates(
       update_context_->session_id, std::vector<std::string>{kUpdateItemId},
-      components, "", true,
+      components, "", true, true,
       base::BindOnce(&UpdateCheckerTest::UpdateCheckComplete,
                      base::Unretained(this)));
   RunThreads();
diff --git a/components/update_client/update_client_unittest.cc b/components/update_client/update_client_unittest.cc
index efca391..835ae94 100644
--- a/components/update_client/update_client_unittest.cc
+++ b/components/update_client/update_client_unittest.cc
@@ -12,6 +12,7 @@
 #include "base/location.h"
 #include "base/macros.h"
 #include "base/memory/ref_counted.h"
+#include "base/optional.h"
 #include "base/path_service.h"
 #include "base/run_loop.h"
 #include "base/task_scheduler/post_task.h"
@@ -247,6 +248,7 @@
                          const IdToComponentPtrMap& components,
                          const std::string& additional_attributes,
                          bool enabled_component_updates,
+                         bool is_foreground,
                          UpdateCheckCallback update_check_callback) override {
       EXPECT_FALSE(session_id.empty());
       EXPECT_TRUE(enabled_component_updates);
@@ -361,6 +363,7 @@
                          const IdToComponentPtrMap& components,
                          const std::string& additional_attributes,
                          bool enabled_component_updates,
+                         bool is_foreground,
                          UpdateCheckCallback update_check_callback) override {
       /*
       Fake the following response:
@@ -574,6 +577,7 @@
                          const IdToComponentPtrMap& components,
                          const std::string& additional_attributes,
                          bool enabled_component_updates,
+                         bool is_foreground,
                          UpdateCheckCallback update_check_callback) override {
       /*
       Fake the following response:
@@ -846,6 +850,7 @@
                          const IdToComponentPtrMap& components,
                          const std::string& additional_attributes,
                          bool enabled_component_updates,
+                         bool is_foreground,
                          UpdateCheckCallback update_check_callback) override {
       /*
       Fake the following response:
@@ -1117,6 +1122,7 @@
                          const IdToComponentPtrMap& components,
                          const std::string& additional_attributes,
                          bool enabled_component_updates,
+                         bool is_foreground,
                          UpdateCheckCallback update_check_callback) override {
       EXPECT_FALSE(session_id.empty());
 
@@ -1448,6 +1454,7 @@
                          const IdToComponentPtrMap& components,
                          const std::string& additional_attributes,
                          bool enabled_component_updates,
+                         bool is_foreground,
                          UpdateCheckCallback update_check_callback) override {
       /*
       Fake the following response:
@@ -1640,6 +1647,7 @@
                          const IdToComponentPtrMap& components,
                          const std::string& additional_attributes,
                          bool enabled_component_updates,
+                         bool is_foreground,
                          UpdateCheckCallback update_check_callback) override {
       EXPECT_FALSE(session_id.empty());
 
@@ -1946,6 +1954,7 @@
                          const IdToComponentPtrMap& components,
                          const std::string& additional_attributes,
                          bool enabled_component_updates,
+                         bool is_foreground,
                          UpdateCheckCallback update_check_callback) override {
       EXPECT_FALSE(session_id.empty());
       EXPECT_TRUE(enabled_component_updates);
@@ -2059,6 +2068,7 @@
                          const IdToComponentPtrMap& components,
                          const std::string& additional_attributes,
                          bool enabled_component_updates,
+                         bool is_foreground,
                          UpdateCheckCallback update_check_callback) override {
       /*
       Fake the following response:
@@ -2254,6 +2264,7 @@
                          const IdToComponentPtrMap& components,
                          const std::string& additional_attributes,
                          bool enabled_component_updates,
+                         bool is_foreground,
                          UpdateCheckCallback update_check_callback) override {
       EXPECT_FALSE(session_id.empty());
       EXPECT_TRUE(enabled_component_updates);
@@ -2360,6 +2371,7 @@
                          const IdToComponentPtrMap& components,
                          const std::string& additional_attributes,
                          bool enabled_component_updates,
+                         bool is_foreground,
                          UpdateCheckCallback update_check_callback) override {
       NOTREACHED();
     }
@@ -2421,6 +2433,7 @@
                          const IdToComponentPtrMap& components,
                          const std::string& additional_attributes,
                          bool enabled_component_updates,
+                         bool is_foreground,
                          UpdateCheckCallback update_check_callback) override {
       NOTREACHED();
     }
@@ -2524,6 +2537,7 @@
                          const IdToComponentPtrMap& components,
                          const std::string& additional_attributes,
                          bool enabled_component_updates,
+                         bool is_foreground,
                          UpdateCheckCallback update_check_callback) override {
       EXPECT_FALSE(session_id.empty());
 
@@ -2702,6 +2716,7 @@
                          const IdToComponentPtrMap& components,
                          const std::string& additional_attributes,
                          bool enabled_component_updates,
+                         bool is_foreground,
                          UpdateCheckCallback update_check_callback) override {
       /*
       Fake the following response:
@@ -2951,6 +2966,7 @@
                          const IdToComponentPtrMap& components,
                          const std::string& additional_attributes,
                          bool enabled_component_updates,
+                         bool is_foreground,
                          UpdateCheckCallback update_check_callback) override {
       EXPECT_FALSE(session_id.empty());
       EXPECT_TRUE(enabled_component_updates);
@@ -3035,6 +3051,7 @@
                          const IdToComponentPtrMap& components,
                          const std::string& additional_attributes,
                          bool enabled_component_updates,
+                         bool is_foreground,
                          UpdateCheckCallback update_check_callback) override {
       /*
       Fake the following response:
@@ -3200,6 +3217,7 @@
                          const IdToComponentPtrMap& components,
                          const std::string& additional_attributes,
                          bool enabled_component_updates,
+                         bool is_foreground,
                          UpdateCheckCallback update_check_callback) override {
       /*
       Fake the following response:
diff --git a/components/update_client/update_engine.cc b/components/update_client/update_engine.cc
index b3b2a25..dadb453 100644
--- a/components/update_client/update_engine.cc
+++ b/components/update_client/update_engine.cc
@@ -161,7 +161,7 @@
   update_context->update_checker->CheckForUpdates(
       update_context->session_id, update_context->ids,
       update_context->components, config_->ExtraRequestParams(),
-      update_context->enabled_component_updates,
+      update_context->enabled_component_updates, update_context->is_foreground,
       base::BindOnce(&UpdateEngine::UpdateCheckDone, base::Unretained(this),
                      it));
 }
diff --git a/components/update_client/url_request_post_interceptor.cc b/components/update_client/url_request_post_interceptor.cc
index 53310d6..38102055 100644
--- a/components/update_client/url_request_post_interceptor.cc
+++ b/components/update_client/url_request_post_interceptor.cc
@@ -49,6 +49,7 @@
     mime_type->assign("text/plain");
     charset->assign("US-ASCII");
     data->assign(response_body_);
+
     return net::OK;
   }
 
@@ -119,21 +120,25 @@
   return static_cast<int>(requests_.size());
 }
 
-std::vector<std::string> URLRequestPostInterceptor::GetRequests() const {
+std::vector<URLRequestPostInterceptor::InterceptedRequest>
+URLRequestPostInterceptor::GetRequests() const {
   base::AutoLock auto_lock(interceptor_lock_);
   return requests_;
 }
 
+std::string URLRequestPostInterceptor::GetRequestBody(size_t n) const {
+  base::AutoLock auto_lock(interceptor_lock_);
+  return requests_[n].first;
+}
+
 std::string URLRequestPostInterceptor::GetRequestsAsString() const {
-  std::vector<std::string> requests(GetRequests());
+  const std::vector<InterceptedRequest> requests = GetRequests();
 
   std::string s = "Requests are:";
 
   int i = 0;
-  for (std::vector<std::string>::const_iterator it = requests.begin();
-       it != requests.end(); ++it) {
-    s.append(base::StringPrintf("\n  (%d): %s", ++i, it->c_str()));
-  }
+  for (auto it = requests.cbegin(); it != requests.cend(); ++it)
+    s.append(base::StringPrintf("\n  [%d]: %s", ++i, it->first.c_str()));
 
   return s;
 }
@@ -212,7 +217,8 @@
 
     {
       base::AutoLock auto_lock(interceptor->interceptor_lock_);
-      interceptor->requests_.push_back(request_body);
+      interceptor->requests_.push_back(
+          {request_body, request->extra_request_headers()});
       if (interceptor->expectations_.empty())
         return nullptr;
       const URLRequestPostInterceptor::Expectation& expectation(
diff --git a/components/update_client/url_request_post_interceptor.h b/components/update_client/url_request_post_interceptor.h
index eaae7775..be47caf 100644
--- a/components/update_client/url_request_post_interceptor.h
+++ b/components/update_client/url_request_post_interceptor.h
@@ -22,15 +22,20 @@
 class SequencedTaskRunner;
 }
 
+namespace net {
+class HttpRequestHeaders;
+}
+
 namespace update_client {
 
 // Intercepts requests to a file path, counts them, and captures the body of
 // the requests. Optionally, for each request, it can return a canned response
 // from a given file. The class maintains a queue of expectations, and returns
-// one and only one response for each request that matches and it is
-// intercepted.
+// one and only one response for each request that matches the expectation.
+// Then, the expectation is removed from the queue.
 class URLRequestPostInterceptor {
  public:
+  using InterceptedRequest = std::pair<std::string, net::HttpRequestHeaders>;
   // Allows a generic string maching interface when setting up expectations.
   class RequestMatcher {
    public:
@@ -61,9 +66,12 @@
   int GetCount() const;
 
   // Returns all requests that have been intercepted, matched or not.
-  std::vector<std::string> GetRequests() const;
+  std::vector<InterceptedRequest> GetRequests() const;
 
-  // Returns all requests as a string for debugging purposes.
+  // Return the body of the n-th request, zero-based.
+  std::string GetRequestBody(size_t n) const;
+
+  // Returns the joined bodies of all requests for debugging purposes.
   std::string GetRequestsAsString() const;
 
   // Resets the state of the interceptor so that new expectations can be set.
@@ -95,9 +103,16 @@
   scoped_refptr<base::SequencedTaskRunner> io_task_runner_;
 
   mutable base::Lock interceptor_lock_;
-  mutable int hit_count_;
-  mutable std::vector<std::string> requests_;
-  mutable base::queue<Expectation> expectations_;
+
+  // Contains the count of the request matching expectations.
+  int hit_count_;
+
+  // Contains the request body and the extra headers of the intercepted
+  // requests.
+  std::vector<InterceptedRequest> requests_;
+
+  // Contains the expectations which this interceptor tries to match.
+  base::queue<Expectation> expectations_;
 
   DISALLOW_COPY_AND_ASSIGN(URLRequestPostInterceptor);
 };
diff --git a/components/update_client/utils.cc b/components/update_client/utils.cc
index 4e7b8c6e..c644100 100644
--- a/components/update_client/utils.cc
+++ b/components/update_client/utils.cc
@@ -20,6 +20,7 @@
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/string_piece.h"
 #include "base/strings/string_util.h"
+#include "base/strings/stringprintf.h"
 #include "base/values.h"
 #include "components/crx_file/id_util.h"
 #include "components/data_use_measurement/core/data_use_user_data.h"
@@ -41,6 +42,7 @@
 std::unique_ptr<net::URLFetcher> SendProtocolRequest(
     const GURL& url,
     const std::string& protocol_request,
+    const base::Optional<bool> is_foreground,
     net::URLFetcherDelegate* url_fetcher_delegate,
     scoped_refptr<net::URLRequestContextGetter> url_request_context_getter) {
   net::NetworkTrafficAnnotationTag traffic_annotation =
@@ -84,8 +86,12 @@
                             net::LOAD_DO_NOT_SAVE_COOKIES |
                             net::LOAD_DISABLE_CACHE);
   url_fetcher->SetAutomaticallyRetryOn5xx(false);
-  url_fetcher->Start();
+  if (is_foreground.has_value()) {
+    url_fetcher->AddExtraRequestHeader(base::StringPrintf(
+        "X-GoogleUpdate-Interactivity: %s", *is_foreground ? "fg" : "bg"));
+  }
 
+  url_fetcher->Start();
   return url_fetcher;
 }
 
diff --git a/components/update_client/utils.h b/components/update_client/utils.h
index 8feb7ddf..a641825 100644
--- a/components/update_client/utils.h
+++ b/components/update_client/utils.h
@@ -12,6 +12,7 @@
 
 #include "base/callback_forward.h"
 #include "base/memory/ref_counted.h"
+#include "base/optional.h"
 #include "components/update_client/update_client.h"
 
 class GURL;
@@ -43,6 +44,7 @@
 std::unique_ptr<net::URLFetcher> SendProtocolRequest(
     const GURL& url,
     const std::string& protocol_request,
+    const base::Optional<bool> is_foreground,
     net::URLFetcherDelegate* url_fetcher_delegate,
     scoped_refptr<net::URLRequestContextGetter> url_request_context_getter);
 
diff --git a/components/url_formatter/idn_spoof_checker.cc b/components/url_formatter/idn_spoof_checker.cc
index 8838faa..15cac62 100644
--- a/components/url_formatter/idn_spoof_checker.cc
+++ b/components/url_formatter/idn_spoof_checker.cc
@@ -155,13 +155,13 @@
   // Supplement the Unicode confusable list by the following mapping.
   //   - {U+00FE (þ), U+03FC (ϼ), U+048F (ҏ)} => p
   //   - {U+0127 (ħ), U+043D (н), U+045B (ћ), U+04A3 (ң), U+04A5 (ҥ),
-  //      U+04C8 (ӈ), U+0527 (ԧ), U+0529 (ԩ)} => h
+  //      U+04C8 (ӈ), U+04CA (ӊ), U+0527 (ԧ), U+0529 (ԩ)} => h
   //   - {U+0138 (ĸ), U+03BA (κ), U+043A (к), U+049B (қ), U+049D (ҝ),
   //      U+049F (ҟ), U+04A1(ҡ), U+04C4 (ӄ), U+051F (ԟ)} => k
   //   - {U+014B (ŋ), U+043F (п)} => n
   //   - {U+0167 (ŧ), U+0442 (т), U+04AD (ҭ)} => t
   //   - {U+0185 (ƅ), U+044C (ь), U+048D (ҍ), U+0432 (в)} => b
-  //   - {U+03C9 (ω), U+0448 (ш), U+0449 (щ)} => w
+  //   - {U+03C9 (ω), U+0448 (ш), U+0449 (щ), U+0E1F (ฟ)} => w
   //   - {U+043C (м), U+04CE (ӎ)} => m
   //   - {U+0454 (є), U+04BD (ҽ), U+04BF (ҿ), U+1054 (ၔ)} => e
   //   - U+0491 (ґ) => r
@@ -172,13 +172,13 @@
   //   - U+04CF (ӏ) => i (on Windows), l (elsewhere)
   //   - U+0503 (ԃ) => d
   //   - {U+050D (ԍ), U+100c (ဌ)} => g
-  //   - U+0D1F (ട) => s
+  //   - {U+0D1F (ട), U+0E23 (ร)} => s
   //   - U+1042 (၂) => j
   extra_confusable_mapper_.reset(icu::Transliterator::createFromRules(
       UNICODE_STRING_SIMPLE("ExtraConf"),
-      icu::UnicodeString::fromUTF8("[þϼҏ] > p; [ħнћңҥӈԧԩ] > h;"
+      icu::UnicodeString::fromUTF8("[þϼҏ] > p; [ħнћңҥӈӊԧԩ] > h;"
                                    "[ĸκкқҝҟҡӄԟ] > k; [ŋп] > n; [ŧтҭ] > t;"
-                                   "[ƅьҍв] > b;  [ωшщ] > w; [мӎ] > m;"
+                                   "[ƅьҍв] > b;  [ωшщฟ] > w; [мӎ] > m;"
                                    "[єҽҿၔ] > e; ґ > r; ғ > f; [ҫင] > c;"
                                    "ұ > y; [χҳӽӿ] > x;"
 #if defined(OS_WIN)
@@ -186,7 +186,7 @@
 #else
                                    "ӏ > l;"
 #endif
-                                   "ԃ  > d; [ԍဌ] > g; ട > s; ၂ > j"),
+                                   "ԃ  > d; [ԍဌ] > g; [ടร] > s; ၂ > j"),
       UTRANS_FORWARD, parse_error, status));
   DCHECK(U_SUCCESS(status))
       << "Spoofchecker initalization failed due to an error: "
diff --git a/components/url_formatter/top_domains/test_domains.list b/components/url_formatter/top_domains/test_domains.list
index 051d37ce..5ce3b43 100644
--- a/components/url_formatter/top_domains/test_domains.list
+++ b/components/url_formatter/top_domains/test_domains.list
@@ -13,3 +13,4 @@
 ldg.com
 idg.com
 cegjo.com
+wsws.com
diff --git a/components/url_formatter/top_domains/test_skeletons.gperf b/components/url_formatter/top_domains/test_skeletons.gperf
index fa0ab30..dcda101 100644
--- a/components/url_formatter/top_domains/test_skeletons.gperf
+++ b/components/url_formatter/top_domains/test_skeletons.gperf
@@ -23,4 +23,5 @@
 ldg.corn, 1
 idg.corn, 1
 cegjo.corn, 1
+wsws.corn, 1
 %%
diff --git a/components/url_formatter/url_formatter_unittest.cc b/components/url_formatter/url_formatter_unittest.cc
index a22bc0d..a156347 100644
--- a/components/url_formatter/url_formatter_unittest.cc
+++ b/components/url_formatter/url_formatter_unittest.cc
@@ -478,6 +478,8 @@
     {"xn--m1a4ne5jry.com", L"\x048f\x043d\x051f\x04ad\x048d.com", false},
     // ҏнԟҭв.com
     {"xn--b1av9v8dry.com", L"\x048f\x043d\x051f\x04ad\x0432.com", false},
+    // ҏӊԟҭв.com
+    {"xn--b1a9p8c1e8r.com", L"\x048f\x04ca\x051f\x04ad\x0432.com", false},
     // wmŋr.com
     {"xn--wmr-jxa.com", L"wm\x014br.com", false},
     // шмпґ.com
@@ -504,6 +506,9 @@
     // ငၔဌ၂ဝ.com (entirely made of Myanmar characters)
     {"xn--ridq5c9hnd.com", L"\x1004\x1054\x100c" L"\x1042\x101d.com", false},
 
+    // ฟรฟร.com (made of two Thai characters)
+    {"xn--w3calb.com", L"\x0e1f\x0e23\x0e1f\x0e23.com", false},
+
     // At one point the skeleton of 'w' was 'vv', ensure that
     // that it's treated as 'w'.
     {"xn--wder-qqa.com",
diff --git a/components/user_manager/fake_user_manager.cc b/components/user_manager/fake_user_manager.cc
index 4e16a3d..fce3279b 100644
--- a/components/user_manager/fake_user_manager.cc
+++ b/components/user_manager/fake_user_manager.cc
@@ -5,6 +5,7 @@
 #include "components/user_manager/fake_user_manager.h"
 
 #include <algorithm>
+#include <utility>
 
 #include "base/callback.h"
 #include "base/command_line.h"
@@ -366,7 +367,7 @@
 
 void FakeUserManager::ScheduleResolveLocale(
     const std::string& locale,
-    const base::Closure& on_resolved_callback,
+    base::OnceClosure on_resolved_callback,
     std::string* out_resolved_locale) const {
   NOTIMPLEMENTED();
   return;
diff --git a/components/user_manager/fake_user_manager.h b/components/user_manager/fake_user_manager.h
index 249e092a..f355499 100644
--- a/components/user_manager/fake_user_manager.h
+++ b/components/user_manager/fake_user_manager.h
@@ -113,7 +113,7 @@
   const gfx::ImageSkia& GetResourceImagekiaNamed(int id) const override;
   base::string16 GetResourceStringUTF16(int string_id) const override;
   void ScheduleResolveLocale(const std::string& locale,
-                             const base::Closure& on_resolved_callback,
+                             base::OnceClosure on_resolved_callback,
                              std::string* out_resolved_locale) const override;
   bool IsValidDefaultUserImageId(int image_index) const override;
 
diff --git a/components/user_manager/user_manager.h b/components/user_manager/user_manager.h
index 149cfe9..4d68eea 100644
--- a/components/user_manager/user_manager.h
+++ b/components/user_manager/user_manager.h
@@ -392,7 +392,7 @@
   // |on_resolved_callback| as reply callback.
   virtual void ScheduleResolveLocale(
       const std::string& locale,
-      const base::Closure& on_resolved_callback,
+      base::OnceClosure on_resolved_callback,
       std::string* out_resolved_locale) const = 0;
 
   // Returns true if |image_index| is a valid default user image index.
diff --git a/components/user_manager/user_manager_base.cc b/components/user_manager/user_manager_base.cc
index e7b45451..67eda989 100644
--- a/components/user_manager/user_manager_base.cc
+++ b/components/user_manager/user_manager_base.cc
@@ -1117,14 +1117,15 @@
                                               const std::string& locale) {
   std::unique_ptr<std::string> resolved_locale(new std::string());
   if (!locale.empty() && locale != GetApplicationLocale()) {
-    // base::Passed will nullptr out |resolved_locale|, so cache the underlying
+    // std::move will nullptr out |resolved_locale|, so cache the underlying
     // ptr.
     std::string* raw_resolved_locale = resolved_locale.get();
-    ScheduleResolveLocale(locale,
-                          base::Bind(&UserManagerBase::DoUpdateAccountLocale,
-                                     weak_factory_.GetWeakPtr(), account_id,
-                                     base::Passed(&resolved_locale)),
-                          raw_resolved_locale);
+    ScheduleResolveLocale(
+        locale,
+        base::BindOnce(&UserManagerBase::DoUpdateAccountLocale,
+                       weak_factory_.GetWeakPtr(), account_id,
+                       std::move(resolved_locale)),
+        raw_resolved_locale);
   } else {
     resolved_locale.reset(new std::string(locale));
     DoUpdateAccountLocale(account_id, std::move(resolved_locale));
diff --git a/components/viz/common/features.cc b/components/viz/common/features.cc
index 7739c5f..76000c2 100644
--- a/components/viz/common/features.cc
+++ b/components/viz/common/features.cc
@@ -5,6 +5,7 @@
 #include "components/viz/common/features.h"
 
 #include "base/command_line.h"
+#include "build/build_config.h"
 #include "components/viz/common/switches.h"
 
 namespace features {
@@ -14,7 +15,7 @@
 const base::Feature kEnableDrawOcclusion{"DrawOcclusion",
                                          base::FEATURE_DISABLED_BY_DEFAULT};
 
-#if defined(USE_AURA)
+#if defined(USE_AURA) || defined(OS_MACOSX)
 const base::Feature kEnableSurfaceSynchronization{
     "SurfaceSynchronization", base::FEATURE_ENABLED_BY_DEFAULT};
 #else
diff --git a/components/viz/common/switches.cc b/components/viz/common/switches.cc
index 9c5b7774..f48c08fd 100644
--- a/components/viz/common/switches.cc
+++ b/components/viz/common/switches.cc
@@ -24,6 +24,11 @@
 // by the parent compositor.
 const char kEnableSurfaceSynchronization[] = "enable-surface-synchronization";
 
+// Effectively disables pipelining of compositor frame production stages by
+// waiting for each stage to finish before completing a frame.
+const char kRunAllCompositorStagesBeforeDraw[] =
+    "run-all-compositor-stages-before-draw";
+
 // Enables the viz hit-test logic (HitTestAggregator and HitTestQuery), with
 // hit-test data coming from draw quad.
 const char kUseVizHitTestDrawQuad[] = "use-viz-hit-test-draw-quad";
@@ -33,8 +38,13 @@
 const char kUseVizHitTestSurfaceLayer[] = "use-viz-hit-test-surface-layer";
 
 base::Optional<uint32_t> GetDeadlineToSynchronizeSurfaces() {
+  base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
+  if (command_line->HasSwitch(switches::kRunAllCompositorStagesBeforeDraw)) {
+    // In full-pipeline mode, surface deadlines should always be unlimited.
+    return base::nullopt;
+  }
   std::string deadline_to_synchronize_surfaces_string =
-      base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
+      command_line->GetSwitchValueASCII(
           switches::kDeadlineToSynchronizeSurfaces);
   if (deadline_to_synchronize_surfaces_string.empty())
     return kDefaultActivationDeadlineInFrames;
diff --git a/components/viz/common/switches.h b/components/viz/common/switches.h
index c3c9712..493cba9 100644
--- a/components/viz/common/switches.h
+++ b/components/viz/common/switches.h
@@ -16,6 +16,7 @@
 // Keep list in alphabetical order.
 VIZ_COMMON_EXPORT extern const char kDeadlineToSynchronizeSurfaces[];
 VIZ_COMMON_EXPORT extern const char kEnableSurfaceSynchronization[];
+VIZ_COMMON_EXPORT extern const char kRunAllCompositorStagesBeforeDraw[];
 VIZ_COMMON_EXPORT extern const char kUseVizHitTestDrawQuad[];
 VIZ_COMMON_EXPORT extern const char kUseVizHitTestSurfaceLayer[];
 
diff --git a/components/viz/host/server_gpu_memory_buffer_manager.cc b/components/viz/host/server_gpu_memory_buffer_manager.cc
index 3a045ac..630b3be0 100644
--- a/components/viz/host/server_gpu_memory_buffer_manager.cc
+++ b/components/viz/host/server_gpu_memory_buffer_manager.cc
@@ -4,6 +4,8 @@
 
 #include "components/viz/host/server_gpu_memory_buffer_manager.h"
 
+#include <utility>
+
 #include "base/logging.h"
 #include "base/strings/stringprintf.h"
 #include "base/threading/thread_task_runner_handle.h"
@@ -60,10 +62,11 @@
       pending_buffers_.insert(client_id);
       gpu_service_->CreateGpuMemoryBuffer(
           id, size, format, usage, client_id, surface_handle,
-          base::Bind(&ServerGpuMemoryBufferManager::OnGpuMemoryBufferAllocated,
-                     weak_ptr_, client_id,
-                     gfx::BufferSizeForBufferFormat(size, format),
-                     base::Passed(std::move(callback))));
+          base::BindOnce(
+              &ServerGpuMemoryBufferManager::OnGpuMemoryBufferAllocated,
+              weak_ptr_, client_id,
+              gfx::BufferSizeForBufferFormat(size, format),
+              std::move(callback)));
       return;
     }
   }
diff --git a/components/viz/host/server_gpu_memory_buffer_manager_unittest.cc b/components/viz/host/server_gpu_memory_buffer_manager_unittest.cc
index 6b65636a..abfa158 100644
--- a/components/viz/host/server_gpu_memory_buffer_manager_unittest.cc
+++ b/components/viz/host/server_gpu_memory_buffer_manager_unittest.cc
@@ -4,6 +4,8 @@
 
 #include "components/viz/host/server_gpu_memory_buffer_manager.h"
 
+#include <utility>
+
 #include "base/run_loop.h"
 #include "base/threading/thread.h"
 #include "build/build_config.h"
@@ -314,8 +316,9 @@
   base::Thread diff_thread("DestroyThread");
   ASSERT_TRUE(diff_thread.Start());
   diff_thread.task_runner()->PostTask(
-      FROM_HERE, base::Bind([](std::unique_ptr<gfx::GpuMemoryBuffer> buffer) {},
-                            base::Passed(&buffer)));
+      FROM_HERE,
+      base::BindOnce([](std::unique_ptr<gfx::GpuMemoryBuffer> buffer) {},
+                     std::move(buffer)));
   diff_thread.Stop();
 }
 
diff --git a/components/viz/service/display/gl_renderer_copier.cc b/components/viz/service/display/gl_renderer_copier.cc
index 54153f3..a22b947 100644
--- a/components/viz/service/display/gl_renderer_copier.cc
+++ b/components/viz/service/display/gl_renderer_copier.cc
@@ -6,6 +6,7 @@
 
 #include <algorithm>
 #include <cstring>
+#include <utility>
 
 #include "base/bind.h"
 #include "base/bind_helpers.h"
@@ -426,7 +427,7 @@
       GetOptimalReadbackFormat());
   const GLuint query = workflow->query();
   context_provider_->ContextSupport()->SignalQuery(
-      query, base::Bind(&ReadPixelsWorkflow::Finish, base::Passed(&workflow)));
+      query, base::BindOnce(&ReadPixelsWorkflow::Finish, std::move(workflow)));
 }
 
 void GLRendererCopier::SendTextureResult(
diff --git a/components/viz/service/display/texture_deleter.cc b/components/viz/service/display/texture_deleter.cc
index e24b61b..32416c4 100644
--- a/components/viz/service/display/texture_deleter.cc
+++ b/components/viz/service/display/texture_deleter.cc
@@ -5,6 +5,7 @@
 #include "components/viz/service/display/texture_deleter.h"
 
 #include <stddef.h>
+#include <utility>
 
 #include "base/bind.h"
 #include "base/location.h"
@@ -72,8 +73,8 @@
   std::unique_ptr<SingleReleaseCallback> main_callback;
   if (impl_task_runner_) {
     main_callback = SingleReleaseCallback::Create(
-        base::Bind(&PostTaskFromMainToImplThread, impl_task_runner_,
-                   base::Passed(&run_impl_callback)));
+        base::BindOnce(&PostTaskFromMainToImplThread, impl_task_runner_,
+                       std::move(run_impl_callback)));
   } else {
     main_callback = SingleReleaseCallback::Create(std::move(run_impl_callback));
   }
diff --git a/components/viz/service/frame_sinks/video_capture/frame_sink_video_capturer_impl_unittest.cc b/components/viz/service/frame_sinks/video_capture/frame_sink_video_capturer_impl_unittest.cc
index 4ece515..c3443125 100644
--- a/components/viz/service/frame_sinks/video_capture/frame_sink_video_capturer_impl_unittest.cc
+++ b/components/viz/service/frame_sinks/video_capture/frame_sink_video_capturer_impl_unittest.cc
@@ -4,6 +4,8 @@
 
 #include "components/viz/service/frame_sinks/video_capture/frame_sink_video_capturer_impl.h"
 
+#include <utility>
+
 #include "base/bind.h"
 #include "base/callback.h"
 #include "base/optional.h"
@@ -134,7 +136,7 @@
     frames_.push_back(std::move(frame));
     done_callbacks_.push_back(
         base::BindOnce(&mojom::FrameSinkVideoConsumerFrameCallbacks::Done,
-                       base::Passed(&callbacks)));
+                       std::move(callbacks)));
   }
 
   mojo::Binding<mojom::FrameSinkVideoConsumer> binding_;
@@ -210,7 +212,7 @@
            std::unique_ptr<CopyOutputResult> result) {
           request->SendResult(std::move(result));
         },
-        base::Passed(&request), base::Passed(&result)));
+        std::move(request), std::move(result)));
   }
 
   void SetCopyOutputColor(YUVColor color) { color_ = color; }
diff --git a/components/viz/service/gl/gpu_service_impl.cc b/components/viz/service/gl/gpu_service_impl.cc
index b169325..76b472f6 100644
--- a/components/viz/service/gl/gpu_service_impl.cc
+++ b/components/viz/service/gl/gpu_service_impl.cc
@@ -5,6 +5,7 @@
 #include "components/viz/service/gl/gpu_service_impl.h"
 
 #include <memory>
+#include <utility>
 
 #include "base/bind.h"
 #include "base/command_line.h"
@@ -221,8 +222,8 @@
   if (main_runner_->BelongsToCurrentThread()) {
     bind_task_tracker_.PostTask(
         io_runner_.get(), FROM_HERE,
-        base::Bind(&GpuServiceImpl::Bind, base::Unretained(this),
-                   base::Passed(std::move(request))));
+        base::BindOnce(&GpuServiceImpl::Bind, base::Unretained(this),
+                       std::move(request)));
     return;
   }
   bindings_->AddBinding(this, std::move(request));
diff --git a/components/viz/service/main/viz_main_impl.cc b/components/viz/service/main/viz_main_impl.cc
index 3fee8988f..d06345c 100644
--- a/components/viz/service/main/viz_main_impl.cc
+++ b/components/viz/service/main/viz_main_impl.cc
@@ -5,6 +5,7 @@
 #include "components/viz/service/main/viz_main_impl.h"
 
 #include <memory>
+#include <utility>
 
 #include "base/command_line.h"
 #include "base/message_loop/message_loop.h"
@@ -253,8 +254,8 @@
 
   compositor_thread_task_runner_->PostTask(
       FROM_HERE,
-      base::Bind(&VizMainImpl::CreateFrameSinkManagerOnCompositorThread,
-                 base::Unretained(this), base::Passed(&params)));
+      base::BindOnce(&VizMainImpl::CreateFrameSinkManagerOnCompositorThread,
+                     base::Unretained(this), std::move(params)));
 }
 
 void VizMainImpl::CreateFrameSinkManagerOnCompositorThread(
diff --git a/components/webcrypto/webcrypto_impl.cc b/components/webcrypto/webcrypto_impl.cc
index a96aeb3..bdda3a7 100644
--- a/components/webcrypto/webcrypto_impl.cc
+++ b/components/webcrypto/webcrypto_impl.cc
@@ -8,6 +8,7 @@
 #include <stdint.h>
 
 #include <memory>
+#include <utility>
 
 #include "base/bind.h"
 #include "base/lazy_instance.h"
@@ -78,8 +79,7 @@
     worker_thread_.StartWithOptions(options);
   }
 
-  static bool PostTask(const base::Location& from_here,
-                       const base::Closure& task);
+  static bool PostTask(const base::Location& from_here, base::OnceClosure task);
 
  private:
   // TODO(gab): the pool is currently using a single non-joinable thread to
@@ -96,9 +96,9 @@
     LAZY_INSTANCE_INITIALIZER;
 
 bool CryptoThreadPool::PostTask(const base::Location& from_here,
-                                const base::Closure& task) {
+                                base::OnceClosure task) {
   return crypto_thread_pool.Get().worker_thread_.task_runner()->PostTask(
-      from_here, task);
+      from_here, std::move(task));
 }
 
 void CompleteWithThreadPoolError(blink::WebCryptoResult* result) {
@@ -393,7 +393,7 @@
       webcrypto::Encrypt(state->algorithm, state->key,
                          webcrypto::CryptoData(state->data), &state->buffer);
   state->origin_thread->PostTask(
-      FROM_HERE, base::Bind(DoEncryptReply, base::Passed(&passed_state)));
+      FROM_HERE, base::BindOnce(DoEncryptReply, std::move(passed_state)));
 }
 
 void DoDecryptReply(std::unique_ptr<DecryptState> state) {
@@ -411,7 +411,7 @@
       webcrypto::Decrypt(state->algorithm, state->key,
                          webcrypto::CryptoData(state->data), &state->buffer);
   state->origin_thread->PostTask(
-      FROM_HERE, base::Bind(DoDecryptReply, base::Passed(&passed_state)));
+      FROM_HERE, base::BindOnce(DoDecryptReply, std::move(passed_state)));
 }
 
 void DoDigestReply(std::unique_ptr<DigestState> state) {
@@ -427,7 +427,7 @@
   state->status = webcrypto::Digest(
       state->algorithm, webcrypto::CryptoData(state->data), &state->buffer);
   state->origin_thread->PostTask(
-      FROM_HERE, base::Bind(DoDigestReply, base::Passed(&passed_state)));
+      FROM_HERE, base::BindOnce(DoDigestReply, std::move(passed_state)));
 }
 
 void DoGenerateKeyReply(std::unique_ptr<GenerateKeyState> state) {
@@ -449,7 +449,7 @@
       webcrypto::GenerateKey(state->algorithm, state->extractable,
                              state->usages, &state->generate_key_result);
   state->origin_thread->PostTask(
-      FROM_HERE, base::Bind(DoGenerateKeyReply, base::Passed(&passed_state)));
+      FROM_HERE, base::BindOnce(DoGenerateKeyReply, std::move(passed_state)));
 }
 
 void DoImportKeyReply(std::unique_ptr<ImportKeyState> state) {
@@ -473,7 +473,7 @@
   }
 
   state->origin_thread->PostTask(
-      FROM_HERE, base::Bind(DoImportKeyReply, base::Passed(&passed_state)));
+      FROM_HERE, base::BindOnce(DoImportKeyReply, std::move(passed_state)));
 }
 
 void DoExportKeyReply(std::unique_ptr<ExportKeyState> state) {
@@ -501,7 +501,7 @@
   state->status =
       webcrypto::ExportKey(state->format, state->key, &state->buffer);
   state->origin_thread->PostTask(
-      FROM_HERE, base::Bind(DoExportKeyReply, base::Passed(&passed_state)));
+      FROM_HERE, base::BindOnce(DoExportKeyReply, std::move(passed_state)));
 }
 
 void DoSignReply(std::unique_ptr<SignState> state) {
@@ -519,7 +519,7 @@
                       webcrypto::CryptoData(state->data), &state->buffer);
 
   state->origin_thread->PostTask(
-      FROM_HERE, base::Bind(DoSignReply, base::Passed(&passed_state)));
+      FROM_HERE, base::BindOnce(DoSignReply, std::move(passed_state)));
 }
 
 void DoVerifyReply(std::unique_ptr<VerifySignatureState> state) {
@@ -541,7 +541,7 @@
       webcrypto::CryptoData(state->data), &state->verify_result);
 
   state->origin_thread->PostTask(
-      FROM_HERE, base::Bind(DoVerifyReply, base::Passed(&passed_state)));
+      FROM_HERE, base::BindOnce(DoVerifyReply, std::move(passed_state)));
 }
 
 void DoWrapKeyReply(std::unique_ptr<WrapKeyState> state) {
@@ -560,7 +560,7 @@
                          state->wrap_algorithm, &state->buffer);
 
   state->origin_thread->PostTask(
-      FROM_HERE, base::Bind(DoWrapKeyReply, base::Passed(&passed_state)));
+      FROM_HERE, base::BindOnce(DoWrapKeyReply, std::move(passed_state)));
 }
 
 void DoUnwrapKeyReply(std::unique_ptr<UnwrapKeyState> state) {
@@ -581,7 +581,7 @@
       &state->unwrapped_key);
 
   state->origin_thread->PostTask(
-      FROM_HERE, base::Bind(DoUnwrapKeyReply, base::Passed(&passed_state)));
+      FROM_HERE, base::BindOnce(DoUnwrapKeyReply, std::move(passed_state)));
 }
 
 void DoDeriveBitsReply(std::unique_ptr<DeriveBitsState> state) {
@@ -600,7 +600,7 @@
       webcrypto::DeriveBits(state->algorithm, state->base_key,
                             state->length_bits, &state->derived_bytes);
   state->origin_thread->PostTask(
-      FROM_HERE, base::Bind(DoDeriveBitsReply, base::Passed(&passed_state)));
+      FROM_HERE, base::BindOnce(DoDeriveBitsReply, std::move(passed_state)));
 }
 
 void DoDeriveKeyReply(std::unique_ptr<DeriveKeyState> state) {
@@ -619,7 +619,7 @@
       state->key_length_algorithm, state->extractable, state->usages,
       &state->derived_key);
   state->origin_thread->PostTask(
-      FROM_HERE, base::Bind(DoDeriveKeyReply, base::Passed(&passed_state)));
+      FROM_HERE, base::BindOnce(DoDeriveKeyReply, std::move(passed_state)));
 }
 
 }  // namespace
@@ -641,7 +641,7 @@
   std::unique_ptr<EncryptState> state(new EncryptState(
       algorithm, key, std::move(data), result, std::move(task_runner)));
   if (!CryptoThreadPool::PostTask(
-          FROM_HERE, base::Bind(DoEncrypt, base::Passed(&state)))) {
+          FROM_HERE, base::BindOnce(DoEncrypt, std::move(state)))) {
     CompleteWithThreadPoolError(&result);
   }
 }
@@ -657,7 +657,7 @@
   std::unique_ptr<DecryptState> state(new DecryptState(
       algorithm, key, std::move(data), result, std::move(task_runner)));
   if (!CryptoThreadPool::PostTask(
-          FROM_HERE, base::Bind(DoDecrypt, base::Passed(&state)))) {
+          FROM_HERE, base::BindOnce(DoDecrypt, std::move(state)))) {
     CompleteWithThreadPoolError(&result);
   }
 }
@@ -673,7 +673,7 @@
       new DigestState(algorithm, blink::WebCryptoKey::CreateNull(),
                       std::move(data), result, std::move(task_runner)));
   if (!CryptoThreadPool::PostTask(FROM_HERE,
-                                  base::Bind(DoDigest, base::Passed(&state)))) {
+                                  base::BindOnce(DoDigest, std::move(state)))) {
     CompleteWithThreadPoolError(&result);
   }
 }
@@ -689,7 +689,7 @@
   std::unique_ptr<GenerateKeyState> state(new GenerateKeyState(
       algorithm, extractable, usages, result, std::move(task_runner)));
   if (!CryptoThreadPool::PostTask(
-          FROM_HERE, base::Bind(DoGenerateKey, base::Passed(&state)))) {
+          FROM_HERE, base::BindOnce(DoGenerateKey, std::move(state)))) {
     CompleteWithThreadPoolError(&result);
   }
 }
@@ -706,7 +706,7 @@
       new ImportKeyState(format, std::move(key_data), algorithm, extractable,
                          usages, result, std::move(task_runner)));
   if (!CryptoThreadPool::PostTask(
-          FROM_HERE, base::Bind(DoImportKey, base::Passed(&state)))) {
+          FROM_HERE, base::BindOnce(DoImportKey, std::move(state)))) {
     CompleteWithThreadPoolError(&result);
   }
 }
@@ -719,7 +719,7 @@
   std::unique_ptr<ExportKeyState> state(
       new ExportKeyState(format, key, result, std::move(task_runner)));
   if (!CryptoThreadPool::PostTask(
-          FROM_HERE, base::Bind(DoExportKey, base::Passed(&state)))) {
+          FROM_HERE, base::BindOnce(DoExportKey, std::move(state)))) {
     CompleteWithThreadPoolError(&result);
   }
 }
@@ -733,7 +733,7 @@
   std::unique_ptr<SignState> state(new SignState(
       algorithm, key, std::move(data), result, std::move(task_runner)));
   if (!CryptoThreadPool::PostTask(FROM_HERE,
-                                  base::Bind(DoSign, base::Passed(&state)))) {
+                                  base::BindOnce(DoSign, std::move(state)))) {
     CompleteWithThreadPoolError(&result);
   }
 }
@@ -749,7 +749,7 @@
       algorithm, key, std::move(signature), std::move(data), result,
       std::move(task_runner)));
   if (!CryptoThreadPool::PostTask(FROM_HERE,
-                                  base::Bind(DoVerify, base::Passed(&state)))) {
+                                  base::BindOnce(DoVerify, std::move(state)))) {
     CompleteWithThreadPoolError(&result);
   }
 }
@@ -765,7 +765,7 @@
       new WrapKeyState(format, key, wrapping_key, wrap_algorithm, result,
                        std::move(task_runner)));
   if (!CryptoThreadPool::PostTask(
-          FROM_HERE, base::Bind(DoWrapKey, base::Passed(&state)))) {
+          FROM_HERE, base::BindOnce(DoWrapKey, std::move(state)))) {
     CompleteWithThreadPoolError(&result);
   }
 }
@@ -785,7 +785,7 @@
                          unwrap_algorithm, unwrapped_key_algorithm, extractable,
                          usages, result, std::move(task_runner)));
   if (!CryptoThreadPool::PostTask(
-          FROM_HERE, base::Bind(DoUnwrapKey, base::Passed(&state)))) {
+          FROM_HERE, base::BindOnce(DoUnwrapKey, std::move(state)))) {
     CompleteWithThreadPoolError(&result);
   }
 }
@@ -799,7 +799,7 @@
   std::unique_ptr<DeriveBitsState> state(new DeriveBitsState(
       algorithm, base_key, length_bits, result, std::move(task_runner)));
   if (!CryptoThreadPool::PostTask(
-          FROM_HERE, base::Bind(DoDeriveBits, base::Passed(&state)))) {
+          FROM_HERE, base::BindOnce(DoDeriveBits, std::move(state)))) {
     CompleteWithThreadPoolError(&result);
   }
 }
@@ -817,7 +817,7 @@
       algorithm, base_key, import_algorithm, key_length_algorithm, extractable,
       usages, result, std::move(task_runner)));
   if (!CryptoThreadPool::PostTask(
-          FROM_HERE, base::Bind(DoDeriveKey, base::Passed(&state)))) {
+          FROM_HERE, base::BindOnce(DoDeriveKey, std::move(state)))) {
     CompleteWithThreadPoolError(&result);
   }
 }
diff --git a/components/webdata/common/web_data_request_manager.cc b/components/webdata/common/web_data_request_manager.cc
index 991ff741..5c74f244 100644
--- a/components/webdata/common/web_data_request_manager.cc
+++ b/components/webdata/common/web_data_request_manager.cc
@@ -105,9 +105,8 @@
   // effectively does a std::move() on |request|!
   scoped_refptr<base::SequencedTaskRunner> task_runner =
       request->GetTaskRunner();
-  auto task =
-      base::BindOnce(&WebDataRequestManager::RequestCompletedOnThread, this,
-                     base::Passed(&request), base::Passed(&result));
+  auto task = base::BindOnce(&WebDataRequestManager::RequestCompletedOnThread,
+                             this, std::move(request), std::move(result));
   if (task_runner)
     task_runner->PostTask(FROM_HERE, std::move(task));
   else
diff --git a/components/webdata/common/web_database_service.cc b/components/webdata/common/web_database_service.cc
index 052a3ad0..c7f41fe5 100644
--- a/components/webdata/common/web_database_service.cc
+++ b/components/webdata/common/web_database_service.cc
@@ -95,8 +95,8 @@
   std::unique_ptr<WebDataRequest> request =
       web_db_backend_->request_manager()->NewRequest(nullptr);
   db_task_runner_->PostTask(
-      from_here, Bind(&WebDatabaseBackend::DBWriteTaskWrapper, web_db_backend_,
-                      task, base::Passed(&request)));
+      from_here, BindOnce(&WebDatabaseBackend::DBWriteTaskWrapper,
+                          web_db_backend_, task, std::move(request)));
 }
 
 WebDataServiceBase::Handle WebDatabaseService::ScheduleDBTaskWithResult(
@@ -109,8 +109,8 @@
       web_db_backend_->request_manager()->NewRequest(consumer);
   WebDataServiceBase::Handle handle = request->GetHandle();
   db_task_runner_->PostTask(
-      from_here, Bind(&WebDatabaseBackend::DBReadTaskWrapper, web_db_backend_,
-                      task, base::Passed(&request)));
+      from_here, BindOnce(&WebDatabaseBackend::DBReadTaskWrapper,
+                          web_db_backend_, task, std::move(request)));
   return handle;
 }
 
diff --git a/content/browser/BUILD.gn b/content/browser/BUILD.gn
index 851218af..55ae5ac 100644
--- a/content/browser/BUILD.gn
+++ b/content/browser/BUILD.gn
@@ -1166,8 +1166,6 @@
     "net/quota_policy_cookie_store.h",
     "net/view_blob_internals_job_factory.cc",
     "net/view_blob_internals_job_factory.h",
-    "net/view_http_cache_job_factory.cc",
-    "net/view_http_cache_job_factory.h",
     "network_service_client.cc",
     "network_service_client.h",
     "network_service_instance.cc",
@@ -1701,6 +1699,8 @@
     "web_package/signed_exchange_url_loader_factory_for_non_network_service.h",
     "web_package/web_package_loader.cc",
     "web_package/web_package_loader.h",
+    "web_package/web_package_prefetch_handler.cc",
+    "web_package/web_package_prefetch_handler.h",
     "web_package/web_package_request_handler.cc",
     "web_package/web_package_request_handler.h",
     "websockets/websocket_handshake_request_info_impl.cc",
diff --git a/content/browser/browser_child_process_host_impl.cc b/content/browser/browser_child_process_host_impl.cc
index 0166bd5c..589568ba 100644
--- a/content/browser/browser_child_process_host_impl.cc
+++ b/content/browser/browser_child_process_host_impl.cc
@@ -387,10 +387,6 @@
   child_process_->GetProcess().Terminate(RESULT_CODE_KILLED_BAD_MESSAGE, false);
 }
 
-bool BrowserChildProcessHostImpl::CanShutdown() {
-  return delegate_->CanShutdown();
-}
-
 void BrowserChildProcessHostImpl::OnChannelInitialized(IPC::Channel* channel) {
   channel_ = channel;
 }
diff --git a/content/browser/browser_child_process_host_impl.h b/content/browser/browser_child_process_host_impl.h
index 7d23f16..76923f92 100644
--- a/content/browser/browser_child_process_host_impl.h
+++ b/content/browser/browser_child_process_host_impl.h
@@ -80,7 +80,6 @@
   service_manager::mojom::ServiceRequest TakeInProcessServiceRequest() override;
 
   // ChildProcessHostDelegate implementation:
-  bool CanShutdown() override;
   void OnChannelInitialized(IPC::Channel* channel) override;
   void OnChildDisconnected() override;
   const base::Process& GetProcess() const override;
diff --git a/content/browser/compositor/gpu_process_transport_factory.cc b/content/browser/compositor/gpu_process_transport_factory.cc
index 0c9a292..e798e61c 100644
--- a/content/browser/compositor/gpu_process_transport_factory.cc
+++ b/content/browser/compositor/gpu_process_transport_factory.cc
@@ -18,7 +18,6 @@
 #include "base/threading/thread_task_runner_handle.h"
 #include "build/build_config.h"
 #include "cc/base/histograms.h"
-#include "cc/base/switches.h"
 #include "cc/raster/single_thread_task_graph_runner.h"
 #include "cc/raster/task_graph_runner.h"
 #include "components/viz/common/features.h"
@@ -27,6 +26,7 @@
 #include "components/viz/common/frame_sinks/delay_based_time_source.h"
 #include "components/viz/common/gl_helper.h"
 #include "components/viz/common/gpu/vulkan_in_process_context_provider.h"
+#include "components/viz/common/switches.h"
 #include "components/viz/host/host_frame_sink_manager.h"
 #include "components/viz/host/renderer_settings_creation.h"
 #include "components/viz/service/display/display.h"
@@ -197,7 +197,7 @@
     }
   }
 
-  if (command_line->HasSwitch(cc::switches::kRunAllCompositorStagesBeforeDraw))
+  if (command_line->HasSwitch(switches::kRunAllCompositorStagesBeforeDraw))
     wait_for_all_pipeline_stages_before_draw_ = true;
 
   task_graph_runner_->Start("CompositorTileWorker1",
diff --git a/content/browser/compositor/viz_process_transport_factory.cc b/content/browser/compositor/viz_process_transport_factory.cc
index 399beea..d92cac2 100644
--- a/content/browser/compositor/viz_process_transport_factory.cc
+++ b/content/browser/compositor/viz_process_transport_factory.cc
@@ -148,8 +148,15 @@
       [](viz::mojom::FrameSinkManagerRequest request,
          viz::mojom::FrameSinkManagerClientPtrInfo client,
          viz::mojom::CompositingModeWatcherPtrInfo mode_watcher) {
-        GpuProcessHost::Get()->ConnectFrameSinkManager(
-            std::move(request), std::move(client), std::move(mode_watcher));
+        // There should always be a GpuProcessHost instance, and GPU process,
+        // for running the compositor thread. The exception is during shutdown
+        // the GPU process won't be restarted and GpuProcessHost::Get() can
+        // return null.
+        auto* gpu_process_host = GpuProcessHost::Get();
+        if (gpu_process_host) {
+          gpu_process_host->ConnectFrameSinkManager(
+              std::move(request), std::move(client), std::move(mode_watcher));
+        }
       };
   BrowserThread::PostTask(
       BrowserThread::IO, FROM_HERE,
diff --git a/content/browser/download/download_browsertest.cc b/content/browser/download/download_browsertest.cc
index 782ad18..ff72f41 100644
--- a/content/browser/download/download_browsertest.cc
+++ b/content/browser/download/download_browsertest.cc
@@ -3160,7 +3160,15 @@
 // Verifies that if the last slice is finished, but the database record is not
 // finished, which may happen in database migration.
 // When the server sends HTTP range not satisfied, the download can complete.
-IN_PROC_BROWSER_TEST_F(ParallelDownloadTest, ResumptionLastSliceUnfinished) {
+#if defined(OS_WIN)
+// Failing on windows: https://crbug.com/814310
+#define MAYBE_ResumptionLastSliceUnfinished \
+  DISABLED_ResumptionLastSliceUnfinished
+#else
+#define MAYBE_ResumptionLastSliceUnfinished ResumptionLastSliceUnfinished
+#endif
+IN_PROC_BROWSER_TEST_F(ParallelDownloadTest,
+                       MAYBE_ResumptionLastSliceUnfinished) {
   // Create the received slices data, last slice is actually finished.
   std::vector<download::DownloadItem::ReceivedSlice> received_slices = {
       download::DownloadItem::ReceivedSlice(0, 1000),
diff --git a/content/browser/loader/mime_sniffing_resource_handler.cc b/content/browser/loader/mime_sniffing_resource_handler.cc
index b0ea07f31..cbc2afd1 100644
--- a/content/browser/loader/mime_sniffing_resource_handler.cc
+++ b/content/browser/loader/mime_sniffing_resource_handler.cc
@@ -117,6 +117,7 @@
       must_download_is_set_(false),
       read_buffer_size_(0),
       bytes_read_(0),
+      need_to_replay_extra_eof_packet_(false),
       parent_read_buffer_(nullptr),
       parent_read_buffer_size_(nullptr),
       intercepting_handler_(intercepting_handler),
@@ -246,6 +247,12 @@
     return;
   }
 
+  // After getting a 0-sized, eof-indicating packet when buffering, the packet
+  // (i.e. the OnReadCompleted(0) call) needs to be replayed against the
+  // downstream handler (unless replaying the buffered data will act as one if
+  // |bytes_read_ == 0| - the first part of the condition below).
+  need_to_replay_extra_eof_packet_ = (bytes_read_ != 0) && (bytes_read == 0);
+
   HoldController(std::move(controller));
   AdvanceState();
 }
@@ -309,6 +316,12 @@
       case STATE_REPLAYING_RESPONSE_RECEIVED:
         ReplayReadCompleted();
         break;
+      case STATE_REPLAYING_EOF_WILL_READ:
+        ReplayWillReadEof();
+        break;
+      case STATE_REPLAYING_EOF_READ_COMPLETED:
+        ReplayReadCompletedEof();
+        break;
       case STATE_STARTING:
       case STATE_STREAMING:
         Resume();
@@ -370,7 +383,10 @@
 void MimeSniffingResourceHandler::ReplayReadCompleted() {
   DCHECK_EQ(STATE_REPLAYING_RESPONSE_RECEIVED, state_);
 
-  state_ = STATE_STREAMING;
+  if (need_to_replay_extra_eof_packet_)
+    state_ = STATE_REPLAYING_EOF_WILL_READ;
+  else
+    state_ = STATE_STREAMING;
 
   if (!read_buffer_.get()) {
     ResumeInternal();
@@ -387,6 +403,27 @@
                                  std::make_unique<Controller>(this));
 }
 
+void MimeSniffingResourceHandler::ReplayWillReadEof() {
+  DCHECK_EQ(STATE_REPLAYING_EOF_WILL_READ, state_);
+
+  state_ = STATE_REPLAYING_EOF_READ_COMPLETED;
+  DCHECK(!read_buffer_);
+  DCHECK_EQ(0, read_buffer_size_);
+  DCHECK_EQ(0, bytes_read_);
+  next_handler_->OnWillRead(&read_buffer_, &read_buffer_size_,
+                            std::make_unique<Controller>(this));
+}
+
+void MimeSniffingResourceHandler::ReplayReadCompletedEof() {
+  DCHECK_EQ(STATE_REPLAYING_EOF_READ_COMPLETED, state_);
+
+  state_ = STATE_STREAMING;
+  read_buffer_ = nullptr;
+  read_buffer_size_ = 0;
+  bytes_read_ = 0;
+  next_handler_->OnReadCompleted(0, std::make_unique<Controller>(this));
+}
+
 bool MimeSniffingResourceHandler::MaybeStartInterception() {
   if (!CanBeIntercepted())
     return true;
diff --git a/content/browser/loader/mime_sniffing_resource_handler.h b/content/browser/loader/mime_sniffing_resource_handler.h
index 5c3c8e2..807f77e 100644
--- a/content/browser/loader/mime_sniffing_resource_handler.h
+++ b/content/browser/loader/mime_sniffing_resource_handler.h
@@ -81,6 +81,12 @@
     // OnResponseStarted event to the downstream ResourceHandlers.
     STATE_REPLAYING_RESPONSE_RECEIVED,
 
+    // In these states, the MimeSniffingResourceHandler is replaying the pair of
+    // OnWillRead + OnReadCompleted(0) calls that indicates end of the response
+    // body.  See also |need_to_replay_extra_eof_packet_|.
+    STATE_REPLAYING_EOF_WILL_READ,
+    STATE_REPLAYING_EOF_READ_COMPLETED,
+
     // In this state, the MimeSniffingResourceHandler is just a blind
     // pass-through
     // ResourceHandler.
@@ -128,6 +134,13 @@
   // Replays OnReadCompleted on the downstreams handlers.
   void ReplayReadCompleted();
 
+  // Replays OnWillRead if needed to notify the downstream handler about EOF.
+  void ReplayWillReadEof();
+
+  // Replays OnReadCompleted(0) if needed to notify the downstream handler about
+  // EOF.
+  void ReplayReadCompletedEof();
+
   // --------------------------------------------------------------------------
 
   // Checks whether this request should be intercepted as a stream or a
@@ -174,6 +187,7 @@
   scoped_refptr<net::IOBuffer> read_buffer_;
   int read_buffer_size_;
   int bytes_read_;
+  bool need_to_replay_extra_eof_packet_;
 
   // Pointers to parent-owned read buffer and its size.  Only used for first
   // OnWillRead call.
diff --git a/content/browser/loader/mime_sniffing_resource_handler_unittest.cc b/content/browser/loader/mime_sniffing_resource_handler_unittest.cc
index 735f945..4ee8298 100644
--- a/content/browser/loader/mime_sniffing_resource_handler_unittest.cc
+++ b/content/browser/loader/mime_sniffing_resource_handler_unittest.cc
@@ -928,4 +928,160 @@
   content::RunAllPendingInMessageLoop();
 }
 
+// The test verifies that MimeSniffingResourceHandler can properly handle a
+// non-empty network response that ends before it is able to determine the mime
+// type.  In particular, when replaying the buffered payload after reaching EOF,
+// we need to make sure that the downstream handler receives *two*
+// OnReadCompleted calls (one with the buffered payload and one indicating EOF)
+// - this is verified by test assertions in
+// TestResourceHandler::OnResponseCompleted that require
+// EXPECT_EQ(1, on_read_eof_called_);
+TEST_F(MimeSniffingResourceHandlerTest, NonEmptyPayloadEndsBeforeDecision) {
+  net::URLRequestContext context;
+  std::unique_ptr<net::URLRequest> request(context.CreateRequest(
+      GURL("http://www.google.com"), net::DEFAULT_PRIORITY, nullptr,
+      TRAFFIC_ANNOTATION_FOR_TESTS));
+  ResourceRequestInfo::AllocateForTesting(request.get(), RESOURCE_TYPE_SCRIPT,
+                                          nullptr,       // context
+                                          0,             // render_process_id
+                                          0,             // render_view_id
+                                          0,             // render_frame_id
+                                          false,         // is_main_frame
+                                          false,         // allow_download
+                                          true,          // is_async
+                                          PREVIEWS_OFF,  // previews_state
+                                          nullptr);      // navigation_ui_data
+
+  TestResourceDispatcherHost host(false);
+
+  TestFakePluginService plugin_service(false, false);
+  std::unique_ptr<InterceptingResourceHandler> intercepting_handler(
+      new InterceptingResourceHandler(std::make_unique<TestResourceHandler>(),
+                                      nullptr));
+
+  std::unique_ptr<TestResourceHandler> scoped_test_handler(
+      new TestResourceHandler());
+  TestResourceHandler* test_handler = scoped_test_handler.get();
+  MimeSniffingResourceHandler mime_sniffing_handler(
+      std::move(scoped_test_handler), &host, &plugin_service,
+      intercepting_handler.get(), request.get(),
+      REQUEST_CONTEXT_TYPE_UNSPECIFIED);
+
+  MockResourceLoader mock_loader(&mime_sniffing_handler);
+
+  // Call OnWillStart and OnResponseStarted.
+  EXPECT_EQ(MockResourceLoader::Status::IDLE,
+            mock_loader.OnWillStart(request->url()));
+  scoped_refptr<network::ResourceResponse> response(
+      new network::ResourceResponse);
+  response->head.mime_type = "text/plain";
+  EXPECT_EQ(MockResourceLoader::Status::IDLE,
+            mock_loader.OnResponseStarted(std::move(response)));
+
+  // Send a small, non-empty packet to OnWillRead and OnReadCompleted.
+  EXPECT_EQ(MockResourceLoader::Status::IDLE, mock_loader.OnWillRead());
+  EXPECT_EQ(MockResourceLoader::Status::IDLE,
+            mock_loader.OnReadCompleted("var x = 3;"));
+
+  // Verify that the mime sniffer didn't yet made the final sniffing decision.
+  // This is not really a verification of product code functionality, but rather
+  // verification that the test covers the desired part of the product code.
+  EXPECT_EQ(0, test_handler->on_response_started_called());
+  EXPECT_EQ(0, test_handler->on_read_completed_called());
+
+  // Send a 0-sized, EOF-indicating packet to OnWillRead and OnReadCompleted.
+  EXPECT_EQ(MockResourceLoader::Status::IDLE, mock_loader.OnWillRead());
+  EXPECT_EQ(MockResourceLoader::Status::IDLE, mock_loader.OnReadCompleted(""));
+
+  // Call OnResponseCompleted to report the final response status.
+  EXPECT_EQ(MockResourceLoader::Status::IDLE,
+            mock_loader.OnResponseCompleted(
+                net::URLRequestStatus::FromError(net::OK)));
+
+  // Verify that the test handler got all the expected calls.
+  EXPECT_EQ(1, test_handler->on_response_started_called());
+  EXPECT_EQ(2, test_handler->on_will_read_called());
+  EXPECT_EQ(2, test_handler->on_read_completed_called());
+  EXPECT_EQ(1, test_handler->on_read_eof_called());
+  EXPECT_EQ(1, test_handler->on_response_completed_called());
+  EXPECT_EQ("var x = 3;", test_handler->body());
+  EXPECT_TRUE(test_handler->final_status().is_success());
+  EXPECT_EQ("text/plain", test_handler->resource_response()->head.mime_type);
+
+  // Process all messages to ensure proper test teardown.
+  content::RunAllPendingInMessageLoop();
+}
+
+// The test verifies that MimeSniffingResourceHandler can properly handle an
+// empty network response.
+TEST_F(MimeSniffingResourceHandlerTest, EmptyPayload) {
+  net::URLRequestContext context;
+  std::unique_ptr<net::URLRequest> request(context.CreateRequest(
+      GURL("http://www.google.com"), net::DEFAULT_PRIORITY, nullptr,
+      TRAFFIC_ANNOTATION_FOR_TESTS));
+  ResourceRequestInfo::AllocateForTesting(request.get(), RESOURCE_TYPE_SCRIPT,
+                                          nullptr,       // context
+                                          0,             // render_process_id
+                                          0,             // render_view_id
+                                          0,             // render_frame_id
+                                          false,         // is_main_frame
+                                          false,         // allow_download
+                                          true,          // is_async
+                                          PREVIEWS_OFF,  // previews_state
+                                          nullptr);      // navigation_ui_data
+
+  TestResourceDispatcherHost host(false);
+
+  TestFakePluginService plugin_service(false, false);
+  std::unique_ptr<InterceptingResourceHandler> intercepting_handler(
+      new InterceptingResourceHandler(std::make_unique<TestResourceHandler>(),
+                                      nullptr));
+
+  std::unique_ptr<TestResourceHandler> scoped_test_handler(
+      new TestResourceHandler());
+  TestResourceHandler* test_handler = scoped_test_handler.get();
+  MimeSniffingResourceHandler mime_sniffing_handler(
+      std::move(scoped_test_handler), &host, &plugin_service,
+      intercepting_handler.get(), request.get(),
+      REQUEST_CONTEXT_TYPE_UNSPECIFIED);
+
+  MockResourceLoader mock_loader(&mime_sniffing_handler);
+
+  // Call OnWillStart and OnResponseStarted.
+  EXPECT_EQ(MockResourceLoader::Status::IDLE,
+            mock_loader.OnWillStart(request->url()));
+  scoped_refptr<network::ResourceResponse> response(
+      new network::ResourceResponse);
+  response->head.mime_type = "text/plain";
+  EXPECT_EQ(MockResourceLoader::Status::IDLE,
+            mock_loader.OnResponseStarted(std::move(response)));
+
+  // Verify that the mime sniffer didn't yet made the sniffing decision
+  // (since no payload data has been sent to the sniffer yet).
+  EXPECT_EQ(0, test_handler->on_response_started_called());
+  EXPECT_EQ(0, test_handler->on_read_completed_called());
+
+  // Send a 0-sized, EOF-indicating packet to OnWillRead and OnReadCompleted.
+  EXPECT_EQ(MockResourceLoader::Status::IDLE, mock_loader.OnWillRead());
+  EXPECT_EQ(MockResourceLoader::Status::IDLE, mock_loader.OnReadCompleted(""));
+
+  // Call OnResponseCompleted to report the final response status.
+  EXPECT_EQ(MockResourceLoader::Status::IDLE,
+            mock_loader.OnResponseCompleted(
+                net::URLRequestStatus::FromError(net::OK)));
+
+  // Verify that the test handler got all the expected calls.
+  EXPECT_EQ(1, test_handler->on_response_started_called());
+  EXPECT_EQ(1, test_handler->on_will_read_called());
+  EXPECT_EQ(1, test_handler->on_read_completed_called());
+  EXPECT_EQ(1, test_handler->on_read_eof_called());
+  EXPECT_EQ(1, test_handler->on_response_completed_called());
+  EXPECT_EQ("", test_handler->body());
+  EXPECT_TRUE(test_handler->final_status().is_success());
+  EXPECT_EQ("text/plain", test_handler->resource_response()->head.mime_type);
+
+  // Process all messages to ensure proper test teardown.
+  content::RunAllPendingInMessageLoop();
+}
+
 }  // namespace content
diff --git a/content/browser/loader/prefetch_browsertest.cc b/content/browser/loader/prefetch_browsertest.cc
index 4273eff..b489e4c 100644
--- a/content/browser/loader/prefetch_browsertest.cc
+++ b/content/browser/loader/prefetch_browsertest.cc
@@ -13,6 +13,8 @@
 #include "base/test/scoped_feature_list.h"
 #include "content/browser/loader/prefetch_url_loader_service.h"
 #include "content/browser/storage_partition_impl.h"
+#include "content/browser/web_package/mock_signed_exchange_handler.h"
+#include "content/browser/web_package/web_package_loader.h"
 #include "content/public/browser/web_contents.h"
 #include "content/public/common/content_features.h"
 #include "content/public/test/browser_test_utils.h"
@@ -34,6 +36,16 @@
   const bool signed_exchange_enabled;
 };
 
+struct ScopedSignedExchangeHandlerFactory {
+  explicit ScopedSignedExchangeHandlerFactory(
+      SignedExchangeHandlerFactory* factory) {
+    WebPackageLoader::SetSignedExchangeHandlerFactoryForTest(factory);
+  }
+  ~ScopedSignedExchangeHandlerFactory() {
+    WebPackageLoader::SetSignedExchangeHandlerFactoryForTest(nullptr);
+  }
+};
+
 class PrefetchBrowserTest
     : public ContentBrowserTest,
       public testing::WithParamInterface<PrefetchBrowserTestParam> {
@@ -316,6 +328,64 @@
   EXPECT_GE(preload_url_entries, 1);
 }
 
+IN_PROC_BROWSER_TEST_P(PrefetchBrowserTest, WebPackageWithPreload) {
+  int target_fetch_count = 0;
+  int preload_fetch_count = 0;
+  const char* prefetch_url = "/prefetch.html";
+  const char* target_htxg = "/target.htxg";
+  const char* target_url = "/target.html";
+  const char* preload_url_in_htxg = "/preload.js";
+
+  RegisterResponse(
+      prefetch_url,
+      ResponseEntry(base::StringPrintf(
+          "<body><link rel='prefetch' href='%s'></body>", target_htxg)));
+  RegisterResponse(
+      target_htxg,
+      // We mock the SignedExchangeHandler, so just return a HTML content
+      // as application/http-exchange+cbor.
+      ResponseEntry("<head><title>Prefetch Target (HTXG)</title></head>",
+                    "application/http-exchange+cbor"));
+  RegisterResponse(preload_url_in_htxg,
+                   ResponseEntry("function foo() {}", "text/javascript"));
+
+  base::RunLoop preload_waiter;
+  base::RunLoop prefetch_waiter;
+  embedded_test_server()->RegisterRequestMonitor(base::BindRepeating(
+      &PrefetchBrowserTest::WatchURLAndRunClosure, base::Unretained(this),
+      target_htxg, &target_fetch_count, prefetch_waiter.QuitClosure()));
+  embedded_test_server()->RegisterRequestMonitor(base::BindRepeating(
+      &PrefetchBrowserTest::WatchURLAndRunClosure, base::Unretained(this),
+      preload_url_in_htxg, &preload_fetch_count, preload_waiter.QuitClosure()));
+  embedded_test_server()->RegisterRequestHandler(base::BindRepeating(
+      &PrefetchBrowserTest::ServeResponses, base::Unretained(this)));
+  ASSERT_TRUE(embedded_test_server()->Start());
+  EXPECT_TRUE(CheckPrefetchURLLoaderCountIfSupported(0));
+
+  MockSignedExchangeHandlerFactory factory(
+      net::OK, GURL(target_url), "text/html",
+      {base::StringPrintf(
+          "Link: <%s>;rel=\"preload\";as=\"script\"",
+          embedded_test_server()->GetURL(preload_url_in_htxg).spec().c_str())});
+  ScopedSignedExchangeHandlerFactory scoped_factory(&factory);
+
+  // Loading a page that prefetches the target URL would increment both
+  // |target_fetch_count| and |preload_fetch_count|.
+  NavigateToURL(shell(), embedded_test_server()->GetURL(prefetch_url));
+  prefetch_waiter.Run();
+  EXPECT_EQ(1, target_fetch_count);
+  EXPECT_TRUE(CheckPrefetchURLLoaderCountIfSupported(1));
+
+  // Test after this point requires SignedHTTPExchange support.
+  if (!base::FeatureList::IsEnabled(features::kSignedHTTPExchange))
+    return;
+
+  // If the header in the .htxg file is correctly extracted, we should
+  // be able to also see the preload.
+  preload_waiter.Run();
+  EXPECT_EQ(1, preload_fetch_count);
+}
+
 INSTANTIATE_TEST_CASE_P(PrefetchBrowserTest,
                         PrefetchBrowserTest,
                         testing::Values(PrefetchBrowserTestParam(true, true),
diff --git a/content/browser/loader/prefetch_url_loader.cc b/content/browser/loader/prefetch_url_loader.cc
index 2f6b8d4a..dfb0bc7 100644
--- a/content/browser/loader/prefetch_url_loader.cc
+++ b/content/browser/loader/prefetch_url_loader.cc
@@ -4,7 +4,12 @@
 
 #include "content/browser/loader/prefetch_url_loader.h"
 
+#include "base/feature_list.h"
+#include "content/browser/web_package/web_package_prefetch_handler.h"
+#include "content/public/common/content_features.h"
+#include "content/public/common/shared_url_loader_factory.h"
 #include "net/url_request/url_request_context_getter.h"
+#include "services/network/public/cpp/features.h"
 
 namespace content {
 
@@ -15,59 +20,77 @@
     const network::ResourceRequest& resource_request,
     network::mojom::URLLoaderClientPtr client,
     const net::MutableNetworkTrafficAnnotationTag& traffic_annotation,
-    network::mojom::URLLoaderFactory* network_loader_factory,
+    scoped_refptr<SharedURLLoaderFactory> network_loader_factory,
     URLLoaderThrottlesGetter url_loader_throttles_getter,
     ResourceContext* resource_context,
     scoped_refptr<net::URLRequestContextGetter> request_context_getter)
-    : network_client_binding_(this),
+    : network_loader_factory_(std::move(network_loader_factory)),
+      client_binding_(this),
       forwarding_client_(std::move(client)),
       url_loader_throttles_getter_(url_loader_throttles_getter),
       resource_context_(resource_context),
       request_context_getter_(std::move(request_context_getter)) {
-  DCHECK(network_loader_factory);
+  DCHECK(network_loader_factory_);
 
-  // TODO(kinuko): Hook up the Web Package code that uses these fields.
-  // (https://crbug.com/803776)
-  DCHECK(resource_context_);
-  DCHECK(request_context_getter_);
+  if (resource_request.request_initiator)
+    request_initiator_ = *resource_request.request_initiator;
 
   network::mojom::URLLoaderClientPtr network_client;
-  network_client_binding_.Bind(mojo::MakeRequest(&network_client));
-  network_client_binding_.set_connection_error_handler(base::BindOnce(
+  client_binding_.Bind(mojo::MakeRequest(&network_client));
+  client_binding_.set_connection_error_handler(base::BindOnce(
       &PrefetchURLLoader::OnNetworkConnectionError, base::Unretained(this)));
-  network_loader_factory->CreateLoaderAndStart(
-      mojo::MakeRequest(&network_loader_), routing_id, request_id, options,
+  network_loader_factory_->CreateLoaderAndStart(
+      mojo::MakeRequest(&loader_), routing_id, request_id, options,
       resource_request, std::move(network_client), traffic_annotation);
 }
 
 PrefetchURLLoader::~PrefetchURLLoader() = default;
 
 void PrefetchURLLoader::FollowRedirect() {
-  network_loader_->FollowRedirect();
+  if (web_package_prefetch_handler_) {
+    // Rebind |client_binding_| and |loader_|.
+    client_binding_.Bind(web_package_prefetch_handler_->FollowRedirect(
+        mojo::MakeRequest(&loader_)));
+    return;
+  }
+
+  loader_->FollowRedirect();
 }
 
 void PrefetchURLLoader::ProceedWithResponse() {
-  network_loader_->ProceedWithResponse();
+  loader_->ProceedWithResponse();
 }
 
 void PrefetchURLLoader::SetPriority(net::RequestPriority priority,
                                     int intra_priority_value) {
-  network_loader_->SetPriority(priority, intra_priority_value);
+  loader_->SetPriority(priority, intra_priority_value);
 }
 
 void PrefetchURLLoader::PauseReadingBodyFromNet() {
-  network_loader_->PauseReadingBodyFromNet();
+  loader_->PauseReadingBodyFromNet();
 }
 
 void PrefetchURLLoader::ResumeReadingBodyFromNet() {
-  network_loader_->ResumeReadingBodyFromNet();
+  loader_->ResumeReadingBodyFromNet();
 }
 
 void PrefetchURLLoader::OnReceiveResponse(
-    const network::ResourceResponseHead& head,
+    const network::ResourceResponseHead& response,
     const base::Optional<net::SSLInfo>& ssl_info,
     network::mojom::DownloadedTempFilePtr downloaded_file) {
-  forwarding_client_->OnReceiveResponse(head, ssl_info,
+  if (WebPackagePrefetchHandler::IsResponseForWebPackage(response)) {
+    DCHECK(!web_package_prefetch_handler_);
+
+    // Note that after this point this doesn't directly get upcalls from the
+    // network. (Until |this| calls the handler's FollowRedirect.)
+    web_package_prefetch_handler_ = std::make_unique<WebPackagePrefetchHandler>(
+        response, std::move(loader_), client_binding_.Unbind(),
+        network_loader_factory_, request_initiator_,
+        url_loader_throttles_getter_, resource_context_,
+        request_context_getter_, this);
+    return;
+  }
+  forwarding_client_->OnReceiveResponse(response, ssl_info,
                                         std::move(downloaded_file));
 }
 
diff --git a/content/browser/loader/prefetch_url_loader.h b/content/browser/loader/prefetch_url_loader.h
index fa43ecb..b4d8459 100644
--- a/content/browser/loader/prefetch_url_loader.h
+++ b/content/browser/loader/prefetch_url_loader.h
@@ -22,7 +22,9 @@
 namespace content {
 
 class ResourceContext;
+class SharedURLLoaderFactory;
 class URLLoaderThrottle;
+class WebPackagePrefetchHandler;
 
 // PrefetchURLLoader which basically just keeps draining the data.
 class CONTENT_EXPORT PrefetchURLLoader
@@ -44,7 +46,7 @@
       const network::ResourceRequest& resource_request,
       network::mojom::URLLoaderClientPtr client,
       const net::MutableNetworkTrafficAnnotationTag& traffic_annotation,
-      network::mojom::URLLoaderFactory* network_loader_factory,
+      scoped_refptr<SharedURLLoaderFactory> network_loader_factory,
       URLLoaderThrottlesGetter url_loader_throttles_getter,
       ResourceContext* resource_context,
       scoped_refptr<net::URLRequestContextGetter> request_context_getter);
@@ -83,13 +85,17 @@
 
   void OnNetworkConnectionError();
 
+  scoped_refptr<SharedURLLoaderFactory> network_loader_factory_;
+
   // For the actual request.
-  network::mojom::URLLoaderPtr network_loader_;
-  mojo::Binding<network::mojom::URLLoaderClient> network_client_binding_;
+  network::mojom::URLLoaderPtr loader_;
+  mojo::Binding<network::mojom::URLLoaderClient> client_binding_;
 
   // To be a URLLoader for the client.
   network::mojom::URLLoaderClientPtr forwarding_client_;
 
+  url::Origin request_initiator_;
+
   // |url_loader_throttles_getter_| and |resource_context_| should be
   // valid as far as |request_context_getter_| returns non-null value.
   URLLoaderThrottlesGetter url_loader_throttles_getter_;
@@ -98,6 +104,8 @@
 
   std::unique_ptr<mojo::common::DataPipeDrainer> pipe_drainer_;
 
+  std::unique_ptr<WebPackagePrefetchHandler> web_package_prefetch_handler_;
+
   DISALLOW_COPY_AND_ASSIGN(PrefetchURLLoader);
 };
 
diff --git a/content/browser/loader/prefetch_url_loader_service.cc b/content/browser/loader/prefetch_url_loader_service.cc
index dad769e..4aa59d3 100644
--- a/content/browser/loader/prefetch_url_loader_service.cc
+++ b/content/browser/loader/prefetch_url_loader_service.cc
@@ -7,7 +7,7 @@
 #include "base/feature_list.h"
 #include "content/browser/loader/prefetch_url_loader.h"
 #include "content/browser/url_loader_factory_getter.h"
-#include "content/common/wrapper_shared_url_loader_factory.h"
+#include "content/common/weak_wrapper_shared_url_loader_factory.h"
 #include "content/public/browser/content_browser_client.h"
 #include "content/public/browser/web_contents.h"
 #include "content/public/common/content_client.h"
@@ -60,7 +60,15 @@
     }
     service_->CreateLoaderAndStart(
         std::move(request), routing_id, request_id, options, resource_request,
-        std::move(client), traffic_annotation, network_loader_factory_.get(),
+        std::move(client), traffic_annotation,
+        // NOTE: This should be fine in most cases, where the loader
+        // factory may become invalid if Network Service process is killed
+        // and restarted. The load can just fail in the case here, but if
+        // we want to be extra sure this should create a SharedURLLoaderFactory
+        // that internally holds a ref to the URLLoaderFactoryGetter so that
+        // it can re-obtain the factory if necessary.
+        base::MakeRefCounted<WeakWrapperSharedURLLoaderFactory>(
+            network_loader_factory_.get()),
         frame_tree_node_id_);
   }
 
@@ -120,7 +128,7 @@
     const network::ResourceRequest& resource_request,
     network::mojom::URLLoaderClientPtr client,
     const net::MutableNetworkTrafficAnnotationTag& traffic_annotation,
-    network::mojom::URLLoaderFactory* network_loader_factory,
+    scoped_refptr<SharedURLLoaderFactory> network_loader_factory,
     int frame_tree_node_id) {
   DCHECK_CURRENTLY_ON(BrowserThread::IO);
   DCHECK_EQ(RESOURCE_TYPE_PREFETCH, resource_request.resource_type);
@@ -136,7 +144,7 @@
   mojo::MakeStrongBinding(
       std::make_unique<PrefetchURLLoader>(
           routing_id, request_id, options, resource_request, std::move(client),
-          traffic_annotation, network_loader_factory,
+          traffic_annotation, std::move(network_loader_factory),
           base::BindRepeating(
               &PrefetchURLLoaderService::CreateURLLoaderThrottles, this,
               resource_request, frame_tree_node_id),
diff --git a/content/browser/loader/prefetch_url_loader_service.h b/content/browser/loader/prefetch_url_loader_service.h
index 3de2f44b2..1fd9cd91 100644
--- a/content/browser/loader/prefetch_url_loader_service.h
+++ b/content/browser/loader/prefetch_url_loader_service.h
@@ -20,6 +20,7 @@
 namespace content {
 
 class ResourceContext;
+class SharedURLLoaderFactory;
 class URLLoaderFactoryGetter;
 class URLLoaderThrottle;
 
@@ -55,7 +56,7 @@
       const network::ResourceRequest& resource_request,
       network::mojom::URLLoaderClientPtr client,
       const net::MutableNetworkTrafficAnnotationTag& traffic_annotation,
-      network::mojom::URLLoaderFactory* factory,
+      scoped_refptr<SharedURLLoaderFactory> network_loader_factory,
       int frame_tree_node_id = -1);
 
   // Register a callback that is fired right before a prefetch load is started
diff --git a/content/browser/loader/resource_message_filter.cc b/content/browser/loader/resource_message_filter.cc
index 75b5bea3..89aba72 100644
--- a/content/browser/loader/resource_message_filter.cc
+++ b/content/browser/loader/resource_message_filter.cc
@@ -121,7 +121,9 @@
       prefetch_url_loader_service_) {
     prefetch_url_loader_service_->CreateLoaderAndStart(
         std::move(request), routing_id, request_id, options, url_request,
-        std::move(client), traffic_annotation, url_loader_factory_.get());
+        std::move(client), traffic_annotation,
+        base::MakeRefCounted<WeakWrapperSharedURLLoaderFactory>(
+            url_loader_factory_.get()));
     return;
   }
 
diff --git a/content/browser/loader/test_resource_handler.cc b/content/browser/loader/test_resource_handler.cc
index 528a8d6..a2098a7 100644
--- a/content/browser/loader/test_resource_handler.cc
+++ b/content/browser/loader/test_resource_handler.cc
@@ -191,6 +191,7 @@
   ScopedCallDepthTracker call_depth_tracker(&call_depth_);
 
   ++on_read_completed_called_;
+  EXPECT_EQ(on_read_completed_called_, on_will_read_called_);
   if (bytes_read == 0)
     ++on_read_eof_called_;
 
diff --git a/content/browser/net/view_http_cache_job_factory.cc b/content/browser/net/view_http_cache_job_factory.cc
deleted file mode 100644
index 2b5ebb9..0000000
--- a/content/browser/net/view_http_cache_job_factory.cc
+++ /dev/null
@@ -1,205 +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 "content/browser/net/view_http_cache_job_factory.h"
-
-#include <stddef.h>
-
-#include "base/bind.h"
-#include "base/bind_helpers.h"
-#include "base/callback.h"
-#include "base/compiler_specific.h"
-#include "base/location.h"
-#include "base/macros.h"
-#include "base/memory/weak_ptr.h"
-#include "base/numerics/safe_conversions.h"
-#include "base/single_thread_task_runner.h"
-#include "base/strings/string_util.h"
-#include "base/threading/thread_task_runner_handle.h"
-#include "content/public/common/url_constants.h"
-#include "net/base/completion_callback.h"
-#include "net/base/net_errors.h"
-#include "net/url_request/url_request.h"
-#include "net/url_request/url_request_simple_job.h"
-#include "net/url_request/view_cache_helper.h"
-
-namespace content {
-namespace {
-
-// A job subclass that dumps an HTTP cache entry.
-class ViewHttpCacheJob : public net::URLRequestJob {
- public:
-  ViewHttpCacheJob(net::URLRequest* request,
-                   net::NetworkDelegate* network_delegate)
-      : net::URLRequestJob(request, network_delegate),
-        core_(new Core),
-        callback_(base::Bind(&ViewHttpCacheJob::OnStartCompleted,
-                             base::Unretained(this))),
-        weak_factory_(this) {
-  }
-
-  // net::URLRequestJob implementation.
-  void Start() override;
-  void Kill() override;
-  bool GetMimeType(std::string* mime_type) const override {
-    return core_->GetMimeType(mime_type);
-  }
-  bool GetCharset(std::string* charset) override {
-    return core_->GetCharset(charset);
-  }
-  int ReadRawData(net::IOBuffer* buf, int buf_size) override {
-    return core_->ReadRawData(buf, buf_size);
-  }
-
- private:
-  class Core : public base::RefCounted<Core> {
-   public:
-    Core()
-        : data_offset_(0),
-          callback_(base::Bind(&Core::OnIOComplete, base::Unretained(this))) {}
-
-    int Start(const net::URLRequest& request, const base::Closure& callback);
-
-    // Prevents it from invoking its callback. It will self-delete.
-    void Orphan() {
-      user_callback_.Reset();
-    }
-
-    bool GetMimeType(std::string* mime_type) const;
-    bool GetCharset(std::string* charset);
-    int ReadRawData(net::IOBuffer* buf, int buf_size);
-
-   private:
-    friend class base::RefCounted<Core>;
-
-    ~Core() {}
-
-    // Called when ViewCacheHelper completes the operation.
-    void OnIOComplete(int result);
-
-    std::string data_;
-    size_t data_offset_;
-    net::ViewCacheHelper cache_helper_;
-    net::CompletionCallback callback_;
-    base::Closure user_callback_;
-
-    DISALLOW_COPY_AND_ASSIGN(Core);
-  };
-
-  ~ViewHttpCacheJob() override {}
-
-  void StartAsync();
-  void OnStartCompleted();
-
-  scoped_refptr<Core> core_;
-  base::Closure callback_;
-
-  base::WeakPtrFactory<ViewHttpCacheJob> weak_factory_;
-
-  DISALLOW_COPY_AND_ASSIGN(ViewHttpCacheJob);
-};
-
-void ViewHttpCacheJob::Start() {
-  base::ThreadTaskRunnerHandle::Get()->PostTask(
-      FROM_HERE, base::BindOnce(&ViewHttpCacheJob::StartAsync,
-                                weak_factory_.GetWeakPtr()));
-}
-
-void ViewHttpCacheJob::Kill() {
-  weak_factory_.InvalidateWeakPtrs();
-  if (core_.get()) {
-    core_->Orphan();
-    core_ = nullptr;
-  }
-  net::URLRequestJob::Kill();
-}
-
-void ViewHttpCacheJob::StartAsync() {
-  DCHECK(request());
-
-  if (!request())
-    return;
-
-  int rv = core_->Start(*request(), callback_);
-  if (rv != net::ERR_IO_PENDING) {
-    DCHECK_EQ(net::OK, rv);
-    OnStartCompleted();
-  }
-}
-
-void ViewHttpCacheJob::OnStartCompleted() {
-  NotifyHeadersComplete();
-}
-
-int ViewHttpCacheJob::Core::Start(const net::URLRequest& request,
-                                  const base::Closure& callback) {
-  DCHECK(!callback.is_null());
-  DCHECK(user_callback_.is_null());
-
-  AddRef();  // Released on OnIOComplete().
-  std::string cache_key =
-      request.url().spec().substr(strlen(kChromeUINetworkViewCacheURL));
-
-  int rv;
-  if (cache_key.empty()) {
-    rv = cache_helper_.GetContentsHTML(request.context(),
-                                       kChromeUINetworkViewCacheURL,
-                                       &data_, callback_);
-  } else {
-    rv = cache_helper_.GetEntryInfoHTML(cache_key, request.context(),
-                                        &data_, callback_);
-  }
-
-  if (rv == net::ERR_IO_PENDING)
-    user_callback_ = callback;
-
-  return rv;
-}
-
-bool ViewHttpCacheJob::Core::GetMimeType(std::string* mime_type) const {
-  mime_type->assign("text/html");
-  return true;
-}
-
-bool ViewHttpCacheJob::Core::GetCharset(std::string* charset) {
-  charset->assign("UTF-8");
-  return true;
-}
-
-int ViewHttpCacheJob::Core::ReadRawData(net::IOBuffer* buf, int buf_size) {
-  DCHECK_LE(data_offset_, data_.size());
-  int remaining = base::checked_cast<int>(data_.size() - data_offset_);
-  if (buf_size > remaining)
-    buf_size = remaining;
-  memcpy(buf->data(), data_.data() + data_offset_, buf_size);
-  data_offset_ += buf_size;
-  return buf_size;
-}
-
-void ViewHttpCacheJob::Core::OnIOComplete(int result) {
-  DCHECK_EQ(net::OK, result);
-
-  if (!user_callback_.is_null())
-    user_callback_.Run();
-
-  // We may be holding the last reference to this job. If it's deleted
-  // synchronously then ViewCacheHelper would have a UaF.
-  base::ThreadTaskRunnerHandle::Get()->ReleaseSoon(FROM_HERE, this);
-}
-
-}  // namespace.
-
-// Static.
-bool ViewHttpCacheJobFactory::IsSupportedURL(const GURL& url) {
-  return url.SchemeIs(kChromeUIScheme) &&
-         url.host_piece() == kChromeUINetworkViewCacheHost;
-}
-
-// Static.
-net::URLRequestJob* ViewHttpCacheJobFactory::CreateJobForRequest(
-    net::URLRequest* request, net::NetworkDelegate* network_delegate) {
-  return new ViewHttpCacheJob(request, network_delegate);
-}
-
-}  // namespace content
diff --git a/content/browser/net/view_http_cache_job_factory.h b/content/browser/net/view_http_cache_job_factory.h
deleted file mode 100644
index 45bca5d..0000000
--- a/content/browser/net/view_http_cache_job_factory.h
+++ /dev/null
@@ -1,27 +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 CONTENT_BROWSER_NET_VIEW_HTTP_CACHE_JOB_FACTORY_H_
-#define CONTENT_BROWSER_NET_VIEW_HTTP_CACHE_JOB_FACTORY_H_
-
-namespace net {
-class NetworkDelegate;
-class URLRequest;
-class URLRequestJob;
-}  // namespace net
-
-class GURL;
-
-namespace content {
-
-class ViewHttpCacheJobFactory {
- public:
-  static bool IsSupportedURL(const GURL& url);
-  static net::URLRequestJob* CreateJobForRequest(
-      net::URLRequest* request, net::NetworkDelegate* network_delegate);
-};
-
-}  // namespace content
-
-#endif  // CONTENT_BROWSER_NET_VIEW_HTTP_CACHE_JOB_FACTORY_H_
diff --git a/content/browser/renderer_host/render_process_host_impl.cc b/content/browser/renderer_host/render_process_host_impl.cc
index 27e7412..f304bee 100644
--- a/content/browser/renderer_host/render_process_host_impl.cc
+++ b/content/browser/renderer_host/render_process_host_impl.cc
@@ -2642,8 +2642,8 @@
     cc::switches::kSlowDownRasterScaleFactor,
     cc::switches::kBrowserControlsHideThreshold,
     cc::switches::kBrowserControlsShowThreshold,
-    cc::switches::kRunAllCompositorStagesBeforeDraw,
     switches::kEnableSurfaceSynchronization,
+    switches::kRunAllCompositorStagesBeforeDraw,
     switches::kUseVizHitTestDrawQuad,
     switches::kUseVizHitTestSurfaceLayer,
 
diff --git a/content/browser/renderer_host/render_widget_host_impl.cc b/content/browser/renderer_host/render_widget_host_impl.cc
index 17fc7dc5..dd189ab 100644
--- a/content/browser/renderer_host/render_widget_host_impl.cc
+++ b/content/browser/renderer_host/render_widget_host_impl.cc
@@ -617,8 +617,6 @@
     IPC_MESSAGE_HANDLER(DragHostMsg_UpdateDragCursor, OnUpdateDragCursor)
     IPC_MESSAGE_HANDLER(ViewHostMsg_FrameSwapMessages,
                         OnFrameSwapMessagesReceived)
-    IPC_MESSAGE_HANDLER(ViewHostMsg_OnRenderFrameSubmitted,
-                        OnRenderFrameMetadata)
     IPC_MESSAGE_UNHANDLED(handled = false)
   IPC_END_MESSAGE_MAP()
 
@@ -2971,11 +2969,6 @@
     input_router_->StopFling();
 }
 
-void RenderWidgetHostImpl::OnRenderFrameMetadata(
-    const cc::RenderFrameMetadata& metadata) {
-  last_render_frame_metadata_ = metadata;
-}
-
 void RenderWidgetHostImpl::SetScreenOrientationForTesting(
     uint16_t angle,
     ScreenOrientationValues type) {
diff --git a/content/browser/renderer_host/render_widget_host_impl.h b/content/browser/renderer_host/render_widget_host_impl.h
index 71e00b2f..d3f6788 100644
--- a/content/browser/renderer_host/render_widget_host_impl.h
+++ b/content/browser/renderer_host/render_widget_host_impl.h
@@ -80,7 +80,6 @@
 
 namespace cc {
 struct BeginFrameAck;
-class RenderFrameMetadata;
 }  // namespace cc
 
 namespace gfx {
@@ -825,8 +824,6 @@
       uint32_t last_shared_bitmap_sequence_number) override;
   void SetupInputRouter();
 
-  void OnRenderFrameMetadata(const cc::RenderFrameMetadata& metadata);
-
   bool SurfacePropertiesMismatch(
       const RenderWidgetSurfaceProperties& first,
       const RenderWidgetSurfaceProperties& second) const;
@@ -1053,7 +1050,6 @@
   base::OnceCallback<void(const viz::FrameSinkId&)> create_frame_sink_callback_;
 
   viz::CompositorFrameMetadata last_frame_metadata_;
-  cc::RenderFrameMetadata last_render_frame_metadata_;
 
   // Last non-zero frame token received from the renderer. Any swap messsages
   // having a token less than or equal to this value will be processed.
diff --git a/content/browser/web_package/mock_signed_exchange_handler.cc b/content/browser/web_package/mock_signed_exchange_handler.cc
new file mode 100644
index 0000000..44f0899e
--- /dev/null
+++ b/content/browser/web_package/mock_signed_exchange_handler.cc
@@ -0,0 +1,62 @@
+// 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 "content/browser/web_package/mock_signed_exchange_handler.h"
+
+#include "base/callback.h"
+#include "base/strings/stringprintf.h"
+#include "net/filter/source_stream.h"
+#include "net/http/http_response_headers.h"
+#include "net/http/http_util.h"
+
+namespace content {
+
+MockSignedExchangeHandler::MockSignedExchangeHandler(
+    net::Error error,
+    const GURL& request_url,
+    const std::string& mime_type,
+    const std::vector<std::string>& response_headers,
+    std::unique_ptr<net::SourceStream> body,
+    ExchangeHeadersCallback headers_callback) {
+  network::ResourceResponseHead head;
+  if (error == net::OK) {
+    head.headers =
+        base::MakeRefCounted<net::HttpResponseHeaders>("HTTP/1.1 200 OK");
+    head.mime_type = mime_type;
+    head.headers->AddHeader(
+        base::StringPrintf("Content-type: %s", mime_type.c_str()));
+    for (const auto& header : response_headers)
+      head.headers->AddHeader(header);
+  }
+  base::SequencedTaskRunnerHandle::Get()->PostTask(
+      FROM_HERE, base::BindOnce(std::move(headers_callback), error, request_url,
+                                "GET", head, std::move(body), base::nullopt));
+}
+
+MockSignedExchangeHandler::~MockSignedExchangeHandler() {}
+
+MockSignedExchangeHandlerFactory::MockSignedExchangeHandlerFactory(
+    net::Error error,
+    const GURL& request_url,
+    const std::string& mime_type,
+    std::vector<std::string> response_headers)
+    : error_(error),
+      request_url_(request_url),
+      mime_type_(mime_type),
+      response_headers_(std::move(response_headers)) {}
+
+MockSignedExchangeHandlerFactory::~MockSignedExchangeHandlerFactory() = default;
+
+std::unique_ptr<SignedExchangeHandler> MockSignedExchangeHandlerFactory::Create(
+    std::unique_ptr<net::SourceStream> body,
+    ExchangeHeadersCallback headers_callback,
+    url::Origin request_initiator,
+    scoped_refptr<SharedURLLoaderFactory> url_loader_factory,
+    URLLoaderThrottlesGetter url_loader_throttles_getter) {
+  return std::make_unique<MockSignedExchangeHandler>(
+      error_, request_url_, mime_type_, response_headers_, std::move(body),
+      std::move(headers_callback));
+}
+
+}  // namespace content
diff --git a/content/browser/web_package/mock_signed_exchange_handler.h b/content/browser/web_package/mock_signed_exchange_handler.h
new file mode 100644
index 0000000..cc20f64
--- /dev/null
+++ b/content/browser/web_package/mock_signed_exchange_handler.h
@@ -0,0 +1,67 @@
+// 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 CONTENT_BROWSER_WEB_PACKAGE_MOCK_SIGNED_EXCHANGE_HANDLER_H_
+#define CONTENT_BROWSER_WEB_PACKAGE_MOCK_SIGNED_EXCHANGE_HANDLER_H_
+
+#include <string>
+#include <vector>
+
+#include "content/browser/web_package/signed_exchange_handler.h"
+#include "url/gurl.h"
+
+namespace content {
+
+class MockSignedExchangeHandler final : public SignedExchangeHandler {
+ public:
+  MockSignedExchangeHandler(net::Error error,
+                            const GURL& request_url,
+                            const std::string& mime_type,
+                            const std::vector<std::string>& response_headers,
+                            std::unique_ptr<net::SourceStream> body,
+                            ExchangeHeadersCallback headers_callback);
+  ~MockSignedExchangeHandler();
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(MockSignedExchangeHandler);
+};
+
+class MockSignedExchangeHandlerFactory final
+    : public SignedExchangeHandlerFactory {
+ public:
+  using ExchangeHeadersCallback =
+      SignedExchangeHandler::ExchangeHeadersCallback;
+  using URLLoaderThrottlesGetter =
+      SignedExchangeHandler::URLLoaderThrottlesGetter;
+
+  // Creates a factory that creates SignedExchangeHandler which always fires
+  // a headers callback with the given |error|, |request_url|, |mime_type|
+  // and |response_headers|.
+  // |mime_type| and |response_headers| are ignored if |error| is not
+  // net::OK.
+  MockSignedExchangeHandlerFactory(net::Error error,
+                                   const GURL& request_url,
+                                   const std::string& mime_type,
+                                   std::vector<std::string> response_headers);
+  ~MockSignedExchangeHandlerFactory() override;
+
+  std::unique_ptr<SignedExchangeHandler> Create(
+      std::unique_ptr<net::SourceStream> body,
+      ExchangeHeadersCallback headers_callback,
+      url::Origin request_initiator,
+      scoped_refptr<SharedURLLoaderFactory> url_loader_factory,
+      URLLoaderThrottlesGetter url_loader_throttles_getter) override;
+
+ private:
+  const net::Error error_;
+  const GURL request_url_;
+  const std::string mime_type_;
+  const std::vector<std::string> response_headers_;
+
+  DISALLOW_COPY_AND_ASSIGN(MockSignedExchangeHandlerFactory);
+};
+
+}  // namespace content
+
+#endif  // CONTENT_BROWSER_WEB_PACKAGE_MOCK_SIGNED_EXCHANGE_HANDLER_H_
diff --git a/content/browser/web_package/signed_exchange_handler.cc b/content/browser/web_package/signed_exchange_handler.cc
index 6c1488f..da36b355 100644
--- a/content/browser/web_package/signed_exchange_handler.cc
+++ b/content/browser/web_package/signed_exchange_handler.cc
@@ -88,6 +88,8 @@
 
 SignedExchangeHandler::~SignedExchangeHandler() = default;
 
+SignedExchangeHandler::SignedExchangeHandler() : weak_factory_(this) {}
+
 void SignedExchangeHandler::ReadLoop() {
   DCHECK(headers_callback_);
   DCHECK(read_buf_);
diff --git a/content/browser/web_package/signed_exchange_handler.h b/content/browser/web_package/signed_exchange_handler.h
index 7ce43e6..648fb01 100644
--- a/content/browser/web_package/signed_exchange_handler.h
+++ b/content/browser/web_package/signed_exchange_handler.h
@@ -9,6 +9,7 @@
 
 #include "base/callback.h"
 #include "base/optional.h"
+#include "content/common/content_export.h"
 #include "content/public/common/shared_url_loader_factory.h"
 #include "mojo/public/cpp/system/data_pipe.h"
 #include "net/base/completion_callback.h"
@@ -31,7 +32,7 @@
 // IMPORTANT: Currenly SignedExchangeHandler doesn't implement any verifying
 // logic.
 // TODO(https://crbug.com/803774): Implement verifying logic.
-class SignedExchangeHandler final {
+class CONTENT_EXPORT SignedExchangeHandler {
  public:
   // TODO(https://crbug.com/803774): Add verification status here.
   using ExchangeHeadersCallback =
@@ -58,6 +59,9 @@
       URLLoaderThrottlesGetter url_loader_throttles_getter);
   ~SignedExchangeHandler();
 
+ protected:
+  SignedExchangeHandler();
+
  private:
   void ReadLoop();
   void DidRead(bool completed_syncly, int result);
@@ -95,6 +99,20 @@
   DISALLOW_COPY_AND_ASSIGN(SignedExchangeHandler);
 };
 
+// Used only for testing.
+class SignedExchangeHandlerFactory {
+ public:
+  virtual ~SignedExchangeHandlerFactory() {}
+
+  virtual std::unique_ptr<SignedExchangeHandler> Create(
+      std::unique_ptr<net::SourceStream> body,
+      SignedExchangeHandler::ExchangeHeadersCallback headers_callback,
+      url::Origin request_initiator,
+      scoped_refptr<SharedURLLoaderFactory> url_loader_factory,
+      SignedExchangeHandler::URLLoaderThrottlesGetter
+          url_loader_throttles_getter) = 0;
+};
+
 }  // namespace content
 
 #endif  // CONTENT_BROWSER_WEB_PACKAGE_SIGNED_EXCHANGE_HANDLER_H_
diff --git a/content/browser/web_package/web_package_loader.cc b/content/browser/web_package/web_package_loader.cc
index 122da91..d055039 100644
--- a/content/browser/web_package/web_package_loader.cc
+++ b/content/browser/web_package/web_package_loader.cc
@@ -34,6 +34,8 @@
 
 constexpr static int kDefaultBufferSize = 64 * 1024;
 
+SignedExchangeHandlerFactory* g_signed_exchange_factory_for_testing_ = nullptr;
+
 }  // namespace
 
 class WebPackageLoader::ResponseTimingInfo {
@@ -154,6 +156,16 @@
 
 void WebPackageLoader::OnStartLoadingResponseBody(
     mojo::ScopedDataPipeConsumerHandle body) {
+  if (g_signed_exchange_factory_for_testing_) {
+    signed_exchange_handler_ = g_signed_exchange_factory_for_testing_->Create(
+        std::make_unique<DataPipeToSourceStream>(std::move(body)),
+        base::BindOnce(&WebPackageLoader::OnHTTPExchangeFound,
+                       weak_factory_.GetWeakPtr()),
+        std::move(request_initiator_), std::move(url_loader_factory_),
+        std::move(url_loader_throttles_getter_));
+    return;
+  }
+
   signed_exchange_handler_ = std::make_unique<SignedExchangeHandler>(
       std::make_unique<DataPipeToSourceStream>(std::move(body)),
       base::BindOnce(&WebPackageLoader::OnHTTPExchangeFound,
@@ -218,7 +230,6 @@
   forwarding_client_->OnReceiveRedirect(
       CreateRedirectInfo(request_url),
       std::move(original_response_timing_info_)->CreateRedirectResponseHead());
-  forwarding_client_->OnComplete(network::URLLoaderCompletionStatus(net::OK));
   forwarding_client_.reset();
 
   if (ssl_info &&
@@ -275,4 +286,9 @@
   client_->OnComplete(status);
 }
 
+void WebPackageLoader::SetSignedExchangeHandlerFactoryForTest(
+    SignedExchangeHandlerFactory* factory) {
+  g_signed_exchange_factory_for_testing_ = factory;
+}
+
 }  // namespace content
diff --git a/content/browser/web_package/web_package_loader.h b/content/browser/web_package/web_package_loader.h
index a7acc45..80fbddf9 100644
--- a/content/browser/web_package/web_package_loader.h
+++ b/content/browser/web_package/web_package_loader.h
@@ -6,6 +6,7 @@
 #define CONTENT_BROWSER_WEB_PACKAGE_WEB_PACKAGE_LOADER_H_
 
 #include "base/optional.h"
+#include "content/common/content_export.h"
 #include "mojo/public/cpp/bindings/binding.h"
 #include "mojo/public/cpp/system/simple_watcher.h"
 #include "net/ssl/ssl_info.h"
@@ -21,8 +22,9 @@
 namespace content {
 
 class SharedURLLoaderFactory;
-class URLLoaderThrottle;
 class SignedExchangeHandler;
+class SignedExchangeHandlerFactory;
+class URLLoaderThrottle;
 class SourceStreamToDataPipe;
 
 // WebPackageLoader handles an origin-signed HTTP exchange response. It is
@@ -74,6 +76,10 @@
 
   void ConnectToClient(network::mojom::URLLoaderClientPtr client);
 
+  // Set nullptr to reset the mocking.
+  CONTENT_EXPORT static void SetSignedExchangeHandlerFactoryForTest(
+      SignedExchangeHandlerFactory* factory);
+
  private:
   class ResponseTimingInfo;
 
diff --git a/content/browser/web_package/web_package_prefetch_handler.cc b/content/browser/web_package/web_package_prefetch_handler.cc
new file mode 100644
index 0000000..0827f95
--- /dev/null
+++ b/content/browser/web_package/web_package_prefetch_handler.cc
@@ -0,0 +1,121 @@
+// 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 "content/browser/web_package/web_package_prefetch_handler.h"
+
+#include "content/browser/web_package/signed_exchange_url_loader_factory_for_non_network_service.h"
+#include "content/browser/web_package/web_package_loader.h"
+#include "content/browser/web_package/web_package_request_handler.h"
+#include "content/common/weak_wrapper_shared_url_loader_factory.h"
+#include "content/public/common/content_features.h"
+#include "mojo/public/cpp/bindings/strong_binding.h"
+#include "net/url_request/url_request_context_getter.h"
+#include "services/network/public/cpp/features.h"
+#include "services/network/public/mojom/url_loader_factory.mojom.h"
+
+namespace content {
+
+bool WebPackagePrefetchHandler::IsResponseForWebPackage(
+    const network::ResourceResponseHead& response) {
+  std::string mime_type;
+  if (base::FeatureList::IsEnabled(features::kSignedHTTPExchange) &&
+      !response.was_fetched_via_service_worker && response.headers &&
+      response.headers->GetMimeType(&mime_type) &&
+      WebPackageRequestHandler::IsSupportedMimeType(mime_type)) {
+    return true;
+  }
+  return false;
+}
+
+WebPackagePrefetchHandler::WebPackagePrefetchHandler(
+    const network::ResourceResponseHead& response,
+    network::mojom::URLLoaderPtr network_loader,
+    network::mojom::URLLoaderClientRequest network_client_request,
+    scoped_refptr<SharedURLLoaderFactory> network_loader_factory,
+    url::Origin request_initiator,
+    URLLoaderThrottlesGetter loader_throttles_getter,
+    ResourceContext* resource_context,
+    scoped_refptr<net::URLRequestContextGetter> request_context_getter,
+    network::mojom::URLLoaderClient* forwarding_client)
+    : loader_client_binding_(this), forwarding_client_(forwarding_client) {
+  network::mojom::URLLoaderClientEndpointsPtr endpoints =
+      network::mojom::URLLoaderClientEndpoints::New(
+          std::move(network_loader).PassInterface(),
+          std::move(network_client_request));
+  network::mojom::URLLoaderClientPtr client;
+  loader_client_binding_.Bind(mojo::MakeRequest(&client));
+  scoped_refptr<SharedURLLoaderFactory> url_loader_factory;
+  if (!base::FeatureList::IsEnabled(network::features::kNetworkService)) {
+    url_loader_factory = base::MakeRefCounted<
+        SignedExchangeURLLoaderFactoryForNonNetworkService>(
+        resource_context, request_context_getter.get());
+  } else {
+    url_loader_factory = std::move(network_loader_factory);
+  }
+  web_package_loader_ = std::make_unique<WebPackageLoader>(
+      response, std::move(client), std::move(endpoints),
+      std::move(request_initiator), network::mojom::kURLLoadOptionNone,
+      std::move(url_loader_factory), loader_throttles_getter);
+}
+
+WebPackagePrefetchHandler::~WebPackagePrefetchHandler() = default;
+
+network::mojom::URLLoaderClientRequest
+WebPackagePrefetchHandler::FollowRedirect(
+    network::mojom::URLLoaderRequest loader_request) {
+  DCHECK(web_package_loader_);
+  network::mojom::URLLoaderClientPtr client;
+  auto pending_request = mojo::MakeRequest(&client);
+  web_package_loader_->ConnectToClient(std::move(client));
+  mojo::MakeStrongBinding(std::move(web_package_loader_),
+                          std::move(loader_request));
+  return pending_request;
+}
+
+void WebPackagePrefetchHandler::OnReceiveResponse(
+    const network::ResourceResponseHead& head,
+    const base::Optional<net::SSLInfo>& ssl_info,
+    network::mojom::DownloadedTempFilePtr downloaded_file) {
+  NOTREACHED();
+}
+
+void WebPackagePrefetchHandler::OnReceiveRedirect(
+    const net::RedirectInfo& redirect_info,
+    const network::ResourceResponseHead& head) {
+  forwarding_client_->OnReceiveRedirect(redirect_info, head);
+}
+
+void WebPackagePrefetchHandler::OnDataDownloaded(int64_t data_length,
+                                                 int64_t encoded_length) {
+  NOTREACHED();
+}
+
+void WebPackagePrefetchHandler::OnUploadProgress(
+    int64_t current_position,
+    int64_t total_size,
+    base::OnceCallback<void()> callback) {
+  NOTREACHED();
+}
+
+void WebPackagePrefetchHandler::OnReceiveCachedMetadata(
+    const std::vector<uint8_t>& data) {
+  NOTREACHED();
+}
+
+void WebPackagePrefetchHandler::OnTransferSizeUpdated(
+    int32_t transfer_size_diff) {
+  NOTREACHED();
+}
+
+void WebPackagePrefetchHandler::OnStartLoadingResponseBody(
+    mojo::ScopedDataPipeConsumerHandle body) {
+  NOTREACHED();
+}
+
+void WebPackagePrefetchHandler::OnComplete(
+    const network::URLLoaderCompletionStatus& status) {
+  forwarding_client_->OnComplete(status);
+}
+
+}  // namespace content
diff --git a/content/browser/web_package/web_package_prefetch_handler.h b/content/browser/web_package/web_package_prefetch_handler.h
new file mode 100644
index 0000000..97158c2
--- /dev/null
+++ b/content/browser/web_package/web_package_prefetch_handler.h
@@ -0,0 +1,86 @@
+// 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 CONTENT_BROWSER_WEB_PACKAGE_WEB_PACKAGE_PREFETCH_HANDLER_H_
+#define CONTENT_BROWSER_WEB_PACKAGE_WEB_PACKAGE_PREFETCH_HANDLER_H_
+
+#include "base/macros.h"
+#include "mojo/public/cpp/bindings/binding.h"
+#include "services/network/public/mojom/url_loader.mojom.h"
+
+namespace net {
+class URLRequestContextGetter;
+}
+
+namespace content {
+
+class ResourceContext;
+class URLLoaderThrottle;
+class SharedURLLoaderFactory;
+class WebPackageLoader;
+
+// Attached to each PrefetchURLLoader if the prefetch is for a signed exchange.
+class WebPackagePrefetchHandler final : public network::mojom::URLLoaderClient {
+ public:
+  using URLLoaderThrottlesGetter = base::RepeatingCallback<
+      std::vector<std::unique_ptr<content::URLLoaderThrottle>>()>;
+
+  static bool IsResponseForWebPackage(
+      const network::ResourceResponseHead& response);
+
+  // This takes |network_loader| and |network_client| to set up the
+  // WebPackageLoader (so that the loader can load data from the network).
+  // |forwarding_client| is a pointer to the downstream client (typically who
+  // creates this handler).
+  WebPackagePrefetchHandler(
+      const network::ResourceResponseHead& response,
+      network::mojom::URLLoaderPtr network_loader,
+      network::mojom::URLLoaderClientRequest network_client_request,
+      scoped_refptr<SharedURLLoaderFactory> network_loader_factory,
+      url::Origin request_initiator,
+      URLLoaderThrottlesGetter loader_throttles_getter,
+      ResourceContext* resource_context,
+      scoped_refptr<net::URLRequestContextGetter> request_context_getter,
+      network::mojom::URLLoaderClient* forwarding_client);
+
+  ~WebPackagePrefetchHandler() override;
+
+  // This connects |loader_request| to the WebPackageLoader, and returns the
+  // pending client request to the loader.
+  // The returned client request can be bound to the downstream client so that
+  // they can start directly receiving upcalls from the WebPackageLoader.
+  // After this point |this| can be destructed.
+  network::mojom::URLLoaderClientRequest FollowRedirect(
+      network::mojom::URLLoaderRequest loader_request);
+
+ private:
+  // network::mojom::URLLoaderClient overrides:
+  void OnReceiveResponse(
+      const network::ResourceResponseHead& head,
+      const base::Optional<net::SSLInfo>& ssl_info,
+      network::mojom::DownloadedTempFilePtr downloaded_file) override;
+  void OnReceiveRedirect(const net::RedirectInfo& redirect_info,
+                         const network::ResourceResponseHead& head) override;
+  void OnDataDownloaded(int64_t data_length, int64_t encoded_length) override;
+  void OnUploadProgress(int64_t current_position,
+                        int64_t total_size,
+                        base::OnceCallback<void()> callback) override;
+  void OnReceiveCachedMetadata(const std::vector<uint8_t>& data) override;
+  void OnTransferSizeUpdated(int32_t transfer_size_diff) override;
+  void OnStartLoadingResponseBody(
+      mojo::ScopedDataPipeConsumerHandle body) override;
+  void OnComplete(const network::URLLoaderCompletionStatus& status) override;
+
+  mojo::Binding<network::mojom::URLLoaderClient> loader_client_binding_;
+
+  std::unique_ptr<WebPackageLoader> web_package_loader_;
+
+  network::mojom::URLLoaderClient* forwarding_client_;
+
+  DISALLOW_COPY_AND_ASSIGN(WebPackagePrefetchHandler);
+};
+
+}  // namespace content
+
+#endif  // CONTENT_BROWSER_WEB_PACKAGE_WEB_PACKAGE_PREFETCH_HANDLER_H_
diff --git a/content/browser/webauth/collected_client_data.cc b/content/browser/webauth/collected_client_data.cc
index 178ea01..0dd995b 100644
--- a/content/browser/webauth/collected_client_data.cc
+++ b/content/browser/webauth/collected_client_data.cc
@@ -68,16 +68,6 @@
   client_data.SetKey(kTypeKey, base::Value(type_));
   client_data.SetKey(kChallengeKey, base::Value(base64_encoded_challenge_));
 
-  if (base::RandDouble() < 0.2) {
-    // An extra key is sometimes added to ensure that RPs do not make
-    // unreasonably specific assumptions about the clientData JSON. This is
-    // done in the fashion of
-    // https://tools.ietf.org/html/draft-davidben-tls-grease-01
-    client_data.SetKey("new_keys_may_be_added_here",
-                       base::Value("do not compare clientDataJSON against a "
-                                   "template. See https://goo.gl/yabPex"));
-  }
-
   // The serialization of callerOrigin.
   client_data.SetKey(kOriginKey, base::Value(origin_));
 
diff --git a/content/browser/webrtc/webrtc_capture_from_element_browsertest.cc b/content/browser/webrtc/webrtc_capture_from_element_browsertest.cc
index 18e78c8..3560e1e 100644
--- a/content/browser/webrtc/webrtc_capture_from_element_browsertest.cc
+++ b/content/browser/webrtc/webrtc_capture_from_element_browsertest.cc
@@ -141,8 +141,16 @@
       kVideoAudioHtmlFile);
 }
 
+// Disable the test until flakiness is resolved, see https://crbug.com/812186.
+#if defined(OS_MACOSX)
+#define MAYBE_CaptureFromCanvas2DHandlesContextLoss \
+  DISABLED_CaptureFromCanvas2DHandlesContextLoss
+#else
+#define MAYBE_CaptureFromCanvas2DHandlesContextLoss \
+  CaptureFromCanvas2DHandlesContextLoss
+#endif  // defined(OS_MACOSX)
 IN_PROC_BROWSER_TEST_F(WebRtcCaptureFromElementBrowserTest,
-                       CaptureFromCanvas2DHandlesContextLoss) {
+                       MAYBE_CaptureFromCanvas2DHandlesContextLoss) {
   MakeTypicalCall("testCanvas2DContextLoss(true);",
                   kCanvasCaptureColorTestHtmlFile);
 }
diff --git a/content/browser/webui/url_data_manager_backend.cc b/content/browser/webui/url_data_manager_backend.cc
index 88de866..daa9763 100644
--- a/content/browser/webui/url_data_manager_backend.cc
+++ b/content/browser/webui/url_data_manager_backend.cc
@@ -28,7 +28,6 @@
 #include "content/browser/blob_storage/chrome_blob_storage_context.h"
 #include "content/browser/histogram_internals_request_job.h"
 #include "content/browser/net/view_blob_internals_job_factory.h"
-#include "content/browser/net/view_http_cache_job_factory.h"
 #include "content/browser/resource_context_impl.h"
 #include "content/browser/webui/shared_resources_data_source.h"
 #include "content/browser/webui/url_data_source_impl.h"
@@ -354,11 +353,6 @@
       net::NetworkDelegate* network_delegate) const override {
     DCHECK(request);
 
-    // Check for chrome://view-http-cache/*, which uses its own job type.
-    if (ViewHttpCacheJobFactory::IsSupportedURL(request->url()))
-      return ViewHttpCacheJobFactory::CreateJobForRequest(request,
-                                                          network_delegate);
-
     // Next check for chrome://blob-internals/, which uses its own job type.
     if (ViewBlobInternalsJobFactory::IsSupportedURL(request->url())) {
       return ViewBlobInternalsJobFactory::CreateJobForRequest(
diff --git a/content/browser/webui/web_ui_browsertest.cc b/content/browser/webui/web_ui_browsertest.cc
deleted file mode 100644
index a89a9e9..0000000
--- a/content/browser/webui/web_ui_browsertest.cc
+++ /dev/null
@@ -1,30 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "content/public/common/url_constants.h"
-#include "content/public/test/browser_test_utils.h"
-#include "content/public/test/content_browser_test.h"
-#include "content/public/test/content_browser_test_utils.h"
-#include "content/shell/browser/shell.h"
-#include "net/test/embedded_test_server/embedded_test_server.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace content {
-
-using WebUIBrowserTest = ContentBrowserTest;
-
-IN_PROC_BROWSER_TEST_F(WebUIBrowserTest, ViewCache) {
-  ASSERT_TRUE(embedded_test_server()->Start());
-  NavigateToURL(shell(), embedded_test_server()->GetURL("/simple_page.html"));
-  int result = -1;
-  NavigateToURL(shell(), GURL(kChromeUINetworkViewCacheURL));
-  std::string script(
-      "document.documentElement.innerHTML.indexOf('simple_page.html')");
-  ASSERT_TRUE(ExecuteScriptAndExtractInt(
-      shell()->web_contents(), "domAutomationController.send(" + script + ")",
-      &result));
-  ASSERT_NE(-1, result);
-}
-
-}  // namespace content
diff --git a/content/browser/webui/web_ui_url_loader_factory.cc b/content/browser/webui/web_ui_url_loader_factory.cc
index 64e1e949..32457c8 100644
--- a/content/browser/webui/web_ui_url_loader_factory.cc
+++ b/content/browser/webui/web_ui_url_loader_factory.cc
@@ -247,12 +247,6 @@
       return;
     }
 
-    if (request.url.host_piece() == kChromeUINetworkViewCacheHost) {
-      GetStoragePartition()->GetNetworkContext()->HandleViewCacheRequest(
-          request.url, std::move(client));
-      return;
-    }
-
     if (request.url.host_piece() == kChromeUIBlobInternalsHost) {
       BrowserThread::PostTask(
           BrowserThread::IO, FROM_HERE,
diff --git a/content/common/view_messages.h b/content/common/view_messages.h
index da2315d4..0d22109 100644
--- a/content/common/view_messages.h
+++ b/content/common/view_messages.h
@@ -763,10 +763,6 @@
 // Sent in reply to ViewMsg_WaitForNextFrameForTests.
 IPC_MESSAGE_ROUTED0(ViewHostMsg_WaitForNextFrameForTests_ACK)
 
-// Sent once a frame with new RenderFrameMetadata has been submitted.
-IPC_MESSAGE_ROUTED1(ViewHostMsg_OnRenderFrameSubmitted,
-                    cc::RenderFrameMetadata /* metadata */)
-
 // Acknowledges that a SelectWordAroundCaret completed with the specified
 // result and adjustments to the selection offsets.
 IPC_MESSAGE_ROUTED3(ViewHostMsg_SelectWordAroundCaretAck,
diff --git a/content/public/browser/BUILD.gn b/content/public/browser/BUILD.gn
index 36f30b5..5290ba7 100644
--- a/content/public/browser/BUILD.gn
+++ b/content/public/browser/BUILD.gn
@@ -56,7 +56,6 @@
     "browser_accessibility_state.h",
     "browser_associated_interface.h",
     "browser_child_process_host.h",
-    "browser_child_process_host_delegate.cc",
     "browser_child_process_host_delegate.h",
     "browser_child_process_host_iterator.cc",
     "browser_child_process_host_iterator.h",
diff --git a/content/public/browser/browser_child_process_host_delegate.cc b/content/public/browser/browser_child_process_host_delegate.cc
deleted file mode 100644
index 06a7c6d..0000000
--- a/content/public/browser/browser_child_process_host_delegate.cc
+++ /dev/null
@@ -1,13 +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 "content/public/browser/browser_child_process_host_delegate.h"
-
-namespace content {
-
-bool BrowserChildProcessHostDelegate::CanShutdown() {
-  return true;
-}
-
-}  // namespace content
diff --git a/content/public/browser/browser_child_process_host_delegate.h b/content/public/browser/browser_child_process_host_delegate.h
index a0862860..8acc006 100644
--- a/content/public/browser/browser_child_process_host_delegate.h
+++ b/content/public/browser/browser_child_process_host_delegate.h
@@ -15,12 +15,6 @@
  public:
   ~BrowserChildProcessHostDelegate() override {}
 
-  // Delegates return true if it's ok to shut down the child process (which is
-  // the default return value). The exception is if the host is in the middle of
-  // sending a request to the process, in which case the other side might think
-  // it's ok to shutdown, when really it's not.
-  virtual bool CanShutdown();
-
   // Called when the process has been started.
   virtual void OnProcessLaunched() {}
 
diff --git a/content/public/common/BUILD.gn b/content/public/common/BUILD.gn
index 16e5b6e..a766b5f 100644
--- a/content/public/common/BUILD.gn
+++ b/content/public/common/BUILD.gn
@@ -117,7 +117,6 @@
     "browser_side_navigation_policy.h",
     "cdm_info.h",
     "child_process_host.h",
-    "child_process_host_delegate.cc",
     "child_process_host_delegate.h",
     "common_param_traits.cc",
     "common_param_traits.h",
diff --git a/content/public/common/child_process_host.h b/content/public/common/child_process_host.h
index b19dd40..926137f 100644
--- a/content/public/common/child_process_host.h
+++ b/content/public/common/child_process_host.h
@@ -69,7 +69,6 @@
   static base::FilePath GetChildPath(int flags);
 
   // Send the shutdown message to the child process.
-  // Does not check with the delegate's CanShutdown.
   virtual void ForceShutdown() = 0;
 
   // Creates the IPC channel over a Mojo message pipe. The pipe connection is
diff --git a/content/public/common/child_process_host_delegate.cc b/content/public/common/child_process_host_delegate.cc
deleted file mode 100644
index 85b0398..0000000
--- a/content/public/common/child_process_host_delegate.cc
+++ /dev/null
@@ -1,13 +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 "content/public/common/child_process_host_delegate.h"
-
-namespace content {
-
-bool ChildProcessHostDelegate::CanShutdown() {
-  return true;
-}
-
-}  // namespace content
diff --git a/content/public/common/child_process_host_delegate.h b/content/public/common/child_process_host_delegate.h
index 274d2e33..9612991 100644
--- a/content/public/common/child_process_host_delegate.h
+++ b/content/public/common/child_process_host_delegate.h
@@ -23,12 +23,6 @@
  public:
   ~ChildProcessHostDelegate() override {}
 
-  // Delegates return true if it's ok to shut down the child process (which is
-  // the default return value). The exception is if the host is in the middle of
-  // sending a request to the process, in which case the other side might think
-  // it's ok to shutdown, when really it's not.
-  CONTENT_EXPORT virtual bool CanShutdown();
-
   // Called when the IPC channel for the child process is initialized.
   virtual void OnChannelInitialized(IPC::Channel* channel) {}
 
diff --git a/content/public/common/url_constants.cc b/content/public/common/url_constants.cc
index 00fd70c..4bfbb922a1 100644
--- a/content/public/common/url_constants.cc
+++ b/content/public/common/url_constants.cc
@@ -30,7 +30,6 @@
 const char kChromeUIHistogramHost[] = "histograms";
 const char kChromeUIMediaInternalsHost[] = "media-internals";
 const char kChromeUIMemoryExhaustHost[] = "memory-exhaust";
-const char kChromeUINetworkViewCacheHost[] = "view-http-cache";
 const char kChromeUINetworkErrorHost[] = "network-error";
 const char kChromeUINetworkErrorsListingHost[] = "network-errors";
 const char kChromeUIResourcesHost[] = "resources";
@@ -74,7 +73,6 @@
 // have a chrome:// scheme that might let it be confused with a WebUI page.
 const char kUnreachableWebDataURL[] = "chrome-error://chromewebdata/";
 
-const char kChromeUINetworkViewCacheURL[] = "chrome://view-http-cache/";
 const char kChromeUIResourcesURL[] = "chrome://resources/";
 const char kChromeUIShorthangURL[] = "chrome://shorthang/";
 
diff --git a/content/public/common/url_constants.h b/content/public/common/url_constants.h
index 001f000..f51416f 100644
--- a/content/public/common/url_constants.h
+++ b/content/public/common/url_constants.h
@@ -40,7 +40,6 @@
 CONTENT_EXPORT extern const char kChromeUIMemoryExhaustHost[];
 CONTENT_EXPORT extern const char kChromeUINetworkErrorHost[];
 CONTENT_EXPORT extern const char kChromeUINetworkErrorsListingHost[];
-CONTENT_EXPORT extern const char kChromeUINetworkViewCacheHost[];
 CONTENT_EXPORT extern const char kChromeUIResourcesHost[];
 CONTENT_EXPORT extern const char kChromeUIServiceWorkerInternalsHost[];
 CONTENT_EXPORT extern const char kChromeUITracingHost[];
diff --git a/content/renderer/gpu/queue_message_swap_promise.cc b/content/renderer/gpu/queue_message_swap_promise.cc
index 9dffc37..b045b83 100644
--- a/content/renderer/gpu/queue_message_swap_promise.cc
+++ b/content/renderer/gpu/queue_message_swap_promise.cc
@@ -46,9 +46,7 @@
   // The OutputSurface will take care of the Drain+Send.
 }
 
-void QueueMessageSwapPromise::WillSwap(
-    viz::CompositorFrameMetadata* compositor_frame_metadata,
-    cc::RenderFrameMetadata* render_frame_metadata) {
+void QueueMessageSwapPromise::WillSwap(viz::CompositorFrameMetadata* metadata) {
 #if DCHECK_IS_ON()
   DCHECK(!completed_);
 #endif
@@ -60,16 +58,12 @@
     std::vector<std::unique_ptr<IPC::Message>> messages;
     message_queue_->DrainMessages(&messages);
 
-    messages.push_back(std::make_unique<ViewHostMsg_OnRenderFrameSubmitted>(
-        message_queue_->routing_id(), *render_frame_metadata));
-
     std::vector<IPC::Message> messages_to_send;
     FrameSwapMessageQueue::TransferMessages(&messages, &messages_to_send);
     if (!messages_to_send.empty()) {
-      compositor_frame_metadata->frame_token =
-          message_queue_->AllocateFrameToken();
+      metadata->frame_token = message_queue_->AllocateFrameToken();
       message_sender_->Send(new ViewHostMsg_FrameSwapMessages(
-          message_queue_->routing_id(), compositor_frame_metadata->frame_token,
+          message_queue_->routing_id(), metadata->frame_token,
           messages_to_send));
     }
   }
diff --git a/content/renderer/gpu/queue_message_swap_promise.h b/content/renderer/gpu/queue_message_swap_promise.h
index 074337f..f888f2f 100644
--- a/content/renderer/gpu/queue_message_swap_promise.h
+++ b/content/renderer/gpu/queue_message_swap_promise.h
@@ -8,7 +8,6 @@
 #include <stdint.h>
 
 #include "base/memory/ref_counted.h"
-#include "cc/trees/render_frame_metadata.h"
 #include "cc/trees/swap_promise.h"
 
 namespace IPC {
@@ -28,8 +27,7 @@
   ~QueueMessageSwapPromise() override;
 
   void DidActivate() override;
-  void WillSwap(viz::CompositorFrameMetadata* compositor_frame_metadata,
-                cc::RenderFrameMetadata* render_frame_metadata) override;
+  void WillSwap(viz::CompositorFrameMetadata* metadata) override;
   void DidSwap() override;
   DidNotSwapAction DidNotSwap(DidNotSwapReason reason) override;
 
diff --git a/content/renderer/gpu/queue_message_swap_promise_unittest.cc b/content/renderer/gpu/queue_message_swap_promise_unittest.cc
index 4929bd45..eb1b54cc 100644
--- a/content/renderer/gpu/queue_message_swap_promise_unittest.cc
+++ b/content/renderer/gpu/queue_message_swap_promise_unittest.cc
@@ -12,7 +12,6 @@
 #include "base/macros.h"
 #include "base/memory/ptr_util.h"
 #include "base/test/scoped_task_environment.h"
-#include "cc/trees/render_frame_metadata.h"
 #include "cc/trees/swap_promise.h"
 #include "content/common/view_messages.h"
 #include "content/renderer/gpu/frame_swap_message_queue.h"
@@ -146,8 +145,7 @@
     for (const auto& promise : promises_) {
       if (promise.get()) {
         promise->DidActivate();
-        promise->WillSwap(&dummy_compositor_frame_metadata_,
-                          &dummy_render_frame_metadata_);
+        promise->WillSwap(&dummy_metadata_);
         promise->DidSwap();
       }
     }
@@ -162,7 +160,7 @@
   scoped_refptr<TestSyncMessageFilter> sync_message_filter_;
   std::vector<IPC::Message> messages_;
   std::vector<std::unique_ptr<cc::SwapPromise>> promises_;
-  viz::CompositorFrameMetadata dummy_compositor_frame_metadata_;
+  viz::CompositorFrameMetadata dummy_metadata_;
   cc::RenderFrameMetadata dummy_render_frame_metadata_;
 
  private:
@@ -180,8 +178,7 @@
 
   ASSERT_TRUE(promises_[0].get());
   promises_[0]->DidActivate();
-  promises_[0]->WillSwap(&dummy_compositor_frame_metadata_,
-                         &dummy_render_frame_metadata_);
+  promises_[0]->WillSwap(&dummy_metadata_);
   promises_[0]->DidSwap();
 
   EXPECT_TRUE(DirectSendMessages().empty());
@@ -286,13 +283,12 @@
   QueueMessages(data, arraysize(data));
 
   promises_[0]->DidActivate();
-  promises_[0]->WillSwap(&dummy_compositor_frame_metadata_,
-                         &dummy_render_frame_metadata_);
+  promises_[0]->WillSwap(&dummy_metadata_);
   promises_[0]->DidSwap();
   ASSERT_FALSE(promises_[1].get());
   std::vector<std::unique_ptr<IPC::Message>> messages;
   messages.swap(LastSwapMessages());
-  EXPECT_EQ(3u, messages.size());
+  EXPECT_EQ(2u, messages.size());
   EXPECT_TRUE(ContainsMessage(messages, messages_[0]));
   EXPECT_TRUE(ContainsMessage(messages, messages_[1]));
   EXPECT_FALSE(ContainsMessage(messages, messages_[2]));
diff --git a/content/renderer/gpu/render_widget_compositor.cc b/content/renderer/gpu/render_widget_compositor.cc
index 06b15e8..4ef2c48 100644
--- a/content/renderer/gpu/render_widget_compositor.cc
+++ b/content/renderer/gpu/render_widget_compositor.cc
@@ -52,6 +52,7 @@
 #include "components/viz/common/frame_sinks/copy_output_request.h"
 #include "components/viz/common/frame_sinks/copy_output_result.h"
 #include "components/viz/common/resources/single_release_callback.h"
+#include "components/viz/common/switches.h"
 #include "content/common/content_switches_internal.h"
 #include "content/common/layer_tree_settings_factory.h"
 #include "content/common/render_frame_metadata.mojom.h"
@@ -115,8 +116,7 @@
   ~ReportTimeSwapPromise() override;
 
   void DidActivate() override {}
-  void WillSwap(viz::CompositorFrameMetadata* compositor_frame_metadata,
-                cc::RenderFrameMetadata* render_frame_metadata) override {}
+  void WillSwap(viz::CompositorFrameMetadata* metadata) override {}
   void DidSwap() override;
   DidNotSwapAction DidNotSwap(DidNotSwapReason reason) override;
 
@@ -589,7 +589,7 @@
   settings.disallow_non_exact_resource_reuse = true;
 #endif
 
-  if (cmd.HasSwitch(cc::switches::kRunAllCompositorStagesBeforeDraw)) {
+  if (cmd.HasSwitch(switches::kRunAllCompositorStagesBeforeDraw)) {
     settings.wait_for_all_pipeline_stages_before_draw = true;
     settings.enable_latency_recovery = false;
   }
diff --git a/content/renderer/render_view_impl.cc b/content/renderer/render_view_impl.cc
index c2376b9..8d25c0dc 100644
--- a/content/renderer/render_view_impl.cc
+++ b/content/renderer/render_view_impl.cc
@@ -426,10 +426,9 @@
 
   void DidActivate() override {}
 
-  void WillSwap(viz::CompositorFrameMetadata* compositor_frame_metadata,
-                cc::RenderFrameMetadata* render_frame_metadata) override {
+  void WillSwap(viz::CompositorFrameMetadata* metadata) override {
     DCHECK(!latency_info_.terminated());
-    compositor_frame_metadata->latency_info.push_back(latency_info_);
+    metadata->latency_info.push_back(latency_info_);
   }
 
   void DidSwap() override {}
diff --git a/content/shell/android/browsertests_apk/src/org/chromium/content_browsertests_apk/ContentBrowserTestsApplication.java b/content/shell/android/browsertests_apk/src/org/chromium/content_browsertests_apk/ContentBrowserTestsApplication.java
index e773ae6..752627d9 100644
--- a/content/shell/android/browsertests_apk/src/org/chromium/content_browsertests_apk/ContentBrowserTestsApplication.java
+++ b/content/shell/android/browsertests_apk/src/org/chromium/content_browsertests_apk/ContentBrowserTestsApplication.java
@@ -4,22 +4,27 @@
 
 package org.chromium.content_browsertests_apk;
 
+import android.app.Application;
 import android.content.Context;
 
 import org.chromium.base.ApplicationStatus;
-import org.chromium.base.BaseChromiumApplication;
+import org.chromium.base.BuildConfig;
 import org.chromium.base.ContextUtils;
 import org.chromium.base.PathUtils;
+import org.chromium.base.multidex.ChromiumMultiDexInstaller;
 
 /**
  * A basic content browser tests {@link android.app.Application}.
  */
-public class ContentBrowserTestsApplication extends BaseChromiumApplication {
+public class ContentBrowserTestsApplication extends Application {
     static final String PRIVATE_DATA_DIRECTORY_SUFFIX = "content_shell";
 
     @Override
     protected void attachBaseContext(Context base) {
         super.attachBaseContext(base);
+        if (BuildConfig.isMultidexEnabled()) {
+            ChromiumMultiDexInstaller.install(this);
+        }
         ContextUtils.initApplicationContext(this);
     }
 
diff --git a/content/shell/android/linker_test_apk/src/org/chromium/chromium_linker_test_apk/ChromiumLinkerTestApplication.java b/content/shell/android/linker_test_apk/src/org/chromium/chromium_linker_test_apk/ChromiumLinkerTestApplication.java
index 231328d2..bf51d3e2 100644
--- a/content/shell/android/linker_test_apk/src/org/chromium/chromium_linker_test_apk/ChromiumLinkerTestApplication.java
+++ b/content/shell/android/linker_test_apk/src/org/chromium/chromium_linker_test_apk/ChromiumLinkerTestApplication.java
@@ -4,21 +4,26 @@
 
 package org.chromium.chromium_linker_test_apk;
 
+import android.app.Application;
 import android.content.Context;
 
-import org.chromium.base.BaseChromiumApplication;
+import org.chromium.base.BuildConfig;
 import org.chromium.base.ContextUtils;
 import org.chromium.base.PathUtils;
+import org.chromium.base.multidex.ChromiumMultiDexInstaller;
 
 /**
  * Application for testing the Chromium Linker
  */
-public class ChromiumLinkerTestApplication extends BaseChromiumApplication {
+public class ChromiumLinkerTestApplication extends Application {
     private static final String PRIVATE_DATA_DIRECTORY_SUFFIX = "chromium_linker_test";
 
     @Override
     protected void attachBaseContext(Context base) {
         super.attachBaseContext(base);
+        if (BuildConfig.isMultidexEnabled()) {
+            ChromiumMultiDexInstaller.install(this);
+        }
         ContextUtils.initApplicationContext(this);
     }
 
diff --git a/content/shell/android/shell_apk/src/org/chromium/content_shell_apk/ContentShellApplication.java b/content/shell/android/shell_apk/src/org/chromium/content_shell_apk/ContentShellApplication.java
index d9846520..b41c605 100644
--- a/content/shell/android/shell_apk/src/org/chromium/content_shell_apk/ContentShellApplication.java
+++ b/content/shell/android/shell_apk/src/org/chromium/content_shell_apk/ContentShellApplication.java
@@ -4,25 +4,30 @@
 
 package org.chromium.content_shell_apk;
 
+import android.app.Application;
 import android.content.Context;
 
 import org.chromium.base.ApplicationStatus;
-import org.chromium.base.BaseChromiumApplication;
+import org.chromium.base.BuildConfig;
 import org.chromium.base.CommandLine;
 import org.chromium.base.ContextUtils;
 import org.chromium.base.PathUtils;
+import org.chromium.base.multidex.ChromiumMultiDexInstaller;
 
 /**
  * Entry point for the content shell application.  Handles initialization of information that needs
  * to be shared across the main activity and the child services created.
  */
-public class ContentShellApplication extends BaseChromiumApplication {
+public class ContentShellApplication extends Application {
     public static final String COMMAND_LINE_FILE = "/data/local/tmp/content-shell-command-line";
     private static final String PRIVATE_DATA_DIRECTORY_SUFFIX = "content_shell";
 
     @Override
     protected void attachBaseContext(Context base) {
         super.attachBaseContext(base);
+        if (BuildConfig.isMultidexEnabled()) {
+            ChromiumMultiDexInstaller.install(this);
+        }
         ContextUtils.initApplicationContext(this);
         PathUtils.setPrivateDataDirectorySuffix(PRIVATE_DATA_DIRECTORY_SUFFIX);
         ApplicationStatus.initialize(this);
diff --git a/content/test/BUILD.gn b/content/test/BUILD.gn
index 3ff735c..97336660 100644
--- a/content/test/BUILD.gn
+++ b/content/test/BUILD.gn
@@ -7,6 +7,7 @@
 import("//build/config/compiler/compiler.gni")
 import("//build/config/crypto.gni")
 import("//build/config/features.gni")
+import("//build/config/jumbo.gni")
 import("//build/config/ui.gni")
 import("//media/media_options.gni")
 import("//net/features.gni")
@@ -20,7 +21,7 @@
 
 # Use a static library here because many test binaries depend on this but don't
 # require many files from it. This makes linking more efficient.
-static_library("test_support") {
+jumbo_static_library("test_support") {
   testonly = true
 
   # See comment at the top of //content/BUILD.gn for why this is disabled in
@@ -54,6 +55,8 @@
     "../browser/service_worker/embedded_worker_test_helper.h",
     "../browser/service_worker/service_worker_test_utils.cc",
     "../browser/service_worker/service_worker_test_utils.h",
+    "../browser/web_package/mock_signed_exchange_handler.cc",
+    "../browser/web_package/mock_signed_exchange_handler.h",
     "../public/test/background_sync_test_util.cc",
     "../public/test/background_sync_test_util.h",
     "../public/test/blink_test_environment.cc",
@@ -488,7 +491,7 @@
 
 # browsertest_support can be used by targets that run content_shell based
 # browser tests.
-static_library("browsertest_support") {
+jumbo_static_library("browsertest_support") {
   testonly = true
 
   # See comment at the top of //content/BUILD.gn for why this is disabled in
@@ -821,7 +824,6 @@
     "../browser/web_contents_binding_set_browsertest.cc",
     "../browser/web_package/web_package_request_handler_browsertest.cc",
     "../browser/webkit_browsertest.cc",
-    "../browser/webui/web_ui_browsertest.cc",
     "../browser/webui/web_ui_mojo_browsertest.cc",
     "../renderer/accessibility/render_accessibility_impl_browsertest.cc",
     "../renderer/blink_platform_audio_hardware_browsertest.cc",
diff --git a/content/test/gpu/generate_buildbot_json.py b/content/test/gpu/generate_buildbot_json.py
index df9f7e4..d2f862b0 100755
--- a/content/test/gpu/generate_buildbot_json.py
+++ b/content/test/gpu/generate_buildbot_json.py
@@ -58,6 +58,9 @@
   # The experimental try servers are meant to test new driver versions
   # and OS flavors.
   EXPERIMENTAL = 'experimental'
+  # This deliberately doesn't match any predicate, and is used to
+  # completely disable a particular trybot.
+  NOOP = 'noop'
 
 # The predicate functions receive a list of types as input and
 # determine whether the test should run on the given bot.
@@ -69,7 +72,8 @@
     # tryservers, not on the client.v8.fyi waterfall, nor on the Win
     # ANGLE AMD tryserver.
     return Types.DEQP not in x and Types.OPTIONAL not in x and \
-      Types.V8_FYI not in x and Types.WIN_ANGLE_AMD_TRYSERVER not in x
+      Types.V8_FYI not in x and Types.WIN_ANGLE_AMD_TRYSERVER not in x and \
+      Types.NOOP not in x
 
   @staticmethod
   def FYI_ONLY(x):
@@ -77,8 +81,8 @@
     # tryservers and the Win ANGLE AMD tryserver are considered to be
     # on the chromium.gpu.fyi waterfall.
     return Types.GPU_FYI in x and Types.DEQP not in x and \
-      Types.OPTIONAL not in x and \
-      Types.WIN_ANGLE_AMD_TRYSERVER not in x
+      Types.OPTIONAL not in x and Types.WIN_ANGLE_AMD_TRYSERVER not in x and \
+      Types.NOOP not in x
 
   @staticmethod
   def FYI_AND_OPTIONAL(x):
@@ -114,6 +118,10 @@
   def EXPERIMENTAL_CONDITIONALLY(x):
     return Types.EXPERIMENTAL in x
 
+  @staticmethod
+  def EXPERIMENTAL_CONDITIONALLY_OR_NOOP(x):
+    return Types.EXPERIMENTAL in x or Types.NOOP in x
+
 # Most of the bots live in the Chrome-GPU pool as defined here (Google
 # employees only, sorry):
 # https://chrome-internal.googlesource.com/infradata/config/+/master/configs/
@@ -910,6 +918,19 @@
       'os_type': 'linux',
       'type': Types.OPTIONAL,
     },
+    'Optional Android Release (Nexus 5X)': {
+      'swarming_dimensions': [
+        {
+          'device_type': 'bullhead',
+          'device_os': 'MMB29Q',
+          'os': 'Android'
+        },
+      ],
+      'build_config': 'android-chromium',
+      'swarming': True,
+      'os_type': 'android',
+      'type': Types.NOOP,
+    },
     # This tryserver doesn't actually exist; it's a separate
     # configuration from the Win AMD bot on this waterfall because we
     # don't have enough tryserver capacity to run all the tests from
@@ -1954,7 +1975,7 @@
     'tester_configs': [
       {
         # Only run the noop sleep test on experimental configs.
-        'predicate': Predicates.EXPERIMENTAL_CONDITIONALLY,
+        'predicate': Predicates.EXPERIMENTAL_CONDITIONALLY_OR_NOOP,
         'disabled_instrumentation_types': ['tsan'],
       },
     ],
@@ -2575,7 +2596,8 @@
   if 'tester_configs' in test_config:
     for tc in test_config['tester_configs']:
       pred = tc.get('predicate', Predicates.DEFAULT)
-      if (pred == Predicates.EXPERIMENTAL_CONDITIONALLY):
+      if (pred == Predicates.EXPERIMENTAL_CONDITIONALLY or \
+          pred == Predicates.EXPERIMENTAL_CONDITIONALLY_OR_NOOP):
         return True
   return False
 
diff --git a/content/test/layouttest_support.cc b/content/test/layouttest_support.cc
index 1814b99..4f00036 100644
--- a/content/test/layouttest_support.cc
+++ b/content/test/layouttest_support.cc
@@ -286,8 +286,7 @@
     DCHECK(layer_tree_frame_sink_from_commit_);
   }
   void DidActivate() override {}
-  void WillSwap(viz::CompositorFrameMetadata*,
-                cc::RenderFrameMetadata*) override {
+  void WillSwap(viz::CompositorFrameMetadata*) override {
     layer_tree_frame_sink_from_commit_->RequestCopyOfOutput(
         std::move(copy_request_));
   }
diff --git a/crypto/nss_util.cc b/crypto/nss_util.cc
index e5a6d6f6..b5aabd3 100644
--- a/crypto/nss_util.cc
+++ b/crypto/nss_util.cc
@@ -325,7 +325,7 @@
                        system_slot_id, tpm_args_ptr),
         base::BindOnce(&NSSInitSingleton::OnInitializedTPMTokenAndSystemSlot,
                        base::Unretained(this),  // NSSInitSingleton is leaky
-                       callback, base::Passed(&tpm_args)));
+                       callback, std::move(tpm_args)));
     initializing_tpm_token_ = true;
   }
 
@@ -488,7 +488,7 @@
                        slot_id, tpm_args_ptr),
         base::BindOnce(&NSSInitSingleton::OnInitializedTPMForChromeOSUser,
                        base::Unretained(this),  // NSSInitSingleton is leaky
-                       username_hash, base::Passed(&tpm_args)));
+                       username_hash, std::move(tpm_args)));
   }
 
   void OnInitializedTPMForChromeOSUser(
@@ -538,7 +538,7 @@
       DVLOG(2) << "empty username_hash";
       if (!callback.is_null()) {
         base::ThreadTaskRunnerHandle::Get()->PostTask(
-            FROM_HERE, base::Bind(callback, base::Passed(ScopedPK11Slot())));
+            FROM_HERE, base::BindOnce(callback, ScopedPK11Slot()));
       }
       return ScopedPK11Slot();
     }
diff --git a/dbus/exported_object.cc b/dbus/exported_object.cc
index 4fdd33a..aa6a7c8 100644
--- a/dbus/exported_object.cc
+++ b/dbus/exported_object.cc
@@ -220,12 +220,10 @@
   const base::TimeTicks start_time = base::TimeTicks::Now();
   if (bus_->HasDBusThread()) {
     // Post a task to run the method in the origin thread.
-    bus_->GetOriginTaskRunner()->PostTask(FROM_HERE,
-                                          base::Bind(&ExportedObject::RunMethod,
-                                                     this,
-                                                     iter->second,
-                                                     base::Passed(&method_call),
-                                                     start_time));
+    bus_->GetOriginTaskRunner()->PostTask(
+        FROM_HERE,
+        base::BindOnce(&ExportedObject::RunMethod, this, iter->second,
+                       std::move(method_call), start_time));
   } else {
     // If the D-Bus thread is not used, just call the method directly.
     MethodCall* method = method_call.get();
@@ -259,12 +257,9 @@
   DCHECK(method_call);
   if (bus_->HasDBusThread()) {
     bus_->GetDBusTaskRunner()->PostTask(
-        FROM_HERE,
-        base::Bind(&ExportedObject::OnMethodCompleted,
-                   this,
-                   base::Passed(&method_call),
-                   base::Passed(&response),
-                   start_time));
+        FROM_HERE, base::BindOnce(&ExportedObject::OnMethodCompleted, this,
+                                  std::move(method_call), std::move(response),
+                                  start_time));
   } else {
     OnMethodCompleted(std::move(method_call), std::move(response), start_time);
   }
diff --git a/dbus/mock_unittest.cc b/dbus/mock_unittest.cc
index 34327cd..aa26bc4 100644
--- a/dbus/mock_unittest.cc
+++ b/dbus/mock_unittest.cc
@@ -126,7 +126,7 @@
     message_loop_.task_runner()->PostTask(
         FROM_HERE,
         base::BindOnce(&MockTest::RunResponseCallback, base::Unretained(this),
-                       std::move(*response_callback), base::Passed(&response)));
+                       std::move(*response_callback), std::move(response)));
   }
 
   // Runs the given response callback with the given response.
diff --git a/device/bluetooth/bluetooth_socket_win.cc b/device/bluetooth/bluetooth_socket_win.cc
index 6ea00df..c7db830d 100644
--- a/device/bluetooth/bluetooth_socket_win.cc
+++ b/device/bluetooth/bluetooth_socket_win.cc
@@ -363,13 +363,9 @@
   }
 
   ui_task_runner()->PostTask(
-    FROM_HERE,
-    base::Bind(&BluetoothSocketWin::OnAcceptOnUI,
-               this,
-               base::Passed(&accept_socket_),
-               accept_address_,
-               success_callback,
-               error_callback));
+      FROM_HERE, base::BindOnce(&BluetoothSocketWin::OnAcceptOnUI, this,
+                                std::move(accept_socket_), accept_address_,
+                                success_callback, error_callback));
 }
 
 void BluetoothSocketWin::OnAcceptOnUI(
diff --git a/device/bluetooth/bluetooth_task_manager_win.cc b/device/bluetooth/bluetooth_task_manager_win.cc
index 81fe1f5..5386145 100644
--- a/device/bluetooth/bluetooth_task_manager_win.cc
+++ b/device/bluetooth/bluetooth_task_manager_win.cc
@@ -9,6 +9,7 @@
 
 #include <memory>
 #include <string>
+#include <utility>
 
 #include "base/bind.h"
 #include "base/memory/ptr_util.h"
@@ -176,7 +177,7 @@
     return;
 
   it->second->callback_task_runner->PostTask(
-      FROM_HERE, base::Bind(it->second->callback, base::Passed(&new_value)));
+      FROM_HERE, base::BindOnce(it->second->callback, std::move(new_value)));
 }
 
 }  // namespace
@@ -467,8 +468,8 @@
   std::vector<std::unique_ptr<DeviceState>> device_list;
   if (SearchDevices(timeout_multiplier, false, &device_list)) {
     ui_task_runner_->PostTask(
-        FROM_HERE, base::Bind(&BluetoothTaskManagerWin::OnDevicesPolled, this,
-                              base::Passed(&device_list)));
+        FROM_HERE, base::BindOnce(&BluetoothTaskManagerWin::OnDevicesPolled,
+                                  this, std::move(device_list)));
   }
 
   if (timeout_multiplier < kMaxDeviceDiscoveryTimeoutMultiplier)
@@ -483,8 +484,8 @@
   std::vector<std::unique_ptr<DeviceState>> device_list;
   if (SearchDevices(1, true, &device_list)) {
     ui_task_runner_->PostTask(
-        FROM_HERE, base::Bind(&BluetoothTaskManagerWin::OnDevicesPolled, this,
-                              base::Passed(&device_list)));
+        FROM_HERE, base::BindOnce(&BluetoothTaskManagerWin::OnDevicesPolled,
+                                  this, std::move(device_list)));
   }
 }
 
@@ -829,8 +830,8 @@
   }
 
   ui_task_runner_->PostTask(
-      FROM_HERE, base::Bind(callback, base::Passed(&win_characteristics_info),
-                            number_of_charateristics, hr));
+      FROM_HERE, base::BindOnce(callback, std::move(win_characteristics_info),
+                                number_of_charateristics, hr));
 }
 
 void BluetoothTaskManagerWin::GetGattIncludedDescriptors(
@@ -847,8 +848,8 @@
               &win_descriptors_info, &number_of_descriptors);
 
   ui_task_runner_->PostTask(
-      FROM_HERE, base::Bind(callback, base::Passed(&win_descriptors_info),
-                            number_of_descriptors, hr));
+      FROM_HERE, base::BindOnce(callback, std::move(win_descriptors_info),
+                                number_of_descriptors, hr));
 }
 
 void BluetoothTaskManagerWin::ReadGattCharacteristicValue(
@@ -863,7 +864,7 @@
 
   ui_task_runner_->PostTask(
       FROM_HERE,
-      base::Bind(callback, base::Passed(&win_characteristic_value), hr));
+      base::BindOnce(callback, std::move(win_characteristic_value), hr));
 }
 
 void BluetoothTaskManagerWin::WriteGattCharacteristicValue(
diff --git a/device/bluetooth/bluez/bluetooth_socket_bluez.cc b/device/bluetooth/bluez/bluetooth_socket_bluez.cc
index b1c8753ad0..fe26649c5 100644
--- a/device/bluetooth/bluez/bluetooth_socket_bluez.cc
+++ b/device/bluetooth/bluez/bluetooth_socket_bluez.cc
@@ -364,8 +364,8 @@
 
     socket_thread()->task_runner()->PostTask(
         FROM_HERE,
-        base::Bind(&BluetoothSocketBlueZ::DoNewConnection, this, device_path_,
-                   base::Passed(&fd), options, callback));
+        base::BindOnce(&BluetoothSocketBlueZ::DoNewConnection, this,
+                       device_path_, std::move(fd), options, callback));
   } else {
     linked_ptr<ConnectionRequest> request(new ConnectionRequest());
     request->device_path = device_path;
@@ -437,11 +437,11 @@
 
   socket_thread()->task_runner()->PostTask(
       FROM_HERE,
-      base::Bind(&BluetoothSocketBlueZ::DoNewConnection, client_socket,
-                 request->device_path, base::Passed(&request->fd),
-                 request->options,
-                 base::Bind(&BluetoothSocketBlueZ::OnNewConnection, this,
-                            client_socket, request->callback)));
+      base::BindOnce(
+          &BluetoothSocketBlueZ::DoNewConnection, client_socket,
+          request->device_path, std::move(request->fd), request->options,
+          base::BindRepeating(&BluetoothSocketBlueZ::OnNewConnection, this,
+                              client_socket, request->callback)));
 }
 
 void BluetoothSocketBlueZ::DoNewConnection(
diff --git a/device/gamepad/gamepad_provider.cc b/device/gamepad/gamepad_provider.cc
index dde5fe62..113a1f6d 100644
--- a/device/gamepad/gamepad_provider.cc
+++ b/device/gamepad/gamepad_provider.cc
@@ -216,8 +216,8 @@
 void GamepadProvider::AddGamepadDataFetcher(
     std::unique_ptr<GamepadDataFetcher> fetcher) {
   polling_thread_->task_runner()->PostTask(
-      FROM_HERE, base::Bind(&GamepadProvider::DoAddGamepadDataFetcher,
-                            base::Unretained(this), base::Passed(&fetcher)));
+      FROM_HERE, base::BindOnce(&GamepadProvider::DoAddGamepadDataFetcher,
+                                base::Unretained(this), std::move(fetcher)));
 }
 
 void GamepadProvider::RemoveSourceGamepadDataFetcher(GamepadSource source) {
diff --git a/device/usb/usb_descriptors.cc b/device/usb/usb_descriptors.cc
index b654a28..ba254f6c 100644
--- a/device/usb/usb_descriptors.cc
+++ b/device/usb/usb_descriptors.cc
@@ -8,6 +8,7 @@
 
 #include <algorithm>
 #include <memory>
+#include <utility>
 #include <vector>
 
 #include "base/barrier_closure.h"
@@ -120,7 +121,7 @@
         UsbControlTransferRecipient::DEVICE, kGetDescriptorRequest,
         kConfigurationDescriptorType << 8 | index, 0, buffer,
         kControlTransferTimeoutMs,
-        base::Bind(&OnReadConfigDescriptor, desc, base::Passed(&closure)));
+        base::BindOnce(&OnReadConfigDescriptor, desc, std::move(closure)));
   } else {
     LOG(ERROR) << "Failed to read length for configuration "
                << static_cast<int>(index) << ".";
@@ -205,7 +206,7 @@
       UsbControlTransferRecipient::DEVICE, kGetDescriptorRequest,
       kStringDescriptorType << 8 | index, language_id, buffer,
       kControlTransferTimeoutMs,
-      base::Bind(&OnReadStringDescriptor, base::Passed(&callback)));
+      base::BindOnce(&OnReadStringDescriptor, std::move(callback)));
 }
 
 void OnReadLanguageIds(scoped_refptr<UsbDeviceHandle> device_handle,
@@ -500,8 +501,8 @@
       UsbTransferDirection::INBOUND, UsbControlTransferType::STANDARD,
       UsbControlTransferRecipient::DEVICE, kGetDescriptorRequest,
       kDeviceDescriptorType << 8, 0, buffer, kControlTransferTimeoutMs,
-      base::Bind(&OnReadDeviceDescriptor, device_handle,
-                 base::Passed(&callback)));
+      base::BindOnce(&OnReadDeviceDescriptor, device_handle,
+                     std::move(callback)));
 }
 
 bool ParseUsbStringDescriptor(const std::vector<uint8_t>& descriptor,
diff --git a/device/usb/usb_service_impl.cc b/device/usb/usb_service_impl.cc
index c6114b1c..bd0cc97a 100644
--- a/device/usb/usb_service_impl.cc
+++ b/device/usb/usb_service_impl.cc
@@ -96,7 +96,7 @@
   }
 
   task_runner->PostTask(FROM_HERE,
-                        base::Bind(callback, base::Passed(&context)));
+                        base::BindOnce(callback, std::move(context)));
 }
 
 void GetDeviceListOnBlockingThread(
@@ -109,7 +109,7 @@
     if (!IsWinUsbInterface(new_device_path)) {
       // Wait to call libusb_get_device_list until libusb will be able to find
       // a WinUSB interface for the device.
-      task_runner->PostTask(FROM_HERE, base::Bind(callback, nullptr, 0));
+      task_runner->PostTask(FROM_HERE, base::BindOnce(callback, nullptr, 0));
       return;
     }
   }
diff --git a/device/vr/android/gvr/gvr_device.cc b/device/vr/android/gvr/gvr_device.cc
index 64b340b..428bd1e 100644
--- a/device/vr/android/gvr/gvr_device.cc
+++ b/device/vr/android/gvr/gvr_device.cc
@@ -6,6 +6,7 @@
 
 #include <math.h>
 #include <algorithm>
+#include <utility>
 
 #include "base/memory/ptr_util.h"
 #include "base/time/time.h"
@@ -163,9 +164,9 @@
   delegate_provider->RequestWebVRPresent(
       std::move(submit_client), std::move(request), GetVRDisplayInfo(),
       std::move(present_options),
-      base::Bind(&GvrDevice::OnRequestPresentResult,
-                 weak_ptr_factory_.GetWeakPtr(), base::Passed(&callback),
-                 base::Unretained(display)));
+      base::BindOnce(&GvrDevice::OnRequestPresentResult,
+                     weak_ptr_factory_.GetWeakPtr(), std::move(callback),
+                     base::Unretained(display)));
 }
 
 void GvrDevice::OnRequestPresentResult(
diff --git a/device/vr/oculus/oculus_device.cc b/device/vr/oculus/oculus_device.cc
index 22436b92..0a4cfb9 100644
--- a/device/vr/oculus/oculus_device.cc
+++ b/device/vr/oculus/oculus_device.cc
@@ -6,6 +6,8 @@
 
 #include <math.h>
 
+#include <utility>
+
 #include "base/memory/ptr_util.h"
 #include "base/numerics/math_constants.h"
 #include "build/build_config.h"
@@ -106,14 +108,13 @@
 
   auto on_request_present_result =
       base::BindOnce(&OculusDevice::OnRequestPresentResult,
-                     weak_ptr_factory_.GetWeakPtr(), base::Passed(&callback));
+                     weak_ptr_factory_.GetWeakPtr(), std::move(callback));
   render_loop_->task_runner()->PostTask(
-      FROM_HERE,
-      base::BindOnce(&OculusRenderLoop::RequestPresent,
-                     render_loop_->GetWeakPtr(),
-                     base::Passed(submit_client.PassInterface()),
-                     base::Passed(&request), std::move(present_options),
-                     base::Passed(&on_request_present_result)));
+      FROM_HERE, base::BindOnce(&OculusRenderLoop::RequestPresent,
+                                render_loop_->GetWeakPtr(),
+                                std::move(submit_client.PassInterface()),
+                                std::move(request), std::move(present_options),
+                                std::move(on_request_present_result)));
 }
 
 void OculusDevice::OnRequestPresentResult(
diff --git a/extensions/browser/updater/extension_downloader.cc b/extensions/browser/updater/extension_downloader.cc
index 35a2cbd..1d96f32 100644
--- a/extensions/browser/updater/extension_downloader.cc
+++ b/extensions/browser/updater/extension_downloader.cc
@@ -88,6 +88,7 @@
 
 const char kNotFromWebstoreInstallSource[] = "notfromwebstore";
 const char kDefaultInstallSource[] = "";
+const char kDefaultInstallLocation[] = "";
 const char kReinstallInstallSource[] = "reinstall";
 
 const char kGoogleDotCom[] = "google.com";
@@ -238,14 +239,16 @@
   if (!ManifestURL::UpdatesFromGallery(&extension))
     extra.update_url_data = delegate_->GetUpdateUrlData(extension.id());
 
-  return AddExtensionData(
-      extension.id(), extension.version(), extension.GetType(),
-      ManifestURL::GetUpdateURL(&extension), extra, request_id, fetch_priority);
+  return AddExtensionData(extension.id(), extension.version(),
+                          extension.GetType(), extension.location(),
+                          ManifestURL::GetUpdateURL(&extension), extra,
+                          request_id, fetch_priority);
 }
 
 bool ExtensionDownloader::AddPendingExtension(
     const std::string& id,
     const GURL& update_url,
+    Manifest::Location install_location,
     bool is_corrupt_reinstall,
     int request_id,
     ManifestFetchData::FetchPriority fetch_priority) {
@@ -258,8 +261,8 @@
   if (is_corrupt_reinstall)
     extra.is_corrupt_reinstall = true;
 
-  return AddExtensionData(id, version, Manifest::TYPE_UNKNOWN, update_url,
-                          extra, request_id, fetch_priority);
+  return AddExtensionData(id, version, Manifest::TYPE_UNKNOWN, install_location,
+                          update_url, extra, request_id, fetch_priority);
 }
 
 void ExtensionDownloader::StartAllPending(ExtensionCache* cache) {
@@ -299,6 +302,7 @@
   DCHECK(blacklist_fetch->base_url().SchemeIsCryptographic());
   blacklist_fetch->AddExtension(kBlacklistAppID, version, &ping_data,
                                 std::string(), kDefaultInstallSource,
+                                kDefaultInstallLocation,
                                 ManifestFetchData::FetchPriority::BACKGROUND);
   StartUpdateCheck(std::move(blacklist_fetch));
 }
@@ -318,6 +322,7 @@
     const std::string& id,
     const base::Version& version,
     Manifest::Type extension_type,
+    Manifest::Location extension_location,
     const GURL& extension_update_url,
     const ExtraParams& extra,
     int request_id,
@@ -381,6 +386,9 @@
   if (extra.is_corrupt_reinstall)
     install_source = kReinstallInstallSource;
 
+  const std::string install_location =
+      ManifestFetchData::GetSimpleLocationString(extension_location);
+
   ManifestFetchData::PingData ping_data;
   ManifestFetchData::PingData* optional_ping_data = NULL;
   if (delegate_->GetPingDataForExtension(id, &ping_data))
@@ -394,9 +402,9 @@
       !existing_iter->second.empty()) {
     // Try to add to the ManifestFetchData at the end of the list.
     ManifestFetchData* existing_fetch = existing_iter->second.back().get();
-    if (existing_fetch->AddExtension(id, version.GetString(),
-                                     optional_ping_data, extra.update_url_data,
-                                     install_source, fetch_priority)) {
+    if (existing_fetch->AddExtension(
+            id, version.GetString(), optional_ping_data, extra.update_url_data,
+            install_source, install_location, fetch_priority)) {
       added = true;
     }
   }
@@ -410,7 +418,7 @@
         std::move(fetch));
     added = fetch_ptr->AddExtension(id, version.GetString(), optional_ping_data,
                                     extra.update_url_data, install_source,
-                                    fetch_priority);
+                                    install_location, fetch_priority);
     DCHECK(added);
   }
 
diff --git a/extensions/browser/updater/extension_downloader.h b/extensions/browser/updater/extension_downloader.h
index bac0601d..ce8f52a3 100644
--- a/extensions/browser/updater/extension_downloader.h
+++ b/extensions/browser/updater/extension_downloader.h
@@ -95,6 +95,7 @@
   // extension update (either foreground or background).
   bool AddPendingExtension(const std::string& id,
                            const GURL& update_url,
+                           Manifest::Location install_source,
                            bool is_corrupt_reinstall,
                            int request_id,
                            ManifestFetchData::FetchPriority fetch_priority);
@@ -216,6 +217,7 @@
   bool AddExtensionData(const std::string& id,
                         const base::Version& version,
                         Manifest::Type extension_type,
+                        Manifest::Location extension_location,
                         const GURL& extension_update_url,
                         const ExtraParams& extra,
                         int request_id,
diff --git a/extensions/browser/updater/manifest_fetch_data.cc b/extensions/browser/updater/manifest_fetch_data.cc
index 40f2453..48535d9 100644
--- a/extensions/browser/updater/manifest_fetch_data.cc
+++ b/extensions/browser/updater/manifest_fetch_data.cc
@@ -22,6 +22,14 @@
 // request. We want to stay under 2K because of proxies, etc.
 const int kExtensionsManifestMaxURLSize = 2000;
 
+// Strings to report the manifest location in Omaha update pings. Please use
+// strings with no capitalization, spaces or underscorse.
+const char kInternalLocation[] = "internal";
+const char kExternalLocation[] = "external";
+const char kPolicyLocation[] = "policy";
+const char kOtherLocation[] = "other";
+const char kInvalidLocation[] = "invalid";
+
 void AddEnabledStateToPing(std::string* ping_value,
                       const ManifestFetchData::PingData* ping_data) {
   *ping_value += "&e=" + std::string(ping_data->is_enabled ? "1" : "0");
@@ -37,6 +45,37 @@
 
 }  // namespace
 
+// static
+std::string ManifestFetchData::GetSimpleLocationString(Manifest::Location loc) {
+  std::string result = kInvalidLocation;
+  switch (loc) {
+    case Manifest::INTERNAL:
+      result = kInternalLocation;
+      break;
+    case Manifest::EXTERNAL_PREF:
+    case Manifest::EXTERNAL_PREF_DOWNLOAD:
+    case Manifest::EXTERNAL_REGISTRY:
+      result = kExternalLocation;
+      break;
+    case Manifest::COMPONENT:
+    case Manifest::EXTERNAL_COMPONENT:
+    case Manifest::UNPACKED:
+    case Manifest::COMMAND_LINE:
+      result = kOtherLocation;
+      break;
+    case Manifest::EXTERNAL_POLICY_DOWNLOAD:
+    case Manifest::EXTERNAL_POLICY:
+      result = kPolicyLocation;
+      break;
+    case Manifest::INVALID_LOCATION:
+    case Manifest::NUM_LOCATIONS:
+      NOTREACHED();
+      break;
+  }
+
+  return result;
+}
+
 ManifestFetchData::ManifestFetchData(const GURL& update_url,
                                      int request_id,
                                      const std::string& brand_code,
@@ -88,6 +127,7 @@
                                      const PingData* ping_data,
                                      const std::string& update_url_data,
                                      const std::string& install_source,
+                                     const std::string& install_location,
                                      FetchPriority fetch_priority) {
   if (extension_ids_.find(id) != extension_ids_.end()) {
     NOTREACHED() << "Duplicate extension id " << id;
@@ -104,6 +144,8 @@
   parts.push_back("v=" + version);
   if (!install_source.empty())
     parts.push_back("installsource=" + install_source);
+  if (!install_location.empty())
+    parts.push_back("installedby=" + install_location);
   parts.push_back("uc");
 
   if (!update_url_data.empty()) {
diff --git a/extensions/browser/updater/manifest_fetch_data.h b/extensions/browser/updater/manifest_fetch_data.h
index 1530978..731dd263 100644
--- a/extensions/browser/updater/manifest_fetch_data.h
+++ b/extensions/browser/updater/manifest_fetch_data.h
@@ -10,6 +10,7 @@
 #include <string>
 
 #include "base/macros.h"
+#include "extensions/common/manifest.h"
 #include "url/gurl.h"
 
 namespace extensions {
@@ -80,6 +81,11 @@
           disable_reasons(reasons) {}
   };
 
+  // Returns a string to use for reporting an extension's install location.
+  // Some locations with a common purpose, such as the external locations, are
+  // grouped together and will return the same string.
+  static std::string GetSimpleLocationString(Manifest::Location loc);
+
   ManifestFetchData(const GURL& update_url,
                     int request_id,
                     const std::string& brand_code,
@@ -97,6 +103,7 @@
                     const PingData* ping_data,
                     const std::string& update_url_data,
                     const std::string& install_source,
+                    const std::string& install_location,
                     FetchPriority fetch_priority);
 
   const GURL& base_url() const { return base_url_; }
diff --git a/headless/lib/DEPS b/headless/lib/DEPS
index ce2850c..30f1265 100644
--- a/headless/lib/DEPS
+++ b/headless/lib/DEPS
@@ -1,6 +1,6 @@
 specific_include_rules = {
   "headless_web_contents_browsertest.cc": [
-    "+cc/base/switches.h",
+    "+components/viz/common/switches.h",
     "+pdf",
     "+printing",
     "+third_party/skia/include",
diff --git a/headless/lib/browser/headless_devtools_manager_delegate.cc b/headless/lib/browser/headless_devtools_manager_delegate.cc
index 4221a5a..93487a4a 100644
--- a/headless/lib/browser/headless_devtools_manager_delegate.cc
+++ b/headless/lib/browser/headless_devtools_manager_delegate.cc
@@ -11,8 +11,8 @@
 #include "base/command_line.h"
 #include "base/json/json_writer.h"
 #include "build/build_config.h"
-#include "cc/base/switches.h"
 #include "components/viz/common/frame_sinks/begin_frame_args.h"
+#include "components/viz/common/switches.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/devtools_agent_host.h"
 #include "content/public/browser/devtools_frontend_host.h"
@@ -951,7 +951,7 @@
   }
 
   if (base::CommandLine::ForCurrentProcess()->HasSwitch(
-          cc::switches::kRunAllCompositorStagesBeforeDraw) &&
+          switches::kRunAllCompositorStagesBeforeDraw) &&
       headless_contents->HasPendingFrame()) {
     LOG(WARNING) << "A BeginFrame is already in flight. In "
                     "--run-all-compositor-stages-before-draw mode, only a "
diff --git a/headless/lib/headless_web_contents_browsertest.cc b/headless/lib/headless_web_contents_browsertest.cc
index ade1a7e..388f05e 100644
--- a/headless/lib/headless_web_contents_browsertest.cc
+++ b/headless/lib/headless_web_contents_browsertest.cc
@@ -12,7 +12,7 @@
 #include "base/run_loop.h"
 #include "base/strings/stringprintf.h"
 #include "build/build_config.h"
-#include "cc/base/switches.h"
+#include "components/viz/common/switches.h"
 #include "content/public/browser/web_contents.h"
 #include "content/public/common/content_switches.h"
 #include "content/public/test/browser_test.h"
@@ -1083,7 +1083,7 @@
 
   void SetUpCommandLine(base::CommandLine* command_line) override {
     HeadlessBrowserTest::SetUpCommandLine(command_line);
-    command_line->AppendSwitch(cc::switches::kRunAllCompositorStagesBeforeDraw);
+    command_line->AppendSwitch(switches::kRunAllCompositorStagesBeforeDraw);
     command_line->AppendSwitch(switches::kDisableNewContentRenderingTimeout);
   }
 
diff --git a/headless/public/util/compositor_controller_browsertest.cc b/headless/public/util/compositor_controller_browsertest.cc
index 0647290d..82bab72 100644
--- a/headless/public/util/compositor_controller_browsertest.cc
+++ b/headless/public/util/compositor_controller_browsertest.cc
@@ -98,7 +98,7 @@
   void SetUpCommandLine(base::CommandLine* command_line) override {
     HeadlessAsyncDevTooledBrowserTest::SetUpCommandLine(command_line);
     // See bit.ly/headless-rendering for why we use these flags.
-    command_line->AppendSwitch(cc::switches::kRunAllCompositorStagesBeforeDraw);
+    command_line->AppendSwitch(switches::kRunAllCompositorStagesBeforeDraw);
     command_line->AppendSwitch(switches::kDisableNewContentRenderingTimeout);
     command_line->AppendSwitch(cc::switches::kDisableCheckerImaging);
     command_line->AppendSwitch(cc::switches::kDisableThreadedAnimation);
@@ -281,15 +281,11 @@
     // With surface sync enabled, we should have waited for the renderer's
     // CompositorFrame in the first BeginFrame.
     EXPECT_EQ(1, begin_frame_counter_->begin_frame_count());
-    // TODO(eseckler, fsamuel): This seems flaky. This depends on the deadline
-    // set, I think.
-    // EXPECT_EQ(1, begin_frame_counter_->main_frame_update_count());
+    EXPECT_EQ(1, begin_frame_counter_->main_frame_update_count());
   }
 };
 
-// Flaky: https://crbug.com/811288
-DISABLED_HEADLESS_ASYNC_DEVTOOLED_TEST_P(
-    CompositorControllerSurfaceSyncBrowserTest);
+HEADLESS_ASYNC_DEVTOOLED_TEST_P(CompositorControllerSurfaceSyncBrowserTest);
 
 // Instantiate test case for both software and gpu compositing modes.
 INSTANTIATE_TEST_CASE_P(CompositorControllerSurfaceSyncBrowserTests,
diff --git a/ios/chrome/browser/bookmarks/BUILD.gn b/ios/chrome/browser/bookmarks/BUILD.gn
index 1581e81..253908fe 100644
--- a/ios/chrome/browser/bookmarks/BUILD.gn
+++ b/ios/chrome/browser/bookmarks/BUILD.gn
@@ -39,6 +39,8 @@
 
 source_set("bookmarks_utils") {
   sources = [
+    "bookmark_remover_helper.cc",
+    "bookmark_remover_helper.h",
     "bookmarks_utils.cc",
     "bookmarks_utils.h",
   ]
diff --git a/ios/chrome/browser/bookmarks/bookmark_remover_helper.cc b/ios/chrome/browser/bookmarks/bookmark_remover_helper.cc
new file mode 100644
index 0000000..3d5cfbf0e
--- /dev/null
+++ b/ios/chrome/browser/bookmarks/bookmark_remover_helper.cc
@@ -0,0 +1,71 @@
+// 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 "ios/chrome/browser/bookmarks/bookmark_remover_helper.h"
+
+#include "base/logging.h"
+#include "base/threading/sequenced_task_runner_handle.h"
+#include "components/bookmarks/browser/bookmark_model.h"
+#include "ios/chrome/browser/bookmarks/bookmark_model_factory.h"
+#include "ios/chrome/browser/bookmarks/bookmarks_utils.h"
+#include "ios/chrome/browser/browser_state/chrome_browser_state.h"
+
+BookmarkRemoverHelper::BookmarkRemoverHelper(
+    ios::ChromeBrowserState* browser_state)
+    : browser_state_(browser_state) {
+  DCHECK(browser_state_);
+}
+
+BookmarkRemoverHelper::~BookmarkRemoverHelper() {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  DCHECK(!browser_state_);
+}
+
+void BookmarkRemoverHelper::BookmarkModelChanged() {
+  NOTREACHED();
+}
+
+void BookmarkRemoverHelper::BookmarkModelLoaded(
+    bookmarks::BookmarkModel* bookmark_model,
+    bool) {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  bookmark_model->RemoveObserver(this);
+  BookmarksRemoved(::RemoveAllUserBookmarksIOS(browser_state_));
+}
+
+void BookmarkRemoverHelper::BookmarkModelBeingDeleted(
+    bookmarks::BookmarkModel* bookmark_model) {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  bookmark_model->RemoveObserver(this);
+  BookmarksRemoved(false);
+}
+
+void BookmarkRemoverHelper::RemoveAllUserBookmarksIOS(Callback completion) {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  completion_ = std::move(completion);
+
+  bookmarks::BookmarkModel* bookmark_model =
+      ios::BookmarkModelFactory::GetForBrowserState(browser_state_);
+
+  if (!bookmark_model) {
+    BookmarksRemoved(false);
+    return;
+  }
+
+  if (bookmark_model->loaded()) {
+    BookmarksRemoved(::RemoveAllUserBookmarksIOS(browser_state_));
+  } else {
+    // Wait for the BookmarkModel to finish loading before deleting entries.
+    bookmark_model->AddObserver(this);
+  }
+}
+
+void BookmarkRemoverHelper::BookmarksRemoved(bool success) {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  browser_state_ = nullptr;
+  if (completion_) {
+    base::SequencedTaskRunnerHandle::Get()->PostTask(
+        FROM_HERE, base::BindOnce(std::move(completion_), success));
+  }
+}
diff --git a/ios/chrome/browser/bookmarks/bookmark_remover_helper.h b/ios/chrome/browser/bookmarks/bookmark_remover_helper.h
new file mode 100644
index 0000000..e5057b6f
--- /dev/null
+++ b/ios/chrome/browser/bookmarks/bookmark_remover_helper.h
@@ -0,0 +1,55 @@
+// 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 IOS_CHROME_BROWSER_BOOKMARKS_BOOKMARK_REMOVER_HELPER_H_
+#define IOS_CHROME_BROWSER_BOOKMARKS_BOOKMARK_REMOVER_HELPER_H_
+
+#include "base/callback.h"
+#include "base/scoped_observer.h"
+#include "base/sequence_checker.h"
+#include "components/bookmarks/browser/base_bookmark_model_observer.h"
+
+namespace ios {
+class ChromeBrowserState;
+}
+
+namespace bookmarks {
+class BookmarkModel;
+}  // namespace bookmarks
+
+// Helper class to asynchronously remove bookmarks.
+class BookmarkRemoverHelper : public bookmarks::BaseBookmarkModelObserver {
+ public:
+  using Callback = base::OnceCallback<void(bool)>;
+
+  explicit BookmarkRemoverHelper(ios::ChromeBrowserState* browser_state);
+  ~BookmarkRemoverHelper() override;
+
+  // Removes all bookmarks and asynchronously invoke |completion| with
+  // boolean indicating success or failure.
+  void RemoveAllUserBookmarksIOS(Callback completion);
+
+  // BaseBookmarkModelObserver implementation.
+  void BookmarkModelChanged() override;
+
+  // BookmarkModelObserver implementation.
+  void BookmarkModelLoaded(bookmarks::BookmarkModel* model,
+                           bool ids_reassigned) override;
+  void BookmarkModelBeingDeleted(bookmarks::BookmarkModel* model) override;
+
+ private:
+  // Invoked when the bookmark entries have been deleted. Invoke the
+  // completion callback with |success| (invocation is asynchronous so
+  // the object won't be deleted immediately).
+  void BookmarksRemoved(bool success);
+
+  Callback completion_;
+  ios::ChromeBrowserState* browser_state_ = nullptr;
+
+  SEQUENCE_CHECKER(sequence_checker_);
+
+  DISALLOW_COPY_AND_ASSIGN(BookmarkRemoverHelper);
+};
+
+#endif  // IOS_CHROME_BROWSER_BOOKMARKS_BOOKMARK_REMOVER_HELPER_H_
diff --git a/ios/chrome/browser/bookmarks/bookmarks_utils.cc b/ios/chrome/browser/bookmarks/bookmarks_utils.cc
index 82a8036..996e4a09 100644
--- a/ios/chrome/browser/bookmarks/bookmarks_utils.cc
+++ b/ios/chrome/browser/bookmarks/bookmarks_utils.cc
@@ -35,13 +35,12 @@
     if (!bookmark_model->client()->CanBeEditedByUser(
             bookmark_model->root_node()->GetChild(i)))
       continue;
-    CHECK(bookmark_model->root_node()->GetChild(i)->empty())
-        << "Failed to remove all user bookmarks.";
+    if (!bookmark_model->root_node()->GetChild(i)->empty())
+      return false;
   }
 
   // The default save folder is reset to the generic one.
   browser_state->GetPrefs()->SetInt64(prefs::kIosBookmarkFolderDefault, -1);
-
   return true;
 }
 
diff --git a/ios/chrome/browser/reading_list/reading_list_remover_helper.cc b/ios/chrome/browser/reading_list/reading_list_remover_helper.cc
index 35ab24fd..b4d4399 100644
--- a/ios/chrome/browser/reading_list/reading_list_remover_helper.cc
+++ b/ios/chrome/browser/reading_list/reading_list_remover_helper.cc
@@ -4,6 +4,7 @@
 
 #include "ios/chrome/browser/reading_list/reading_list_remover_helper.h"
 
+#include "base/threading/sequenced_task_runner_handle.h"
 #include "components/reading_list/core/reading_list_model.h"
 #include "ios/chrome/browser/browser_state/chrome_browser_state.h"
 #include "ios/chrome/browser/reading_list/reading_list_download_service.h"
@@ -14,49 +15,62 @@
 
 ReadingListRemoverHelper::ReadingListRemoverHelper(
     ios::ChromeBrowserState* browser_state)
-    : ReadingListModelObserver(), scoped_observer_(this) {
+    : scoped_observer_(this) {
   reading_list_model_ =
       ReadingListModelFactory::GetForBrowserState(browser_state);
   reading_list_download_service_ =
       ReadingListDownloadServiceFactory::GetForBrowserState(browser_state);
 }
 
-ReadingListRemoverHelper::~ReadingListRemoverHelper() {}
+ReadingListRemoverHelper::~ReadingListRemoverHelper() {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  DCHECK(!reading_list_model_);
+  DCHECK(!reading_list_download_service_);
+}
 
 void ReadingListRemoverHelper::ReadingListModelLoaded(
-    const ReadingListModel* model) {
+    const ReadingListModel* reading_list_model) {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  DCHECK_EQ(reading_list_model_, reading_list_model);
   scoped_observer_.Remove(reading_list_model_);
 
   bool model_cleared = reading_list_model_->DeleteAllEntries();
   reading_list_download_service_->Clear();
-  reading_list_model_ = nullptr;
-  if (completion_) {
-    // |completion_| may delete this. Do not use the object after this call.
-    std::move(completion_).Run(model_cleared);
-  }
+
+  ReadlingListItemsRemoved(model_cleared);
 }
 
 void ReadingListRemoverHelper::ReadingListModelBeingDeleted(
-    const ReadingListModel* model) {
+    const ReadingListModel* reading_list_model) {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  DCHECK_EQ(reading_list_model_, reading_list_model);
   scoped_observer_.Remove(reading_list_model_);
-  reading_list_model_ = nullptr;
-  if (completion_) {
-    // |completion_| may delete this. Do not use the object after this call.
-    std::move(completion_).Run(false);
-  }
+  ReadlingListItemsRemoved(false);
 }
 
 void ReadingListRemoverHelper::RemoveAllUserReadingListItemsIOS(
     Callback completion) {
-  if (!reading_list_model_) {
-    // |completion_| may delete this. Do not use the object after this call.
-    std::move(completion_).Run(false);
-    return;
-  }
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   completion_ = std::move(completion);
 
-  // Calls ReadingListModelLoaded if model is already loaded.
+  if (!reading_list_model_) {
+    ReadlingListItemsRemoved(false);
+    return;
+  }
+
+  // ReadingListModel::AddObserver calls ReadingListModelLoaded if model is
+  // already loaded, so there is no need to check.
   scoped_observer_.Add(reading_list_model_);
 }
 
+void ReadingListRemoverHelper::ReadlingListItemsRemoved(bool success) {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  reading_list_model_ = nullptr;
+  reading_list_download_service_ = nullptr;
+  if (completion_) {
+    base::SequencedTaskRunnerHandle::Get()->PostTask(
+        FROM_HERE, base::BindOnce(std::move(completion_), success));
+  }
+}
+
 }  // namespace reading_list
diff --git a/ios/chrome/browser/reading_list/reading_list_remover_helper.h b/ios/chrome/browser/reading_list/reading_list_remover_helper.h
index 68a0c55..6cd77e7e 100644
--- a/ios/chrome/browser/reading_list/reading_list_remover_helper.h
+++ b/ios/chrome/browser/reading_list/reading_list_remover_helper.h
@@ -7,6 +7,7 @@
 
 #include "base/callback.h"
 #include "base/scoped_observer.h"
+#include "base/sequence_checker.h"
 #include "components/reading_list/core/reading_list_model_observer.h"
 
 namespace ios {
@@ -17,14 +18,17 @@
 class ReadingListDownloadService;
 
 namespace reading_list {
+
+// Helper class to asynchronously remove reading list entries.
 class ReadingListRemoverHelper : public ReadingListModelObserver {
  public:
   using Callback = base::OnceCallback<void(bool)>;
-  ReadingListRemoverHelper(ios::ChromeBrowserState* browser_state);
+
+  explicit ReadingListRemoverHelper(ios::ChromeBrowserState* browser_state);
   ~ReadingListRemoverHelper() override;
 
-  // Removes all Reading list items and call completion with |true| if the
-  // cleaning was successful.
+  // Removes all Reading list items and asynchronously invoke |completion| with
+  // boolean indicating success or failure.
   void RemoveAllUserReadingListItemsIOS(Callback completion);
 
   // ReadingListModelObserver implementation.
@@ -32,13 +36,21 @@
   void ReadingListModelBeingDeleted(const ReadingListModel* model) override;
 
  private:
+  // Invoked when the reading list items have been deleted. Invoke the
+  // completion callback with |success| (invocation is asynchronous so
+  // the object won't be deleted immediately).
+  void ReadlingListItemsRemoved(bool success);
+
   Callback completion_;
-  ReadingListModel* reading_list_model_;
-  ReadingListDownloadService* reading_list_download_service_;
+  ReadingListModel* reading_list_model_ = nullptr;
+  ReadingListDownloadService* reading_list_download_service_ = nullptr;
   ScopedObserver<ReadingListModel, ReadingListModelObserver> scoped_observer_;
 
+  SEQUENCE_CHECKER(sequence_checker_);
+
   DISALLOW_COPY_AND_ASSIGN(ReadingListRemoverHelper);
 };
+
 }  // namespace reading_list
 
 #endif  // IOS_CHROME_BROWSER_READING_LIST_READING_LIST_REMOVER_HELPER_H_
diff --git a/ios/chrome/browser/ui/content_suggestions/BUILD.gn b/ios/chrome/browser/ui/content_suggestions/BUILD.gn
index e162ec8..4b7bbd2 100644
--- a/ios/chrome/browser/ui/content_suggestions/BUILD.gn
+++ b/ios/chrome/browser/ui/content_suggestions/BUILD.gn
@@ -128,6 +128,7 @@
     "//ios/chrome/browser/ui/ntp:ntp_header",
     "//ios/chrome/browser/ui/overscroll_actions",
     "//ios/chrome/browser/ui/toolbar:toolbar_ui",
+    "//ios/chrome/browser/ui/toolbar/buttons:buttons",
     "//ios/chrome/browser/ui/util:util",
     "//ui/base",
   ]
diff --git a/ios/chrome/browser/ui/content_suggestions/content_suggestions_header_view.mm b/ios/chrome/browser/ui/content_suggestions/content_suggestions_header_view.mm
index 35ebea3..ad5b1bc1 100644
--- a/ios/chrome/browser/ui/content_suggestions/content_suggestions_header_view.mm
+++ b/ios/chrome/browser/ui/content_suggestions/content_suggestions_header_view.mm
@@ -9,7 +9,11 @@
 #include "base/logging.h"
 #import "ios/chrome/browser/ui/content_suggestions/content_suggestions_collection_utils.h"
 #import "ios/chrome/browser/ui/ntp/new_tab_page_header_constants.h"
+#import "ios/chrome/browser/ui/toolbar/buttons/toolbar_button_factory.h"
+#import "ios/chrome/browser/ui/toolbar/buttons/toolbar_configuration.h"
+#import "ios/chrome/browser/ui/toolbar/buttons/toolbar_constants.h"
 #import "ios/chrome/browser/ui/toolbar/toolbar_snapshot_providing.h"
+#import "ios/chrome/browser/ui/util/constraints_ui_util.h"
 #import "ios/chrome/browser/ui/util/named_guide.h"
 #import "ui/gfx/ios/uikit_util.h"
 
@@ -18,10 +22,19 @@
 #endif
 
 @interface ContentSuggestionsHeaderView ()<ToolbarSnapshotProviding>
+
+// Layout constraints for fake omnibox background image.
+@property(nonatomic, strong) NSLayoutConstraint* backgroundHeightConstraint;
+@property(nonatomic, strong) NSLayoutConstraint* backgroundLeadingConstraint;
+@property(nonatomic, strong) NSLayoutConstraint* backgroundTrailingConstraint;
+
 @end
 
 @implementation ContentSuggestionsHeaderView
 
+@synthesize backgroundHeightConstraint = _backgroundHeightConstraint;
+@synthesize backgroundLeadingConstraint = _backgroundLeadingConstraint;
+@synthesize backgroundTrailingConstraint = _backgroundTrailingConstraint;
 @synthesize toolBarView = _toolBarView;
 
 #pragma mark - Public
@@ -56,6 +69,36 @@
 }
 
 - (void)addViewsToSearchField:(UIView*)searchField {
+  UIBlurEffect* blurEffect = [[ToolbarButtonFactory alloc] initWithStyle:NORMAL]
+                                 .toolbarConfiguration.blurEffect;
+  UIVisualEffectView* blur =
+      [[UIVisualEffectView alloc] initWithEffect:blurEffect];
+  blur.layer.cornerRadius = kAdaptiveLocationBarCornerRadius;
+  [searchField insertSubview:blur atIndex:0];
+  blur.translatesAutoresizingMaskIntoConstraints = NO;
+  AddSameConstraints(blur, searchField);
+
+  UIView* backgroundContainer = [[UIView alloc] init];
+  backgroundContainer.userInteractionEnabled = NO;
+  backgroundContainer.backgroundColor =
+      [UIColor colorWithWhite:0 alpha:kAdaptiveLocationBarBackgroundAlpha];
+  backgroundContainer.layer.cornerRadius = kAdaptiveLocationBarCornerRadius;
+  [searchField addSubview:backgroundContainer];
+  backgroundContainer.translatesAutoresizingMaskIntoConstraints = NO;
+  self.backgroundLeadingConstraint = [backgroundContainer.leadingAnchor
+      constraintEqualToAnchor:searchField.leadingAnchor];
+  self.backgroundTrailingConstraint = [backgroundContainer.trailingAnchor
+      constraintEqualToAnchor:searchField.trailingAnchor];
+  self.backgroundHeightConstraint =
+      [backgroundContainer.heightAnchor constraintEqualToConstant:0];
+  [NSLayoutConstraint activateConstraints:@[
+    [backgroundContainer.centerYAnchor
+        constraintEqualToAnchor:searchField.centerYAnchor],
+    self.backgroundLeadingConstraint,
+    self.backgroundTrailingConstraint,
+    self.backgroundHeightConstraint,
+  ]];
+
   // TODO(crbug.com/805644) Update fake omnibox theme.
 }
 
@@ -88,8 +131,8 @@
 
   // Calculate the amount to grow the width and height of searchField so that
   // its frame covers the entire toolbar area.
-  CGFloat maxXInset = ui::AlignValueToUpperPixel(
-      (searchFieldNormalWidth - screenWidth) / 2 - 1);
+  CGFloat maxXInset =
+      ui::AlignValueToUpperPixel((searchFieldNormalWidth - screenWidth) / 2);
   CGFloat maxHeightDiff =
       ntp_header::kToolbarHeight - content_suggestions::kSearchFieldHeight;
 
@@ -99,6 +142,26 @@
   heightConstraint.constant =
       content_suggestions::kSearchFieldHeight + maxHeightDiff * percent;
 
+  // Calculate the amount to shrink the width and height of background so that
+  // it's where the focused adapative toolbar focuses.
+  self.backgroundLeadingConstraint.constant =
+      (safeAreaInsets.left + kAdaptiveToolbarHorizontalMargin) * percent;
+  // TODO(crbug.com/805636) Placeholder for specifications. For now using hard
+  // coded size of cancel button of 64pt.
+  CGFloat kCancelButtonWidth = 64;
+  self.backgroundTrailingConstraint.constant =
+      -(safeAreaInsets.right + kAdaptiveToolbarHorizontalMargin +
+        kCancelButtonWidth) *
+      percent;
+  // TODO(crbug.com/805636) Placeholder for specifications. For now using hard
+  // coded height of location bar, which is 42 or
+  // kToolbarHeight - 2 * kLocationBarVerticalMargin
+  CGFloat kLocationBarHeight = 42;
+  CGFloat minHeightDiff =
+      kLocationBarHeight - content_suggestions::kSearchFieldHeight;
+  self.backgroundHeightConstraint.constant =
+      content_suggestions::kSearchFieldHeight + minHeightDiff * percent;
+
   // Adjust the position of the search field's subviews by adjusting their
   // constraint constant value.
   CGFloat constantDiff =
diff --git a/ios/chrome/browser/ui/orchestrator/omnibox_focus_orchestrator.h b/ios/chrome/browser/ui/orchestrator/omnibox_focus_orchestrator.h
index 3c05af4..2a31ac0 100644
--- a/ios/chrome/browser/ui/orchestrator/omnibox_focus_orchestrator.h
+++ b/ios/chrome/browser/ui/orchestrator/omnibox_focus_orchestrator.h
@@ -16,9 +16,11 @@
 // Toolbar animatee, orchestrated by this object.
 @property(nonatomic, weak) id<ToolbarAnimatee> toolbarAnimatee;
 
-// Updates the UI elements orchestrated by this object to reflect the omnibox
-// |focused| state, |animated| or not.
-- (void)transitionToStateFocused:(BOOL)focused animated:(BOOL)animated;
+// Updates the UI elements orchestrated by this object to reflect the
+// |omniboxFocused| state, and the |toolbarExpanded| state, |animated| or not.
+- (void)transitionToStateOmniboxFocused:(BOOL)omniboxFocused
+                        toolbarExpanded:(BOOL)toolbarExpanded
+                               animated:(BOOL)animated;
 
 @end
 
diff --git a/ios/chrome/browser/ui/orchestrator/omnibox_focus_orchestrator.mm b/ios/chrome/browser/ui/orchestrator/omnibox_focus_orchestrator.mm
index 3de2ae8..46d95251 100644
--- a/ios/chrome/browser/ui/orchestrator/omnibox_focus_orchestrator.mm
+++ b/ios/chrome/browser/ui/orchestrator/omnibox_focus_orchestrator.mm
@@ -15,18 +15,22 @@
 
 @synthesize toolbarAnimatee = _toolbarAnimatee;
 
-- (void)transitionToStateFocused:(BOOL)focused animated:(BOOL)animated {
-  if (focused) {
-    [self focusOmniboxAnimated:animated];
+- (void)transitionToStateOmniboxFocused:(BOOL)omniboxFocused
+                        toolbarExpanded:(BOOL)toolbarExpanded
+                               animated:(BOOL)animated {
+  // TODO(crbug.com/805485): manage the changes in the location bar.
+  if (toolbarExpanded) {
+    [self updateUIToExpandedState:animated];
   } else {
-    [self unfocusOmniboxAnimated:animated];
+    [self updateUIToContractedState:animated];
   }
 }
 
 #pragma mark - Private
 
-// Updates the UI elements reflect the omnibox focused state, |animated| or not.
-- (void)focusOmniboxAnimated:(BOOL)animated {
+// Updates the UI elements reflect the toolbar expanded state, |animated| or
+// not.
+- (void)updateUIToExpandedState:(BOOL)animated {
   void (^expansion)() = ^{
     [self.toolbarAnimatee expandLocationBar];
     [self.toolbarAnimatee showCancelButton];
@@ -55,9 +59,9 @@
   }
 }
 
-// Updates the UI elements reflect the omnibox unfocused state, |animated| or
+// Updates the UI elements reflect the toolbar contracted state, |animated| or
 // not.
-- (void)unfocusOmniboxAnimated:(BOOL)animated {
+- (void)updateUIToContractedState:(BOOL)animated {
   void (^contraction)() = ^{
     [self.toolbarAnimatee contractLocationBar];
   };
diff --git a/ios/chrome/browser/ui/settings/reauthentication_module_unittest.mm b/ios/chrome/browser/ui/settings/reauthentication_module_unittest.mm
index 3132ba2a..85d13ae 100644
--- a/ios/chrome/browser/ui/settings/reauthentication_module_unittest.mm
+++ b/ios/chrome/browser/ui/settings/reauthentication_module_unittest.mm
@@ -61,8 +61,19 @@
   ReauthenticationModule* reauthentication_module_;
 };
 
+// Tests that reauthentication is not reused when reuse is not permitted
+// even if the time interval since the previous reauthentication is less
+// than 60 seconds.
 TEST_F(ReauthenticationModuleTest, ReauthReuseNotPermitted) {
-  [time_accessor_ updateSuccessfulReauthTime];
+  const int kIntervalFromFakePreviousAuthInSeconds = 20;
+  NSDate* lastReauthTime = [NSDate date];
+  [time_accessor_ updateSuccessfulReauthTime:lastReauthTime];
+  NSDate* newReauthTime =
+      [NSDate dateWithTimeInterval:kIntervalFromFakePreviousAuthInSeconds
+                         sinceDate:lastReauthTime];
+
+  id nsDateMock = OCMClassMock([NSDate class]);
+  OCMStub([nsDateMock date]).andReturn(newReauthTime);
 
   OCMExpect([auth_context_ evaluatePolicy:LAPolicyDeviceOwnerAuthentication
                           localizedReason:[OCMArg any]
@@ -75,9 +86,19 @@
   EXPECT_OCMOCK_VERIFY(auth_context_);
 }
 
+// Tests that the previous reauthentication is reused when reuse is permitted
+// and the last successful reauthentication occured less than 60 seconds
+// before the current attempt.
 TEST_F(ReauthenticationModuleTest, ReauthReusePermittedLessThanSixtySeconds) {
-  [time_accessor_ updateSuccessfulReauthTime];
+  const int kIntervalFromFakePreviousAuthInSeconds = 20;
+  NSDate* lastReauthTime = [NSDate date];
+  [time_accessor_ updateSuccessfulReauthTime:lastReauthTime];
+  NSDate* newReauthTime =
+      [NSDate dateWithTimeInterval:kIntervalFromFakePreviousAuthInSeconds
+                         sinceDate:lastReauthTime];
 
+  id nsDateMock = OCMClassMock([NSDate class]);
+  OCMStub([nsDateMock date]).andReturn(newReauthTime);
   [[auth_context_ reject] evaluatePolicy:LAPolicyDeviceOwnerAuthentication
                          localizedReason:[OCMArg any]
                                    reply:[OCMArg any]];
@@ -97,11 +118,19 @@
   }
 }
 
+// Tests that the previous reauthentication is not reused when reuse is
+// permitted, but the last successful reauthentication occured more than 60
+// seconds before the current attempt.
 TEST_F(ReauthenticationModuleTest, ReauthReusePermittedMoreThanSixtySeconds) {
-  const int kIntervalForFakePreviousAuthInSeconds = -70;
-  [time_accessor_ updateSuccessfulReauthTime:
-                      [NSDate dateWithTimeIntervalSinceNow:
-                                  kIntervalForFakePreviousAuthInSeconds]];
+  const int kIntervalFromFakePreviousAuthInSeconds = 70;
+  NSDate* lastReauthTime = [NSDate date];
+  [time_accessor_ updateSuccessfulReauthTime:lastReauthTime];
+  NSDate* newReauthTime =
+      [NSDate dateWithTimeInterval:kIntervalFromFakePreviousAuthInSeconds
+                         sinceDate:lastReauthTime];
+
+  id nsDateMock = OCMClassMock([NSDate class]);
+  OCMStub([nsDateMock date]).andReturn(newReauthTime);
 
   OCMExpect([auth_context_ evaluatePolicy:LAPolicyDeviceOwnerAuthentication
                           localizedReason:[OCMArg any]
diff --git a/ios/chrome/browser/ui/toolbar/adaptive/BUILD.gn b/ios/chrome/browser/ui/toolbar/adaptive/BUILD.gn
index 7526d75..fce64dc 100644
--- a/ios/chrome/browser/ui/toolbar/adaptive/BUILD.gn
+++ b/ios/chrome/browser/ui/toolbar/adaptive/BUILD.gn
@@ -55,6 +55,7 @@
     "primary_toolbar_view.mm",
     "primary_toolbar_view_controller.h",
     "primary_toolbar_view_controller.mm",
+    "primary_toolbar_view_controller_delegate.h",
     "secondary_toolbar_view.h",
     "secondary_toolbar_view.mm",
     "secondary_toolbar_view_controller.h",
diff --git a/ios/chrome/browser/ui/toolbar/adaptive/primary_toolbar_coordinator.mm b/ios/chrome/browser/ui/toolbar/adaptive/primary_toolbar_coordinator.mm
index c32f492..36ace6e6 100644
--- a/ios/chrome/browser/ui/toolbar/adaptive/primary_toolbar_coordinator.mm
+++ b/ios/chrome/browser/ui/toolbar/adaptive/primary_toolbar_coordinator.mm
@@ -20,6 +20,7 @@
 #import "ios/chrome/browser/ui/orchestrator/omnibox_focus_orchestrator.h"
 #import "ios/chrome/browser/ui/toolbar/adaptive/adaptive_toolbar_coordinator+subclassing.h"
 #import "ios/chrome/browser/ui/toolbar/adaptive/primary_toolbar_view_controller.h"
+#import "ios/chrome/browser/ui/toolbar/adaptive/primary_toolbar_view_controller_delegate.h"
 #import "ios/chrome/browser/ui/toolbar/clean/toolbar_coordinator_delegate.h"
 #import "ios/chrome/browser/ui/toolbar/public/web_toolbar_controller_constants.h"
 #import "ios/chrome/browser/ui/uikit_ui_util.h"
@@ -31,7 +32,8 @@
 #error "This file requires ARC support."
 #endif
 
-@interface PrimaryToolbarCoordinator ()<OmniboxPopupPositioner> {
+@interface PrimaryToolbarCoordinator ()<OmniboxPopupPositioner,
+                                        PrimaryToolbarViewControllerDelegate> {
   // Observer that updates |toolbarViewController| for fullscreen events.
   std::unique_ptr<FullscreenControllerObserver> _fullscreenObserver;
 }
@@ -59,6 +61,7 @@
   self.viewController = [[PrimaryToolbarViewController alloc] init];
   self.viewController.buttonFactory = [self buttonFactoryWithType:PRIMARY];
   self.viewController.dispatcher = self.dispatcher;
+  self.viewController.delegate = self;
 
   self.orchestrator = [[OmniboxFocusOrchestrator alloc] init];
   self.orchestrator.toolbarAnimatee = self.viewController;
@@ -109,11 +112,21 @@
 }
 
 - (void)transitionToLocationBarFocusedState:(BOOL)focused {
-  if (!IsSplitToolbarMode()) {
-    // No animation when the toolbar is unsplit.
-    return;
-  }
-  [self.orchestrator transitionToStateFocused:focused animated:YES];
+  [self.orchestrator
+      transitionToStateOmniboxFocused:focused
+                      toolbarExpanded:focused && IsSplitToolbarMode()
+                             animated:YES];
+}
+
+#pragma mark - PrimaryToolbarViewControllerDelegate
+
+- (void)viewControllerTraitCollectionDidChange:
+    (UITraitCollection*)previousTraitCollection {
+  BOOL omniboxFocused = self.isOmniboxFirstResponder;
+  [self.orchestrator
+      transitionToStateOmniboxFocused:omniboxFocused
+                      toolbarExpanded:omniboxFocused && IsSplitToolbarMode()
+                             animated:NO];
 }
 
 #pragma mark - FakeboxFocuser
diff --git a/ios/chrome/browser/ui/toolbar/adaptive/primary_toolbar_view_controller.h b/ios/chrome/browser/ui/toolbar/adaptive/primary_toolbar_view_controller.h
index fa0fcdd..a4cbdc0 100644
--- a/ios/chrome/browser/ui/toolbar/adaptive/primary_toolbar_view_controller.h
+++ b/ios/chrome/browser/ui/toolbar/adaptive/primary_toolbar_view_controller.h
@@ -11,6 +11,8 @@
 #import "ios/chrome/browser/ui/orchestrator/toolbar_animatee.h"
 #import "ios/chrome/browser/ui/toolbar/adaptive/adaptive_toolbar_view_controller.h"
 
+@protocol PrimaryToolbarViewControllerDelegate;
+
 // ViewController for the primary toobar part of the adaptive toolbar. It is the
 // part always displayed and containing the location bar.
 @interface PrimaryToolbarViewController
@@ -19,6 +21,8 @@
                                     TabHistoryUIUpdater,
                                     ToolbarAnimatee>
 
+@property(nonatomic, weak) id<PrimaryToolbarViewControllerDelegate> delegate;
+
 // Sets the location bar view, containing the omnibox.
 - (void)setLocationBarView:(UIView*)locationBarView;
 
diff --git a/ios/chrome/browser/ui/toolbar/adaptive/primary_toolbar_view_controller.mm b/ios/chrome/browser/ui/toolbar/adaptive/primary_toolbar_view_controller.mm
index 9883d33..eb4c410 100644
--- a/ios/chrome/browser/ui/toolbar/adaptive/primary_toolbar_view_controller.mm
+++ b/ios/chrome/browser/ui/toolbar/adaptive/primary_toolbar_view_controller.mm
@@ -12,6 +12,7 @@
 #import "ios/chrome/browser/ui/history_popup/requirements/tab_history_constants.h"
 #import "ios/chrome/browser/ui/toolbar/adaptive/adaptive_toolbar_view_controller+subclassing.h"
 #import "ios/chrome/browser/ui/toolbar/adaptive/primary_toolbar_view.h"
+#import "ios/chrome/browser/ui/toolbar/adaptive/primary_toolbar_view_controller_delegate.h"
 #import "ios/chrome/browser/ui/toolbar/buttons/toolbar_button.h"
 #import "ios/chrome/browser/ui/toolbar/buttons/toolbar_button_factory.h"
 #import "ios/chrome/browser/ui/toolbar/buttons/toolbar_configuration.h"
@@ -31,6 +32,7 @@
 
 @implementation PrimaryToolbarViewController
 
+@synthesize delegate = _delegate;
 @dynamic view;
 
 #pragma mark - Public
@@ -98,6 +100,12 @@
   ConstrainNamedGuideToView(kOmniboxGuide, self.view.locationBarContainer);
 }
 
+- (void)traitCollectionDidChange:(UITraitCollection*)previousTraitCollection {
+  [super traitCollectionDidChange:previousTraitCollection];
+  [self.delegate
+      viewControllerTraitCollectionDidChange:previousTraitCollection];
+}
+
 #pragma mark - Property accessors
 
 - (void)setLocationBarView:(UIView*)locationBarView {
diff --git a/ios/chrome/browser/ui/toolbar/adaptive/primary_toolbar_view_controller_delegate.h b/ios/chrome/browser/ui/toolbar/adaptive/primary_toolbar_view_controller_delegate.h
new file mode 100644
index 0000000..0e1503a
--- /dev/null
+++ b/ios/chrome/browser/ui/toolbar/adaptive/primary_toolbar_view_controller_delegate.h
@@ -0,0 +1,19 @@
+// 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 IOS_CHROME_BROWSER_UI_TOOLBAR_ADAPTIVE_PRIMARY_TOOLBAR_VIEW_CONTROLLER_DELEGATE_H_
+#define IOS_CHROME_BROWSER_UI_TOOLBAR_ADAPTIVE_PRIMARY_TOOLBAR_VIEW_CONTROLLER_DELEGATE_H_
+
+#import <UIKit/UIKit.h>
+
+// Protocol implemented by the delegate of the PrimaryToolbarViewController.
+@protocol PrimaryToolbarViewControllerDelegate
+
+// Called when the trait collection of the view controller changed.
+- (void)viewControllerTraitCollectionDidChange:
+    (UITraitCollection*)previousTraitCollection;
+
+@end
+
+#endif  // IOS_CHROME_BROWSER_UI_TOOLBAR_ADAPTIVE_PRIMARY_TOOLBAR_VIEW_CONTROLLER_DELEGATE_H_
diff --git a/ios/web/BUILD.gn b/ios/web/BUILD.gn
index 574b8f58..66bd5223 100644
--- a/ios/web/BUILD.gn
+++ b/ios/web/BUILD.gn
@@ -472,8 +472,10 @@
     "//ios/web/test:test_constants",
     "//ios/web/test:test_support",
     "//ios/web/test/fakes:fakes",
+    "//ios/web/web_state:context_menu",
     "//ios/web/web_state:wk_web_view_security_util",
     "//ios/web/web_state/js",
+    "//ios/web/web_state/ui:crw_context_menu_controller",
     "//ios/web/web_state/ui:crw_wk_script_message_router",
     "//ios/web/web_state/ui:web_view_js_utils",
     "//net:test_support",
@@ -490,6 +492,7 @@
     "web_state/ui/crw_web_view_scroll_view_proxy_unittest.mm",
     "web_state/ui/crw_wk_navigation_states_unittest.mm",
     "web_state/ui/crw_wk_script_message_router_unittest.mm",
+    "web_state/ui/html_element_fetch_request_unittest.mm",
     "web_state/ui/web_view_js_utils_unittest.mm",
     "web_state/ui/wk_back_forward_list_item_holder_unittest.mm",
     "web_state/ui/wk_navigation_action_util_unittest.mm",
diff --git a/ios/web/web_state/ui/BUILD.gn b/ios/web/web_state/ui/BUILD.gn
index d2c053c..17a391a 100644
--- a/ios/web/web_state/ui/BUILD.gn
+++ b/ios/web/web_state/ui/BUILD.gn
@@ -95,6 +95,8 @@
   sources = [
     "crw_context_menu_controller.h",
     "crw_context_menu_controller.mm",
+    "html_element_fetch_request.h",
+    "html_element_fetch_request.mm",
   ]
 
   configs += [ "//build/config/compiler:enable_arc" ]
diff --git a/ios/web/web_state/ui/html_element_fetch_request.h b/ios/web/web_state/ui/html_element_fetch_request.h
new file mode 100644
index 0000000..4571948
--- /dev/null
+++ b/ios/web/web_state/ui/html_element_fetch_request.h
@@ -0,0 +1,32 @@
+// 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 IOS_WEB_WEB_STATE_UI_HTML_ELEMENT_FETCH_REQUEST_H_
+#define IOS_WEB_WEB_STATE_UI_HTML_ELEMENT_FETCH_REQUEST_H_
+
+#import <Foundation/Foundation.h>
+
+namespace base {
+class TimeTicks;
+}  // namespace base
+
+// Tracks request details for fetching attributes of an element.
+@interface HTMLElementFetchRequest : NSObject
+
+// The time this object was created.
+@property(nonatomic, readonly) base::TimeTicks creationTime;
+
+- (instancetype)init NS_UNAVAILABLE;
+// Designated initializer to create a new object with the given completion
+// handler |foundElementHandler|.
+- (instancetype)initWithFoundElementHandler:
+    (void (^)(NSDictionary*))foundElementHandler NS_DESIGNATED_INITIALIZER;
+
+// Calls the |foundElementHandler| from the receiver's initializer with
+// |response| as the parameter.
+- (void)runHandlerWithResponse:(NSDictionary*)response;
+
+@end
+
+#endif  // IOS_WEB_WEB_STATE_UI_HTML_ELEMENT_FETCH_REQUEST_H_
diff --git a/ios/web/web_state/ui/html_element_fetch_request.mm b/ios/web/web_state/ui/html_element_fetch_request.mm
new file mode 100644
index 0000000..89861e70
--- /dev/null
+++ b/ios/web/web_state/ui/html_element_fetch_request.mm
@@ -0,0 +1,37 @@
+// 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.
+
+#import "ios/web/web_state/ui/html_element_fetch_request.h"
+
+#include "base/time/time.h"
+
+#if !defined(__has_feature) || !__has_feature(objc_arc)
+#error "This file requires ARC support."
+#endif
+
+@interface HTMLElementFetchRequest ()
+// Completion handler to call with found DOM element.
+@property(nonatomic, copy) void (^foundElementHandler)(NSDictionary*);
+@end
+
+@implementation HTMLElementFetchRequest
+
+@synthesize creationTime = _creationTime;
+@synthesize foundElementHandler = _foundElementHandler;
+
+- (instancetype)initWithFoundElementHandler:
+    (void (^)(NSDictionary*))foundElementHandler {
+  self = [super init];
+  if (self) {
+    _creationTime = base::TimeTicks::Now();
+    _foundElementHandler = foundElementHandler;
+  }
+  return self;
+}
+
+- (void)runHandlerWithResponse:(NSDictionary*)response {
+  _foundElementHandler(response);
+}
+
+@end
diff --git a/ios/web/web_state/ui/html_element_fetch_request_unittest.mm b/ios/web/web_state/ui/html_element_fetch_request_unittest.mm
new file mode 100644
index 0000000..bfd5731a
--- /dev/null
+++ b/ios/web/web_state/ui/html_element_fetch_request_unittest.mm
@@ -0,0 +1,48 @@
+// 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.
+
+#import "ios/web/web_state/ui/html_element_fetch_request.h"
+
+#include "base/time/time.h"
+#import "ios/web/web_state/context_menu_constants.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "testing/gtest_mac.h"
+#include "testing/platform_test.h"
+
+#if !defined(__has_feature) || !__has_feature(objc_arc)
+#error "This file requires ARC support."
+#endif
+
+namespace web {
+
+using HtmlElementFetchRequestTest = PlatformTest;
+
+// Tests that |creationTime| is set at HtmlElementFetchRequest object creation.
+TEST_F(HtmlElementFetchRequestTest, CreationTime) {
+  HTMLElementFetchRequest* request =
+      [[HTMLElementFetchRequest alloc] initWithFoundElementHandler:nil];
+  base::TimeDelta delta = base::TimeTicks::Now() - request.creationTime;
+  // Validate that |request.creationTime| is "now", but only use second
+  // precision to avoid performance induced test flake.
+  EXPECT_GT(1, delta.InSeconds());
+}
+
+// Tests that |runHandlerWithResponse:| runs the handler from the object's
+// initializer with the expected |response|.
+TEST_F(HtmlElementFetchRequestTest, RunHandler) {
+  __block bool handler_called = false;
+  __block NSDictionary* received_response = nil;
+  void (^handler)(NSDictionary*) = ^(NSDictionary* response) {
+    handler_called = true;
+    received_response = response;
+  };
+  HTMLElementFetchRequest* request =
+      [[HTMLElementFetchRequest alloc] initWithFoundElementHandler:handler];
+  NSDictionary* response = @{kContextMenuElementInnerText : @"text"};
+  [request runHandlerWithResponse:response];
+  EXPECT_TRUE(handler_called);
+  EXPECT_NSEQ(response, received_response);
+}
+
+}  // namespace web
diff --git a/media/audio/audio_input_device.cc b/media/audio/audio_input_device.cc
index 5eb728d..ea731f1 100644
--- a/media/audio/audio_input_device.cc
+++ b/media/audio/audio_input_device.cc
@@ -123,13 +123,13 @@
 }
 
 void AudioInputDevice::Start() {
-  DVLOG(1) << "Start()";
+  TRACE_EVENT0("audio", "AudioInputDevice::Start");
   task_runner()->PostTask(
       FROM_HERE, base::BindOnce(&AudioInputDevice::StartUpOnIOThread, this));
 }
 
 void AudioInputDevice::Stop() {
-  DVLOG(1) << "Stop()";
+  TRACE_EVENT0("audio", "AudioInputDevice::Stop");
 
   {
     base::AutoLock auto_lock(audio_thread_lock_);
@@ -142,6 +142,8 @@
 }
 
 void AudioInputDevice::SetVolume(double volume) {
+  TRACE_EVENT1("audio", "AudioInputDevice::SetVolume", "volume", volume);
+
   if (volume < 0 || volume > 1.0) {
     DLOG(ERROR) << "Invalid volume value specified";
     return;
@@ -153,7 +155,9 @@
 }
 
 void AudioInputDevice::SetAutomaticGainControl(bool enabled) {
-  DVLOG(1) << "SetAutomaticGainControl(enabled=" << enabled << ")";
+  TRACE_EVENT1("audio", "AudioInputDevice::SetAutomaticGainControl", "enabled",
+               enabled);
+
   task_runner()->PostTask(
       FROM_HERE,
       base::BindOnce(&AudioInputDevice::SetAutomaticGainControlOnIOThread, this,
@@ -163,6 +167,7 @@
 void AudioInputDevice::OnStreamCreated(base::SharedMemoryHandle handle,
                                        base::SyncSocket::Handle socket_handle,
                                        bool initially_muted) {
+  TRACE_EVENT0("audio", "AudioInputDevice::OnStreamCreated");
   DCHECK(task_runner()->BelongsToCurrentThread());
   DCHECK(base::SharedMemory::IsHandleValid(handle));
 #if defined(OS_WIN)
@@ -226,13 +231,15 @@
 }
 
 void AudioInputDevice::OnError() {
+  TRACE_EVENT0("audio", "AudioInputDevice::OnError");
   DCHECK(task_runner()->BelongsToCurrentThread());
 
   // Do nothing if the stream has been closed.
   if (state_ < CREATING_STREAM)
     return;
 
-  DLOG(WARNING) << "AudioInputDevice::OnStateChanged(ERROR)";
+  had_callback_error_ = true;
+
   if (state_ == CREATING_STREAM) {
     // At this point, we haven't attempted to start the audio thread.
     // Accessing the hardware might have failed or we may have reached
@@ -256,7 +263,9 @@
 }
 
 void AudioInputDevice::OnMuted(bool is_muted) {
+  TRACE_EVENT0("audio", "AudioInputDevice::OnMuted");
   DCHECK(task_runner()->BelongsToCurrentThread());
+
   // Do nothing if the stream has been closed.
   if (state_ < CREATING_STREAM)
     return;
@@ -264,7 +273,9 @@
 }
 
 void AudioInputDevice::OnIPCClosed() {
+  TRACE_EVENT0("audio", "AudioInputDevice::OnIPCClosed");
   DCHECK(task_runner()->BelongsToCurrentThread());
+
   state_ = IPC_CLOSED;
   ipc_.reset();
 }
@@ -307,6 +318,9 @@
       "Media.Audio.Capture.DetectedMissingCallbacks",
       alive_checker_ ? alive_checker_->DetectedDead() : false);
 
+  UMA_HISTOGRAM_BOOLEAN("Media.Audio.Capture.StreamCallbackError",
+                        had_callback_error_);
+
   // Close the stream, if we haven't already.
   if (state_ >= CREATING_STREAM) {
     ipc_->CloseStream();
diff --git a/media/audio/audio_input_device.h b/media/audio/audio_input_device.h
index 9e99b70..6d3b847 100644
--- a/media/audio/audio_input_device.h
+++ b/media/audio/audio_input_device.h
@@ -153,6 +153,9 @@
   // State enum above.
   State state_;
 
+  // For UMA stats. May only be accessed on the IO thread.
+  bool had_callback_error_ = false;
+
   // The media session ID used to identify which input device to be started.
   // Only modified in Initialize() and ShutDownOnIOThread().
   int session_id_;
diff --git a/media/audio/audio_output_device.cc b/media/audio/audio_output_device.cc
index 9b2688a..b949d07 100644
--- a/media/audio/audio_output_device.cc
+++ b/media/audio/audio_output_device.cc
@@ -115,52 +115,59 @@
 }
 
 void AudioOutputDevice::RequestDeviceAuthorization() {
+  TRACE_EVENT0("audio", "AudioOutputDevice::RequestDeviceAuthorization");
   task_runner()->PostTask(
       FROM_HERE,
-      base::Bind(&AudioOutputDevice::RequestDeviceAuthorizationOnIOThread,
-                 this));
+      base::BindOnce(&AudioOutputDevice::RequestDeviceAuthorizationOnIOThread,
+                     this));
 }
 
 void AudioOutputDevice::Start() {
+  TRACE_EVENT0("audio", "AudioOutputDevice::Start");
   task_runner()->PostTask(
-      FROM_HERE, base::Bind(&AudioOutputDevice::CreateStreamOnIOThread, this));
+      FROM_HERE,
+      base::BindOnce(&AudioOutputDevice::CreateStreamOnIOThread, this));
 }
 
 void AudioOutputDevice::Stop() {
+  TRACE_EVENT0("audio", "AudioOutputDevice::Stop");
   {
     base::AutoLock auto_lock(audio_thread_lock_);
     audio_thread_.reset();
     stopping_hack_ = true;
   }
 
-  task_runner()->PostTask(FROM_HERE,
-      base::Bind(&AudioOutputDevice::ShutDownOnIOThread, this));
+  task_runner()->PostTask(
+      FROM_HERE, base::BindOnce(&AudioOutputDevice::ShutDownOnIOThread, this));
 }
 
 void AudioOutputDevice::Play() {
-  task_runner()->PostTask(FROM_HERE,
-      base::Bind(&AudioOutputDevice::PlayOnIOThread, this));
+  TRACE_EVENT0("audio", "AudioOutputDevice::Play");
+  task_runner()->PostTask(
+      FROM_HERE, base::BindOnce(&AudioOutputDevice::PlayOnIOThread, this));
 }
 
 void AudioOutputDevice::Pause() {
-  task_runner()->PostTask(FROM_HERE,
-      base::Bind(&AudioOutputDevice::PauseOnIOThread, this));
+  TRACE_EVENT0("audio", "AudioOutputDevice::Pause");
+  task_runner()->PostTask(
+      FROM_HERE, base::BindOnce(&AudioOutputDevice::PauseOnIOThread, this));
 }
 
 bool AudioOutputDevice::SetVolume(double volume) {
+  TRACE_EVENT1("audio", "AudioOutputDevice::Pause", "volume", volume);
+
   if (volume < 0 || volume > 1.0)
     return false;
 
-  if (!task_runner()->PostTask(FROM_HERE,
-          base::Bind(&AudioOutputDevice::SetVolumeOnIOThread, this, volume))) {
-    return false;
-  }
-
-  return true;
+  return task_runner()->PostTask(
+      FROM_HERE,
+      base::BindOnce(&AudioOutputDevice::SetVolumeOnIOThread, this, volume));
 }
 
 OutputDeviceInfo AudioOutputDevice::GetOutputDeviceInfo() {
-  CHECK(!task_runner()->BelongsToCurrentThread());
+  TRACE_EVENT0("audio", "AudioOutputDevice::GetOutputDeviceInfo");
+  DCHECK(!task_runner()->BelongsToCurrentThread());
+
   did_receive_auth_.Wait();
   return OutputDeviceInfo(AudioDeviceDescription::UseSessionIdToSelectDevice(
                               session_id_, device_id_)
@@ -196,13 +203,14 @@
     auth_timeout_action_.reset(new base::OneShotTimer());
     auth_timeout_action_->Start(
         FROM_HERE, auth_timeout_,
-        base::Bind(&AudioOutputDevice::OnDeviceAuthorized, this,
-                   OUTPUT_DEVICE_STATUS_ERROR_TIMED_OUT,
-                   media::AudioParameters(), std::string()));
+        base::BindRepeating(&AudioOutputDevice::OnDeviceAuthorized, this,
+                            OUTPUT_DEVICE_STATUS_ERROR_TIMED_OUT,
+                            media::AudioParameters(), std::string()));
   }
 }
 
 void AudioOutputDevice::CreateStreamOnIOThread() {
+  TRACE_EVENT0("audio", "AudioOutputDevice::Create");
   DCHECK(task_runner()->BelongsToCurrentThread());
   DCHECK(callback_) << "Initialize hasn't been called";
   switch (state_) {
@@ -290,6 +298,9 @@
   audio_thread_.reset();
   audio_callback_.reset();
   stopping_hack_ = false;
+
+  UMA_HISTOGRAM_BOOLEAN("Media.Audio.Render.StreamCallbackError",
+                        had_callback_error_);
 }
 
 void AudioOutputDevice::SetVolumeOnIOThread(double volume) {
@@ -299,13 +310,15 @@
 }
 
 void AudioOutputDevice::OnError() {
+  TRACE_EVENT0("audio", "AudioOutputDevice::OnError");
+
   DCHECK(task_runner()->BelongsToCurrentThread());
 
   // Do nothing if the stream has been closed.
   if (state_ < CREATING_STREAM)
     return;
 
-  DLOG(WARNING) << "AudioOutputDevice::OnError()";
+  had_callback_error_ = true;
   // Don't dereference the callback object if the audio thread
   // is stopped or stopping.  That could mean that the callback
   // object has been deleted.
@@ -359,6 +372,8 @@
   }
 
   if (device_status == OUTPUT_DEVICE_STATUS_OK) {
+    TRACE_EVENT0("audio", "AudioOutputDevice authorized");
+
     state_ = AUTHORIZED;
     if (!did_receive_auth_.IsSignaled()) {
       output_params_ = output_params;
@@ -380,6 +395,9 @@
     if (start_on_authorized_)
       CreateStreamOnIOThread();
   } else {
+    TRACE_EVENT1("audio", "AudioOutputDevice not authorized", "auth status",
+                 device_status_);
+
     // Closing IPC forces a Signal(), so no clients are locked waiting
     // indefinitely after this method returns.
     ipc_->CloseStream();
@@ -392,6 +410,8 @@
 void AudioOutputDevice::OnStreamCreated(
     base::SharedMemoryHandle handle,
     base::SyncSocket::Handle socket_handle) {
+  TRACE_EVENT0("audio", "AudioOutputDevice::OnStreamCreated")
+
   DCHECK(task_runner()->BelongsToCurrentThread());
   DCHECK(base::SharedMemory::IsHandleValid(handle));
 #if defined(OS_WIN)
@@ -438,7 +458,9 @@
 }
 
 void AudioOutputDevice::OnIPCClosed() {
+  TRACE_EVENT0("audio", "AudioOutputDevice::OnIPCClosed");
   DCHECK(task_runner()->BelongsToCurrentThread());
+
   state_ = IPC_CLOSED;
   ipc_.reset();
 
diff --git a/media/audio/audio_output_device.h b/media/audio/audio_output_device.h
index c6755a8e..4f7e118 100644
--- a/media/audio/audio_output_device.h
+++ b/media/audio/audio_output_device.h
@@ -180,6 +180,9 @@
   // State of Start() calls before OnDeviceAuthorized() is called.
   bool start_on_authorized_;
 
+  // For UMA stats. May only be accessed on the IO thread.
+  bool had_callback_error_ = false;
+
   // State of Play() / Pause() calls before OnStreamCreated() is called.
   bool play_on_start_;
 
diff --git a/media/cast/net/udp_socket_client_unittest.cc b/media/cast/net/udp_socket_client_unittest.cc
index 34c0065..22d8fd6 100644
--- a/media/cast/net/udp_socket_client_unittest.cc
+++ b/media/cast/net/udp_socket_client_unittest.cc
@@ -110,9 +110,6 @@
   // network::mojom::NetworkContext implementation:
   void CreateURLLoaderFactory(network::mojom::URLLoaderFactoryRequest request,
                               uint32_t process_id) override {}
-  void HandleViewCacheRequest(
-      const GURL& url,
-      network::mojom::URLLoaderClientPtr client) override {}
   void GetCookieManager(network::mojom::CookieManagerRequest request) override {
   }
   void GetRestrictedCookieManager(
diff --git a/net/BUILD.gn b/net/BUILD.gn
index 237b857..b28d93e 100644
--- a/net/BUILD.gn
+++ b/net/BUILD.gn
@@ -538,8 +538,6 @@
       "cert/cert_verify_proc_nss.h",
       "cert/cert_verify_proc_win.cc",
       "cert/cert_verify_proc_win.h",
-      "cert/crl_set_storage.cc",
-      "cert/crl_set_storage.h",
       "cert/ct_log_response_parser.cc",
       "cert/ct_log_response_parser.h",
       "cert/ct_log_verifier.cc",
@@ -2862,20 +2860,6 @@
     ]
   }
 
-  executable("crl_set_dump") {
-    testonly = true
-    sources = [
-      "tools/crl_set_dump/crl_set_dump.cc",
-    ]
-
-    deps = [
-      ":net",
-      "//base",
-      "//build/config:exe_and_shlib_deps",
-      "//build/win:default_exe_manifest",
-    ]
-  }
-
   executable("dns_fuzz_stub") {
     testonly = true
     sources = [
diff --git a/net/android/junit/src/org/chromium/net/HttpNegotiateAuthenticatorTest.java b/net/android/junit/src/org/chromium/net/HttpNegotiateAuthenticatorTest.java
index 723bd04..9d381cf 100644
--- a/net/android/junit/src/org/chromium/net/HttpNegotiateAuthenticatorTest.java
+++ b/net/android/junit/src/org/chromium/net/HttpNegotiateAuthenticatorTest.java
@@ -58,7 +58,6 @@
 import org.robolectric.shadows.multidex.ShadowMultiDex;
 
 import org.chromium.base.ApplicationStatus;
-import org.chromium.base.BaseChromiumApplication;
 import org.chromium.base.test.BaseRobolectricTestRunner;
 import org.chromium.net.HttpNegotiateAuthenticator.GetAccountsCallback;
 import org.chromium.net.HttpNegotiateAuthenticator.RequestData;
@@ -70,7 +69,7 @@
  * Robolectric tests for HttpNegotiateAuthenticator
  */
 @RunWith(BaseRobolectricTestRunner.class)
-@Config(manifest = Config.NONE, application = BaseChromiumApplication.class,
+@Config(manifest = Config.NONE,
         shadows = {HttpNegotiateAuthenticatorTest.ExtendedShadowAccountManager.class,
                 ShadowMultiDex.class})
 public class HttpNegotiateAuthenticatorTest {
diff --git a/net/android/unittest_support/AndroidManifest.xml b/net/android/unittest_support/AndroidManifest.xml
index a6ee79bb..a7f04e7 100644
--- a/net/android/unittest_support/AndroidManifest.xml
+++ b/net/android/unittest_support/AndroidManifest.xml
@@ -27,7 +27,7 @@
     <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
 
     <application android:label="NativeTests"
-            android:name="org.chromium.base.BaseChromiumApplication">
+            android:name="org.chromium.native_test.NativeTestApplication">
         <activity android:name=".NativeUnitTestActivity"
                 android:label="NativeTest"
                 android:configChanges="orientation|keyboardHidden"
diff --git a/net/cert/cert_verify_proc_mac_unittest.cc b/net/cert/cert_verify_proc_mac_unittest.cc
index 91bcd26c..79a0a08d 100644
--- a/net/cert/cert_verify_proc_mac_unittest.cc
+++ b/net/cert/cert_verify_proc_mac_unittest.cc
@@ -15,7 +15,6 @@
 #include "net/cert/cert_verifier.h"
 #include "net/cert/cert_verify_result.h"
 #include "net/cert/crl_set.h"
-#include "net/cert/crl_set_storage.h"
 #include "net/cert/test_keychain_search_list_mac.h"
 #include "net/cert/test_root_certs.h"
 #include "net/cert/x509_certificate.h"
@@ -103,7 +102,7 @@
   EXPECT_TRUE(base::ReadFileToString(
       GetTestCertsDirectory().AppendASCII("multi-root-crlset-C.raw"),
       &crl_set_bytes));
-  ASSERT_TRUE(CRLSetStorage::Parse(crl_set_bytes, &crl_set));
+  ASSERT_TRUE(CRLSet::Parse(crl_set_bytes, &crl_set));
 
   int flags = 0;
   CertVerifyResult verify_result;
diff --git a/net/cert/cert_verify_proc_unittest.cc b/net/cert/cert_verify_proc_unittest.cc
index 95331c0..191650d4 100644
--- a/net/cert/cert_verify_proc_unittest.cc
+++ b/net/cert/cert_verify_proc_unittest.cc
@@ -24,7 +24,6 @@
 #include "net/cert/cert_verify_proc_builtin.h"
 #include "net/cert/cert_verify_result.h"
 #include "net/cert/crl_set.h"
-#include "net/cert/crl_set_storage.h"
 #include "net/cert/ev_root_ca_metadata.h"
 #include "net/cert/internal/signature_algorithm.h"
 #include "net/cert/test_root_certs.h"
@@ -1850,7 +1849,7 @@
   EXPECT_TRUE(base::ReadFileToString(
       GetTestCertsDirectory().AppendASCII("crlset_by_leaf_spki.raw"),
       &crl_set_bytes));
-  ASSERT_TRUE(CRLSetStorage::Parse(crl_set_bytes, &crl_set));
+  ASSERT_TRUE(CRLSet::Parse(crl_set_bytes, &crl_set));
 
   error = Verify(cert.get(), "127.0.0.1", flags, crl_set.get(),
                  CertificateList(), &verify_result);
@@ -1862,7 +1861,7 @@
   EXPECT_TRUE(base::ReadFileToString(
       GetTestCertsDirectory().AppendASCII("crlset_by_root_serial.raw"),
       &crl_set_bytes));
-  ASSERT_TRUE(CRLSetStorage::Parse(crl_set_bytes, &crl_set));
+  ASSERT_TRUE(CRLSet::Parse(crl_set_bytes, &crl_set));
 
   error = Verify(cert.get(), "127.0.0.1", flags, crl_set.get(),
                  CertificateList(), &verify_result);
@@ -1911,7 +1910,7 @@
   ASSERT_TRUE(base::ReadFileToString(
       GetTestCertsDirectory().AppendASCII("crlset_by_intermediate_serial.raw"),
       &crl_set_bytes));
-  ASSERT_TRUE(CRLSetStorage::Parse(crl_set_bytes, &crl_set));
+  ASSERT_TRUE(CRLSet::Parse(crl_set_bytes, &crl_set));
 
   error = Verify(leaf.get(), "127.0.0.1", flags, crl_set.get(),
                  CertificateList(), &verify_result);
@@ -1951,7 +1950,7 @@
   ASSERT_TRUE(base::ReadFileToString(
       GetTestCertsDirectory().AppendASCII("crlset_by_leaf_subject_no_spki.raw"),
       &crl_set_bytes));
-  ASSERT_TRUE(CRLSetStorage::Parse(crl_set_bytes, &crl_set));
+  ASSERT_TRUE(CRLSet::Parse(crl_set_bytes, &crl_set));
 
   error = Verify(leaf.get(), "127.0.0.1", flags, crl_set.get(),
                  CertificateList(), &verify_result);
@@ -1961,7 +1960,7 @@
   ASSERT_TRUE(base::ReadFileToString(
       GetTestCertsDirectory().AppendASCII("crlset_by_root_subject_no_spki.raw"),
       &crl_set_bytes));
-  ASSERT_TRUE(CRLSetStorage::Parse(crl_set_bytes, &crl_set));
+  ASSERT_TRUE(CRLSet::Parse(crl_set_bytes, &crl_set));
 
   error = Verify(leaf.get(), "127.0.0.1", flags, crl_set.get(),
                  CertificateList(), &verify_result);
@@ -1972,7 +1971,7 @@
   ASSERT_TRUE(base::ReadFileToString(
       GetTestCertsDirectory().AppendASCII("crlset_by_root_subject.raw"),
       &crl_set_bytes));
-  ASSERT_TRUE(CRLSetStorage::Parse(crl_set_bytes, &crl_set));
+  ASSERT_TRUE(CRLSet::Parse(crl_set_bytes, &crl_set));
 
   error = Verify(leaf.get(), "127.0.0.1", flags, crl_set.get(),
                  CertificateList(), &verify_result);
@@ -2060,7 +2059,7 @@
     std::string crl_set_bytes;
     EXPECT_TRUE(base::ReadFileToString(
         GetTestCertsDirectory().AppendASCII(testcase.crlset), &crl_set_bytes));
-    ASSERT_TRUE(CRLSetStorage::Parse(crl_set_bytes, &crl_set));
+    ASSERT_TRUE(CRLSet::Parse(crl_set_bytes, &crl_set));
 
     int flags = 0;
     CertVerifyResult verify_result;
diff --git a/net/cert/crl_set.cc b/net/cert/crl_set.cc
index da71f4b..c860467 100644
--- a/net/cert/crl_set.cc
+++ b/net/cert/crl_set.cc
@@ -4,14 +4,188 @@
 
 #include "net/cert/crl_set.h"
 
-#include "base/logging.h"
+#include "base/base64.h"
+#include "base/json/json_reader.h"
 #include "base/time/time.h"
+#include "base/trace_event/trace_event.h"
+#include "base/values.h"
 #include "crypto/sha2.h"
+#include "net/base/trace_constants.h"
 #include "third_party/boringssl/src/include/openssl/bytestring.h"
 #include "third_party/boringssl/src/include/openssl/mem.h"
 
 namespace net {
 
+namespace {
+
+// CRLSet format:
+//
+// uint16le header_len
+// byte[header_len] header_bytes
+// repeated {
+//   byte[32] parent_spki_sha256
+//   uint32le num_serials
+//   [num_serials] {
+//     uint8_t serial_length;
+//     byte[serial_length] serial;
+//   }
+//
+// header_bytes consists of a JSON dictionary with the following keys:
+//   Version (int): currently 0
+//   ContentType (string): "CRLSet" or "CRLSetDelta" (magic value)
+//   DeltaFrom (int32_t): if this is a delta update (see below), then this
+//       contains the sequence number of the base CRLSet.
+//   Sequence (int32_t): the monotonic sequence number of this CRL set.
+//
+// ReadHeader reads the header (including length prefix) from |data| and
+// updates |data| to remove the header on return. Caller takes ownership of the
+// returned pointer.
+base::DictionaryValue* ReadHeader(base::StringPiece* data) {
+  uint16_t header_len;
+  if (data->size() < sizeof(header_len))
+    return nullptr;
+  // Assumes little-endian.
+  memcpy(&header_len, data->data(), sizeof(header_len));
+  data->remove_prefix(sizeof(header_len));
+
+  if (data->size() < header_len)
+    return nullptr;
+
+  const base::StringPiece header_bytes(data->data(), header_len);
+  data->remove_prefix(header_len);
+
+  std::unique_ptr<base::Value> header =
+      base::JSONReader::Read(header_bytes, base::JSON_ALLOW_TRAILING_COMMAS);
+  if (header.get() == nullptr)
+    return nullptr;
+
+  if (!header->is_dict())
+    return nullptr;
+  return static_cast<base::DictionaryValue*>(header.release());
+}
+
+// kCurrentFileVersion is the version of the CRLSet file format that we
+// currently implement.
+static const int kCurrentFileVersion = 0;
+
+bool ReadCRL(base::StringPiece* data,
+             std::string* out_parent_spki_hash,
+             std::vector<std::string>* out_serials) {
+  if (data->size() < crypto::kSHA256Length)
+    return false;
+  out_parent_spki_hash->assign(data->data(), crypto::kSHA256Length);
+  data->remove_prefix(crypto::kSHA256Length);
+
+  uint32_t num_serials;
+  if (data->size() < sizeof(num_serials))
+    return false;
+  // Assumes little endian.
+  memcpy(&num_serials, data->data(), sizeof(num_serials));
+  data->remove_prefix(sizeof(num_serials));
+
+  if (num_serials > 32 * 1024 * 1024)  // Sanity check.
+    return false;
+
+  out_serials->reserve(num_serials);
+
+  for (uint32_t i = 0; i < num_serials; ++i) {
+    if (data->size() < sizeof(uint8_t))
+      return false;
+
+    uint8_t serial_length = data->data()[0];
+    data->remove_prefix(sizeof(uint8_t));
+
+    if (data->size() < serial_length)
+      return false;
+
+    out_serials->push_back(std::string());
+    out_serials->back().assign(data->data(), serial_length);
+    data->remove_prefix(serial_length);
+  }
+
+  return true;
+}
+
+// CopyHashListFromHeader parses a list of base64-encoded, SHA-256 hashes from
+// the given |key| in |header_dict| and sets |*out| to the decoded values. It's
+// not an error if |key| is not found in |header_dict|.
+bool CopyHashListFromHeader(base::DictionaryValue* header_dict,
+                            const char* key,
+                            std::vector<std::string>* out) {
+  base::ListValue* list = nullptr;
+  if (!header_dict->GetList(key, &list)) {
+    // Hash lists are optional so it's not an error if not present.
+    return true;
+  }
+
+  out->clear();
+  out->reserve(list->GetSize());
+
+  std::string sha256_base64;
+
+  for (size_t i = 0; i < list->GetSize(); ++i) {
+    sha256_base64.clear();
+
+    if (!list->GetString(i, &sha256_base64))
+      return false;
+
+    out->push_back(std::string());
+    if (!base::Base64Decode(sha256_base64, &out->back())) {
+      out->pop_back();
+      return false;
+    }
+  }
+
+  return true;
+}
+
+// CopyHashToHashesMapFromHeader parse a map from base64-encoded, SHA-256
+// hashes to lists of the same, from the given |key| in |header_dict|. It
+// copies the map data into |out| (after base64-decoding) and writes the order
+// of map keys into |out_key_order|.
+bool CopyHashToHashesMapFromHeader(
+    base::DictionaryValue* header_dict,
+    const char* key,
+    std::unordered_map<std::string, std::vector<std::string>>* out,
+    std::vector<std::string>* out_key_order) {
+  out->clear();
+  out_key_order->clear();
+
+  base::Value* const dict =
+      header_dict->FindKeyOfType(key, base::Value::Type::DICTIONARY);
+  if (dict == nullptr) {
+    // Maps are optional so it's not an error if not present.
+    return true;
+  }
+
+  for (const auto& i : dict->DictItems()) {
+    if (!i.second.is_list()) {
+      return false;
+    }
+
+    std::vector<std::string> allowed_spkis;
+    for (const auto& j : i.second.GetList()) {
+      allowed_spkis.push_back(std::string());
+      if (!j.is_string() ||
+          !base::Base64Decode(j.GetString(), &allowed_spkis.back())) {
+        return false;
+      }
+    }
+
+    std::string subject_hash;
+    if (!base::Base64Decode(i.first, &subject_hash)) {
+      return false;
+    }
+
+    out_key_order->push_back(subject_hash);
+    (*out)[subject_hash] = allowed_spkis;
+  }
+
+  return true;
+}
+
+}  // namespace
+
 CRLSet::CRLSet()
     : sequence_(0),
       not_after_(0) {
@@ -19,6 +193,81 @@
 
 CRLSet::~CRLSet() = default;
 
+// static
+bool CRLSet::Parse(base::StringPiece data, scoped_refptr<CRLSet>* out_crl_set) {
+  TRACE_EVENT0(kNetTracingCategory, "CRLSet::Parse");
+// Other parts of Chrome assume that we're little endian, so we don't lose
+// anything by doing this.
+#if defined(__BYTE_ORDER)
+  // Linux check
+  static_assert(__BYTE_ORDER == __LITTLE_ENDIAN, "assumes little endian");
+#elif defined(__BIG_ENDIAN__)
+// Mac check
+#error assumes little endian
+#endif
+
+  std::unique_ptr<base::DictionaryValue> header_dict(ReadHeader(&data));
+  if (!header_dict.get())
+    return false;
+
+  std::string contents;
+  if (!header_dict->GetString("ContentType", &contents))
+    return false;
+  if (contents != "CRLSet")
+    return false;
+
+  int version;
+  if (!header_dict->GetInteger("Version", &version) ||
+      version != kCurrentFileVersion) {
+    return false;
+  }
+
+  int sequence;
+  if (!header_dict->GetInteger("Sequence", &sequence))
+    return false;
+
+  double not_after;
+  if (!header_dict->GetDouble("NotAfter", &not_after)) {
+    // NotAfter is optional for now.
+    not_after = 0;
+  }
+  if (not_after < 0)
+    return false;
+
+  scoped_refptr<CRLSet> crl_set(new CRLSet());
+  crl_set->sequence_ = static_cast<uint32_t>(sequence);
+  crl_set->not_after_ = static_cast<uint64_t>(not_after);
+  crl_set->crls_.reserve(64);  // Value observed experimentally.
+
+  for (size_t crl_index = 0; !data.empty(); crl_index++) {
+    // Speculatively push back a pair and pass it to ReadCRL() to avoid
+    // unnecessary copies.
+    crl_set->crls_.push_back(
+        std::make_pair(std::string(), std::vector<std::string>()));
+    std::pair<std::string, std::vector<std::string>>* const back_pair =
+        &crl_set->crls_.back();
+
+    if (!ReadCRL(&data, &back_pair->first, &back_pair->second)) {
+      // Undo the speculative push_back() performed above.
+      crl_set->crls_.pop_back();
+      return false;
+    }
+
+    crl_set->crls_index_by_issuer_[back_pair->first] = crl_index;
+  }
+
+  if (!CopyHashListFromHeader(header_dict.get(), "BlockedSPKIs",
+                              &crl_set->blocked_spkis_) ||
+      !CopyHashToHashesMapFromHeader(header_dict.get(), "LimitedSubjects",
+                                     &crl_set->limited_subjects_,
+                                     &crl_set->limited_subjects_ordered_)) {
+    return false;
+  }
+
+  *out_crl_set = std::move(crl_set);
+  return true;
+}
+
 CRLSet::Result CRLSet::CheckSPKI(const base::StringPiece& spki_hash) const {
   for (std::vector<std::string>::const_iterator i = blocked_spkis_.begin();
        i != blocked_spkis_.end(); ++i) {
@@ -96,11 +345,11 @@
 
 // static
 scoped_refptr<CRLSet> CRLSet::EmptyCRLSetForTesting() {
-  return ForTesting(false, NULL, "", "", {});
+  return ForTesting(false, nullptr, "", "", {});
 }
 
 scoped_refptr<CRLSet> CRLSet::ExpiredCRLSetForTesting() {
-  return ForTesting(true, NULL, "", "", {});
+  return ForTesting(true, nullptr, "", "", {});
 }
 
 // static
@@ -143,7 +392,7 @@
   if (is_expired)
     crl_set->not_after_ = 1;
 
-  if (issuer_spki != NULL) {
+  if (issuer_spki != nullptr) {
     const std::string spki(reinterpret_cast<const char*>(issuer_spki->data),
                            sizeof(issuer_spki->data));
     crl_set->crls_.push_back(make_pair(spki, std::vector<std::string>()));
diff --git a/net/cert/crl_set.h b/net/cert/crl_set.h
index 8cb293f..7a02be6d 100644
--- a/net/cert/crl_set.h
+++ b/net/cert/crl_set.h
@@ -32,6 +32,10 @@
     GOOD,     // the certificate is not listed.
   };
 
+  // Parses the bytes in |data| and, on success, puts a new CRLSet in
+  // |out_crl_set| and returns true.
+  static bool Parse(base::StringPiece data, scoped_refptr<CRLSet>* out_crl_set);
+
   // CheckSPKI checks whether the given SPKI has been listed as blocked.
   //   spki_hash: the SHA256 of the SubjectPublicKeyInfo of the certificate.
   Result CheckSPKI(const base::StringPiece& spki_hash) const;
@@ -95,7 +99,6 @@
   ~CRLSet();
 
   friend class base::RefCountedThreadSafe<CRLSet>;
-  friend class CRLSetStorage;
 
   uint32_t sequence_;
   CRLList crls_;
diff --git a/net/cert/crl_set_storage.cc b/net/cert/crl_set_storage.cc
deleted file mode 100644
index 0ca26779..0000000
--- a/net/cert/crl_set_storage.cc
+++ /dev/null
@@ -1,643 +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 "net/cert/crl_set_storage.h"
-
-#include <memory>
-
-#include "base/base64.h"
-#include "base/format_macros.h"
-#include "base/json/json_reader.h"
-#include "base/numerics/safe_conversions.h"
-#include "base/strings/stringprintf.h"
-#include "base/trace_event/trace_event.h"
-#include "base/values.h"
-#include "crypto/sha2.h"
-#include "net/base/trace_constants.h"
-#include "third_party/zlib/zlib.h"
-
-namespace net {
-
-// Decompress zlib decompressed |in| into |out|. |out_len| is the number of
-// bytes at |out| and must be exactly equal to the size of the decompressed
-// data.
-static bool DecompressZlib(uint8_t* out, int out_len, base::StringPiece in) {
-  z_stream z;
-  memset(&z, 0, sizeof(z));
-
-  z.next_in = reinterpret_cast<Bytef*>(const_cast<char*>(in.data()));
-  z.avail_in = in.size();
-  z.next_out = reinterpret_cast<Bytef*>(out);
-  z.avail_out = out_len;
-
-  if (inflateInit(&z) != Z_OK)
-    return false;
-  bool ret = false;
-  int r = inflate(&z, Z_FINISH);
-  if (r != Z_STREAM_END)
-    goto err;
-  if (z.avail_in || z.avail_out)
-    goto err;
-  ret = true;
-
- err:
-  inflateEnd(&z);
-  return ret;
-}
-
-// CRLSet format:
-//
-// uint16le header_len
-// byte[header_len] header_bytes
-// repeated {
-//   byte[32] parent_spki_sha256
-//   uint32le num_serials
-//   [num_serials] {
-//     uint8_t serial_length;
-//     byte[serial_length] serial;
-//   }
-//
-// header_bytes consists of a JSON dictionary with the following keys:
-//   Version (int): currently 0
-//   ContentType (string): "CRLSet" or "CRLSetDelta" (magic value)
-//   DeltaFrom (int32_t): if this is a delta update (see below), then this
-//       contains the sequence number of the base CRLSet.
-//   Sequence (int32_t): the monotonic sequence number of this CRL set.
-//
-// A delta CRLSet is similar to a CRLSet:
-//
-// struct CompressedChanges {
-//    uint32le uncompressed_size
-//    uint32le compressed_size
-//    byte[compressed_size] zlib_data
-// }
-//
-// uint16le header_len
-// byte[header_len] header_bytes
-// CompressedChanges crl_changes
-// [crl_changes.uncompressed_size] {
-//   switch (crl_changes[i]) {
-//   case 0:
-//     // CRL is the same
-//   case 1:
-//     // New CRL inserted
-//     // See CRL structure from the non-delta format
-//   case 2:
-//     // CRL deleted
-//   case 3:
-//     // CRL changed
-//     CompressedChanges serials_changes
-//     [serials_changes.uncompressed_size] {
-//       switch (serials_changes[i]) {
-//       case 0:
-//         // the serial is the same
-//       case 1:
-//         // serial inserted
-//         uint8_t serial_length
-//         byte[serial_length] serial
-//       case 2:
-//         // serial deleted
-//       }
-//     }
-//   }
-// }
-//
-// A delta CRLSet applies to a specific CRL set as given in the
-// header's "DeltaFrom" value. The delta describes the changes to each CRL
-// in turn with a zlib compressed array of options: either the CRL is the same,
-// a new CRL is inserted, the CRL is deleted or the CRL is updated. In the case
-// of an update, the serials in the CRL are considered in the same fashion
-// except there is no delta update of a serial number: they are either
-// inserted, deleted or left the same.
-
-// ReadHeader reads the header (including length prefix) from |data| and
-// updates |data| to remove the header on return. Caller takes ownership of the
-// returned pointer.
-static base::DictionaryValue* ReadHeader(base::StringPiece* data) {
-  uint16_t header_len;
-  if (data->size() < sizeof(header_len))
-    return NULL;
-  // Assumes little-endian.
-  memcpy(&header_len, data->data(), sizeof(header_len));
-  data->remove_prefix(sizeof(header_len));
-
-  if (data->size() < header_len)
-    return NULL;
-
-  const base::StringPiece header_bytes(data->data(), header_len);
-  data->remove_prefix(header_len);
-
-  std::unique_ptr<base::Value> header =
-      base::JSONReader::Read(header_bytes, base::JSON_ALLOW_TRAILING_COMMAS);
-  if (header.get() == NULL)
-    return NULL;
-
-  if (!header->is_dict())
-    return NULL;
-  return static_cast<base::DictionaryValue*>(header.release());
-}
-
-// kCurrentFileVersion is the version of the CRLSet file format that we
-// currently implement.
-static const int kCurrentFileVersion = 0;
-
-static bool ReadCRL(base::StringPiece* data, std::string* out_parent_spki_hash,
-                    std::vector<std::string>* out_serials) {
-  if (data->size() < crypto::kSHA256Length)
-    return false;
-  out_parent_spki_hash->assign(data->data(), crypto::kSHA256Length);
-  data->remove_prefix(crypto::kSHA256Length);
-
-  uint32_t num_serials;
-  if (data->size() < sizeof(num_serials))
-    return false;
-  // Assumes little endian.
-  memcpy(&num_serials, data->data(), sizeof(num_serials));
-  data->remove_prefix(sizeof(num_serials));
-
-  if (num_serials > 32 * 1024 * 1024)  // Sanity check.
-    return false;
-
-  out_serials->reserve(num_serials);
-
-  for (uint32_t i = 0; i < num_serials; ++i) {
-    if (data->size() < sizeof(uint8_t))
-      return false;
-
-    uint8_t serial_length = data->data()[0];
-    data->remove_prefix(sizeof(uint8_t));
-
-    if (data->size() < serial_length)
-      return false;
-
-    out_serials->push_back(std::string());
-    out_serials->back().assign(data->data(), serial_length);
-    data->remove_prefix(serial_length);
-  }
-
-  return true;
-}
-
-// CopyHashListFromHeader parses a list of base64-encoded, SHA-256 hashes from
-// the given |key| in |header_dict| and sets |*out| to the decoded values. It's
-// not an error if |key| is not found in |header_dict|.
-static bool CopyHashListFromHeader(base::DictionaryValue* header_dict,
-                                   const char* key,
-                                   std::vector<std::string>* out) {
-  base::ListValue* list = nullptr;
-  if (!header_dict->GetList(key, &list)) {
-    // Hash lists are optional so it's not an error if not present.
-    return true;
-  }
-
-  out->clear();
-  out->reserve(list->GetSize());
-
-  std::string sha256_base64;
-
-  for (size_t i = 0; i < list->GetSize(); ++i) {
-    sha256_base64.clear();
-
-    if (!list->GetString(i, &sha256_base64))
-      return false;
-
-    out->push_back(std::string());
-    if (!base::Base64Decode(sha256_base64, &out->back())) {
-      out->pop_back();
-      return false;
-    }
-  }
-
-  return true;
-}
-
-// CopyHashToHashesMapFromHeader parse a map from base64-encoded, SHA-256
-// hashes to lists of the same, from the given |key| in |header_dict|. It
-// copies the map data into |out| (after base64-decoding) and writes the order
-// of map keys into |out_key_order|.
-static bool CopyHashToHashesMapFromHeader(
-    base::DictionaryValue* header_dict,
-    const char* key,
-    std::unordered_map<std::string, std::vector<std::string>>* out,
-    std::vector<std::string>* out_key_order) {
-  out->clear();
-  out_key_order->clear();
-
-  base::Value* const dict =
-      header_dict->FindKeyOfType(key, base::Value::Type::DICTIONARY);
-  if (dict == nullptr) {
-    // Maps are optional so it's not an error if not present.
-    return true;
-  }
-
-  for (const auto& i : dict->DictItems()) {
-    if (!i.second.is_list()) {
-      return false;
-    }
-
-    std::vector<std::string> allowed_spkis;
-    for (const auto& j : i.second.GetList()) {
-      allowed_spkis.push_back(std::string());
-      if (!j.is_string() ||
-          !base::Base64Decode(j.GetString(), &allowed_spkis.back())) {
-        return false;
-      }
-    }
-
-    std::string subject_hash;
-    if (!base::Base64Decode(i.first, &subject_hash)) {
-      return false;
-    }
-
-    out_key_order->push_back(subject_hash);
-    (*out)[subject_hash] = allowed_spkis;
-  }
-
-  return true;
-}
-
-// kMaxUncompressedChangesLength is the largest changes array that we'll
-// accept. This bounds the number of CRLs in the CRLSet as well as the number
-// of serial numbers in a given CRL.
-static const unsigned kMaxUncompressedChangesLength = 1024 * 1024;
-
-static bool ReadChanges(base::StringPiece* data,
-                        std::vector<uint8_t>* out_changes) {
-  uint32_t uncompressed_size, compressed_size;
-  if (data->size() < sizeof(uncompressed_size) + sizeof(compressed_size))
-    return false;
-  // Assumes little endian.
-  memcpy(&uncompressed_size, data->data(), sizeof(uncompressed_size));
-  data->remove_prefix(sizeof(uncompressed_size));
-  memcpy(&compressed_size, data->data(), sizeof(compressed_size));
-  data->remove_prefix(sizeof(compressed_size));
-
-  if (uncompressed_size > kMaxUncompressedChangesLength)
-    return false;
-  if (data->size() < compressed_size)
-    return false;
-
-  out_changes->clear();
-  if (uncompressed_size == 0)
-    return true;
-
-  out_changes->resize(uncompressed_size);
-  base::StringPiece compressed(data->data(), compressed_size);
-  data->remove_prefix(compressed_size);
-  return DecompressZlib(&(*out_changes)[0], uncompressed_size, compressed);
-}
-
-// These are the range coder symbols used in delta updates.
-enum {
-  SYMBOL_SAME = 0,
-  SYMBOL_INSERT = 1,
-  SYMBOL_DELETE = 2,
-  SYMBOL_CHANGED = 3,
-};
-
-static bool ReadDeltaCRL(base::StringPiece* data,
-                         const std::vector<std::string>& old_serials,
-                         std::vector<std::string>* out_serials) {
-  std::vector<uint8_t> changes;
-  if (!ReadChanges(data, &changes))
-    return false;
-
-  size_t i = 0;
-  for (std::vector<uint8_t>::const_iterator k = changes.begin();
-       k != changes.end(); ++k) {
-    if (*k == SYMBOL_SAME) {
-      if (i >= old_serials.size())
-        return false;
-      out_serials->push_back(old_serials[i]);
-      i++;
-    } else if (*k == SYMBOL_INSERT) {
-      if (data->size() < sizeof(uint8_t))
-        return false;
-      uint8_t serial_length = data->data()[0];
-      data->remove_prefix(sizeof(uint8_t));
-
-      if (data->size() < serial_length)
-        return false;
-      const std::string serial(data->data(), serial_length);
-      data->remove_prefix(serial_length);
-
-      out_serials->push_back(serial);
-    } else if (*k == SYMBOL_DELETE) {
-      if (i >= old_serials.size())
-        return false;
-      i++;
-    } else {
-      NOTREACHED();
-      return false;
-    }
-  }
-
-  if (i != old_serials.size())
-    return false;
-  return true;
-}
-
-// static
-bool CRLSetStorage::Parse(base::StringPiece data,
-                          scoped_refptr<CRLSet>* out_crl_set) {
-  TRACE_EVENT0(kNetTracingCategory, "CRLSetStorage::Parse");
-  // Other parts of Chrome assume that we're little endian, so we don't lose
-  // anything by doing this.
-#if defined(__BYTE_ORDER)
-  // Linux check
-  static_assert(__BYTE_ORDER == __LITTLE_ENDIAN, "assumes little endian");
-#elif defined(__BIG_ENDIAN__)
-  // Mac check
-  #error assumes little endian
-#endif
-
-  std::unique_ptr<base::DictionaryValue> header_dict(ReadHeader(&data));
-  if (!header_dict.get())
-    return false;
-
-  std::string contents;
-  if (!header_dict->GetString("ContentType", &contents))
-    return false;
-  if (contents != "CRLSet")
-    return false;
-
-  int version;
-  if (!header_dict->GetInteger("Version", &version) ||
-      version != kCurrentFileVersion) {
-    return false;
-  }
-
-  int sequence;
-  if (!header_dict->GetInteger("Sequence", &sequence))
-    return false;
-
-  double not_after;
-  if (!header_dict->GetDouble("NotAfter", &not_after)) {
-    // NotAfter is optional for now.
-    not_after = 0;
-  }
-  if (not_after < 0)
-    return false;
-
-  scoped_refptr<CRLSet> crl_set(new CRLSet());
-  crl_set->sequence_ = static_cast<uint32_t>(sequence);
-  crl_set->not_after_ = static_cast<uint64_t>(not_after);
-  crl_set->crls_.reserve(64);  // Value observed experimentally.
-
-  for (size_t crl_index = 0; !data.empty(); crl_index++) {
-    // Speculatively push back a pair and pass it to ReadCRL() to avoid
-    // unnecessary copies.
-    crl_set->crls_.push_back(
-        std::make_pair(std::string(), std::vector<std::string>()));
-    std::pair<std::string, std::vector<std::string> >* const back_pair =
-        &crl_set->crls_.back();
-
-    if (!ReadCRL(&data, &back_pair->first, &back_pair->second)) {
-      // Undo the speculative push_back() performed above.
-      crl_set->crls_.pop_back();
-      return false;
-    }
-
-    crl_set->crls_index_by_issuer_[back_pair->first] = crl_index;
-  }
-
-  if (!CopyHashListFromHeader(header_dict.get(), "BlockedSPKIs",
-                              &crl_set->blocked_spkis_) ||
-      !CopyHashToHashesMapFromHeader(header_dict.get(), "LimitedSubjects",
-                                     &crl_set->limited_subjects_,
-                                     &crl_set->limited_subjects_ordered_)) {
-    return false;
-  }
-
-  *out_crl_set = crl_set;
-  return true;
-}
-
-// static
-bool CRLSetStorage::ApplyDelta(const CRLSet* in_crl_set,
-                               const base::StringPiece& delta_bytes,
-                               scoped_refptr<CRLSet>* out_crl_set) {
-  base::StringPiece data(delta_bytes);
-  std::unique_ptr<base::DictionaryValue> header_dict(ReadHeader(&data));
-  if (!header_dict.get())
-    return false;
-
-  std::string contents;
-  if (!header_dict->GetString("ContentType", &contents))
-    return false;
-  if (contents != "CRLSetDelta")
-    return false;
-
-  int version;
-  if (!header_dict->GetInteger("Version", &version) ||
-      version != kCurrentFileVersion) {
-    return false;
-  }
-
-  int sequence, delta_from;
-  if (!header_dict->GetInteger("Sequence", &sequence) ||
-      !header_dict->GetInteger("DeltaFrom", &delta_from) || delta_from < 0 ||
-      static_cast<uint32_t>(delta_from) != in_crl_set->sequence_) {
-    return false;
-  }
-
-  double not_after;
-  if (!header_dict->GetDouble("NotAfter", &not_after)) {
-    // NotAfter is optional for now.
-    not_after = 0;
-  }
-  if (not_after < 0)
-    return false;
-
-  scoped_refptr<CRLSet> crl_set(new CRLSet);
-  crl_set->sequence_ = static_cast<uint32_t>(sequence);
-  crl_set->not_after_ = static_cast<uint64_t>(not_after);
-
-  if (!CopyHashListFromHeader(header_dict.get(), "BlockedSPKIs",
-                              &crl_set->blocked_spkis_) ||
-      !CopyHashToHashesMapFromHeader(header_dict.get(), "LimitedSubjects",
-                                     &crl_set->limited_subjects_,
-                                     &crl_set->limited_subjects_ordered_)) {
-    return false;
-  }
-
-  std::vector<uint8_t> crl_changes;
-
-  if (!ReadChanges(&data, &crl_changes))
-    return false;
-
-  size_t i = 0, j = 0;
-  for (std::vector<uint8_t>::const_iterator k = crl_changes.begin();
-       k != crl_changes.end(); ++k) {
-    if (*k == SYMBOL_SAME) {
-      if (i >= in_crl_set->crls_.size())
-        return false;
-      crl_set->crls_.push_back(in_crl_set->crls_[i]);
-      crl_set->crls_index_by_issuer_[in_crl_set->crls_[i].first] = j;
-      i++;
-      j++;
-    } else if (*k == SYMBOL_INSERT) {
-      std::string parent_spki_hash;
-      std::vector<std::string> serials;
-      if (!ReadCRL(&data, &parent_spki_hash, &serials))
-        return false;
-      crl_set->crls_.push_back(std::make_pair(parent_spki_hash, serials));
-      crl_set->crls_index_by_issuer_[parent_spki_hash] = j;
-      j++;
-    } else if (*k == SYMBOL_DELETE) {
-      if (i >= in_crl_set->crls_.size())
-        return false;
-      i++;
-    } else if (*k == SYMBOL_CHANGED) {
-      if (i >= in_crl_set->crls_.size())
-        return false;
-      std::vector<std::string> serials;
-      if (!ReadDeltaCRL(&data, in_crl_set->crls_[i].second, &serials))
-        return false;
-      crl_set->crls_.push_back(
-          std::make_pair(in_crl_set->crls_[i].first, serials));
-      crl_set->crls_index_by_issuer_[in_crl_set->crls_[i].first] = j;
-      i++;
-      j++;
-    } else {
-      NOTREACHED();
-      return false;
-    }
-  }
-
-  if (!data.empty())
-    return false;
-  if (i != in_crl_set->crls_.size())
-    return false;
-
-  *out_crl_set = crl_set;
-  return true;
-}
-
-// static
-bool CRLSetStorage::GetIsDeltaUpdate(const base::StringPiece& bytes,
-                                     bool* is_delta) {
-  base::StringPiece data(bytes);
-  std::unique_ptr<base::DictionaryValue> header_dict(ReadHeader(&data));
-  if (!header_dict.get())
-    return false;
-
-  std::string contents;
-  if (!header_dict->GetString("ContentType", &contents))
-    return false;
-
-  if (contents == "CRLSet") {
-    *is_delta = false;
-  } else if (contents == "CRLSetDelta") {
-    *is_delta = true;
-  } else {
-    return false;
-  }
-
-  return true;
-}
-
-// static
-std::string CRLSetStorage::Serialize(const CRLSet* crl_set) {
-  std::string header = base::StringPrintf(
-      "{"
-      "\"Version\":0,"
-      "\"ContentType\":\"CRLSet\","
-      "\"Sequence\":%u,"
-      "\"DeltaFrom\":0,"
-      "\"NumParents\":%u,"
-      "\"BlockedSPKIs\":[",
-      static_cast<unsigned>(crl_set->sequence_),
-      static_cast<unsigned>(crl_set->crls_.size()));
-
-  for (std::vector<std::string>::const_iterator i =
-           crl_set->blocked_spkis_.begin();
-       i != crl_set->blocked_spkis_.end(); ++i) {
-    std::string spki_hash_base64;
-    base::Base64Encode(*i, &spki_hash_base64);
-
-    if (i != crl_set->blocked_spkis_.begin())
-      header += ",";
-    header += "\"" + spki_hash_base64 + "\"";
-  }
-
-  header += "]";
-  if (crl_set->not_after_ != 0)
-    header += base::StringPrintf(",\"NotAfter\":%" PRIu64, crl_set->not_after_);
-
-  if (!crl_set->limited_subjects_ordered_.empty()) {
-    header += ",LimitedSubjects:{";
-    bool first = true;
-
-    for (const auto& i : crl_set->limited_subjects_ordered_) {
-      if (!first)
-        header += ",";
-      first = false;
-
-      std::string subject_hash_base64;
-      base::Base64Encode(i, &subject_hash_base64);
-      header += "\"" + subject_hash_base64 + "\":[";
-
-      bool first_hash = true;
-      for (const auto& j : crl_set->limited_subjects_.find(i)->second) {
-        if (!first_hash)
-          header += ",";
-        first_hash = false;
-
-        std::string spki_hash_base64;
-        base::Base64Encode(j, &spki_hash_base64);
-        header += "\"" + spki_hash_base64 + "\"";
-      }
-
-      header += "]";
-    }
-
-    header += "}";
-  }
-
-  header += "}";
-
-  size_t len = 2 /* header len */ + header.size();
-
-  for (CRLSet::CRLList::const_iterator i = crl_set->crls_.begin();
-       i != crl_set->crls_.end(); ++i) {
-    len += i->first.size() + 4 /* num serials */;
-    for (std::vector<std::string>::const_iterator j = i->second.begin();
-         j != i->second.end(); ++j) {
-      len += 1 /* serial length */ + j->size();
-    }
-  }
-
-  std::string ret;
-  uint8_t* out = reinterpret_cast<uint8_t*>(
-      base::WriteInto(&ret, len + 1 /* to include final NUL */));
-  size_t off = 0;
-  CHECK(base::IsValueInRangeForNumericType<uint16_t>(header.size()));
-  out[off++] = static_cast<uint8_t>(header.size());
-  out[off++] = static_cast<uint8_t>(header.size() >> 8);
-  memcpy(out + off, header.data(), header.size());
-  off += header.size();
-
-  for (CRLSet::CRLList::const_iterator i = crl_set->crls_.begin();
-       i != crl_set->crls_.end(); ++i) {
-    memcpy(out + off, i->first.data(), i->first.size());
-    off += i->first.size();
-    const uint32_t num_serials = i->second.size();
-    memcpy(out + off, &num_serials, sizeof(num_serials));
-    off += sizeof(num_serials);
-
-    for (std::vector<std::string>::const_iterator j = i->second.begin();
-         j != i->second.end(); ++j) {
-      CHECK(base::IsValueInRangeForNumericType<uint8_t>(j->size()));
-      out[off++] = static_cast<uint8_t>(j->size());
-      memcpy(out + off, j->data(), j->size());
-      off += j->size();
-    }
-  }
-
-  CHECK_EQ(off, len);
-  return ret;
-}
-
-}  // namespace net
diff --git a/net/cert/crl_set_storage.h b/net/cert/crl_set_storage.h
deleted file mode 100644
index 92659931..0000000
--- a/net/cert/crl_set_storage.h
+++ /dev/null
@@ -1,45 +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 NET_CERT_CRL_SET_STORAGE_H_
-#define NET_CERT_CRL_SET_STORAGE_H_
-
-#include <string>
-#include <utility>
-#include <vector>
-
-#include "base/strings/string_piece.h"
-#include "net/base/net_export.h"
-#include "net/cert/crl_set.h"
-
-namespace net {
-
-// Static helpers to save and load CRLSet.
-class NET_EXPORT CRLSetStorage {
- public:
-  // Parse parses the bytes in |data| and, on success, puts a new CRLSet in
-  // |out_crl_set| and returns true.
-  static bool Parse(base::StringPiece data,
-                    scoped_refptr<CRLSet>* out_crl_set);
-
-  // ApplyDelta returns a new CRLSet in |out_crl_set| that is the result of
-  // updating |in_crl_set| with the delta information in |delta_bytes|.
-  static bool ApplyDelta(const CRLSet* in_crl_set,
-                         const base::StringPiece& delta_bytes,
-                         scoped_refptr<CRLSet>* out_crl_set);
-
-  // GetIsDeltaUpdate extracts the header from |bytes|, sets *is_delta to
-  // whether |bytes| is a delta CRL set or not and returns true. In the event
-  // of a parse error, it returns false.
-  static bool GetIsDeltaUpdate(const base::StringPiece& bytes, bool *is_delta);
-
-  // Serialize returns a string of bytes suitable for passing to Parse. Parsing
-  // and serializing a CRLSet is a lossless operation - the resulting bytes
-  // will be equal.
-  static std::string Serialize(const CRLSet* crl_set);
-};
-
-}  // namespace net
-
-#endif  // NET_CERT_CRL_SET_STORAGE_H_
diff --git a/net/cert/crl_set_unittest.cc b/net/cert/crl_set_unittest.cc
index 88c07203..3878f989 100644
--- a/net/cert/crl_set_unittest.cc
+++ b/net/cert/crl_set_unittest.cc
@@ -7,7 +7,6 @@
 #include "base/files/file_util.h"
 #include "crypto/sha2.h"
 #include "net/cert/asn1_util.h"
-#include "net/cert/crl_set_storage.h"
 #include "net/cert/x509_certificate.h"
 #include "net/cert/x509_util.h"
 #include "net/test/cert_test_util.h"
@@ -43,121 +42,6 @@
   0x00, 0x00, 0x1d, 0x77,
 };
 
-static const uint8_t kNoopDeltaCRL[] = {
-  0xc3, 0x00, 0x7b, 0x22, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x22, 0x3a,
-  0x30, 0x2c, 0x22, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x54, 0x79, 0x70,
-  0x65, 0x22, 0x3a, 0x22, 0x43, 0x52, 0x4c, 0x53, 0x65, 0x74, 0x44, 0x65, 0x6c,
-  0x74, 0x61, 0x22, 0x2c, 0x22, 0x53, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x65,
-  0x22, 0x3a, 0x30, 0x2c, 0x22, 0x4e, 0x65, 0x78, 0x74, 0x55, 0x70, 0x64, 0x61,
-  0x74, 0x65, 0x22, 0x3a, 0x31, 0x33, 0x31, 0x31, 0x31, 0x32, 0x33, 0x37, 0x39,
-  0x33, 0x2c, 0x22, 0x57, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x53, 0x65, 0x63, 0x73,
-  0x22, 0x3a, 0x34, 0x33, 0x32, 0x30, 0x30, 0x2c, 0x22, 0x44, 0x65, 0x6c, 0x74,
-  0x61, 0x46, 0x72, 0x6f, 0x6d, 0x22, 0x3a, 0x30, 0x2c, 0x22, 0x4e, 0x75, 0x6d,
-  0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x73, 0x22, 0x3a, 0x31, 0x2c, 0x22, 0x53,
-  0x69, 0x67, 0x6e, 0x69, 0x6e, 0x67, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b,
-  0x65, 0x79, 0x22, 0x3a, 0x22, 0x22, 0x2c, 0x22, 0x53, 0x69, 0x67, 0x6e, 0x69,
-  0x6e, 0x67, 0x4b, 0x65, 0x79, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72,
-  0x65, 0x22, 0x3a, 0x22, 0x22, 0x2c, 0x22, 0x50, 0x61, 0x79, 0x6c, 0x6f, 0x61,
-  0x64, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x22, 0x3a, 0x22,
-  0x22, 0x7d, 0x01, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x78, 0x9c, 0x62,
-  0x00, 0x04, 0x00, 0x00, 0xff, 0xff, 0x00, 0x01, 0x00, 0x01,
-};
-
-static const uint8_t kAddCRLDelta[] = {
-  0xc3, 0x00, 0x7b, 0x22, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x22, 0x3a,
-  0x30, 0x2c, 0x22, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x54, 0x79, 0x70,
-  0x65, 0x22, 0x3a, 0x22, 0x43, 0x52, 0x4c, 0x53, 0x65, 0x74, 0x44, 0x65, 0x6c,
-  0x74, 0x61, 0x22, 0x2c, 0x22, 0x53, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x65,
-  0x22, 0x3a, 0x30, 0x2c, 0x22, 0x4e, 0x65, 0x78, 0x74, 0x55, 0x70, 0x64, 0x61,
-  0x74, 0x65, 0x22, 0x3a, 0x31, 0x33, 0x31, 0x31, 0x31, 0x32, 0x35, 0x39, 0x34,
-  0x38, 0x2c, 0x22, 0x57, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x53, 0x65, 0x63, 0x73,
-  0x22, 0x3a, 0x34, 0x33, 0x32, 0x30, 0x30, 0x2c, 0x22, 0x44, 0x65, 0x6c, 0x74,
-  0x61, 0x46, 0x72, 0x6f, 0x6d, 0x22, 0x3a, 0x30, 0x2c, 0x22, 0x4e, 0x75, 0x6d,
-  0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x73, 0x22, 0x3a, 0x32, 0x2c, 0x22, 0x53,
-  0x69, 0x67, 0x6e, 0x69, 0x6e, 0x67, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b,
-  0x65, 0x79, 0x22, 0x3a, 0x22, 0x22, 0x2c, 0x22, 0x53, 0x69, 0x67, 0x6e, 0x69,
-  0x6e, 0x67, 0x4b, 0x65, 0x79, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72,
-  0x65, 0x22, 0x3a, 0x22, 0x22, 0x2c, 0x22, 0x50, 0x61, 0x79, 0x6c, 0x6f, 0x61,
-  0x64, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x22, 0x3a, 0x22,
-  0x22, 0x7d, 0x02, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x78, 0x9c, 0x62,
-  0x60, 0x04, 0x04, 0x00, 0x00, 0xff, 0xff, 0x00, 0x03, 0x00, 0x02, 0xe4, 0x2f,
-  0x24, 0xbd, 0x4d, 0x37, 0xf4, 0xaa, 0x2e, 0x56, 0xb9, 0x79, 0xd8, 0x3d, 0x1e,
-  0x65, 0x21, 0x9f, 0xe0, 0xe9, 0xe3, 0xa3, 0x82, 0xa1, 0xb3, 0xcb, 0x66, 0xc9,
-  0x39, 0x55, 0xde, 0x75, 0x0c, 0x00, 0x00, 0x00, 0x01, 0x02, 0x01, 0x03, 0x01,
-  0x04, 0x01, 0x05, 0x01, 0x06, 0x01, 0x07, 0x01, 0x08, 0x01, 0x09, 0x01, 0x2f,
-  0x01, 0x30, 0x01, 0x31, 0x01, 0x32,
-};
-
-static const uint8_t kRemoveCRLDelta[] = {
-  0xc3, 0x00, 0x7b, 0x22, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x22, 0x3a,
-  0x30, 0x2c, 0x22, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x54, 0x79, 0x70,
-  0x65, 0x22, 0x3a, 0x22, 0x43, 0x52, 0x4c, 0x53, 0x65, 0x74, 0x44, 0x65, 0x6c,
-  0x74, 0x61, 0x22, 0x2c, 0x22, 0x53, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x65,
-  0x22, 0x3a, 0x30, 0x2c, 0x22, 0x4e, 0x65, 0x78, 0x74, 0x55, 0x70, 0x64, 0x61,
-  0x74, 0x65, 0x22, 0x3a, 0x31, 0x33, 0x31, 0x31, 0x31, 0x32, 0x36, 0x31, 0x31,
-  0x36, 0x2c, 0x22, 0x57, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x53, 0x65, 0x63, 0x73,
-  0x22, 0x3a, 0x34, 0x33, 0x32, 0x30, 0x30, 0x2c, 0x22, 0x44, 0x65, 0x6c, 0x74,
-  0x61, 0x46, 0x72, 0x6f, 0x6d, 0x22, 0x3a, 0x30, 0x2c, 0x22, 0x4e, 0x75, 0x6d,
-  0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x73, 0x22, 0x3a, 0x31, 0x2c, 0x22, 0x53,
-  0x69, 0x67, 0x6e, 0x69, 0x6e, 0x67, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b,
-  0x65, 0x79, 0x22, 0x3a, 0x22, 0x22, 0x2c, 0x22, 0x53, 0x69, 0x67, 0x6e, 0x69,
-  0x6e, 0x67, 0x4b, 0x65, 0x79, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72,
-  0x65, 0x22, 0x3a, 0x22, 0x22, 0x2c, 0x22, 0x50, 0x61, 0x79, 0x6c, 0x6f, 0x61,
-  0x64, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x22, 0x3a, 0x22,
-  0x22, 0x7d, 0x02, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x78, 0x9c, 0x62,
-  0x60, 0x02, 0x04, 0x00, 0x00, 0xff, 0xff, 0x00, 0x04, 0x00, 0x03,
-};
-
-static const uint8_t kUpdateSerialsDelta[] = {
-  0xc3, 0x00, 0x7b, 0x22, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x22, 0x3a,
-  0x30, 0x2c, 0x22, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x54, 0x79, 0x70,
-  0x65, 0x22, 0x3a, 0x22, 0x43, 0x52, 0x4c, 0x53, 0x65, 0x74, 0x44, 0x65, 0x6c,
-  0x74, 0x61, 0x22, 0x2c, 0x22, 0x53, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x65,
-  0x22, 0x3a, 0x30, 0x2c, 0x22, 0x4e, 0x65, 0x78, 0x74, 0x55, 0x70, 0x64, 0x61,
-  0x74, 0x65, 0x22, 0x3a, 0x31, 0x33, 0x31, 0x31, 0x31, 0x32, 0x36, 0x34, 0x36,
-  0x31, 0x2c, 0x22, 0x57, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x53, 0x65, 0x63, 0x73,
-  0x22, 0x3a, 0x34, 0x33, 0x32, 0x30, 0x30, 0x2c, 0x22, 0x44, 0x65, 0x6c, 0x74,
-  0x61, 0x46, 0x72, 0x6f, 0x6d, 0x22, 0x3a, 0x30, 0x2c, 0x22, 0x4e, 0x75, 0x6d,
-  0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x73, 0x22, 0x3a, 0x31, 0x2c, 0x22, 0x53,
-  0x69, 0x67, 0x6e, 0x69, 0x6e, 0x67, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b,
-  0x65, 0x79, 0x22, 0x3a, 0x22, 0x22, 0x2c, 0x22, 0x53, 0x69, 0x67, 0x6e, 0x69,
-  0x6e, 0x67, 0x4b, 0x65, 0x79, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72,
-  0x65, 0x22, 0x3a, 0x22, 0x22, 0x2c, 0x22, 0x50, 0x61, 0x79, 0x6c, 0x6f, 0x61,
-  0x64, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x22, 0x3a, 0x22,
-  0x22, 0x7d, 0x01, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x78, 0x9c, 0x62,
-  0x06, 0x04, 0x00, 0x00, 0xff, 0xff, 0x00, 0x04, 0x00, 0x04, 0x2d, 0x00, 0x00,
-  0x00, 0x15, 0x00, 0x00, 0x00, 0x78, 0x9c, 0x62, 0x80, 0x00, 0x46, 0x2c, 0x00,
-  0x45, 0x14, 0xac, 0x08, 0x10, 0x00, 0x00, 0xff, 0xff, 0x02, 0xe1, 0x00, 0x21,
-  0x0a, 0x10, 0x0d, 0x7f, 0x30, 0x00, 0x03, 0x00, 0x00, 0x23, 0xb0, 0x0a, 0x10,
-  0x0d, 0x7f, 0x30, 0x00, 0x03, 0x00, 0x00, 0x23, 0xb0, 0x0a, 0x10, 0x0d, 0x7f,
-  0x30, 0x00, 0x03, 0x00, 0x00, 0x23, 0xb0, 0x0a, 0x10, 0x0d, 0x7f, 0x30, 0x00,
-  0x03, 0x00, 0x00, 0x23, 0xb0, 0x0a, 0x10, 0x0d, 0x7f, 0x30, 0x00, 0x03, 0x00,
-  0x00, 0x23, 0xb0, 0x0a, 0x10, 0x0d, 0x7f, 0x30, 0x00, 0x03, 0x00, 0x00, 0x23,
-  0xb0, 0x0a, 0x10, 0x0d, 0x7f, 0x30, 0x00, 0x03, 0x00, 0x00, 0x23, 0xb0, 0x0a,
-  0x10, 0x0d, 0x7f, 0x30, 0x00, 0x03, 0x00, 0x00, 0x23, 0xb0, 0x0a, 0x10, 0x0d,
-  0x7f, 0x30, 0x00, 0x03, 0x00, 0x00, 0x23, 0xb0, 0x0a, 0x10, 0x0d, 0x7f, 0x30,
-  0x00, 0x03, 0x00, 0x00, 0x23, 0xb0, 0x0a, 0x10, 0x0d, 0x7f, 0x30, 0x00, 0x03,
-  0x00, 0x00, 0x23, 0xb0, 0x0a, 0x10, 0x0d, 0x7f, 0x30, 0x00, 0x03, 0x00, 0x00,
-  0x23, 0xb0, 0x0a, 0x10, 0x0d, 0x7f, 0x30, 0x00, 0x03, 0x00, 0x00, 0x23, 0xb0,
-  0x0a, 0x10, 0x0d, 0x7f, 0x30, 0x00, 0x03, 0x00, 0x00, 0x23, 0xb0, 0x0a, 0x10,
-  0x0d, 0x7f, 0x30, 0x00, 0x03, 0x00, 0x00, 0x23, 0xb0, 0x0a, 0x10, 0x0d, 0x7f,
-  0x30, 0x00, 0x03, 0x00, 0x00, 0x23, 0xb0, 0x0a, 0x10, 0x0d, 0x7f, 0x30, 0x00,
-  0x03, 0x00, 0x00, 0x23, 0xb0, 0x0a, 0x10, 0x0d, 0x7f, 0x30, 0x00, 0x03, 0x00,
-  0x00, 0x23, 0xb0, 0x0a, 0x10, 0x0d, 0x7f, 0x30, 0x00, 0x03, 0x00, 0x00, 0x23,
-  0xb0, 0x0a, 0x10, 0x0d, 0x7f, 0x30, 0x00, 0x03, 0x00, 0x00, 0x23, 0xb0, 0x0a,
-  0x10, 0x0d, 0x7f, 0x30, 0x00, 0x03, 0x00, 0x00, 0x23, 0xb0, 0x0a, 0x10, 0x0d,
-  0x7f, 0x30, 0x00, 0x03, 0x00, 0x00, 0x23, 0xb0, 0x0a, 0x10, 0x0d, 0x7f, 0x30,
-  0x00, 0x03, 0x00, 0x00, 0x23, 0xb0, 0x0a, 0x10, 0x0d, 0x7f, 0x30, 0x00, 0x03,
-  0x00, 0x00, 0x23, 0xb0, 0x0a, 0x10, 0x0d, 0x7f, 0x30, 0x00, 0x03, 0x00, 0x00,
-  0x23, 0xb0, 0x0a, 0x10, 0x0d, 0x7f, 0x30, 0x00, 0x03, 0x00, 0x00, 0x23, 0xb0,
-  0x0a, 0x10, 0x0d, 0x7f, 0x30, 0x00, 0x03, 0x00, 0x00, 0x23, 0xb0, 0x0a, 0x10,
-  0x0d, 0x7f, 0x30, 0x00, 0x03, 0x00, 0x00, 0x23, 0xb0, 0x0a, 0x10, 0x0d, 0x7f,
-  0x30, 0x00, 0x03, 0x00, 0x00, 0x23, 0xb0, 0x0a, 0x10, 0x0d, 0x7f, 0x30, 0x00,
-  0x03, 0x00, 0x00, 0x23, 0xb0, 0x0a, 0x10, 0x0d, 0x7f, 0x30, 0x00, 0x03, 0x00,
-  0x00, 0x23, 0xb0, 0x0a, 0x10, 0x0d, 0x7f, 0x30, 0x00, 0x03, 0x00, 0x00, 0x23,
-  0xb0,
-};
-
 static const uint8_t kBlockedSPKICRLSet[] = {
   0x8e, 0x00, 0x7b, 0x22, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x22, 0x3a,
   0x30, 0x2c, 0x22, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x54, 0x79, 0x70,
@@ -197,7 +81,7 @@
   base::StringPiece s(reinterpret_cast<const char*>(kGIACRLSet),
                       sizeof(kGIACRLSet));
   scoped_refptr<CRLSet> set;
-  EXPECT_TRUE(CRLSetStorage::Parse(s, &set));
+  EXPECT_TRUE(CRLSet::Parse(s, &set));
   ASSERT_TRUE(set.get() != NULL);
 
   const CRLSet::CRLList& crls = set->crls();
@@ -224,94 +108,11 @@
   EXPECT_FALSE(set->IsExpired());
 }
 
-TEST(CRLSetTest, NoOpDeltaUpdate) {
-  base::StringPiece s(reinterpret_cast<const char*>(kGIACRLSet),
-                      sizeof(kGIACRLSet));
-  scoped_refptr<CRLSet> set;
-  EXPECT_TRUE(CRLSetStorage::Parse(s, &set));
-  ASSERT_TRUE(set.get() != NULL);
-
-  scoped_refptr<CRLSet> delta_set;
-  base::StringPiece delta(reinterpret_cast<const char*>(kNoopDeltaCRL),
-                          sizeof(kNoopDeltaCRL));
-  EXPECT_TRUE(CRLSetStorage::ApplyDelta(set.get(), delta, &delta_set));
-  ASSERT_TRUE(delta_set.get() != NULL);
-
-  std::string out = CRLSetStorage::Serialize(delta_set.get());
-  EXPECT_EQ(s.as_string(), out);
-}
-
-TEST(CRLSetTest, AddCRLDelta) {
-  base::StringPiece s(reinterpret_cast<const char*>(kGIACRLSet),
-                      sizeof(kGIACRLSet));
-  scoped_refptr<CRLSet> set;
-  EXPECT_TRUE(CRLSetStorage::Parse(s, &set));
-  ASSERT_TRUE(set.get() != NULL);
-
-  scoped_refptr<CRLSet> delta_set;
-  base::StringPiece delta(reinterpret_cast<const char*>(kAddCRLDelta),
-                          sizeof(kAddCRLDelta));
-  EXPECT_TRUE(CRLSetStorage::ApplyDelta(set.get(), delta, &delta_set));
-  ASSERT_TRUE(delta_set.get() != NULL);
-
-  const CRLSet::CRLList& crls = delta_set->crls();
-  ASSERT_EQ(2u, crls.size());
-  const std::vector<std::string>& serials = crls[1].second;
-  ASSERT_EQ(12u, serials.size());
-  EXPECT_EQ(std::string("\x02", 1), serials[0]);
-  EXPECT_EQ(std::string("\x03", 1), serials[1]);
-  EXPECT_EQ(std::string("\x04", 1), serials[2]);
-}
-
-TEST(CRLSetTest, AddRemoveCRLDelta) {
-  base::StringPiece s(reinterpret_cast<const char*>(kGIACRLSet),
-                      sizeof(kGIACRLSet));
-  scoped_refptr<CRLSet> set;
-  EXPECT_TRUE(CRLSetStorage::Parse(s, &set));
-  ASSERT_TRUE(set.get() != NULL);
-
-  scoped_refptr<CRLSet> delta_set;
-  base::StringPiece delta(reinterpret_cast<const char*>(kAddCRLDelta),
-                          sizeof(kAddCRLDelta));
-  EXPECT_TRUE(CRLSetStorage::ApplyDelta(set.get(), delta, &delta_set));
-  ASSERT_TRUE(delta_set.get() != NULL);
-
-  scoped_refptr<CRLSet> delta2_set;
-  base::StringPiece delta2(reinterpret_cast<const char*>(kRemoveCRLDelta),
-                           sizeof(kRemoveCRLDelta));
-  EXPECT_TRUE(CRLSetStorage::ApplyDelta(delta_set.get(), delta2, &delta2_set));
-  ASSERT_TRUE(delta2_set.get() != NULL);
-
-  const CRLSet::CRLList& crls = delta2_set->crls();
-  ASSERT_EQ(1u, crls.size());
-  const std::vector<std::string>& serials = crls[0].second;
-  ASSERT_EQ(13u, serials.size());
-}
-
-TEST(CRLSetTest, UpdateSerialsDelta) {
-  base::StringPiece s(reinterpret_cast<const char*>(kGIACRLSet),
-                      sizeof(kGIACRLSet));
-  scoped_refptr<CRLSet> set;
-  EXPECT_TRUE(CRLSetStorage::Parse(s, &set));
-  ASSERT_TRUE(set.get() != NULL);
-
-  scoped_refptr<CRLSet> delta_set;
-  base::StringPiece delta(reinterpret_cast<const char*>(kUpdateSerialsDelta),
-                          sizeof(kUpdateSerialsDelta));
-  EXPECT_TRUE(CRLSetStorage::ApplyDelta(set.get(), delta, &delta_set));
-  ASSERT_TRUE(delta_set.get() != NULL);
-
-  const CRLSet::CRLList& crls = delta_set->crls();
-  ASSERT_EQ(1u, crls.size());
-  const std::vector<std::string>& serials = crls[0].second;
-  EXPECT_EQ(45u, serials.size());
-}
-
 TEST(CRLSetTest, BlockedSPKIs) {
   base::StringPiece s(reinterpret_cast<const char*>(kBlockedSPKICRLSet),
                       sizeof(kBlockedSPKICRLSet));
   scoped_refptr<CRLSet> set;
-  EXPECT_TRUE(CRLSetStorage::Parse(s, &set));
+  EXPECT_TRUE(CRLSet::Parse(s, &set));
   ASSERT_TRUE(set.get() != NULL);
 
   const uint8_t spki_hash[] = {
@@ -331,7 +132,7 @@
       GetTestCertsDirectory().AppendASCII("crlset_by_root_subject.raw"),
       &crl_set_bytes));
   scoped_refptr<CRLSet> set;
-  EXPECT_TRUE(CRLSetStorage::Parse(crl_set_bytes, &set));
+  EXPECT_TRUE(CRLSet::Parse(crl_set_bytes, &set));
   ASSERT_TRUE(set.get() != NULL);
 
   scoped_refptr<X509Certificate> root = CreateCertificateChainFromFile(
@@ -373,7 +174,7 @@
   base::StringPiece s(reinterpret_cast<const char*>(kExpiredCRLSet),
                       sizeof(kExpiredCRLSet));
   scoped_refptr<CRLSet> set;
-  EXPECT_TRUE(CRLSetStorage::Parse(s, &set));
+  EXPECT_TRUE(CRLSet::Parse(s, &set));
   ASSERT_TRUE(set.get() != NULL);
 
   EXPECT_TRUE(set->IsExpired());
diff --git a/net/tools/cert_verify_tool/cert_verify_tool.cc b/net/tools/cert_verify_tool/cert_verify_tool.cc
index c5c35b6..b8c9f8df 100644
--- a/net/tools/cert_verify_tool/cert_verify_tool.cc
+++ b/net/tools/cert_verify_tool/cert_verify_tool.cc
@@ -18,7 +18,6 @@
 #include "net/cert/cert_verify_proc.h"
 #include "net/cert/cert_verify_proc_builtin.h"
 #include "net/cert/crl_set.h"
-#include "net/cert/crl_set_storage.h"
 #include "net/cert_net/cert_net_fetcher_impl.h"
 #include "net/tools/cert_verify_tool/cert_verify_tool_util.h"
 #include "net/tools/cert_verify_tool/verify_using_cert_verify_proc.h"
@@ -251,7 +250,7 @@
     std::string crl_set_bytes;
     if (!ReadFromFile(crlset_path, &crl_set_bytes))
       return 1;
-    if (!net::CRLSetStorage::Parse(crl_set_bytes, &crl_set)) {
+    if (!net::CRLSet::Parse(crl_set_bytes, &crl_set)) {
       std::cerr << "Error parsing CRLSet\n";
       return 1;
     }
diff --git a/net/tools/crl_set_dump/crl_set_dump.cc b/net/tools/crl_set_dump/crl_set_dump.cc
deleted file mode 100644
index 72ed59c..0000000
--- a/net/tools/crl_set_dump/crl_set_dump.cc
+++ /dev/null
@@ -1,84 +0,0 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-// This utility can dump the contents of CRL set, optionally augmented with a
-// delta CRL set.
-
-#include <errno.h>
-#include <stdio.h>
-#include <stdlib.h>
-
-#include <string>
-
-#include "base/at_exit.h"
-#include "base/files/file_util.h"
-#include "base/memory/ref_counted.h"
-#include "base/strings/string_number_conversions.h"
-#include "net/cert/crl_set.h"
-#include "net/cert/crl_set_storage.h"
-
-static int Usage(const char* argv0) {
-  fprintf(stderr, "Usage: %s <crl-set file> [<delta file>]"
-                  " [<resulting output file>]\n", argv0);
-  return 1;
-}
-
-int main(int argc, char** argv) {
-  base::AtExitManager at_exit_manager;
-
-  base::FilePath crl_set_filename, delta_filename, output_filename;
-
-  if (argc < 2 || argc > 4)
-    return Usage(argv[0]);
-
-  crl_set_filename = base::FilePath::FromUTF8Unsafe(argv[1]);
-  if (argc >= 3)
-    delta_filename = base::FilePath::FromUTF8Unsafe(argv[2]);
-  if (argc >= 4)
-    output_filename = base::FilePath::FromUTF8Unsafe(argv[3]);
-
-  std::string crl_set_bytes, delta_bytes;
-  if (!base::ReadFileToString(crl_set_filename, &crl_set_bytes))
-    return 1;
-  if (!delta_filename.empty() &&
-      !base::ReadFileToString(delta_filename, &delta_bytes)) {
-    return 1;
-  }
-
-  scoped_refptr<net::CRLSet> crl_set, final_crl_set;
-  if (!net::CRLSetStorage::Parse(crl_set_bytes, &crl_set)) {
-    fprintf(stderr, "Failed to parse CRLSet\n");
-    return 1;
-  }
-
-  if (!delta_bytes.empty()) {
-    if (!net::CRLSetStorage::ApplyDelta(
-            crl_set.get(), delta_bytes, &final_crl_set)) {
-      fprintf(stderr, "Failed to apply delta to CRLSet\n");
-      return 1;
-    }
-  } else {
-    final_crl_set = crl_set;
-  }
-
-  if (!output_filename.empty()) {
-    const std::string out = net::CRLSetStorage::Serialize(final_crl_set.get());
-    if (base::WriteFile(output_filename, out.data(), out.size()) == -1) {
-      fprintf(stderr, "Failed to write resulting CRL set\n");
-      return 1;
-    }
-  }
-
-  const net::CRLSet::CRLList& crls = final_crl_set->crls();
-  for (net::CRLSet::CRLList::const_iterator i = crls.begin(); i != crls.end();
-       i++) {
-    printf("%s\n", base::HexEncode(i->first.data(), i->first.size()).c_str());
-    for (std::vector<std::string>::const_iterator j = i->second.begin();
-         j != i->second.end(); j++) {
-      printf("  %s\n", base::HexEncode(j->data(), j->size()).c_str());
-    }
-  }
-
-  return 0;
-}
diff --git a/services/network/BUILD.gn b/services/network/BUILD.gn
index 86744357..edff41e 100644
--- a/services/network/BUILD.gn
+++ b/services/network/BUILD.gn
@@ -10,8 +10,6 @@
 
 component("network_service") {
   sources = [
-    "cache_url_loader.cc",
-    "cache_url_loader.h",
     "cookie_manager.cc",
     "cookie_manager.h",
     "data_pipe_element_reader.cc",
diff --git a/services/network/cache_url_loader.cc b/services/network/cache_url_loader.cc
deleted file mode 100644
index 3cf9f135..0000000
--- a/services/network/cache_url_loader.cc
+++ /dev/null
@@ -1,83 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "services/network/cache_url_loader.h"
-
-#include "base/bind.h"
-#include "base/macros.h"
-#include "base/strings/string_util.h"
-#include "base/threading/thread_task_runner_handle.h"
-#include "mojo/common/data_pipe_utils.h"
-#include "net/url_request/view_cache_helper.h"
-
-namespace network {
-
-namespace {
-
-class CacheURLLoader {
- public:
-  CacheURLLoader(const GURL& url,
-                 net::URLRequestContext* request_context,
-                 mojom::URLLoaderClientPtr client)
-      : client_(std::move(client)) {
-    scoped_refptr<net::HttpResponseHeaders> headers(
-        new net::HttpResponseHeaders("HTTP/1.1 200 OK"));
-    ResourceResponseHead resource_response;
-    resource_response.headers = headers;
-    resource_response.mime_type = "text/html";
-    client_->OnReceiveResponse(resource_response, base::nullopt, nullptr);
-
-    auto url_prefix = url.GetWithEmptyPath().spec();
-    std::string cache_key = url.spec().substr(url_prefix.size());
-
-    int rv;
-    if (cache_key.empty()) {
-      rv = cache_helper_.GetContentsHTML(
-          request_context, url_prefix, &data_,
-          base::Bind(&CacheURLLoader::DataAvailable, base::Unretained(this)));
-    } else {
-      rv = cache_helper_.GetEntryInfoHTML(
-          cache_key, request_context, &data_,
-          base::Bind(&CacheURLLoader::DataAvailable, base::Unretained(this)));
-    }
-
-    if (rv != net::ERR_IO_PENDING)
-      DataAvailable(rv);
-  }
-
-  ~CacheURLLoader() {}
-
- private:
-  void DataAvailable(int result) {
-    DCHECK_EQ(net::OK, result);
-    mojo::DataPipe data_pipe(data_.size());
-
-    CHECK(
-        mojo::common::BlockingCopyFromString(data_, data_pipe.producer_handle));
-
-    client_->OnStartLoadingResponseBody(std::move(data_pipe.consumer_handle));
-    URLLoaderCompletionStatus status(net::OK);
-    status.encoded_data_length = data_.size();
-    status.encoded_body_length = data_.size();
-    client_->OnComplete(status);
-
-    // So we don't delete |this| in the constructor.
-    base::ThreadTaskRunnerHandle::Get()->DeleteSoon(FROM_HERE, this);
-  }
-
-  std::string data_;
-  mojom::URLLoaderClientPtr client_;
-  net::ViewCacheHelper cache_helper_;
-
-  DISALLOW_COPY_AND_ASSIGN(CacheURLLoader);
-};
-}  // namespace
-
-void StartCacheURLLoader(const GURL& url,
-                         net::URLRequestContext* request_context,
-                         mojom::URLLoaderClientPtr client) {
-  new CacheURLLoader(url, request_context, std::move(client));
-}
-
-}  // namespace network
diff --git a/services/network/cache_url_loader.h b/services/network/cache_url_loader.h
deleted file mode 100644
index 1080387..0000000
--- a/services/network/cache_url_loader.h
+++ /dev/null
@@ -1,23 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef SERVICES_NETWORK_CACHE_URL_LOADER_H_
-#define SERVICES_NETWORK_CACHE_URL_LOADER_H_
-
-#include "services/network/public/mojom/url_loader.mojom.h"
-
-namespace net {
-class URLRequestContext;
-}
-
-namespace network {
-
-// Creates a URLLoader that responds to developer requests to view the cache.
-void StartCacheURLLoader(const GURL& url,
-                         net::URLRequestContext* request_context,
-                         mojom::URLLoaderClientPtr client);
-
-}  // namespace network
-
-#endif  // SERVICES_NETWORK_CACHE_URL_LOADER_H_
diff --git a/services/network/network_context.cc b/services/network/network_context.cc
index ee15fcb..b681ac5 100644
--- a/services/network/network_context.cc
+++ b/services/network/network_context.cc
@@ -38,7 +38,6 @@
 #include "net/ssl/default_channel_id_store.h"
 #include "net/url_request/url_request_context.h"
 #include "net/url_request/url_request_context_builder.h"
-#include "services/network/cache_url_loader.h"
 #include "services/network/http_server_properties_pref_delegate.h"
 #include "services/network/ignore_errors_cert_verifier.h"
 #include "services/network/network_service.h"
@@ -188,11 +187,6 @@
                          std::move(resource_scheduler_client));
 }
 
-void NetworkContext::HandleViewCacheRequest(const GURL& url,
-                                            mojom::URLLoaderClientPtr client) {
-  StartCacheURLLoader(url, GetURLRequestContext(), std::move(client));
-}
-
 void NetworkContext::GetCookieManager(mojom::CookieManagerRequest request) {
   cookie_manager_->AddRequest(std::move(request));
 }
diff --git a/services/network/network_context.h b/services/network/network_context.h
index 6035ad2..b39c97b 100644
--- a/services/network/network_context.h
+++ b/services/network/network_context.h
@@ -95,8 +95,6 @@
   // mojom::NetworkContext implementation:
   void CreateURLLoaderFactory(mojom::URLLoaderFactoryRequest request,
                               uint32_t process_id) override;
-  void HandleViewCacheRequest(const GURL& url,
-                              mojom::URLLoaderClientPtr client) override;
   void GetCookieManager(mojom::CookieManagerRequest request) override;
   void GetRestrictedCookieManager(mojom::RestrictedCookieManagerRequest request,
                                   int32_t render_process_id,
diff --git a/services/network/public/mojom/network_service.mojom b/services/network/public/mojom/network_service.mojom
index a1c897b6e..de72e9a 100644
--- a/services/network/public/mojom/network_service.mojom
+++ b/services/network/public/mojom/network_service.mojom
@@ -123,11 +123,6 @@
   CreateURLLoaderFactory(URLLoaderFactory& url_loader_factory,
                          uint32 process_id);
 
-  // Handles a request to display cache data to the user. |url| is parsed to
-  // display different parts of the cache.
-  HandleViewCacheRequest(url.mojom.Url url,
-                         URLLoaderClient client);
-
   // Gets the CookieManager associated with this network context.
   GetCookieManager(CookieManager& cookie_manager);
 
diff --git a/services/resource_coordinator/manifest.json b/services/resource_coordinator/manifest.json
index 0dd7654..c9746fe 100644
--- a/services/resource_coordinator/manifest.json
+++ b/services/resource_coordinator/manifest.json
@@ -12,7 +12,7 @@
           "resource_coordinator::mojom::CoordinationUnitIntrospector"
         ],
         "coordination_unit": [ "resource_coordinator::mojom::CoordinationUnitProvider" ],
-        "heap_profiling": [ "memory_instrumentation::mojom::HeapProfilerHelper" ],
+        "heap_profiler_helper": [ "memory_instrumentation::mojom::HeapProfilerHelper" ],
         "page_signal": [ "resource_coordinator::mojom::PageSignalGenerator" ],
         "tracing": [ "tracing::mojom::Coordinator" ],
         "tests": [ "*" ]
diff --git a/services/resource_coordinator/memory_instrumentation/coordinator_impl.cc b/services/resource_coordinator/memory_instrumentation/coordinator_impl.cc
index 575ecd8..429ce99 100644
--- a/services/resource_coordinator/memory_instrumentation/coordinator_impl.cc
+++ b/services/resource_coordinator/memory_instrumentation/coordinator_impl.cc
@@ -42,6 +42,21 @@
 
 memory_instrumentation::CoordinatorImpl* g_coordinator_impl;
 
+constexpr base::TimeDelta kHeapDumpTimeout = base::TimeDelta::FromSeconds(60);
+
+// A wrapper classes that allows a string to be exported as JSON in a trace
+// event.
+class StringWrapper : public base::trace_event::ConvertableToTraceFormat {
+ public:
+  explicit StringWrapper(std::string json) : json_(std::move(json)) {}
+
+  void AppendAsTraceFormat(std::string* out) const override {
+    out->append(json_);
+  }
+
+  std::string json_;
+};
+
 }  // namespace
 
 
@@ -150,6 +165,12 @@
   RequestGlobalMemoryDumpInternal(args, base::BindRepeating(adapter, callback));
 }
 
+void CoordinatorImpl::RegisterHeapProfiler(
+    mojom::HeapProfilerPtr heap_profiler) {
+  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+  heap_profiler_ = std::move(heap_profiler);
+}
+
 void CoordinatorImpl::GetVmRegionsForHeapProfiler(
     const std::vector<base::ProcessId>& pids,
     const GetVmRegionsForHeapProfilerCallback& callback) {
@@ -298,6 +319,24 @@
   FinalizeGlobalMemoryDumpIfAllManagersReplied();
 }
 
+void CoordinatorImpl::OnHeapDumpTimeOut(uint64_t dump_guid) {
+  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+  QueuedRequest* request = GetCurrentRequest();
+
+  // TODO(lalitm): add metrics for how often this happens.
+
+  // Only consider the current request timed out if we fired off this
+  // delayed callback in association with this request.
+  if (!request || request->dump_guid != dump_guid)
+    return;
+
+  // Fail all remaining dumps being waited upon and clear the vector.
+  if (request->heap_dump_in_progress) {
+    request->heap_dump_in_progress = false;
+    FinalizeGlobalMemoryDumpIfAllManagersReplied();
+  }
+}
+
 void CoordinatorImpl::PerformNextQueuedGlobalMemoryDump() {
   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
   QueuedRequest* request = GetCurrentRequest();
@@ -327,6 +366,29 @@
                      base::Unretained(this), request->dump_guid),
       client_process_timeout_);
 
+  if (request->args.add_to_trace && heap_profiler_) {
+    request->heap_dump_in_progress = true;
+
+    // |IsArgumentFilterEnabled| is the round-about way of asking to anonymize
+    // the trace. The only way that PII gets leaked is if the full path is
+    // emitted for mapped files. Passing |strip_path_from_mapped_files|
+    // is all that is necessary to anonymize the trace.
+    bool strip_path_from_mapped_files =
+        base::trace_event::TraceLog::GetInstance()
+            ->GetCurrentTraceConfig()
+            .IsArgumentFilterEnabled();
+    heap_profiler_->DumpProcessesForTracing(
+        strip_path_from_mapped_files,
+            base::BindRepeating(&CoordinatorImpl::OnDumpProcessesForTracing,
+                           base::Unretained(this), request->dump_guid));
+
+    base::SequencedTaskRunnerHandle::Get()->PostDelayedTask(
+        FROM_HERE,
+        base::BindOnce(&CoordinatorImpl::OnHeapDumpTimeOut,
+                       base::Unretained(this), request->dump_guid),
+        kHeapDumpTimeout);
+  }
+
   // Run the callback in case there are no client processes registered.
   FinalizeGlobalMemoryDumpIfAllManagersReplied();
 }
@@ -427,6 +489,54 @@
   in_progress_vm_region_requests_.erase(it);
 }
 
+void CoordinatorImpl::OnDumpProcessesForTracing(
+    uint64_t dump_guid,
+    std::vector<mojom::SharedBufferWithSizePtr> buffers) {
+  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+  QueuedRequest* request = GetCurrentRequest();
+  if (!request || request->dump_guid != dump_guid) {
+    return;
+  }
+
+  request->heap_dump_in_progress = false;
+
+  for (auto& buffer_ptr : buffers) {
+    mojo::ScopedSharedBufferHandle& buffer = buffer_ptr->buffer;
+    uint32_t size = buffer_ptr->size;
+
+    if (!buffer->is_valid())
+      continue;
+
+    mojo::ScopedSharedBufferMapping mapping = buffer->Map(size);
+    if (!mapping) {
+      DLOG(ERROR) << "Failed to map buffer";
+      continue;
+    }
+
+    const char* char_buffer = static_cast<const char*>(mapping.get());
+    std::string json(char_buffer, char_buffer + size);
+
+    const int kTraceEventNumArgs = 1;
+    const char* const kTraceEventArgNames[] = {"dumps"};
+    const unsigned char kTraceEventArgTypes[] = {TRACE_VALUE_TYPE_CONVERTABLE};
+    std::unique_ptr<base::trace_event::ConvertableToTraceFormat> wrapper(
+        new StringWrapper(std::move(json)));
+
+    // Using the same id merges all of the heap dumps into a single detailed
+    // dump node in the UI.
+    TRACE_EVENT_API_ADD_TRACE_EVENT_WITH_PROCESS_ID(
+        TRACE_EVENT_PHASE_MEMORY_DUMP,
+        base::trace_event::TraceLog::GetCategoryGroupEnabled(
+            base::trace_event::MemoryDumpManager::kTraceCategory),
+        "periodic_interval", trace_event_internal::kGlobalScope, dump_guid,
+        buffer_ptr->pid, kTraceEventNumArgs, kTraceEventArgNames,
+        kTraceEventArgTypes, nullptr /* arg_values */, &wrapper,
+        TRACE_EVENT_FLAG_HAS_ID);
+  }
+
+  FinalizeGlobalMemoryDumpIfAllManagersReplied();
+}
+
 void CoordinatorImpl::RemovePendingResponse(
     mojom::ClientProcess* client,
     QueuedRequest::PendingResponse::Type type) {
@@ -449,8 +559,10 @@
   DCHECK(!queued_memory_dump_requests_.empty());
 
   QueuedRequest* request = &queued_memory_dump_requests_.front();
-  if (!request->dump_in_progress || request->pending_responses.size() > 0)
+  if (!request->dump_in_progress || request->pending_responses.size() > 0 ||
+      request->heap_dump_in_progress) {
     return;
+  }
 
   QueuedRequestDispatcher::Finalize(request, tracing_observer_.get());
 
diff --git a/services/resource_coordinator/memory_instrumentation/coordinator_impl.h b/services/resource_coordinator/memory_instrumentation/coordinator_impl.h
index aa0472d..ecebb20 100644
--- a/services/resource_coordinator/memory_instrumentation/coordinator_impl.h
+++ b/services/resource_coordinator/memory_instrumentation/coordinator_impl.h
@@ -70,6 +70,7 @@
       base::trace_event::MemoryDumpType,
       base::trace_event::MemoryDumpLevelOfDetail,
       const RequestGlobalMemoryDumpAndAppendToTraceCallback&) override;
+  void RegisterHeapProfiler(mojom::HeapProfilerPtr heap_profiler) override;
 
   // mojom::HeapProfilerHelper implementation.
   void GetVmRegionsForHeapProfiler(
@@ -129,10 +130,16 @@
 
   void FinalizeVmRegionDumpIfAllManagersReplied(uint64_t dump_guid);
 
+  // Callback of DumpProcessesForTracing.
+  void OnDumpProcessesForTracing(
+      uint64_t dump_guid,
+      std::vector<mojom::SharedBufferWithSizePtr> buffers);
+
   void RemovePendingResponse(mojom::ClientProcess*,
                              QueuedRequest::PendingResponse::Type);
 
   void OnQueuedRequestTimedOut(uint64_t dump_guid);
+  void OnHeapDumpTimeOut(uint64_t dump_guid);
 
   void PerformNextQueuedGlobalMemoryDump();
   void FinalizeGlobalMemoryDumpIfAllManagersReplied();
@@ -187,6 +194,9 @@
   // Timeout for registered client processes to respond to dump requests.
   base::TimeDelta client_process_timeout_;
 
+  // When not null, can be queried for heap dumps.
+  mojom::HeapProfilerPtr heap_profiler_;
+
   THREAD_CHECKER(thread_checker_);
   DISALLOW_COPY_AND_ASSIGN(CoordinatorImpl);
 };
diff --git a/services/resource_coordinator/memory_instrumentation/queued_request.h b/services/resource_coordinator/memory_instrumentation/queued_request.h
index 30ea3dd..2457cc0 100644
--- a/services/resource_coordinator/memory_instrumentation/queued_request.h
+++ b/services/resource_coordinator/memory_instrumentation/queued_request.h
@@ -105,6 +105,10 @@
   int failed_memory_dump_count = 0;
   bool dump_in_progress = false;
 
+  // This field is set to |true| before a heap dump is requested, and set to
+  // |false| after the heap dump has been added to the trace.
+  bool heap_dump_in_progress = false;
+
   // The time we started handling the request (does not including queuing
   // time).
   base::Time start_time;
diff --git a/services/resource_coordinator/public/cpp/memory_instrumentation/tracing_integration_unittest.cc b/services/resource_coordinator/public/cpp/memory_instrumentation/tracing_integration_unittest.cc
index 3518988..0d893c6 100644
--- a/services/resource_coordinator/public/cpp/memory_instrumentation/tracing_integration_unittest.cc
+++ b/services/resource_coordinator/public/cpp/memory_instrumentation/tracing_integration_unittest.cc
@@ -115,6 +115,8 @@
   void RegisterClientProcess(mojom::ClientProcessPtr,
                              mojom::ProcessType) override {}
 
+  void RegisterHeapProfiler(mojom::HeapProfilerPtr heap_profiler) override {}
+
   void RequestGlobalMemoryDump(
       MemoryDumpType dump_type,
       MemoryDumpLevelOfDetail level_of_detail,
diff --git a/services/resource_coordinator/public/mojom/memory_instrumentation/memory_instrumentation.mojom b/services/resource_coordinator/public/mojom/memory_instrumentation/memory_instrumentation.mojom
index ef24d68..1b4b2d1 100644
--- a/services/resource_coordinator/public/mojom/memory_instrumentation/memory_instrumentation.mojom
+++ b/services/resource_coordinator/public/mojom/memory_instrumentation/memory_instrumentation.mojom
@@ -225,6 +225,42 @@
       (bool success, map<mojo.common.mojom.ProcessId, RawOSMemDump> dumps);
 };
 
+struct SharedBufferWithSize {
+  handle<shared_buffer> buffer;
+  uint32 size;
+  mojo.common.mojom.ProcessId pid;
+};
+
+// HeapProfilers expose a single interface to memory_instrumentation, allowing
+// the latter to query for heap dumps when necessary.
+//
+// This interface is NOT implemented in resource_coordinator but by the
+// profiling service in chrome/profiler. The profiling service registers itself
+// with the Coordinator (see RegisterHeapProfiler) and is invoked when a memory
+// dump is requested (via Coordinator::RequestGlobalMemoryDump).
+interface HeapProfiler {
+  // Dumps the memory log of all profiled processes into shared buffers. The
+  // contents of each shared buffer is a JSON string compatible with
+  // TRACE_EVENT* macros. Processes that fail to dump will be omitted from
+  // |buffers|. When |strip_path_from_mapped_files| is true, only the base name
+  // of mapped files is emitted. This prevents usernames from sneaking into the
+  // trace.
+  // |strip_path_from_mapped_files| should only be true for traces that will be
+  // uploaded to the crash servers - this strips potential PII, but prevents
+  // symbolization of local builds.
+  DumpProcessesForTracing(bool strip_path_from_mapped_files) =>
+      (array<SharedBufferWithSize> buffers);
+};
+
+// Implemented by resource_coordinator to provide additional information needed
+// by the HeapProfiler.
+interface HeapProfilerHelper {
+  // Broadcasts a RequestOSMemoryDump-only request for all registered client
+  // processes and retrieves only their memory maps.
+  GetVmRegionsForHeapProfiler(array<mojo.common.mojom.ProcessId> pids) =>
+      (map<mojo.common.mojom.ProcessId, array<VmRegion>> vm_regions);
+};
+
 // The memory-infra service implements this interface. There is one instance for
 // the whole system. The coordinator maintains a list of registered client
 // processes and polls them whenever a global dump is required.
@@ -252,12 +288,11 @@
   RequestGlobalMemoryDumpAndAppendToTrace(DumpType dump_type,
                                           LevelOfDetail level_of_detail) =>
       (bool success, uint64 dump_id);
-};
 
-// Used by the Chrome heap profiler
-interface HeapProfilerHelper {
-  // Broadcasts a RequestOSMemoryDump-only request for all registered client
-  // processes and retrieves only their memory maps.
-  GetVmRegionsForHeapProfiler(array<mojo.common.mojom.ProcessId> pids) =>
-      (map<mojo.common.mojom.ProcessId, array<VmRegion>> vm_regions);
+  // When a heap profiler is registered, heap dumps will be added to the trace
+  // any time RequestGlobalMemoryDumpAndAppendToTrace is called.
+  // This is cleaner than having the memory_instrumentation service talk
+  // directly to the HeapProfiler, since that will spawn the HeapProfiler in a
+  // new process if it isn't already running.
+  RegisterHeapProfiler(HeapProfiler heap_profiler);
 };
diff --git a/testing/android/native_test/BUILD.gn b/testing/android/native_test/BUILD.gn
index b1acb24f..2e63483f 100644
--- a/testing/android/native_test/BUILD.gn
+++ b/testing/android/native_test/BUILD.gn
@@ -52,6 +52,7 @@
     "//testing/android/reporter:reporter_java",
   ]
   java_files = [
+    "java/src/org/chromium/native_test/NativeTestApplication.java",
     "java/src/org/chromium/native_test/NativeBrowserTestActivity.java",
     "java/src/org/chromium/native_test/NativeTest.java",
     "java/src/org/chromium/native_test/NativeTestInstrumentationTestRunner.java",
diff --git a/testing/android/native_test/java/AndroidManifest.xml.jinja2 b/testing/android/native_test/java/AndroidManifest.xml.jinja2
index e4884de..dd600400 100644
--- a/testing/android/native_test/java/AndroidManifest.xml.jinja2
+++ b/testing/android/native_test/java/AndroidManifest.xml.jinja2
@@ -24,7 +24,7 @@
     <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
 
     <application android:label="NativeTests"
-            android:name="org.chromium.base.BaseChromiumApplication">
+            android:name="org.chromium.native_test.NativeTestApplication">
         <uses-library android:name="android.test.runner"/>
         {% if use_native_activity == 'true' %}
         <activity android:name=".NativeUnitTestNativeActivity"
diff --git a/testing/android/native_test/java/src/org/chromium/native_test/NativeTestApplication.java b/testing/android/native_test/java/src/org/chromium/native_test/NativeTestApplication.java
new file mode 100644
index 0000000..80ca421
--- /dev/null
+++ b/testing/android/native_test/java/src/org/chromium/native_test/NativeTestApplication.java
@@ -0,0 +1,25 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.native_test;
+
+import android.app.Application;
+import android.content.Context;
+
+import org.chromium.base.BuildConfig;
+import org.chromium.base.multidex.ChromiumMultiDexInstaller;
+
+/**
+ * Application class to be used by native_test apks.
+ */
+public class NativeTestApplication extends Application {
+    @Override
+    protected void attachBaseContext(Context base) {
+        super.attachBaseContext(base);
+        assert getBaseContext() != null;
+        if (BuildConfig.isMultidexEnabled()) {
+            ChromiumMultiDexInstaller.install(this);
+        }
+    }
+}
diff --git a/testing/buildbot/chromium.gpu.fyi.json b/testing/buildbot/chromium.gpu.fyi.json
index 7a29e11..ae829af 100644
--- a/testing/buildbot/chromium.gpu.fyi.json
+++ b/testing/buildbot/chromium.gpu.fyi.json
@@ -9958,6 +9958,36 @@
       }
     ]
   },
+  "Optional Android Release (Nexus 5X)": {
+    "gtest_tests": [],
+    "isolated_scripts": [
+      {
+        "args": [
+          "noop_sleep",
+          "--show-stdout",
+          "--browser=android-chromium",
+          "--passthrough",
+          "-v",
+          "--extra-browser-args=--enable-logging=stderr --js-flags=--expose-gc"
+        ],
+        "isolate_name": "telemetry_gpu_integration_test",
+        "name": "noop_sleep_tests",
+        "override_compile_targets": [
+          "telemetry_gpu_integration_test"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "device_os": "MMB29Q",
+              "device_type": "bullhead",
+              "os": "Android"
+            }
+          ]
+        }
+      }
+    ]
+  },
   "Optional Linux Release (Intel HD 630)": {
     "gtest_tests": [
       {
diff --git a/testing/buildbot/chromium.win.json b/testing/buildbot/chromium.win.json
index e4d4f35..43b21af5 100644
--- a/testing/buildbot/chromium.win.json
+++ b/testing/buildbot/chromium.win.json
@@ -2303,6 +2303,19 @@
         "args": [
           "--jobs=1"
         ],
+        "experiment_percentage": 100,
+        "isolate_name": "telemetry_perf_unittests",
+        "name": "telemetry_perf_unittests",
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "hard_timeout": 960,
+          "shards": 20
+        }
+      },
+      {
+        "args": [
+          "--jobs=1"
+        ],
         "isolate_name": "telemetry_unittests",
         "name": "telemetry_unittests",
         "swarming": {
diff --git a/testing/buildbot/filters/ash_unittests_mash.filter b/testing/buildbot/filters/ash_unittests_mash.filter
index f934483..228ee17 100644
--- a/testing/buildbot/filters/ash_unittests_mash.filter
+++ b/testing/buildbot/filters/ash_unittests_mash.filter
@@ -33,10 +33,12 @@
 -CursorWindowControllerTest.ShouldEnableCursorCompositing
 -CursorWindowControllerTest.VisibilityTest
 
-# TODO: wire up mirroring and unified display. http://crbug.com/770243.
+# TODO: wire up mirroring and unified display. http://crbug.com/813978
+-DisplayManagerTest.CompositingCursorInMultiSoftwareMirroring
 -DisplayManagerTest.SoftwareMirroring
--DisplayManagerTest.SoftwareMirroringWithCompositingCursor
--DisplayManagerTest.SingleDisplayToSoftwareMirroring
+-DisplayManagerTest.SoftwareMirrorModeBasics
+-DisplayManagerTest.UpdateMouseCursorAfterRotateZoom
+-DisplayManagerTestDisableMultiMirroring.SoftwareMirroringWithCompositingCursor
 
 # TODO: CursorManagerTestApi. http://crbug.com/780637
 -DragWindowResizerTest.CursorDeviceScaleFactor
@@ -93,14 +95,20 @@
 -ImmersiveFullscreenControllerTest.RevealViaGestureChildConsumesEvents
 -ImmersiveFullscreenControllerTest.Transient
 
-# TODO: http://crbug.com/725257
--LockScreenSanityTest.PasswordSubmitClearsPasswordAfterAuthentication
-
-# TODO: Triage
--LoginMetricsRecorderTest.UnlockAttempts
+# Input event or IME problem, keystrokes not delivered to password field.
+# http://crbug.com/725257
+-LockScreenSanityTest.PasswordSubmitClearsPasswordAfterFailedAuthentication
 -LoginPasswordViewTest.PasswordSubmitClearsPassword
 -LoginPasswordViewTest.PasswordSubmitIncludesPasswordText
 -LoginPasswordViewTest.PasswordSubmitViaButton
+-LoginPasswordViewTest.SubmitButtonUpdatesUiState
+
+# Ash.Login.Lock.AuthMethod.Used.ClamShellMode histogram count is wrong,
+# possible TabletModeController problem. http://crbug.com/814009
+-LoginMetricsRecorderTest.UnlockAttempts
+
+# Focus doesn't move. Possible EventGenerator problem. http://crbug.com/814011
+-LoginShelfViewTest.TabGoesFromShelfToStatusAreaAndBackToShelf
 
 # TODO: Triage
 -MagnificationControllerTest.CenterTextCaretInViewport
@@ -154,6 +162,12 @@
 -PanelWindowResizerTest.DetachThenAttachToSecondDisplay
 -PanelWindowResizerTest.DetachThenDragAcrossDisplays
 
+# "Host widget" for magnifier is null. http://crbug.com/814014
+-PartialMagnificationControllerTest.ActiveOnPointerDown
+-PartialMagnificationControllerTest.DisablingDisablesActive
+-PartialMagnificationControllerTest.MagnifierFollowsPointer
+-PartialMagnificationControllerTest.MultipleDisplays
+
 # TODO: Needs cursor manager support. http://crbug.com/698033
 -PartialScreenshotControllerTest.CursorVisibilityTest
 -PartialScreenshotControllerTest.LargeCursor
@@ -169,6 +183,10 @@
 -ResizeShadowAndCursorTest.MouseHover
 -ResizeShadowAndCursorTest.Touch
 
+# shelf_view.cc(366) Check failed: TYPE_APP_LIST != model_->items()[index].type
+# http://crbug.com/814015
+-RootWindowControllerTest.MoveWindows_Basic
+
 # TODO: Triage
 -ShelfLayoutManagerTest.SwipingUpOnShelfInLaptopModeForFullscreenAppList
 -ShelfLayoutManagerTest.SwipingUpOnShelfInTabletModeForFullscreenAppList
@@ -179,6 +197,9 @@
 # TODO: Probably event filter problem. http://crbug.com/695758
 -ShellTest.TestPreTargetHandlerOrder
 
+# Focus traversal problem. http://crbug.com/814019
+-StatusAreaWidgetFocusTest.FocusOutObserver
+
 # TODO: Needs virtual keyboard. http://crbug.com/698892
 -SystemModalContainerLayoutManagerTest.SystemModalDialogGetPushedButNotCroppedFromKeyboard
 -SystemModalContainerLayoutManagerTest.SystemModalDialogGetPushedButNotCroppedFromKeyboardIfNotCentered
@@ -231,18 +252,28 @@
 -WindowCycleControllerTest.TabKeyNotLeaked
 
 # TODO: Needs CursorManager. http://crbug.com/631103
+-WindowManagerTest.ActivateOnMouse
+-WindowManagerTest.ActivateOnPointerWindowProperty
+-WindowManagerTest.ActivateOnTouch
+-WindowManagerTest.AdditionalFilters
+-WindowManagerTest.Focus
 -WindowManagerTest.MouseEventCursors
--WindowManagerTest.UpdateCursorVisibility
--WindowManagerTest.UpdateCursorVisibilityOnKeyEvent
--WindowManagerTest.UpdateCursorVisibilityAccelerator
+-WindowManagerTest.PanelActivation
 -WindowManagerTest.TestCursorClientObserver
+-WindowManagerTest.TransformActivate
+-WindowManagerTest.UpdateCursorVisibility
+-WindowManagerTest.UpdateCursorVisibilityAccelerator
+-WindowManagerTest.UpdateCursorVisibilityOnKeyEvent
 
 # TODO: Crashes in bounds_animator.cc. http://crbug.com/730759
 -WindowSelectorTest.MultipleDisplays
 -WindowSelectorTest.RemoveDisplay
 -WindowSelectorTest.RemoveDisplayWithAnimation
 
-# TODO: CursorManagerTestApi. http://crbug.com/780637
+# Needs CursorManager/CursorManagerTestApi. http://crbug.com/780637
+-WindowTreeHostManagerTest.DontUpdateInvisibleCursorLocationAfterDisplayChange
+-WindowTreeHostManagerTest.UpdateMouseLocationAfterDisplayChange
+-WindowTreeHostManagerTest.UpdateMouseLocationAfterDisplayChange_2ndOnLeft
 -WindowTreeHostManagerTest.UpdateMouseLocationAfterDisplayChange_PrimaryDisconnected
 -WindowTreeHostManagerTest.UpdateMouseLocationAfterDisplayChange_SwapPrimary
 
@@ -267,31 +298,5 @@
 # TODO: Needs CursorManager. http://crbug.com/631103
 -WorkspaceWindowResizerTest.MouseMoveWithTouchDrag
 
-# TODO: these all crash/fail because we weren't running ash_unittests --mash
-# for a period of time. The crashes need to be understood and more specific
-# bugs filed. http://crbug.com/813115.
--DisplayManagerTest.CompositingCursorInMultiSoftwareMirroring
--DisplayManagerTestDisableMultiMirroring.SoftwareMirroringWithCompositingCursor
--DisplayManagerTest.SoftwareMirrorModeBasics
--DisplayManagerTest.UpdateMouseCursorAfterRotateZoom
--LockScreenSanityTest.PasswordSubmitClearsPasswordAfterFailedAuthentication
--LoginPasswordViewTest.SubmitButtonUpdatesUiState
--LoginShelfViewTest.TabGoesFromShelfToStatusAreaAndBackToShelf
--PartialMagnificationControllerTest.ActiveOnPointerDown
--PartialMagnificationControllerTest.DisablingDisablesActive
--PartialMagnificationControllerTest.MagnifierFollowsPointer
--PartialMagnificationControllerTest.MultipleDisplays
--RootWindowControllerTest.MoveWindows_Basic
--StatusAreaWidgetFocusTest.FocusOutObserver
--WindowManagerTest.ActivateOnMouse
--WindowManagerTest.ActivateOnPointerWindowProperty
--WindowManagerTest.ActivateOnTouch
--WindowManagerTest.AdditionalFilters
--WindowManagerTest.Focus
--WindowManagerTest.PanelActivation
--WindowManagerTest.TransformActivate
--WindowTreeHostManagerTest.DontUpdateInvisibleCursorLocationAfterDisplayChange
--WindowTreeHostManagerTest.UpdateMouseLocationAfterDisplayChange
--WindowTreeHostManagerTest.UpdateMouseLocationAfterDisplayChange_2ndOnLeft
-
 # Keep alphabetized. See comment at top of file.
+
diff --git a/testing/buildbot/filters/mojo.fyi.network_browser_tests.filter b/testing/buildbot/filters/mojo.fyi.network_browser_tests.filter
index acfd9a6..2ac8822 100644
--- a/testing/buildbot/filters/mojo.fyi.network_browser_tests.filter
+++ b/testing/buildbot/filters/mojo.fyi.network_browser_tests.filter
@@ -420,13 +420,6 @@
 -ExtensionRequestLimitingThrottleBrowserTest.ThrottleRequest_RedirectCached
 -ExtensionRequestLimitingThrottleCommandLineBrowserTest.ThrottleRequestDisabled
 
-# Redirect responses using NavigationThrottle or by hooking
-# NavigationURLLoaderNetworkService::URLLoaderRequestController
-# instead of net::URLRequestInterceptor.
--NewTabPageInterceptorTest.204Interception
--NewTabPageInterceptorTest.404Interception
--NewTabPageInterceptorTest.FailedRequestInterception
-
 # This requires that InterceptNetworkTransactions works
 -ErrorPageNavigationCorrectionsFailTest.StaleCacheStatusFailedCorrections
 
diff --git a/testing/buildbot/test_suite_exceptions.pyl b/testing/buildbot/test_suite_exceptions.pyl
index 6a1fca0..c31add9 100644
--- a/testing/buildbot/test_suite_exceptions.pyl
+++ b/testing/buildbot/test_suite_exceptions.pyl
@@ -3338,12 +3338,20 @@
           '--jobs=1',
         ],
       },
+      'Win7 Tests (dbg)(1)': {
+        'args': [
+          '--jobs=1',
+        ],
+        'swarming': {
+          'shards': 20,
+        },
+        'experiment_percentage': 100,
+      },
     },
     'remove_from': [
       'Linux Tests (dbg)(1)(32)',
       'Mac10.9 Tests',
       'Mac10.9 Tests (dbg)',
-      'Win7 Tests (dbg)(1)',
       # client.v8.chromium
       'Linux - Future (dbg)',
     ],
diff --git a/testing/variations/fieldtrial_testing_config.json b/testing/variations/fieldtrial_testing_config.json
index 2886f57..67e864ae 100644
--- a/testing/variations/fieldtrial_testing_config.json
+++ b/testing/variations/fieldtrial_testing_config.json
@@ -2337,8 +2337,6 @@
                         "UIVerticalMargin": "8"
                     },
                     "enable_features": [
-                        "OmniboxUIExperimentHideSuggestionUrlScheme",
-                        "OmniboxUIExperimentHideSuggestionUrlTrivialSubdomains",
                         "OmniboxUIExperimentShowSuggestionFavicons",
                         "OmniboxUIExperimentSwapTitleAndUrl",
                         "OmniboxUIExperimentVerticalMargin"
diff --git a/third_party/WebKit/LayoutTests/external/wpt/feature-policy/picture-in-picture-default-feature-policy.https.sub.html b/third_party/WebKit/LayoutTests/external/wpt/feature-policy/picture-in-picture-default-feature-policy.https.sub.html
index 6f82016..94cec08 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/feature-policy/picture-in-picture-default-feature-policy.https.sub.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/feature-policy/picture-in-picture-default-feature-policy.https.sub.html
@@ -11,7 +11,7 @@
   const same_origin_src = '/feature-policy/resources/feature-policy-picture-in-picture.html';
   const cross_origin_src = 'https://{{domains[www]}}:{{ports[https][0]}}' +
     same_origin_src;
-  const header = 'Default "picture-in-picture" feature policy ["self"]';
+  const header = 'Default "picture-in-picture" feature policy [*]';
 
   async_test(t => {
     isPictureInPictureAllowed().then(t.step_func_done((result) => {
@@ -26,8 +26,8 @@
 
   async_test(t => {
     test_feature_availability('picture-in-picture', t, cross_origin_src,
-        expect_feature_unavailable_default,);
-  }, header + ' disallows cross-origin iframes.');
+        expect_feature_available_default,);
+  }, header + ' allows cross-origin iframes.');
 
   </script>
 </body>
diff --git a/third_party/WebKit/LayoutTests/http/tests/devtools/unit/object-events-expected.txt b/third_party/WebKit/LayoutTests/http/tests/devtools/unit/object-events-expected.txt
new file mode 100644
index 0000000..83a54f5
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/http/tests/devtools/unit/object-events-expected.txt
@@ -0,0 +1,23 @@
+The test verifies that DevTools events work.
+
+Adding a listener with this 'original listener'
+Dispatching event with the data 'first event'
+Heard event with the data 'first event' and this 'original listener'
+
+Adding a listener with this 'second listener'
+Dispatching event with the data 'second event'
+Heard event with the data 'second event' and this 'original listener'
+Heard event with the data 'second event' and this 'second listener'
+
+Removing a listener with this 'second listener'
+Dispatching event with the data 'third event'
+Heard event with the data 'third event' and this 'original listener'
+
+Adding a listener that removes a later listener
+Adding a listener with this 'later listener to be removed'
+Dispatching event with the data 'fourth event'
+Heard event with the data 'fourth event' and this 'original listener'
+removing the listener during the event: fourth event 
+Removing a listener with this 'later listener to be removed'
+
+
diff --git a/third_party/WebKit/LayoutTests/http/tests/devtools/unit/object-events.js b/third_party/WebKit/LayoutTests/http/tests/devtools/unit/object-events.js
new file mode 100644
index 0000000..3910f4b8
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/http/tests/devtools/unit/object-events.js
@@ -0,0 +1,48 @@
+// 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.
+
+(async function() {
+  TestRunner.addResult(`The test verifies that DevTools events work.\n`);
+  var object = new Common.Object();
+  var eventSymbol = Symbol('Event');
+
+  addListener('original listener');
+  dispatch('first event');
+  addListener('second listener');
+  dispatch('second event');
+  removeListener('second listener');
+  dispatch('third event');
+
+  TestRunner.addResult('Adding a listener that removes a later listener')
+  object.addEventListener(eventSymbol, event => {
+    TestRunner.addResult(`removing the listener during the event: ${event.data} `);
+    removeListener('later listener to be removed');
+  });
+  addListener('later listener to be removed')
+  dispatch('fourth event');
+
+  TestRunner.completeTest();
+
+  function eventListener(event) {
+    TestRunner.addResult(`Heard event with the data '${event.data}' and this '${this}'`);
+  }
+
+  function dispatch(data) {
+    TestRunner.addResult(`Dispatching event with the data '${data}'`);
+    object.dispatchEventToListeners(eventSymbol, data);
+    TestRunner.addResult('');
+  }
+
+  function addListener(thisValue) {
+    TestRunner.addResult(`Adding a listener with this '${thisValue}'`);
+    object.addEventListener(eventSymbol, eventListener, thisValue);
+  }
+
+  function removeListener(thisValue) {
+    TestRunner.addResult(`Removing a listener with this '${thisValue}'`);
+    object.removeEventListener(eventSymbol, eventListener, thisValue);
+
+  }
+
+})();
diff --git a/third_party/WebKit/LayoutTests/paint/invalidation/compositing/frame-child-clipping-mask-resize-crash.html b/third_party/WebKit/LayoutTests/paint/invalidation/compositing/frame-child-clipping-mask-resize-crash.html
new file mode 100644
index 0000000..9b40705
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/paint/invalidation/compositing/frame-child-clipping-mask-resize-crash.html
@@ -0,0 +1,18 @@
+<!DOCTYPE html>
+<iframe id="target" style="border-radius: 20px"
+        srcdoc="<div style='width: 300px; height:400px; background: blue'>"></iframe>
+<script src="../../../resources/testharness.js"></script>
+<script src="../../../resources/testharnessreport.js"></script>
+<script src="../../../resources/run-after-layout-and-paint.js"></script>
+<script>
+if (window.internals)
+  internals.settings.setPreferCompositingToLCDTextEnabled(true);
+onload = () => {
+  async_test(t => {
+    runAfterLayoutAndPaint(t.step_func_done(() => {
+      target.style.height = "600px";
+    }));
+  });
+};
+</script>
+
diff --git a/third_party/WebKit/LayoutTests/paint/masks/composited-mask-with-outline-crash.html b/third_party/WebKit/LayoutTests/paint/masks/composited-mask-with-outline-crash.html
new file mode 100644
index 0000000..3493cb2
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/paint/masks/composited-mask-with-outline-crash.html
@@ -0,0 +1,11 @@
+<!DOCTYPE html>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
+<script>test(function(){})</script>
+Passes if it does not crash.
+<div style="
+  border: 2px solid blue;
+  -webkit-mask-image: linear-gradient(black, white);
+  outline: 2px solid green;
+  will-change: transform">
+</div>
diff --git a/third_party/WebKit/Source/core/paint/PaintLayerPainter.cpp b/third_party/WebKit/Source/core/paint/PaintLayerPainter.cpp
index 91e1850..d2a6dfd 100644
--- a/third_party/WebKit/Source/core/paint/PaintLayerPainter.cpp
+++ b/third_party/WebKit/Source/core/paint/PaintLayerPainter.cpp
@@ -343,12 +343,15 @@
       paint_flags & kPaintLayerPaintingCompositingDecorationPhase;
   bool is_painting_overflow_contents =
       paint_flags & kPaintLayerPaintingOverflowContents;
+  bool is_painting_mask = paint_flags & kPaintLayerPaintingCompositingMaskPhase;
+
   // Outline always needs to be painted even if we have no visible content.
   // It is painted as part of the decoration phase which paints content that
   // is not scrolled and should be above scrolled content.
   bool should_paint_self_outline =
       is_self_painting_layer && !is_painting_overlay_scrollbars &&
-      (is_painting_composited_decoration || !is_painting_scrolling_content) &&
+      (is_painting_composited_decoration ||
+       (!is_painting_scrolling_content && !is_painting_mask)) &&
       paint_layer_.GetLayoutObject().StyleRef().HasOutline();
 
   if (paint_flags & kPaintLayerPaintingRootBackgroundOnly &&
@@ -405,8 +408,7 @@
   // construction, so they are nested properly.
   Optional<ClipPathClipper> clip_path_clipper;
   bool should_paint_clip_path =
-      paint_layer_.GetLayoutObject().HasClipPath() &&
-      (paint_flags & kPaintLayerPaintingCompositingMaskPhase);
+      is_painting_mask && paint_layer_.GetLayoutObject().HasClipPath();
   if (should_paint_clip_path) {
     LayoutPoint visual_offset_from_root =
         paint_layer_.EnclosingPaginationLayer()
@@ -644,22 +646,18 @@
     }
   }  // FilterPainter block
 
-  bool should_paint_mask =
-      (paint_flags & kPaintLayerPaintingCompositingMaskPhase) &&
-      should_paint_content && paint_layer_.GetLayoutObject().HasMask() &&
-      !selection_only;
+  bool should_paint_mask = is_painting_mask && should_paint_content &&
+                           paint_layer_.GetLayoutObject().HasMask() &&
+                           !selection_only;
   if (should_paint_mask) {
     PaintMaskForFragments(layer_fragments, context, local_painting_info,
                           paint_flags);
-  }
-  bool is_painting_composited_mask_layer =
-      !RuntimeEnabledFeatures::SlimmingPaintV2Enabled() &&
-      !(painting_info.GetGlobalPaintFlags() &
-        kGlobalPaintFlattenCompositingLayers) &&
-      paint_layer_.GetCompositedLayerMapping() &&
-      paint_layer_.GetCompositedLayerMapping()->MaskLayer() &&
-      (paint_flags & kPaintLayerPaintingCompositingMaskPhase);
-  if (is_painting_composited_mask_layer && !should_paint_mask) {
+  } else if (!RuntimeEnabledFeatures::SlimmingPaintV2Enabled() &&
+             is_painting_mask &&
+             !(painting_info.GetGlobalPaintFlags() &
+               kGlobalPaintFlattenCompositingLayers) &&
+             paint_layer_.GetCompositedLayerMapping() &&
+             paint_layer_.GetCompositedLayerMapping()->MaskLayer()) {
     // In SPv1 it is possible for CompositedLayerMapping to create a mask layer
     // for just CSS clip-path but without a CSS mask. In that case we need to
     // paint a fully filled mask (which will subsequently clipped by the
diff --git a/third_party/WebKit/Source/core/paint/PaintLayerScrollableArea.cpp b/third_party/WebKit/Source/core/paint/PaintLayerScrollableArea.cpp
index e653622..ad4ab3f 100644
--- a/third_party/WebKit/Source/core/paint/PaintLayerScrollableArea.cpp
+++ b/third_party/WebKit/Source/core/paint/PaintLayerScrollableArea.cpp
@@ -2073,16 +2073,8 @@
     DCHECK(Layer()->HasCompositedLayerMapping());
     Layer()->GetCompositedLayerMapping()->SetNeedsGraphicsLayerUpdate(
         kGraphicsLayerUpdateSubtree);
-
-    ScrollingCoordinator* scrolling_coordinator = GetScrollingCoordinator();
-    bool handled_scroll =
-        Layer()->IsRootLayer() && scrolling_coordinator &&
-        scrolling_coordinator->ScrollableAreaScrollLayerDidChange(this);
-
-    if (!handled_scroll) {
-      compositor->SetNeedsCompositingUpdate(
-          kCompositingUpdateAfterGeometryChange);
-    }
+    compositor->SetNeedsCompositingUpdate(
+        kCompositingUpdateAfterGeometryChange);
 
     // If we have fixed elements and we scroll the root layer in RLS we might
     // change compositing since the fixed elements might now overlap a
diff --git a/third_party/WebKit/Source/devtools/front_end/audits2/Audits2Panel.js b/third_party/WebKit/Source/devtools/front_end/audits2/Audits2Panel.js
index af8fdce..21c6075 100644
--- a/third_party/WebKit/Source/devtools/front_end/audits2/Audits2Panel.js
+++ b/third_party/WebKit/Source/devtools/front_end/audits2/Audits2Panel.js
@@ -14,24 +14,7 @@
 
     this._protocolService = new Audits2.ProtocolService();
 
-    const toolbar = new UI.Toolbar('', this.element);
-
-    const newButton = new UI.ToolbarButton(Common.UIString('New audit\u2026'), 'largeicon-add');
-    toolbar.appendToolbarItem(newButton);
-    newButton.addEventListener(UI.ToolbarButton.Events.Click, this._showDialog.bind(this));
-
-    const downloadButton = new UI.ToolbarButton(Common.UIString('Download report'), 'largeicon-download');
-    toolbar.appendToolbarItem(downloadButton);
-    downloadButton.addEventListener(UI.ToolbarButton.Events.Click, this._downloadSelected.bind(this));
-
-    toolbar.appendSeparator();
-
-    this._reportSelector = new Audits2.ReportSelector();
-    toolbar.appendToolbarItem(this._reportSelector.comboBox());
-
-    const clearButton = new UI.ToolbarButton(Common.UIString('Clear all'), 'largeicon-clear');
-    toolbar.appendToolbarItem(clearButton);
-    clearButton.addEventListener(UI.ToolbarButton.Events.Click, this._clearAll.bind(this));
+    this._renderToolbar();
 
     this._auditResultsElement = this.contentElement.createChild('div', 'audits2-results-container');
     this._dropTarget = new UI.DropTarget(
@@ -40,6 +23,7 @@
 
     for (const preset of Audits2.Audits2Panel.Presets)
       preset.setting.addChangeListener(this._refreshDialogUI.bind(this));
+
     this._showLandingPage();
     SDK.targetManager.observeModels(SDK.ServiceWorkerManager, this);
     SDK.targetManager.addEventListener(SDK.TargetManager.Events.InspectedURLChanged, this._refreshDialogUI, this);
@@ -157,17 +141,45 @@
     this._dialog.setStartEnabled(!isDisabled);
   }
 
+  _refreshToolbarUI() {
+    this._downloadButton.setEnabled(this._reportSelector.hasCurrentSelection());
+    this._clearButton.setEnabled(this._reportSelector.hasItems());
+  }
+
   _clearAll() {
     this._reportSelector.clearAll();
     this._showLandingPage();
+    this._refreshToolbarUI();
   }
 
   _downloadSelected() {
     this._reportSelector.downloadSelected();
   }
 
+  _renderToolbar() {
+    const toolbar = new UI.Toolbar('', this.element);
+
+    this._newButton = new UI.ToolbarButton(Common.UIString('Perform an audit\u2026'), 'largeicon-add');
+    toolbar.appendToolbarItem(this._newButton);
+    this._newButton.addEventListener(UI.ToolbarButton.Events.Click, this._showDialog.bind(this));
+
+    this._downloadButton = new UI.ToolbarButton(Common.UIString('Download report'), 'largeicon-download');
+    toolbar.appendToolbarItem(this._downloadButton);
+    this._downloadButton.addEventListener(UI.ToolbarButton.Events.Click, this._downloadSelected.bind(this));
+
+    toolbar.appendSeparator();
+
+    this._reportSelector = new Audits2.ReportSelector();
+    toolbar.appendToolbarItem(this._reportSelector.comboBox());
+
+    this._clearButton = new UI.ToolbarButton(Common.UIString('Clear all'), 'largeicon-clear');
+    toolbar.appendToolbarItem(this._clearButton);
+    this._clearButton.addEventListener(UI.ToolbarButton.Events.Click, this._clearAll.bind(this));
+    this._refreshToolbarUI();
+  }
+
   _showLandingPage() {
-    if (this._reportSelector.comboBox().size())
+    if (this._reportSelector.hasCurrentSelection())
       return;
 
     this._auditResultsElement.removeChildren();
@@ -188,6 +200,7 @@
         Common.UIString('Perform an audit\u2026'), this._showDialog.bind(this), '', true /* primary */);
     landingCenter.appendChild(newButton);
     this.setDefaultFocusedElement(newButton);
+    this._refreshToolbarUI();
   }
 
   _showDialog() {
@@ -215,6 +228,7 @@
         new Audits2.ReportSelector.Item(lighthouseResult, this._auditResultsElement, this._showLandingPage.bind(this));
     this._reportSelector.prepend(optionElement);
     this._hideDialog();
+    this._refreshToolbarUI();
   }
 
   /**
@@ -319,10 +333,20 @@
 
 Audits2.ReportSelector = class {
   constructor() {
+    this._emptyItem = null;
     this._comboBox = new UI.ToolbarComboBox(this._handleChange.bind(this), 'audits2-report');
     this._comboBox.setMaxWidth(270);
     this._comboBox.setMinWidth(200);
     this._itemByOptionElement = new Map();
+    this._setPlaceholderState();
+  }
+
+  _setPlaceholderState() {
+    this._comboBox.setEnabled(false);
+    this._emptyItem = createElement('option');
+    this._emptyItem.label = Common.UIString('(no reports)');
+    this._comboBox.selectElement().appendChild(this._emptyItem);
+    this._comboBox.select(this._emptyItem);
   }
 
   /**
@@ -343,6 +367,20 @@
   }
 
   /**
+   * @return {boolean}
+   */
+  hasCurrentSelection() {
+    return !!this._selectedItem();
+  }
+
+  /**
+   * @return {boolean}
+   */
+  hasItems() {
+    return this._itemByOptionElement.size > 0;
+  }
+
+  /**
    * @return {!UI.ToolbarComboBox}
    */
   comboBox() {
@@ -353,18 +391,28 @@
    * @param {!Audits2.ReportSelector.Item} item
    */
   prepend(item) {
+    if (this._emptyItem) {
+      this._emptyItem.remove();
+      delete this._emptyItem;
+    }
+
     const optionEl = item.optionElement();
     const selectEl = this._comboBox.selectElement();
 
     this._itemByOptionElement.set(optionEl, item);
     selectEl.insertBefore(optionEl, selectEl.firstElementChild);
+    this._comboBox.setEnabled(true);
     this._comboBox.select(optionEl);
     item.select();
   }
 
   clearAll() {
-    for (const elem of this._comboBox.options())
+    for (const elem of this._comboBox.options()) {
       this._itemByOptionElement.get(elem).delete();
+      this._itemByOptionElement.delete(elem);
+    }
+
+    this._setPlaceholderState();
   }
 
   downloadSelected() {
diff --git a/third_party/WebKit/Source/devtools/front_end/common/Object.js b/third_party/WebKit/Source/devtools/front_end/common/Object.js
index 43bab9b0..6c8fb3c 100644
--- a/third_party/WebKit/Source/devtools/front_end/common/Object.js
+++ b/third_party/WebKit/Source/devtools/front_end/common/Object.js
@@ -80,8 +80,10 @@
       return;
     const listeners = this._listeners.get(eventType);
     for (let i = 0; i < listeners.length; ++i) {
-      if (listeners[i].listener === listener && listeners[i].thisObject === thisObject)
+      if (listeners[i].listener === listener && listeners[i].thisObject === thisObject) {
+        listeners[i].disposed = true;
         listeners.splice(i--, 1);
+      }
     }
 
     if (!listeners.length)
@@ -108,8 +110,10 @@
 
     const event = /** @type {!Common.Event} */ ({data: eventData});
     const listeners = this._listeners.get(eventType).slice(0);
-    for (let i = 0; i < listeners.length; ++i)
-      listeners[i].listener.call(listeners[i].thisObject, event);
+    for (let i = 0; i < listeners.length; ++i) {
+      if (!listeners[i].disposed)
+        listeners[i].listener.call(listeners[i].thisObject, event);
+    }
   }
 };
 
@@ -119,7 +123,7 @@
 Common.Event;
 
 /**
- * @typedef {!{thisObject: (!Object|undefined), listener: function(!Common.Event)}}
+ * @typedef {!{thisObject: (!Object|undefined), listener: function(!Common.Event), disposed: (boolean|undefined)}}
  */
 Common.Object._listenerCallbackTuple;
 
diff --git a/third_party/WebKit/Source/devtools/front_end/sources/AdvancedSearchView.js b/third_party/WebKit/Source/devtools/front_end/sources/AdvancedSearchView.js
index f2a1ff1..467fcf20 100644
--- a/third_party/WebKit/Source/devtools/front_end/sources/AdvancedSearchView.js
+++ b/third_party/WebKit/Source/devtools/front_end/sources/AdvancedSearchView.js
@@ -1,16 +1,30 @@
 // 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.
-/**
- * @unrestricted
- */
 Sources.AdvancedSearchView = class extends UI.VBox {
   constructor() {
     super(true);
     this.setMinimumSize(0, 40);
     this.registerRequiredCSS('sources/sourcesSearch.css');
 
-    this._searchId = 0;
+    this._focusOnShow = false;
+    this._isIndexing = false;
+    this._searchId = 1;
+    this._searchMatchesCount = 0;
+    this._searchResultsCount = 0;
+    this._nonEmptySearchResultsCount = 0;
+    /** @type {?UI.Widget} */
+    this._searchingView = null;
+    /** @type {?UI.Widget} */
+    this._notFoundView = null;
+    /** @type {?Workspace.SearchConfig} */
+    this._searchConfig = null;
+    /** @type {?Workspace.SearchConfig} */
+    this._pendingSearchConfig = null;
+    /** @type {?Sources.FileBasedSearchResultsPane} */
+    this._searchResultsPane = null;
+    /** @type {?UI.ProgressIndicator} */
+    this._progressIndicator = null;
 
     this.contentElement.classList.add('search-view');
 
@@ -38,22 +52,16 @@
     const cancelButtonContainer = this._searchPanelElement.createChild('div', 'search-cancel-button-container');
     cancelButtonContainer.appendChild(this._searchInputClearElement);
 
-    this._ignoreCaseLabel = UI.CheckboxLabel.create(Common.UIString('Ignore case'));
-    this._ignoreCaseLabel.classList.add('search-config-label');
-    this._searchPanelElement.appendChild(this._ignoreCaseLabel);
-    this._ignoreCaseCheckbox = this._ignoreCaseLabel.checkboxElement;
-    this._ignoreCaseCheckbox.classList.add('search-config-checkbox');
+    const toolbar = new UI.Toolbar('search-toolbar', this._searchPanelElement);
+    this._ignoreCaseCheckbox = new UI.ToolbarCheckbox(Common.UIString('Ignore case'));
+    toolbar.appendToolbarItem(this._ignoreCaseCheckbox);
+    this._regexCheckbox = new UI.ToolbarCheckbox(Common.UIString('Regular expression'));
+    toolbar.appendToolbarItem(this._regexCheckbox);
 
-    this._regexLabel = UI.CheckboxLabel.create(Common.UIString('Regular expression'));
-    this._regexLabel.classList.add('search-config-label');
-    this._searchPanelElement.appendChild(this._regexLabel);
-    this._regexCheckbox = this._regexLabel.checkboxElement;
-    this._regexCheckbox.classList.add('search-config-checkbox');
-
-    this._searchToolbarElement = this.contentElement.createChild('div', 'search-toolbar-summary');
-    this._searchMessageElement = this._searchToolbarElement.createChild('div', 'search-message');
-    this._searchProgressPlaceholderElement = this._searchToolbarElement.createChild('div', 'flex-centered');
-    this._searchResultsMessageElement = this._searchToolbarElement.createChild('div', 'search-message');
+    const searchStatusBarElement = this.contentElement.createChild('div', 'search-toolbar-summary');
+    this._searchMessageElement = searchStatusBarElement.createChild('div', 'search-message');
+    this._searchProgressPlaceholderElement = searchStatusBarElement.createChild('div', 'flex-centered');
+    this._searchResultsMessageElement = searchStatusBarElement.createChild('div', 'search-message');
 
     this._advancedSearchConfig = Common.settings.createLocalSetting(
         'advancedSearchConfig', new Workspace.SearchConfig('', true, false).toPlainObject());
@@ -79,7 +87,7 @@
    */
   _buildSearchConfig() {
     return new Workspace.SearchConfig(
-        this._search.value, this._ignoreCaseCheckbox.checked, this._regexCheckbox.checked);
+        this._search.value, this._ignoreCaseCheckbox.checked(), this._regexCheckbox.checked());
   }
 
   /**
@@ -103,22 +111,22 @@
   wasShown() {
     if (this._focusOnShow) {
       this.focus();
-      delete this._focusOnShow;
+      this._focusOnShow = false;
     }
   }
 
   _onIndexingFinished() {
     const finished = !this._progressIndicator.isCanceled();
     this._progressIndicator.done();
-    delete this._progressIndicator;
-    delete this._isIndexing;
+    this._progressIndicator = null;
+    this._isIndexing = false;
     this._indexingFinished(finished);
     if (!finished)
-      delete this._pendingSearchConfig;
+      this._pendingSearchConfig = null;
     if (!this._pendingSearchConfig)
       return;
     const searchConfig = this._pendingSearchConfig;
-    delete this._pendingSearchConfig;
+    this._pendingSearchConfig = null;
     this._innerStartSearch(searchConfig);
   }
 
@@ -153,8 +161,10 @@
     this._addSearchResult(searchResult);
     if (!searchResult.searchMatches.length)
       return;
-    if (!this._searchResultsPane)
-      this._searchResultsPane = new Sources.FileBasedSearchResultsPane(this._searchConfig);
+    if (!this._searchResultsPane) {
+      this._searchResultsPane =
+          new Sources.FileBasedSearchResultsPane(/** @type {!Workspace.SearchConfig} */ (this._searchConfig));
+    }
     this._resetResults();
     this._searchResultsElement.appendChild(this._searchResultsPane.element);
     this._searchResultsPane.addSearchResult(searchResult);
@@ -334,8 +344,8 @@
   _load() {
     const searchConfig = Workspace.SearchConfig.fromPlainObject(this._advancedSearchConfig.get());
     this._search.value = searchConfig.query();
-    this._ignoreCaseCheckbox.checked = searchConfig.ignoreCase();
-    this._regexCheckbox.checked = searchConfig.isRegex();
+    this._ignoreCaseCheckbox.setChecked(searchConfig.ignoreCase());
+    this._regexCheckbox.setChecked(searchConfig.isRegex());
     if (this._search.value && this._search.value.length)
       this._searchInputClearElement.classList.remove('hidden');
   }
@@ -351,9 +361,6 @@
 };
 
 
-/**
- * @unrestricted
- */
 Sources.SearchResultsPane = class {
   /**
    * @param {!Workspace.ProjectSearchConfig} searchConfig
@@ -379,7 +386,6 @@
 
 /**
  * @implements {UI.ActionDelegate}
- * @unrestricted
  */
 Sources.AdvancedSearchView.ActionDelegate = class {
   /**
diff --git a/third_party/WebKit/Source/devtools/front_end/sources/FileBasedSearchResultsPane.js b/third_party/WebKit/Source/devtools/front_end/sources/FileBasedSearchResultsPane.js
index 6041d05a..bf8d828e1 100644
--- a/third_party/WebKit/Source/devtools/front_end/sources/FileBasedSearchResultsPane.js
+++ b/third_party/WebKit/Source/devtools/front_end/sources/FileBasedSearchResultsPane.js
@@ -1,12 +1,9 @@
 // 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.
-/**
- * @unrestricted
- */
 Sources.FileBasedSearchResultsPane = class extends Sources.SearchResultsPane {
   /**
-   * @param {!Workspace.ProjectSearchConfig} searchConfig
+   * @param {!Workspace.SearchConfig} searchConfig
    */
   constructor(searchConfig) {
     super(searchConfig);
@@ -47,9 +44,6 @@
 Sources.FileBasedSearchResultsPane.matchesExpandedByDefaultCount = 20;
 Sources.FileBasedSearchResultsPane.fileMatchesShownAtOnce = 20;
 
-/**
- * @unrestricted
- */
 Sources.FileBasedSearchResultsPane.FileTreeElement = class extends UI.TreeElement {
   /**
    * @param {!Workspace.ProjectSearchConfig} searchConfig
@@ -59,6 +53,7 @@
     super('', true);
     this._searchConfig = searchConfig;
     this._searchResult = searchResult;
+    this._initialized = false;
 
     this.toggleOnClick = true;
     this.selectable = false;
@@ -162,10 +157,11 @@
   _appendShowMoreMatchesElement(startMatchIndex) {
     const matchesLeftCount = this._searchResult.searchMatches.length - startMatchIndex;
     const showMoreMatchesText = Common.UIString('Show all matches (%d more).', matchesLeftCount);
-    this._showMoreMatchesTreeElement = new UI.TreeElement(showMoreMatchesText);
-    this.appendChild(this._showMoreMatchesTreeElement);
-    this._showMoreMatchesTreeElement.listItemElement.classList.add('show-more-matches');
-    this._showMoreMatchesTreeElement.onselect = this._showMoreMatchesElementSelected.bind(this, startMatchIndex);
+    const showMoreMatchesTreeElement = new UI.TreeElement(showMoreMatchesText);
+    this.appendChild(showMoreMatchesTreeElement);
+    showMoreMatchesTreeElement.listItemElement.classList.add('show-more-matches');
+    showMoreMatchesTreeElement.onselect =
+        this._showMoreMatchesElementSelected.bind(this, showMoreMatchesTreeElement, startMatchIndex);
   }
 
   /**
@@ -206,11 +202,12 @@
   }
 
   /**
+   * @param {!UI.TreeElement} showMoreMatchesTreeElement
    * @param {number} startMatchIndex
    * @return {boolean}
    */
-  _showMoreMatchesElementSelected(startMatchIndex) {
-    this.removeChild(this._showMoreMatchesTreeElement);
+  _showMoreMatchesElementSelected(showMoreMatchesTreeElement, startMatchIndex) {
+    this.removeChild(showMoreMatchesTreeElement);
     this._appendSearchMatches(startMatchIndex, this._searchResult.searchMatches.length);
     return false;
   }
diff --git a/third_party/WebKit/Source/devtools/front_end/sources/sourcesSearch.css b/third_party/WebKit/Source/devtools/front_end/sources/sourcesSearch.css
index 1517544..f51b59e 100644
--- a/third_party/WebKit/Source/devtools/front_end/sources/sourcesSearch.css
+++ b/third_party/WebKit/Source/devtools/front_end/sources/sourcesSearch.css
@@ -50,19 +50,6 @@
     top: 1px;
 }
 
-.search-drawer-header label.search-config-label:first-of-type {
-    border-left: 1px solid #dadada;
-    margin: 0px 0px 0px 1px;
-    padding-left: 10px;
-}
-
-.search-drawer-header label.search-config-label {
-    margin: 2px 4px;
-    margin-left: 8px;
-    color: #303030;
-    display: flex;
-}
-
 .search-toolbar-summary {
     background-color: #eee;
     border-top: 1px solid #ccc;
@@ -103,3 +90,10 @@
     align-items: center;
     justify-content: center;
 }
+
+
+.search-toolbar {
+    border-left: 1px solid #dadada;
+    padding: 4px 16px 0 8px;
+    flex-grow: 1;
+}
diff --git a/third_party/WebKit/Source/devtools/front_end/ui/toolbar.css b/third_party/WebKit/Source/devtools/front_end/ui/toolbar.css
index fbd9293..fcc1b6c 100644
--- a/third_party/WebKit/Source/devtools/front_end/ui/toolbar.css
+++ b/third_party/WebKit/Source/devtools/front_end/ui/toolbar.css
@@ -52,12 +52,20 @@
     color: #5a5a5a;
 }
 
+select.toolbar-item:disabled {
+    opacity: 0.5;
+}
+
 .toolbar-dropdown-arrow {
     background-color: #6D6D6D;
     pointer-events: none;
     flex: none;
 }
 
+select.toolbar-item:disabled + .toolbar-dropdown-arrow {
+    opacity: 0.5;
+}
+
 /* Toolbar item */
 
 .toolbar-button {
diff --git a/third_party/WebKit/Source/devtools/front_end/workspace/SearchConfig.js b/third_party/WebKit/Source/devtools/front_end/workspace/SearchConfig.js
index 1118b97..f191419 100644
--- a/third_party/WebKit/Source/devtools/front_end/workspace/SearchConfig.js
+++ b/third_party/WebKit/Source/devtools/front_end/workspace/SearchConfig.js
@@ -3,7 +3,6 @@
 // found in the LICENSE file.
 /**
  * @implements {Workspace.ProjectSearchConfig}
- * @unrestricted
  */
 Workspace.SearchConfig = class {
   /**
@@ -177,9 +176,6 @@
 Workspace.SearchConfig.RegexQuery;
 
 
-/**
- * @unrestricted
- */
 Workspace.SearchConfig.QueryTerm = class {
   /**
    * @param {string} text
diff --git a/third_party/WebKit/Source/platform/graphics/GraphicsLayer.cpp b/third_party/WebKit/Source/platform/graphics/GraphicsLayer.cpp
index 2fc58bd..d6380e42 100644
--- a/third_party/WebKit/Source/platform/graphics/GraphicsLayer.cpp
+++ b/third_party/WebKit/Source/platform/graphics/GraphicsLayer.cpp
@@ -984,6 +984,9 @@
 
   size_ = clamped_size;
 
+  // Invalidate the layer as a DisplayItemClient.
+  SetDisplayItemsUncached();
+
   layer_->Layer()->SetBounds(FlooredIntSize(size_));
   // Note that we don't resize m_contentsLayer. It's up the caller to do that.
 }
diff --git a/third_party/WebKit/Source/platform/heap/BlinkGC.h b/third_party/WebKit/Source/platform/heap/BlinkGC.h
index 4bac963..cee5c09b3 100644
--- a/third_party/WebKit/Source/platform/heap/BlinkGC.h
+++ b/third_party/WebKit/Source/platform/heap/BlinkGC.h
@@ -14,12 +14,14 @@
 
 namespace blink {
 
+class MarkingVisitor;
 class Visitor;
 
 using Address = uint8_t*;
 
 using FinalizationCallback = void (*)(void*);
-using VisitorCallback = void (*)(Visitor*, void* self);
+using VisitorCallback = void (*)(Visitor*, void*);
+using MarkingVisitorCallback = void (*)(MarkingVisitor*, void*);
 using TraceCallback = VisitorCallback;
 using WeakCallback = VisitorCallback;
 using EphemeronCallback = VisitorCallback;
@@ -110,4 +112,4 @@
 
 }  // namespace blink
 
-#endif
+#endif  // BlinkGC_h
diff --git a/third_party/WebKit/Source/platform/heap/GarbageCollected.h b/third_party/WebKit/Source/platform/heap/GarbageCollected.h
index 421caa90..70a0609 100644
--- a/third_party/WebKit/Source/platform/heap/GarbageCollected.h
+++ b/third_party/WebKit/Source/platform/heap/GarbageCollected.h
@@ -72,16 +72,16 @@
 class PLATFORM_EXPORT GarbageCollectedMixin {
  public:
   typedef int IsGarbageCollectedMixinMarker;
-  virtual void AdjustAndMark(Visitor*) const = 0;
+  virtual void AdjustAndMark(MarkingVisitor*) const = 0;
   virtual void Trace(Visitor*) {}
   virtual HeapObjectHeader* GetHeapObjectHeader() const = 0;
   virtual void AdjustAndTraceMarkedWrapper(
       const ScriptWrappableVisitor*) const = 0;
 };
 
-#define DEFINE_GARBAGE_COLLECTED_MIXIN_METHODS(VISITOR, TYPE)                 \
+#define DEFINE_GARBAGE_COLLECTED_MIXIN_METHODS(TYPE)                          \
  public:                                                                      \
-  void AdjustAndMark(VISITOR visitor) const override {                        \
+  void AdjustAndMark(blink::MarkingVisitor* visitor) const override {         \
     typedef WTF::IsSubclassOfTemplate<typename std::remove_const<TYPE>::type, \
                                       blink::GarbageCollected>                \
         IsSubclassOfGarbageCollected;                                         \
@@ -166,9 +166,9 @@
 // when the "operator new" for B runs, and leaving the forbidden GC scope
 // when the constructor of the recorded GarbageCollectedMixinConstructorMarker
 // runs.
-#define USING_GARBAGE_COLLECTED_MIXIN(TYPE)                     \
-  IS_GARBAGE_COLLECTED_TYPE();                                  \
-  DEFINE_GARBAGE_COLLECTED_MIXIN_METHODS(blink::Visitor*, TYPE) \
+#define USING_GARBAGE_COLLECTED_MIXIN(TYPE)    \
+  IS_GARBAGE_COLLECTED_TYPE();                 \
+  DEFINE_GARBAGE_COLLECTED_MIXIN_METHODS(TYPE) \
   DEFINE_GARBAGE_COLLECTED_MIXIN_CONSTRUCTOR_MARKER(TYPE)
 
 // An empty class with a constructor that's arranged invoked when all derived
@@ -210,7 +210,7 @@
 //  };
 #define MERGE_GARBAGE_COLLECTED_MIXINS()                          \
  public:                                                          \
-  void AdjustAndMark(Visitor*) const override = 0;                \
+  void AdjustAndMark(MarkingVisitor*) const override = 0;         \
   HeapObjectHeader* GetHeapObjectHeader() const override = 0;     \
   void AdjustAndTraceMarkedWrapper(const ScriptWrappableVisitor*) \
       const override = 0;                                         \
diff --git a/third_party/WebKit/Source/platform/heap/Heap.cpp b/third_party/WebKit/Source/platform/heap/Heap.cpp
index 5fac04a4..77f3a33 100644
--- a/third_party/WebKit/Source/platform/heap/Heap.cpp
+++ b/third_party/WebKit/Source/platform/heap/Heap.cpp
@@ -161,7 +161,8 @@
     delete arenas_[i];
 }
 
-Address ThreadHeap::CheckAndMarkPointer(Visitor* visitor, Address address) {
+Address ThreadHeap::CheckAndMarkPointer(MarkingVisitor* visitor,
+                                        Address address) {
   DCHECK(thread_state_->IsInGC());
 
 #if !DCHECK_IS_ON()
@@ -193,7 +194,7 @@
 // into the heap, provide a checkAndMarkPointer() version with an
 // extra notification argument.
 Address ThreadHeap::CheckAndMarkPointer(
-    Visitor* visitor,
+    MarkingVisitor* visitor,
     Address address,
     MarkedPointerCallbackForTesting callback) {
   DCHECK(thread_state_->IsInGC());
@@ -523,7 +524,7 @@
   thread_state_->VisitPersistents(visitor);
 }
 
-void ThreadHeap::VisitStackRoots(Visitor* visitor) {
+void ThreadHeap::VisitStackRoots(MarkingVisitor* visitor) {
   DCHECK(thread_state_->IsInGC());
   TRACE_EVENT0("blink_gc", "ThreadHeap::visitStackRoots");
   thread_state_->VisitStack(visitor);
diff --git a/third_party/WebKit/Source/platform/heap/Heap.h b/third_party/WebKit/Source/platform/heap/Heap.h
index 11663bc0..60a29a7 100644
--- a/third_party/WebKit/Source/platform/heap/Heap.h
+++ b/third_party/WebKit/Source/platform/heap/Heap.h
@@ -227,7 +227,7 @@
   CallbackStack* EphemeronStack() const { return ephemeron_stack_.get(); }
 
   void VisitPersistentRoots(Visitor*);
-  void VisitStackRoots(Visitor*);
+  void VisitStackRoots(MarkingVisitor*);
   void EnterSafePoint(ThreadState*);
   void LeaveSafePoint();
 
@@ -352,9 +352,9 @@
 
   // Conservatively checks whether an address is a pointer in any of the
   // thread heaps.  If so marks the object pointed to as live.
-  Address CheckAndMarkPointer(Visitor*, Address);
+  Address CheckAndMarkPointer(MarkingVisitor*, Address);
 #if DCHECK_IS_ON()
-  Address CheckAndMarkPointer(Visitor*,
+  Address CheckAndMarkPointer(MarkingVisitor*,
                               Address,
                               MarkedPointerCallbackForTesting);
 #endif
diff --git a/third_party/WebKit/Source/platform/heap/HeapPage.cpp b/third_party/WebKit/Source/platform/heap/HeapPage.cpp
index dfe76ca8..8f5c632 100644
--- a/third_party/WebKit/Source/platform/heap/HeapPage.cpp
+++ b/third_party/WebKit/Source/platform/heap/HeapPage.cpp
@@ -1617,7 +1617,7 @@
 }
 #endif
 
-static void MarkPointer(Visitor* visitor, HeapObjectHeader* header) {
+static void MarkPointer(MarkingVisitor* visitor, HeapObjectHeader* header) {
   const GCInfo* gc_info = ThreadHeap::GcInfo(header->GcInfoIndex());
   if (gc_info->HasVTable() && !VTableInitialized(header->Payload())) {
     // We hit this branch when a GC strikes before GarbageCollected<>'s
@@ -1640,7 +1640,7 @@
   }
 }
 
-void NormalPage::CheckAndMarkPointer(Visitor* visitor, Address address) {
+void NormalPage::CheckAndMarkPointer(MarkingVisitor* visitor, Address address) {
 #if DCHECK_IS_ON()
   DCHECK(Contains(address));
 #endif
@@ -1651,7 +1651,7 @@
 }
 
 #if DCHECK_IS_ON()
-void NormalPage::CheckAndMarkPointer(Visitor* visitor,
+void NormalPage::CheckAndMarkPointer(MarkingVisitor* visitor,
                                      Address address,
                                      MarkedPointerCallbackForTesting callback) {
   DCHECK(Contains(address));
@@ -1760,7 +1760,8 @@
 }
 #endif
 
-void LargeObjectPage::CheckAndMarkPointer(Visitor* visitor, Address address) {
+void LargeObjectPage::CheckAndMarkPointer(MarkingVisitor* visitor,
+                                          Address address) {
 #if DCHECK_IS_ON()
   DCHECK(Contains(address));
 #endif
@@ -1771,7 +1772,7 @@
 
 #if DCHECK_IS_ON()
 void LargeObjectPage::CheckAndMarkPointer(
-    Visitor* visitor,
+    MarkingVisitor* visitor,
     Address address,
     MarkedPointerCallbackForTesting callback) {
   DCHECK(Contains(address));
diff --git a/third_party/WebKit/Source/platform/heap/HeapPage.h b/third_party/WebKit/Source/platform/heap/HeapPage.h
index 5d08e64..736122c 100644
--- a/third_party/WebKit/Source/platform/heap/HeapPage.h
+++ b/third_party/WebKit/Source/platform/heap/HeapPage.h
@@ -388,9 +388,9 @@
   //
   // This is used during conservative stack scanning to conservatively mark all
   // objects that could be referenced from the stack.
-  virtual void CheckAndMarkPointer(Visitor*, Address) = 0;
+  virtual void CheckAndMarkPointer(MarkingVisitor*, Address) = 0;
 #if DCHECK_IS_ON()
-  virtual void CheckAndMarkPointer(Visitor*,
+  virtual void CheckAndMarkPointer(MarkingVisitor*,
                                    Address,
                                    MarkedPointerCallbackForTesting) = 0;
 #endif
@@ -532,9 +532,9 @@
 #if defined(ADDRESS_SANITIZER)
   void PoisonUnmarkedObjects() override;
 #endif
-  void CheckAndMarkPointer(Visitor*, Address) override;
+  void CheckAndMarkPointer(MarkingVisitor*, Address) override;
 #if DCHECK_IS_ON()
-  void CheckAndMarkPointer(Visitor*,
+  void CheckAndMarkPointer(MarkingVisitor*,
                            Address,
                            MarkedPointerCallbackForTesting) override;
 #endif
@@ -628,9 +628,9 @@
 #if defined(ADDRESS_SANITIZER)
   void PoisonUnmarkedObjects() override;
 #endif
-  void CheckAndMarkPointer(Visitor*, Address) override;
+  void CheckAndMarkPointer(MarkingVisitor*, Address) override;
 #if DCHECK_IS_ON()
-  void CheckAndMarkPointer(Visitor*,
+  void CheckAndMarkPointer(MarkingVisitor*,
                            Address,
                            MarkedPointerCallbackForTesting) override;
 #endif
diff --git a/third_party/WebKit/Source/platform/heap/HeapTest.cpp b/third_party/WebKit/Source/platform/heap/HeapTest.cpp
index e26a712..8088400 100644
--- a/third_party/WebKit/Source/platform/heap/HeapTest.cpp
+++ b/third_party/WebKit/Source/platform/heap/HeapTest.cpp
@@ -853,9 +853,9 @@
 
   virtual void Trace(blink::Visitor* visitor) {
     if (points_to_foo_)
-      visitor->Mark(static_cast<Foo*>(bar_));
+      visitor->Trace(static_cast<Foo*>(bar_));
     else
-      visitor->Mark(bar_);
+      visitor->Trace(bar_);
   }
 
  private:
@@ -3995,7 +3995,8 @@
   {
     ThreadState::GCForbiddenScope gc_scope(ThreadState::Current());
     TestGCScope scope(BlinkGC::kHeapPointersOnStack);
-    Visitor visitor(ThreadState::Current(), Visitor::kGlobalMarking);
+    MarkingVisitor visitor(ThreadState::Current(),
+                           MarkingVisitor::kGlobalMarking);
     heap.FlushHeapDoesNotContainCache();
     for (size_t i = 0; i < object_addresses.size(); i++) {
       EXPECT_TRUE(heap.CheckAndMarkPointer(&visitor, object_addresses[i],
@@ -4019,7 +4020,8 @@
   {
     ThreadState::GCForbiddenScope gc_scope(ThreadState::Current());
     TestGCScope scope(BlinkGC::kHeapPointersOnStack);
-    Visitor visitor(ThreadState::Current(), Visitor::kGlobalMarking);
+    MarkingVisitor visitor(ThreadState::Current(),
+                           MarkingVisitor::kGlobalMarking);
     heap.FlushHeapDoesNotContainCache();
     for (size_t i = 0; i < object_addresses.size(); i++) {
       // We would like to assert that checkAndMarkPointer returned false
diff --git a/third_party/WebKit/Source/platform/heap/ThreadState.cpp b/third_party/WebKit/Source/platform/heap/ThreadState.cpp
index 8806fd4..cecec265d 100644
--- a/third_party/WebKit/Source/platform/heap/ThreadState.cpp
+++ b/third_party/WebKit/Source/platform/heap/ThreadState.cpp
@@ -228,7 +228,8 @@
 }
 
 NO_SANITIZE_ADDRESS
-void ThreadState::VisitAsanFakeStackForPointer(Visitor* visitor, Address ptr) {
+void ThreadState::VisitAsanFakeStackForPointer(MarkingVisitor* visitor,
+                                               Address ptr) {
 #if defined(ADDRESS_SANITIZER)
   Address* start = reinterpret_cast<Address*>(start_of_stack_);
   Address* end = reinterpret_cast<Address*>(end_of_stack_);
@@ -256,7 +257,7 @@
 // other threads that use this stack.
 NO_SANITIZE_ADDRESS
 NO_SANITIZE_THREAD
-void ThreadState::VisitStack(Visitor* visitor) {
+void ThreadState::VisitStack(MarkingVisitor* visitor) {
   if (stack_state_ == BlinkGC::kNoHeapPointersOnStack)
     return;
 
@@ -1320,17 +1321,19 @@
   current_gc_data_.marking_time_in_milliseconds = 0;
 
   if (gc_type == BlinkGC::kTakeSnapshot) {
-    current_gc_data_.visitor = Visitor::Create(this, Visitor::kSnapshotMarking);
+    current_gc_data_.visitor =
+        MarkingVisitor::Create(this, MarkingVisitor::kSnapshotMarking);
   } else {
     DCHECK(gc_type == BlinkGC::kGCWithSweep ||
            gc_type == BlinkGC::kGCWithoutSweep);
     if (Heap().Compaction()->ShouldCompact(&Heap(), stack_state, gc_type,
                                            reason)) {
       Heap().Compaction()->Initialize(this);
-      current_gc_data_.visitor =
-          Visitor::Create(this, Visitor::kGlobalMarkingWithCompaction);
+      current_gc_data_.visitor = MarkingVisitor::Create(
+          this, MarkingVisitor::kGlobalMarkingWithCompaction);
     } else {
-      current_gc_data_.visitor = Visitor::Create(this, Visitor::kGlobalMarking);
+      current_gc_data_.visitor =
+          MarkingVisitor::Create(this, MarkingVisitor::kGlobalMarking);
     }
   }
 
diff --git a/third_party/WebKit/Source/platform/heap/ThreadState.h b/third_party/WebKit/Source/platform/heap/ThreadState.h
index 1b7bad0..723d16f 100644
--- a/third_party/WebKit/Source/platform/heap/ThreadState.h
+++ b/third_party/WebKit/Source/platform/heap/ThreadState.h
@@ -60,6 +60,7 @@
 }  // namespace incremental_marking_test
 
 class GarbageCollectedMixinConstructorMarkerBase;
+class MarkingVisitor;
 class PersistentNode;
 class PersistentRegion;
 class ThreadHeap;
@@ -417,11 +418,11 @@
   }
 
   // Visit local thread stack and trace all pointers conservatively.
-  void VisitStack(Visitor*);
+  void VisitStack(MarkingVisitor*);
 
   // Visit the asan fake stack frame corresponding to a slot on the
   // real machine stack if there is one.
-  void VisitAsanFakeStackForPointer(Visitor*, Address);
+  void VisitAsanFakeStackForPointer(MarkingVisitor*, Address);
 
   // Visit all non-weak persistents allocated on this thread.
   void VisitPersistents(Visitor*);
@@ -533,7 +534,7 @@
 
   int GcAge() const { return gc_age_; }
 
-  Visitor* CurrentVisitor() { return current_gc_data_.visitor.get(); }
+  MarkingVisitor* CurrentVisitor() { return current_gc_data_.visitor.get(); }
 
  private:
   // Needs to set up visitor for testing purposes.
@@ -683,7 +684,7 @@
     BlinkGC::GCReason reason;
     double marking_time_in_milliseconds;
     size_t marked_object_size;
-    std::unique_ptr<Visitor> visitor;
+    std::unique_ptr<MarkingVisitor> visitor;
   };
   GCData current_gc_data_;
 
diff --git a/third_party/WebKit/Source/platform/heap/TraceTraits.h b/third_party/WebKit/Source/platform/heap/TraceTraits.h
index fc765e1..7ba6ec9 100644
--- a/third_party/WebKit/Source/platform/heap/TraceTraits.h
+++ b/third_party/WebKit/Source/platform/heap/TraceTraits.h
@@ -66,8 +66,7 @@
   STATIC_ONLY(AdjustAndMarkTrait);
 
  public:
-  template <typename VisitorDispatcher>
-  static NOINLINE_GXX_ONLY void Mark(VisitorDispatcher visitor, const T* t) {
+  static NOINLINE_GXX_ONLY void Mark(MarkingVisitor* visitor, const T* t) {
 #if DCHECK_IS_ON()
     AssertObjectHasGCInfo(const_cast<T*>(t), GCInfoTrait<T>::Index());
 #endif
@@ -123,8 +122,7 @@
   STATIC_ONLY(AdjustAndMarkTrait);
 
  public:
-  template <typename VisitorDispatcher>
-  static void Mark(VisitorDispatcher visitor, const T* self) {
+  static void Mark(MarkingVisitor* visitor, const T* self) {
     if (!self)
       return;
     self->AdjustAndMark(visitor);
@@ -244,9 +242,10 @@
   static void TraceMarkedWrapper(const ScriptWrappableVisitor*, const void*);
   static HeapObjectHeader* GetHeapObjectHeader(const void*);
 
-  template <typename VisitorDispatcher>
-  static void Mark(VisitorDispatcher visitor, const T* t) {
-    AdjustAndMarkTrait<T>::Mark(visitor, t);
+  static void Mark(Visitor* visitor, void* t) {
+    // TODO(mlippautz): Remove cast.
+    AdjustAndMarkTrait<T>::Mark(reinterpret_cast<MarkingVisitor*>(visitor),
+                                reinterpret_cast<T*>(t));
   }
 
  private:
@@ -295,9 +294,11 @@
     }
   }
 
-  template <typename VisitorDispatcher>
-  static void Mark(VisitorDispatcher visitor, const Backing* backing) {
-    AdjustAndMarkTrait<Backing>::Mark(visitor, backing);
+  static void Mark(Visitor* visitor, void* backing) {
+    // TODO(mlippautz): Remove cast.
+    AdjustAndMarkTrait<Backing>::Mark(
+        reinterpret_cast<MarkingVisitor*>(visitor),
+        reinterpret_cast<Backing*>(backing));
   }
 };
 
@@ -322,9 +323,11 @@
     }
   }
 
-  template <typename VisitorDispatcher>
-  static void Mark(VisitorDispatcher visitor, const Backing* backing) {
-    AdjustAndMarkTrait<Backing>::Mark(visitor, backing);
+  static void Mark(Visitor* visitor, void* backing) {
+    // TODO(mlippautz): Remove cast.
+    AdjustAndMarkTrait<Backing>::Mark(
+        reinterpret_cast<MarkingVisitor*>(visitor),
+        reinterpret_cast<Backing*>(backing));
   }
 };
 
@@ -696,7 +699,9 @@
         // the contents, and there is no need to trace the next and
         // prev fields since iterating over the hash table backing will
         // find the whole chain.
-        visitor->MarkNoTracing(array[i]);
+        // TODO(mlippautz): Remove cast.
+        reinterpret_cast<blink::MarkingVisitor*>(visitor)->MarkNoTracing(
+            array[i]);
       }
     }
     return false;
diff --git a/third_party/WebKit/Source/platform/heap/Visitor.cpp b/third_party/WebKit/Source/platform/heap/Visitor.cpp
index ce2f9cf..20ddf6c 100644
--- a/third_party/WebKit/Source/platform/heap/Visitor.cpp
+++ b/third_party/WebKit/Source/platform/heap/Visitor.cpp
@@ -12,12 +12,17 @@
 
 namespace blink {
 
-std::unique_ptr<Visitor> Visitor::Create(ThreadState* state, MarkingMode mode) {
-  return std::make_unique<Visitor>(state, mode);
+Visitor::Visitor(ThreadState* state) : state_(state) {}
+
+Visitor::~Visitor() = default;
+
+std::unique_ptr<MarkingVisitor> MarkingVisitor::Create(ThreadState* state,
+                                                       MarkingMode mode) {
+  return std::make_unique<MarkingVisitor>(state, mode);
 }
 
-Visitor::Visitor(ThreadState* state, MarkingMode marking_mode)
-    : state_(state), marking_mode_(marking_mode) {
+MarkingVisitor::MarkingVisitor(ThreadState* state, MarkingMode marking_mode)
+    : Visitor(state), marking_mode_(marking_mode) {
   // See ThreadState::runScheduledGC() why we need to already be in a
   // GCForbiddenScope before any safe point is entered.
   DCHECK(state->IsGCForbidden());
@@ -26,10 +31,11 @@
 #endif
 }
 
-Visitor::~Visitor() = default;
+MarkingVisitor::~MarkingVisitor() = default;
 
-void Visitor::MarkNoTracingCallback(Visitor* visitor, void* object) {
-  visitor->MarkNoTracing(object);
+void MarkingVisitor::MarkNoTracingCallback(Visitor* visitor, void* object) {
+  // TODO(mlippautz): Remove cast;
+  reinterpret_cast<MarkingVisitor*>(visitor)->MarkNoTracing(object);
 }
 
 }  // namespace blink
diff --git a/third_party/WebKit/Source/platform/heap/Visitor.h b/third_party/WebKit/Source/platform/heap/Visitor.h
index 9b792bd..3c409d8 100644
--- a/third_party/WebKit/Source/platform/heap/Visitor.h
+++ b/third_party/WebKit/Source/platform/heap/Visitor.h
@@ -68,59 +68,21 @@
   }
 };
 
-// Visitor is used to traverse the Blink object graph. Used for the
-// marking phase of the mark-sweep garbage collector.
-//
-// Pointers are marked and pushed on the marking stack by calling the
-// |mark| method with the pointer as an argument.
-//
-// Pointers within objects are traced by calling the |trace| methods
-// with the object as an argument. Tracing objects will mark all of the
-// contained pointers and push them on the marking stack.
+// Visitor is used to traverse Oilpan's object graph.
 class PLATFORM_EXPORT Visitor {
  public:
-  enum MarkingMode {
-    // This is a default visitor. This is used for GCType=GCWithSweep
-    // and GCType=GCWithoutSweep.
-    kGlobalMarking,
-    // This visitor just marks objects and ignores weak processing.
-    // This is used for GCType=TakeSnapshot.
-    kSnapshotMarking,
-    // This visitor is used to trace objects during weak processing.
-    // This visitor is allowed to trace only already marked objects.
-    kWeakProcessing,
-    // Perform global marking along with preparing for additional sweep
-    // compaction of heap arenas afterwards. Compared to the GlobalMarking
-    // visitor, this visitor will also register references to objects
-    // that might be moved during arena compaction -- the compaction
-    // pass will then fix up those references when the object move goes
-    // ahead.
-    kGlobalMarkingWithCompaction,
-  };
-
-  static std::unique_ptr<Visitor> Create(ThreadState*, MarkingMode);
-
-  Visitor(ThreadState*, MarkingMode);
+  Visitor(ThreadState*);
   virtual ~Visitor();
 
-  // One-argument templated mark method. This uses the static type of
-  // the argument to get the TraceTrait. By default, the mark method
-  // of the TraceTrait just calls the virtual two-argument mark method on this
-  // visitor, where the second argument is the static trace method of the trait.
-  template <typename T>
-  void Mark(T* t) {
-    static_assert(sizeof(T), "T must be fully defined");
-    static_assert(IsGarbageCollectedType<T>::value,
-                  "T needs to be a garbage collected object");
-    if (!t)
-      return;
-    TraceTrait<T>::Mark(this, t);
-  }
+  inline ThreadState* GetState() const { return state_; }
+  inline ThreadHeap& Heap() const { return GetState()->Heap(); }
+
+  // Static visitor implementation forwarding to dynamic interface.
 
   // Member version of the one-argument templated trace method.
   template <typename T>
   void Trace(const Member<T>& t) {
-    Mark(t.Get());
+    Trace(t.Get());
   }
 
   template <typename T>
@@ -133,15 +95,22 @@
     Trace(*(static_cast<const Member<T>*>(&t)));
   }
 
-  // Fallback method used only when we need to trace raw pointers of T.
-  // This is the case when a member is a union where we do not support members.
+  // Fallback methods used only when we need to trace raw pointers of T. This is
+  // the case when a member is a union where we do not support members.
   template <typename T>
   void Trace(const T* t) {
-    Mark(const_cast<T*>(t));
+    Trace(const_cast<T*>(t));
   }
+
   template <typename T>
   void Trace(T* t) {
-    Mark(t);
+    static_assert(sizeof(T), "T must be fully defined");
+    static_assert(IsGarbageCollectedType<T>::value,
+                  "T needs to be a garbage collected object");
+    if (!t)
+      return;
+    Visit(const_cast<void*>(reinterpret_cast<const void*>(t)),
+          TraceTrait<T>::Trace, TraceTrait<T>::Mark);
   }
 
   // WeakMember version of the templated trace method. It doesn't keep
@@ -200,78 +169,126 @@
                          &TraceMethodDelegate<T, method>::Trampoline);
   }
 
-  inline void RegisterBackingStoreReference(void* slot);
+  // Dynamic visitor interface.
 
-  inline void RegisterBackingStoreCallback(void* backing_store,
-                                           MovingObjectCallback,
-                                           void* callback_data);
+  // Visits an object through a strong reference.
+  virtual void Visit(void*, TraceCallback, TraceCallback) = 0;
 
-  // This method marks an object and adds it to the set of objects
-  // that should have their trace method called. Since not all
-  // objects have vtables we have to have the callback as an
-  // explicit argument, but we can use the templated one-argument
-  // mark method above to automatically provide the callback
-  // function.
-  inline void Mark(const void* object_pointer, TraceCallback);
+  // Registers backing store pointers so that they can be moved and properly
+  // updated.
+  virtual void RegisterBackingStoreReference(void* slot) = 0;
+  virtual void RegisterBackingStoreCallback(void* backing_store,
+                                            MovingObjectCallback,
+                                            void* callback_data) = 0;
 
-  // Used to delay the marking of objects until the usual marking
-  // including emphemeron iteration is done. This is used to delay
-  // the marking of collection backing stores until we know if they
-  // are reachable from locations other than the collection front
-  // object. If collection backings are reachable from other
-  // locations we strongify them to avoid issues with iterators and
-  // weak processing.
-  inline void RegisterDelayedMarkNoTracing(const void* pointer);
+  // Used to delay the marking of objects until the usual marking including
+  // ephemeron iteration is done. This is used to delay the marking of
+  // collection backing stores until we know if they are reachable from
+  // locations other than the collection front object. If collection backings
+  // are reachable from other locations we strongify them to avoid issues with
+  // iterators and weak processing.
+  virtual void RegisterDelayedMarkNoTracing(const void* pointer) = 0;
 
-  // If the object calls this during the regular trace callback, then the
-  // WeakCallback argument may be called later, when the strong roots
-  // have all been found. The WeakCallback will normally use isAlive
-  // to find out whether some pointers are pointing to dying objects. When
-  // the WeakCallback is done the object must have purged all pointers
-  // to objects where isAlive returned false. In the weak callback it is not
-  // allowed to do anything that adds or extends the object graph (e.g.,
-  // allocate a new object, add a new reference revive a dead object etc.)
-  // Clearing out pointers to other heap objects is allowed, however. Note
-  // that even removing things from HeapHashSet or HeapHashMap can cause
-  // an allocation if the backing store resizes, but these collections know
-  // how to remove WeakMember elements safely.
-  inline void RegisterWeakCallback(void* closure, WeakCallback);
-
-  inline void RegisterWeakTable(const void* closure,
-                                EphemeronCallback iteration_callback,
-                                EphemeronCallback iteration_done_callback);
-
+  // Used to register ephemeron callbacks.
+  virtual void RegisterWeakTable(const void* closure,
+                                 EphemeronCallback iteration_callback,
+                                 EphemeronCallback iteration_done_callback) = 0;
 #if DCHECK_IS_ON()
-  inline bool WeakTableRegistered(const void* closure);
+  virtual bool WeakTableRegistered(const void* closure) = 0;
 #endif
 
-  inline bool EnsureMarked(const void* pointer);
-
-  inline void MarkNoTracing(const void* pointer) {
-    Mark(pointer, reinterpret_cast<TraceCallback>(0));
-  }
-
-  inline void MarkHeaderNoTracing(HeapObjectHeader*);
-
-  // Used to mark objects during conservative scanning.
-  inline void MarkHeader(HeapObjectHeader*,
-                         const void* object_pointer,
-                         TraceCallback);
-
-  inline void MarkHeader(HeapObjectHeader*, TraceCallback);
-
-  inline ThreadState* GetState() const { return state_; }
-  inline ThreadHeap& Heap() const { return GetState()->Heap(); }
-
-  inline MarkingMode GetMarkingMode() const { return marking_mode_; }
+  // |WeakCallback| will usually use |ObjectAliveTrait| to figure out liveness
+  // of any children of |closure|. Upon return from the callback all references
+  // to dead objects must have been purged. Any operation that extends the
+  // object graph, including allocation or reviving objects, is prohibited.
+  // Clearing out additional pointers is allowed. Note that removing elements
+  // from heap collections such as HeapHashSet can cause an allocation if the
+  // backing store requires resizing. These collections know how to deal with
+  // WeakMember elements though.
+  virtual void RegisterWeakCallback(void* closure, WeakCallback) = 0;
 
  private:
   template <typename T>
   static void HandleWeakCell(Visitor* self, void*);
 
+  ThreadState* const state_;
+};
+
+// Visitor used to mark Oilpan objects.
+class PLATFORM_EXPORT MarkingVisitor final : public Visitor {
+ public:
+  enum MarkingMode {
+    // This is a default visitor. This is used for GCType=GCWithSweep
+    // and GCType=GCWithoutSweep.
+    kGlobalMarking,
+    // This visitor just marks objects and ignores weak processing.
+    // This is used for GCType=TakeSnapshot.
+    kSnapshotMarking,
+    // This visitor is used to trace objects during weak processing.
+    // This visitor is allowed to trace only already marked objects.
+    kWeakProcessing,
+    // Perform global marking along with preparing for additional sweep
+    // compaction of heap arenas afterwards. Compared to the GlobalMarking
+    // visitor, this visitor will also register references to objects
+    // that might be moved during arena compaction -- the compaction
+    // pass will then fix up those references when the object move goes
+    // ahead.
+    kGlobalMarkingWithCompaction,
+  };
+
+  static std::unique_ptr<MarkingVisitor> Create(ThreadState*, MarkingMode);
+
+  MarkingVisitor(ThreadState*, MarkingMode);
+  virtual ~MarkingVisitor();
+
+  inline MarkingMode GetMarkingMode() const { return marking_mode_; }
+
+  // Marking implementation.
+
+  // This method marks an object and adds it to the set of objects that should
+  // have their trace method called. Since not all objects have vtables we have
+  // to have the callback as an explicit argument, but we can use the templated
+  // one-argument mark method above to automatically provide the callback
+  // function.
+  inline void Mark(const void* object_pointer, TraceCallback);
+
+  // Used to mark objects during conservative scanning.
+  inline void MarkHeader(HeapObjectHeader*, TraceCallback);
+  inline void MarkHeaderNoTracing(HeapObjectHeader*);
+
+  // Marks the header of an object. Is used for eagerly tracing of objects.
+  inline bool EnsureMarked(const void* pointer);
+
+  // Used for eagerly marking objects and for delayed marking of backing stores
+  // when the actual payload is processed differently, e.g., by weak handling.
+  inline void MarkNoTracing(const void* pointer) {
+    Mark(pointer, reinterpret_cast<TraceCallback>(0));
+  }
+
+  // Implementation of the visitor interface. See above for descriptions.
+
+  void Visit(void* object,
+             TraceCallback trace_callback,
+             TraceCallback mark_callback) final {
+    mark_callback(this, object);
+  }
+
+  void RegisterBackingStoreReference(void* slot) final;
+  void RegisterBackingStoreCallback(void* backing_store,
+                                    MovingObjectCallback,
+                                    void* callback_data) final;
+  void RegisterDelayedMarkNoTracing(const void* pointer) final;
+  void RegisterWeakTable(const void* closure,
+                         EphemeronCallback iteration_callback,
+                         EphemeronCallback iteration_done_callback) final;
+#if DCHECK_IS_ON()
+  bool WeakTableRegistered(const void* closure) final;
+#endif
+  void RegisterWeakCallback(void* closure, WeakCallback) final;
+
+ private:
   static void MarkNoTracingCallback(Visitor*, void*);
 
-  ThreadState* const state_;
   const MarkingMode marking_mode_;
 };
 
diff --git a/third_party/WebKit/Source/platform/heap/VisitorImpl.h b/third_party/WebKit/Source/platform/heap/VisitorImpl.h
index ec30d01..1a3f796 100644
--- a/third_party/WebKit/Source/platform/heap/VisitorImpl.h
+++ b/third_party/WebKit/Source/platform/heap/VisitorImpl.h
@@ -12,12 +12,9 @@
 
 namespace blink {
 
-inline void Visitor::MarkHeader(HeapObjectHeader* header,
-                                const void* object_pointer,
-                                TraceCallback callback) {
+inline void MarkingVisitor::MarkHeader(HeapObjectHeader* header,
+                                       TraceCallback callback) {
   DCHECK(header);
-  DCHECK(object_pointer);
-
   if (header->IsMarked())
     return;
 
@@ -25,6 +22,7 @@
          ThreadState::Current()->IsIncrementalMarking());
   DCHECK(GetMarkingMode() != kWeakProcessing);
 
+  const void* object_pointer = header->Payload();
   // A GC should only mark the objects that belong in its heap.
   DCHECK(&PageFromObject(object_pointer)->Arena()->GetThreadState()->Heap() ==
          &Heap());
@@ -35,29 +33,26 @@
     Heap().PushTraceCallback(const_cast<void*>(object_pointer), callback);
 }
 
-inline void Visitor::MarkHeader(HeapObjectHeader* header,
-                                TraceCallback callback) {
-  MarkHeader(header, header->Payload(), callback);
-}
-
-inline void Visitor::Mark(const void* object_pointer, TraceCallback callback) {
+inline void MarkingVisitor::Mark(const void* object_pointer,
+                                 TraceCallback callback) {
   if (!object_pointer)
     return;
   HeapObjectHeader* header = HeapObjectHeader::FromPayload(object_pointer);
-  MarkHeader(header, header->Payload(), callback);
+  MarkHeader(header, callback);
 }
 
-inline void Visitor::MarkHeaderNoTracing(HeapObjectHeader* header) {
-  MarkHeader(header, header->Payload(), reinterpret_cast<TraceCallback>(0));
+inline void MarkingVisitor::MarkHeaderNoTracing(HeapObjectHeader* header) {
+  MarkHeader(header, reinterpret_cast<TraceCallback>(0));
 }
 
-inline void Visitor::RegisterDelayedMarkNoTracing(const void* object_pointer) {
+inline void MarkingVisitor::RegisterDelayedMarkNoTracing(
+    const void* object_pointer) {
   DCHECK(GetMarkingMode() != kWeakProcessing);
   Heap().PushPostMarkingCallback(const_cast<void*>(object_pointer),
                                  &MarkNoTracingCallback);
 }
 
-inline void Visitor::RegisterWeakTable(
+inline void MarkingVisitor::RegisterWeakTable(
     const void* closure,
     EphemeronCallback iteration_callback,
     EphemeronCallback iteration_done_callback) {
@@ -67,12 +62,12 @@
 }
 
 #if DCHECK_IS_ON()
-inline bool Visitor::WeakTableRegistered(const void* closure) {
+inline bool MarkingVisitor::WeakTableRegistered(const void* closure) {
   return Heap().WeakTableRegistered(closure);
 }
 #endif
 
-inline bool Visitor::EnsureMarked(const void* object_pointer) {
+inline bool MarkingVisitor::EnsureMarked(const void* object_pointer) {
   if (!object_pointer)
     return false;
 
@@ -89,8 +84,8 @@
   return true;
 }
 
-inline void Visitor::RegisterWeakCallback(void* closure,
-                                          WeakCallback callback) {
+inline void MarkingVisitor::RegisterWeakCallback(void* closure,
+                                                 WeakCallback callback) {
   DCHECK(GetMarkingMode() != kWeakProcessing);
   // We don't want to run weak processings when taking a snapshot.
   if (GetMarkingMode() == kSnapshotMarking)
@@ -98,16 +93,17 @@
   Heap().PushWeakCallback(closure, callback);
 }
 
-inline void Visitor::RegisterBackingStoreReference(void* slot) {
+inline void MarkingVisitor::RegisterBackingStoreReference(void* slot) {
   if (GetMarkingMode() != kGlobalMarkingWithCompaction)
     return;
   Heap().RegisterMovingObjectReference(
       reinterpret_cast<MovableReference*>(slot));
 }
 
-inline void Visitor::RegisterBackingStoreCallback(void* backing_store,
-                                                  MovingObjectCallback callback,
-                                                  void* callback_data) {
+inline void MarkingVisitor::RegisterBackingStoreCallback(
+    void* backing_store,
+    MovingObjectCallback callback,
+    void* callback_data) {
   if (GetMarkingMode() != kGlobalMarkingWithCompaction)
     return;
   Heap().RegisterMovingObjectCallback(
diff --git a/third_party/WebKit/Source/platform/scheduler/base/lazy_now.cc b/third_party/WebKit/Source/platform/scheduler/base/lazy_now.cc
index b554a95e..7e8bc7b 100644
--- a/third_party/WebKit/Source/platform/scheduler/base/lazy_now.cc
+++ b/third_party/WebKit/Source/platform/scheduler/base/lazy_now.cc
@@ -5,7 +5,6 @@
 #include "platform/scheduler/base/lazy_now.h"
 
 #include "base/time/tick_clock.h"
-#include "platform/scheduler/base/task_queue_manager.h"
 
 namespace blink {
 namespace scheduler {
diff --git a/third_party/WebKit/Source/platform/scheduler/base/lazy_now.h b/third_party/WebKit/Source/platform/scheduler/base/lazy_now.h
index 2cb6d0b..ca3f5b4 100644
--- a/third_party/WebKit/Source/platform/scheduler/base/lazy_now.h
+++ b/third_party/WebKit/Source/platform/scheduler/base/lazy_now.h
@@ -25,6 +25,7 @@
 
   explicit LazyNow(base::TickClock* tick_clock) : tick_clock_(tick_clock) {}
 
+  // Result will not be updated on any subsesequent calls.
   base::TimeTicks Now();
 
  private:
diff --git a/third_party/WebKit/Source/platform/scheduler/base/task_queue.cc b/third_party/WebKit/Source/platform/scheduler/base/task_queue.cc
index 362f766..fe842885 100644
--- a/third_party/WebKit/Source/platform/scheduler/base/task_queue.cc
+++ b/third_party/WebKit/Source/platform/scheduler/base/task_queue.cc
@@ -73,28 +73,40 @@
 bool TaskQueue::PostDelayedTask(const base::Location& from_here,
                                 base::OnceClosure task,
                                 base::TimeDelta delay) {
-  auto lock = AcquireImplReadLockIfNeeded();
-  if (!impl_)
-    return false;
-  return impl_->PostDelayedTask(
-      PostedTask(std::move(task), from_here, delay, base::Nestable::kNestable));
+  internal::TaskQueueImpl::PostTaskResult result;
+  {
+    auto lock = AcquireImplReadLockIfNeeded();
+    if (!impl_)
+      return false;
+    result = impl_->PostDelayedTask(PostedTask(
+        std::move(task), from_here, delay, base::Nestable::kNestable));
+  }
+  return result.success;
 }
 
 bool TaskQueue::PostNonNestableDelayedTask(const base::Location& from_here,
                                            base::OnceClosure task,
                                            base::TimeDelta delay) {
-  auto lock = AcquireImplReadLockIfNeeded();
-  if (!impl_)
-    return false;
-  return impl_->PostDelayedTask(PostedTask(std::move(task), from_here, delay,
-                                           base::Nestable::kNonNestable));
+  internal::TaskQueueImpl::PostTaskResult result;
+  {
+    auto lock = AcquireImplReadLockIfNeeded();
+    if (!impl_)
+      return false;
+    result = impl_->PostDelayedTask(PostedTask(
+        std::move(task), from_here, delay, base::Nestable::kNonNestable));
+  }
+  return result.success;
 }
 
 bool TaskQueue::PostTaskWithMetadata(PostedTask task) {
-  auto lock = AcquireImplReadLockIfNeeded();
-  if (!impl_)
-    return false;
-  return impl_->PostDelayedTask(std::move(task));
+  internal::TaskQueueImpl::PostTaskResult result;
+  {
+    auto lock = AcquireImplReadLockIfNeeded();
+    if (!impl_)
+      return false;
+    result = impl_->PostDelayedTask(std::move(task));
+  }
+  return result.success;
 }
 
 std::unique_ptr<TaskQueue::QueueEnabledVoter>
diff --git a/third_party/WebKit/Source/platform/scheduler/base/task_queue_impl.cc b/third_party/WebKit/Source/platform/scheduler/base/task_queue_impl.cc
index 5be2ec8..8df55f5 100644
--- a/third_party/WebKit/Source/platform/scheduler/base/task_queue_impl.cc
+++ b/third_party/WebKit/Source/platform/scheduler/base/task_queue_impl.cc
@@ -64,6 +64,23 @@
 #endif
 }
 
+TaskQueueImpl::PostTaskResult::PostTaskResult()
+    : task(base::OnceClosure(), base::Location()) {}
+
+TaskQueueImpl::PostTaskResult::PostTaskResult(bool success,
+                                              TaskQueue::PostedTask task)
+    : success(success), task(std::move(task)) {}
+
+TaskQueueImpl::PostTaskResult TaskQueueImpl::PostTaskResult::Success() {
+  return PostTaskResult(
+      true, TaskQueue::PostedTask(base::OnceClosure(), base::Location()));
+}
+
+TaskQueueImpl::PostTaskResult TaskQueueImpl::PostTaskResult::Fail(
+    TaskQueue::PostedTask task) {
+  return PostTaskResult(false, std::move(task));
+}
+
 TaskQueueImpl::Task::Task(TaskQueue::PostedTask task,
                           base::TimeTicks desired_run_time,
                           EnqueueOrder sequence_number)
@@ -169,20 +186,22 @@
   return base::PlatformThread::CurrentId() == thread_id_;
 }
 
-bool TaskQueueImpl::PostDelayedTask(TaskQueue::PostedTask task) {
+TaskQueueImpl::PostTaskResult TaskQueueImpl::PostDelayedTask(
+    TaskQueue::PostedTask task) {
   if (task.delay.is_zero())
     return PostImmediateTaskImpl(std::move(task));
 
   return PostDelayedTaskImpl(std::move(task));
 }
 
-bool TaskQueueImpl::PostImmediateTaskImpl(TaskQueue::PostedTask task) {
+TaskQueueImpl::PostTaskResult TaskQueueImpl::PostImmediateTaskImpl(
+    TaskQueue::PostedTask task) {
   // Use CHECK instead of DCHECK to crash earlier. See http://crbug.com/711167
   // for details.
   CHECK(task.callback);
   base::AutoLock lock(any_thread_lock_);
   if (!any_thread().task_queue_manager)
-    return false;
+    return PostTaskResult::Fail(std::move(task));
 
   EnqueueOrder sequence_number =
       any_thread().task_queue_manager->GetNextSequenceNumber();
@@ -190,10 +209,11 @@
   PushOntoImmediateIncomingQueueLocked(Task(std::move(task),
                                             any_thread().time_domain->Now(),
                                             sequence_number, sequence_number));
-  return true;
+  return PostTaskResult::Success();
 }
 
-bool TaskQueueImpl::PostDelayedTaskImpl(TaskQueue::PostedTask task) {
+TaskQueueImpl::PostTaskResult TaskQueueImpl::PostDelayedTaskImpl(
+    TaskQueue::PostedTask task) {
   // Use CHECK instead of DCHECK to crash earlier. See http://crbug.com/711167
   // for details.
   CHECK(task.callback);
@@ -201,7 +221,7 @@
   if (base::PlatformThread::CurrentId() == thread_id_) {
     // Lock-free fast path for delayed tasks posted from the main thread.
     if (!main_thread_only().task_queue_manager)
-      return false;
+      return PostTaskResult::Fail(std::move(task));
 
     EnqueueOrder sequence_number =
         main_thread_only().task_queue_manager->GetNextSequenceNumber();
@@ -218,7 +238,7 @@
     // assumption prove to be false in future, we may need to revisit this.
     base::AutoLock lock(any_thread_lock_);
     if (!any_thread().task_queue_manager)
-      return false;
+      return PostTaskResult::Fail(std::move(task));
 
     EnqueueOrder sequence_number =
         any_thread().task_queue_manager->GetNextSequenceNumber();
@@ -228,7 +248,7 @@
     PushOntoDelayedIncomingQueueLocked(
         Task(std::move(task), time_domain_delayed_run_time, sequence_number));
   }
-  return true;
+  return PostTaskResult::Success();
 }
 
 void TaskQueueImpl::PushOntoDelayedIncomingQueueFromMainThread(
diff --git a/third_party/WebKit/Source/platform/scheduler/base/task_queue_impl.h b/third_party/WebKit/Source/platform/scheduler/base/task_queue_impl.h
index 3a1ef6e5..2045f463 100644
--- a/third_party/WebKit/Source/platform/scheduler/base/task_queue_impl.h
+++ b/third_party/WebKit/Source/platform/scheduler/base/task_queue_impl.h
@@ -131,6 +131,19 @@
     EnqueueOrder enqueue_order_;
   };
 
+  // A result retuned by PostDelayedTask. When scheduler failed to post a task
+  // due to being shutdown a task is returned to be destroyed outside the lock.
+  struct PostTaskResult {
+    PostTaskResult();
+    PostTaskResult(bool success, TaskQueue::PostedTask task);
+
+    static PostTaskResult Success();
+    static PostTaskResult Fail(TaskQueue::PostedTask task);
+
+    bool success = false;
+    TaskQueue::PostedTask task;
+  };
+
   using OnNextWakeUpChangedCallback = base::Callback<void(base::TimeTicks)>;
   using OnTaskStartedHandler =
       base::RepeatingCallback<void(const TaskQueue::Task&, base::TimeTicks)>;
@@ -143,7 +156,7 @@
   // TaskQueue implementation.
   const char* GetName() const;
   bool RunsTasksInCurrentSequence() const;
-  bool PostDelayedTask(TaskQueue::PostedTask task);
+  PostTaskResult PostDelayedTask(TaskQueue::PostedTask task);
   // Require a reference to enclosing task queue for lifetime control.
   std::unique_ptr<TaskQueue::QueueEnabledVoter> CreateQueueEnabledVoter(
       scoped_refptr<TaskQueue> owning_task_queue);
@@ -331,8 +344,8 @@
     bool is_enabled_for_test;
   };
 
-  bool PostImmediateTaskImpl(TaskQueue::PostedTask task);
-  bool PostDelayedTaskImpl(TaskQueue::PostedTask task);
+  PostTaskResult PostImmediateTaskImpl(TaskQueue::PostedTask task);
+  PostTaskResult PostDelayedTaskImpl(TaskQueue::PostedTask task);
 
   // Push the task onto the |delayed_incoming_queue|. Lock-free main thread
   // only fast path.
diff --git a/third_party/WebKit/Source/platform/scheduler/base/task_queue_manager.h b/third_party/WebKit/Source/platform/scheduler/base/task_queue_manager.h
index 56cf5da..a15782c 100644
--- a/third_party/WebKit/Source/platform/scheduler/base/task_queue_manager.h
+++ b/third_party/WebKit/Source/platform/scheduler/base/task_queue_manager.h
@@ -199,7 +199,6 @@
   explicit TaskQueueManager(
       std::unique_ptr<internal::ThreadController> controller);
 
-  friend class LazyNow;
   friend class internal::TaskQueueImpl;
   friend class task_queue_manager_unittest::TaskQueueManagerTest;
 
diff --git a/third_party/WebKit/Source/platform/scheduler/base/task_queue_manager_unittest.cc b/third_party/WebKit/Source/platform/scheduler/base/task_queue_manager_unittest.cc
index 7935fd6f..21324ff 100644
--- a/third_party/WebKit/Source/platform/scheduler/base/task_queue_manager_unittest.cc
+++ b/third_party/WebKit/Source/platform/scheduler/base/task_queue_manager_unittest.cc
@@ -3391,6 +3391,61 @@
   thread->Stop();
 }
 
+namespace {
+
+void DoNothing() {}
+
+class PostTaskInDestructor {
+ public:
+  explicit PostTaskInDestructor(scoped_refptr<TaskQueue> task_queue)
+      : task_queue_(task_queue) {}
+
+  ~PostTaskInDestructor() {
+    task_queue_->PostTask(FROM_HERE, base::BindOnce(&DoNothing));
+  }
+
+  void Do() {}
+
+ private:
+  scoped_refptr<TaskQueue> task_queue_;
+};
+
+}  // namespace
+
+TEST_F(TaskQueueManagerTest, TaskQueueUsedInTaskDestructorAfterShutdown) {
+  // This test checks that when a task is posted to a shutdown queue and
+  // destroyed, it can try to post a task to the same queue without deadlocks.
+  Initialize(0u);
+  test_task_runner_->SetAutoAdvanceNowToPendingTasks(true);
+
+  scoped_refptr<TestTaskQueue> main_tq = CreateTaskQueue();
+
+  base::WaitableEvent test_executed(
+      base::WaitableEvent::ResetPolicy::MANUAL,
+      base::WaitableEvent::InitialState::NOT_SIGNALED);
+  std::unique_ptr<base::Thread> thread =
+      std::make_unique<base::Thread>("test thread");
+  thread->StartAndWaitForTesting();
+
+  manager_.reset();
+
+  thread->task_runner()->PostTask(
+      FROM_HERE,
+      base::BindOnce(
+          [](scoped_refptr<base::SingleThreadTaskRunner> task_queue,
+             std::unique_ptr<PostTaskInDestructor> test_object,
+             base::WaitableEvent* test_executed) {
+            task_queue->PostTask(
+                FROM_HERE,
+                base::BindOnce(&PostTaskInDestructor::Do,
+                               base::Passed(std::move(test_object))));
+            test_executed->Signal();
+          },
+          main_tq, std::make_unique<PostTaskInDestructor>(main_tq),
+          &test_executed));
+  test_executed.Wait();
+}
+
 }  // namespace task_queue_manager_unittest
 }  // namespace scheduler
 }  // namespace blink
diff --git a/third_party/WebKit/Source/platform/text/HyphenationTest.cpp b/third_party/WebKit/Source/platform/text/HyphenationTest.cpp
index 89d80df..3d9d3b1 100644
--- a/third_party/WebKit/Source/platform/text/HyphenationTest.cpp
+++ b/third_party/WebKit/Source/platform/text/HyphenationTest.cpp
@@ -10,6 +10,7 @@
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
+using testing::ElementsAre;
 using testing::ElementsAreArray;
 
 #if defined(OS_ANDROID)
@@ -107,6 +108,36 @@
   EXPECT_THAT(actual, ElementsAreArray(locations));
 }
 
+TEST_F(HyphenationTest, LeadingSpaces) {
+  scoped_refptr<Hyphenation> hyphenation = GetHyphenation("en-us");
+#if defined(OS_ANDROID)
+  // Hyphenation is available only for Android M MR1 or later.
+  if (!hyphenation)
+    return;
+#endif
+  ASSERT_TRUE(hyphenation) << "Cannot find the hyphenation for en-us";
+
+  String leading_space(" principle");
+  EXPECT_THAT(hyphenation->HyphenLocations(leading_space), ElementsAre(7, 5));
+  EXPECT_EQ(5u, hyphenation->LastHyphenLocation(leading_space, 6));
+
+  String multi_leading_spaces("   principle");
+  EXPECT_THAT(hyphenation->HyphenLocations(multi_leading_spaces),
+              ElementsAre(9, 7));
+  EXPECT_EQ(7u, hyphenation->LastHyphenLocation(multi_leading_spaces, 8));
+
+  // Line breaker is not supposed to pass only spaces, no locations.
+  String only_spaces("   ");
+  EXPECT_THAT(hyphenation->HyphenLocations(only_spaces), ElementsAre());
+  EXPECT_EQ(0u, hyphenation->LastHyphenLocation(only_spaces, 3));
+
+  // Line breaker is not supposed to pass with trailing spaces.
+  String trailing_space("principle ");
+  EXPECT_THAT(hyphenation->HyphenLocations(trailing_space),
+              testing::AnyOf(ElementsAre(), ElementsAre(6, 4)));
+  EXPECT_EQ(0u, hyphenation->LastHyphenLocation(trailing_space, 10));
+}
+
 TEST_F(HyphenationTest, English) {
   scoped_refptr<Hyphenation> hyphenation = GetHyphenation("en-us");
 #if defined(OS_ANDROID)
diff --git a/third_party/WebKit/Source/platform/text/hyphenation/HyphenationMinikin.cpp b/third_party/WebKit/Source/platform/text/hyphenation/HyphenationMinikin.cpp
index 6e028ff..ccc04351 100644
--- a/third_party/WebKit/Source/platform/text/hyphenation/HyphenationMinikin.cpp
+++ b/third_party/WebKit/Source/platform/text/hyphenation/HyphenationMinikin.cpp
@@ -9,6 +9,7 @@
 #include "base/metrics/histogram_macros.h"
 #include "base/timer/elapsed_timer.h"
 #include "platform/LayoutLocale.h"
+#include "platform/text/Character.h"
 #include "platform/text/hyphenation/HyphenatorAOSP.h"
 #include "public/platform/InterfaceProvider.h"
 #include "public/platform/Platform.h"
@@ -16,6 +17,32 @@
 
 namespace blink {
 
+namespace {
+
+template <typename CharType>
+StringView SkipLeadingSpaces(const CharType* text,
+                             unsigned length,
+                             unsigned* num_leading_spaces_out) {
+  const CharType* begin = text;
+  const CharType* end = text + length;
+  while (text != end && Character::TreatAsSpace(*text))
+    text++;
+  *num_leading_spaces_out = text - begin;
+  return StringView(text, end - text);
+}
+
+StringView SkipLeadingSpaces(const StringView& text,
+                             unsigned* num_leading_spaces_out) {
+  if (text.Is8Bit()) {
+    return SkipLeadingSpaces(text.Characters8(), text.length(),
+                             num_leading_spaces_out);
+  }
+  return SkipLeadingSpaces(text.Characters16(), text.length(),
+                           num_leading_spaces_out);
+}
+
+}  // namespace
+
 using Hyphenator = android::Hyphenator;
 
 static mojom::blink::HyphenationPtr ConnectToRemoteService() {
@@ -70,36 +97,44 @@
 
 size_t HyphenationMinikin::LastHyphenLocation(const StringView& text,
                                               size_t before_index) const {
-  if (text.length() < kMinimumPrefixLength + kMinimumSuffixLength ||
+  unsigned num_leading_spaces;
+  StringView word = SkipLeadingSpaces(text, &num_leading_spaces);
+  if (before_index <= num_leading_spaces)
+    return 0;
+  before_index = std::min<size_t>(before_index - num_leading_spaces,
+                                  word.length() - kMinimumSuffixLength);
+
+  if (word.length() < kMinimumPrefixLength + kMinimumSuffixLength ||
       before_index <= kMinimumPrefixLength)
     return 0;
 
-  std::vector<uint8_t> result = Hyphenate(text);
-  before_index =
-      std::min<size_t>(before_index, text.length() - kMinimumSuffixLength);
+  std::vector<uint8_t> result = Hyphenate(word);
   CHECK_LE(before_index, result.size());
   CHECK_GE(before_index, 1u);
   static_assert(kMinimumPrefixLength >= 1, "|beforeIndex - 1| can underflow");
   for (size_t i = before_index - 1; i >= kMinimumPrefixLength; i--) {
     if (result[i])
-      return i;
+      return i + num_leading_spaces;
   }
   return 0;
 }
 
 Vector<size_t, 8> HyphenationMinikin::HyphenLocations(
     const StringView& text) const {
+  unsigned num_leading_spaces;
+  StringView word = SkipLeadingSpaces(text, &num_leading_spaces);
+
   Vector<size_t, 8> hyphen_locations;
-  if (text.length() < kMinimumPrefixLength + kMinimumSuffixLength)
+  if (word.length() < kMinimumPrefixLength + kMinimumSuffixLength)
     return hyphen_locations;
 
-  std::vector<uint8_t> result = Hyphenate(text);
+  std::vector<uint8_t> result = Hyphenate(word);
   static_assert(kMinimumPrefixLength >= 1,
                 "Change the 'if' above if this fails");
-  for (size_t i = text.length() - kMinimumSuffixLength - 1;
+  for (size_t i = word.length() - kMinimumSuffixLength - 1;
        i >= kMinimumPrefixLength; i--) {
     if (result[i])
-      hyphen_locations.push_back(i);
+      hyphen_locations.push_back(i + num_leading_spaces);
   }
   return hyphen_locations;
 }
diff --git a/third_party/WebKit/common/feature_policy/feature_policy.cc b/third_party/WebKit/common/feature_policy/feature_policy.cc
index 6093208..c7c54bd 100644
--- a/third_party/WebKit/common/feature_policy/feature_policy.cc
+++ b/third_party/WebKit/common/feature_policy/feature_policy.cc
@@ -283,7 +283,7 @@
                            {mojom::FeaturePolicyFeature::kUnsizedMedia,
                             FeaturePolicy::FeatureDefault::EnableForAll},
                            {mojom::FeaturePolicyFeature::kPictureInPicture,
-                            FeaturePolicy::FeatureDefault::EnableForSelf}}));
+                            FeaturePolicy::FeatureDefault::EnableForAll}}));
   return default_feature_list;
 }
 
diff --git a/third_party/libovr/BUILD.gn b/third_party/libovr/BUILD.gn
index bec8d4f1..901bf6e8 100644
--- a/third_party/libovr/BUILD.gn
+++ b/third_party/libovr/BUILD.gn
@@ -3,7 +3,8 @@
 # found in the LICENSE file.
 
 config("libovr-config") {
-  cflags = [ "-Wno-unused-function" ]
+  if (is_clang)
+    cflags = [ "-Wno-unused-function" ]
 }
 
 static_library("libovr") {
diff --git a/third_party/protobuf/README.chromium b/third_party/protobuf/README.chromium
index a50aa9c9..8d42ca7 100644
--- a/third_party/protobuf/README.chromium
+++ b/third_party/protobuf/README.chromium
@@ -114,3 +114,7 @@
 - 0018-fallthrough.patch
 
   Cherry-picks upstream https://github.com/google/protobuf/commit/b8e47830d
+
+- 0019-rename-a-shadowed-variable.patch
+
+  Cherry-picks upstream https://github.com/google/protobuf/commit/af3813cd7
diff --git a/third_party/protobuf/patches/0019-rename-a-shadowed-variable.patch b/third_party/protobuf/patches/0019-rename-a-shadowed-variable.patch
new file mode 100644
index 0000000..d400db33
--- /dev/null
+++ b/third_party/protobuf/patches/0019-rename-a-shadowed-variable.patch
@@ -0,0 +1,31 @@
+From af3813cd7337c622df067914cfa22732c08d6067 Mon Sep 17 00:00:00 2001
+From: Dave Tapuska <dtapuska@chromium.org>
+Date: Tue, 20 Feb 2018 17:16:33 -0500
+Subject: [PATCH 2/2] Rename a shadowed variable.
+
+Shadowed variables can cause readability issues. Ensure a shadowed
+variable isn't used in header files which may be used in a dependent
+project that explicitly disables them.
+---
+ src/google/protobuf/map_entry_lite.h | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/src/google/protobuf/map_entry_lite.h b/src/google/protobuf/map_entry_lite.h
+index dc6ec917..bbfb9c15 100644
+--- a/src/google/protobuf/map_entry_lite.h
++++ b/src/google/protobuf/map_entry_lite.h
+@@ -354,9 +354,9 @@ class MapEntryImpl : public Base {
+         // We could use memcmp here, but we don't bother. The tag is one byte.
+         GOOGLE_COMPILE_ASSERT(kTagSize == 1, tag_size_error);
+         if (size > 0 && *reinterpret_cast<const char*>(data) == kValueTag) {
+-          typename Map::size_type size = map_->size();
++          typename Map::size_type map_size = map_->size();
+           value_ptr_ = &(*map_)[key_];
+-          if (GOOGLE_PREDICT_TRUE(size != map_->size())) {
++          if (GOOGLE_PREDICT_TRUE(map_size != map_->size())) {
+             // We created a new key-value pair.  Fill in the value.
+             typedef
+                 typename MapIf<ValueTypeHandler::kIsEnum, int*, Value*>::type T;
+-- 
+2.16.1.291.g4437f3f132-goog
+
diff --git a/third_party/protobuf/src/google/protobuf/map_entry_lite.h b/third_party/protobuf/src/google/protobuf/map_entry_lite.h
index b0307a6..634c8ac2 100644
--- a/third_party/protobuf/src/google/protobuf/map_entry_lite.h
+++ b/third_party/protobuf/src/google/protobuf/map_entry_lite.h
@@ -359,9 +359,9 @@
         // We could use memcmp here, but we don't bother. The tag is one byte.
         GOOGLE_COMPILE_ASSERT(kTagSize == 1, tag_size_error);
         if (size > 0 && *reinterpret_cast<const char*>(data) == kValueTag) {
-          typename Map::size_type size = map_->size();
+          typename Map::size_type map_size = map_->size();
           value_ptr_ = &(*map_)[key_];
-          if (GOOGLE_PREDICT_TRUE(size != map_->size())) {
+          if (GOOGLE_PREDICT_TRUE(map_size != map_->size())) {
             // We created a new key-value pair.  Fill in the value.
             typedef
                 typename MapIf<ValueTypeHandler::kIsEnum, int*, Value*>::type T;
diff --git a/tools/clang/scripts/upload_revision.py b/tools/clang/scripts/upload_revision.py
index 44c6e99d..8eb4eb3 100755
--- a/tools/clang/scripts/upload_revision.py
+++ b/tools/clang/scripts/upload_revision.py
@@ -73,15 +73,9 @@
       clang_old_revision, clang_revision, commit_message)])
 
   Git(["cl", "upload", "-f"])
-  Git(["cl", "try", "-m", "tryserver.chromium.linux",
-                    "-b", "linux_upload_clang",
-                    "-r", git_revision])
-  Git(["cl", "try", "-m", "tryserver.chromium.mac",
-                    "-b", "mac_upload_clang",
-                    "-r", git_revision])
-  Git(["cl", "try", "-m", "tryserver.chromium.win",
-                    "-b", "win_upload_clang",
-                    "-r", git_revision])
+  Git(["cl", "try", "-b", "linux_upload_clang", "-r", git_revision])
+  Git(["cl", "try", "-b", "mac_upload_clang", "-r", git_revision])
+  Git(["cl", "try", "-b", "win_upload_clang", "-r", git_revision])
 
   print ("Please, wait until the try bots succeeded "
          "and then push the binaries to goma.")
diff --git a/tools/mb/mb_config.pyl b/tools/mb/mb_config.pyl
index f7aa55e0..0827264 100644
--- a/tools/mb/mb_config.pyl
+++ b/tools/mb/mb_config.pyl
@@ -306,6 +306,7 @@
       'GPU FYI Win x64 dEQP Builder': 'deqp_release_no_clang_trybot',
       'Linux FYI GPU TSAN Release': 'gpu_fyi_tests_release_trybot_tsan',
       'Mac FYI GPU ASAN Release': 'gpu_fyi_tests_release_trybot_asan',
+      'Optional Android Release (Nexus 5X)': 'gpu_tests_android_release_trybot_arm64',
     },
 
     'chromium.infra.codesearch': {
diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml
index b904e8c..2a80737 100644
--- a/tools/metrics/histograms/histograms.xml
+++ b/tools/metrics/histograms/histograms.xml
@@ -26818,6 +26818,16 @@
   </summary>
 </histogram>
 
+<histogram name="GCM.Crypto.GCMDatabaseUpgradeResult" enum="Boolean">
+  <owner>nator@chromium.org</owner>
+  <summary>
+    Result of upgrading GCM Key Store Database from deprecated format to current
+    format. We upgrade the GCM Key store when it first initialized, if it
+    contains any EncryptionData object with a KeyPair in it, and then record
+    whether the upgrade was successful in this metric.
+  </summary>
+</histogram>
+
 <histogram name="GCM.Crypto.GetKeySuccessRate" enum="BooleanSuccess">
   <owner>peter@chromium.org</owner>
   <summary>
@@ -33582,6 +33592,14 @@
   </summary>
 </histogram>
 
+<histogram name="Media.Audio.Capture.StreamCallbackError" enum="BooleanError">
+  <owner>maxmorin@chromium.org</owner>
+  <summary>
+    When AudioInputDevice is stopped, this stat is recorded with whether an
+    error callback was ever received over IPC.
+  </summary>
+</histogram>
+
 <histogram name="Media.Audio.Capture.VirtualCallbackError" enum="BooleanError">
   <owner>maxmorin@chromium.org</owner>
   <summary>
@@ -34006,6 +34024,14 @@
   </summary>
 </histogram>
 
+<histogram name="Media.Audio.Render.StreamCallbackError" enum="BooleanError">
+  <owner>maxmorin@chromium.org</owner>
+  <summary>
+    When AudioOutputDevice is stopped, this stat is recorded with whether an
+    error callback was ever received over IPC.
+  </summary>
+</histogram>
+
 <histogram name="Media.Audio.RenderFailsWhenBufferSizeChangesMac"
     enum="BooleanChanged">
   <owner>henrika@chromium.org</owner>
@@ -88966,6 +88992,9 @@
 </histogram>
 
 <histogram name="Sync.PageRevisitBookmarksDuration" units="ms">
+  <obsolete>
+    Deprecated in M66.
+  </obsolete>
   <owner>skym@chromium.org</owner>
   <summary>
     The client side execution time to check for revisits with bookmarks data.
@@ -88973,6 +89002,9 @@
 </histogram>
 
 <histogram name="Sync.PageRevisitBookmarksMatchAge" units="minutes">
+  <obsolete>
+    Deprecated in M66.
+  </obsolete>
   <owner>skym@chromium.org</owner>
   <summary>
     Age of bookmark that matches a navigation event, where matching means the
@@ -88982,17 +89014,26 @@
 
 <histogram name="Sync.PageRevisitBookmarksMatchTransition"
     enum="PageVisitTransitionType">
+  <obsolete>
+    Deprecated in M66.
+  </obsolete>
   <owner>skym@chromium.org</owner>
   <summary>Transition type to a page that matched a bookmark.</summary>
 </histogram>
 
 <histogram name="Sync.PageRevisitBookmarksMissTransition"
     enum="PageVisitTransitionType">
+  <obsolete>
+    Deprecated in M66.
+  </obsolete>
   <owner>skym@chromium.org</owner>
   <summary>Transition type to a page that didn't match a bookmark.</summary>
 </histogram>
 
 <histogram name="Sync.PageRevisitNavigationMatchAge" units="minutes">
+  <obsolete>
+    Deprecated in M66.
+  </obsolete>
   <owner>skym@chromium.org</owner>
   <summary>
     Difference in time between finding the match and the creation of the most
@@ -89002,6 +89043,9 @@
 </histogram>
 
 <histogram name="Sync.PageRevisitNavigationMatchOffset">
+  <obsolete>
+    Deprecated in M66.
+  </obsolete>
   <owner>skym@chromium.org</owner>
   <summary>
     The number of navigations forward or backwards the matching noncurrent
@@ -89013,17 +89057,26 @@
 
 <histogram name="Sync.PageRevisitNavigationMatchTransition"
     enum="PageVisitTransitionType">
+  <obsolete>
+    Deprecated in M66.
+  </obsolete>
   <owner>skym@chromium.org</owner>
   <summary>Transition type that matched a synced navigation.</summary>
 </histogram>
 
 <histogram name="Sync.PageRevisitNavigationMissTransition"
     enum="PageVisitTransitionType">
+  <obsolete>
+    Deprecated in M66.
+  </obsolete>
   <owner>skym@chromium.org</owner>
   <summary>Transition type that didn't match a synced navigation.</summary>
 </histogram>
 
 <histogram name="Sync.PageRevisitSessionDuration" units="ms">
+  <obsolete>
+    Deprecated in M66.
+  </obsolete>
   <owner>skym@chromium.org</owner>
   <summary>
     The client side execution time to check for revisits with session data.
@@ -89031,6 +89084,9 @@
 </histogram>
 
 <histogram name="Sync.PageRevisitTabMatchAge" units="minutes">
+  <obsolete>
+    Deprecated in M66.
+  </obsolete>
   <owner>skym@chromium.org</owner>
   <summary>
     Difference in time between finding the match and the creation of the most
@@ -89040,17 +89096,26 @@
 
 <histogram name="Sync.PageRevisitTabMatchTransition"
     enum="PageVisitTransitionType">
+  <obsolete>
+    Deprecated in M66.
+  </obsolete>
   <owner>skym@chromium.org</owner>
   <summary>Transition type that matched a synced tab.</summary>
 </histogram>
 
 <histogram name="Sync.PageRevisitTabMissTransition"
     enum="PageVisitTransitionType">
+  <obsolete>
+    Deprecated in M66.
+  </obsolete>
   <owner>skym@chromium.org</owner>
   <summary>Transition type that didn't match a synced tab.</summary>
 </histogram>
 
 <histogram name="Sync.PageRevisitTypedUrlDuration" units="ms">
+  <obsolete>
+    Deprecated in M66.
+  </obsolete>
   <owner>skym@chromium.org</owner>
   <summary>
     The client side execution time to check for revisits with typed URL data.
@@ -89058,6 +89123,9 @@
 </histogram>
 
 <histogram name="Sync.PageRevisitTypedUrlMatchAge" units="minutes">
+  <obsolete>
+    Deprecated in M66.
+  </obsolete>
   <owner>skym@chromium.org</owner>
   <summary>
     Difference in time between finding the match and the last time this URL was
@@ -89067,12 +89135,18 @@
 
 <histogram name="Sync.PageRevisitTypedUrlMatchTransition"
     enum="PageVisitTransitionType">
+  <obsolete>
+    Deprecated in M66.
+  </obsolete>
   <owner>skym@chromium.org</owner>
   <summary>Transition type that matched a typed URL.</summary>
 </histogram>
 
 <histogram name="Sync.PageRevisitTypedUrlMissTransition"
     enum="PageVisitTransitionType">
+  <obsolete>
+    Deprecated in M66.
+  </obsolete>
   <owner>skym@chromium.org</owner>
   <summary>Transition type that didn't match a typed URL.</summary>
 </histogram>
diff --git a/tools/perf/expectations.config b/tools/perf/expectations.config
index cb4bd46..5dc18ee 100644
--- a/tools/perf/expectations.config
+++ b/tools/perf/expectations.config
@@ -295,63 +295,65 @@
 crbug.com/773084 [ Mac ] v8.browsing_desktop/browse:tools:maps [ Skip ]
 crbug.com/788796 [ Linux ] v8.browsing_desktop/browse:media:imgur [ Skip ]
 crbug.com/806001 [ Linux ] v8.browsing_desktop/browse:media:tumblr [ Skip ]
-#crbug.com/676336 [ Win ] v8.browsing_desktop/browse:news:hackernews [ Skip ]
+crbug.com/676336 [ Win ] v8.browsing_desktop/browse:news:hackernews [ Skip ]
 crbug.com/676336 [ Mac ] v8.browsing_desktop/browse:news:hackernews [ Skip ]
 [ Mac ] v8.browsing_desktop/browse:news:cnn [ Skip ]
 crbug.com/798465 [ Mac ] v8.browsing_desktop/browse:news:flipboard [ Skip ]
 crbug.com/798465 [ Win ] v8.browsing_desktop/browse:news:flipboard [ Skip ]
 crbug.com/813165 [ Win ] v8.browsing_desktop/browse:media:flickr_infinite_scroll [ Skip ]
+crbug.com/805934 [ Mac_10.12 ] v8.browsing_desktop/browse:tech:discourse_infinite_scroll [ Skip ]
 
 # Benchmark: v8.browsing_desktop-future
 crbug.com/773084 [ Mac ] v8.browsing_desktop-future/browse:tools:maps [ Skip ]
 crbug.com/788796 [ Linux ] v8.browsing_desktop-future/browse:media:imgur [ Skip ]
 crbug.com/806001 [ Linux ] v8.browsing_desktop-future/browse:media:tumblr [ Skip ]
-crbug.com/676336 [ Win ] v8.browsing_desktop-future/browse:media:flickr_infinite_scroll [ Skip ]
 crbug.com/676336 [ Win ] v8.browsing_desktop-future/browse:news:hackernews [ Skip ]
 crbug.com/676336 [ Mac ] v8.browsing_desktop-future/browse:news:hackernews [ Skip ]
 crbug.com/728576 [ Mac ] v8.browsing_desktop-future/browse:news:cnn [ Skip ]
 crbug.com/798465 [ Mac ] v8.browsing_desktop-future/browse:news:flipboard [ Skip ]
 crbug.com/798465 [ Win ] v8.browsing_desktop-future/browse:news:flipboard [ Skip ]
+crbug.com/676336 [ Win ] v8.browsing_desktop-future/browse:media:flickr_infinite_scroll [ Skip ]
 crbug.com/805934 [ Mac_10.12 ] v8.browsing_desktop-future/browse:tech:discourse_infinite_scroll [ Skip ]
 
 # Benchmark: v8.browsing_mobile
-crbug.com/788797 [ Cherry_Mobile_Android_One ] v8.browsing_mobile/browse:social:facebook_infinite_scroll [ Skip ]
-crbug.com/788797 [ Cherry_Mobile_Android_One ] v8.browsing_mobile/browse:social:pinterest_infinite_scroll [ Skip ]
-crbug.com/768472 [ Cherry_Mobile_Android_One ] v8.browsing_mobile/browse:shopping:lazada [ Skip ]
 crbug.com/714650 [ Android ] v8.browsing_mobile/browse:news:globo [ Skip ]
-crbug.com/767970 [ Cherry_Mobile_Android_One ] v8.browsing_mobile/browse:tech:discourse_infinite_scroll [ Skip ]
-crbug.com/767970 [ Cherry_Mobile_Android_One ] v8.browsing_mobile/browse:shopping:avito [ Skip ]
-[ Android_Webview ] v8.browsing_mobile/browse:chrome:omnibox [ Skip ]
 crbug.com/728081 [ Android ] v8.browsing_mobile/browse:news:toi [ Skip ]
-crbug.com/767970 [ Cherry_Mobile_Android_One ] v8.browsing_mobile/browse:news:cnn [ Skip ]
 crbug.com/767970 [ Mobile ] v8.browsing_mobile/browse:shopping:flipkart [ Skip ]
 crbug.com/708300 [ Mobile ] v8.browsing_mobile/browse:shopping:flipkart [ Skip ]
+crbug.com/788797 [ Cherry_Mobile_Android_One ] v8.browsing_mobile/browse:social:facebook_infinite_scroll [ Skip ]
+crbug.com/788797 [ Cherry_Mobile_Android_One ] v8.browsing_mobile/browse:social:pinterest_infinite_scroll [ Skip ]
+crbug.com/803870 [ Cherry_Mobile_Android_One ] v8.browsing_mobile/browse:social:tumblr_infinite_scroll [ Skip ]
+crbug.com/767970 [ Cherry_Mobile_Android_One ] v8.browsing_mobile/browse:tech:discourse_infinite_scroll [ Skip ]
+crbug.com/768472 [ Cherry_Mobile_Android_One ] v8.browsing_mobile/browse:shopping:lazada [ Skip ]
+crbug.com/767970 [ Cherry_Mobile_Android_One ] v8.browsing_mobile/browse:shopping:avito [ Skip ]
+crbug.com/803870 [ Cherry_Mobile_Android_One ] v8.browsing_mobile/browse:media:youtube [ Skip ]
+crbug.com/767970 [ Cherry_Mobile_Android_One ] v8.browsing_mobile/browse:news:cnn [ Skip ]
+[ Android_Webview ] v8.browsing_mobile/browse:chrome:omnibox [ Skip ]
 [ Android_Webview ] v8.browsing_mobile/browse:chrome:newtab [ Skip ]
 crbug.com/803465 [ Nexus_5 ] v8.browsing_mobile/browse:chrome:newtab [ Skip ]
-crbug.com/803870 [ Cherry_Mobile_Android_One ] v8.browsing_mobile/browse:social:tumblr_infinite_scroll [ Skip ]
-crbug.com/803870 [ Cherry_Mobile_Android_One ] v8.browsing_mobile/browse:media:youtube [ Skip ]
 crbug.com/799080 [ Nexus_7 ] v8.browsing_mobile-future/browse:news:cnn [ Skip ]
 
 # Benchmark: v8.browsing_mobile-future
-crbug.com/788797 [ Cherry_Mobile_Android_One ] v8.browsing_mobile-future/browse:social:facebook_infinite_scroll [ Skip ]
-crbug.com/788797 [ Cherry_Mobile_Android_One ] v8.browsing_mobile-future/browse:social:pinterest_infinite_scroll [ Skip ]
-crbug.com/768472 [ Cherry_Mobile_Android_One ] v8.browsing_mobile-future/browse:shopping:lazada [ Skip ]
 crbug.com/714650 [ Android ] v8.browsing_mobile-future/browse:news:globo [ Skip ]
-crbug.com/767970 [ Cherry_Mobile_Android_One ] v8.browsing_mobile-future/browse:tech:discourse_infinite_scroll [ Skip ]
-crbug.com/767970 [ Cherry_Mobile_Android_One ] v8.browsing_mobile-future/browse:shopping:avito [ Skip ]
-[ Android_Webview ] v8.browsing_mobile-future/browse:chrome:omnibox [ Skip ]
 crbug.com/728081 [ Android ] v8.browsing_mobile-future/browse:news:toi [ Skip ]
-crbug.com/767970 [ Cherry_Mobile_Android_One ] v8.browsing_mobile-future/browse:news:cnn [ Skip ]
-crbug.com/803870 [ Cherry_Mobile_Android_One ] v8.browsing_mobile-future/browse:media:youtube [ Skip ]
 crbug.com/767970 [ Mobile ] v8.browsing_mobile-future/browse:shopping:flipkart [ Skip ]
 crbug.com/708300 [ Mobile ] v8.browsing_mobile-future/browse:shopping:flipkart [ Skip ]
+crbug.com/788797 [ Cherry_Mobile_Android_One ] v8.browsing_mobile-future/browse:social:facebook_infinite_scroll [ Skip ]
+crbug.com/788797 [ Cherry_Mobile_Android_One ] v8.browsing_mobile-future/browse:social:pinterest_infinite_scroll [ Skip ]
+crbug.com/803870 [ Cherry_Mobile_Android_One ] v8.browsing_mobile/browse:social:tumblr_infinite_scroll [ Skip ]
+crbug.com/767970 [ Cherry_Mobile_Android_One ] v8.browsing_mobile-future/browse:tech:discourse_infinite_scroll [ Skip ]
+crbug.com/768472 [ Cherry_Mobile_Android_One ] v8.browsing_mobile-future/browse:shopping:lazada [ Skip ]
+crbug.com/767970 [ Cherry_Mobile_Android_One ] v8.browsing_mobile-future/browse:shopping:avito [ Skip ]
+crbug.com/803870 [ Cherry_Mobile_Android_One ] v8.browsing_mobile-future/browse:media:youtube [ Skip ]
+crbug.com/767970 [ Cherry_Mobile_Android_One ] v8.browsing_mobile-future/browse:news:cnn [ Skip ]
+[ Android_Webview ] v8.browsing_mobile-future/browse:chrome:omnibox [ Skip ]
 [ Android_Webview ] v8.browsing_mobile-future/browse:chrome:newtab [ Skip ]
+crbug.com/803465 [ Nexus_5 ] v8.browsing_mobile-future/browse:chrome:newtab [ Skip ]
 crbug.com/799080 [ Nexus_5 ] v8.browsing_mobile-future/browse:social:tumblr_infinite_scroll [ Skip ]
 crbug.com/799080 [ Nexus_5X Android_Webview ] v8.browsing_mobile-future/browse:social:facebook [ Skip ]
 crbug.com/799080 [ Nexus_7 ] v8.browsing_mobile-future/browse:news:cnn [ Skip ]
 crbug.com/799080 [ Nexus_7 ] v8.browsing_mobile-future/browse:shopping:avito [ Skip ]
 crbug.com/799080 [ Nexus_7 ] v8.browsing_mobile-future/browse:social:pinterest_infinite_scroll [ Skip ]
-crbug.com/803465 [ Nexus_5 ] v8.browsing_mobile-future/browse:chrome:newtab [ Skip ]
 
 # Benchmark: v8.detached_context_age_in_gc
 crbug.com/770982 [ Win ] v8.detached_context_age_in_gc/Docs_(1_open_document_tab) [ Skip ]
@@ -363,6 +365,8 @@
 
 # Benchmark: wasm
 [ Cherry_Mobile_Android_One ] wasm/WasmSpaceBuggy [ Skip ]
+crbug.com/814012 [ Mac ] wasm/AsmJsZenGarden [ Skip ]
+crbug.com/814012 [ Win ] wasm/AsmJsZenGarden [ Skip ]
 
 ##### Perf FYI benchmarks go after here #####
 # Benchmark: loading.desktop.network_service
diff --git a/tools/perf/page_sets/data/wasm_realworld_pages.json b/tools/perf/page_sets/data/wasm_realworld_pages.json
index cc8d5da4..47e5b48 100644
--- a/tools/perf/page_sets/data/wasm_realworld_pages.json
+++ b/tools/perf/page_sets/data/wasm_realworld_pages.json
@@ -1,19 +1,22 @@
 {
     "archives": {
+        "AsmJsZenGarden": {
+            "DEFAULT": "wasm_realworld_pages_004.wprgo"
+        },
         "WasmSpaceBuggy": {
-            "DEFAULT": "wasm_realworld_pages_003.wprgo"
+            "DEFAULT": "wasm_realworld_pages_004.wprgo"
         },
         "WasmStylizedRenderer": {
-            "DEFAULT": "wasm_realworld_pages_003.wprgo"
+            "DEFAULT": "wasm_realworld_pages_004.wprgo"
         },
         "WasmSunTemple": {
-            "DEFAULT": "wasm_realworld_pages_003.wprgo"
+            "DEFAULT": "wasm_realworld_pages_004.wprgo"
         },
         "WasmTanks": {
-            "DEFAULT": "wasm_realworld_pages_003.wprgo"
+            "DEFAULT": "wasm_realworld_pages_004.wprgo"
         },
         "WasmZenGarden": {
-            "DEFAULT": "wasm_realworld_pages_003.wprgo"
+            "DEFAULT": "wasm_realworld_pages_004.wprgo"
         }
     },
     "description": "Describes the Web Page Replay archives for a story set. Don't edit by hand! Use record_wpr for updating.",
diff --git a/tools/perf/page_sets/data/wasm_realworld_pages_004.wprgo.sha1 b/tools/perf/page_sets/data/wasm_realworld_pages_004.wprgo.sha1
new file mode 100644
index 0000000..827d7ebf
--- /dev/null
+++ b/tools/perf/page_sets/data/wasm_realworld_pages_004.wprgo.sha1
@@ -0,0 +1 @@
+780b372a021875868b7deb082da426c04759cdd4
\ No newline at end of file
diff --git a/tools/perf/page_sets/wasm_realworld_pages.py b/tools/perf/page_sets/wasm_realworld_pages.py
index b035834e..ca9a67b7 100644
--- a/tools/perf/page_sets/wasm_realworld_pages.py
+++ b/tools/perf/page_sets/wasm_realworld_pages.py
@@ -106,6 +106,30 @@
     super(EpicStylizedRenderer, self).__init__(
         page_set=page_set, url=url, name='WasmStylizedRenderer')
 
+class EpicZenGardenAsm(page_module.Page):
+
+  def __init__(self, page_set):
+    url = ("https://s3.amazonaws.com/unrealengine/HTML5/TestBuilds/Release-4."
+           "17.1-CL-3637171/Zen-HTML5-Shipping.html")
+    super(EpicZenGardenAsm, self).__init__(
+        url=url,
+        page_set=page_set,
+        shared_page_state_class=(
+            webgl_supported_shared_state.WebGLSupportedSharedState),
+        name='AsmJsZenGarden')
+
+  @property
+  def skipped_gpus(self):
+    # Unity WebGL is not supported on mobile
+    return ['arm', 'qualcomm']
+
+  def RunPageInteractions(self, action_runner):
+    action_runner.WaitForJavaScriptCondition(
+        """document.getElementsByClassName('emscripten').length != 0""")
+    action_runner.WaitForJavaScriptCondition(
+        """document.getElementsByClassName('emscripten')[0].style['display']
+          != 'none'""")
+
 class WasmRealWorldPagesStorySet(story.StorySet):
   """Top apps, used to monitor web assembly apps."""
 
@@ -119,3 +143,4 @@
     self.AddStory(EpicZenGarden(self))
     self.AddStory(EpicSunTemple(self))
     self.AddStory(EpicStylizedRenderer(self))
+    self.AddStory(EpicZenGardenAsm(self))
diff --git a/tools/perf/process_perf_results.py b/tools/perf/process_perf_results.py
index 8053971..7ee94478 100755
--- a/tools/perf/process_perf_results.py
+++ b/tools/perf/process_perf_results.py
@@ -88,6 +88,10 @@
 
   test_results_list = []
   for directory in benchmark_directory_list:
+    if '.reference' in directory:
+      # We don't need to upload reference build data to the
+      # flakiness dashboard since we don't monitor the ref build
+      continue
     with open(join(directory, 'test_results.json')) as json_data:
       test_results_list.append(json.load(json_data))
   _merge_json_output(output_json, test_results_list)
diff --git a/tools/traffic_annotation/auditor/BUILD.gn b/tools/traffic_annotation/auditor/BUILD.gn
index f4b33ba..7704bf9df 100644
--- a/tools/traffic_annotation/auditor/BUILD.gn
+++ b/tools/traffic_annotation/auditor/BUILD.gn
@@ -86,6 +86,8 @@
     "traffic_annotation_auditor_unittest.cc",
   ]
   data = [
+    "../scripts/annotations_xml_downstream_caller.py",
+    "../summary/annotations.xml",
     "tests/annotations_diff12.txt",
     "tests/annotations_diff13.txt",
     "tests/annotations_diff23.txt",
diff --git a/tools/traffic_annotation/auditor/traffic_annotation_auditor_unittest.cc b/tools/traffic_annotation/auditor/traffic_annotation_auditor_unittest.cc
index 0dab1425..54eadb5 100644
--- a/tools/traffic_annotation/auditor/traffic_annotation_auditor_unittest.cc
+++ b/tools/traffic_annotation/auditor/traffic_annotation_auditor_unittest.cc
@@ -935,12 +935,6 @@
   EXPECT_EQ(0, tests_result);
 }
 
-// Tests if AnnotationInstance::GetClangLibraryPath finds a path.
-TEST_F(TrafficAnnotationAuditorTest, GetClangLibraryPath) {
-  base::FilePath clang_library = auditor().GetClangLibraryPath();
-  EXPECT_FALSE(clang_library.empty());
-}
-
 // Tests if 'annotations.xml' is read and has at least one item.
 TEST_F(TrafficAnnotationAuditorTest, AnnotationsXMLLines) {
   TrafficAnnotationExporter exporter(source_path());
diff --git a/ui/android/java/src/org/chromium/ui/base/ResourceBundle.java b/ui/android/java/src/org/chromium/ui/base/ResourceBundle.java
index 3567d37..0382559 100644
--- a/ui/android/java/src/org/chromium/ui/base/ResourceBundle.java
+++ b/ui/android/java/src/org/chromium/ui/base/ResourceBundle.java
@@ -4,14 +4,9 @@
 
 package org.chromium.ui.base;
 
-import android.util.DisplayMetrics;
-import android.view.Display;
-
 import org.chromium.base.BuildConfig;
-import org.chromium.base.ContextUtils;
 import org.chromium.base.annotations.CalledByNative;
 import org.chromium.base.annotations.JNINamespace;
-import org.chromium.ui.display.DisplayAndroidManager;
 
 import java.util.Arrays;
 
@@ -31,13 +26,4 @@
         }
         return null;
     }
-
-    @CalledByNative
-    private static float getPrimaryDisplayScale() {
-        Display primaryDisplay = DisplayAndroidManager.getDefaultDisplayForContext(
-                ContextUtils.getApplicationContext());
-        DisplayMetrics displayMetrics = new DisplayMetrics();
-        primaryDisplay.getMetrics(displayMetrics);
-        return displayMetrics.density;
-    }
 }
diff --git a/ui/base/BUILD.gn b/ui/base/BUILD.gn
index e98737e..38102b3 100644
--- a/ui/base/BUILD.gn
+++ b/ui/base/BUILD.gn
@@ -141,6 +141,8 @@
     "cocoa/remote_layer_api.mm",
     "cocoa/scoped_cg_context_smooth_fonts.h",
     "cocoa/scoped_cg_context_smooth_fonts.mm",
+    "cocoa/text_services_context_menu.cc",
+    "cocoa/text_services_context_menu.h",
     "cocoa/three_part_image.h",
     "cocoa/three_part_image.mm",
     "cocoa/tool_tip_base_view.h",
diff --git a/ui/base/cocoa/text_services_context_menu.cc b/ui/base/cocoa/text_services_context_menu.cc
new file mode 100644
index 0000000..d675d0e6
--- /dev/null
+++ b/ui/base/cocoa/text_services_context_menu.cc
@@ -0,0 +1,103 @@
+// 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 "ui/base/cocoa/text_services_context_menu.h"
+
+#include <utility>
+
+#include <ApplicationServices/ApplicationServices.h>
+#include <CoreAudio/CoreAudio.h>
+
+#include "base/mac/mac_logging.h"
+#include "base/strings/sys_string_conversions.h"
+#include "base/strings/utf_string_conversions.h"
+#include "ui/base/l10n/l10n_util.h"
+#include "ui/strings/grit/ui_strings.h"
+
+namespace {
+
+// The speech channel used for speaking. This is shared to check if a speech
+// channel is currently speaking.
+SpeechChannel g_speech_channel;
+
+}  // namespace
+
+namespace ui {
+
+TextServicesContextMenu::TextServicesContextMenu(Delegate* delegate)
+    : speech_submenu_model_(this), delegate_(delegate) {
+  DCHECK(delegate);
+
+  speech_submenu_model_.AddItemWithStringId(IDS_SPEECH_START_SPEAKING_MAC,
+                                            IDS_SPEECH_START_SPEAKING_MAC);
+  speech_submenu_model_.AddItemWithStringId(IDS_SPEECH_STOP_SPEAKING_MAC,
+                                            IDS_SPEECH_STOP_SPEAKING_MAC);
+}
+
+void TextServicesContextMenu::SpeakText(const base::string16& text) {
+  if (IsSpeaking())
+    StopSpeaking();
+
+  if (!g_speech_channel) {
+    OSErr result = NewSpeechChannel(nullptr, &g_speech_channel);
+    OSSTATUS_DCHECK(result == noErr, result);
+  }
+
+  SpeakCFString(g_speech_channel, base::SysUTF16ToCFStringRef(text), nullptr);
+}
+
+void TextServicesContextMenu::StopSpeaking() {
+  DCHECK(g_speech_channel);
+  StopSpeechAt(g_speech_channel, kImmediate);
+  DisposeSpeechChannel(g_speech_channel);
+  g_speech_channel = nullptr;
+}
+
+bool TextServicesContextMenu::IsSpeaking() {
+  return SpeechBusy();
+}
+
+void TextServicesContextMenu::AppendToContextMenu(SimpleMenuModel* model) {
+  model->AddSeparator(NORMAL_SEPARATOR);
+  model->AddSubMenuWithStringId(IDS_SPEECH_MAC, IDS_SPEECH_MAC,
+                                &speech_submenu_model_);
+}
+
+bool TextServicesContextMenu::IsCommandIdChecked(int command_id) const {
+  switch (command_id) {
+    case IDS_SPEECH_START_SPEAKING_MAC:
+    case IDS_SPEECH_STOP_SPEAKING_MAC:
+      return false;
+  }
+
+  NOTREACHED();
+  return false;
+}
+
+bool TextServicesContextMenu::IsCommandIdEnabled(int command_id) const {
+  switch (command_id) {
+    case IDS_SPEECH_START_SPEAKING_MAC:
+      return true;
+    case IDS_SPEECH_STOP_SPEAKING_MAC:
+      return IsSpeaking();
+  }
+
+  NOTREACHED();
+  return false;
+}
+
+void TextServicesContextMenu::ExecuteCommand(int command_id, int event_flags) {
+  switch (command_id) {
+    case IDS_SPEECH_START_SPEAKING_MAC:
+      SpeakText(delegate_->GetSelectedText());
+      break;
+    case IDS_SPEECH_STOP_SPEAKING_MAC:
+      StopSpeaking();
+      break;
+    default:
+      NOTREACHED();
+  }
+}
+
+}  // namespace ui
\ No newline at end of file
diff --git a/ui/base/cocoa/text_services_context_menu.h b/ui/base/cocoa/text_services_context_menu.h
new file mode 100644
index 0000000..dbc47136
--- /dev/null
+++ b/ui/base/cocoa/text_services_context_menu.h
@@ -0,0 +1,55 @@
+// 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 UI_BASE_COCOA_TEXT_SERVICES_CONTEXT_MENU_H_
+#define UI_BASE_COCOA_TEXT_SERVICES_CONTEXT_MENU_H_
+
+#include "base/macros.h"
+#include "base/strings/string16.h"
+#include "ui/base/models/simple_menu_model.h"
+#include "ui/base/ui_base_export.h"
+
+namespace ui {
+
+// This class is used to append and handle the Speech and BiDi submenu for the
+// context menu.
+// TODO (spqchan): Replace the Speech logic in RenderViewContextMenu
+// with TextServicesContextMenu.
+class UI_BASE_EXPORT TextServicesContextMenu
+    : public SimpleMenuModel::Delegate {
+ public:
+  class UI_BASE_EXPORT Delegate {
+   public:
+    // Returns the selected text.
+    virtual base::string16 GetSelectedText() const = 0;
+  };
+
+  explicit TextServicesContextMenu(Delegate* delegate);
+
+  // Methods for speaking.
+  static void SpeakText(const base::string16& text);
+  static void StopSpeaking();
+  static bool IsSpeaking();
+
+  // Appends text service items to |model|. A submenu is added for speech,
+  // which |this| serves as the delegate for.
+  void AppendToContextMenu(SimpleMenuModel* model);
+
+  // SimpleMenuModel::Delegate:
+  bool IsCommandIdChecked(int command_id) const override;
+  bool IsCommandIdEnabled(int command_id) const override;
+  void ExecuteCommand(int command_id, int event_flags) override;
+
+ private:
+  // Model for the "Speech" submenu.
+  ui::SimpleMenuModel speech_submenu_model_;
+
+  Delegate* delegate_;  // Weak.
+
+  DISALLOW_COPY_AND_ASSIGN(TextServicesContextMenu);
+};
+
+}  // namespace ui
+
+#endif  // UI_BASE_COCOA_TEXT_SERVICES_CONTEXT_MENU_H_
\ No newline at end of file
diff --git a/ui/base/resource/resource_bundle.cc b/ui/base/resource/resource_bundle.cc
index 5610188..3bfd3cd 100644
--- a/ui/base/resource/resource_bundle.cc
+++ b/ui/base/resource/resource_bundle.cc
@@ -74,25 +74,6 @@
 
 ResourceBundle* g_shared_instance_ = NULL;
 
-#if defined(OS_ANDROID)
-// Returns the scale factor closest to |scale| from the full list of factors.
-// Note that it does NOT rely on the list of supported scale factors.
-// Finding the closest match is inefficient and shouldn't be done frequently.
-ScaleFactor FindClosestScaleFactorUnsafe(float scale) {
-  float smallest_diff =  std::numeric_limits<float>::max();
-  ScaleFactor closest_match = SCALE_FACTOR_100P;
-  for (int i = SCALE_FACTOR_100P; i < NUM_SCALE_FACTORS; ++i) {
-    const ScaleFactor scale_factor = static_cast<ScaleFactor>(i);
-    float diff = std::abs(GetScaleForScaleFactor(scale_factor) - scale);
-    if (diff < smallest_diff) {
-      closest_match = scale_factor;
-      smallest_diff = diff;
-    }
-  }
-  return closest_match;
-}
-#endif  // OS_ANDROID
-
 base::FilePath GetResourcesPakFilePath(const std::string& pak_name) {
   base::FilePath path;
   if (PathService::Get(base::DIR_MODULE, &path))
@@ -761,22 +742,7 @@
   DCHECK(g_shared_instance_ == NULL) << "ResourceBundle initialized twice";
   g_shared_instance_ = new ResourceBundle(delegate);
   static std::vector<ScaleFactor> supported_scale_factors;
-#if !defined(OS_IOS)
-  // On platforms other than iOS, 100P is always a supported scale factor.
-  // For Windows we have a separate case in this function.
-  supported_scale_factors.push_back(SCALE_FACTOR_100P);
-#endif
-#if defined(OS_ANDROID)
-  float display_density;
-  if (display::Display::HasForceDeviceScaleFactor()) {
-    display_density = display::Display::GetForcedDeviceScaleFactor();
-  } else {
-    display_density = GetPrimaryDisplayScale();
-  }
-  const ScaleFactor closest = FindClosestScaleFactorUnsafe(display_density);
-  if (closest != SCALE_FACTOR_100P)
-    supported_scale_factors.push_back(closest);
-#elif defined(OS_IOS)
+#if defined(OS_IOS)
   display::Display display = display::Screen::GetScreen()->GetPrimaryDisplay();
   if (display.device_scale_factor() > 2.0) {
     DCHECK_EQ(3.0, display.device_scale_factor());
@@ -787,9 +753,14 @@
   } else {
     supported_scale_factors.push_back(SCALE_FACTOR_100P);
   }
-#elif defined(OS_MACOSX) || defined(OS_LINUX) || defined(OS_WIN)
+#else
+  // On platforms other than iOS, 100P is always a supported scale factor.
+  // For Windows we have a separate case in this function.
+  supported_scale_factors.push_back(SCALE_FACTOR_100P);
+#if defined(OS_MACOSX) || defined(OS_LINUX) || defined(OS_WIN)
   supported_scale_factors.push_back(SCALE_FACTOR_200P);
 #endif
+#endif
   ui::SetSupportedScaleFactors(supported_scale_factors);
 }
 
diff --git a/ui/base/resource/resource_bundle_android.cc b/ui/base/resource/resource_bundle_android.cc
index 0923b6fd..a91fdabe 100644
--- a/ui/base/resource/resource_bundle_android.cc
+++ b/ui/base/resource/resource_bundle_android.cc
@@ -211,9 +211,4 @@
   return base::android::ConvertJavaStringToUTF8(env, ret.obj());
 }
 
-float GetPrimaryDisplayScale() {
-  return Java_ResourceBundle_getPrimaryDisplayScale(
-      base::android::AttachCurrentThread());
-}
-
 }  // namespace ui
diff --git a/ui/compositor/compositor.cc b/ui/compositor/compositor.cc
index aff0414..88e39c0 100644
--- a/ui/compositor/compositor.cc
+++ b/ui/compositor/compositor.cc
@@ -35,6 +35,7 @@
 #include "components/viz/common/resources/resource_format.h"
 #include "components/viz/common/resources/resource_settings.h"
 #include "components/viz/common/surfaces/parent_local_surface_id_allocator.h"
+#include "components/viz/common/switches.h"
 #include "components/viz/host/host_frame_sink_manager.h"
 #include "components/viz/host/renderer_settings_creation.h"
 #include "components/viz/service/frame_sinks/frame_sink_manager_impl.h"
@@ -178,8 +179,7 @@
   settings.disallow_non_exact_resource_reuse =
       command_line->HasSwitch(switches::kDisallowNonExactResourceReuse);
 
-  if (command_line->HasSwitch(
-          cc::switches::kRunAllCompositorStagesBeforeDraw)) {
+  if (command_line->HasSwitch(switches::kRunAllCompositorStagesBeforeDraw)) {
     settings.wait_for_all_pipeline_stages_before_draw = true;
     settings.enable_latency_recovery = false;
   }
diff --git a/ui/events/BUILD.gn b/ui/events/BUILD.gn
index d6363a7b..f5cdb2e7 100644
--- a/ui/events/BUILD.gn
+++ b/ui/events/BUILD.gn
@@ -99,6 +99,13 @@
       "Carbon.framework",
     ]
   }
+
+  if (is_chromecast && !is_android) {
+    sources += [
+      "chromecast/scroller.cc",
+      "chromecast/scroller.h",
+    ]
+  }
 }
 
 component("events") {
@@ -487,6 +494,10 @@
     if (is_win) {
       sources += [ "blink/web_input_event_builders_win_unittest.cc" ]
     }
+
+    if (is_chromecast && !is_android) {
+      sources += [ "chromecast/scroller_unittest.cc" ]
+    }
   }
 }
 
diff --git a/ui/events/chromecast/scroller.cc b/ui/events/chromecast/scroller.cc
new file mode 100644
index 0000000..9c989a95
--- /dev/null
+++ b/ui/events/chromecast/scroller.cc
@@ -0,0 +1,477 @@
+// 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 "ui/events/chromecast/scroller.h"
+
+#include <cmath>
+
+#include "base/lazy_instance.h"
+#include "base/macros.h"
+
+namespace ui {
+namespace {
+
+// Default scroll duration from android.widget.Scroller.
+const int kDefaultDurationMs = 250;
+
+// Default friction constant in android.view.ViewConfiguration.
+const float kDefaultFriction = 0.015f;
+
+// == std::log(0.78f) / std::log(0.9f)
+const float kDecelerationRate = 2.3582018f;
+
+// Tension lines cross at (kInflexion, 1).
+const float kInflexion = 0.35f;
+
+const float kEpsilon = 1e-5f;
+
+// Fling scroll is stopped when the scroll position is |kThresholdForFlingEnd|
+// pixels or closer from the end.
+const float kThresholdForFlingEnd = 0.1;
+
+bool ApproxEquals(float a, float b) {
+  return std::abs(a - b) < kEpsilon;
+}
+
+struct ViscosityConstants {
+  ViscosityConstants()
+      : viscous_fluid_scale_(8.f), viscous_fluid_normalize_(1.f) {
+    viscous_fluid_normalize_ = 1.0f / ApplyViscosity(1.0f);
+  }
+
+  float ApplyViscosity(float x) {
+    x *= viscous_fluid_scale_;
+    if (x < 1.0f) {
+      x -= (1.0f - std::exp(-x));
+    } else {
+      float start = 0.36787944117f;  // 1/e == exp(-1)
+      x = 1.0f - std::exp(1.0f - x);
+      x = start + x * (1.0f - start);
+    }
+    x *= viscous_fluid_normalize_;
+    return x;
+  }
+
+ private:
+  // This controls the intensity of the viscous fluid effect.
+  float viscous_fluid_scale_;
+  float viscous_fluid_normalize_;
+
+  DISALLOW_COPY_AND_ASSIGN(ViscosityConstants);
+};
+
+struct SplineConstants {
+  SplineConstants() {
+    const float kStartTension = 0.5f;
+    const float kEndTension = 1.0f;
+    const float kP1 = kStartTension * kInflexion;
+    const float kP2 = 1.0f - kEndTension * (1.0f - kInflexion);
+
+    float x_min = 0.0f;
+    float y_min = 0.0f;
+    for (int i = 0; i < NUM_SAMPLES; i++) {
+      const float alpha = static_cast<float>(i) / NUM_SAMPLES;
+
+      float x_max = 1.0f;
+      float x, tx, coef;
+      while (true) {
+        x = x_min + (x_max - x_min) / 2.0f;
+        coef = 3.0f * x * (1.0f - x);
+        tx = coef * ((1.0f - x) * kP1 + x * kP2) + x * x * x;
+        if (ApproxEquals(tx, alpha))
+          break;
+        if (tx > alpha)
+          x_max = x;
+        else
+          x_min = x;
+      }
+      spline_position_[i] = coef * ((1.0f - x) * kStartTension + x) + x * x * x;
+
+      float y_max = 1.0f;
+      float y, dy;
+      while (true) {
+        y = y_min + (y_max - y_min) / 2.0f;
+        coef = 3.0f * y * (1.0f - y);
+        dy = coef * ((1.0f - y) * kStartTension + y) + y * y * y;
+        if (ApproxEquals(dy, alpha))
+          break;
+        if (dy > alpha)
+          y_max = y;
+        else
+          y_min = y;
+      }
+      spline_time_[i] = coef * ((1.0f - y) * kP1 + y * kP2) + y * y * y;
+    }
+    spline_position_[NUM_SAMPLES] = spline_time_[NUM_SAMPLES] = 1.0f;
+  }
+
+  void CalculateCoefficients(float t,
+                             float* distance_coef,
+                             float* velocity_coef) {
+    *distance_coef = 1.f;
+    *velocity_coef = 0.f;
+    const int index = static_cast<int>(NUM_SAMPLES * t);
+    if (index < NUM_SAMPLES) {
+      const float t_inf = static_cast<float>(index) / NUM_SAMPLES;
+      const float t_sup = static_cast<float>(index + 1) / NUM_SAMPLES;
+      const float d_inf = spline_position_[index];
+      const float d_sup = spline_position_[index + 1];
+      *velocity_coef = (d_sup - d_inf) / (t_sup - t_inf);
+      *distance_coef = d_inf + (t - t_inf) * *velocity_coef;
+    }
+  }
+
+ private:
+  enum { NUM_SAMPLES = 100 };
+
+  float spline_position_[NUM_SAMPLES + 1];
+  float spline_time_[NUM_SAMPLES + 1];
+
+  DISALLOW_COPY_AND_ASSIGN(SplineConstants);
+};
+
+float ComputeDeceleration(float friction) {
+  const float kGravityEarth = 9.80665f;
+  return kGravityEarth  // g (m/s^2)
+         * 39.37f       // inch/meter
+         * 160.f        // pixels/inch
+         * friction;
+}
+
+template <typename T>
+int Signum(T t) {
+  return (T(0) < t) - (t < T(0));
+}
+
+template <typename T>
+T Clamped(T t, T a, T b) {
+  return t < a ? a : (t > b ? b : t);
+}
+
+// Leaky to allow access from the impl thread.
+base::LazyInstance<ViscosityConstants>::Leaky g_viscosity_constants =
+    LAZY_INSTANCE_INITIALIZER;
+
+base::LazyInstance<SplineConstants>::Leaky g_spline_constants =
+    LAZY_INSTANCE_INITIALIZER;
+
+}  // namespace
+
+Scroller::Config::Config()
+    : fling_friction(kDefaultFriction), flywheel_enabled(false) {
+}
+
+Scroller::Scroller(const Config& config)
+    : mode_(UNDEFINED),
+      start_x_(0),
+      start_y_(0),
+      final_x_(0),
+      final_y_(0),
+      min_x_(0),
+      max_x_(0),
+      min_y_(0),
+      max_y_(0),
+      curr_x_(0),
+      curr_y_(0),
+      duration_seconds_reciprocal_(1),
+      delta_x_(0),
+      delta_x_norm_(1),
+      delta_y_(0),
+      delta_y_norm_(1),
+      finished_(true),
+      flywheel_enabled_(config.flywheel_enabled),
+      velocity_(0),
+      curr_velocity_(0),
+      distance_(0),
+      fling_friction_(config.fling_friction),
+      deceleration_(ComputeDeceleration(fling_friction_)),
+      tuning_coeff_(ComputeDeceleration(0.84f)) {
+}
+
+Scroller::~Scroller() {
+}
+
+bool Scroller::ComputeScrollOffset(base::TimeTicks time,
+                                   gfx::Vector2dF* offset,
+                                   gfx::Vector2dF* velocity) {
+  DCHECK(offset);
+  DCHECK(velocity);
+  if (!ComputeScrollOffsetInternal(time)) {
+    *offset = gfx::Vector2dF(GetFinalX(), GetFinalY());
+    *velocity = gfx::Vector2dF();
+    return false;
+  }
+
+  *offset = gfx::Vector2dF(GetCurrX(), GetCurrY());
+  *velocity = gfx::Vector2dF(GetCurrVelocityX(), GetCurrVelocityY());
+  return true;
+}
+
+void Scroller::StartScroll(float start_x,
+                           float start_y,
+                           float dx,
+                           float dy,
+                           base::TimeTicks start_time) {
+  StartScroll(start_x,
+              start_y,
+              dx,
+              dy,
+              start_time,
+              base::TimeDelta::FromMilliseconds(kDefaultDurationMs));
+}
+
+void Scroller::StartScroll(float start_x,
+                           float start_y,
+                           float dx,
+                           float dy,
+                           base::TimeTicks start_time,
+                           base::TimeDelta duration) {
+  DCHECK_GT(duration, base::TimeDelta());
+  mode_ = SCROLL_MODE;
+  finished_ = false;
+  duration_ = duration;
+  duration_seconds_reciprocal_ = 1.0 / duration_.InSecondsF();
+  start_time_ = start_time;
+  curr_x_ = start_x_ = start_x;
+  curr_y_ = start_y_ = start_y;
+  final_x_ = start_x + dx;
+  final_y_ = start_y + dy;
+  RecomputeDeltas();
+  curr_time_ = start_time_;
+}
+
+void Scroller::Fling(float start_x,
+                     float start_y,
+                     float velocity_x,
+                     float velocity_y,
+                     float min_x,
+                     float max_x,
+                     float min_y,
+                     float max_y,
+                     base::TimeTicks start_time) {
+  DCHECK(velocity_x || velocity_y);
+
+  // Continue a scroll or fling in progress.
+  if (flywheel_enabled_ && !finished_) {
+    float old_velocity_x = GetCurrVelocityX();
+    float old_velocity_y = GetCurrVelocityY();
+    if (Signum(velocity_x) == Signum(old_velocity_x) &&
+        Signum(velocity_y) == Signum(old_velocity_y)) {
+      velocity_x += old_velocity_x;
+      velocity_y += old_velocity_y;
+    }
+  }
+
+  mode_ = FLING_MODE;
+  finished_ = false;
+
+  float velocity = std::sqrt(velocity_x * velocity_x + velocity_y * velocity_y);
+
+  velocity_ = velocity;
+  duration_ = GetSplineFlingDuration(velocity);
+  DCHECK_GT(duration_, base::TimeDelta());
+  duration_seconds_reciprocal_ = 1.0 / duration_.InSecondsF();
+  start_time_ = start_time;
+  curr_time_ = start_time_;
+  curr_x_ = start_x_ = start_x;
+  curr_y_ = start_y_ = start_y;
+
+  float coeff_x = velocity == 0 ? 1.0f : velocity_x / velocity;
+  float coeff_y = velocity == 0 ? 1.0f : velocity_y / velocity;
+
+  double total_distance = GetSplineFlingDistance(velocity);
+  distance_ = total_distance * Signum(velocity);
+
+  min_x_ = min_x;
+  max_x_ = max_x;
+  min_y_ = min_y;
+  max_y_ = max_y;
+
+  final_x_ = start_x + total_distance * coeff_x;
+  final_x_ = Clamped(final_x_, min_x_, max_x_);
+
+  final_y_ = start_y + total_distance * coeff_y;
+  final_y_ = Clamped(final_y_, min_y_, max_y_);
+
+  RecomputeDeltas();
+}
+
+void Scroller::ExtendDuration(base::TimeDelta extend) {
+  base::TimeDelta passed = GetTimePassed();
+  duration_ = passed + extend;
+  duration_seconds_reciprocal_ = 1.0 / duration_.InSecondsF();
+  finished_ = false;
+}
+
+void Scroller::SetFinalX(float new_x) {
+  final_x_ = new_x;
+  finished_ = false;
+  RecomputeDeltas();
+}
+
+void Scroller::SetFinalY(float new_y) {
+  final_y_ = new_y;
+  finished_ = false;
+  RecomputeDeltas();
+}
+
+void Scroller::AbortAnimation() {
+  curr_x_ = final_x_;
+  curr_y_ = final_y_;
+  curr_velocity_ = 0;
+  curr_time_ = start_time_ + duration_;
+  finished_ = true;
+}
+
+void Scroller::ForceFinished(bool finished) {
+  finished_ = finished;
+}
+
+bool Scroller::IsFinished() const {
+  return finished_;
+}
+
+base::TimeDelta Scroller::GetTimePassed() const {
+  return curr_time_ - start_time_;
+}
+
+base::TimeDelta Scroller::GetDuration() const {
+  return duration_;
+}
+
+float Scroller::GetCurrX() const {
+  return curr_x_;
+}
+
+float Scroller::GetCurrY() const {
+  return curr_y_;
+}
+
+float Scroller::GetCurrVelocity() const {
+  if (finished_)
+    return 0;
+  if (mode_ == FLING_MODE)
+    return curr_velocity_;
+  return velocity_ - deceleration_ * GetTimePassed().InSecondsF() * 0.5f;
+}
+
+float Scroller::GetCurrVelocityX() const {
+  return delta_x_norm_ * GetCurrVelocity();
+}
+
+float Scroller::GetCurrVelocityY() const {
+  return delta_y_norm_ * GetCurrVelocity();
+}
+
+float Scroller::GetStartX() const {
+  return start_x_;
+}
+
+float Scroller::GetStartY() const {
+  return start_y_;
+}
+
+float Scroller::GetFinalX() const {
+  return final_x_;
+}
+
+float Scroller::GetFinalY() const {
+  return final_y_;
+}
+
+bool Scroller::IsScrollingInDirection(float xvel, float yvel) const {
+  return !finished_ && Signum(xvel) == Signum(delta_x_) &&
+         Signum(yvel) == Signum(delta_y_);
+}
+
+bool Scroller::ComputeScrollOffsetInternal(base::TimeTicks time) {
+  if (finished_)
+    return false;
+
+  if (time <= start_time_)
+    return true;
+
+  if (time == curr_time_)
+    return true;
+
+  base::TimeDelta time_passed = time - start_time_;
+  if (time_passed >= duration_) {
+    AbortAnimation();
+    return false;
+  }
+
+  curr_time_ = time;
+
+  const float u = time_passed.InSecondsF() * duration_seconds_reciprocal_;
+  switch (mode_) {
+    case UNDEFINED:
+      NOTREACHED() << "|StartScroll()| or |Fling()| must be called prior to "
+                      "scroll offset computation.";
+      return false;
+
+    case SCROLL_MODE: {
+      float x = g_viscosity_constants.Get().ApplyViscosity(u);
+
+      curr_x_ = start_x_ + x * delta_x_;
+      curr_y_ = start_y_ + x * delta_y_;
+    } break;
+
+    case FLING_MODE: {
+      float distance_coef = 1.f;
+      float velocity_coef = 0.f;
+      g_spline_constants.Get().CalculateCoefficients(
+          u, &distance_coef, &velocity_coef);
+
+      curr_velocity_ = velocity_coef * distance_ * duration_seconds_reciprocal_;
+
+      curr_x_ = start_x_ + distance_coef * delta_x_;
+      curr_x_ = Clamped(curr_x_, min_x_, max_x_);
+
+      curr_y_ = start_y_ + distance_coef * delta_y_;
+      curr_y_ = Clamped(curr_y_, min_y_, max_y_);
+
+      float diff_x = std::abs(curr_x_ - final_x_);
+      float diff_y = std::abs(curr_y_ - final_y_);
+      if (diff_x < kThresholdForFlingEnd && diff_y < kThresholdForFlingEnd)
+        AbortAnimation();
+    } break;
+  }
+
+  return !finished_;
+}
+
+void Scroller::RecomputeDeltas() {
+  delta_x_ = final_x_ - start_x_;
+  delta_y_ = final_y_ - start_y_;
+
+  const float hyp = std::sqrt(delta_x_ * delta_x_ + delta_y_ * delta_y_);
+  if (hyp > kEpsilon) {
+    delta_x_norm_ = delta_x_ / hyp;
+    delta_y_norm_ = delta_y_ / hyp;
+  } else {
+    delta_x_norm_ = delta_y_norm_ = 1;
+  }
+}
+
+double Scroller::GetSplineDeceleration(float velocity) const {
+  return std::log(kInflexion * std::abs(velocity) /
+                  (fling_friction_ * tuning_coeff_));
+}
+
+base::TimeDelta Scroller::GetSplineFlingDuration(float velocity) const {
+  const double l = GetSplineDeceleration(velocity);
+  const double decel_minus_one = kDecelerationRate - 1.0;
+  const double time_seconds = std::exp(l / decel_minus_one);
+  return base::TimeDelta::FromMicroseconds(time_seconds *
+                                           base::Time::kMicrosecondsPerSecond);
+}
+
+double Scroller::GetSplineFlingDistance(float velocity) const {
+  const double l = GetSplineDeceleration(velocity);
+  const double decel_minus_one = kDecelerationRate - 1.0;
+  return fling_friction_ * tuning_coeff_ *
+         std::exp(kDecelerationRate / decel_minus_one * l);
+}
+
+}  // namespace ui
diff --git a/ui/events/chromecast/scroller.h b/ui/events/chromecast/scroller.h
new file mode 100644
index 0000000..f4ef836
--- /dev/null
+++ b/ui/events/chromecast/scroller.h
@@ -0,0 +1,151 @@
+// 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 UI_EVENTS_CHROMECAST_SCROLLER_H_
+#define UI_EVENTS_CHROMECAST_SCROLLER_H_
+
+#include "base/time/time.h"
+#include "ui/events/events_base_export.h"
+#include "ui/events/gesture_curve.h"
+#include "ui/gfx/geometry/vector2d_f.h"
+
+namespace ui {
+
+// Native port of android.widget.Scroller.
+// * Change-Id: I4365946f890a76fcfa78ca9d69f2a8e0848095a9
+// * Please update the Change-Id as upstream Android changes are pulled.
+class EVENTS_BASE_EXPORT Scroller : public GestureCurve {
+ public:
+  struct Config {
+    Config();
+
+    // Controls fling deceleration. Defaults to 0.015f.
+    float fling_friction;
+
+    // Controls fling accumulation. Defaults to disabled.
+    bool flywheel_enabled;
+  };
+
+  explicit Scroller(const Config& config);
+  ~Scroller() override;
+
+  // GestureCurve implementation.
+  bool ComputeScrollOffset(base::TimeTicks time,
+                           gfx::Vector2dF* offset,
+                           gfx::Vector2dF* velocity) override;
+
+  // Start scrolling by providing a starting point and the distance to travel.
+  // The default value of 250 milliseconds will be used for the duration.
+  void StartScroll(float start_x,
+                   float start_y,
+                   float dx,
+                   float dy,
+                   base::TimeTicks start_time);
+
+  // Start scrolling by providing a starting point, the distance to travel,
+  // and the duration of the scroll.
+  void StartScroll(float start_x,
+                   float start_y,
+                   float dx,
+                   float dy,
+                   base::TimeTicks start_time,
+                   base::TimeDelta duration);
+
+  // Start scrolling based on a fling gesture. The distance travelled will
+  // depend on the initial velocity of the fling.
+  void Fling(float start_x,
+             float start_y,
+             float velocity_x,
+             float velocity_y,
+             float min_x,
+             float max_x,
+             float min_y,
+             float max_y,
+             base::TimeTicks start_time);
+
+  // Extend the scroll animation by |extend|. This allows a running animation
+  // to scroll further and longer when used with |SetFinalX()| or |SetFinalY()|.
+  void ExtendDuration(base::TimeDelta extend);
+  void SetFinalX(float new_x);
+  void SetFinalY(float new_y);
+
+  // Stops the animation. Contrary to |ForceFinished()|, aborting the animation
+  // causes the scroller to move to the final x and y position.
+  void AbortAnimation();
+
+  // Terminate the scroll without affecting the current x and y positions.
+  void ForceFinished(bool finished);
+
+  // Returns whether the scroller has finished scrolling.
+  bool IsFinished() const;
+
+  // Returns the time elapsed since the beginning of the scrolling.
+  base::TimeDelta GetTimePassed() const;
+
+  // Returns how long the scroll event will take.
+  base::TimeDelta GetDuration() const;
+
+  float GetStartX() const;
+  float GetStartY() const;
+  float GetCurrX() const;
+  float GetCurrY() const;
+  float GetCurrVelocity() const;
+  float GetCurrVelocityX() const;
+  float GetCurrVelocityY() const;
+  float GetFinalX() const;
+  float GetFinalY() const;
+
+  bool IsScrollingInDirection(float xvel, float yvel) const;
+
+ private:
+  enum Mode {
+    UNDEFINED,
+    SCROLL_MODE,
+    FLING_MODE,
+  };
+
+  bool ComputeScrollOffsetInternal(base::TimeTicks time);
+  void RecomputeDeltas();
+
+  double GetSplineDeceleration(float velocity) const;
+  base::TimeDelta GetSplineFlingDuration(float velocity) const;
+  double GetSplineFlingDistance(float velocity) const;
+
+  Mode mode_;
+
+  float start_x_;
+  float start_y_;
+  float final_x_;
+  float final_y_;
+
+  float min_x_;
+  float max_x_;
+  float min_y_;
+  float max_y_;
+
+  float curr_x_;
+  float curr_y_;
+  base::TimeTicks start_time_;
+  base::TimeTicks curr_time_;
+  base::TimeDelta duration_;
+  double duration_seconds_reciprocal_;
+  float delta_x_;
+  float delta_x_norm_;
+  float delta_y_;
+  float delta_y_norm_;
+  bool finished_;
+  bool flywheel_enabled_;
+
+  float velocity_;
+  float curr_velocity_;
+  float distance_;
+
+  float fling_friction_;
+  float deceleration_;
+  float tuning_coeff_;
+};
+
+}  // namespace ui
+
+#endif  // UI_EVENTS_CHROMECAST_SCROLLER_H_
diff --git a/ui/events/chromecast/scroller_unittest.cc b/ui/events/chromecast/scroller_unittest.cc
new file mode 100644
index 0000000..1303f7f8
--- /dev/null
+++ b/ui/events/chromecast/scroller_unittest.cc
@@ -0,0 +1,178 @@
+// 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 <limits.h>
+
+#include "base/time/time.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/events/chromecast/scroller.h"
+
+namespace ui {
+namespace {
+
+const float kDefaultStartX = 7.f;
+const float kDefaultStartY = 25.f;
+const float kDefaultDeltaX = -20.f;
+const float kDefaultDeltaY = 73.f;
+const float kDefaultVelocityX = -350.f;
+const float kDefaultVelocityY = 220.f;
+const float kEpsilon = 1e-3f;
+
+Scroller::Config DefaultConfig() {
+  return Scroller::Config();
+}
+
+}  // namespace
+
+class ScrollerTest : public testing::Test {};
+
+TEST_F(ScrollerTest, Scroll) {
+  Scroller scroller(DefaultConfig());
+  base::TimeTicks start_time = base::TimeTicks::Now();
+
+  // Start a scroll and verify initialized values.
+  scroller.StartScroll(kDefaultStartX,
+                       kDefaultStartY,
+                       kDefaultDeltaX,
+                       kDefaultDeltaY,
+                       start_time);
+
+  EXPECT_EQ(kDefaultStartX, scroller.GetStartX());
+  EXPECT_EQ(kDefaultStartY, scroller.GetStartY());
+  EXPECT_EQ(kDefaultStartX, scroller.GetCurrX());
+  EXPECT_EQ(kDefaultStartY, scroller.GetCurrY());
+  EXPECT_EQ(kDefaultStartX + kDefaultDeltaX, scroller.GetFinalX());
+  EXPECT_EQ(kDefaultStartY + kDefaultDeltaY, scroller.GetFinalY());
+  EXPECT_FALSE(scroller.IsFinished());
+  EXPECT_EQ(base::TimeDelta(), scroller.GetTimePassed());
+
+  // Advance halfway through the scroll.
+  const base::TimeDelta scroll_duration = scroller.GetDuration();
+  gfx::Vector2dF offset, velocity;
+  EXPECT_TRUE(scroller.ComputeScrollOffset(
+      start_time + scroll_duration / 2, &offset, &velocity));
+
+  // Ensure we've moved in the direction of the delta, but have yet to reach
+  // the target.
+  EXPECT_GT(kDefaultStartX, offset.x());
+  EXPECT_LT(kDefaultStartY, offset.y());
+  EXPECT_LT(scroller.GetFinalX(), offset.x());
+  EXPECT_GT(scroller.GetFinalY(), offset.y());
+  EXPECT_FALSE(scroller.IsFinished());
+
+  // Ensure our velocity is non-zero and in the same direction as the delta.
+  EXPECT_GT(0.f, velocity.x() * kDefaultDeltaX);
+  EXPECT_GT(0.f, velocity.y() * kDefaultDeltaY);
+  EXPECT_TRUE(scroller.IsScrollingInDirection(kDefaultDeltaX, kDefaultDeltaY));
+
+  // Repeated offset computations at the same timestamp should yield identical
+  // results.
+  float curr_x = offset.x();
+  float curr_y = offset.y();
+  float curr_velocity_x = velocity.x();
+  float curr_velocity_y = velocity.y();
+  EXPECT_TRUE(scroller.ComputeScrollOffset(
+      start_time + scroll_duration / 2, &offset, &velocity));
+  EXPECT_EQ(curr_x, offset.x());
+  EXPECT_EQ(curr_y, offset.y());
+  EXPECT_EQ(curr_velocity_x, velocity.x());
+  EXPECT_EQ(curr_velocity_y, velocity.y());
+
+  // Advance to the end.
+  EXPECT_FALSE(scroller.ComputeScrollOffset(
+      start_time + scroll_duration, &offset, &velocity));
+  EXPECT_EQ(scroller.GetFinalX(), offset.x());
+  EXPECT_EQ(scroller.GetFinalY(), offset.y());
+  EXPECT_TRUE(scroller.IsFinished());
+  EXPECT_EQ(scroll_duration, scroller.GetTimePassed());
+  EXPECT_NEAR(0.f, velocity.x(), kEpsilon);
+  EXPECT_NEAR(0.f, velocity.y(), kEpsilon);
+
+  // Try to advance further; nothing should change.
+  EXPECT_FALSE(scroller.ComputeScrollOffset(
+      start_time + scroll_duration * 2, &offset, &velocity));
+  EXPECT_EQ(scroller.GetFinalX(), offset.x());
+  EXPECT_EQ(scroller.GetFinalY(), offset.y());
+  EXPECT_TRUE(scroller.IsFinished());
+  EXPECT_EQ(scroll_duration, scroller.GetTimePassed());
+}
+
+TEST_F(ScrollerTest, Fling) {
+  Scroller scroller(DefaultConfig());
+  base::TimeTicks start_time = base::TimeTicks::Now();
+
+  // Start a fling and verify initialized values.
+  scroller.Fling(kDefaultStartX,
+                 kDefaultStartY,
+                 kDefaultVelocityX,
+                 kDefaultVelocityY,
+                 INT_MIN,
+                 INT_MAX,
+                 INT_MIN,
+                 INT_MAX,
+                 start_time);
+
+  EXPECT_EQ(kDefaultStartX, scroller.GetStartX());
+  EXPECT_EQ(kDefaultStartY, scroller.GetStartY());
+  EXPECT_EQ(kDefaultStartX, scroller.GetCurrX());
+  EXPECT_EQ(kDefaultStartY, scroller.GetCurrY());
+  EXPECT_GT(kDefaultStartX, scroller.GetFinalX());
+  EXPECT_LT(kDefaultStartY, scroller.GetFinalY());
+  EXPECT_FALSE(scroller.IsFinished());
+  EXPECT_EQ(base::TimeDelta(), scroller.GetTimePassed());
+
+  // Advance halfway through the fling.
+  const base::TimeDelta scroll_duration = scroller.GetDuration();
+  gfx::Vector2dF offset, velocity;
+  scroller.ComputeScrollOffset(
+      start_time + scroll_duration / 2, &offset, &velocity);
+
+  // Ensure we've moved in the direction of the velocity, but have yet to reach
+  // the target.
+  EXPECT_GT(kDefaultStartX, offset.x());
+  EXPECT_LT(kDefaultStartY, offset.y());
+  EXPECT_LT(scroller.GetFinalX(), offset.x());
+  EXPECT_GT(scroller.GetFinalY(), offset.y());
+  EXPECT_FALSE(scroller.IsFinished());
+
+  // Ensure our velocity is non-zero and in the same direction as the original
+  // velocity.
+  EXPECT_LT(0.f, velocity.x() * kDefaultVelocityX);
+  EXPECT_LT(0.f, velocity.y() * kDefaultVelocityY);
+  EXPECT_TRUE(
+      scroller.IsScrollingInDirection(kDefaultVelocityX, kDefaultVelocityY));
+
+  // Repeated offset computations at the same timestamp should yield identical
+  // results.
+  float curr_x = offset.x();
+  float curr_y = offset.y();
+  float curr_velocity_x = velocity.x();
+  float curr_velocity_y = velocity.y();
+  EXPECT_TRUE(scroller.ComputeScrollOffset(
+      start_time + scroll_duration / 2, &offset, &velocity));
+  EXPECT_EQ(curr_x, offset.x());
+  EXPECT_EQ(curr_y, offset.y());
+  EXPECT_EQ(curr_velocity_x, velocity.x());
+  EXPECT_EQ(curr_velocity_y, velocity.y());
+
+  // Advance to the end.
+  EXPECT_FALSE(scroller.ComputeScrollOffset(
+      start_time + scroll_duration, &offset, &velocity));
+  EXPECT_EQ(scroller.GetFinalX(), offset.x());
+  EXPECT_EQ(scroller.GetFinalY(), offset.y());
+  EXPECT_TRUE(scroller.IsFinished());
+  EXPECT_EQ(scroll_duration, scroller.GetTimePassed());
+  EXPECT_NEAR(0.f, velocity.x(), kEpsilon);
+  EXPECT_NEAR(0.f, velocity.y(), kEpsilon);
+
+  // Try to advance further; nothing should change.
+  EXPECT_FALSE(scroller.ComputeScrollOffset(
+      start_time + scroll_duration * 2, &offset, &velocity));
+  EXPECT_EQ(scroller.GetFinalX(), offset.x());
+  EXPECT_EQ(scroller.GetFinalY(), offset.y());
+  EXPECT_TRUE(scroller.IsFinished());
+  EXPECT_EQ(scroll_duration, scroller.GetTimePassed());
+}
+
+}  // namespace ui
diff --git a/ui/events/gestures/blink/web_gesture_curve_impl.cc b/ui/events/gestures/blink/web_gesture_curve_impl.cc
index 65f680e..b2aec0cb 100644
--- a/ui/events/gestures/blink/web_gesture_curve_impl.cc
+++ b/ui/events/gestures/blink/web_gesture_curve_impl.cc
@@ -24,6 +24,10 @@
 #include "ui/events/android/scroller.h"
 #endif
 
+#if !defined(OS_ANDROID) && defined(CHROMECAST_BUILD)
+#include "ui/events/chromecast/scroller.h"
+#endif
+
 using blink::WebGestureCurve;
 
 namespace ui {
@@ -37,7 +41,7 @@
                                                 base::TimeTicks());
   }
 
-#if defined(OS_ANDROID)
+#if defined(OS_ANDROID) || defined(CHROMECAST_BUILD)
   auto scroller = std::make_unique<Scroller>(Scroller::Config());
   scroller->Fling(0,
                   0,
diff --git a/ui/strings/ui_strings.grd b/ui/strings/ui_strings.grd
index 526f76d4..83d5d1d 100644
--- a/ui/strings/ui_strings.grd
+++ b/ui/strings/ui_strings.grd
@@ -334,6 +334,22 @@
         <message name="IDS_SELECT_UPLOAD_FOLDER_BUTTON_TITLE" desc="The name of the Select button in the folder selection dialog for uploading.">
           Upload
         </message>
+
+        <!-- Edit::Speech submenu -->
+        <message name="IDS_SPEECH_MAC" desc="The Mac menu item for the 'Speech' submenu in the edit and context menu. To translate, launch /Applications/TextEdit.app in an appropriately localized version of OS X, open the Edit menu and use the translation from there.">
+          Speech
+        </message>
+        <message name="IDS_SPEECH_START_SPEAKING_MAC" desc="The Mac menu item for the 'Start Speaking' item from the 'Speech' submenu in edit and context menu. To translate, launch /Applications/TextEdit.app in an appropriately localized version of OS X, open the Edit menu and use the translation from there.">
+          Start Speaking
+        </message>
+        <message name="IDS_SPEECH_STOP_SPEAKING_MAC" desc="The Mac menu item for the 'Stop Speaking' item from the 'Speech' submenu in edit and context menu. To translate, launch /Applications/TextEdit.app in an appropriately localized version of OS X, open the Edit menu and use the translation from there.">
+          Stop Speaking
+        </message>
+
+        <message name="IDS_CONTENT_CONTEXT_LOOK_UP" desc="The name of the 'Look Up “string”' item in the content area context menu. To translate, launch /Applications/TextEdit.app in an appropriately localized version of OS X, right-click on the text entry area and use the translation from there.">
+          Look Up “<ph name="LOOKUP_STRING">$1<ex>orthogonal</ex></ph>”
+        </message>
+
       </if>
 
       <!-- File chooser dialog default titles (only used on Linux) -->
diff --git a/ui/views/BUILD.gn b/ui/views/BUILD.gn
index b2543a4..8d72c2a2 100644
--- a/ui/views/BUILD.gn
+++ b/ui/views/BUILD.gn
@@ -167,6 +167,7 @@
     "controls/tree/tree_view.h",
     "controls/tree/tree_view_controller.h",
     "controls/tree/tree_view_drawing_provider.h",
+    "controls/views_text_services_context_menu.h",
     "debug_utils.h",
     "drag_controller.h",
     "drag_utils.h",
@@ -355,6 +356,8 @@
     "controls/tree/tree_view.cc",
     "controls/tree/tree_view_controller.cc",
     "controls/tree/tree_view_drawing_provider.cc",
+    "controls/views_text_services_context_menu.cc",
+    "controls/views_text_services_context_menu_mac.mm",
     "debug_utils.cc",
     "drag_utils.cc",
     "drag_utils_mac.mm",
@@ -683,6 +686,7 @@
   }
 
   if (is_mac) {
+    sources -= [ "controls/views_text_services_context_menu.cc" ]
     deps += [
       "//components/crash/core/common",
       "//ui/accelerated_widget_mac",
diff --git a/ui/views/controls/textfield/textfield.cc b/ui/views/controls/textfield/textfield.cc
index abe0b2f..1226a19 100644
--- a/ui/views/controls/textfield/textfield.cc
+++ b/ui/views/controls/textfield/textfield.cc
@@ -46,6 +46,7 @@
 #include "ui/views/controls/menu/menu_runner.h"
 #include "ui/views/controls/native/native_view_host.h"
 #include "ui/views/controls/textfield/textfield_controller.h"
+#include "ui/views/controls/views_text_services_context_menu.h"
 #include "ui/views/drag_utils.h"
 #include "ui/views/layout/layout_provider.h"
 #include "ui/views/native_cursor.h"
@@ -2137,7 +2138,11 @@
     // IsCommandIdEnabled() as appropriate, for the commands added.
     if (controller_)
       controller_->UpdateContextMenu(context_menu_contents_.get());
+
+    text_services_context_menu_ = ViewsTextServicesContextMenu::Create(
+        context_menu_contents_.get(), this);
   }
+
   context_menu_runner_.reset(
       new MenuRunner(context_menu_contents_.get(),
                      MenuRunner::HAS_MNEMONICS | MenuRunner::CONTEXT_MENU));
diff --git a/ui/views/controls/textfield/textfield.h b/ui/views/controls/textfield/textfield.h
index 703b90c2..ab521fa 100644
--- a/ui/views/controls/textfield/textfield.h
+++ b/ui/views/controls/textfield/textfield.h
@@ -43,6 +43,7 @@
 class Label;
 class MenuRunner;
 class TextfieldController;
+class ViewsTextServicesContextMenu;
 
 // A views/skia textfield implementation. No platform-specific code is used.
 class VIEWS_EXPORT Textfield : public View,
@@ -563,6 +564,7 @@
 
   // Context menu related members.
   std::unique_ptr<ui::SimpleMenuModel> context_menu_contents_;
+  std::unique_ptr<ViewsTextServicesContextMenu> text_services_context_menu_;
   std::unique_ptr<views::MenuRunner> context_menu_runner_;
 
   // View containing the text cursor.
diff --git a/ui/views/controls/views_text_services_context_menu.cc b/ui/views/controls/views_text_services_context_menu.cc
new file mode 100644
index 0000000..e7a41a2
--- /dev/null
+++ b/ui/views/controls/views_text_services_context_menu.cc
@@ -0,0 +1,16 @@
+// 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 "ui/views/controls/views_text_services_context_menu.h"
+
+namespace views {
+
+// static
+std::unique_ptr<ViewsTextServicesContextMenu>
+ViewsTextServicesContextMenu::Create(ui::SimpleMenuModel* menu,
+                                     Textfield* client) {
+  return nullptr;
+}
+
+}  // namespace views
\ No newline at end of file
diff --git a/ui/views/controls/views_text_services_context_menu.h b/ui/views/controls/views_text_services_context_menu.h
new file mode 100644
index 0000000..78a9348
--- /dev/null
+++ b/ui/views/controls/views_text_services_context_menu.h
@@ -0,0 +1,32 @@
+// 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 UI_VIEWS_CONTROLS_TEXTFIELD_VIEWS_TEXT_SERVICES_CONTEXT_MENU_H_
+#define UI_VIEWS_CONTROLS_TEXTFIELD_VIEWS_TEXT_SERVICES_CONTEXT_MENU_H_
+
+#include <memory>
+
+namespace ui {
+class SimpleMenuModel;
+}
+
+namespace views {
+
+class Textfield;
+
+// This class is used to add and handle text service items in the text context
+// menu.
+class ViewsTextServicesContextMenu {
+ public:
+  virtual ~ViewsTextServicesContextMenu() {}
+
+  // Creates a platform-specific ViewsTextServicesContextMenu object.
+  static std::unique_ptr<ViewsTextServicesContextMenu> Create(
+      ui::SimpleMenuModel* menu,
+      Textfield* textfield);
+};
+
+}  // namespace views
+
+#endif  // UI_VIEWS_CONTROLS_TEXTFIELD_VIEWS_TEXT_SERVICES_CONTEXT_MENU_H_
diff --git a/ui/views/controls/views_text_services_context_menu_mac.mm b/ui/views/controls/views_text_services_context_menu_mac.mm
new file mode 100644
index 0000000..8e8036a
--- /dev/null
+++ b/ui/views/controls/views_text_services_context_menu_mac.mm
@@ -0,0 +1,55 @@
+// 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 "ui/views/controls/views_text_services_context_menu.h"
+
+#include "base/memory/ptr_util.h"
+#include "ui/base/cocoa/text_services_context_menu.h"
+#include "ui/base/models/simple_menu_model.h"
+#include "ui/views/controls/textfield/textfield.h"
+
+namespace views {
+
+namespace {
+
+// This class serves as a bridge to TextServicesContextMenu to add and handle
+// text service items in the context menu. The items include Speech, Look Up
+// and BiDi.
+// TODO (spqchan): Add Look Up and BiDi.
+class ViewsTextServicesContextMenuMac
+    : public ViewsTextServicesContextMenu,
+      public ui::TextServicesContextMenu::Delegate {
+ public:
+  ViewsTextServicesContextMenuMac(ui::SimpleMenuModel* menu, Textfield* client)
+      : text_services_menu_(this), client_(client) {
+    text_services_menu_.AppendToContextMenu(menu);
+  }
+
+  ~ViewsTextServicesContextMenuMac() override {}
+
+  // TextServicesContextMenu::Delegate:
+  base::string16 GetSelectedText() const override {
+    return client_->GetSelectedText();
+  }
+
+ private:
+  // Appends and handles the text service menu.
+  ui::TextServicesContextMenu text_services_menu_;
+
+  // The view associated with the menu. Weak. Owns |this|.
+  Textfield* client_;
+
+  DISALLOW_COPY_AND_ASSIGN(ViewsTextServicesContextMenuMac);
+};
+
+}  // namespace
+
+// static
+std::unique_ptr<ViewsTextServicesContextMenu>
+ViewsTextServicesContextMenu::Create(ui::SimpleMenuModel* menu,
+                                     Textfield* client) {
+  return base::MakeUnique<ViewsTextServicesContextMenuMac>(menu, client);
+}
+
+}  // namespace views
\ No newline at end of file